2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
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"};
32 float mod_md3_sin[320];
34 void Mod_AliasInit (void)
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);
47 void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
50 // vertex weighted skeletal
53 float boneposerelative[MAX_BONES][12];
54 float *matrix, m[12], bonepose[MAX_BONES][12];
57 size = model->num_surfaces * sizeof(msurface_t) + model->num_surfaces * sizeof(int) + model->num_surfaces * model->numskins * sizeof(texture_t) + model->surfmesh.num_triangles * sizeof(int[3]) + model->surfmesh.num_triangles * sizeof(int[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[3]) + model->surfmesh.num_vertices * sizeof(float[2]) + model->surfmesh.num_vertices * sizeof(int[4]) + model->surfmesh.num_vertices * sizeof(float[4]) + model->num_poses * sizeof(float[12]) + model->num_bones * sizeof(float[12]) + model->numskins * sizeof(animscene_t) + model->num_bones * sizeof(aliasbone_t) + model->numframes * sizeof(animscene_t) + ((model->surfmesh.num_vertices <= 65536) ? (model->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
58 if (size > ((memheader_t *)model->data_surfaces)[-1].size)
59 Con_Printf("%s:%i for %s: %i > %i\n", __FILE__, __LINE__, model->name, (int)size, (int)((memheader_t *)model->data_surfaces)[-1].size);
60 else if(size < ((memheader_t *)model->data_surfaces)[-1].size)
61 Con_DPrintf("%s:%i for %s: %i < %i\n", __FILE__, __LINE__, model->name, (int)size, (int)((memheader_t *)model->data_surfaces)[-1].size);
63 // interpolate matrices and concatenate them to their parents
64 for (i = 0;i < model->num_bones;i++)
66 for (k = 0;k < 12;k++)
68 for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
70 matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12;
71 if ((unsigned char *)(matrix + 12) >(unsigned char *)model->data_surfaces + ((memheader_t *)model->data_surfaces)[-1].size)
72 Sys_Error("%s:%i: matrix %p >= data %p + size %i\n", __FILE__, __LINE__, matrix, model->data_surfaces, (int)((memheader_t *)model->data_surfaces)[-1].size);
73 for (k = 0;k < 12;k++)
74 m[k] += matrix[k] * frameblend[blends].lerp;
76 if (i == r_skeletal_debugbone.integer)
77 m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
78 m[3] *= r_skeletal_debugtranslatex.value;
79 m[7] *= r_skeletal_debugtranslatey.value;
80 m[11] *= r_skeletal_debugtranslatez.value;
81 if (model->data_bones[i].parent >= 0)
82 R_ConcatTransforms(bonepose[model->data_bones[i].parent], m, bonepose[i]);
84 for (k = 0;k < 12;k++)
85 bonepose[i][k] = m[k];
86 // create a relative deformation matrix to describe displacement
87 // from the base mesh, which is used by the actual weighting
88 R_ConcatTransforms(bonepose[i], model->data_baseboneposeinverse + i * 12, boneposerelative[i]);
90 // blend the vertex bone weights
91 // special case for the extremely common wf[0] == 1 because it saves 3 multiplies per array when compared to the other case (w[0] is always 1 if only one bone controls this vertex, artists only use multiple bones for certain special cases)
92 // special case for the first bone because it avoids the need to memset the arrays before filling
94 const float *v = model->surfmesh.data_vertex3f;
95 const int *wi = model->surfmesh.data_vertexweightindex4i;
96 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
97 memset(vertex3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
98 for (i = 0;i < model->surfmesh.num_vertices;i++, v += 3, wi += 4, wf += 4, vertex3f += 3)
102 const float *m = boneposerelative[wi[0]];
103 vertex3f[0] = (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
104 vertex3f[1] = (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
105 vertex3f[2] = (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
109 const float *m = boneposerelative[wi[0]];
111 vertex3f[0] = f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
112 vertex3f[1] = f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
113 vertex3f[2] = f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
114 for (k = 1;k < 4 && wf[k];k++)
116 const float *m = boneposerelative[wi[k]];
118 vertex3f[0] += f * (v[0] * m[0] + v[1] * m[1] + v[2] * m[ 2] + m[ 3]);
119 vertex3f[1] += f * (v[0] * m[4] + v[1] * m[5] + v[2] * m[ 6] + m[ 7]);
120 vertex3f[2] += f * (v[0] * m[8] + v[1] * m[9] + v[2] * m[10] + m[11]);
127 const float *n = model->surfmesh.data_normal3f;
128 const int *wi = model->surfmesh.data_vertexweightindex4i;
129 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
130 memset(normal3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
131 for (i = 0;i < model->surfmesh.num_vertices;i++, n += 3, wi += 4, wf += 4, normal3f += 3)
135 const float *m = boneposerelative[wi[0]];
136 normal3f[0] = (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
137 normal3f[1] = (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
138 normal3f[2] = (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
142 const float *m = boneposerelative[wi[0]];
144 normal3f[0] = f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
145 normal3f[1] = f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
146 normal3f[2] = f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
147 for (k = 1;k < 4 && wf[k];k++)
149 const float *m = boneposerelative[wi[k]];
151 normal3f[0] += f * (n[0] * m[0] + n[1] * m[1] + n[2] * m[ 2]);
152 normal3f[1] += f * (n[0] * m[4] + n[1] * m[5] + n[2] * m[ 6]);
153 normal3f[2] += f * (n[0] * m[8] + n[1] * m[9] + n[2] * m[10]);
160 const float *sv = model->surfmesh.data_svector3f;
161 const int *wi = model->surfmesh.data_vertexweightindex4i;
162 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
163 memset(svector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
164 for (i = 0;i < model->surfmesh.num_vertices;i++, sv += 3, wi += 4, wf += 4, svector3f += 3)
168 const float *m = boneposerelative[wi[0]];
169 svector3f[0] = (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
170 svector3f[1] = (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
171 svector3f[2] = (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
175 const float *m = boneposerelative[wi[0]];
177 svector3f[0] = f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
178 svector3f[1] = f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
179 svector3f[2] = f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
180 for (k = 1;k < 4 && wf[k];k++)
182 const float *m = boneposerelative[wi[k]];
184 svector3f[0] += f * (sv[0] * m[0] + sv[1] * m[1] + sv[2] * m[ 2]);
185 svector3f[1] += f * (sv[0] * m[4] + sv[1] * m[5] + sv[2] * m[ 6]);
186 svector3f[2] += f * (sv[0] * m[8] + sv[1] * m[9] + sv[2] * m[10]);
193 const float *tv = model->surfmesh.data_tvector3f;
194 const int *wi = model->surfmesh.data_vertexweightindex4i;
195 const float *wf = model->surfmesh.data_vertexweightinfluence4f;
196 memset(tvector3f, 0, sizeof(float[3]) * model->surfmesh.num_vertices);
197 for (i = 0;i < model->surfmesh.num_vertices;i++, tv += 3, wi += 4, wf += 4, tvector3f += 3)
201 const float *m = boneposerelative[wi[0]];
202 tvector3f[0] = (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
203 tvector3f[1] = (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
204 tvector3f[2] = (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
208 const float *m = boneposerelative[wi[0]];
210 tvector3f[0] = f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
211 tvector3f[1] = f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
212 tvector3f[2] = f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
213 for (k = 1;k < 4 && wf[k];k++)
215 const float *m = boneposerelative[wi[k]];
217 tvector3f[0] += f * (tv[0] * m[0] + tv[1] * m[1] + tv[2] * m[ 2]);
218 tvector3f[1] += f * (tv[0] * m[4] + tv[1] * m[5] + tv[2] * m[ 6]);
219 tvector3f[2] += f * (tv[0] * m[8] + tv[1] * m[9] + tv[2] * m[10]);
226 void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
229 int i, numblends, blendnum;
230 int numverts = model->surfmesh.num_vertices;
232 for (blendnum = 0;blendnum < 4;blendnum++)
234 //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
235 if (frameblend[blendnum].lerp > 0)
236 numblends = blendnum + 1;
238 // special case for the first blend because it avoids some adds and the need to memset the arrays first
239 for (blendnum = 0;blendnum < numblends;blendnum++)
241 const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame;
242 float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
245 for (i = 0;i < numverts;i++)
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;
254 for (i = 0;i < numverts;i++)
256 vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
257 vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
258 vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
261 // the yaw and pitch stored in md3 models are 8bit quantized angles
262 // (0-255), and as such a lookup table is very well suited to
263 // decoding them, and since cosine is equivilant to sine with an
264 // extra 45 degree rotation, this uses one lookup table for both
265 // sine and cosine with a +64 bias to get cosine.
268 float lerp = frameblend[blendnum].lerp;
271 for (i = 0;i < numverts;i++)
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;
280 for (i = 0;i < numverts;i++)
282 normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
283 normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
284 normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
290 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
291 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
294 for (i = 0;i < numverts;i++, texvecvert++)
296 VectorScale(texvecvert->svec, f, svector3f + i*3);
297 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
302 for (i = 0;i < numverts;i++, texvecvert++)
304 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
305 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
312 void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameblend, float *vertex3f, float *normal3f, float *svector3f, float *tvector3f)
315 int i, numblends, blendnum;
316 int numverts = model->surfmesh.num_vertices;
318 VectorClear(translate);
320 // blend the frame translates to avoid redundantly doing so on each vertex
321 // (a bit of a brain twister but it works)
322 for (blendnum = 0;blendnum < 4;blendnum++)
324 if (model->surfmesh.data_morphmd2framesize6f)
325 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate);
327 VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
328 if (frameblend[blendnum].lerp > 0)
329 numblends = blendnum + 1;
331 // special case for the first blend because it avoids some adds and the need to memset the arrays first
332 for (blendnum = 0;blendnum < numblends;blendnum++)
334 const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame;
336 if (model->surfmesh.data_morphmd2framesize6f)
337 VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale);
339 VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
342 for (i = 0;i < numverts;i++)
344 vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
345 vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
346 vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
351 for (i = 0;i < numverts;i++)
353 vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
354 vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
355 vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
358 // the vertex normals in mdl models are an index into a table of
359 // 162 unique values, this very crude quantization reduces the
360 // vertex normal to only one byte, which saves a lot of space but
361 // also makes lighting pretty coarse
364 float lerp = frameblend[blendnum].lerp;
367 for (i = 0;i < numverts;i++)
369 const float *vn = m_bytenormals[verts[i].lightnormalindex];
370 VectorScale(vn, lerp, normal3f + i*3);
375 for (i = 0;i < numverts;i++)
377 const float *vn = m_bytenormals[verts[i].lightnormalindex];
378 VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
384 const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
385 float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
388 for (i = 0;i < numverts;i++, texvecvert++)
390 VectorScale(texvecvert->svec, f, svector3f + i*3);
391 VectorScale(texvecvert->tvec, f, tvector3f + i*3);
396 for (i = 0;i < numverts;i++, texvecvert++)
398 VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
399 VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
406 int Mod_Alias_GetTagMatrix(const dp_model_t *model, int poseframe, int tagindex, matrix4x4_t *outmatrix)
408 const float *boneframe;
409 float tempbonematrix[12], bonematrix[12];
410 *outmatrix = identitymatrix;
411 if (model->num_bones)
413 if (tagindex < 0 || tagindex >= model->num_bones)
415 if (poseframe >= model->num_poses)
417 boneframe = model->data_poses + poseframe * model->num_bones * 12;
418 memcpy(bonematrix, boneframe + tagindex * 12, sizeof(float[12]));
419 while (model->data_bones[tagindex].parent >= 0)
421 memcpy(tempbonematrix, bonematrix, sizeof(float[12]));
422 R_ConcatTransforms(boneframe + model->data_bones[tagindex].parent * 12, tempbonematrix, bonematrix);
423 tagindex = model->data_bones[tagindex].parent;
425 Matrix4x4_FromArray12FloatD3D(outmatrix, bonematrix);
427 else if (model->num_tags)
429 if (tagindex < 0 || tagindex >= model->num_tags)
431 if (poseframe >= model->num_tagframes)
433 Matrix4x4_FromArray12FloatGL(outmatrix, model->data_tags[poseframe * model->num_tags + tagindex].matrixgl);
438 int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
441 if(skin >= (unsigned int)model->numskins)
443 if (model->num_bones)
444 for (i = 0;i < model->num_bones;i++)
445 if (!strcasecmp(tagname, model->data_bones[i].name))
448 for (i = 0;i < model->num_tags;i++)
449 if (!strcasecmp(tagname, model->data_tags[i].name))
454 static void Mod_BuildBaseBonePoses(void)
458 float *basebonepose = Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(float[12]));
459 float *in12f = loadmodel->data_poses;
460 float *out12f = basebonepose;
461 float *outinv12f = loadmodel->data_baseboneposeinverse;
462 for (i = 0;i < loadmodel->num_bones;i++, in12f += 12, out12f += 12, outinv12f += 12)
464 if (loadmodel->data_bones[i].parent >= 0)
465 R_ConcatTransforms(basebonepose + 12 * loadmodel->data_bones[i].parent, in12f, out12f);
467 for (k = 0;k < 12;k++)
468 out12f[k] = in12f[k];
472 // we only support uniform scaling, so assume the first row is enough
473 // (note the lack of sqrt here, because we're trying to undo the scaling,
474 // this means multiplying by the inverse scale twice - squaring it, which
475 // makes the sqrt a waste of time)
476 scale = 1.0 / (out12f[ 0] * out12f[ 0] + out12f[ 1] * out12f[ 1] + out12f[ 2] * out12f[ 2]);
478 // invert the rotation by transposing and multiplying by the squared
479 // recipricol of the input matrix scale as described above
480 outinv12f[ 0] = (float)(out12f[ 0] * scale);
481 outinv12f[ 1] = (float)(out12f[ 4] * scale);
482 outinv12f[ 2] = (float)(out12f[ 8] * scale);
483 outinv12f[ 4] = (float)(out12f[ 1] * scale);
484 outinv12f[ 5] = (float)(out12f[ 5] * scale);
485 outinv12f[ 6] = (float)(out12f[ 9] * scale);
486 outinv12f[ 8] = (float)(out12f[ 2] * scale);
487 outinv12f[ 9] = (float)(out12f[ 6] * scale);
488 outinv12f[10] = (float)(out12f[10] * scale);
490 // invert the translate
491 outinv12f[ 3] = -(out12f[ 3] * outinv12f[ 0] + out12f[ 7] * outinv12f[ 1] + out12f[11] * outinv12f[ 2]);
492 outinv12f[ 7] = -(out12f[ 3] * outinv12f[ 4] + out12f[ 7] * outinv12f[ 5] + out12f[11] * outinv12f[ 6]);
493 outinv12f[11] = -(out12f[ 3] * outinv12f[ 8] + out12f[ 7] * outinv12f[ 9] + out12f[11] * outinv12f[10]);
495 Mem_Free(basebonepose);
498 static void Mod_Alias_CalculateBoundingBox(void)
501 qboolean firstvertex = true;
502 float dist, yawradius, radius;
505 frameblend_t frameblend[4];
506 memset(frameblend, 0, sizeof(frameblend));
507 frameblend[0].lerp = 1;
508 vertex3f = Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
509 VectorClear(loadmodel->normalmins);
510 VectorClear(loadmodel->normalmaxs);
513 for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++)
515 loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL);
516 for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
521 VectorCopy(v, loadmodel->normalmins);
522 VectorCopy(v, loadmodel->normalmaxs);
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];
533 dist = v[0] * v[0] + v[1] * v[1];
534 if (yawradius < dist)
542 radius = sqrt(radius);
543 yawradius = sqrt(yawradius);
544 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
545 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
546 loadmodel->yawmins[2] = loadmodel->normalmins[2];
547 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
548 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
549 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
550 loadmodel->radius = radius;
551 loadmodel->radius2 = radius * radius;
554 static void Mod_Alias_MorphMesh_CompileFrames(void)
557 frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
558 unsigned char *datapointer;
559 datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
560 loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
561 loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
562 loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
563 loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
564 loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
565 // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
566 for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
568 frameblend[0].frame = i;
569 loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
570 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer);
571 // encode the svector and tvector in 3 byte format for permanent storage
572 for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
574 VectorScale(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
575 VectorScale(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
580 static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
583 float segmentmins[3], segmentmaxs[3];
584 frameblend_t frameblend[4];
586 static int maxvertices = 0;
587 static float *vertex3f = NULL;
588 memset(trace, 0, sizeof(*trace));
590 trace->realfraction = 1;
591 trace->hitsupercontentsmask = hitsupercontentsmask;
592 memset(frameblend, 0, sizeof(frameblend));
593 frameblend[0].frame = frame;
594 frameblend[0].lerp = 1;
595 if (maxvertices < model->surfmesh.num_vertices)
599 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
600 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
602 if (VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0)
605 segmentmins[0] = min(start[0], end[0]) - 1;
606 segmentmins[1] = min(start[1], end[1]) - 1;
607 segmentmins[2] = min(start[2], end[2]) - 1;
608 segmentmaxs[0] = max(start[0], end[0]) + 1;
609 segmentmaxs[1] = max(start[1], end[1]) + 1;
610 segmentmaxs[2] = max(start[2], end[2]) + 1;
611 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
613 model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
614 Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
619 // box trace, performed as brush trace
620 colbrushf_t *thisbrush_start, *thisbrush_end;
621 vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
622 segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
623 segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
624 segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
625 segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
626 segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
627 segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
628 VectorAdd(start, boxmins, boxstartmins);
629 VectorAdd(start, boxmaxs, boxstartmaxs);
630 VectorAdd(end, boxmins, boxendmins);
631 VectorAdd(end, boxmaxs, boxendmaxs);
632 thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
633 thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
634 for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
636 if (maxvertices < model->surfmesh.num_vertices)
640 maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
641 vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
643 model->AnimateVertices(model, frameblend, vertex3f, NULL, NULL, NULL);
644 Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, SUPERCONTENTS_SOLID, 0, surface->texture, segmentmins, segmentmaxs);
649 static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
652 for (i = 0;i < inverts;i++)
654 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
656 j = vertremap[i]; // not onseam
659 j = vertremap[i+inverts]; // onseam
665 static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
667 int i, f, pose, groupframes;
669 daliasframetype_t *pframetype;
670 daliasframe_t *pinframe;
671 daliasgroup_t *group;
672 daliasinterval_t *intervals;
675 scene = loadmodel->animscenes;
676 for (f = 0;f < loadmodel->numframes;f++)
678 pframetype = (daliasframetype_t *)datapointer;
679 datapointer += sizeof(daliasframetype_t);
680 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
682 // a single frame is still treated as a group
689 group = (daliasgroup_t *)datapointer;
690 datapointer += sizeof(daliasgroup_t);
691 groupframes = LittleLong (group->numframes);
693 // intervals (time per frame)
694 intervals = (daliasinterval_t *)datapointer;
695 datapointer += sizeof(daliasinterval_t) * groupframes;
697 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
698 if (interval < 0.01f)
700 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
705 // get scene name from first frame
706 pinframe = (daliasframe_t *)datapointer;
708 strlcpy(scene->name, pinframe->name, sizeof(scene->name));
709 scene->firstframe = pose;
710 scene->framecount = groupframes;
711 scene->framerate = 1.0f / interval;
716 for (i = 0;i < groupframes;i++)
718 pinframe = (daliasframe_t *)datapointer;
719 datapointer += sizeof(daliasframe_t);
720 Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
721 datapointer += sizeof(trivertx_t) * inverts;
727 static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
729 if (cls.state == ca_dedicated)
733 skinframe = R_SkinFrame_LoadMissing();
734 memset(texture, 0, sizeof(*texture));
735 texture->currentframe = texture;
736 //texture->animated = false;
737 texture->numskinframes = 1;
738 texture->skinframerate = 1;
739 texture->skinframes[0] = skinframe;
740 texture->currentskinframe = skinframe;
741 //texture->backgroundnumskinframes = 0;
742 //texture->customblendfunc[0] = 0;
743 //texture->customblendfunc[1] = 0;
744 //texture->surfaceflags = 0;
745 //texture->supercontents = 0;
746 //texture->surfaceparms = 0;
747 //texture->textureflags = 0;
749 texture->basematerialflags = MATERIALFLAG_WALL;
750 if (texture->currentskinframe->fog)
751 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
752 texture->currentmaterialflags = texture->basematerialflags;
755 static void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, char *meshname, char *shadername)
758 skinfileitem_t *skinfileitem;
761 // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
762 for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
764 memset(skin, 0, sizeof(*skin));
766 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
768 // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
769 if (!strcmp(skinfileitem->name, meshname))
771 Mod_LoadTextureFromQ3Shader(skin, skinfileitem->replacement, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
777 // don't render unmentioned meshes
778 Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
779 skin->basematerialflags = skin->currentmaterialflags = 0;
784 Mod_LoadTextureFromQ3Shader(skin, shadername, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
787 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
788 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
789 void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
791 int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
792 float scales, scalet, interval;
796 stvert_t *pinstverts;
797 dtriangle_t *pintriangles;
798 daliasskintype_t *pinskintype;
799 daliasskingroup_t *pinskingroup;
800 daliasskininterval_t *pinskinintervals;
801 daliasframetype_t *pinframetype;
802 daliasgroup_t *pinframegroup;
803 unsigned char *datapointer, *startframes, *startskins;
804 char name[MAX_QPATH];
805 skinframe_t *tempskinframe;
806 animscene_t *tempskinscenes;
807 texture_t *tempaliasskins;
809 int *vertonseam, *vertremap;
810 skinfile_t *skinfiles;
812 datapointer = (unsigned char *)buffer;
813 pinmodel = (mdl_t *)datapointer;
814 datapointer += sizeof(mdl_t);
816 version = LittleLong (pinmodel->version);
817 if (version != ALIAS_VERSION)
818 Host_Error ("%s has wrong version number (%i should be %i)",
819 loadmodel->name, version, ALIAS_VERSION);
821 loadmodel->modeldatatypestring = "MDL";
823 loadmodel->type = mod_alias;
824 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
825 loadmodel->DrawSky = NULL;
826 loadmodel->DrawAddWaterPlanes = NULL;
827 loadmodel->Draw = R_Q1BSP_Draw;
828 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
829 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
830 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
831 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
832 loadmodel->DrawLight = R_Q1BSP_DrawLight;
833 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
834 loadmodel->PointSuperContents = NULL;
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;
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);
861 for (i = 0;i < 3;i++)
863 loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
864 loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
867 startskins = datapointer;
869 for (i = 0;i < loadmodel->numskins;i++)
871 pinskintype = (daliasskintype_t *)datapointer;
872 datapointer += sizeof(daliasskintype_t);
873 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
877 pinskingroup = (daliasskingroup_t *)datapointer;
878 datapointer += sizeof(daliasskingroup_t);
879 groupskins = LittleLong(pinskingroup->numskins);
880 datapointer += sizeof(daliasskininterval_t) * groupskins;
883 for (j = 0;j < groupskins;j++)
885 datapointer += skinwidth * skinheight;
890 pinstverts = (stvert_t *)datapointer;
891 datapointer += sizeof(stvert_t) * numverts;
893 pintriangles = (dtriangle_t *)datapointer;
894 datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
896 startframes = datapointer;
897 loadmodel->surfmesh.num_morphframes = 0;
898 for (i = 0;i < loadmodel->numframes;i++)
900 pinframetype = (daliasframetype_t *)datapointer;
901 datapointer += sizeof(daliasframetype_t);
902 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
906 pinframegroup = (daliasgroup_t *)datapointer;
907 datapointer += sizeof(daliasgroup_t);
908 groupframes = LittleLong(pinframegroup->numframes);
909 datapointer += sizeof(daliasinterval_t) * groupframes;
912 for (j = 0;j < groupframes;j++)
914 datapointer += sizeof(daliasframe_t);
915 datapointer += sizeof(trivertx_t) * numverts;
916 loadmodel->surfmesh.num_morphframes++;
919 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
921 // store texture coordinates into temporary array, they will be stored
922 // after usage is determined (triangle data)
923 vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
924 vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
925 vertonseam = vertremap + numverts * 2;
927 scales = 1.0 / skinwidth;
928 scalet = 1.0 / skinheight;
929 for (i = 0;i < numverts;i++)
931 vertonseam[i] = LittleLong(pinstverts[i].onseam);
932 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
933 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
934 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
935 vertst[(i+numverts)*2+1] = vertst[i*2+1];
938 // load triangle data
939 loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
941 // read the triangle elements
942 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
943 for (j = 0;j < 3;j++)
944 loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
945 // validate (note numverts is used because this is the original data)
946 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
947 // now butcher the elements according to vertonseam and tri->facesfront
948 // and then compact the vertex set to remove duplicates
949 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
950 if (!LittleLong(pintriangles[i].facesfront)) // backface
951 for (j = 0;j < 3;j++)
952 if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
953 loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
955 // (this uses vertremap to count usage to save some memory)
956 for (i = 0;i < numverts*2;i++)
958 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
959 vertremap[loadmodel->surfmesh.data_element3i[i]]++;
960 // build remapping table and compact array
961 loadmodel->surfmesh.num_vertices = 0;
962 for (i = 0;i < numverts*2;i++)
966 vertremap[i] = loadmodel->surfmesh.num_vertices;
967 vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
968 vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
969 loadmodel->surfmesh.num_vertices++;
972 vertremap[i] = -1; // not used at all
974 // remap the elements to the new vertex set
975 for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
976 loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
977 // store the texture coordinates
978 loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
979 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
981 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
982 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
985 // generate ushort elements array if possible
986 if (loadmodel->surfmesh.num_vertices <= 65536)
988 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
989 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
990 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
994 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
995 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
996 loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
997 Mod_MDL_LoadFrames (startframes, numverts, vertremap);
998 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
999 Mod_Alias_CalculateBoundingBox();
1000 Mod_Alias_MorphMesh_CompileFrames();
1003 Mem_Free(vertremap);
1006 skinfiles = Mod_LoadSkinFiles();
1007 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
1008 loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
1009 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1010 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1013 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1014 Mod_FreeSkinFiles(skinfiles);
1015 for (i = 0;i < loadmodel->numskins;i++)
1017 loadmodel->skinscenes[i].firstframe = i;
1018 loadmodel->skinscenes[i].framecount = 1;
1019 loadmodel->skinscenes[i].loop = true;
1020 loadmodel->skinscenes[i].framerate = 10;
1026 datapointer = startskins;
1027 for (i = 0;i < loadmodel->numskins;i++)
1029 pinskintype = (daliasskintype_t *)datapointer;
1030 datapointer += sizeof(daliasskintype_t);
1032 if (pinskintype->type == ALIAS_SKIN_SINGLE)
1039 pinskingroup = (daliasskingroup_t *)datapointer;
1040 datapointer += sizeof(daliasskingroup_t);
1042 groupskins = LittleLong (pinskingroup->numskins);
1044 pinskinintervals = (daliasskininterval_t *)datapointer;
1045 datapointer += sizeof(daliasskininterval_t) * groupskins;
1047 interval = LittleFloat(pinskinintervals[0].interval);
1048 if (interval < 0.01f)
1050 Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
1055 dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
1056 loadmodel->skinscenes[i].firstframe = totalskins;
1057 loadmodel->skinscenes[i].framecount = groupskins;
1058 loadmodel->skinscenes[i].framerate = 1.0f / interval;
1059 loadmodel->skinscenes[i].loop = true;
1061 for (j = 0;j < groupskins;j++)
1064 dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
1066 dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
1067 if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
1068 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
1069 datapointer += skinwidth * skinheight;
1073 // check for skins that don't exist in the model, but do exist as external images
1074 // (this was added because yummyluv kept pestering me about support for it)
1075 // TODO: support shaders here?
1076 while ((tempskinframe = R_SkinFrame_LoadExternal(va("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
1078 // expand the arrays to make room
1079 tempskinscenes = loadmodel->skinscenes;
1080 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
1081 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
1082 Mem_Free(tempskinscenes);
1084 tempaliasskins = loadmodel->data_textures;
1085 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t));
1086 memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
1087 Mem_Free(tempaliasskins);
1089 // store the info about the new skin
1090 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe);
1091 strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name));
1092 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
1093 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
1094 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
1095 loadmodel->skinscenes[loadmodel->numskins].loop = true;
1097 //increase skin counts
1098 loadmodel->numskins++;
1101 // fix up the pointers since they are pointing at the old textures array
1102 // FIXME: this is a hack!
1103 for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++)
1104 loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j];
1108 surface = loadmodel->data_surfaces;
1109 surface->texture = loadmodel->data_textures;
1110 surface->num_firsttriangle = 0;
1111 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1112 surface->num_firstvertex = 0;
1113 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1115 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1118 void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
1120 int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end;
1121 float iskinwidth, iskinheight;
1122 unsigned char *data;
1123 msurface_t *surface;
1125 unsigned char *base, *datapointer;
1126 md2frame_t *pinframe;
1128 md2triangle_t *intri;
1129 unsigned short *inst;
1130 struct md2verthash_s
1132 struct md2verthash_s *next;
1136 *hash, **md2verthash, *md2verthashdata;
1137 skinfile_t *skinfiles;
1139 pinmodel = (md2_t *)buffer;
1140 base = (unsigned char *)buffer;
1142 version = LittleLong (pinmodel->version);
1143 if (version != MD2ALIAS_VERSION)
1144 Host_Error ("%s has wrong version number (%i should be %i)",
1145 loadmodel->name, version, MD2ALIAS_VERSION);
1147 loadmodel->modeldatatypestring = "MD2";
1149 loadmodel->type = mod_alias;
1150 loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
1151 loadmodel->DrawSky = NULL;
1152 loadmodel->DrawAddWaterPlanes = NULL;
1153 loadmodel->Draw = R_Q1BSP_Draw;
1154 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1155 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1156 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1157 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1158 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1159 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1160 loadmodel->PointSuperContents = NULL;
1162 if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536)
1163 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
1164 if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536)
1165 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
1166 if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536)
1167 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
1168 if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256)
1169 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
1171 end = LittleLong(pinmodel->ofs_end);
1172 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end))
1173 Host_Error ("%s is not a valid model", loadmodel->name);
1174 if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end)
1175 Host_Error ("%s is not a valid model", loadmodel->name);
1176 if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end)
1177 Host_Error ("%s is not a valid model", loadmodel->name);
1178 if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end)
1179 Host_Error ("%s is not a valid model", loadmodel->name);
1180 if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end)
1181 Host_Error ("%s is not a valid model", loadmodel->name);
1183 loadmodel->numskins = LittleLong(pinmodel->num_skins);
1184 numxyz = LittleLong(pinmodel->num_xyz);
1185 numst = LittleLong(pinmodel->num_st);
1186 loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris);
1187 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1188 loadmodel->surfmesh.num_morphframes = loadmodel->numframes;
1189 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1190 skinwidth = LittleLong(pinmodel->skinwidth);
1191 skinheight = LittleLong(pinmodel->skinheight);
1192 iskinwidth = 1.0f / skinwidth;
1193 iskinheight = 1.0f / skinheight;
1195 loadmodel->num_surfaces = 1;
1196 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1197 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]));
1198 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1199 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1200 loadmodel->surfacelist[0] = 0;
1201 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1202 loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
1203 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1204 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
1206 loadmodel->synctype = ST_RAND;
1209 inskin = (char *)(base + LittleLong(pinmodel->ofs_skins));
1210 skinfiles = Mod_LoadSkinFiles();
1213 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1214 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1215 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1216 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
1217 Mod_FreeSkinFiles(skinfiles);
1219 else if (loadmodel->numskins)
1221 // skins found (most likely not a player model)
1222 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1223 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1224 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1225 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
1226 Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP | TEXF_COMPRESS);
1230 // no skins (most likely a player model)
1231 loadmodel->numskins = 1;
1232 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1233 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1234 loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
1235 Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL);
1238 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1239 for (i = 0;i < loadmodel->numskins;i++)
1241 loadmodel->skinscenes[i].firstframe = i;
1242 loadmodel->skinscenes[i].framecount = 1;
1243 loadmodel->skinscenes[i].loop = true;
1244 loadmodel->skinscenes[i].framerate = 10;
1247 // load the triangles and stvert data
1248 inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st));
1249 intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris));
1250 md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash));
1251 md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash));
1252 // swap the triangle list
1253 loadmodel->surfmesh.num_vertices = 0;
1254 for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
1256 for (j = 0;j < 3;j++)
1258 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
1259 st = (unsigned short) LittleShort (intri[i].index_st[j]);
1262 Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i);
1267 Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i);
1270 hashindex = (xyz * 256 + st) & 65535;
1271 for (hash = md2verthash[hashindex];hash;hash = hash->next)
1272 if (hash->xyz == xyz && hash->st == st)
1276 hash = md2verthashdata + loadmodel->surfmesh.num_vertices++;
1279 hash->next = md2verthash[hashindex];
1280 md2verthash[hashindex] = hash;
1282 loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata);
1286 vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int));
1287 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t));
1288 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
1289 loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t);
1290 for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
1293 hash = md2verthashdata + i;
1294 vertremap[i] = hash->xyz;
1295 sts = LittleShort(inst[hash->st*2+0]);
1296 stt = LittleShort(inst[hash->st*2+1]);
1297 if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight)
1299 Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i);
1303 loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth;
1304 loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight;
1307 Mem_Free(md2verthash);
1308 Mem_Free(md2verthashdata);
1310 // generate ushort elements array if possible
1311 if (loadmodel->surfmesh.num_vertices <= 65536)
1313 loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
1314 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1315 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1319 datapointer = (base + LittleLong(pinmodel->ofs_frames));
1320 for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++)
1325 pinframe = (md2frame_t *)datapointer;
1326 datapointer += sizeof(md2frame_t);
1327 // store the frame scale/translate into the appropriate array
1328 for (j = 0;j < 3;j++)
1330 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]);
1331 loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]);
1333 // convert the vertices
1334 v = (trivertx_t *)datapointer;
1335 out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices;
1336 for (k = 0;k < loadmodel->surfmesh.num_vertices;k++)
1337 out[k] = v[vertremap[k]];
1338 datapointer += numxyz * sizeof(trivertx_t);
1340 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1341 loadmodel->animscenes[i].firstframe = i;
1342 loadmodel->animscenes[i].framecount = 1;
1343 loadmodel->animscenes[i].framerate = 10;
1344 loadmodel->animscenes[i].loop = true;
1347 Mem_Free(vertremap);
1349 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1350 Mod_Alias_CalculateBoundingBox();
1351 Mod_Alias_MorphMesh_CompileFrames();
1353 surface = loadmodel->data_surfaces;
1354 surface->texture = loadmodel->data_textures;
1355 surface->num_firsttriangle = 0;
1356 surface->num_triangles = loadmodel->surfmesh.num_triangles;
1357 surface->num_firstvertex = 0;
1358 surface->num_vertices = loadmodel->surfmesh.num_vertices;
1360 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1363 void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
1365 int i, j, k, version, meshvertices, meshtriangles;
1366 unsigned char *data;
1367 msurface_t *surface;
1368 md3modelheader_t *pinmodel;
1369 md3frameinfo_t *pinframe;
1372 skinfile_t *skinfiles;
1374 pinmodel = (md3modelheader_t *)buffer;
1376 if (memcmp(pinmodel->identifier, "IDP3", 4))
1377 Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name);
1378 version = LittleLong (pinmodel->version);
1379 if (version != MD3VERSION)
1380 Host_Error ("%s has wrong version number (%i should be %i)",
1381 loadmodel->name, version, MD3VERSION);
1383 skinfiles = Mod_LoadSkinFiles();
1384 if (loadmodel->numskins < 1)
1385 loadmodel->numskins = 1;
1387 loadmodel->modeldatatypestring = "MD3";
1389 loadmodel->type = mod_alias;
1390 loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
1391 loadmodel->DrawSky = NULL;
1392 loadmodel->DrawAddWaterPlanes = NULL;
1393 loadmodel->Draw = R_Q1BSP_Draw;
1394 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1395 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1396 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1397 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1398 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1399 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1400 loadmodel->PointSuperContents = NULL;
1401 loadmodel->synctype = ST_RAND;
1402 // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
1403 i = LittleLong (pinmodel->flags);
1404 loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
1406 // set up some global info about the model
1407 loadmodel->numframes = LittleLong(pinmodel->num_frames);
1408 loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes);
1410 // make skinscenes for the skins (no groups)
1411 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1412 for (i = 0;i < loadmodel->numskins;i++)
1414 loadmodel->skinscenes[i].firstframe = i;
1415 loadmodel->skinscenes[i].framecount = 1;
1416 loadmodel->skinscenes[i].loop = true;
1417 loadmodel->skinscenes[i].framerate = 10;
1421 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
1422 for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
1424 strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name));
1425 loadmodel->animscenes[i].firstframe = i;
1426 loadmodel->animscenes[i].framecount = 1;
1427 loadmodel->animscenes[i].framerate = 10;
1428 loadmodel->animscenes[i].loop = true;
1432 loadmodel->num_tagframes = loadmodel->numframes;
1433 loadmodel->num_tags = LittleLong(pinmodel->num_tags);
1434 loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t));
1435 for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++)
1437 strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name));
1438 for (j = 0;j < 9;j++)
1439 loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]);
1440 for (j = 0;j < 3;j++)
1441 loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]);
1442 //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->num_tags, i % loadmodel->num_tags, loadmodel->data_tags[i].name);
1448 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1450 if (memcmp(pinmesh->identifier, "IDP3", 4))
1451 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1452 if (LittleLong(pinmesh->num_frames) != loadmodel->numframes)
1453 Host_Error("Mod_IDP3_Load: mesh numframes differs from header");
1454 meshvertices += LittleLong(pinmesh->num_vertices);
1455 meshtriangles += LittleLong(pinmesh->num_triangles);
1458 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1459 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1460 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1461 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t));
1462 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1463 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1464 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1465 loadmodel->surfmesh.num_vertices = meshvertices;
1466 loadmodel->surfmesh.num_triangles = meshtriangles;
1467 loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove?
1468 loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
1469 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1470 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1471 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1472 loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
1473 if (meshvertices <= 65536)
1475 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1476 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1477 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1482 for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end)))
1484 if (memcmp(pinmesh->identifier, "IDP3", 4))
1485 Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)");
1486 loadmodel->surfacelist[i] = i;
1487 surface = loadmodel->data_surfaces + i;
1488 surface->texture = loadmodel->data_textures + i;
1489 surface->num_firsttriangle = meshtriangles;
1490 surface->num_triangles = LittleLong(pinmesh->num_triangles);
1491 surface->num_firstvertex = meshvertices;
1492 surface->num_vertices = LittleLong(pinmesh->num_vertices);
1493 meshvertices += surface->num_vertices;
1494 meshtriangles += surface->num_triangles;
1496 for (j = 0;j < surface->num_triangles * 3;j++)
1497 loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]);
1498 for (j = 0;j < surface->num_vertices;j++)
1500 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]);
1501 loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]);
1503 for (j = 0;j < loadmodel->numframes;j++)
1505 const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices;
1506 md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices;
1507 for (k = 0;k < surface->num_vertices;k++, in++, out++)
1509 out->origin[0] = LittleShort(in->origin[0]);
1510 out->origin[1] = LittleShort(in->origin[1]);
1511 out->origin[2] = LittleShort(in->origin[2]);
1512 out->pitch = in->pitch;
1517 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : "");
1519 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
1521 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1522 Mod_Alias_MorphMesh_CompileFrames();
1523 Mod_Alias_CalculateBoundingBox();
1524 Mod_FreeSkinFiles(skinfiles);
1526 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
1527 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
1530 void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1532 zymtype1header_t *pinmodel, *pheader;
1533 unsigned char *pbase;
1534 int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements;
1535 float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose;
1536 zymvertex_t *verts, *vertdata;
1540 skinfile_t *skinfiles;
1541 unsigned char *data;
1542 msurface_t *surface;
1544 pinmodel = (zymtype1header_t *)buffer;
1545 pbase = (unsigned char *)buffer;
1546 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
1547 Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name);
1548 if (BigLong(pinmodel->type) != 1)
1549 Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1551 loadmodel->modeldatatypestring = "ZYM";
1553 loadmodel->type = mod_alias;
1554 loadmodel->synctype = ST_RAND;
1558 pheader->type = BigLong(pinmodel->type);
1559 pheader->filesize = BigLong(pinmodel->filesize);
1560 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
1561 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
1562 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
1563 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
1564 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
1565 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
1566 pheader->radius = BigFloat(pinmodel->radius);
1567 pheader->numverts = BigLong(pinmodel->numverts);
1568 pheader->numtris = BigLong(pinmodel->numtris);
1569 pheader->numshaders = BigLong(pinmodel->numshaders);
1570 pheader->numbones = BigLong(pinmodel->numbones);
1571 pheader->numscenes = BigLong(pinmodel->numscenes);
1572 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
1573 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
1574 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
1575 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
1576 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
1577 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
1578 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
1579 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
1580 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
1581 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
1582 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
1583 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
1584 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
1585 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
1586 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
1587 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
1588 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
1589 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
1591 if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1)
1593 Con_Printf("%s has no geometry\n", loadmodel->name);
1596 if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4]))
1598 Con_Printf("%s has no animations\n", loadmodel->name);
1602 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1603 loadmodel->DrawSky = NULL;
1604 loadmodel->DrawAddWaterPlanes = NULL;
1605 loadmodel->Draw = R_Q1BSP_Draw;
1606 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1607 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1608 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1609 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1610 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1611 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1612 loadmodel->PointSuperContents = NULL;
1614 loadmodel->numframes = pheader->numscenes;
1615 loadmodel->num_surfaces = pheader->numshaders;
1617 skinfiles = Mod_LoadSkinFiles();
1618 if (loadmodel->numskins < 1)
1619 loadmodel->numskins = 1;
1621 // make skinscenes for the skins (no groups)
1622 loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
1623 for (i = 0;i < loadmodel->numskins;i++)
1625 loadmodel->skinscenes[i].firstframe = i;
1626 loadmodel->skinscenes[i].framecount = 1;
1627 loadmodel->skinscenes[i].loop = true;
1628 loadmodel->skinscenes[i].framerate = 10;
1632 modelradius = pheader->radius;
1633 for (i = 0;i < 3;i++)
1635 loadmodel->normalmins[i] = pheader->mins[i];
1636 loadmodel->normalmaxs[i] = pheader->maxs[i];
1637 loadmodel->rotatedmins[i] = -modelradius;
1638 loadmodel->rotatedmaxs[i] = modelradius;
1640 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
1641 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
1642 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
1643 if (loadmodel->yawmaxs[0] > modelradius)
1644 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
1645 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
1646 loadmodel->yawmins[2] = loadmodel->normalmins[2];
1647 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
1648 loadmodel->radius = modelradius;
1649 loadmodel->radius2 = modelradius * modelradius;
1651 // go through the lumps, swapping things
1653 //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
1654 loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
1655 scene = (zymscene_t *) (pheader->lump_scenes.start + pbase);
1656 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
1657 for (i = 0;i < pheader->numscenes;i++)
1659 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
1660 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
1661 loadmodel->animscenes[i].framecount = BigLong(scene->length);
1662 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
1663 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
1664 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
1665 Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes);
1666 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
1667 Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
1668 if (loadmodel->animscenes[i].framerate < 0)
1669 Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate);
1673 //zymlump_t lump_bones; // zymbone_t bone[numbones];
1674 loadmodel->num_bones = pheader->numbones;
1675 loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(aliasbone_t));
1676 bone = (zymbone_t *) (pheader->lump_bones.start + pbase);
1677 for (i = 0;i < pheader->numbones;i++)
1679 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1680 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1681 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1682 if (loadmodel->data_bones[i].parent >= i)
1683 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
1686 //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1687 vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1688 bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase);
1689 for (i = 0;i < pheader->numverts;i++)
1691 vertbonecounts[i] = BigLong(bonecount[i]);
1692 if (vertbonecounts[i] != 1)
1693 Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i);
1696 loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]);
1698 meshvertices = pheader->numverts;
1699 meshtriangles = pheader->numtris;
1701 loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
1702 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1703 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1704 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[14]) + meshvertices * sizeof(int[4]) + meshvertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]));
1705 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1706 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1707 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1708 loadmodel->surfmesh.num_vertices = meshvertices;
1709 loadmodel->surfmesh.num_triangles = meshtriangles;
1710 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1711 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1712 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1713 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1714 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1715 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1716 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1717 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1718 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1719 loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1720 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1721 if (loadmodel->surfmesh.num_vertices <= 65536)
1723 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
1724 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1725 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1728 //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
1729 poses = (float *) (pheader->lump_poses.start + pbase);
1730 for (i = 0;i < pheader->lump_poses.length / 4;i++)
1731 loadmodel->data_poses[i] = BigFloat(poses[i]);
1733 //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1734 verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1735 vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase);
1736 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
1737 // (converting from weight-blending skeletal animation to
1738 // deformation-based skeletal animation)
1739 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
1740 for (i = 0;i < loadmodel->num_bones;i++)
1742 const float *m = loadmodel->data_poses + i * 12;
1743 if (loadmodel->data_bones[i].parent >= 0)
1744 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
1746 for (k = 0;k < 12;k++)
1747 bonepose[12*i+k] = m[k];
1749 for (j = 0;j < pheader->numverts;j++)
1751 // this format really should have had a per vertexweight weight value...
1752 // but since it does not, the weighting is completely ignored and
1753 // only one weight is allowed per vertex
1754 int boneindex = BigLong(vertdata[j].bonenum);
1755 const float *m = bonepose + 12 * boneindex;
1756 float relativeorigin[3];
1757 relativeorigin[0] = BigFloat(vertdata[j].origin[0]);
1758 relativeorigin[1] = BigFloat(vertdata[j].origin[1]);
1759 relativeorigin[2] = BigFloat(vertdata[j].origin[2]);
1760 // transform the vertex bone weight into the base mesh
1761 loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3];
1762 loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7];
1763 loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11];
1764 // store the weight as the primary weight on this vertex
1765 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
1766 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = 1;
1769 // normals and tangents are calculated after elements are loaded
1771 //zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1772 outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f;
1773 intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase);
1774 for (i = 0;i < pheader->numverts;i++)
1776 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1777 // flip T coordinate for OpenGL
1778 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1781 //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1782 //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1783 //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);
1785 //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1786 //zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
1787 // byteswap, validate, and swap winding order of tris
1788 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1789 if (pheader->lump_render.length != count)
1790 Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count);
1791 renderlist = (int *) (pheader->lump_render.start + pbase);
1792 renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length);
1794 for (i = 0;i < loadmodel->num_surfaces;i++)
1796 int firstvertex, lastvertex;
1797 if (renderlist >= renderlistend)
1798 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1799 count = BigLong(*renderlist);renderlist++;
1800 if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend))
1801 Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name);
1803 loadmodel->surfacelist[i] = i;
1804 surface = loadmodel->data_surfaces + i;
1805 surface->texture = loadmodel->data_textures + i;
1806 surface->num_firsttriangle = meshtriangles;
1807 surface->num_triangles = count;
1808 meshtriangles += surface->num_triangles;
1810 // load the elements
1811 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1812 for (j = 0;j < surface->num_triangles;j++, renderlist += 3)
1814 outelements[j*3+2] = BigLong(renderlist[0]);
1815 outelements[j*3+1] = BigLong(renderlist[1]);
1816 outelements[j*3+0] = BigLong(renderlist[2]);
1818 // validate the elements and find the used vertex range
1819 firstvertex = meshvertices;
1821 for (j = 0;j < surface->num_triangles * 3;j++)
1823 if ((unsigned int)outelements[j] >= (unsigned int)meshvertices)
1824 Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name);
1825 firstvertex = min(firstvertex, outelements[j]);
1826 lastvertex = max(lastvertex, outelements[j]);
1828 surface->num_firstvertex = firstvertex;
1829 surface->num_vertices = lastvertex + 1 - firstvertex;
1831 // since zym models do not have named sections, reuse their shader
1832 // name as the section name
1833 shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32;
1834 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername);
1836 Mod_FreeSkinFiles(skinfiles);
1837 Mem_Free(vertbonecounts);
1840 // compute all the mesh information that was not loaded from the file
1841 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
1842 Mod_BuildBaseBonePoses();
1843 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
1844 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
1845 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
1847 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
1850 void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
1852 dpmheader_t *pheader;
1856 unsigned char *pbase;
1857 int i, j, k, meshvertices, meshtriangles;
1858 skinfile_t *skinfiles;
1859 unsigned char *data;
1862 pheader = (dpmheader_t *)buffer;
1863 pbase = (unsigned char *)buffer;
1864 if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16))
1865 Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name);
1866 if (BigLong(pheader->type) != 2)
1867 Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name);
1869 loadmodel->modeldatatypestring = "DPM";
1871 loadmodel->type = mod_alias;
1872 loadmodel->synctype = ST_RAND;
1875 pheader->type = BigLong(pheader->type);
1876 pheader->filesize = BigLong(pheader->filesize);
1877 pheader->mins[0] = BigFloat(pheader->mins[0]);
1878 pheader->mins[1] = BigFloat(pheader->mins[1]);
1879 pheader->mins[2] = BigFloat(pheader->mins[2]);
1880 pheader->maxs[0] = BigFloat(pheader->maxs[0]);
1881 pheader->maxs[1] = BigFloat(pheader->maxs[1]);
1882 pheader->maxs[2] = BigFloat(pheader->maxs[2]);
1883 pheader->yawradius = BigFloat(pheader->yawradius);
1884 pheader->allradius = BigFloat(pheader->allradius);
1885 pheader->num_bones = BigLong(pheader->num_bones);
1886 pheader->num_meshs = BigLong(pheader->num_meshs);
1887 pheader->num_frames = BigLong(pheader->num_frames);
1888 pheader->ofs_bones = BigLong(pheader->ofs_bones);
1889 pheader->ofs_meshs = BigLong(pheader->ofs_meshs);
1890 pheader->ofs_frames = BigLong(pheader->ofs_frames);
1892 if (pheader->num_bones < 1 || pheader->num_meshs < 1)
1894 Con_Printf("%s has no geometry\n", loadmodel->name);
1897 if (pheader->num_frames < 1)
1899 Con_Printf("%s has no frames\n", loadmodel->name);
1903 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
1904 loadmodel->DrawSky = NULL;
1905 loadmodel->DrawAddWaterPlanes = NULL;
1906 loadmodel->Draw = R_Q1BSP_Draw;
1907 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
1908 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
1909 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
1910 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
1911 loadmodel->DrawLight = R_Q1BSP_DrawLight;
1912 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
1913 loadmodel->PointSuperContents = NULL;
1916 for (i = 0;i < 3;i++)
1918 loadmodel->normalmins[i] = pheader->mins[i];
1919 loadmodel->normalmaxs[i] = pheader->maxs[i];
1920 loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i];
1921 loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i];
1922 loadmodel->rotatedmins[i] = -pheader->allradius;
1923 loadmodel->rotatedmaxs[i] = pheader->allradius;
1925 loadmodel->radius = pheader->allradius;
1926 loadmodel->radius2 = pheader->allradius * pheader->allradius;
1928 // load external .skin files if present
1929 skinfiles = Mod_LoadSkinFiles();
1930 if (loadmodel->numskins < 1)
1931 loadmodel->numskins = 1;
1936 // gather combined statistics from the meshes
1937 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
1938 for (i = 0;i < (int)pheader->num_meshs;i++)
1940 int numverts = BigLong(dpmmesh->num_verts);
1941 meshvertices += numverts;;
1942 meshtriangles += BigLong(dpmmesh->num_tris);
1946 loadmodel->numframes = pheader->num_frames;
1947 loadmodel->num_bones = pheader->num_bones;
1948 loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
1949 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
1950 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
1951 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
1952 // do most allocations as one merged chunk
1953 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshtriangles * sizeof(int[3]) + meshvertices * (sizeof(float[14]) + sizeof(int[4]) + sizeof(float[4])) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
1954 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
1955 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
1956 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
1957 loadmodel->surfmesh.num_vertices = meshvertices;
1958 loadmodel->surfmesh.num_triangles = meshtriangles;
1959 loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1960 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
1961 loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
1962 loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1963 loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
1964 loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]);
1965 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
1966 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += meshvertices * sizeof(int[4]);
1967 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += meshvertices * sizeof(float[4]);
1968 loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
1969 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
1970 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
1971 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
1972 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
1973 if (meshvertices <= 65536)
1975 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
1976 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
1977 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
1980 for (i = 0;i < loadmodel->numskins;i++)
1982 loadmodel->skinscenes[i].firstframe = i;
1983 loadmodel->skinscenes[i].framecount = 1;
1984 loadmodel->skinscenes[i].loop = true;
1985 loadmodel->skinscenes[i].framerate = 10;
1988 // load the bone info
1989 bone = (dpmbone_t *) (pbase + pheader->ofs_bones);
1990 for (i = 0;i < loadmodel->num_bones;i++)
1992 memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name));
1993 loadmodel->data_bones[i].flags = BigLong(bone[i].flags);
1994 loadmodel->data_bones[i].parent = BigLong(bone[i].parent);
1995 if (loadmodel->data_bones[i].parent >= i)
1996 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
2000 frame = (dpmframe_t *) (pbase + pheader->ofs_frames);
2001 for (i = 0;i < loadmodel->numframes;i++)
2004 memcpy(loadmodel->animscenes[i].name, frame->name, sizeof(frame->name));
2005 loadmodel->animscenes[i].firstframe = i;
2006 loadmodel->animscenes[i].framecount = 1;
2007 loadmodel->animscenes[i].loop = true;
2008 loadmodel->animscenes[i].framerate = 10;
2009 // load the bone poses for this frame
2010 poses = (float *) (pbase + BigLong(frame->ofs_bonepositions));
2011 for (j = 0;j < loadmodel->num_bones*12;j++)
2012 loadmodel->data_poses[i * loadmodel->num_bones*12 + j] = BigFloat(poses[j]);
2013 // stuff not processed here: mins, maxs, yawradius, allradius
2017 // load the meshes now
2018 dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs);
2021 // reconstruct frame 0 matrices to allow reconstruction of the base mesh
2022 // (converting from weight-blending skeletal animation to
2023 // deformation-based skeletal animation)
2024 bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12]));
2025 for (i = 0;i < loadmodel->num_bones;i++)
2027 const float *m = loadmodel->data_poses + i * 12;
2028 if (loadmodel->data_bones[i].parent >= 0)
2029 R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i);
2031 for (k = 0;k < 12;k++)
2032 bonepose[12*i+k] = m[k];
2034 for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++)
2036 const int *inelements;
2038 const float *intexcoord;
2039 msurface_t *surface;
2041 loadmodel->surfacelist[i] = i;
2042 surface = loadmodel->data_surfaces + i;
2043 surface->texture = loadmodel->data_textures + i;
2044 surface->num_firsttriangle = meshtriangles;
2045 surface->num_triangles = BigLong(dpmmesh->num_tris);
2046 surface->num_firstvertex = meshvertices;
2047 surface->num_vertices = BigLong(dpmmesh->num_verts);
2048 meshvertices += surface->num_vertices;
2049 meshtriangles += surface->num_triangles;
2051 inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices));
2052 outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3;
2053 for (j = 0;j < surface->num_triangles;j++)
2055 // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard)
2056 outelements[0] = surface->num_firstvertex + BigLong(inelements[2]);
2057 outelements[1] = surface->num_firstvertex + BigLong(inelements[1]);
2058 outelements[2] = surface->num_firstvertex + BigLong(inelements[0]);
2063 intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords));
2064 for (j = 0;j < surface->num_vertices*2;j++)
2065 loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]);
2067 data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts));
2068 for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++)
2072 int numweights = BigLong(((dpmvertex_t *)data)->numbones);
2073 data += sizeof(dpmvertex_t);
2074 for (k = 0;k < numweights;k++)
2076 const dpmbonevert_t *vert = (dpmbonevert_t *) data;
2077 int boneindex = BigLong(vert->bonenum);
2078 const float *m = bonepose + 12 * boneindex;
2079 float influence = BigFloat(vert->influence);
2080 float relativeorigin[3], relativenormal[3];
2081 relativeorigin[0] = BigFloat(vert->origin[0]);
2082 relativeorigin[1] = BigFloat(vert->origin[1]);
2083 relativeorigin[2] = BigFloat(vert->origin[2]);
2084 relativenormal[0] = BigFloat(vert->normal[0]);
2085 relativenormal[1] = BigFloat(vert->normal[1]);
2086 relativenormal[2] = BigFloat(vert->normal[2]);
2087 // blend the vertex bone weights into the base mesh
2088 loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3];
2089 loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7];
2090 loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11];
2091 loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2];
2092 loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6];
2093 loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10];
2096 // store the first (and often only) weight
2097 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+0] = influence;
2098 loadmodel->surfmesh.data_vertexweightindex4i[j*4+0] = boneindex;
2102 // sort the new weight into this vertex's weight table
2103 // (which only accepts up to 4 bones per vertex)
2104 for (l = 0;l < 4;l++)
2106 if (loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] < influence)
2108 // move weaker influence weights out of the way first
2110 for (l2 = 3;l2 > l;l2--)
2112 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l2-1];
2113 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[j*4+l2-1];
2115 // store the new weight
2116 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] = influence;
2117 loadmodel->surfmesh.data_vertexweightindex4i[j*4+l] = boneindex;
2122 data += sizeof(dpmbonevert_t);
2125 for (l = 0;l < 4;l++)
2126 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l];
2127 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2129 float f = 1.0f / sum;
2130 for (l = 0;l < 4;l++)
2131 loadmodel->surfmesh.data_vertexweightinfluence4f[j*4+l] *= f;
2135 // since dpm models do not have named sections, reuse their shader name as the section name
2136 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername);
2138 Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__);
2141 Mod_FreeSkinFiles(skinfiles);
2143 // compute all the mesh information that was not loaded from the file
2144 Mod_BuildBaseBonePoses();
2145 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
2146 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2148 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
2151 // no idea why PSK/PSA files contain weird quaternions but they do...
2152 #define PSKQUATNEGATIONS
2153 void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
2155 int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles;
2156 int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys;
2157 fs_offset_t filesize;
2162 pskboneinfo_t *bones;
2163 pskrawweights_t *rawweights;
2164 pskboneinfo_t *animbones;
2165 pskaniminfo_t *anims;
2166 pskanimkeys_t *animkeys;
2167 void *animfilebuffer, *animbuffer, *animbufferend;
2168 unsigned char *data;
2170 skinfile_t *skinfiles;
2171 char animname[MAX_QPATH];
2174 pchunk = (pskchunk_t *)buffer;
2175 if (strcmp(pchunk->id, "ACTRHEAD"))
2176 Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name);
2178 loadmodel->modeldatatypestring = "PSK";
2180 loadmodel->type = mod_alias;
2181 loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
2182 loadmodel->DrawSky = NULL;
2183 loadmodel->DrawAddWaterPlanes = NULL;
2184 loadmodel->Draw = R_Q1BSP_Draw;
2185 loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
2186 loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
2187 loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
2188 loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
2189 loadmodel->DrawLight = R_Q1BSP_DrawLight;
2190 loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
2191 loadmodel->PointSuperContents = NULL;
2192 loadmodel->synctype = ST_RAND;
2194 FS_StripExtension(loadmodel->name, animname, sizeof(animname));
2195 strlcat(animname, ".psa", sizeof(animname));
2196 animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
2197 animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
2198 if (animbuffer == NULL)
2199 Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
2218 while (buffer < bufferend)
2220 pchunk = (pskchunk_t *)buffer;
2221 buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t));
2222 version = LittleLong(pchunk->version);
2223 recordsize = LittleLong(pchunk->recordsize);
2224 numrecords = LittleLong(pchunk->numrecords);
2225 if (developer.integer >= 100)
2226 Con_Printf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2227 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2228 Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version);
2229 if (!strcmp(pchunk->id, "ACTRHEAD"))
2233 else if (!strcmp(pchunk->id, "PNTS0000"))
2236 if (recordsize != sizeof(*p))
2237 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2238 // byteswap in place and keep the pointer
2239 numpnts = numrecords;
2240 pnts = (pskpnts_t *)buffer;
2241 for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++)
2243 p->origin[0] = LittleFloat(p->origin[0]);
2244 p->origin[1] = LittleFloat(p->origin[1]);
2245 p->origin[2] = LittleFloat(p->origin[2]);
2249 else if (!strcmp(pchunk->id, "VTXW0000"))
2252 if (recordsize != sizeof(*p))
2253 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2254 // byteswap in place and keep the pointer
2255 numvtxw = numrecords;
2256 vtxw = (pskvtxw_t *)buffer;
2257 for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++)
2259 p->pntsindex = LittleShort(p->pntsindex);
2260 p->texcoord[0] = LittleFloat(p->texcoord[0]);
2261 p->texcoord[1] = LittleFloat(p->texcoord[1]);
2262 if (p->pntsindex >= numpnts)
2264 Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2270 else if (!strcmp(pchunk->id, "FACE0000"))
2273 if (recordsize != sizeof(*p))
2274 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2275 // byteswap in place and keep the pointer
2276 numfaces = numrecords;
2277 faces = (pskface_t *)buffer;
2278 for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++)
2280 p->vtxwindex[0] = LittleShort(p->vtxwindex[0]);
2281 p->vtxwindex[1] = LittleShort(p->vtxwindex[1]);
2282 p->vtxwindex[2] = LittleShort(p->vtxwindex[2]);
2283 p->group = LittleLong(p->group);
2284 if (p->vtxwindex[0] >= numvtxw)
2286 Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw);
2287 p->vtxwindex[0] = 0;
2289 if (p->vtxwindex[1] >= numvtxw)
2291 Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw);
2292 p->vtxwindex[1] = 0;
2294 if (p->vtxwindex[2] >= numvtxw)
2296 Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw);
2297 p->vtxwindex[2] = 0;
2302 else if (!strcmp(pchunk->id, "MATT0000"))
2305 if (recordsize != sizeof(*p))
2306 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2307 // byteswap in place and keep the pointer
2308 nummatts = numrecords;
2309 matts = (pskmatt_t *)buffer;
2310 for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++)
2316 else if (!strcmp(pchunk->id, "REFSKELT"))
2319 if (recordsize != sizeof(*p))
2320 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2321 // byteswap in place and keep the pointer
2322 numbones = numrecords;
2323 bones = (pskboneinfo_t *)buffer;
2324 for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++)
2326 p->numchildren = LittleLong(p->numchildren);
2327 p->parent = LittleLong(p->parent);
2328 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2329 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2330 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2331 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2332 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2333 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2334 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2335 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2336 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2337 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2338 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2339 #ifdef PSKQUATNEGATIONS
2342 p->basepose.quat[0] *= -1;
2343 p->basepose.quat[1] *= -1;
2344 p->basepose.quat[2] *= -1;
2348 p->basepose.quat[0] *= 1;
2349 p->basepose.quat[1] *= -1;
2350 p->basepose.quat[2] *= 1;
2353 if (p->parent < 0 || p->parent >= numbones)
2355 Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones);
2361 else if (!strcmp(pchunk->id, "RAWWEIGHTS"))
2364 if (recordsize != sizeof(*p))
2365 Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id);
2366 // byteswap in place and keep the pointer
2367 numrawweights = numrecords;
2368 rawweights = (pskrawweights_t *)buffer;
2369 for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++)
2371 p->weight = LittleFloat(p->weight);
2372 p->pntsindex = LittleLong(p->pntsindex);
2373 p->boneindex = LittleLong(p->boneindex);
2374 if (p->pntsindex < 0 || p->pntsindex >= numpnts)
2376 Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts);
2379 if (p->boneindex < 0 || p->boneindex >= numbones)
2381 Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones);
2389 while (animbuffer < animbufferend)
2391 pchunk = (pskchunk_t *)animbuffer;
2392 animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t));
2393 version = LittleLong(pchunk->version);
2394 recordsize = LittleLong(pchunk->recordsize);
2395 numrecords = LittleLong(pchunk->numrecords);
2396 if (developer.integer >= 100)
2397 Con_Printf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords);
2398 if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0)
2399 Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version);
2400 if (!strcmp(pchunk->id, "ANIMHEAD"))
2404 else if (!strcmp(pchunk->id, "BONENAMES"))
2407 if (recordsize != sizeof(*p))
2408 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2409 // byteswap in place and keep the pointer
2410 numanimbones = numrecords;
2411 animbones = (pskboneinfo_t *)animbuffer;
2412 // NOTE: supposedly psa does not need to match the psk model, the
2413 // bones missing from the psa would simply use their base
2414 // positions from the psk, but this is hard for me to implement
2415 // and people can easily make animations that match.
2416 if (numanimbones != numbones)
2417 Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name);
2418 for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++)
2420 p->numchildren = LittleLong(p->numchildren);
2421 p->parent = LittleLong(p->parent);
2422 p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]);
2423 p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]);
2424 p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]);
2425 p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]);
2426 p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]);
2427 p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]);
2428 p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]);
2429 p->basepose.unknown = LittleFloat(p->basepose.unknown);
2430 p->basepose.size[0] = LittleFloat(p->basepose.size[0]);
2431 p->basepose.size[1] = LittleFloat(p->basepose.size[1]);
2432 p->basepose.size[2] = LittleFloat(p->basepose.size[2]);
2433 #ifdef PSKQUATNEGATIONS
2436 p->basepose.quat[0] *= -1;
2437 p->basepose.quat[1] *= -1;
2438 p->basepose.quat[2] *= -1;
2442 p->basepose.quat[0] *= 1;
2443 p->basepose.quat[1] *= -1;
2444 p->basepose.quat[2] *= 1;
2447 if (p->parent < 0 || p->parent >= numanimbones)
2449 Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones);
2452 // check that bones are the same as in the base
2453 if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent)
2454 Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname);
2458 else if (!strcmp(pchunk->id, "ANIMINFO"))
2461 if (recordsize != sizeof(*p))
2462 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2463 // byteswap in place and keep the pointer
2464 numanims = numrecords;
2465 anims = (pskaniminfo_t *)animbuffer;
2466 for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++)
2468 p->numbones = LittleLong(p->numbones);
2469 p->playtime = LittleFloat(p->playtime);
2470 p->fps = LittleFloat(p->fps);
2471 p->firstframe = LittleLong(p->firstframe);
2472 p->numframes = LittleLong(p->numframes);
2473 if (p->numbones != numbones)
2474 Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname);
2478 else if (!strcmp(pchunk->id, "ANIMKEYS"))
2481 if (recordsize != sizeof(*p))
2482 Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id);
2483 numanimkeys = numrecords;
2484 animkeys = (pskanimkeys_t *)animbuffer;
2485 for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++)
2487 p->origin[0] = LittleFloat(p->origin[0]);
2488 p->origin[1] = LittleFloat(p->origin[1]);
2489 p->origin[2] = LittleFloat(p->origin[2]);
2490 p->quat[0] = LittleFloat(p->quat[0]);
2491 p->quat[1] = LittleFloat(p->quat[1]);
2492 p->quat[2] = LittleFloat(p->quat[2]);
2493 p->quat[3] = LittleFloat(p->quat[3]);
2494 p->frametime = LittleFloat(p->frametime);
2495 #ifdef PSKQUATNEGATIONS
2496 if (index % numbones)
2511 // TODO: allocate bonepose stuff
2514 Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
2517 if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
2518 Host_Error("%s: missing required chunks", loadmodel->name);
2520 loadmodel->numframes = 0;
2521 for (index = 0;index < numanims;index++)
2522 loadmodel->numframes += anims[index].numframes;
2524 if (numanimkeys != numbones * loadmodel->numframes)
2525 Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id);
2527 meshvertices = numvtxw;
2528 meshtriangles = numfaces;
2530 // load external .skin files if present
2531 skinfiles = Mod_LoadSkinFiles();
2532 if (loadmodel->numskins < 1)
2533 loadmodel->numskins = 1;
2534 loadmodel->num_bones = numbones;
2535 loadmodel->num_poses = loadmodel->num_bones * loadmodel->numframes;
2536 loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts;
2537 loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
2538 loadmodel->num_texturesperskin = loadmodel->num_surfaces;
2539 loadmodel->surfmesh.num_vertices = meshvertices;
2540 loadmodel->surfmesh.num_triangles = meshtriangles;
2541 // do most allocations as one merged chunk
2542 size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2543 data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size);
2544 loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
2545 loadmodel->surfacelist = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
2546 loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
2547 loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2548 loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
2549 loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2550 loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2551 loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2552 loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2553 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2554 loadmodel->surfmesh.data_vertexweightindex4i = (int *)data;data += loadmodel->surfmesh.num_vertices * sizeof(int[4]);
2555 loadmodel->surfmesh.data_vertexweightinfluence4f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2556 loadmodel->data_poses = (float *)data;data += loadmodel->num_poses * sizeof(float[12]);
2557 loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]);
2558 loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t);
2559 loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t);
2560 loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t);
2561 if (loadmodel->surfmesh.num_vertices <= 65536)
2563 loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
2564 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2565 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2567 if (data != (unsigned char *)loadmodel->data_surfaces + size)
2568 Sys_Error("%s: combined alloc has wrong size! (%i bytes should be %i)\n", loadmodel->name, (int)size, (int)(data - (unsigned char *)loadmodel->data_surfaces));
2570 for (i = 0;i < loadmodel->numskins;i++)
2572 loadmodel->skinscenes[i].firstframe = i;
2573 loadmodel->skinscenes[i].framecount = 1;
2574 loadmodel->skinscenes[i].loop = true;
2575 loadmodel->skinscenes[i].framerate = 10;
2579 for (index = 0, i = 0;index < nummatts;index++)
2581 // since psk models do not have named sections, reuse their shader name as the section name
2582 Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name);
2583 loadmodel->surfacelist[index] = index;
2584 loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index;
2585 loadmodel->data_surfaces[index].num_firstvertex = 0;
2586 loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices;
2589 // copy over the vertex locations and texcoords
2590 for (index = 0;index < numvtxw;index++)
2592 loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0];
2593 loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1];
2594 loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2];
2595 loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0];
2596 loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1];
2599 // loading the faces is complicated because we need to sort them into surfaces by mattindex
2600 for (index = 0;index < numfaces;index++)
2601 loadmodel->data_surfaces[faces[index].mattindex].num_triangles++;
2602 for (index = 0, i = 0;index < nummatts;index++)
2604 loadmodel->data_surfaces[index].num_firsttriangle = i;
2605 i += loadmodel->data_surfaces[index].num_triangles;
2606 loadmodel->data_surfaces[index].num_triangles = 0;
2608 for (index = 0;index < numfaces;index++)
2610 i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3;
2611 loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0];
2612 loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1];
2613 loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2];
2616 // copy over the bones
2617 for (index = 0;index < numbones;index++)
2619 strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name));
2620 loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1;
2621 if (loadmodel->data_bones[index].parent >= index)
2622 Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index);
2625 // sort the psk point weights into the vertex weight tables
2626 // (which only accept up to 4 bones per vertex)
2627 for (index = 0;index < numvtxw;index++)
2631 for (j = 0;j < numrawweights;j++)
2633 if (rawweights[j].pntsindex == vtxw[index].pntsindex)
2635 int boneindex = rawweights[j].boneindex;
2636 float influence = rawweights[j].weight;
2637 for (l = 0;l < 4;l++)
2639 if (loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] < influence)
2641 // move lower influence weights out of the way first
2643 for (l2 = 3;l2 > l;l2--)
2645 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2] = loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l2-1];
2646 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2] = loadmodel->surfmesh.data_vertexweightindex4i[index*4+l2-1];
2648 // store the new weight
2649 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] = influence;
2650 loadmodel->surfmesh.data_vertexweightindex4i[index*4+l] = boneindex;
2657 for (l = 0;l < 4;l++)
2658 sum += loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l];
2659 if (sum && fabs(sum - 1) > (1.0f / 256.0f))
2661 float f = 1.0f / sum;
2662 for (l = 0;l < 4;l++)
2663 loadmodel->surfmesh.data_vertexweightinfluence4f[index*4+l] *= f;
2667 // set up the animscenes based on the anims
2668 for (index = 0, i = 0;index < numanims;index++)
2670 for (j = 0;j < anims[index].numframes;j++, i++)
2672 dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j);
2673 loadmodel->animscenes[i].firstframe = i;
2674 loadmodel->animscenes[i].framecount = 1;
2675 loadmodel->animscenes[i].loop = true;
2676 loadmodel->animscenes[i].framerate = 10;
2680 // load the poses from the animkeys
2681 for (index = 0;index < numanimkeys;index++)
2683 pskanimkeys_t *k = animkeys + index;
2685 Matrix4x4_FromOriginQuat(&matrix, k->origin[0], k->origin[1], k->origin[2], k->quat[0], k->quat[1], k->quat[2], k->quat[3]);
2686 Matrix4x4_ToArray12FloatD3D(&matrix, loadmodel->data_poses + index*12);
2688 Mod_FreeSkinFiles(skinfiles);
2689 Mem_Free(animfilebuffer);
2691 // compute all the mesh information that was not loaded from the file
2692 // TODO: honor smoothing groups somehow?
2693 Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__);
2694 Mod_BuildBaseBonePoses();
2695 Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, true);
2696 Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
2697 Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
2698 Mod_Alias_CalculateBoundingBox();
2700 size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(int[4]) + loadmodel->surfmesh.num_vertices * sizeof(float[4]) + loadmodel->num_poses * sizeof(float[12]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0);
2701 if (size != ((memheader_t *)loadmodel->data_surfaces)[-1].size)
2702 Sys_Error("%s:%i: %i != %i", __FILE__, __LINE__, (int)size, (int)((memheader_t *)loadmodel->data_surfaces)[-1].size);
2704 loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;