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 byte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
25 qboolean hlbsp; // LordHavoc: true if it is a HalfLife BSP file (version 30)
27 cvar_t gl_subdivide_size = {CVAR_SAVE, "gl_subdivide_size", "128"};
28 cvar_t halflifebsp = {0, "halflifebsp", "0"};
29 cvar_t r_novis = {0, "r_novis", "0"};
36 void Mod_BrushInit (void)
38 Cvar_RegisterVariable (&gl_subdivide_size);
39 Cvar_RegisterVariable (&halflifebsp);
40 Cvar_RegisterVariable (&r_novis);
41 memset(mod_novis, 0xff, sizeof(mod_novis));
44 void Mod_Brush_SERAddEntity(void)
46 R_Clip_AddBox(currentrenderentity->mins, currentrenderentity->maxs, R_Entity_Callback, currentrenderentity, NULL);
54 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
58 // if (!model || !model->nodes)
59 // Sys_Error ("Mod_PointInLeaf: bad model");
63 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
64 while (node->contents == 0);
66 return (mleaf_t *)node;
69 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
75 if (!model || !model->nodes)
76 Sys_Error ("Mod_PointInLeaf: bad model");
81 if (node->contents < 0)
82 return (mleaf_t *)node;
84 d = DotProduct (p,plane->normal) - plane->dist;
86 node = node->children[0];
88 node = node->children[1];
91 return NULL; // never reached
100 static byte *Mod_DecompressVis (byte *in, model_t *model)
102 static byte decompressed[MAX_MAP_LEAFS/8];
107 row = (model->numleafs+7)>>3;
112 { // no vis info, so make all visible
137 } while (out - decompressed < row);
142 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
144 if (r_novis.value || leaf == model->leafs || leaf->compressed_vis == NULL)
146 return Mod_DecompressVis (leaf->compressed_vis, model);
149 rtexture_t *r_notexture;
150 texture_t r_notexture_mip;
152 void Mod_SetupNoTexture(void)
157 // create a simple checkerboard texture for the default
158 // LordHavoc: redesigned this to remove reliance on the palette and texture_t
159 for (y = 0;y < 16;y++)
161 for (x = 0;x < 16;x++)
163 if ((y < 8) ^ (x < 8))
180 r_notexture = R_LoadTexture("notexture", 16, 16, &pix[0][0][0], TEXF_MIPMAP | TEXF_RGBA);
182 strcpy(r_notexture_mip.name, "notexture");
183 r_notexture_mip.width = 16;
184 r_notexture_mip.height = 16;
185 r_notexture_mip.transparent = false;
186 r_notexture_mip.texture = r_notexture;
187 r_notexture_mip.glowtexture = NULL;
195 static void Mod_LoadTextures (lump_t *l)
197 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs;
199 texture_t *tx, *tx2, *anims[10], *altanims[10];
205 loadmodel->textures = NULL;
209 m = (dmiptexlump_t *)(mod_base + l->fileofs);
211 m->nummiptex = LittleLong (m->nummiptex);
213 loadmodel->numtextures = m->nummiptex;
214 loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures), va("%s texture headers", loadname));
216 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
218 for (i = 0;i < m->nummiptex;i++)
220 dofs[i] = LittleLong(dofs[i]);
223 dmiptex = (miptex_t *)((byte *)m + dofs[i]);
224 mtwidth = LittleLong (dmiptex->width);
225 mtheight = LittleLong (dmiptex->height);
227 j = LittleLong (dmiptex->offsets[0]);
231 if (j < 40 || j + mtwidth * mtheight > l->filelen)
232 Host_Error ("Texture %s is corrupt or incomplete\n", dmiptex->name);
233 mtdata = (byte *)dmiptex + j;
236 if ((mtwidth & 15) || (mtheight & 15))
237 Host_Error ("Texture %s is not 16 aligned", dmiptex->name);
238 // LordHavoc: rewriting the map texture loader for GLQuake
239 tx = Hunk_AllocName (sizeof(texture_t), va("%s textures", loadname));
240 memset(tx, 0, sizeof(texture_t));
242 tx->alternate_anims = NULL;
243 loadmodel->textures[i] = tx;
245 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
246 for (j = 0;dmiptex->name[j] && j < 15;j++)
248 if (dmiptex->name[j] >= 'A' && dmiptex->name[j] <= 'Z')
249 tx->name[j] = dmiptex->name[j] + ('a' - 'A');
251 tx->name[j] = dmiptex->name[j];
258 Con_Printf("warning: unnamed texture in %s\n", loadname);
259 sprintf(tx->name, "unnamed%i", i);
262 tx->transparent = false;
263 data = loadimagepixels(tx->name, false, 0, 0);
266 if (!hlbsp && !strncmp(tx->name,"sky",3) && image_width == 256 && image_height == 128) // LordHavoc: HL sky textures are entirely unrelated
270 tx->transparent = false;
272 tx->glowtexture = NULL;
278 tx->height = mtheight;
279 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
280 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
281 tx->glowtexture = NULL;
289 if (mtdata) // texture included
291 data = W_ConvertWAD3Texture(dmiptex);
295 tx->height = mtheight;
296 tx->transparent = Image_CheckAlpha(data, mtwidth * mtheight, true);
297 tx->texture = R_LoadTexture (tx->name, mtwidth, mtheight, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
298 tx->glowtexture = NULL;
304 data = W_GetTexture(tx->name);
305 // get the size from the wad texture
308 tx->width = image_width;
309 tx->height = image_height;
310 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
311 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
312 tx->glowtexture = NULL;
320 tx->transparent = false;
321 tx->texture = r_notexture;
322 tx->glowtexture = NULL;
327 if (!strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128)
330 tx->height = mtheight;
331 tx->transparent = false;
333 tx->glowtexture = NULL;
334 R_InitSky (mtdata, 1);
338 if (mtdata) // texture included
343 tx->height = mtheight;
344 tx->transparent = false;
346 if (r_fullbrights.value && tx->name[0] != '*')
348 for (j = 0;j < tx->width*tx->height;j++)
350 if (data[j] >= 224) // fullbright
361 data2 = qmalloc(tx->width*tx->height);
362 for (j = 0;j < tx->width*tx->height;j++)
363 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
364 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
365 strcpy(name, tx->name);
366 strcat(name, "_glow");
367 for (j = 0;j < tx->width*tx->height;j++)
368 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
369 tx->glowtexture = R_LoadTexture (name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
374 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data, TEXF_MIPMAP | TEXF_PRECACHE);
375 tx->glowtexture = NULL;
378 else // no texture, and no external replacement texture was found
382 tx->transparent = false;
383 tx->texture = r_notexture;
384 tx->glowtexture = NULL;
392 // sequence the animations
394 for (i = 0;i < m->nummiptex;i++)
396 tx = loadmodel->textures[i];
397 if (!tx || tx->name[0] != '+')
400 continue; // already sequenced
402 // find the number of frames in the animation
403 memset (anims, 0, sizeof(anims));
404 memset (altanims, 0, sizeof(altanims));
407 for (j = i;j < m->nummiptex;j++)
409 tx2 = loadmodel->textures[j];
410 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
414 if (num >= '0' && num <= '9')
415 anims[num - '0'] = tx2;
416 else if (num >= 'a' && num <= 'j')
417 altanims[num - 'a'] = tx2;
419 Host_Error ("Bad animating texture %s", tx->name);
422 for (j = 0;j < 10;j++)
424 if (anims[j] != NULL)
426 if (altanims[j] != NULL)
430 // link them all together
431 for (j = 0;j < max;j++)
435 Host_Error ("Missing frame %i of %s", j, tx->name);
436 tx2->anim_total = max;
437 tx2->alternate_anims = altanims[0]; // NULL if there is no alternate
438 for (k = 0;k < 10;k++)
439 tx2->anim_frames[k] = anims[k];
442 for (j = 0;j < altmax;j++)
446 Host_Error ("Missing frame %i of %s", j, tx->name);
447 tx2->anim_total = altmax;
448 tx2->alternate_anims = anims[0]; // NULL if there is no alternate
449 for (k = 0;k < 10;k++)
450 tx2->anim_frames[k] = altanims[k];
460 static void Mod_LoadLighting (lump_t *l)
463 byte *in, *out, *data;
465 char litfilename[1024];
466 loadmodel->lightdata = NULL;
467 if (hlbsp) // LordHavoc: load the colored lighting data straight
469 loadmodel->lightdata = Hunk_AllocName ( l->filelen, va("%s lightmaps", loadname));
470 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
472 else // LordHavoc: bsp version 29 (normal white lighting)
474 // LordHavoc: hope is not lost yet, check for a .lit file to load
475 strcpy(litfilename, loadmodel->name);
476 COM_StripExtension(litfilename, litfilename);
477 strcat(litfilename, ".lit");
478 data = (byte*) COM_LoadHunkFile (litfilename, false);
481 if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
483 i = LittleLong(((int *)data)[1]);
486 Con_DPrintf("%s loaded", litfilename);
487 loadmodel->lightdata = data + 8;
491 Con_Printf("Unknown .lit file version (%d)\n", i);
494 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
496 // LordHavoc: oh well, expand the white lighting data
499 loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, va("%s lightmaps", loadname));
500 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
501 out = loadmodel->lightdata;
502 memcpy (in, mod_base + l->fileofs, l->filelen);
503 for (i = 0;i < l->filelen;i++)
519 static void Mod_LoadVisibility (lump_t *l)
523 loadmodel->visdata = NULL;
526 loadmodel->visdata = Hunk_AllocName ( l->filelen, va("%s visdata", loadname));
527 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
535 static void Mod_LoadEntities (lump_t *l)
539 loadmodel->entities = NULL;
542 loadmodel->entities = Hunk_AllocName ( l->filelen, va("%s entities", loadname));
543 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
546 CL_ParseEntityLump(loadmodel->entities);
555 static void Mod_LoadVertexes (lump_t *l)
561 in = (void *)(mod_base + l->fileofs);
562 if (l->filelen % sizeof(*in))
563 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
564 count = l->filelen / sizeof(*in);
565 out = Hunk_AllocName ( count*sizeof(*out), va("%s vertices", loadname));
567 loadmodel->vertexes = out;
568 loadmodel->numvertexes = count;
570 for ( i=0 ; i<count ; i++, in++, out++)
572 out->position[0] = LittleFloat (in->point[0]);
573 out->position[1] = LittleFloat (in->point[1]);
574 out->position[2] = LittleFloat (in->point[2]);
583 static void Mod_LoadSubmodels (lump_t *l)
589 in = (void *)(mod_base + l->fileofs);
590 if (l->filelen % sizeof(*in))
591 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
592 count = l->filelen / sizeof(*in);
593 out = Hunk_AllocName ( count*sizeof(*out), va("%s submodels", loadname));
595 loadmodel->submodels = out;
596 loadmodel->numsubmodels = count;
598 for ( i=0 ; i<count ; i++, in++, out++)
600 for (j=0 ; j<3 ; j++)
602 // spread the mins / maxs by a pixel
603 out->mins[j] = LittleFloat (in->mins[j]) - 1;
604 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
605 out->origin[j] = LittleFloat (in->origin[j]);
607 for (j=0 ; j<MAX_MAP_HULLS ; j++)
608 out->headnode[j] = LittleLong (in->headnode[j]);
609 out->visleafs = LittleLong (in->visleafs);
610 out->firstface = LittleLong (in->firstface);
611 out->numfaces = LittleLong (in->numfaces);
620 static void Mod_LoadEdges (lump_t *l)
626 in = (void *)(mod_base + l->fileofs);
627 if (l->filelen % sizeof(*in))
628 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
629 count = l->filelen / sizeof(*in);
630 out = Hunk_AllocName ( (count + 1) * sizeof(*out), va("%s edges", loadname));
632 loadmodel->edges = out;
633 loadmodel->numedges = count;
635 for ( i=0 ; i<count ; i++, in++, out++)
637 out->v[0] = (unsigned short)LittleShort(in->v[0]);
638 out->v[1] = (unsigned short)LittleShort(in->v[1]);
647 static void Mod_LoadTexinfo (lump_t *l)
654 in = (void *)(mod_base + l->fileofs);
655 if (l->filelen % sizeof(*in))
656 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
657 count = l->filelen / sizeof(*in);
658 out = Hunk_AllocName ( count*sizeof(*out), va("%s texinfo", loadname));
660 loadmodel->texinfo = out;
661 loadmodel->numtexinfo = count;
663 for ( i=0 ; i<count ; i++, in++, out++)
665 for (k=0 ; k<2 ; k++)
666 for (j=0 ; j<4 ; j++)
667 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
669 miptex = LittleLong (in->miptex);
670 out->flags = LittleLong (in->flags);
672 if (!loadmodel->textures)
674 out->texture = &r_notexture_mip; // checkerboard texture
679 if (miptex >= loadmodel->numtextures)
680 Host_Error ("miptex >= loadmodel->numtextures");
681 out->texture = loadmodel->textures[miptex];
684 out->texture = &r_notexture_mip; // checkerboard texture
695 Fills in s->texturemins[] and s->extents[]
698 static void CalcSurfaceExtents (msurface_t *s)
700 float mins[2], maxs[2], val;
704 int bmins[2], bmaxs[2];
706 mins[0] = mins[1] = 999999;
707 maxs[0] = maxs[1] = -99999;
711 for (i=0 ; i<s->numedges ; i++)
713 e = loadmodel->surfedges[s->firstedge+i];
715 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
717 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
719 for (j=0 ; j<2 ; j++)
721 val = v->position[0] * tex->vecs[j][0] +
722 v->position[1] * tex->vecs[j][1] +
723 v->position[2] * tex->vecs[j][2] +
732 for (i=0 ; i<2 ; i++)
734 bmins[i] = floor(mins[i]/16);
735 bmaxs[i] = ceil(maxs[i]/16);
737 s->texturemins[i] = bmins[i] * 16;
738 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
739 // if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
740 if ((tex->flags & TEX_SPECIAL) == 0 && (s->extents[i]+1) > (256*16))
741 Host_Error ("Bad surface extents");
745 void GL_SubdivideSurface (msurface_t *fa);
752 static void Mod_LoadFaces (lump_t *l)
756 int i, count, surfnum;
759 in = (void *)(mod_base + l->fileofs);
760 if (l->filelen % sizeof(*in))
761 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
762 count = l->filelen / sizeof(*in);
763 out = Hunk_AllocName ( count*sizeof(*out), va("%s faces", loadname));
765 loadmodel->surfaces = out;
766 loadmodel->numsurfaces = count;
768 for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
770 out->firstedge = LittleLong(in->firstedge);
771 out->numedges = LittleShort(in->numedges);
774 planenum = LittleShort(in->planenum);
775 side = LittleShort(in->side);
777 out->flags |= SURF_PLANEBACK;
779 out->plane = loadmodel->planes + planenum;
781 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
783 CalcSurfaceExtents (out);
787 for (i=0 ; i<MAXLIGHTMAPS ; i++)
788 out->styles[i] = in->styles[i];
789 i = LittleLong(in->lightofs);
792 else if (hlbsp) // LordHavoc: HalfLife map (bsp version 30)
793 out->samples = loadmodel->lightdata + i;
794 else // LordHavoc: white lighting (bsp version 29)
795 out->samples = loadmodel->lightdata + (i * 3);
797 // set the drawing flags flag
799 // if (!strncmp(out->texinfo->texture->name,"sky",3)) // sky
800 // LordHavoc: faster check
801 if ((out->texinfo->texture->name[0] == 's' || out->texinfo->texture->name[0] == 'S')
802 && (out->texinfo->texture->name[1] == 'k' || out->texinfo->texture->name[1] == 'K')
803 && (out->texinfo->texture->name[2] == 'y' || out->texinfo->texture->name[2] == 'Y'))
805 // LordHavoc: for consistency reasons, mark sky as fullbright and solid as well
806 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
807 GL_SubdivideSurface (out); // cut up polygon for warps
811 // if (!strncmp(out->texinfo->texture->name,"*",1)) // turbulent
812 if (out->texinfo->texture->name[0] == '*') // LordHavoc: faster check
814 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED | SURF_LIGHTBOTHSIDES);
815 // LordHavoc: some turbulent textures should be fullbright and solid
816 if (!strncmp(out->texinfo->texture->name,"*lava",5)
817 || !strncmp(out->texinfo->texture->name,"*teleport",9)
818 || !strncmp(out->texinfo->texture->name,"*rift",5)) // Scourge of Armagon texture
819 out->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
820 for (i=0 ; i<2 ; i++)
822 out->extents[i] = 16384;
823 out->texturemins[i] = -8192;
825 GL_SubdivideSurface (out); // cut up polygon for warps
829 if (!out->texinfo->texture->transparent)
830 out->flags |= SURF_CLIPSOLID;
840 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
842 node->parent = parent;
843 if (node->contents < 0)
845 Mod_SetParent (node->children[0], node);
846 Mod_SetParent (node->children[1], node);
854 static void Mod_LoadNodes (lump_t *l)
860 in = (void *)(mod_base + l->fileofs);
861 if (l->filelen % sizeof(*in))
862 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
863 count = l->filelen / sizeof(*in);
864 out = Hunk_AllocName ( count*sizeof(*out), va("%s nodes", loadname));
866 loadmodel->nodes = out;
867 loadmodel->numnodes = count;
869 for ( i=0 ; i<count ; i++, in++, out++)
871 for (j=0 ; j<3 ; j++)
873 out->mins[j] = LittleShort (in->mins[j]);
874 out->maxs[j] = LittleShort (in->maxs[j]);
877 p = LittleLong(in->planenum);
878 out->plane = loadmodel->planes + p;
880 out->firstsurface = LittleShort (in->firstface);
881 out->numsurfaces = LittleShort (in->numfaces);
883 for (j=0 ; j<2 ; j++)
885 p = LittleShort (in->children[j]);
887 out->children[j] = loadmodel->nodes + p;
889 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
893 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
901 static void Mod_LoadLeafs (lump_t *l)
907 in = (void *)(mod_base + l->fileofs);
908 if (l->filelen % sizeof(*in))
909 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
910 count = l->filelen / sizeof(*in);
911 out = Hunk_AllocName ( count*sizeof(*out), va("%s leafs", loadname));
913 loadmodel->leafs = out;
914 loadmodel->numleafs = count;
916 for ( i=0 ; i<count ; i++, in++, out++)
918 for (j=0 ; j<3 ; j++)
920 out->mins[j] = LittleShort (in->mins[j]);
921 out->maxs[j] = LittleShort (in->maxs[j]);
924 p = LittleLong(in->contents);
927 out->firstmarksurface = loadmodel->marksurfaces +
928 LittleShort(in->firstmarksurface);
929 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
931 p = LittleLong(in->visofs);
933 out->compressed_vis = NULL;
935 out->compressed_vis = loadmodel->visdata + p;
937 for (j=0 ; j<4 ; j++)
938 out->ambient_sound_level[j] = in->ambient_level[j];
940 // gl underwater warp
941 // LordHavoc: disabled underwater warping
943 if (out->contents != CONTENTS_EMPTY)
945 for (j=0 ; j<out->nummarksurfaces ; j++)
946 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
957 static void Mod_LoadClipnodes (lump_t *l)
959 dclipnode_t *in, *out;
963 in = (void *)(mod_base + l->fileofs);
964 if (l->filelen % sizeof(*in))
965 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
966 count = l->filelen / sizeof(*in);
967 out = Hunk_AllocName ( count*sizeof(*out), va("%s clipnodes", loadname));
969 loadmodel->clipnodes = out;
970 loadmodel->numclipnodes = count;
974 hull = &loadmodel->hulls[1];
975 hull->clipnodes = out;
976 hull->firstclipnode = 0;
977 hull->lastclipnode = count-1;
978 hull->planes = loadmodel->planes;
979 hull->clip_mins[0] = -16;
980 hull->clip_mins[1] = -16;
981 hull->clip_mins[2] = -36;
982 hull->clip_maxs[0] = 16;
983 hull->clip_maxs[1] = 16;
984 hull->clip_maxs[2] = 36;
986 hull = &loadmodel->hulls[2];
987 hull->clipnodes = out;
988 hull->firstclipnode = 0;
989 hull->lastclipnode = count-1;
990 hull->planes = loadmodel->planes;
991 hull->clip_mins[0] = -32;
992 hull->clip_mins[1] = -32;
993 hull->clip_mins[2] = -32;
994 hull->clip_maxs[0] = 32;
995 hull->clip_maxs[1] = 32;
996 hull->clip_maxs[2] = 32;
998 hull = &loadmodel->hulls[3];
999 hull->clipnodes = out;
1000 hull->firstclipnode = 0;
1001 hull->lastclipnode = count-1;
1002 hull->planes = loadmodel->planes;
1003 hull->clip_mins[0] = -16;
1004 hull->clip_mins[1] = -16;
1005 hull->clip_mins[2] = -18;
1006 hull->clip_maxs[0] = 16;
1007 hull->clip_maxs[1] = 16;
1008 hull->clip_maxs[2] = 18;
1012 hull = &loadmodel->hulls[1];
1013 hull->clipnodes = out;
1014 hull->firstclipnode = 0;
1015 hull->lastclipnode = count-1;
1016 hull->planes = loadmodel->planes;
1017 hull->clip_mins[0] = -16;
1018 hull->clip_mins[1] = -16;
1019 hull->clip_mins[2] = -24;
1020 hull->clip_maxs[0] = 16;
1021 hull->clip_maxs[1] = 16;
1022 hull->clip_maxs[2] = 32;
1024 hull = &loadmodel->hulls[2];
1025 hull->clipnodes = out;
1026 hull->firstclipnode = 0;
1027 hull->lastclipnode = count-1;
1028 hull->planes = loadmodel->planes;
1029 hull->clip_mins[0] = -32;
1030 hull->clip_mins[1] = -32;
1031 hull->clip_mins[2] = -24;
1032 hull->clip_maxs[0] = 32;
1033 hull->clip_maxs[1] = 32;
1034 hull->clip_maxs[2] = 64;
1037 for (i=0 ; i<count ; i++, out++, in++)
1039 out->planenum = LittleLong(in->planenum);
1040 out->children[0] = LittleShort(in->children[0]);
1041 out->children[1] = LittleShort(in->children[1]);
1042 if (out->children[0] >= count || out->children[1] >= count)
1043 Host_Error("Corrupt clipping hull (out of range child)\n");
1051 Duplicate the drawing hull structure as a clipping hull
1054 static void Mod_MakeHull0 (void)
1061 hull = &loadmodel->hulls[0];
1063 in = loadmodel->nodes;
1064 count = loadmodel->numnodes;
1065 out = Hunk_AllocName ( count*sizeof(*out), va("%s hull0", loadname));
1067 hull->clipnodes = out;
1068 hull->firstclipnode = 0;
1069 hull->lastclipnode = count - 1;
1070 hull->planes = loadmodel->planes;
1072 for (i = 0;i < count;i++, out++, in++)
1074 out->planenum = in->plane - loadmodel->planes;
1075 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1076 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1082 Mod_LoadMarksurfaces
1085 static void Mod_LoadMarksurfaces (lump_t *l)
1091 in = (void *)(mod_base + l->fileofs);
1092 if (l->filelen % sizeof(*in))
1093 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1094 count = l->filelen / sizeof(*in);
1095 out = Hunk_AllocName ( count*sizeof(*out), va("%s marksurfaces", loadname));
1097 loadmodel->marksurfaces = out;
1098 loadmodel->nummarksurfaces = count;
1100 for ( i=0 ; i<count ; i++)
1102 j = LittleShort(in[i]);
1103 if (j >= loadmodel->numsurfaces)
1104 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1105 out[i] = loadmodel->surfaces + j;
1114 static void Mod_LoadSurfedges (lump_t *l)
1119 in = (void *)(mod_base + l->fileofs);
1120 if (l->filelen % sizeof(*in))
1121 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1122 count = l->filelen / sizeof(*in);
1123 out = Hunk_AllocName ( count*sizeof(*out), va("%s surfedges", loadname));
1125 loadmodel->surfedges = out;
1126 loadmodel->numsurfedges = count;
1128 for ( i=0 ; i<count ; i++)
1129 out[i] = LittleLong (in[i]);
1138 static void Mod_LoadPlanes (lump_t *l)
1145 in = (void *)(mod_base + l->fileofs);
1146 if (l->filelen % sizeof(*in))
1147 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1148 count = l->filelen / sizeof(*in);
1149 out = Hunk_AllocName ( count*2*sizeof(*out), va("%s planes", loadname));
1151 loadmodel->planes = out;
1152 loadmodel->numplanes = count;
1154 for ( i=0 ; i<count ; i++, in++, out++)
1156 for (j=0 ; j<3 ; j++)
1157 out->normal[j] = LittleFloat (in->normal[j]);
1159 out->dist = LittleFloat (in->dist);
1160 // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
1161 // out->type = LittleLong (in->type);
1166 #define MAX_POINTS_ON_WINDING 64
1171 vec3_t points[8]; // variable sized
1180 static winding_t *NewWinding (int points)
1185 if (points > MAX_POINTS_ON_WINDING)
1186 Host_Error("NewWinding: too many points\n");
1188 size = (int)((winding_t *)0)->points[points];
1190 memset (w, 0, size);
1195 static void FreeWinding (winding_t *w)
1205 static winding_t *BaseWindingForPlane (mplane_t *p)
1207 vec3_t org, vright, vup;
1210 VectorVectors(p->normal, vright, vup);
1212 VectorScale (vup, 65536, vup);
1213 VectorScale (vright, 65536, vright);
1215 // project a really big axis aligned box onto the plane
1218 VectorScale (p->normal, p->dist, org);
1220 VectorSubtract (org, vright, w->points[0]);
1221 VectorAdd (w->points[0], vup, w->points[0]);
1223 VectorAdd (org, vright, w->points[1]);
1224 VectorAdd (w->points[1], vup, w->points[1]);
1226 VectorAdd (org, vright, w->points[2]);
1227 VectorSubtract (w->points[2], vup, w->points[2]);
1229 VectorSubtract (org, vright, w->points[3]);
1230 VectorSubtract (w->points[3], vup, w->points[3]);
1241 Clips the winding to the plane, returning the new winding on the positive side
1242 Frees the input winding.
1243 If keepon is true, an exactly on-plane winding will be saved, otherwise
1244 it will be clipped away.
1247 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1249 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1250 int sides[MAX_POINTS_ON_WINDING + 1];
1259 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1261 // determine sides for each point
1262 for (i = 0;i < in->numpoints;i++)
1264 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1265 if (dot > ON_EPSILON)
1266 sides[i] = SIDE_FRONT;
1267 else if (dot < -ON_EPSILON)
1268 sides[i] = SIDE_BACK;
1273 sides[i] = sides[0];
1274 dists[i] = dists[0];
1276 if (keepon && !counts[0] && !counts[1])
1287 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1288 neww = NewWinding (maxpts);
1290 for (i = 0;i < in->numpoints;i++)
1294 if (sides[i] == SIDE_ON)
1296 VectorCopy (p1, neww->points[neww->numpoints]);
1301 if (sides[i] == SIDE_FRONT)
1303 VectorCopy (p1, neww->points[neww->numpoints]);
1307 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1310 // generate a split point
1311 p2 = in->points[(i+1)%in->numpoints];
1313 dot = dists[i] / (dists[i]-dists[i+1]);
1314 for (j = 0;j < 3;j++)
1315 { // avoid round off error when possible
1316 if (split->normal[j] == 1)
1317 mid[j] = split->dist;
1318 else if (split->normal[j] == -1)
1319 mid[j] = -split->dist;
1321 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1324 VectorCopy (mid, neww->points[neww->numpoints]);
1328 if (neww->numpoints > maxpts)
1329 Host_Error ("ClipWinding: points exceeded estimate");
1331 // free the original winding
1342 Divides a winding by a plane, producing one or two windings. The
1343 original winding is not damaged or freed. If only on one side, the
1344 returned winding will be the input winding. If on both sides, two
1345 new windings will be created.
1348 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1350 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1351 int sides[MAX_POINTS_ON_WINDING + 1];
1360 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1362 // determine sides for each point
1363 for (i = 0;i < in->numpoints;i++)
1365 dot = DotProduct (in->points[i], split->normal);
1368 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1369 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1370 else sides[i] = SIDE_ON;
1373 sides[i] = sides[0];
1374 dists[i] = dists[0];
1376 *front = *back = NULL;
1389 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1391 *front = f = NewWinding (maxpts);
1392 *back = b = NewWinding (maxpts);
1394 for (i = 0;i < in->numpoints;i++)
1398 if (sides[i] == SIDE_ON)
1400 VectorCopy (p1, f->points[f->numpoints]);
1402 VectorCopy (p1, b->points[b->numpoints]);
1407 if (sides[i] == SIDE_FRONT)
1409 VectorCopy (p1, f->points[f->numpoints]);
1412 else if (sides[i] == SIDE_BACK)
1414 VectorCopy (p1, b->points[b->numpoints]);
1418 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1421 // generate a split point
1422 p2 = in->points[(i+1)%in->numpoints];
1424 dot = dists[i] / (dists[i]-dists[i+1]);
1425 for (j = 0;j < 3;j++)
1426 { // avoid round off error when possible
1427 if (split->normal[j] == 1)
1428 mid[j] = split->dist;
1429 else if (split->normal[j] == -1)
1430 mid[j] = -split->dist;
1432 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1435 VectorCopy (mid, f->points[f->numpoints]);
1437 VectorCopy (mid, b->points[b->numpoints]);
1441 if (f->numpoints > maxpts || b->numpoints > maxpts)
1442 Host_Error ("DivideWinding: points exceeded estimate");
1445 typedef struct portal_s
1448 mnode_t *nodes[2]; // [0] = front side of plane
1449 struct portal_s *next[2];
1451 struct portal_s *chain; // all portals are linked into a list
1455 static portal_t *portalchain;
1462 static portal_t *AllocPortal (void)
1465 p = qmalloc(sizeof(portal_t));
1466 memset(p, 0, sizeof(portal_t));
1467 p->chain = portalchain;
1472 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
1474 // calculate children first
1475 if (node->children[0]->contents >= 0)
1476 Mod_RecursiveRecalcNodeBBox(node->children[0]);
1477 if (node->children[1]->contents >= 0)
1478 Mod_RecursiveRecalcNodeBBox(node->children[1]);
1480 // make combined bounding box from children
1481 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
1482 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
1483 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
1484 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
1485 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
1486 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
1489 static void Mod_FinalizePortals(void)
1491 int i, j, numportals, numpoints;
1492 portal_t *p, *pnext;
1495 mleaf_t *leaf, *endleaf;
1498 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
1499 leaf = loadmodel->leafs;
1500 endleaf = leaf + loadmodel->numleafs;
1501 for (;leaf < endleaf;leaf++)
1503 VectorSet( 2000000000, 2000000000, 2000000000, leaf->mins);
1504 VectorSet(-2000000000, -2000000000, -2000000000, leaf->maxs);
1511 for (i = 0;i < 2;i++)
1513 leaf = (mleaf_t *)p->nodes[i];
1515 for (j = 0;j < w->numpoints;j++)
1517 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
1518 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
1519 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
1520 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
1521 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
1522 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
1531 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
1535 // tally up portal and point counts
1541 // note: this check must match the one below or it will usually corrupt the hunk
1542 // 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
1543 if (p->winding && p->nodes[0] != p->nodes[1]
1544 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
1545 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
1548 numpoints += p->winding->numpoints * 2;
1552 loadmodel->portals = Hunk_AllocName(numportals * sizeof(mportal_t), va("%s portals", loadmodel->name));
1553 loadmodel->numportals = numportals;
1554 loadmodel->portalpoints = Hunk_AllocName(numpoints * sizeof(mvertex_t), va("%s portals", loadmodel->name));
1555 loadmodel->numportalpoints = numpoints;
1556 // clear all leaf portal chains
1557 for (i = 0;i < loadmodel->numleafs;i++)
1558 loadmodel->leafs[i].portals = NULL;
1559 // process all portals in the global portal chain, while freeing them
1560 portal = loadmodel->portals;
1561 point = loadmodel->portalpoints;
1570 // note: this check must match the one below or it will usually corrupt the hunk
1571 // 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
1572 if (p->nodes[0] != p->nodes[1]
1573 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
1574 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
1576 // first make the back to front portal (forward portal)
1577 portal->points = point;
1578 portal->numpoints = p->winding->numpoints;
1579 portal->plane.dist = p->plane.dist;
1580 VectorCopy(p->plane.normal, portal->plane.normal);
1581 portal->here = (mleaf_t *)p->nodes[1];
1582 portal->past = (mleaf_t *)p->nodes[0];
1584 for (j = 0;j < portal->numpoints;j++)
1586 VectorCopy(p->winding->points[j], point->position);
1589 PlaneClassify(&portal->plane);
1591 // link into leaf's portal chain
1592 portal->next = portal->here->portals;
1593 portal->here->portals = portal;
1595 // advance to next portal
1598 // then make the front to back portal (backward portal)
1599 portal->points = point;
1600 portal->numpoints = p->winding->numpoints;
1601 portal->plane.dist = -p->plane.dist;
1602 VectorNegate(p->plane.normal, portal->plane.normal);
1603 portal->here = (mleaf_t *)p->nodes[0];
1604 portal->past = (mleaf_t *)p->nodes[1];
1606 for (j = portal->numpoints - 1;j >= 0;j--)
1608 VectorCopy(p->winding->points[j], point->position);
1611 PlaneClassify(&portal->plane);
1613 // link into leaf's portal chain
1614 portal->next = portal->here->portals;
1615 portal->here->portals = portal;
1617 // advance to next portal
1620 FreeWinding(p->winding);
1632 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
1635 Host_Error ("AddPortalToNodes: NULL front node");
1637 Host_Error ("AddPortalToNodes: NULL back node");
1638 if (p->nodes[0] || p->nodes[1])
1639 Host_Error ("AddPortalToNodes: already included");
1640 // 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
1642 p->nodes[0] = front;
1643 p->next[0] = (portal_t *)front->portals;
1644 front->portals = (mportal_t *)p;
1647 p->next[1] = (portal_t *)back->portals;
1648 back->portals = (mportal_t *)p;
1653 RemovePortalFromNode
1656 static void RemovePortalFromNodes(portal_t *portal)
1660 void **portalpointer;
1662 for (i = 0;i < 2;i++)
1664 node = portal->nodes[i];
1666 portalpointer = (void **) &node->portals;
1671 Host_Error ("RemovePortalFromNodes: portal not in leaf");
1675 if (portal->nodes[0] == node)
1677 *portalpointer = portal->next[0];
1678 portal->nodes[0] = NULL;
1680 else if (portal->nodes[1] == node)
1682 *portalpointer = portal->next[1];
1683 portal->nodes[1] = NULL;
1686 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1690 if (t->nodes[0] == node)
1691 portalpointer = (void **) &t->next[0];
1692 else if (t->nodes[1] == node)
1693 portalpointer = (void **) &t->next[1];
1695 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1700 static void Mod_RecursiveNodePortals (mnode_t *node)
1703 mnode_t *front, *back, *other_node;
1704 mplane_t clipplane, *plane;
1705 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
1706 winding_t *nodeportalwinding, *frontwinding, *backwinding;
1708 // CheckLeafPortalConsistancy (node);
1710 // if a leaf, we're done
1714 plane = node->plane;
1716 front = node->children[0];
1717 back = node->children[1];
1719 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
1721 // create the new portal by generating a polygon for the node plane,
1722 // and clipping it by all of the other portals (which came from nodes above this one)
1723 nodeportal = AllocPortal ();
1724 nodeportal->plane = *node->plane;
1726 nodeportalwinding = BaseWindingForPlane (node->plane);
1727 side = 0; // shut up compiler warning
1728 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
1730 clipplane = portal->plane;
1731 if (portal->nodes[0] == portal->nodes[1])
1732 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
1733 if (portal->nodes[0] == node)
1735 else if (portal->nodes[1] == node)
1737 clipplane.dist = -clipplane.dist;
1738 VectorNegate (clipplane.normal, clipplane.normal);
1742 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1744 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
1745 if (!nodeportalwinding)
1747 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
1752 if (nodeportalwinding)
1754 // if the plane was not clipped on all sides, there was an error
1755 nodeportal->winding = nodeportalwinding;
1756 AddPortalToNodes (nodeportal, front, back);
1759 // split the portals of this node along this node's plane and assign them to the children of this node
1760 // (migrating the portals downward through the tree)
1761 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
1763 if (portal->nodes[0] == portal->nodes[1])
1764 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
1765 if (portal->nodes[0] == node)
1767 else if (portal->nodes[1] == node)
1770 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1771 nextportal = portal->next[side];
1773 other_node = portal->nodes[!side];
1774 RemovePortalFromNodes (portal);
1776 // cut the portal into two portals, one on each side of the node plane
1777 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
1782 AddPortalToNodes (portal, back, other_node);
1784 AddPortalToNodes (portal, other_node, back);
1790 AddPortalToNodes (portal, front, other_node);
1792 AddPortalToNodes (portal, other_node, front);
1796 // the winding is split
1797 splitportal = AllocPortal ();
1798 temp = splitportal->chain;
1799 *splitportal = *portal;
1800 splitportal->chain = temp;
1801 splitportal->winding = backwinding;
1802 FreeWinding (portal->winding);
1803 portal->winding = frontwinding;
1807 AddPortalToNodes (portal, front, other_node);
1808 AddPortalToNodes (splitportal, back, other_node);
1812 AddPortalToNodes (portal, other_node, front);
1813 AddPortalToNodes (splitportal, other_node, back);
1817 Mod_RecursiveNodePortals(front);
1818 Mod_RecursiveNodePortals(back);
1822 void Mod_MakeOutsidePortals(mnode_t *node)
1825 portal_t *p, *portals[6];
1826 mnode_t *outside_node;
1828 outside_node = Hunk_AllocName(sizeof(mnode_t), loadmodel->name);
1829 outside_node->contents = CONTENTS_SOLID;
1830 outside_node->portals = NULL;
1832 for (i = 0;i < 3;i++)
1834 for (j = 0;j < 2;j++)
1836 portals[j*3 + i] = p = AllocPortal ();
1837 memset (&p->plane, 0, sizeof(mplane_t));
1838 p->plane.normal[i] = j ? -1 : 1;
1839 p->plane.dist = -65536;
1840 p->winding = BaseWindingForPlane (&p->plane);
1842 AddPortalToNodes (p, outside_node, node);
1844 AddPortalToNodes (p, node, outside_node);
1848 // clip the basewindings by all the other planes
1849 for (i = 0;i < 6;i++)
1851 for (j = 0;j < 6;j++)
1855 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
1861 static void Mod_MakePortals(void)
1863 // Con_Printf("building portals for %s\n", loadmodel->name);
1866 // Mod_MakeOutsidePortals (loadmodel->nodes);
1867 Mod_RecursiveNodePortals (loadmodel->nodes);
1868 Mod_FinalizePortals();
1876 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1882 loadmodel->type = mod_brush;
1884 header = (dheader_t *)buffer;
1886 i = LittleLong (header->version);
1887 if (i != BSPVERSION && i != 30)
1888 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
1890 halflifebsp.value = hlbsp;
1892 // swap all the lumps
1893 mod_base = (byte *)header;
1895 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1896 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1900 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
1901 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1903 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1904 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1905 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1906 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1907 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1908 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1909 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1910 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1911 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1912 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1913 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1914 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1915 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1916 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1917 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1923 mod->numframes = 2; // regular and alternate animation
1926 // set up the submodels (FIXME: this is confusing)
1928 for (i = 0;i < mod->numsubmodels;i++)
1931 float dist, modelyawradius, modelradius, *vec;
1934 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
1935 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
1939 bm = &mod->submodels[i];
1941 mod->hulls[0].firstclipnode = bm->headnode[0];
1942 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1944 mod->hulls[j].firstclipnode = bm->headnode[j];
1945 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
1948 mod->firstmodelsurface = bm->firstface;
1949 mod->nummodelsurfaces = bm->numfaces;
1951 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
1952 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
1954 for (k = 0;k < surf->numedges;k++)
1956 l = mod->surfedges[k + surf->firstedge];
1958 vec = mod->vertexes[mod->edges[l].v[0]].position;
1960 vec = mod->vertexes[mod->edges[-l].v[1]].position;
1961 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
1962 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
1963 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
1964 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
1965 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
1966 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
1967 dist = vec[0]*vec[0]+vec[1]*vec[1];
1968 if (modelyawradius < dist)
1969 modelyawradius = dist;
1970 dist += vec[2]*vec[2];
1971 if (modelradius < dist)
1975 modelyawradius = sqrt(modelyawradius);
1976 modelradius = sqrt(modelradius);
1977 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
1978 mod->yawmins[2] = mod->normalmins[2];
1979 mod->yawmaxs[2] = mod->normalmaxs[2];
1980 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
1981 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
1982 // mod->modelradius = modelradius;
1984 // VectorCopy (bm->maxs, mod->maxs);
1985 // VectorCopy (bm->mins, mod->mins);
1987 // mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1989 mod->numleafs = bm->visleafs;
1991 mod->SERAddEntity = Mod_Brush_SERAddEntity;
1992 mod->DrawEarly = R_DrawBrushModel;
1993 mod->DrawLate = NULL;
1994 mod->DrawShadow = NULL;
1996 if (isworldmodel && i < (mod->numsubmodels - 1)) // LordHavoc: only register submodels if it is the world (prevents bsp models from replacing world submodels)
1997 { // duplicate the basic information
2000 sprintf (name, "*%i", i+1);
2001 loadmodel = Mod_FindName (name);
2003 strcpy (loadmodel->name, name);