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 static cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"};
27 void Mod_AliasInit (void)
29 Cvar_RegisterVariable(&r_mipskins);
32 static void Mod_CalcAliasModelBBoxes (void)
35 float dist, yawradius, radius;
38 VectorClear(loadmodel->normalmins);
39 VectorClear(loadmodel->normalmaxs);
42 for (meshnum = 0, mesh = loadmodel->aliasdata_meshes;meshnum < loadmodel->aliasnum_meshes;meshnum++, mesh++)
44 for (vnum = 0, v = mesh->data_aliasvertex;vnum < mesh->num_vertices * mesh->num_frames;vnum++, v++)
46 if (loadmodel->normalmins[0] > v->origin[0]) loadmodel->normalmins[0] = v->origin[0];
47 if (loadmodel->normalmins[1] > v->origin[1]) loadmodel->normalmins[1] = v->origin[1];
48 if (loadmodel->normalmins[2] > v->origin[2]) loadmodel->normalmins[2] = v->origin[2];
49 if (loadmodel->normalmaxs[0] < v->origin[0]) loadmodel->normalmaxs[0] = v->origin[0];
50 if (loadmodel->normalmaxs[1] < v->origin[1]) loadmodel->normalmaxs[1] = v->origin[1];
51 if (loadmodel->normalmaxs[2] < v->origin[2]) loadmodel->normalmaxs[2] = v->origin[2];
52 dist = v->origin[0] * v->origin[0] + v->origin[1] * v->origin[1];
55 dist += v->origin[2] * v->origin[2];
60 radius = sqrt(radius);
61 yawradius = sqrt(yawradius);
62 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
63 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
64 loadmodel->yawmins[2] = loadmodel->normalmins[2];
65 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
66 loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
67 loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
68 loadmodel->radius = radius;
69 loadmodel->radius2 = radius * radius;
72 static void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, aliasvertex_t *out, int *vertremap)
76 for (i = 0;i < inverts;i++)
78 if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
80 temp[0] = v[i].v[0] * scale[0] + translate[0];
81 temp[1] = v[i].v[1] * scale[1] + translate[1];
82 temp[2] = v[i].v[2] * scale[2] + translate[2];
83 j = vertremap[i]; // not onseam
85 VectorCopy(temp, out[j].origin);
86 j = vertremap[i+inverts]; // onseam
88 VectorCopy(temp, out[j].origin);
92 static void Mod_BuildAliasVertexTextureVectors(int numverts, aliasvertex_t *vertices, const float *texcoords, float *vertexbuffer, float *svectorsbuffer, float *tvectorsbuffer, float *normalsbuffer, int numtriangles, const int *elements)
95 for (i = 0;i < numverts;i++)
96 VectorCopy(vertices[i].origin, &vertexbuffer[i * 3]);
97 Mod_BuildTextureVectorsAndNormals(numverts, numtriangles, vertexbuffer, texcoords, elements, svectorsbuffer, tvectorsbuffer, normalsbuffer);
98 for (i = 0;i < numverts;i++)
100 vertices[i].normal[0] = normalsbuffer[i * 3 + 0];
101 vertices[i].normal[1] = normalsbuffer[i * 3 + 1];
102 vertices[i].normal[2] = normalsbuffer[i * 3 + 2];
103 vertices[i].svector[0] = svectorsbuffer[i * 3 + 0];
104 vertices[i].svector[1] = svectorsbuffer[i * 3 + 1];
105 vertices[i].svector[2] = svectorsbuffer[i * 3 + 2];
109 static void Mod_MDL_LoadFrames (qbyte* datapointer, int inverts, int outverts, vec3_t scale, vec3_t translate, float *texcoords, aliasvertex_t *posedata, int numtris, int *elements, int *vertremap)
111 int i, f, pose, groupframes;
112 float interval, *vertexbuffer, *svectorsbuffer, *tvectorsbuffer, *normalsbuffer;
113 daliasframetype_t *pframetype;
114 daliasframe_t *pinframe;
115 daliasgroup_t *group;
116 daliasinterval_t *intervals;
119 scene = loadmodel->animscenes;
120 vertexbuffer = Mem_Alloc(tempmempool, outverts * sizeof(float[3+3+3+3]));
121 svectorsbuffer = vertexbuffer + outverts * 3;
122 tvectorsbuffer = svectorsbuffer + outverts * 3;
123 normalsbuffer = tvectorsbuffer + outverts * 3;
124 for (f = 0;f < loadmodel->numframes;f++)
126 pframetype = (daliasframetype_t *)datapointer;
127 datapointer += sizeof(daliasframetype_t);
128 if (LittleLong (pframetype->type) == ALIAS_SINGLE)
130 // a single frame is still treated as a group
137 group = (daliasgroup_t *)datapointer;
138 datapointer += sizeof(daliasgroup_t);
139 groupframes = LittleLong (group->numframes);
141 // intervals (time per frame)
142 intervals = (daliasinterval_t *)datapointer;
143 datapointer += sizeof(daliasinterval_t) * groupframes;
145 interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
146 if (interval < 0.01f)
147 Host_Error("Mod_MDL_LoadFrames: invalid interval");
150 // get scene name from first frame
151 pinframe = (daliasframe_t *)datapointer;
153 strcpy(scene->name, pinframe->name);
154 scene->firstframe = pose;
155 scene->framecount = groupframes;
156 scene->framerate = 1.0f / interval;
161 for (i = 0;i < groupframes;i++)
163 pinframe = (daliasframe_t *)datapointer;
164 datapointer += sizeof(daliasframe_t);
165 Mod_ConvertAliasVerts(inverts, scale, translate, (trivertx_t *)datapointer, posedata + pose * outverts, vertremap);
166 Mod_BuildAliasVertexTextureVectors(outverts, posedata + pose * outverts, texcoords, vertexbuffer, svectorsbuffer, tvectorsbuffer, normalsbuffer, numtris, elements);
167 datapointer += sizeof(trivertx_t) * inverts;
171 Mem_Free(vertexbuffer);
174 aliaslayer_t mod_alias_layersbuffer[16]; // 7 currently used
175 void Mod_BuildAliasSkinFromSkinFrame(aliasskin_t *skin, skinframe_t *skinframe)
179 memset(&mod_alias_layersbuffer, 0, sizeof(mod_alias_layersbuffer));
180 layer = mod_alias_layersbuffer;
181 layer->flags = ALIASLAYER_SPECULAR;
182 layer->texture = skinframe->gloss;
183 layer->nmap = skinframe->nmap;
185 if (skinframe->merged != NULL)
187 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_COLORMAPPED;
188 layer->texture = skinframe->merged;
189 layer->nmap = skinframe->nmap;
192 if (skinframe->base != NULL)
194 layer->flags = ALIASLAYER_DIFFUSE;
195 if (skinframe->merged != NULL)
196 layer->flags |= ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED;
197 layer->texture = skinframe->base;
198 layer->nmap = skinframe->nmap;
201 if (skinframe->pants != NULL)
203 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_PANTS;
204 layer->texture = skinframe->pants;
205 layer->nmap = skinframe->nmap;
208 if (skinframe->shirt != NULL)
210 layer->flags = ALIASLAYER_DIFFUSE | ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED | ALIASLAYER_COLORMAP_SHIRT;
211 layer->texture = skinframe->shirt;
212 layer->nmap = skinframe->nmap;
216 if (skinframe->glow != NULL)
219 layer->texture = skinframe->glow;
221 layer->flags = ALIASLAYER_FOG;
222 layer->texture = skinframe->fog;
227 layer->flags = ALIASLAYER_FOG | ALIASLAYER_FORCEDRAW_IF_FIRSTPASS;
228 layer->texture = skinframe->fog;
233 // fog texture only exists if some pixels are transparent...
234 if (skinframe->fog != NULL)
235 skin->flags |= ALIASSKIN_TRANSPARENT;
237 skin->num_layers = layer - mod_alias_layersbuffer;
238 skin->data_layers = Mem_Alloc(loadmodel->mempool, skin->num_layers * sizeof(aliaslayer_t));
239 memcpy(skin->data_layers, mod_alias_layersbuffer, skin->num_layers * sizeof(aliaslayer_t));
242 void Mod_BuildMDLMD2MeshInfo(int numverts, int numtris, int *elements, float *texcoord2f, aliasvertex_t *posedata)
247 loadmodel->aliasnum_meshes = 1;
248 mesh = loadmodel->aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->aliasnum_meshes * sizeof(aliasmesh_t));
250 mesh->num_frames = 0;
251 for (i = 0;i < loadmodel->numframes;i++)
252 mesh->num_frames += loadmodel->animscenes[i].framecount;
253 for (i = 0;i < loadmodel->numskins;i++)
254 mesh->num_skins += loadmodel->skinscenes[i].framecount;
255 mesh->num_triangles = numtris;
256 mesh->num_vertices = numverts;
257 mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t));
258 mesh->data_element3i = elements;
259 mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, numtris * sizeof(int[3]));
260 Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
261 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
262 mesh->data_texcoord2f = texcoord2f;
263 mesh->data_aliasvertex = posedata;
264 for (i = 0;i < mesh->num_skins;i++)
265 Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins + i, loadmodel->skinframes + i);
266 Mod_CalcAliasModelBBoxes();
269 #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX);
270 #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX);
271 extern void R_Model_Alias_Draw(entity_render_t *ent);
272 extern void R_Model_Alias_DrawFakeShadow(entity_render_t *ent);
273 extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
274 extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
275 void Mod_LoadQ1AliasModel (model_t *mod, void *buffer)
277 int i, j, version, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins, *elements, numverts, numtris;
278 float scales, scalet, scale[3], translate[3], interval, *texcoords;
280 stvert_t *pinstverts;
281 dtriangle_t *pintriangles;
282 daliasskintype_t *pinskintype;
283 daliasskingroup_t *pinskingroup;
284 daliasskininterval_t *pinskinintervals;
285 daliasframetype_t *pinframetype;
286 daliasgroup_t *pinframegroup;
287 aliasvertex_t *posedata;
288 qbyte *datapointer, *startframes, *startskins;
289 char name[MAX_QPATH];
290 skinframe_t tempskinframe;
291 animscene_t *tempskinscenes;
292 skinframe_t *tempskinframes;
294 int *vertonseam, *vertusage, *vertremap, *temptris;
296 datapointer = buffer;
297 pinmodel = (mdl_t *)datapointer;
298 datapointer += sizeof(mdl_t);
300 version = LittleLong (pinmodel->version);
301 if (version != ALIAS_VERSION)
302 Host_Error ("%s has wrong version number (%i should be %i)",
303 loadmodel->name, version, ALIAS_VERSION);
305 loadmodel->type = mod_alias;
306 loadmodel->aliastype = ALIASTYPE_ALIAS;
307 loadmodel->DrawSky = NULL;
308 loadmodel->Draw = R_Model_Alias_Draw;
309 loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
310 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
311 loadmodel->DrawLight = R_Model_Alias_DrawLight;
313 loadmodel->numskins = LittleLong(pinmodel->numskins);
314 BOUNDI(loadmodel->numskins,0,256);
315 skinwidth = LittleLong (pinmodel->skinwidth);
316 BOUNDI(skinwidth,0,4096);
317 skinheight = LittleLong (pinmodel->skinheight);
318 BOUNDI(skinheight,0,4096);
319 numverts = LittleLong(pinmodel->numverts);
320 BOUNDI(numverts,0,65536);
321 numtris = LittleLong(pinmodel->numtris);
322 BOUNDI(numtris,0,65536 / 3); // max elements limit, rather than max triangles limit
323 loadmodel->numframes = LittleLong(pinmodel->numframes);
324 BOUNDI(loadmodel->numframes,0,65536);
325 loadmodel->synctype = LittleLong (pinmodel->synctype);
326 BOUNDI(loadmodel->synctype,0,2);
327 loadmodel->flags = LittleLong (pinmodel->flags);
329 for (i = 0;i < 3;i++)
331 scale[i] = LittleFloat (pinmodel->scale[i]);
332 translate[i] = LittleFloat (pinmodel->scale_origin[i]);
335 startskins = datapointer;
337 for (i = 0;i < loadmodel->numskins;i++)
339 pinskintype = (daliasskintype_t *)datapointer;
340 datapointer += sizeof(daliasskintype_t);
341 if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
345 pinskingroup = (daliasskingroup_t *)datapointer;
346 datapointer += sizeof(daliasskingroup_t);
347 groupskins = LittleLong(pinskingroup->numskins);
348 datapointer += sizeof(daliasskininterval_t) * groupskins;
351 for (j = 0;j < groupskins;j++)
353 datapointer += skinwidth * skinheight;
358 pinstverts = (stvert_t *)datapointer;
359 datapointer += sizeof(stvert_t) * numverts;
361 pintriangles = (dtriangle_t *)datapointer;
362 datapointer += sizeof(dtriangle_t) * numtris;
364 startframes = datapointer;
366 for (i = 0;i < loadmodel->numframes;i++)
368 pinframetype = (daliasframetype_t *)datapointer;
369 datapointer += sizeof(daliasframetype_t);
370 if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
374 pinframegroup = (daliasgroup_t *)datapointer;
375 datapointer += sizeof(daliasgroup_t);
376 groupframes = LittleLong(pinframegroup->numframes);
377 datapointer += sizeof(daliasinterval_t) * groupframes;
380 for (j = 0;j < groupframes;j++)
382 datapointer += sizeof(daliasframe_t);
383 datapointer += sizeof(trivertx_t) * numverts;
389 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
390 loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, totalskins * sizeof(skinframe_t));
392 datapointer = startskins;
393 for (i = 0;i < loadmodel->numskins;i++)
395 pinskintype = (daliasskintype_t *)datapointer;
396 datapointer += sizeof(daliasskintype_t);
398 if (pinskintype->type == ALIAS_SKIN_SINGLE)
405 pinskingroup = (daliasskingroup_t *)datapointer;
406 datapointer += sizeof(daliasskingroup_t);
408 groupskins = LittleLong (pinskingroup->numskins);
410 pinskinintervals = (daliasskininterval_t *)datapointer;
411 datapointer += sizeof(daliasskininterval_t) * groupskins;
413 interval = LittleFloat(pinskinintervals[0].interval);
414 if (interval < 0.01f)
415 Host_Error("Mod_LoadQ1AliasModel: invalid interval\n");
418 sprintf(loadmodel->skinscenes[i].name, "skin %i", i);
419 loadmodel->skinscenes[i].firstframe = totalskins;
420 loadmodel->skinscenes[i].framecount = groupskins;
421 loadmodel->skinscenes[i].framerate = 1.0f / interval;
422 loadmodel->skinscenes[i].loop = true;
424 for (j = 0;j < groupskins;j++)
427 sprintf (name, "%s_%i_%i", loadmodel->name, i, j);
429 sprintf (name, "%s_%i", loadmodel->name, i);
430 if (!Mod_LoadSkinFrame(loadmodel->skinframes + totalskins, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true))
431 Mod_LoadSkinFrame_Internal(loadmodel->skinframes + totalskins, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true, (qbyte *)datapointer, skinwidth, skinheight);
432 datapointer += skinwidth * skinheight;
436 // check for skins that don't exist in the model, but do exist as external images
437 // (this was added because yummyluv kept pestering me about support for it)
440 sprintf (name, "%s_%i", loadmodel->name, loadmodel->numskins);
441 if (Mod_LoadSkinFrame (&tempskinframe, name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_CLAMP | TEXF_ALPHA, true, false, true))
443 // expand the arrays to make room
444 tempskinscenes = loadmodel->skinscenes;
445 tempskinframes = loadmodel->skinframes;
446 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t));
447 loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, (totalskins + 1) * sizeof(skinframe_t));
448 memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t));
449 memcpy(loadmodel->skinframes, tempskinframes, totalskins * sizeof(skinframe_t));
450 Mem_Free(tempskinscenes);
451 Mem_Free(tempskinframes);
452 // store the info about the new skin
453 strcpy(loadmodel->skinscenes[loadmodel->numskins].name, name);
454 loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins;
455 loadmodel->skinscenes[loadmodel->numskins].framecount = 1;
456 loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f;
457 loadmodel->skinscenes[loadmodel->numskins].loop = true;
458 loadmodel->skinframes[totalskins] = tempskinframe;
459 loadmodel->numskins++;
466 // store texture coordinates into temporary array, they will be stored after usage is determined (triangle data)
467 vertst = Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
468 vertonseam = Mem_Alloc(tempmempool, numverts * sizeof(int));
469 vertusage = Mem_Alloc(tempmempool, numverts * 2 * sizeof(int));
470 vertremap = Mem_Alloc(tempmempool, numverts * 2 * sizeof(int));
471 temptris = Mem_Alloc(tempmempool, numtris * sizeof(int[3]));
473 scales = 1.0 / skinwidth;
474 scalet = 1.0 / skinheight;
475 for (i = 0;i < numverts;i++)
477 vertonseam[i] = LittleLong(pinstverts[i].onseam);
478 vertst[i*2+0] = (LittleLong(pinstverts[i].s) + 0.5) * scales;
479 vertst[i*2+1] = (LittleLong(pinstverts[i].t) + 0.5) * scalet;
480 vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
481 vertst[(i+numverts)*2+1] = vertst[i*2+1];
483 vertusage[i+numverts] = 0;
486 // load triangle data
487 elements = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * numtris);
489 // count the vertices used
490 for (i = 0;i < numverts*2;i++)
492 for (i = 0;i < numtris;i++)
494 temptris[i*3+0] = LittleLong(pintriangles[i].vertindex[0]);
495 temptris[i*3+1] = LittleLong(pintriangles[i].vertindex[1]);
496 temptris[i*3+2] = LittleLong(pintriangles[i].vertindex[2]);
497 if (!LittleLong(pintriangles[i].facesfront)) // backface
499 if (vertonseam[temptris[i*3+0]]) temptris[i*3+0] += numverts;
500 if (vertonseam[temptris[i*3+1]]) temptris[i*3+1] += numverts;
501 if (vertonseam[temptris[i*3+2]]) temptris[i*3+2] += numverts;
503 vertusage[temptris[i*3+0]]++;
504 vertusage[temptris[i*3+1]]++;
505 vertusage[temptris[i*3+2]]++;
507 // build remapping table and compact array
509 for (i = 0;i < numverts*2;i++)
513 vertremap[i] = totalverts;
514 vertst[totalverts*2+0] = vertst[i*2+0];
515 vertst[totalverts*2+1] = vertst[i*2+1];
519 vertremap[i] = -1; // not used at all
521 // remap the triangle references
522 for (i = 0;i < numtris * 3;i++)
523 elements[i] = vertremap[temptris[i]];
524 // store the texture coordinates
525 texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * totalverts);
526 for (i = 0;i < totalverts;i++)
528 texcoords[i*2+0] = vertst[i*2+0];
529 texcoords[i*2+1] = vertst[i*2+1];
533 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
534 posedata = Mem_Alloc(loadmodel->mempool, sizeof(aliasvertex_t) * totalposes * totalverts);
535 Mod_MDL_LoadFrames (startframes, numverts, totalverts, scale, translate, texcoords, posedata, numtris, elements, vertremap);
536 Mod_BuildMDLMD2MeshInfo(totalverts, numtris, elements, texcoords, posedata);
539 Mem_Free(vertonseam);
545 static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, aliasvertex_t *out, int numverts, int *vertremap)
549 for (i = 0;i < numverts;i++)
551 in = v + vertremap[i];
552 out[i].origin[0] = in->v[0] * scale[0] + translate[0];
553 out[i].origin[1] = in->v[1] * scale[1] + translate[1];
554 out[i].origin[2] = in->v[2] * scale[2] + translate[2];
558 void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
560 int i, j, k, hashindex, num, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end, *elements, numverts, numtris;
561 float *stverts, s, t, scale[3], translate[3], *vertexbuffer, *svectorsbuffer, *tvectorsbuffer, *normalsbuffer, *texcoords;
562 aliasvertex_t *posedata;
564 qbyte *base, *datapointer;
565 md2frame_t *pinframe;
567 md2triangle_t *intri;
568 unsigned short *inst;
571 struct md2verthash_s *next;
575 *hash, **md2verthash, *md2verthashdata;
580 version = LittleLong (pinmodel->version);
581 if (version != MD2ALIAS_VERSION)
582 Host_Error ("%s has wrong version number (%i should be %i)",
583 loadmodel->name, version, MD2ALIAS_VERSION);
585 loadmodel->type = mod_alias;
586 loadmodel->aliastype = ALIASTYPE_ALIAS;
587 loadmodel->DrawSky = NULL;
588 loadmodel->Draw = R_Model_Alias_Draw;
589 loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
590 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
591 loadmodel->DrawLight = R_Model_Alias_DrawLight;
593 if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > (65536 / 3))
594 Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
595 if (LittleLong(pinmodel->num_xyz < 1) || LittleLong(pinmodel->num_xyz) > 65536)
596 Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
597 if (LittleLong(pinmodel->num_frames < 1) || LittleLong(pinmodel->num_frames) > 65536)
598 Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
599 if (LittleLong(pinmodel->num_skins < 0) || LittleLong(pinmodel->num_skins) > 256)
600 Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
602 end = LittleLong(pinmodel->ofs_end);
603 if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins <= 0) || LittleLong(pinmodel->ofs_skins) >= end))
604 Host_Error ("%s is not a valid model", loadmodel->name);
605 if (LittleLong(pinmodel->ofs_st <= 0) || LittleLong(pinmodel->ofs_st) >= end)
606 Host_Error ("%s is not a valid model", loadmodel->name);
607 if (LittleLong(pinmodel->ofs_tris <= 0) || LittleLong(pinmodel->ofs_tris) >= end)
608 Host_Error ("%s is not a valid model", loadmodel->name);
609 if (LittleLong(pinmodel->ofs_frames <= 0) || LittleLong(pinmodel->ofs_frames) >= end)
610 Host_Error ("%s is not a valid model", loadmodel->name);
611 if (LittleLong(pinmodel->ofs_glcmds <= 0) || LittleLong(pinmodel->ofs_glcmds) >= end)
612 Host_Error ("%s is not a valid model", loadmodel->name);
614 loadmodel->numskins = LittleLong(pinmodel->num_skins);
615 numxyz = LittleLong(pinmodel->num_xyz);
616 numst = LittleLong(pinmodel->num_st);
617 numtris = LittleLong(pinmodel->num_tris);
618 loadmodel->numframes = LittleLong(pinmodel->num_frames);
620 loadmodel->flags = 0; // there are no MD2 flags
621 loadmodel->synctype = ST_RAND;
624 inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
625 if (loadmodel->numskins)
627 // skins found (most likely not a player model)
628 loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, sizeof(skinframe_t) * loadmodel->numskins);
629 for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME)
630 Mod_LoadSkinFrame (loadmodel->skinframes + i, inskin, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true);
634 // no skins (most likely a player model)
635 loadmodel->numskins = 1;
636 loadmodel->skinframes = Mem_Alloc(loadmodel->mempool, sizeof(skinframe_t) * loadmodel->numskins);
639 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
640 for (i = 0;i < loadmodel->numskins;i++)
642 loadmodel->skinscenes[i].firstframe = i;
643 loadmodel->skinscenes[i].framecount = 1;
644 loadmodel->skinscenes[i].loop = true;
645 loadmodel->skinscenes[i].framerate = 10;
648 // load the triangles and stvert data
649 inst = (void*)(base + LittleLong(pinmodel->ofs_st));
650 intri = (void*)(base + LittleLong(pinmodel->ofs_tris));
651 skinwidth = LittleLong(pinmodel->skinwidth);
652 skinheight = LittleLong(pinmodel->skinheight);
654 stverts = Mem_Alloc(tempmempool, numst * sizeof(float[2]));
655 s = 1.0f / skinwidth;
656 t = 1.0f / skinheight;
657 for (i = 0;i < numst;i++)
659 j = (unsigned short) LittleShort(inst[i*2+0]);
660 k = (unsigned short) LittleShort(inst[i*2+1]);
661 if (j >= skinwidth || k >= skinheight)
664 Host_Error("Mod_MD2_LoadGeometry: invalid skin coordinate (%i %i) on vert %i of model %s\n", j, k, i, loadmodel->name);
666 stverts[i*2+0] = j * s;
667 stverts[i*2+1] = k * t;
670 md2verthash = Mem_Alloc(tempmempool, 256 * sizeof(hash));
671 md2verthashdata = Mem_Alloc(tempmempool, numtris * 3 * sizeof(*hash));
672 // swap the triangle list
674 elements = Mem_Alloc(loadmodel->mempool, numtris * sizeof(int[3]));
675 for (i = 0;i < numtris;i++)
677 for (j = 0;j < 3;j++)
679 xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
680 st = (unsigned short) LittleShort (intri[i].index_st[j]);
681 if (xyz >= numxyz || st >= numst)
683 Mem_Free(md2verthash);
684 Mem_Free(md2verthashdata);
687 Host_Error("Mod_MD2_LoadGeometry: invalid xyz index (%i) on triangle %i of model %s\n", xyz, i, loadmodel->name);
689 Host_Error("Mod_MD2_LoadGeometry: invalid st index (%i) on triangle %i of model %s\n", st, i, loadmodel->name);
693 hashindex = (xyz * 17 + st) & 255;
694 for (hash = md2verthash[hashindex];hash;hash = hash->next)
695 if (hash->xyz == xyz && hash->st[0] == s && hash->st[1] == t)
699 hash = md2verthashdata + num++;
703 hash->next = md2verthash[hashindex];
704 md2verthash[hashindex] = hash;
706 elements[i*3+j] = (hash - md2verthashdata);
713 vertremap = Mem_Alloc(loadmodel->mempool, num * sizeof(int));
714 texcoords = Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
715 for (i = 0;i < num;i++)
717 hash = md2verthashdata + i;
718 vertremap[i] = hash->xyz;
719 texcoords[i*2+0] = hash->st[0];
720 texcoords[i*2+1] = hash->st[1];
723 Mem_Free(md2verthash);
724 Mem_Free(md2verthashdata);
727 datapointer = (base + LittleLong(pinmodel->ofs_frames));
728 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
729 posedata = Mem_Alloc(loadmodel->mempool, numverts * loadmodel->numframes * sizeof(aliasvertex_t));
731 vertexbuffer = Mem_Alloc(tempmempool, numverts * sizeof(float[3+3+3+3]));
732 svectorsbuffer = vertexbuffer + numverts * 3;
733 tvectorsbuffer = svectorsbuffer + numverts * 3;
734 normalsbuffer = tvectorsbuffer + numverts * 3;
735 for (i = 0;i < loadmodel->numframes;i++)
737 pinframe = (md2frame_t *)datapointer;
738 datapointer += sizeof(md2frame_t);
739 for (j = 0;j < 3;j++)
741 scale[j] = LittleFloat(pinframe->scale[j]);
742 translate[j] = LittleFloat(pinframe->translate[j]);
744 Mod_MD2_ConvertVerts(scale, translate, (void *)datapointer, posedata + i * numverts, numverts, vertremap);
745 Mod_BuildAliasVertexTextureVectors(numverts, posedata + i * numverts, texcoords, vertexbuffer, svectorsbuffer, tvectorsbuffer, normalsbuffer, numtris, elements);
746 datapointer += numxyz * sizeof(trivertx_t);
748 strcpy(loadmodel->animscenes[i].name, pinframe->name);
749 loadmodel->animscenes[i].firstframe = i;
750 loadmodel->animscenes[i].framecount = 1;
751 loadmodel->animscenes[i].framerate = 10;
752 loadmodel->animscenes[i].loop = true;
754 Mem_Free(vertexbuffer);
758 Mod_BuildMDLMD2MeshInfo(numverts, numtris, elements, texcoords, posedata);
761 void Mod_LoadQ3AliasModel(model_t *mod, void *buffer)
764 float *vertexbuffer, *svectorsbuffer, *tvectorsbuffer, *normalsbuffer;
765 md3modelheader_t *pinmodel;
766 md3frameinfo_t *pinframe;
769 skinframe_t tempskinframe;
773 if (memcmp(pinmodel->identifier, "IDP3", 4))
774 Host_Error ("%s is not a MD3 (IDP3) file\n", loadmodel->name);
775 version = LittleLong (pinmodel->version);
776 if (version != MD3VERSION)
777 Host_Error ("%s has wrong version number (%i should be %i)",
778 loadmodel->name, version, MD3VERSION);
780 loadmodel->type = mod_alias;
781 loadmodel->aliastype = ALIASTYPE_ALIAS;
782 loadmodel->DrawSky = NULL;
783 loadmodel->Draw = R_Model_Alias_Draw;
784 loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow;
785 loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume;
786 loadmodel->DrawLight = R_Model_Alias_DrawLight;
787 loadmodel->flags = 0;
788 loadmodel->synctype = ST_RAND;
790 // set up some global info about the model
791 loadmodel->numframes = LittleLong(pinmodel->num_frames);
792 loadmodel->numskins = 1;
793 loadmodel->aliasnum_meshes = LittleLong(pinmodel->num_meshes);
794 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
795 loadmodel->skinscenes[0].firstframe = 0;
796 loadmodel->skinscenes[0].framecount = 1;
797 loadmodel->skinscenes[0].loop = true;
798 loadmodel->skinscenes[0].framerate = 10;
801 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
802 for (i = 0, pinframe = (md3frameinfo_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++)
804 strcpy(loadmodel->animscenes[i].name, pinframe->name);
805 loadmodel->animscenes[i].firstframe = i;
806 loadmodel->animscenes[i].framecount = 1;
807 loadmodel->animscenes[i].framerate = 10;
808 loadmodel->animscenes[i].loop = true;
811 // tags are not loaded yet
814 loadmodel->aliasdata_meshes = Mem_Alloc(loadmodel->mempool, loadmodel->aliasnum_meshes * sizeof(aliasmesh_t));
815 for (i = 0, pinmesh = (md3mesh_t *)((qbyte *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->aliasnum_meshes;i++, pinmesh = (md3mesh_t *)((qbyte *)pinmesh + LittleLong(pinmesh->lump_end)))
817 if (memcmp(pinmesh->identifier, "IDP3", 4))
818 Host_Error("Mod_LoadQ3AliasModel: invalid mesh identifier (not IDP3)\n");
819 mesh = loadmodel->aliasdata_meshes + i;
820 mesh->num_skins = loadmodel->numskins;
821 mesh->num_frames = LittleLong(pinmesh->num_frames);
822 mesh->num_vertices = LittleLong(pinmesh->num_vertices);
823 mesh->num_triangles = LittleLong(pinmesh->num_triangles);
824 mesh->data_skins = Mem_Alloc(loadmodel->mempool, mesh->num_skins * sizeof(aliasskin_t));
825 mesh->data_element3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
826 mesh->data_neighbor3i = Mem_Alloc(loadmodel->mempool, mesh->num_triangles * sizeof(int[3]));
827 mesh->data_texcoord2f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[2]));
828 mesh->data_aliasvertex = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * mesh->num_frames * sizeof(aliasvertex_t));
829 for (j = 0;j < mesh->num_triangles * 3;j++)
830 mesh->data_element3i[j] = LittleLong(((int *)((qbyte *)pinmesh + pinmesh->lump_elements))[j]);
831 for (j = 0;j < mesh->num_vertices;j++)
833 mesh->data_texcoord2f[j * 2 + 0] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 0]);
834 mesh->data_texcoord2f[j * 2 + 1] = LittleLong(((float *)((qbyte *)pinmesh + pinmesh->lump_texcoords))[j * 2 + 1]);
836 for (j = 0;j < mesh->num_vertices * mesh->num_frames;j++)
838 mesh->data_aliasvertex[j].origin[0] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 0]) * (1.0f / 64.0f);
839 mesh->data_aliasvertex[j].origin[1] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 1]) * (1.0f / 64.0f);
840 mesh->data_aliasvertex[j].origin[2] = LittleShort(((short *)((qbyte *)pinmesh + pinmesh->lump_framevertices))[j * 4 + 2]) * (1.0f / 64.0f);
842 vertexbuffer = Mem_Alloc(tempmempool, mesh->num_vertices * sizeof(float[3+3+3+3]));
843 svectorsbuffer = vertexbuffer + mesh->num_vertices * 3;
844 tvectorsbuffer = svectorsbuffer + mesh->num_vertices * 3;
845 normalsbuffer = tvectorsbuffer + mesh->num_vertices * 3;
846 for (j = 0;j < mesh->num_frames;j++)
847 Mod_BuildAliasVertexTextureVectors(mesh->num_vertices, mesh->data_aliasvertex + j * mesh->num_vertices, mesh->data_texcoord2f, vertexbuffer, svectorsbuffer, tvectorsbuffer, normalsbuffer, mesh->num_triangles, mesh->data_element3i);
848 Mem_Free(vertexbuffer);
850 memset(&tempskinframe, 0, sizeof(tempskinframe));
851 if (LittleLong(pinmesh->num_shaders) >= 1 && ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name[0])
852 Mod_LoadSkinFrame (&tempskinframe, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_CLAMP | TEXF_PRECACHE, true, false, true);
853 Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
854 Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
855 Mod_BuildAliasSkinFromSkinFrame(mesh->data_skins, &tempskinframe);
857 Mod_CalcAliasModelBBoxes();
860 extern void R_Model_Zymotic_DrawSky(entity_render_t *ent);
861 extern void R_Model_Zymotic_Draw(entity_render_t *ent);
862 extern void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent);
863 extern void R_Model_Zymotic_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
864 extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
865 void Mod_LoadZymoticModel(model_t *mod, void *buffer)
867 zymtype1header_t *pinmodel, *pheader;
870 pinmodel = (void *)buffer;
872 if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12))
873 Host_Error ("Mod_LoadZymoticModel: %s is not a zymotic model\n");
874 if (BigLong(pinmodel->type) != 1)
875 Host_Error ("Mod_LoadZymoticModel: only type 1 (skeletal pose) models are currently supported (name = %s)\n", loadmodel->name);
877 loadmodel->type = mod_alias;
878 loadmodel->aliastype = ALIASTYPE_ZYM;
879 loadmodel->DrawSky = NULL;
880 loadmodel->Draw = R_Model_Zymotic_Draw;
881 loadmodel->DrawFakeShadow = NULL;//R_Model_Zymotic_DrawFakeShadow;
882 loadmodel->DrawShadowVolume = NULL;//R_Model_Zymotic_DrawShadowVolume;
883 loadmodel->DrawLight = NULL;//R_Model_Zymotic_DrawLight;
887 pheader->type = BigLong(pinmodel->type);
888 pheader->filesize = BigLong(pinmodel->filesize);
889 pheader->mins[0] = BigFloat(pinmodel->mins[0]);
890 pheader->mins[1] = BigFloat(pinmodel->mins[1]);
891 pheader->mins[2] = BigFloat(pinmodel->mins[2]);
892 pheader->maxs[0] = BigFloat(pinmodel->maxs[0]);
893 pheader->maxs[1] = BigFloat(pinmodel->maxs[1]);
894 pheader->maxs[2] = BigFloat(pinmodel->maxs[2]);
895 pheader->radius = BigFloat(pinmodel->radius);
896 pheader->numverts = loadmodel->zymnum_verts = BigLong(pinmodel->numverts);
897 pheader->numtris = loadmodel->zymnum_tris = BigLong(pinmodel->numtris);
898 pheader->numshaders = loadmodel->zymnum_shaders = BigLong(pinmodel->numshaders);
899 pheader->numbones = loadmodel->zymnum_bones = BigLong(pinmodel->numbones);
900 pheader->numscenes = loadmodel->zymnum_scenes = BigLong(pinmodel->numscenes);
901 pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start);
902 pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length);
903 pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start);
904 pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length);
905 pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start);
906 pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length);
907 pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start);
908 pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length);
909 pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start);
910 pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length);
911 pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start);
912 pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length);
913 pheader->lump_render.start = BigLong(pinmodel->lump_render.start);
914 pheader->lump_render.length = BigLong(pinmodel->lump_render.length);
915 pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start);
916 pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length);
917 pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start);
918 pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length);
920 loadmodel->flags = 0; // there are no flags
921 loadmodel->numframes = pheader->numscenes;
922 loadmodel->synctype = ST_SYNC;
923 //loadmodel->numtris = pheader->numtris;
924 //loadmodel->numverts = 0;
928 float modelradius, corner[2];
930 modelradius = pheader->radius;
931 for (i = 0;i < 3;i++)
933 loadmodel->normalmins[i] = pheader->mins[i];
934 loadmodel->normalmaxs[i] = pheader->maxs[i];
935 loadmodel->rotatedmins[i] = -modelradius;
936 loadmodel->rotatedmaxs[i] = modelradius;
938 corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0]));
939 corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1]));
940 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]);
941 if (loadmodel->yawmaxs[0] > modelradius)
942 loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius;
943 loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0];
944 loadmodel->yawmins[2] = loadmodel->normalmins[2];
945 loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
946 loadmodel->radius = modelradius;
947 loadmodel->radius2 = modelradius * modelradius;
951 // FIXME: add shaders, and make them switchable shader sets and...
952 loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) + sizeof(skinframe_t));
953 loadmodel->skinscenes[0].firstframe = 0;
954 loadmodel->skinscenes[0].framecount = 1;
955 loadmodel->skinscenes[0].loop = true;
956 loadmodel->skinscenes[0].framerate = 10;
957 loadmodel->skinframes = (void *)(loadmodel->skinscenes + 1);
958 loadmodel->numskins = 1;
961 // go through the lumps, swapping things
966 // zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
967 loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
968 scene = (void *) (pheader->lump_scenes.start + pbase);
969 numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]);
970 for (i = 0;i < pheader->numscenes;i++)
972 memcpy(loadmodel->animscenes[i].name, scene->name, 32);
973 loadmodel->animscenes[i].firstframe = BigLong(scene->start);
974 loadmodel->animscenes[i].framecount = BigLong(scene->length);
975 loadmodel->animscenes[i].framerate = BigFloat(scene->framerate);
976 loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0;
977 if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes)
978 Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, numposes);
979 if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes)
980 Host_Error("Mod_LoadZymoticModel: scene firstframe (%i) + framecount (%i) >= numposes (%i)\n", loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes);
981 if (loadmodel->animscenes[i].framerate < 0)
982 Host_Error("Mod_LoadZymoticModel: scene framerate (%f) < 0\n", loadmodel->animscenes[i].framerate);
990 // zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data
991 loadmodel->zymdata_poses = Mem_Alloc(loadmodel->mempool, pheader->lump_poses.length);
992 poses = (void *) (pheader->lump_poses.start + pbase);
993 for (i = 0;i < pheader->lump_poses.length / 4;i++)
994 loadmodel->zymdata_poses[i] = BigFloat(poses[i]);
1000 // zymlump_t lump_bones; // zymbone_t bone[numbones];
1001 loadmodel->zymdata_bones = Mem_Alloc(loadmodel->mempool, pheader->numbones * sizeof(zymbone_t));
1002 bone = (void *) (pheader->lump_bones.start + pbase);
1003 for (i = 0;i < pheader->numbones;i++)
1005 memcpy(loadmodel->zymdata_bones[i].name, bone[i].name, sizeof(bone[i].name));
1006 loadmodel->zymdata_bones[i].flags = BigLong(bone[i].flags);
1007 loadmodel->zymdata_bones[i].parent = BigLong(bone[i].parent);
1008 if (loadmodel->zymdata_bones[i].parent >= i)
1009 Host_Error("Mod_LoadZymoticModel: bone[%i].parent >= %i in %s\n", i, i, loadmodel->name);
1015 // zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
1016 loadmodel->zymdata_vertbonecounts = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int));
1017 bonecount = (void *) (pheader->lump_vertbonecounts.start + pbase);
1018 for (i = 0;i < pheader->numverts;i++)
1020 loadmodel->zymdata_vertbonecounts[i] = BigLong(bonecount[i]);
1021 if (loadmodel->zymdata_vertbonecounts[i] < 1)
1022 Host_Error("Mod_LoadZymoticModel: bone vertex count < 1 in %s\n", loadmodel->name);
1028 zymvertex_t *vertdata;
1029 // zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct
1030 loadmodel->zymdata_verts = Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length);
1031 vertdata = (void *) (pheader->lump_verts.start + pbase);
1032 for (i = 0;i < pheader->lump_verts.length / (int) sizeof(zymvertex_t);i++)
1034 loadmodel->zymdata_verts[i].bonenum = BigLong(vertdata[i].bonenum);
1035 loadmodel->zymdata_verts[i].origin[0] = BigFloat(vertdata[i].origin[0]);
1036 loadmodel->zymdata_verts[i].origin[1] = BigFloat(vertdata[i].origin[1]);
1037 loadmodel->zymdata_verts[i].origin[2] = BigFloat(vertdata[i].origin[2]);
1043 float *intexcoord2f, *outtexcoord2f;
1044 // zymlump_t lump_texcoords; // float texcoords[numvertices][2];
1045 loadmodel->zymdata_texcoords = outtexcoord2f = Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(float[2]));
1046 intexcoord2f = (void *) (pheader->lump_texcoords.start + pbase);
1047 for (i = 0;i < pheader->numverts;i++)
1049 outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]);
1050 // flip T coordinate for OpenGL
1051 outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]);
1056 int i, count, *renderlist, *renderlistend, *outrenderlist;
1057 // 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)
1058 loadmodel->zymdata_renderlist = Mem_Alloc(loadmodel->mempool, pheader->lump_render.length);
1059 // byteswap, validate, and swap winding order of tris
1060 count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]);
1061 if (pheader->lump_render.length != count)
1062 Host_Error("Mod_LoadZymoticModel: renderlist is wrong size in %s (is %i bytes, should be %i bytes)\n", loadmodel->name, pheader->lump_render.length, count);
1063 outrenderlist = loadmodel->zymdata_renderlist = Mem_Alloc(loadmodel->mempool, count);
1064 renderlist = (void *) (pheader->lump_render.start + pbase);
1065 renderlistend = (void *) ((qbyte *) renderlist + pheader->lump_render.length);
1066 for (i = 0;i < pheader->numshaders;i++)
1068 if (renderlist >= renderlistend)
1069 Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name);
1070 count = BigLong(*renderlist);renderlist++;
1071 if (renderlist + count * 3 > renderlistend)
1072 Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (wrong size)\n", loadmodel->name);
1073 *outrenderlist++ = count;
1076 outrenderlist[2] = BigLong(renderlist[0]);
1077 outrenderlist[1] = BigLong(renderlist[1]);
1078 outrenderlist[0] = BigLong(renderlist[2]);
1079 if ((unsigned int)outrenderlist[0] >= (unsigned int)pheader->numverts
1080 || (unsigned int)outrenderlist[1] >= (unsigned int)pheader->numverts
1081 || (unsigned int)outrenderlist[2] >= (unsigned int)pheader->numverts)
1082 Host_Error("Mod_LoadZymoticModel: corrupt renderlist in %s (out of bounds index)\n", loadmodel->name);
1092 // zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model
1093 loadmodel->zymdata_textures = Mem_Alloc(loadmodel->mempool, pheader->numshaders * sizeof(rtexture_t *));
1094 shadername = (void *) (pheader->lump_shaders.start + pbase);
1095 for (i = 0;i < pheader->numshaders;i++)
1096 loadmodel->zymdata_textures[i] = loadtextureimage(loadmodel->texturepool, shadername + i * 32, 0, 0, true, TEXF_ALPHA | TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0));
1100 // zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation
1101 loadmodel->zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris);
1102 memcpy(loadmodel->zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris);