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.
23 // note: model_shared.c sets up r_notexture, and r_surf_notexture
25 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
27 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
28 cvar_t halflifebsp = {0, "halflifebsp", "0"};
29 cvar_t r_novis = {0, "r_novis", "0"};
30 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
31 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
32 cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"};
33 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
34 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
36 #define NUM_DETAILTEXTURES 1
37 static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
38 static rtexturepool_t *detailtexturepool;
45 void Mod_BrushInit (void)
47 // Cvar_RegisterVariable(&r_subdivide_size);
48 Cvar_RegisterVariable(&halflifebsp);
49 Cvar_RegisterVariable(&r_novis);
50 Cvar_RegisterVariable(&r_miplightmaps);
51 Cvar_RegisterVariable(&r_lightmaprgba);
52 Cvar_RegisterVariable(&r_vertexsurfacesthreshold);
53 Cvar_RegisterVariable(&r_nosurftextures);
54 Cvar_RegisterVariable(&r_sortsurfaces);
55 memset(mod_novis, 0xff, sizeof(mod_novis));
58 void Mod_BrushStartup (void)
61 float vc[3], vx[3], vy[3], vn[3], lightdir[3];
62 #define DETAILRESOLUTION 256
63 qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
64 detailtexturepool = R_AllocTexturePool();
68 VectorNormalize(lightdir);
69 for (i = 0;i < NUM_DETAILTEXTURES;i++)
71 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
72 for (y = 0;y < DETAILRESOLUTION;y++)
74 for (x = 0;x < DETAILRESOLUTION;x++)
78 vc[2] = noise[y][x] * (1.0f / 32.0f);
81 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
84 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
85 VectorSubtract(vx, vc, vx);
86 VectorSubtract(vy, vc, vy);
87 CrossProduct(vx, vy, vn);
89 light = 128 - DotProduct(vn, lightdir) * 128;
90 light = bound(0, light, 255);
91 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
95 detailtextures[i] = R_LoadTexture(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE);
99 void Mod_BrushShutdown (void)
102 for (i = 0;i < NUM_DETAILTEXTURES;i++)
103 R_FreeTexture(detailtextures[i]);
104 R_FreeTexturePool(&detailtexturepool);
112 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
119 Mod_CheckLoaded(model);
121 // LordHavoc: modified to start at first clip node,
122 // in other words: first node of the (sub)model
123 node = model->nodes + model->hulls[0].firstclipnode;
124 while (node->contents == 0)
125 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
127 return (mleaf_t *)node;
130 int Mod_PointContents (const vec3_t p, model_t *model)
135 return CONTENTS_EMPTY;
137 Mod_CheckLoaded(model);
139 // LordHavoc: modified to start at first clip node,
140 // in other words: first node of the (sub)model
141 node = model->nodes + model->hulls[0].firstclipnode;
142 while (node->contents == 0)
143 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
145 return ((mleaf_t *)node)->contents;
148 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
150 if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
151 pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
152 pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
154 pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
155 pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
157 pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
158 pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
168 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
170 static qbyte decompressed[MAX_MAP_LEAFS/8];
175 row = (model->numleafs+7)>>3;
193 } while (out - decompressed < row);
198 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
200 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
202 return Mod_DecompressVis (leaf->compressed_vis, model);
210 static void Mod_LoadTextures (lump_t *l)
212 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
214 texture_t *tx, *tx2, *anims[10], *altanims[10];
216 qbyte *data, *mtdata, *data2;
219 loadmodel->textures = NULL;
224 m = (dmiptexlump_t *)(mod_base + l->fileofs);
226 m->nummiptex = LittleLong (m->nummiptex);
228 // add two slots for notexture walls and notexture liquids
229 loadmodel->numtextures = m->nummiptex + 2;
230 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(*loadmodel->textures));
232 // fill out all slots with notexture
233 for (i = 0;i < loadmodel->numtextures;i++)
235 loadmodel->textures[i] = tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t));
238 tx->texture = r_notexture;
239 if (i == loadmodel->numtextures - 1)
240 tx->flags = SURF_DRAWTURB | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID;
243 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
245 // LordHavoc: mostly rewritten map texture loader
246 for (i = 0;i < m->nummiptex;i++)
248 dofs[i] = LittleLong(dofs[i]);
249 if (dofs[i] == -1 || r_nosurftextures.integer)
251 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
253 // make sure name is no more than 15 characters
254 for (j = 0;dmiptex->name[j] && j < 15;j++)
255 name[j] = dmiptex->name[j];
258 mtwidth = LittleLong (dmiptex->width);
259 mtheight = LittleLong (dmiptex->height);
261 j = LittleLong (dmiptex->offsets[0]);
265 if (j < 40 || j + mtwidth * mtheight > l->filelen)
267 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
270 mtdata = (qbyte *)dmiptex + j;
273 if ((mtwidth & 15) || (mtheight & 15))
274 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
276 // LordHavoc: force all names to lowercase
277 for (j = 0;name[j];j++)
278 if (name[j] >= 'A' && name[j] <= 'Z')
279 name[j] += 'a' - 'A';
281 tx = loadmodel->textures[i];
282 strcpy(tx->name, name);
284 tx->height = mtheight;
286 tx->glowtexture = NULL;
287 tx->fogtexture = NULL;
291 sprintf(tx->name, "unnamed%i", i);
292 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
295 // LordHavoc: HL sky textures are entirely different than quake
296 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
298 if (loadmodel->isworldmodel)
300 data = loadimagepixels(tx->name, false, 0, 0);
303 if (image_width == 256 && image_height == 128)
311 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
313 R_InitSky (mtdata, 1);
316 else if (mtdata != NULL)
317 R_InitSky (mtdata, 1);
320 else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
322 tx->fogtexture = image_masktex;
323 strcpy(name, tx->name);
324 strcat(name, "_glow");
325 tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
329 if (loadmodel->ishlbsp)
331 if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
334 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
335 if (R_TextureHasAlpha(tx->texture))
338 for (j = 0;j < image_width * image_height;j++)
339 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
340 strcpy(name, tx->name);
341 strcat(name, "_fog");
342 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
346 else if ((data = W_GetTexture(tx->name)))
348 // get the size from the wad texture
349 tx->width = image_width;
350 tx->height = image_height;
351 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
352 if (R_TextureHasAlpha(tx->texture))
355 for (j = 0;j < image_width * image_height;j++)
356 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
357 strcpy(name, tx->name);
358 strcat(name, "_fog");
359 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
367 tx->texture = r_notexture;
372 if (mtdata) // texture included
377 if (r_fullbrights.value && tx->name[0] != '*')
379 for (j = 0;j < tx->width*tx->height;j++)
381 if (data[j] >= 224) // fullbright
390 data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height);
391 for (j = 0;j < tx->width*tx->height;j++)
392 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
393 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
394 strcpy(name, tx->name);
395 strcat(name, "_glow");
396 for (j = 0;j < tx->width*tx->height;j++)
397 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
398 tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
402 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
404 else // no texture, and no external replacement texture was found
408 tx->texture = r_notexture;
413 if (tx->name[0] == '*')
415 tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES);
416 // LordHavoc: some turbulent textures should be fullbright and solid
417 if (!strncmp(tx->name,"*lava",5)
418 || !strncmp(tx->name,"*teleport",9)
419 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
420 tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
422 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
423 tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID);
426 tx->flags |= SURF_LIGHTMAP;
427 if (!R_TextureHasAlpha(tx->texture))
428 tx->flags |= SURF_CLIPSOLID;
431 tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
434 // sequence the animations
435 for (i = 0;i < m->nummiptex;i++)
437 tx = loadmodel->textures[i];
438 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
440 if (tx->anim_total[0] || tx->anim_total[1])
441 continue; // already sequenced
443 // find the number of frames in the animation
444 memset (anims, 0, sizeof(anims));
445 memset (altanims, 0, sizeof(altanims));
447 for (j = i;j < m->nummiptex;j++)
449 tx2 = loadmodel->textures[j];
450 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
454 if (num >= '0' && num <= '9')
455 anims[num - '0'] = tx2;
456 else if (num >= 'a' && num <= 'j')
457 altanims[num - 'a'] = tx2;
459 Con_Printf ("Bad animating texture %s\n", tx->name);
463 for (j = 0;j < 10;j++)
470 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
473 for (j = 0;j < max;j++)
477 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
481 for (j = 0;j < altmax;j++)
485 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
494 // if there is no alternate animation, duplicate the primary
495 // animation into the alternate
497 for (k = 0;k < 10;k++)
498 altanims[k] = anims[k];
501 // link together the primary animation
502 for (j = 0;j < max;j++)
505 tx2->animated = true;
506 tx2->anim_total[0] = max;
507 tx2->anim_total[1] = altmax;
508 for (k = 0;k < 10;k++)
510 tx2->anim_frames[0][k] = anims[k];
511 tx2->anim_frames[1][k] = altanims[k];
515 // if there really is an alternate anim...
516 if (anims[0] != altanims[0])
518 // link together the alternate animation
519 for (j = 0;j < altmax;j++)
522 tx2->animated = true;
523 // the primary/alternate are reversed here
524 tx2->anim_total[0] = altmax;
525 tx2->anim_total[1] = max;
526 for (k = 0;k < 10;k++)
528 tx2->anim_frames[0][k] = altanims[k];
529 tx2->anim_frames[1][k] = anims[k];
541 static void Mod_LoadLighting (lump_t *l)
544 qbyte *in, *out, *data, d;
545 char litfilename[1024];
546 loadmodel->lightdata = NULL;
547 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
549 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
550 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
552 else // LordHavoc: bsp version 29 (normal white lighting)
554 // LordHavoc: hope is not lost yet, check for a .lit file to load
555 strcpy(litfilename, loadmodel->name);
556 COM_StripExtension(litfilename, litfilename);
557 strcat(litfilename, ".lit");
558 data = (qbyte*) COM_LoadFile (litfilename, false);
561 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
563 i = LittleLong(((int *)data)[1]);
566 Con_DPrintf("%s loaded", litfilename);
567 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
568 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
574 Con_Printf("Unknown .lit file version (%d)\n", i);
581 Con_Printf("Empty .lit file, ignoring\n");
583 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
587 // LordHavoc: oh well, expand the white lighting data
590 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
591 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
592 out = loadmodel->lightdata;
593 memcpy (in, mod_base + l->fileofs, l->filelen);
594 for (i = 0;i < l->filelen;i++)
604 void Mod_LoadLightList(void)
607 char lightsfilename[1024], *s, *t, *lightsstring;
610 strcpy(lightsfilename, loadmodel->name);
611 COM_StripExtension(lightsfilename, lightsfilename);
612 strcat(lightsfilename, ".lights");
613 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
619 while (*s && *s != '\n')
623 Mem_Free(lightsstring);
624 Host_Error("lights file must end with a newline\n");
629 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
632 while (*s && n < numlights)
635 while (*s && *s != '\n')
639 Mem_Free(lightsstring);
640 Host_Error("misparsed lights file!\n");
642 e = loadmodel->lights + n;
644 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
648 Mem_Free(lightsstring);
649 Host_Error("invalid lights file, found %d parameters on line %i, should be 13 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone style)\n", a, n + 1);
656 Mem_Free(lightsstring);
657 Host_Error("misparsed lights file!\n");
659 loadmodel->numlights = numlights;
660 Mem_Free(lightsstring);
670 static void Mod_LoadVisibility (lump_t *l)
672 loadmodel->visdata = NULL;
675 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
676 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
679 // used only for HalfLife maps
680 void Mod_ParseWadsFromEntityLump(char *data)
682 char key[128], value[4096];
687 data = COM_Parse(data);
690 if (com_token[0] != '{')
694 data = COM_Parse(data);
697 if (com_token[0] == '}')
698 break; // end of worldspawn
699 if (com_token[0] == '_')
700 strcpy(key, com_token + 1);
702 strcpy(key, com_token);
703 while (key[strlen(key)-1] == ' ') // remove trailing spaces
704 key[strlen(key)-1] = 0;
705 data = COM_Parse(data);
708 strcpy(value, com_token);
709 if (!strcmp("wad", key)) // for HalfLife maps
711 if (loadmodel->ishlbsp)
714 for (i = 0;i < 4096;i++)
715 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
721 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
722 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
724 else if (value[i] == ';' || value[i] == 0)
728 strcpy(wadname, "textures/");
729 strcat(wadname, &value[j]);
730 W_LoadTextureWadFile (wadname, false);
747 static void Mod_LoadEntities (lump_t *l)
749 loadmodel->entities = NULL;
752 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
753 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
754 if (loadmodel->ishlbsp)
755 Mod_ParseWadsFromEntityLump(loadmodel->entities);
764 static void Mod_LoadVertexes (lump_t *l)
770 in = (void *)(mod_base + l->fileofs);
771 if (l->filelen % sizeof(*in))
772 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
773 count = l->filelen / sizeof(*in);
774 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
776 loadmodel->vertexes = out;
777 loadmodel->numvertexes = count;
779 for ( i=0 ; i<count ; i++, in++, out++)
781 out->position[0] = LittleFloat (in->point[0]);
782 out->position[1] = LittleFloat (in->point[1]);
783 out->position[2] = LittleFloat (in->point[2]);
792 static void Mod_LoadSubmodels (lump_t *l)
798 in = (void *)(mod_base + l->fileofs);
799 if (l->filelen % sizeof(*in))
800 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
801 count = l->filelen / sizeof(*in);
802 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
804 loadmodel->submodels = out;
805 loadmodel->numsubmodels = count;
807 for ( i=0 ; i<count ; i++, in++, out++)
809 for (j=0 ; j<3 ; j++)
811 // spread the mins / maxs by a pixel
812 out->mins[j] = LittleFloat (in->mins[j]) - 1;
813 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
814 out->origin[j] = LittleFloat (in->origin[j]);
816 for (j=0 ; j<MAX_MAP_HULLS ; j++)
817 out->headnode[j] = LittleLong (in->headnode[j]);
818 out->visleafs = LittleLong (in->visleafs);
819 out->firstface = LittleLong (in->firstface);
820 out->numfaces = LittleLong (in->numfaces);
829 static void Mod_LoadEdges (lump_t *l)
835 in = (void *)(mod_base + l->fileofs);
836 if (l->filelen % sizeof(*in))
837 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
838 count = l->filelen / sizeof(*in);
839 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
841 loadmodel->edges = out;
842 loadmodel->numedges = count;
844 for ( i=0 ; i<count ; i++, in++, out++)
846 out->v[0] = (unsigned short)LittleShort(in->v[0]);
847 out->v[1] = (unsigned short)LittleShort(in->v[1]);
856 static void Mod_LoadTexinfo (lump_t *l)
860 int i, j, k, count, miptex;
862 in = (void *)(mod_base + l->fileofs);
863 if (l->filelen % sizeof(*in))
864 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
865 count = l->filelen / sizeof(*in);
866 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
868 loadmodel->texinfo = out;
869 loadmodel->numtexinfo = count;
871 for (i = 0;i < count;i++, in++, out++)
873 for (k = 0;k < 2;k++)
874 for (j = 0;j < 4;j++)
875 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
877 miptex = LittleLong (in->miptex);
878 out->flags = LittleLong (in->flags);
881 if (loadmodel->textures)
883 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
884 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
886 out->texture = loadmodel->textures[miptex];
888 if (out->texture == NULL)
890 // choose either the liquid notexture, or the normal notexture
891 if (out->flags & TEX_SPECIAL)
892 out->texture = loadmodel->textures[loadmodel->numtextures - 1];
894 out->texture = loadmodel->textures[loadmodel->numtextures - 2];
903 Fills in s->texturemins[] and s->extents[]
906 static void CalcSurfaceExtents (msurface_t *s)
908 float mins[2], maxs[2], val;
912 int bmins[2], bmaxs[2];
914 mins[0] = mins[1] = 999999999;
915 maxs[0] = maxs[1] = -999999999;
919 for (i=0 ; i<s->numedges ; i++)
921 e = loadmodel->surfedges[s->firstedge+i];
923 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
925 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
927 for (j=0 ; j<2 ; j++)
929 val = v->position[0] * tex->vecs[j][0] +
930 v->position[1] * tex->vecs[j][1] +
931 v->position[2] * tex->vecs[j][2] +
940 for (i=0 ; i<2 ; i++)
942 bmins[i] = floor(mins[i]/16);
943 bmaxs[i] = ceil(maxs[i]/16);
945 s->texturemins[i] = bmins[i] * 16;
946 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
951 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
956 mins[0] = mins[1] = mins[2] = 9999;
957 maxs[0] = maxs[1] = maxs[2] = -9999;
959 for (i = 0;i < numverts;i++)
961 for (j = 0;j < 3;j++, v++)
972 #define MAX_SUBDIVPOLYTRIANGLES 4096
973 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
975 static int subdivpolyverts, subdivpolytriangles;
976 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
977 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
979 static int subdivpolylookupvert(vec3_t v)
982 for (i = 0;i < subdivpolyverts;i++)
983 if (subdivpolyvert[i][0] == v[0]
984 && subdivpolyvert[i][1] == v[1]
985 && subdivpolyvert[i][2] == v[2])
987 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
988 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
989 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
990 return subdivpolyverts++;
993 static void SubdividePolygon (int numverts, float *verts)
995 int i, i1, i2, i3, f, b, c, p;
996 vec3_t mins, maxs, front[256], back[256];
997 float m, *pv, *cv, dist[256], frac;
1000 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1002 BoundPoly (numverts, verts, mins, maxs);
1004 for (i = 0;i < 3;i++)
1006 m = (mins[i] + maxs[i]) * 0.5;
1007 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1008 if (maxs[i] - m < 8)
1010 if (m - mins[i] < 8)
1014 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1015 dist[c] = cv[i] - m;
1018 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1022 VectorCopy (pv, front[f]);
1027 VectorCopy (pv, back[b]);
1030 if (dist[p] == 0 || dist[c] == 0)
1032 if ( (dist[p] > 0) != (dist[c] > 0) )
1035 frac = dist[p] / (dist[p] - dist[c]);
1036 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1037 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1038 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1044 SubdividePolygon (f, front[0]);
1045 SubdividePolygon (b, back[0]);
1049 i1 = subdivpolylookupvert(verts);
1050 i2 = subdivpolylookupvert(verts + 3);
1051 for (i = 2;i < numverts;i++)
1053 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1055 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1059 i3 = subdivpolylookupvert(verts + i * 3);
1060 subdivpolyindex[subdivpolytriangles][0] = i1;
1061 subdivpolyindex[subdivpolytriangles][1] = i2;
1062 subdivpolyindex[subdivpolytriangles][2] = i3;
1064 subdivpolytriangles++;
1070 Mod_GenerateWarpMesh
1072 Breaks a polygon up along axial 64 unit
1073 boundaries so that turbulent and sky warps
1074 can be done reasonably.
1077 void Mod_GenerateWarpMesh (msurface_t *surf)
1083 subdivpolytriangles = 0;
1084 subdivpolyverts = 0;
1085 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1086 if (subdivpolytriangles < 1)
1087 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1089 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1090 mesh->numverts = subdivpolyverts;
1091 mesh->numtriangles = subdivpolytriangles;
1092 mesh->vertex = (surfvertex_t *)(mesh + 1);
1093 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1094 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1096 for (i = 0;i < mesh->numtriangles;i++)
1097 for (j = 0;j < 3;j++)
1098 mesh->index[i*3+j] = subdivpolyindex[i][j];
1100 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1102 VectorCopy(subdivpolyvert[i], v->v);
1103 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1104 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1109 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1111 int i, iu, iv, *index, smax, tmax;
1112 float *in, s, t, u, v, ubase, vbase, uscale, vscale;
1115 smax = surf->extents[0] >> 4;
1116 tmax = surf->extents[1] >> 4;
1120 surf->lightmaptexturestride = 0;
1121 surf->lightmaptexture = NULL;
1129 surf->flags |= SURF_LIGHTMAP;
1130 if (r_miplightmaps.integer)
1132 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1133 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE);
1137 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1138 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
1140 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1141 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1142 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1145 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1) * sizeof(float));
1146 mesh->numverts = surf->poly_numverts;
1147 mesh->numtriangles = surf->poly_numverts - 2;
1148 mesh->verts = (float *)(mesh + 1);
1149 mesh->st = mesh->verts + mesh->numverts * 4;
1150 mesh->uv = mesh->st + mesh->numverts * 2;
1151 mesh->ab = mesh->uv + mesh->numverts * 2;
1152 mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2);
1153 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1155 index = mesh->index;
1156 for (i = 0;i < mesh->numtriangles;i++)
1163 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1165 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1166 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1167 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0) * uscale + ubase;
1168 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0) * vscale + vbase;
1169 // LordHavoc: calc lightmap data offset for vertex lighting to use
1172 iu = bound(0, iu, smax);
1173 iv = bound(0, iv, tmax);
1175 mesh->verts[i * 4 + 0] = in[0];
1176 mesh->verts[i * 4 + 1] = in[1];
1177 mesh->verts[i * 4 + 2] = in[2];
1178 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1179 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1180 mesh->uv[i * 2 + 0] = u;
1181 mesh->uv[i * 2 + 1] = v;
1182 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1183 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1184 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1188 void Mod_GenerateVertexMesh (msurface_t *surf)
1194 surf->lightmaptexturestride = 0;
1195 surf->lightmaptexture = NULL;
1197 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * (4 + 2 + 2) * sizeof(float));
1198 mesh->numverts = surf->poly_numverts;
1199 mesh->numtriangles = surf->poly_numverts - 2;
1200 mesh->verts = (float *)(mesh + 1);
1201 mesh->st = mesh->verts + mesh->numverts * 4;
1202 mesh->ab = mesh->st + mesh->numverts * 2;
1203 mesh->index = (int *)(mesh->ab + mesh->numverts * 2);
1205 index = mesh->index;
1206 for (i = 0;i < mesh->numtriangles;i++)
1213 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1215 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1216 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1217 mesh->verts[i * 4 + 0] = in[0];
1218 mesh->verts[i * 4 + 1] = in[1];
1219 mesh->verts[i * 4 + 2] = in[2];
1220 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1221 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1222 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1223 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1227 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1230 float *vec, *vert, mins[3], maxs[3];
1232 // convert edges back to a normal polygon
1233 surf->poly_numverts = surf->numedges;
1234 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1235 for (i = 0;i < surf->numedges;i++)
1237 lindex = loadmodel->surfedges[surf->firstedge + i];
1239 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1241 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1242 VectorCopy (vec, vert);
1245 vert = surf->poly_verts;
1246 VectorCopy(vert, mins);
1247 VectorCopy(vert, maxs);
1249 for (i = 1;i < surf->poly_numverts;i++)
1251 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1252 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1253 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1256 VectorCopy(mins, surf->poly_mins);
1257 VectorCopy(maxs, surf->poly_maxs);
1258 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1259 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1260 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1268 static void Mod_LoadFaces (lump_t *l)
1272 int i, count, surfnum, planenum, ssize, tsize;
1274 in = (void *)(mod_base + l->fileofs);
1275 if (l->filelen % sizeof(*in))
1276 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1277 count = l->filelen / sizeof(*in);
1278 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1280 loadmodel->surfaces = out;
1281 loadmodel->numsurfaces = count;
1283 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1285 // FIXME: validate edges, texinfo, etc?
1286 out->firstedge = LittleLong(in->firstedge);
1287 out->numedges = LittleShort(in->numedges);
1288 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1289 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1291 i = LittleShort (in->texinfo);
1292 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1293 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1294 out->texinfo = loadmodel->texinfo + i;
1295 out->flags = out->texinfo->texture->flags;
1297 planenum = LittleShort(in->planenum);
1298 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1299 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1301 if (LittleShort(in->side))
1302 out->flags |= SURF_PLANEBACK;
1304 out->plane = loadmodel->planes + planenum;
1306 // clear lightmap (filled in later)
1307 out->lightmaptexture = NULL;
1309 // force lightmap upload on first time seeing the surface
1310 out->cached_dlight = true;
1311 out->cached_ambient = -1000;
1312 out->cached_lightscalebit = -1000;
1314 CalcSurfaceExtents (out);
1316 ssize = (out->extents[0] >> 4) + 1;
1317 tsize = (out->extents[1] >> 4) + 1;
1320 for (i = 0;i < MAXLIGHTMAPS;i++)
1321 out->styles[i] = in->styles[i];
1322 i = LittleLong(in->lightofs);
1324 out->samples = NULL;
1325 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1326 out->samples = loadmodel->lightdata + i;
1327 else // LordHavoc: white lighting (bsp version 29)
1328 out->samples = loadmodel->lightdata + (i * 3);
1330 Mod_GenerateSurfacePolygon(out);
1332 if (out->texinfo->texture->flags & SURF_DRAWSKY)
1334 out->shader = &Cshader_sky;
1335 out->samples = NULL;
1336 Mod_GenerateVertexMesh (out);
1338 else if (out->texinfo->texture->flags & SURF_DRAWTURB)
1340 out->shader = &Cshader_water;
1341 out->samples = NULL;
1342 Mod_GenerateVertexMesh (out);
1346 if (!R_TextureHasAlpha(out->texinfo->texture->texture))
1347 out->flags |= SURF_CLIPSOLID;
1348 if (out->texinfo->flags & TEX_SPECIAL)
1350 // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb
1351 out->shader = &Cshader_water;
1352 out->shader = &Cshader_water;
1353 out->samples = NULL;
1354 Mod_GenerateVertexMesh (out);
1356 else if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1358 Con_Printf ("Bad surface extents, converting to fullbright polygon");
1359 out->shader = &Cshader_wall_fullbright;
1360 out->samples = NULL;
1361 Mod_GenerateVertexMesh(out);
1365 // stainmap for permanent marks on walls
1366 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1368 memset(out->stainsamples, 255, ssize * tsize * 3);
1369 if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
1371 out->shader = &Cshader_wall_vertex;
1372 Mod_GenerateWallMesh (out, true);
1376 out->shader = &Cshader_wall_lightmap;
1377 Mod_GenerateWallMesh (out, false);
1384 static model_t *sortmodel;
1386 static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
1388 const msurface_t *a, *b;
1389 a = *((const msurface_t **)voida);
1390 b = *((const msurface_t **)voidb);
1391 if (a->shader != b->shader)
1392 return (qbyte *) a->shader - (qbyte *) b->shader;
1393 if (a->texinfo->texture != b->texinfo->texture);
1394 return a->texinfo->texture - b->texinfo->texture;
1398 static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool)
1402 sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *));
1403 for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++)
1404 sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface];
1406 if (r_sortsurfaces.integer)
1407 qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare);
1416 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1418 node->parent = parent;
1419 if (node->contents < 0)
1421 Mod_SetParent (node->children[0], node);
1422 Mod_SetParent (node->children[1], node);
1430 static void Mod_LoadNodes (lump_t *l)
1436 in = (void *)(mod_base + l->fileofs);
1437 if (l->filelen % sizeof(*in))
1438 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1439 count = l->filelen / sizeof(*in);
1440 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1442 loadmodel->nodes = out;
1443 loadmodel->numnodes = count;
1445 for ( i=0 ; i<count ; i++, in++, out++)
1447 for (j=0 ; j<3 ; j++)
1449 out->mins[j] = LittleShort (in->mins[j]);
1450 out->maxs[j] = LittleShort (in->maxs[j]);
1453 p = LittleLong(in->planenum);
1454 out->plane = loadmodel->planes + p;
1456 out->firstsurface = LittleShort (in->firstface);
1457 out->numsurfaces = LittleShort (in->numfaces);
1459 for (j=0 ; j<2 ; j++)
1461 p = LittleShort (in->children[j]);
1463 out->children[j] = loadmodel->nodes + p;
1465 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1469 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1477 static void Mod_LoadLeafs (lump_t *l)
1483 in = (void *)(mod_base + l->fileofs);
1484 if (l->filelen % sizeof(*in))
1485 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1486 count = l->filelen / sizeof(*in);
1487 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1489 loadmodel->leafs = out;
1490 loadmodel->numleafs = count;
1492 for ( i=0 ; i<count ; i++, in++, out++)
1494 for (j=0 ; j<3 ; j++)
1496 out->mins[j] = LittleShort (in->mins[j]);
1497 out->maxs[j] = LittleShort (in->maxs[j]);
1500 p = LittleLong(in->contents);
1503 out->firstmarksurface = loadmodel->marksurfaces +
1504 LittleShort(in->firstmarksurface);
1505 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1507 p = LittleLong(in->visofs);
1509 out->compressed_vis = NULL;
1511 out->compressed_vis = loadmodel->visdata + p;
1513 for (j=0 ; j<4 ; j++)
1514 out->ambient_sound_level[j] = in->ambient_level[j];
1516 // FIXME: Insert caustics here
1525 static void Mod_LoadClipnodes (lump_t *l)
1527 dclipnode_t *in, *out;
1531 in = (void *)(mod_base + l->fileofs);
1532 if (l->filelen % sizeof(*in))
1533 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1534 count = l->filelen / sizeof(*in);
1535 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1537 loadmodel->clipnodes = out;
1538 loadmodel->numclipnodes = count;
1540 if (loadmodel->ishlbsp)
1542 hull = &loadmodel->hulls[1];
1543 hull->clipnodes = out;
1544 hull->firstclipnode = 0;
1545 hull->lastclipnode = count-1;
1546 hull->planes = loadmodel->planes;
1547 hull->clip_mins[0] = -16;
1548 hull->clip_mins[1] = -16;
1549 hull->clip_mins[2] = -36;
1550 hull->clip_maxs[0] = 16;
1551 hull->clip_maxs[1] = 16;
1552 hull->clip_maxs[2] = 36;
1553 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1555 hull = &loadmodel->hulls[2];
1556 hull->clipnodes = out;
1557 hull->firstclipnode = 0;
1558 hull->lastclipnode = count-1;
1559 hull->planes = loadmodel->planes;
1560 hull->clip_mins[0] = -32;
1561 hull->clip_mins[1] = -32;
1562 hull->clip_mins[2] = -32;
1563 hull->clip_maxs[0] = 32;
1564 hull->clip_maxs[1] = 32;
1565 hull->clip_maxs[2] = 32;
1566 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1568 hull = &loadmodel->hulls[3];
1569 hull->clipnodes = out;
1570 hull->firstclipnode = 0;
1571 hull->lastclipnode = count-1;
1572 hull->planes = loadmodel->planes;
1573 hull->clip_mins[0] = -16;
1574 hull->clip_mins[1] = -16;
1575 hull->clip_mins[2] = -18;
1576 hull->clip_maxs[0] = 16;
1577 hull->clip_maxs[1] = 16;
1578 hull->clip_maxs[2] = 18;
1579 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1583 hull = &loadmodel->hulls[1];
1584 hull->clipnodes = out;
1585 hull->firstclipnode = 0;
1586 hull->lastclipnode = count-1;
1587 hull->planes = loadmodel->planes;
1588 hull->clip_mins[0] = -16;
1589 hull->clip_mins[1] = -16;
1590 hull->clip_mins[2] = -24;
1591 hull->clip_maxs[0] = 16;
1592 hull->clip_maxs[1] = 16;
1593 hull->clip_maxs[2] = 32;
1594 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1596 hull = &loadmodel->hulls[2];
1597 hull->clipnodes = out;
1598 hull->firstclipnode = 0;
1599 hull->lastclipnode = count-1;
1600 hull->planes = loadmodel->planes;
1601 hull->clip_mins[0] = -32;
1602 hull->clip_mins[1] = -32;
1603 hull->clip_mins[2] = -24;
1604 hull->clip_maxs[0] = 32;
1605 hull->clip_maxs[1] = 32;
1606 hull->clip_maxs[2] = 64;
1607 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1610 for (i=0 ; i<count ; i++, out++, in++)
1612 out->planenum = LittleLong(in->planenum);
1613 out->children[0] = LittleShort(in->children[0]);
1614 out->children[1] = LittleShort(in->children[1]);
1615 if (out->children[0] >= count || out->children[1] >= count)
1616 Host_Error("Corrupt clipping hull (out of range child)\n");
1624 Duplicate the drawing hull structure as a clipping hull
1627 static void Mod_MakeHull0 (void)
1634 hull = &loadmodel->hulls[0];
1636 in = loadmodel->nodes;
1637 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1639 hull->clipnodes = out;
1640 hull->firstclipnode = 0;
1641 hull->lastclipnode = loadmodel->numnodes - 1;
1642 hull->planes = loadmodel->planes;
1644 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1646 out->planenum = in->plane - loadmodel->planes;
1647 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1648 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1654 Mod_LoadMarksurfaces
1657 static void Mod_LoadMarksurfaces (lump_t *l)
1662 in = (void *)(mod_base + l->fileofs);
1663 if (l->filelen % sizeof(*in))
1664 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1665 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1666 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
1668 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1670 j = (unsigned) LittleShort(in[i]);
1671 if (j >= loadmodel->numsurfaces)
1672 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1673 loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
1682 static void Mod_LoadSurfedges (lump_t *l)
1687 in = (void *)(mod_base + l->fileofs);
1688 if (l->filelen % sizeof(*in))
1689 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1690 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1691 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1693 for (i = 0;i < loadmodel->numsurfedges;i++)
1694 loadmodel->surfedges[i] = LittleLong (in[i]);
1703 static void Mod_LoadPlanes (lump_t *l)
1709 in = (void *)(mod_base + l->fileofs);
1710 if (l->filelen % sizeof(*in))
1711 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1713 loadmodel->numplanes = l->filelen / sizeof(*in);
1714 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1716 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1718 out->normal[0] = LittleFloat (in->normal[0]);
1719 out->normal[1] = LittleFloat (in->normal[1]);
1720 out->normal[2] = LittleFloat (in->normal[2]);
1721 out->dist = LittleFloat (in->dist);
1727 #define MAX_POINTS_ON_WINDING 64
1733 double points[8][3]; // variable sized
1742 static winding_t *NewWinding (int points)
1747 if (points > MAX_POINTS_ON_WINDING)
1748 Sys_Error("NewWinding: too many points\n");
1750 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1751 w = Mem_Alloc(loadmodel->mempool, size);
1752 memset (w, 0, size);
1757 static void FreeWinding (winding_t *w)
1767 static winding_t *BaseWindingForPlane (mplane_t *p)
1769 double org[3], vright[3], vup[3], normal[3];
1772 VectorCopy(p->normal, normal);
1773 VectorVectorsDouble(normal, vright, vup);
1775 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1776 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1778 // project a really big axis aligned box onto the plane
1781 VectorScale (p->normal, p->dist, org);
1783 VectorSubtract (org, vright, w->points[0]);
1784 VectorAdd (w->points[0], vup, w->points[0]);
1786 VectorAdd (org, vright, w->points[1]);
1787 VectorAdd (w->points[1], vup, w->points[1]);
1789 VectorAdd (org, vright, w->points[2]);
1790 VectorSubtract (w->points[2], vup, w->points[2]);
1792 VectorSubtract (org, vright, w->points[3]);
1793 VectorSubtract (w->points[3], vup, w->points[3]);
1804 Clips the winding to the plane, returning the new winding on the positive side
1805 Frees the input winding.
1806 If keepon is true, an exactly on-plane winding will be saved, otherwise
1807 it will be clipped away.
1810 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1812 double dists[MAX_POINTS_ON_WINDING + 1];
1813 int sides[MAX_POINTS_ON_WINDING + 1];
1822 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1824 // determine sides for each point
1825 for (i = 0;i < in->numpoints;i++)
1827 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1828 if (dot > ON_EPSILON)
1829 sides[i] = SIDE_FRONT;
1830 else if (dot < -ON_EPSILON)
1831 sides[i] = SIDE_BACK;
1836 sides[i] = sides[0];
1837 dists[i] = dists[0];
1839 if (keepon && !counts[0] && !counts[1])
1850 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1851 if (maxpts > MAX_POINTS_ON_WINDING)
1852 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1854 neww = NewWinding (maxpts);
1856 for (i = 0;i < in->numpoints;i++)
1858 if (neww->numpoints >= maxpts)
1859 Sys_Error ("ClipWinding: points exceeded estimate");
1863 if (sides[i] == SIDE_ON)
1865 VectorCopy (p1, neww->points[neww->numpoints]);
1870 if (sides[i] == SIDE_FRONT)
1872 VectorCopy (p1, neww->points[neww->numpoints]);
1876 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1879 // generate a split point
1880 p2 = in->points[(i+1)%in->numpoints];
1882 dot = dists[i] / (dists[i]-dists[i+1]);
1883 for (j = 0;j < 3;j++)
1884 { // avoid round off error when possible
1885 if (split->normal[j] == 1)
1886 mid[j] = split->dist;
1887 else if (split->normal[j] == -1)
1888 mid[j] = -split->dist;
1890 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1893 VectorCopy (mid, neww->points[neww->numpoints]);
1897 // free the original winding
1908 Divides a winding by a plane, producing one or two windings. The
1909 original winding is not damaged or freed. If only on one side, the
1910 returned winding will be the input winding. If on both sides, two
1911 new windings will be created.
1914 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1916 double dists[MAX_POINTS_ON_WINDING + 1];
1917 int sides[MAX_POINTS_ON_WINDING + 1];
1926 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1928 // determine sides for each point
1929 for (i = 0;i < in->numpoints;i++)
1931 dot = DotProduct (in->points[i], split->normal);
1934 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1935 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1936 else sides[i] = SIDE_ON;
1939 sides[i] = sides[0];
1940 dists[i] = dists[0];
1942 *front = *back = NULL;
1955 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1957 if (maxpts > MAX_POINTS_ON_WINDING)
1958 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1960 *front = f = NewWinding (maxpts);
1961 *back = b = NewWinding (maxpts);
1963 for (i = 0;i < in->numpoints;i++)
1965 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
1966 Sys_Error ("DivideWinding: points exceeded estimate");
1970 if (sides[i] == SIDE_ON)
1972 VectorCopy (p1, f->points[f->numpoints]);
1974 VectorCopy (p1, b->points[b->numpoints]);
1979 if (sides[i] == SIDE_FRONT)
1981 VectorCopy (p1, f->points[f->numpoints]);
1984 else if (sides[i] == SIDE_BACK)
1986 VectorCopy (p1, b->points[b->numpoints]);
1990 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1993 // generate a split point
1994 p2 = in->points[(i+1)%in->numpoints];
1996 dot = dists[i] / (dists[i]-dists[i+1]);
1997 for (j = 0;j < 3;j++)
1998 { // avoid round off error when possible
1999 if (split->normal[j] == 1)
2000 mid[j] = split->dist;
2001 else if (split->normal[j] == -1)
2002 mid[j] = -split->dist;
2004 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2007 VectorCopy (mid, f->points[f->numpoints]);
2009 VectorCopy (mid, b->points[b->numpoints]);
2014 typedef struct portal_s
2017 mnode_t *nodes[2]; // [0] = front side of plane
2018 struct portal_s *next[2];
2020 struct portal_s *chain; // all portals are linked into a list
2024 static portal_t *portalchain;
2031 static portal_t *AllocPortal (void)
2034 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2035 p->chain = portalchain;
2040 static void FreePortal(portal_t *p)
2045 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2047 // calculate children first
2048 if (node->children[0]->contents >= 0)
2049 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2050 if (node->children[1]->contents >= 0)
2051 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2053 // make combined bounding box from children
2054 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2055 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2056 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2057 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2058 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2059 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2062 static void Mod_FinalizePortals(void)
2064 int i, j, numportals, numpoints;
2065 portal_t *p, *pnext;
2068 mleaf_t *leaf, *endleaf;
2071 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2072 leaf = loadmodel->leafs;
2073 endleaf = leaf + loadmodel->numleafs;
2074 for (;leaf < endleaf;leaf++)
2076 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2077 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2084 for (i = 0;i < 2;i++)
2086 leaf = (mleaf_t *)p->nodes[i];
2088 for (j = 0;j < w->numpoints;j++)
2090 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2091 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2092 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2093 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2094 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2095 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2102 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2104 // tally up portal and point counts
2110 // note: this check must match the one below or it will usually corrupt memory
2111 // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2112 if (p->winding && p->nodes[0] != p->nodes[1]
2113 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2114 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2117 numpoints += p->winding->numpoints * 2;
2121 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2122 loadmodel->numportals = numportals;
2123 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2124 loadmodel->numportalpoints = numpoints;
2125 // clear all leaf portal chains
2126 for (i = 0;i < loadmodel->numleafs;i++)
2127 loadmodel->leafs[i].portals = NULL;
2128 // process all portals in the global portal chain, while freeing them
2129 portal = loadmodel->portals;
2130 point = loadmodel->portalpoints;
2139 // note: this check must match the one above or it will usually corrupt memory
2140 // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2141 if (p->nodes[0] != p->nodes[1]
2142 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2143 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2145 // first make the back to front portal (forward portal)
2146 portal->points = point;
2147 portal->numpoints = p->winding->numpoints;
2148 portal->plane.dist = p->plane.dist;
2149 VectorCopy(p->plane.normal, portal->plane.normal);
2150 portal->here = (mleaf_t *)p->nodes[1];
2151 portal->past = (mleaf_t *)p->nodes[0];
2153 for (j = 0;j < portal->numpoints;j++)
2155 VectorCopy(p->winding->points[j], point->position);
2158 PlaneClassify(&portal->plane);
2160 // link into leaf's portal chain
2161 portal->next = portal->here->portals;
2162 portal->here->portals = portal;
2164 // advance to next portal
2167 // then make the front to back portal (backward portal)
2168 portal->points = point;
2169 portal->numpoints = p->winding->numpoints;
2170 portal->plane.dist = -p->plane.dist;
2171 VectorNegate(p->plane.normal, portal->plane.normal);
2172 portal->here = (mleaf_t *)p->nodes[0];
2173 portal->past = (mleaf_t *)p->nodes[1];
2175 for (j = portal->numpoints - 1;j >= 0;j--)
2177 VectorCopy(p->winding->points[j], point->position);
2180 PlaneClassify(&portal->plane);
2182 // link into leaf's portal chain
2183 portal->next = portal->here->portals;
2184 portal->here->portals = portal;
2186 // advance to next portal
2189 FreeWinding(p->winding);
2201 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2204 Host_Error ("AddPortalToNodes: NULL front node");
2206 Host_Error ("AddPortalToNodes: NULL back node");
2207 if (p->nodes[0] || p->nodes[1])
2208 Host_Error ("AddPortalToNodes: already included");
2209 // note: front == back is handled gracefully, because leaf 0 is the shared solid leaf, it can often have portals with the same leaf on both sides
2211 p->nodes[0] = front;
2212 p->next[0] = (portal_t *)front->portals;
2213 front->portals = (mportal_t *)p;
2216 p->next[1] = (portal_t *)back->portals;
2217 back->portals = (mportal_t *)p;
2222 RemovePortalFromNode
2225 static void RemovePortalFromNodes(portal_t *portal)
2229 void **portalpointer;
2231 for (i = 0;i < 2;i++)
2233 node = portal->nodes[i];
2235 portalpointer = (void **) &node->portals;
2240 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2244 if (portal->nodes[0] == node)
2246 *portalpointer = portal->next[0];
2247 portal->nodes[0] = NULL;
2249 else if (portal->nodes[1] == node)
2251 *portalpointer = portal->next[1];
2252 portal->nodes[1] = NULL;
2255 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2259 if (t->nodes[0] == node)
2260 portalpointer = (void **) &t->next[0];
2261 else if (t->nodes[1] == node)
2262 portalpointer = (void **) &t->next[1];
2264 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2269 static void Mod_RecursiveNodePortals (mnode_t *node)
2272 mnode_t *front, *back, *other_node;
2273 mplane_t clipplane, *plane;
2274 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2275 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2277 // if a leaf, we're done
2281 plane = node->plane;
2283 front = node->children[0];
2284 back = node->children[1];
2286 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2288 // create the new portal by generating a polygon for the node plane,
2289 // and clipping it by all of the other portals (which came from nodes above this one)
2290 nodeportal = AllocPortal ();
2291 nodeportal->plane = *node->plane;
2293 nodeportalwinding = BaseWindingForPlane (node->plane);
2294 side = 0; // shut up compiler warning
2295 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2297 clipplane = portal->plane;
2298 if (portal->nodes[0] == portal->nodes[1])
2299 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2300 if (portal->nodes[0] == node)
2302 else if (portal->nodes[1] == node)
2304 clipplane.dist = -clipplane.dist;
2305 VectorNegate (clipplane.normal, clipplane.normal);
2309 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2311 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2312 if (!nodeportalwinding)
2314 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2319 if (nodeportalwinding)
2321 // if the plane was not clipped on all sides, there was an error
2322 nodeportal->winding = nodeportalwinding;
2323 AddPortalToNodes (nodeportal, front, back);
2326 // split the portals of this node along this node's plane and assign them to the children of this node
2327 // (migrating the portals downward through the tree)
2328 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2330 if (portal->nodes[0] == portal->nodes[1])
2331 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2332 if (portal->nodes[0] == node)
2334 else if (portal->nodes[1] == node)
2337 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2338 nextportal = portal->next[side];
2340 other_node = portal->nodes[!side];
2341 RemovePortalFromNodes (portal);
2343 // cut the portal into two portals, one on each side of the node plane
2344 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2349 AddPortalToNodes (portal, back, other_node);
2351 AddPortalToNodes (portal, other_node, back);
2357 AddPortalToNodes (portal, front, other_node);
2359 AddPortalToNodes (portal, other_node, front);
2363 // the winding is split
2364 splitportal = AllocPortal ();
2365 temp = splitportal->chain;
2366 *splitportal = *portal;
2367 splitportal->chain = temp;
2368 splitportal->winding = backwinding;
2369 FreeWinding (portal->winding);
2370 portal->winding = frontwinding;
2374 AddPortalToNodes (portal, front, other_node);
2375 AddPortalToNodes (splitportal, back, other_node);
2379 AddPortalToNodes (portal, other_node, front);
2380 AddPortalToNodes (splitportal, other_node, back);
2384 Mod_RecursiveNodePortals(front);
2385 Mod_RecursiveNodePortals(back);
2389 static void Mod_MakePortals(void)
2392 Mod_RecursiveNodePortals (loadmodel->nodes);
2393 Mod_FinalizePortals();
2401 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2406 mempool_t *mainmempool;
2409 mod->type = mod_brush;
2411 header = (dheader_t *)buffer;
2413 i = LittleLong (header->version);
2414 if (i != BSPVERSION && i != 30)
2415 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2416 mod->ishlbsp = i == 30;
2417 if (loadmodel->isworldmodel)
2419 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2420 // until we get a texture for it...
2424 // swap all the lumps
2425 mod_base = (qbyte *)header;
2427 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2428 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2432 // store which lightmap format to use
2433 mod->lightmaprgba = r_lightmaprgba.integer;
2435 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2436 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2437 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2438 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2439 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2440 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2441 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2442 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2443 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2444 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2445 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2446 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2447 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2448 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2449 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2454 mod->numframes = 2; // regular and alternate animation
2456 mainmempool = mod->mempool;
2457 loadname = mod->name;
2459 Mod_LoadLightList ();
2462 // set up the submodels (FIXME: this is confusing)
2464 for (i = 0;i < mod->numsubmodels;i++)
2467 float dist, modelyawradius, modelradius, *vec;
2470 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2471 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2475 bm = &mod->submodels[i];
2477 mod->hulls[0].firstclipnode = bm->headnode[0];
2478 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2480 mod->hulls[j].firstclipnode = bm->headnode[j];
2481 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2484 mod->firstmodelsurface = bm->firstface;
2485 mod->nummodelsurfaces = bm->numfaces;
2487 mod->DrawSky = NULL;
2488 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2489 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2491 // we only need to have a drawsky function if it is used (usually only on world model)
2492 if (surf->shader == &Cshader_sky)
2493 mod->DrawSky = R_DrawBrushModelSky;
2494 for (k = 0;k < surf->numedges;k++)
2496 l = mod->surfedges[k + surf->firstedge];
2498 vec = mod->vertexes[mod->edges[l].v[0]].position;
2500 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2501 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2502 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2503 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2504 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2505 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2506 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2507 dist = vec[0]*vec[0]+vec[1]*vec[1];
2508 if (modelyawradius < dist)
2509 modelyawradius = dist;
2510 dist += vec[2]*vec[2];
2511 if (modelradius < dist)
2515 modelyawradius = sqrt(modelyawradius);
2516 modelradius = sqrt(modelradius);
2517 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2518 mod->yawmins[2] = mod->normalmins[2];
2519 mod->yawmaxs[2] = mod->normalmaxs[2];
2520 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2521 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2522 // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
2523 if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
2525 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2526 VectorClear(mod->normalmins);
2527 VectorClear(mod->normalmaxs);
2528 VectorClear(mod->yawmins);
2529 VectorClear(mod->yawmaxs);
2530 VectorClear(mod->rotatedmins);
2531 VectorClear(mod->rotatedmaxs);
2534 mod->numleafs = bm->visleafs;
2536 mod->Draw = R_DrawBrushModelNormal;
2537 mod->DrawShadow = NULL;
2539 Mod_BrushSortedSurfaces(mod, mainmempool);
2541 // LordHavoc: only register submodels if it is the world
2542 // (prevents bsp models from replacing world submodels)
2543 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2546 // duplicate the basic information
2547 sprintf (name, "*%i", i+1);
2548 loadmodel = Mod_FindName (name);
2550 strcpy (loadmodel->name, name);
2551 // textures and memory belong to the main model
2552 loadmodel->texturepool = NULL;
2553 loadmodel->mempool = NULL;