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/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));
49 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
53 // if (!model || !model->nodes)
54 // Sys_Error ("Mod_PointInLeaf: bad model");
58 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
59 while (node->contents == 0);
61 return (mleaf_t *)node;
64 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
70 if (!model || !model->nodes)
71 Sys_Error ("Mod_PointInLeaf: bad model");
76 if (node->contents < 0)
77 return (mleaf_t *)node;
79 d = DotProduct (p,plane->normal) - plane->dist;
81 node = node->children[0];
83 node = node->children[1];
86 return NULL; // never reached
95 byte *Mod_DecompressVis (byte *in, model_t *model)
97 static byte decompressed[MAX_MAP_LEAFS/8];
102 row = (model->numleafs+7)>>3;
107 { // no vis info, so make all visible
132 } while (out - decompressed < row);
137 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
139 if (r_novis.value || leaf == model->leafs || leaf->compressed_vis == NULL)
141 return Mod_DecompressVis (leaf->compressed_vis, model);
144 rtexture_t *r_notexture;
145 texture_t r_notexture_mip;
147 void Mod_SetupNoTexture(void)
152 // create a simple checkerboard texture for the default
153 // LordHavoc: redesigned this to remove reliance on the palette and texture_t
154 for (y = 0;y < 16;y++)
156 for (x = 0;x < 16;x++)
158 if ((y < 8) ^ (x < 8))
175 r_notexture = R_LoadTexture("notexture", 16, 16, &pix[0][0][0], TEXF_MIPMAP | TEXF_RGBA);
177 strcpy(r_notexture_mip.name, "notexture");
178 r_notexture_mip.width = 16;
179 r_notexture_mip.height = 16;
180 r_notexture_mip.transparent = false;
181 r_notexture_mip.texture = r_notexture;
182 r_notexture_mip.glowtexture = NULL;
190 void Mod_LoadTextures (lump_t *l)
192 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs;
194 texture_t *tx, *tx2, *anims[10], *altanims[10];
200 loadmodel->textures = NULL;
204 m = (dmiptexlump_t *)(mod_base + l->fileofs);
206 m->nummiptex = LittleLong (m->nummiptex);
208 loadmodel->numtextures = m->nummiptex;
209 loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures), va("%s texture headers", loadname));
211 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
213 for (i = 0;i < m->nummiptex;i++)
215 dofs[i] = LittleLong(dofs[i]);
218 dmiptex = (miptex_t *)((byte *)m + dofs[i]);
219 mtwidth = LittleLong (dmiptex->width);
220 mtheight = LittleLong (dmiptex->height);
222 j = LittleLong (dmiptex->offsets[0]);
226 if (j < 40 || j + mtwidth * mtheight > l->filelen)
227 Host_Error ("Texture %s is corrupt or incomplete\n", dmiptex->name);
228 mtdata = (byte *)dmiptex + j;
231 if ((mtwidth & 15) || (mtheight & 15))
232 Host_Error ("Texture %s is not 16 aligned", dmiptex->name);
233 // LordHavoc: rewriting the map texture loader for GLQuake
234 tx = Hunk_AllocName (sizeof(texture_t), va("%s textures", loadname));
235 loadmodel->textures[i] = tx;
237 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
238 for (j = 0;dmiptex->name[j] && j < 15;j++)
240 if (dmiptex->name[j] >= 'A' && dmiptex->name[j] <= 'Z')
241 tx->name[j] = dmiptex->name[j] + ('a' - 'A');
243 tx->name[j] = dmiptex->name[j];
250 Con_Printf("warning: unnamed texture in %s\n", loadname);
251 sprintf(tx->name, "unnamed%i", i);
254 tx->transparent = false;
255 data = loadimagepixels(tx->name, false, 0, 0);
258 if (!hlbsp && !strncmp(tx->name,"sky",3) && image_width == 256 && image_height == 128) // LordHavoc: HL sky textures are entirely unrelated
262 tx->transparent = false;
264 tx->glowtexture = NULL;
270 tx->height = mtheight;
271 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
272 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
273 tx->glowtexture = NULL;
281 if (mtdata) // texture included
283 data = W_ConvertWAD3Texture(dmiptex);
287 tx->height = mtheight;
288 tx->transparent = Image_CheckAlpha(data, mtwidth * mtheight, true);
289 tx->texture = R_LoadTexture (tx->name, mtwidth, mtheight, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
290 tx->glowtexture = NULL;
296 data = W_GetTexture(tx->name);
297 // get the size from the wad texture
300 tx->width = image_width;
301 tx->height = image_height;
302 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
303 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
304 tx->glowtexture = NULL;
312 tx->transparent = false;
313 tx->texture = r_notexture;
314 tx->glowtexture = NULL;
319 if (!strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128)
322 tx->height = mtheight;
323 tx->transparent = false;
325 tx->glowtexture = NULL;
326 R_InitSky (mtdata, 1);
330 if (mtdata) // texture included
335 tx->height = mtheight;
336 tx->transparent = false;
338 if (r_fullbrights.value && tx->name[0] != '*')
340 for (j = 0;j < tx->width*tx->height;j++)
342 if (data[j] >= 224) // fullbright
353 data2 = qmalloc(tx->width*tx->height);
354 for (j = 0;j < tx->width*tx->height;j++)
355 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
356 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
357 strcpy(name, tx->name);
358 strcat(name, "_glow");
359 for (j = 0;j < tx->width*tx->height;j++)
360 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
361 tx->glowtexture = R_LoadTexture (name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
366 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data, TEXF_MIPMAP | TEXF_PRECACHE);
367 tx->glowtexture = NULL;
370 else // no texture, and no external replacement texture was found
374 tx->transparent = false;
375 tx->texture = r_notexture;
376 tx->glowtexture = NULL;
384 // sequence the animations
386 for (i = 0;i < m->nummiptex;i++)
388 tx = loadmodel->textures[i];
389 if (!tx || tx->name[0] != '+')
392 continue; // already sequenced
394 // find the number of frames in the animation
395 memset (anims, 0, sizeof(anims));
396 memset (altanims, 0, sizeof(altanims));
400 if (max >= '0' && max <= '9')
407 else if (max >= 'a' && max <= 'j')
411 altanims[altmax] = tx;
415 Host_Error ("Bad animating texture %s", tx->name);
417 for (j = i + 1;j < m->nummiptex;j++)
419 tx2 = loadmodel->textures[j];
420 if (!tx2 || tx2->name[0] != '+')
422 if (strcmp (tx2->name+2, tx->name+2))
426 if (num >= '0' && num <= '9')
433 else if (num >= 'a' && num <= 'j')
441 Host_Error ("Bad animating texture %s", tx->name);
444 // link them all together
445 for (j = 0;j < max;j++)
449 Host_Error ("Missing frame %i of %s", j, tx->name);
450 tx2->anim_total = max;
452 tx2->alternate_anims = altanims[0];
453 for (k = 0;k < 10;k++)
454 tx2->anim_frames[k] = anims[j];
456 for (j = 0;j < altmax;j++)
460 Host_Error ("Missing frame %i of %s", j, tx->name);
461 tx2->anim_total = altmax;
463 tx2->alternate_anims = anims[0];
464 for (k = 0;k < 10;k++)
465 tx2->anim_frames[k] = altanims[j];
475 void Mod_LoadLighting (lump_t *l)
478 byte *in, *out, *data;
480 char litfilename[1024];
481 loadmodel->lightdata = NULL;
482 if (hlbsp) // LordHavoc: load the colored lighting data straight
484 loadmodel->lightdata = Hunk_AllocName ( l->filelen, va("%s lightmaps", loadname));
485 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
487 else // LordHavoc: bsp version 29 (normal white lighting)
489 // LordHavoc: hope is not lost yet, check for a .lit file to load
490 strcpy(litfilename, loadmodel->name);
491 COM_StripExtension(litfilename, litfilename);
492 strcat(litfilename, ".lit");
493 data = (byte*) COM_LoadHunkFile (litfilename, false);
496 if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
498 i = LittleLong(((int *)data)[1]);
501 Con_DPrintf("%s loaded", litfilename);
502 loadmodel->lightdata = data + 8;
506 Con_Printf("Unknown .lit file version (%d)\n", i);
509 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
511 // LordHavoc: oh well, expand the white lighting data
514 loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, va("%s lightmaps", loadname));
515 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
516 out = loadmodel->lightdata;
517 memcpy (in, mod_base + l->fileofs, l->filelen);
518 for (i = 0;i < l->filelen;i++)
534 void Mod_LoadVisibility (lump_t *l)
538 loadmodel->visdata = NULL;
541 loadmodel->visdata = Hunk_AllocName ( l->filelen, va("%s visdata", loadname));
542 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
550 void Mod_LoadEntities (lump_t *l)
554 loadmodel->entities = NULL;
557 loadmodel->entities = Hunk_AllocName ( l->filelen, va("%s entities", loadname));
558 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
561 CL_ParseEntityLump(loadmodel->entities);
570 void Mod_LoadVertexes (lump_t *l)
576 in = (void *)(mod_base + l->fileofs);
577 if (l->filelen % sizeof(*in))
578 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
579 count = l->filelen / sizeof(*in);
580 out = Hunk_AllocName ( count*sizeof(*out), va("%s vertices", loadname));
582 loadmodel->vertexes = out;
583 loadmodel->numvertexes = count;
585 for ( i=0 ; i<count ; i++, in++, out++)
587 out->position[0] = LittleFloat (in->point[0]);
588 out->position[1] = LittleFloat (in->point[1]);
589 out->position[2] = LittleFloat (in->point[2]);
598 void Mod_LoadSubmodels (lump_t *l)
604 in = (void *)(mod_base + l->fileofs);
605 if (l->filelen % sizeof(*in))
606 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
607 count = l->filelen / sizeof(*in);
608 out = Hunk_AllocName ( count*sizeof(*out), va("%s submodels", loadname));
610 loadmodel->submodels = out;
611 loadmodel->numsubmodels = count;
613 for ( i=0 ; i<count ; i++, in++, out++)
615 for (j=0 ; j<3 ; j++)
617 // spread the mins / maxs by a pixel
618 out->mins[j] = LittleFloat (in->mins[j]) - 1;
619 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
620 out->origin[j] = LittleFloat (in->origin[j]);
622 for (j=0 ; j<MAX_MAP_HULLS ; j++)
623 out->headnode[j] = LittleLong (in->headnode[j]);
624 out->visleafs = LittleLong (in->visleafs);
625 out->firstface = LittleLong (in->firstface);
626 out->numfaces = LittleLong (in->numfaces);
635 void Mod_LoadEdges (lump_t *l)
641 in = (void *)(mod_base + l->fileofs);
642 if (l->filelen % sizeof(*in))
643 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
644 count = l->filelen / sizeof(*in);
645 out = Hunk_AllocName ( (count + 1) * sizeof(*out), va("%s edges", loadname));
647 loadmodel->edges = out;
648 loadmodel->numedges = count;
650 for ( i=0 ; i<count ; i++, in++, out++)
652 out->v[0] = (unsigned short)LittleShort(in->v[0]);
653 out->v[1] = (unsigned short)LittleShort(in->v[1]);
662 void Mod_LoadTexinfo (lump_t *l)
669 in = (void *)(mod_base + l->fileofs);
670 if (l->filelen % sizeof(*in))
671 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
672 count = l->filelen / sizeof(*in);
673 out = Hunk_AllocName ( count*sizeof(*out), va("%s texinfo", loadname));
675 loadmodel->texinfo = out;
676 loadmodel->numtexinfo = count;
678 for ( i=0 ; i<count ; i++, in++, out++)
680 for (k=0 ; k<2 ; k++)
681 for (j=0 ; j<4 ; j++)
682 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
684 miptex = LittleLong (in->miptex);
685 out->flags = LittleLong (in->flags);
687 if (!loadmodel->textures)
689 out->texture = &r_notexture_mip; // checkerboard texture
694 if (miptex >= loadmodel->numtextures)
695 Host_Error ("miptex >= loadmodel->numtextures");
696 out->texture = loadmodel->textures[miptex];
699 out->texture = &r_notexture_mip; // checkerboard texture
710 Fills in s->texturemins[] and s->extents[]
713 void CalcSurfaceExtents (msurface_t *s)
715 float mins[2], maxs[2], val;
719 int bmins[2], bmaxs[2];
721 mins[0] = mins[1] = 999999;
722 maxs[0] = maxs[1] = -99999;
726 for (i=0 ; i<s->numedges ; i++)
728 e = loadmodel->surfedges[s->firstedge+i];
730 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
732 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
734 for (j=0 ; j<2 ; j++)
736 val = v->position[0] * tex->vecs[j][0] +
737 v->position[1] * tex->vecs[j][1] +
738 v->position[2] * tex->vecs[j][2] +
747 for (i=0 ; i<2 ; i++)
749 bmins[i] = floor(mins[i]/16);
750 bmaxs[i] = ceil(maxs[i]/16);
752 s->texturemins[i] = bmins[i] * 16;
753 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
754 // if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
755 if ((tex->flags & TEX_SPECIAL) == 0 && (s->extents[i]+1) > (256*16))
756 Host_Error ("Bad surface extents");
760 void GL_SubdivideSurface (msurface_t *fa);
767 void Mod_LoadFaces (lump_t *l)
771 int i, count, surfnum;
774 in = (void *)(mod_base + l->fileofs);
775 if (l->filelen % sizeof(*in))
776 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
777 count = l->filelen / sizeof(*in);
778 out = Hunk_AllocName ( count*sizeof(*out), va("%s faces", loadname));
780 loadmodel->surfaces = out;
781 loadmodel->numsurfaces = count;
783 for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
785 out->firstedge = LittleLong(in->firstedge);
786 out->numedges = LittleShort(in->numedges);
789 planenum = LittleShort(in->planenum);
790 side = LittleShort(in->side);
792 out->flags |= SURF_PLANEBACK;
794 out->plane = loadmodel->planes + planenum;
796 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
798 CalcSurfaceExtents (out);
802 for (i=0 ; i<MAXLIGHTMAPS ; i++)
803 out->styles[i] = in->styles[i];
804 i = LittleLong(in->lightofs);
807 else if (hlbsp) // LordHavoc: HalfLife map (bsp version 30)
808 out->samples = loadmodel->lightdata + i;
809 else // LordHavoc: white lighting (bsp version 29)
810 out->samples = loadmodel->lightdata + (i * 3);
812 // set the drawing flags flag
814 // if (!strncmp(out->texinfo->texture->name,"sky",3)) // sky
815 // LordHavoc: faster check
816 if ((out->texinfo->texture->name[0] == 's' || out->texinfo->texture->name[0] == 'S')
817 && (out->texinfo->texture->name[1] == 'k' || out->texinfo->texture->name[1] == 'K')
818 && (out->texinfo->texture->name[2] == 'y' || out->texinfo->texture->name[2] == 'Y'))
820 // LordHavoc: for consistency reasons, mark sky as fullbright and solid as well
821 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
822 GL_SubdivideSurface (out); // cut up polygon for warps
826 // if (!strncmp(out->texinfo->texture->name,"*",1)) // turbulent
827 if (out->texinfo->texture->name[0] == '*') // LordHavoc: faster check
829 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED | SURF_LIGHTBOTHSIDES);
830 // LordHavoc: some turbulent textures should be fullbright and solid
831 if (!strncmp(out->texinfo->texture->name,"*lava",5)
832 || !strncmp(out->texinfo->texture->name,"*teleport",9)
833 || !strncmp(out->texinfo->texture->name,"*rift",5)) // Scourge of Armagon texture
834 out->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA);
835 for (i=0 ; i<2 ; i++)
837 out->extents[i] = 16384;
838 out->texturemins[i] = -8192;
840 GL_SubdivideSurface (out); // cut up polygon for warps
844 out->flags |= SURF_CLIPSOLID;
854 void Mod_SetParent (mnode_t *node, mnode_t *parent)
856 node->parent = parent;
857 if (node->contents < 0)
859 Mod_SetParent (node->children[0], node);
860 Mod_SetParent (node->children[1], node);
868 void Mod_LoadNodes (lump_t *l)
874 in = (void *)(mod_base + l->fileofs);
875 if (l->filelen % sizeof(*in))
876 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
877 count = l->filelen / sizeof(*in);
878 out = Hunk_AllocName ( count*sizeof(*out), va("%s nodes", loadname));
880 loadmodel->nodes = out;
881 loadmodel->numnodes = count;
883 for ( i=0 ; i<count ; i++, in++, out++)
885 for (j=0 ; j<3 ; j++)
887 out->mins[j] = LittleShort (in->mins[j]);
888 out->maxs[j] = LittleShort (in->maxs[j]);
891 p = LittleLong(in->planenum);
892 out->plane = loadmodel->planes + p;
894 out->firstsurface = LittleShort (in->firstface);
895 out->numsurfaces = LittleShort (in->numfaces);
897 for (j=0 ; j<2 ; j++)
899 p = LittleShort (in->children[j]);
901 out->children[j] = loadmodel->nodes + p;
903 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
907 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
915 void Mod_LoadLeafs (lump_t *l)
921 in = (void *)(mod_base + l->fileofs);
922 if (l->filelen % sizeof(*in))
923 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
924 count = l->filelen / sizeof(*in);
925 out = Hunk_AllocName ( count*sizeof(*out), va("%s leafs", loadname));
927 loadmodel->leafs = out;
928 loadmodel->numleafs = count;
930 for ( i=0 ; i<count ; i++, in++, out++)
932 for (j=0 ; j<3 ; j++)
934 out->mins[j] = LittleShort (in->mins[j]);
935 out->maxs[j] = LittleShort (in->maxs[j]);
938 p = LittleLong(in->contents);
941 out->firstmarksurface = loadmodel->marksurfaces +
942 LittleShort(in->firstmarksurface);
943 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
945 p = LittleLong(in->visofs);
947 out->compressed_vis = NULL;
949 out->compressed_vis = loadmodel->visdata + p;
951 for (j=0 ; j<4 ; j++)
952 out->ambient_sound_level[j] = in->ambient_level[j];
954 // gl underwater warp
955 // LordHavoc: disabled underwater warping
957 if (out->contents != CONTENTS_EMPTY)
959 for (j=0 ; j<out->nummarksurfaces ; j++)
960 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
971 void Mod_LoadClipnodes (lump_t *l)
973 dclipnode_t *in, *out;
977 in = (void *)(mod_base + l->fileofs);
978 if (l->filelen % sizeof(*in))
979 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
980 count = l->filelen / sizeof(*in);
981 out = Hunk_AllocName ( count*sizeof(*out), va("%s clipnodes", loadname));
983 loadmodel->clipnodes = out;
984 loadmodel->numclipnodes = count;
988 hull = &loadmodel->hulls[1];
989 hull->clipnodes = out;
990 hull->firstclipnode = 0;
991 hull->lastclipnode = count-1;
992 hull->planes = loadmodel->planes;
993 hull->clip_mins[0] = -16;
994 hull->clip_mins[1] = -16;
995 hull->clip_mins[2] = -36;
996 hull->clip_maxs[0] = 16;
997 hull->clip_maxs[1] = 16;
998 hull->clip_maxs[2] = 36;
1000 hull = &loadmodel->hulls[2];
1001 hull->clipnodes = out;
1002 hull->firstclipnode = 0;
1003 hull->lastclipnode = count-1;
1004 hull->planes = loadmodel->planes;
1005 hull->clip_mins[0] = -32;
1006 hull->clip_mins[1] = -32;
1007 hull->clip_mins[2] = -32;
1008 hull->clip_maxs[0] = 32;
1009 hull->clip_maxs[1] = 32;
1010 hull->clip_maxs[2] = 32;
1012 hull = &loadmodel->hulls[3];
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] = -18;
1020 hull->clip_maxs[0] = 16;
1021 hull->clip_maxs[1] = 16;
1022 hull->clip_maxs[2] = 18;
1026 hull = &loadmodel->hulls[1];
1027 hull->clipnodes = out;
1028 hull->firstclipnode = 0;
1029 hull->lastclipnode = count-1;
1030 hull->planes = loadmodel->planes;
1031 hull->clip_mins[0] = -16;
1032 hull->clip_mins[1] = -16;
1033 hull->clip_mins[2] = -24;
1034 hull->clip_maxs[0] = 16;
1035 hull->clip_maxs[1] = 16;
1036 hull->clip_maxs[2] = 32;
1038 hull = &loadmodel->hulls[2];
1039 hull->clipnodes = out;
1040 hull->firstclipnode = 0;
1041 hull->lastclipnode = count-1;
1042 hull->planes = loadmodel->planes;
1043 hull->clip_mins[0] = -32;
1044 hull->clip_mins[1] = -32;
1045 hull->clip_mins[2] = -24;
1046 hull->clip_maxs[0] = 32;
1047 hull->clip_maxs[1] = 32;
1048 hull->clip_maxs[2] = 64;
1051 for (i=0 ; i<count ; i++, out++, in++)
1053 out->planenum = LittleLong(in->planenum);
1054 out->children[0] = LittleShort(in->children[0]);
1055 out->children[1] = LittleShort(in->children[1]);
1056 if (out->children[0] >= count || out->children[1] >= count)
1057 Host_Error("Corrupt clipping hull (out of range child)\n");
1065 Duplicate the drawing hull structure as a clipping hull
1068 void Mod_MakeHull0 (void)
1075 hull = &loadmodel->hulls[0];
1077 in = loadmodel->nodes;
1078 count = loadmodel->numnodes;
1079 out = Hunk_AllocName ( count*sizeof(*out), va("%s hull0", loadname));
1081 hull->clipnodes = out;
1082 hull->firstclipnode = 0;
1083 hull->lastclipnode = count - 1;
1084 hull->planes = loadmodel->planes;
1086 for (i = 0;i < count;i++, out++, in++)
1088 out->planenum = in->plane - loadmodel->planes;
1089 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1090 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1096 Mod_LoadMarksurfaces
1099 void Mod_LoadMarksurfaces (lump_t *l)
1105 in = (void *)(mod_base + l->fileofs);
1106 if (l->filelen % sizeof(*in))
1107 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1108 count = l->filelen / sizeof(*in);
1109 out = Hunk_AllocName ( count*sizeof(*out), va("%s marksurfaces", loadname));
1111 loadmodel->marksurfaces = out;
1112 loadmodel->nummarksurfaces = count;
1114 for ( i=0 ; i<count ; i++)
1116 j = LittleShort(in[i]);
1117 if (j >= loadmodel->numsurfaces)
1118 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1119 out[i] = loadmodel->surfaces + j;
1128 void Mod_LoadSurfedges (lump_t *l)
1133 in = (void *)(mod_base + l->fileofs);
1134 if (l->filelen % sizeof(*in))
1135 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1136 count = l->filelen / sizeof(*in);
1137 out = Hunk_AllocName ( count*sizeof(*out), va("%s surfedges", loadname));
1139 loadmodel->surfedges = out;
1140 loadmodel->numsurfedges = count;
1142 for ( i=0 ; i<count ; i++)
1143 out[i] = LittleLong (in[i]);
1152 void Mod_LoadPlanes (lump_t *l)
1159 in = (void *)(mod_base + l->fileofs);
1160 if (l->filelen % sizeof(*in))
1161 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1162 count = l->filelen / sizeof(*in);
1163 out = Hunk_AllocName ( count*2*sizeof(*out), va("%s planes", loadname));
1165 loadmodel->planes = out;
1166 loadmodel->numplanes = count;
1168 for ( i=0 ; i<count ; i++, in++, out++)
1170 for (j=0 ; j<3 ; j++)
1171 out->normal[j] = LittleFloat (in->normal[j]);
1173 out->dist = LittleFloat (in->dist);
1174 // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
1175 // out->type = LittleLong (in->type);
1180 #define MAX_POINTS_ON_WINDING 64
1185 vec3_t points[8]; // variable sized
1194 winding_t *NewWinding (int points)
1199 if (points > MAX_POINTS_ON_WINDING)
1200 Host_Error("NewWinding: too many points\n");
1202 size = (int)((winding_t *)0)->points[points];
1204 memset (w, 0, size);
1209 void FreeWinding (winding_t *w)
1219 winding_t *BaseWindingForPlane (mplane_t *p)
1221 vec3_t org, vright, vup;
1224 VectorVectors(p->normal, vright, vup);
1226 VectorScale (vup, 65536, vup);
1227 VectorScale (vright, 65536, vright);
1229 // project a really big axis aligned box onto the plane
1232 VectorScale (p->normal, p->dist, org);
1234 VectorSubtract (org, vright, w->points[0]);
1235 VectorAdd (w->points[0], vup, w->points[0]);
1237 VectorAdd (org, vright, w->points[1]);
1238 VectorAdd (w->points[1], vup, w->points[1]);
1240 VectorAdd (org, vright, w->points[2]);
1241 VectorSubtract (w->points[2], vup, w->points[2]);
1243 VectorSubtract (org, vright, w->points[3]);
1244 VectorSubtract (w->points[3], vup, w->points[3]);
1255 Clips the winding to the plane, returning the new winding on the positive side
1256 Frees the input winding.
1257 If keepon is true, an exactly on-plane winding will be saved, otherwise
1258 it will be clipped away.
1261 winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1263 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1264 int sides[MAX_POINTS_ON_WINDING + 1];
1273 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1275 // determine sides for each point
1276 for (i = 0;i < in->numpoints;i++)
1278 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1279 if (dot > ON_EPSILON)
1280 sides[i] = SIDE_FRONT;
1281 else if (dot < -ON_EPSILON)
1282 sides[i] = SIDE_BACK;
1287 sides[i] = sides[0];
1288 dists[i] = dists[0];
1290 if (keepon && !counts[0] && !counts[1])
1301 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1302 neww = NewWinding (maxpts);
1304 for (i = 0;i < in->numpoints;i++)
1308 if (sides[i] == SIDE_ON)
1310 VectorCopy (p1, neww->points[neww->numpoints]);
1315 if (sides[i] == SIDE_FRONT)
1317 VectorCopy (p1, neww->points[neww->numpoints]);
1321 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1324 // generate a split point
1325 p2 = in->points[(i+1)%in->numpoints];
1327 dot = dists[i] / (dists[i]-dists[i+1]);
1328 for (j = 0;j < 3;j++)
1329 { // avoid round off error when possible
1330 if (split->normal[j] == 1)
1331 mid[j] = split->dist;
1332 else if (split->normal[j] == -1)
1333 mid[j] = -split->dist;
1335 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1338 VectorCopy (mid, neww->points[neww->numpoints]);
1342 if (neww->numpoints > maxpts)
1343 Host_Error ("ClipWinding: points exceeded estimate");
1345 // free the original winding
1356 Divides a winding by a plane, producing one or two windings. The
1357 original winding is not damaged or freed. If only on one side, the
1358 returned winding will be the input winding. If on both sides, two
1359 new windings will be created.
1362 void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1364 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1365 int sides[MAX_POINTS_ON_WINDING + 1];
1374 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1376 // determine sides for each point
1377 for (i = 0;i < in->numpoints;i++)
1379 dot = DotProduct (in->points[i], split->normal);
1382 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1383 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1384 else sides[i] = SIDE_ON;
1387 sides[i] = sides[0];
1388 dists[i] = dists[0];
1390 *front = *back = NULL;
1403 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1405 *front = f = NewWinding (maxpts);
1406 *back = b = NewWinding (maxpts);
1408 for (i = 0;i < in->numpoints;i++)
1412 if (sides[i] == SIDE_ON)
1414 VectorCopy (p1, f->points[f->numpoints]);
1416 VectorCopy (p1, b->points[b->numpoints]);
1421 if (sides[i] == SIDE_FRONT)
1423 VectorCopy (p1, f->points[f->numpoints]);
1426 else if (sides[i] == SIDE_BACK)
1428 VectorCopy (p1, b->points[b->numpoints]);
1432 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1435 // generate a split point
1436 p2 = in->points[(i+1)%in->numpoints];
1438 dot = dists[i] / (dists[i]-dists[i+1]);
1439 for (j = 0;j < 3;j++)
1440 { // avoid round off error when possible
1441 if (split->normal[j] == 1)
1442 mid[j] = split->dist;
1443 else if (split->normal[j] == -1)
1444 mid[j] = -split->dist;
1446 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1449 VectorCopy (mid, f->points[f->numpoints]);
1451 VectorCopy (mid, b->points[b->numpoints]);
1455 if (f->numpoints > maxpts || b->numpoints > maxpts)
1456 Host_Error ("DivideWinding: points exceeded estimate");
1459 typedef struct portal_s
1462 mnode_t *nodes[2]; // [0] = front side of plane
1463 struct portal_s *next[2];
1465 struct portal_s *chain; // all portals are linked into a list
1469 static portal_t *portalchain;
1476 portal_t *AllocPortal (void)
1479 p = qmalloc(sizeof(portal_t));
1480 memset(p, 0, sizeof(portal_t));
1481 p->chain = portalchain;
1486 void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
1488 // calculate children first
1489 if (node->children[0]->contents >= 0)
1490 Mod_RecursiveRecalcNodeBBox(node->children[0]);
1491 if (node->children[1]->contents >= 0)
1492 Mod_RecursiveRecalcNodeBBox(node->children[1]);
1494 // make combined bounding box from children
1495 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
1496 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
1497 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
1498 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
1499 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
1500 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
1503 void Mod_FinalizePortals(void)
1505 int i, j, numportals, numpoints;
1506 portal_t *p, *pnext;
1509 mleaf_t *leaf, *endleaf;
1512 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
1513 leaf = loadmodel->leafs;
1514 endleaf = leaf + loadmodel->numleafs;
1515 for (;leaf < endleaf;leaf++)
1517 VectorSet( 2000000000, 2000000000, 2000000000, leaf->mins);
1518 VectorSet(-2000000000, -2000000000, -2000000000, leaf->maxs);
1525 for (i = 0;i < 2;i++)
1527 leaf = (mleaf_t *)p->nodes[i];
1529 for (j = 0;j < w->numpoints;j++)
1531 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
1532 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
1533 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
1534 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
1535 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
1536 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
1545 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
1549 // tally up portal and point counts
1555 // note: this check must match the one below or it will usually corrupt the hunk
1556 // 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
1557 if (p->winding && p->nodes[0] != p->nodes[1]
1558 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
1559 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
1562 numpoints += p->winding->numpoints * 2;
1566 loadmodel->portals = Hunk_AllocName(numportals * sizeof(mportal_t), va("%s portals", loadmodel->name));
1567 loadmodel->numportals = numportals;
1568 loadmodel->portalpoints = Hunk_AllocName(numpoints * sizeof(mvertex_t), va("%s portals", loadmodel->name));
1569 loadmodel->numportalpoints = numpoints;
1570 // clear all leaf portal chains
1571 for (i = 0;i < loadmodel->numleafs;i++)
1572 loadmodel->leafs[i].portals = NULL;
1573 // process all portals in the global portal chain, while freeing them
1574 portal = loadmodel->portals;
1575 point = loadmodel->portalpoints;
1584 // note: this check must match the one below or it will usually corrupt the hunk
1585 // 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
1586 if (p->nodes[0] != p->nodes[1]
1587 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
1588 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
1590 // first make the back to front portal (forward portal)
1591 portal->points = point;
1592 portal->numpoints = p->winding->numpoints;
1593 portal->plane.dist = p->plane.dist;
1594 VectorCopy(p->plane.normal, portal->plane.normal);
1595 portal->here = (mleaf_t *)p->nodes[1];
1596 portal->past = (mleaf_t *)p->nodes[0];
1598 for (j = 0;j < portal->numpoints;j++)
1600 VectorCopy(p->winding->points[j], point->position);
1603 PlaneClassify(&portal->plane);
1605 // link into leaf's portal chain
1606 portal->next = portal->here->portals;
1607 portal->here->portals = portal;
1609 // advance to next portal
1612 // then make the front to back portal (backward portal)
1613 portal->points = point;
1614 portal->numpoints = p->winding->numpoints;
1615 portal->plane.dist = -p->plane.dist;
1616 VectorNegate(p->plane.normal, portal->plane.normal);
1617 portal->here = (mleaf_t *)p->nodes[0];
1618 portal->past = (mleaf_t *)p->nodes[1];
1620 for (j = portal->numpoints - 1;j >= 0;j--)
1622 VectorCopy(p->winding->points[j], point->position);
1625 PlaneClassify(&portal->plane);
1627 // link into leaf's portal chain
1628 portal->next = portal->here->portals;
1629 portal->here->portals = portal;
1631 // advance to next portal
1634 FreeWinding(p->winding);
1646 void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
1649 Host_Error ("AddPortalToNodes: NULL front node");
1651 Host_Error ("AddPortalToNodes: NULL back node");
1652 if (p->nodes[0] || p->nodes[1])
1653 Host_Error ("AddPortalToNodes: already included");
1654 // 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
1656 p->nodes[0] = front;
1657 p->next[0] = (portal_t *)front->portals;
1658 front->portals = (mportal_t *)p;
1661 p->next[1] = (portal_t *)back->portals;
1662 back->portals = (mportal_t *)p;
1667 RemovePortalFromNode
1670 void RemovePortalFromNodes(portal_t *portal)
1674 void **portalpointer;
1676 for (i = 0;i < 2;i++)
1678 node = portal->nodes[i];
1680 portalpointer = (void **) &node->portals;
1685 Host_Error ("RemovePortalFromNodes: portal not in leaf");
1689 if (portal->nodes[0] == node)
1691 *portalpointer = portal->next[0];
1692 portal->nodes[0] = NULL;
1694 else if (portal->nodes[1] == node)
1696 *portalpointer = portal->next[1];
1697 portal->nodes[1] = NULL;
1700 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1704 if (t->nodes[0] == node)
1705 portalpointer = (void **) &t->next[0];
1706 else if (t->nodes[1] == node)
1707 portalpointer = (void **) &t->next[1];
1709 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1714 void Mod_RecursiveNodePortals (mnode_t *node)
1717 mnode_t *front, *back, *other_node;
1718 mplane_t clipplane, *plane;
1719 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
1720 winding_t *nodeportalwinding, *frontwinding, *backwinding;
1722 // CheckLeafPortalConsistancy (node);
1724 // if a leaf, we're done
1728 plane = node->plane;
1730 front = node->children[0];
1731 back = node->children[1];
1733 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
1735 // create the new portal by generating a polygon for the node plane,
1736 // and clipping it by all of the other portals (which came from nodes above this one)
1737 nodeportal = AllocPortal ();
1738 nodeportal->plane = *node->plane;
1740 nodeportalwinding = BaseWindingForPlane (node->plane);
1741 side = 0; // shut up compiler warning
1742 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
1744 clipplane = portal->plane;
1745 if (portal->nodes[0] == portal->nodes[1])
1746 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
1747 if (portal->nodes[0] == node)
1749 else if (portal->nodes[1] == node)
1751 clipplane.dist = -clipplane.dist;
1752 VectorNegate (clipplane.normal, clipplane.normal);
1756 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1758 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
1759 if (!nodeportalwinding)
1761 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
1766 if (nodeportalwinding)
1768 // if the plane was not clipped on all sides, there was an error
1769 nodeportal->winding = nodeportalwinding;
1770 AddPortalToNodes (nodeportal, front, back);
1773 // split the portals of this node along this node's plane and assign them to the children of this node
1774 // (migrating the portals downward through the tree)
1775 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
1777 if (portal->nodes[0] == portal->nodes[1])
1778 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
1779 if (portal->nodes[0] == node)
1781 else if (portal->nodes[1] == node)
1784 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1785 nextportal = portal->next[side];
1787 other_node = portal->nodes[!side];
1788 RemovePortalFromNodes (portal);
1790 // cut the portal into two portals, one on each side of the node plane
1791 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
1796 AddPortalToNodes (portal, back, other_node);
1798 AddPortalToNodes (portal, other_node, back);
1804 AddPortalToNodes (portal, front, other_node);
1806 AddPortalToNodes (portal, other_node, front);
1810 // the winding is split
1811 splitportal = AllocPortal ();
1812 temp = splitportal->chain;
1813 *splitportal = *portal;
1814 splitportal->chain = temp;
1815 splitportal->winding = backwinding;
1816 FreeWinding (portal->winding);
1817 portal->winding = frontwinding;
1821 AddPortalToNodes (portal, front, other_node);
1822 AddPortalToNodes (splitportal, back, other_node);
1826 AddPortalToNodes (portal, other_node, front);
1827 AddPortalToNodes (splitportal, other_node, back);
1831 Mod_RecursiveNodePortals(front);
1832 Mod_RecursiveNodePortals(back);
1836 void Mod_MakeOutsidePortals(mnode_t *node)
1839 portal_t *p, *portals[6];
1840 mnode_t *outside_node;
1842 outside_node = Hunk_AllocName(sizeof(mnode_t), loadmodel->name);
1843 outside_node->contents = CONTENTS_SOLID;
1844 outside_node->portals = NULL;
1846 for (i = 0;i < 3;i++)
1848 for (j = 0;j < 2;j++)
1850 portals[j*3 + i] = p = AllocPortal ();
1851 memset (&p->plane, 0, sizeof(mplane_t));
1852 p->plane.normal[i] = j ? -1 : 1;
1853 p->plane.dist = -65536;
1854 p->winding = BaseWindingForPlane (&p->plane);
1856 AddPortalToNodes (p, outside_node, node);
1858 AddPortalToNodes (p, node, outside_node);
1862 // clip the basewindings by all the other planes
1863 for (i = 0;i < 6;i++)
1865 for (j = 0;j < 6;j++)
1869 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
1875 void Mod_MakePortals(void)
1877 // Con_Printf("building portals for %s\n", loadmodel->name);
1880 // Mod_MakeOutsidePortals (loadmodel->nodes);
1881 Mod_RecursiveNodePortals (loadmodel->nodes);
1882 Mod_FinalizePortals();
1890 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1896 loadmodel->type = mod_brush;
1898 header = (dheader_t *)buffer;
1900 i = LittleLong (header->version);
1901 if (i != BSPVERSION && i != 30)
1902 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
1904 halflifebsp.value = hlbsp;
1906 // swap all the lumps
1907 mod_base = (byte *)header;
1909 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1910 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1914 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
1915 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1917 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1918 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1919 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1920 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1921 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1922 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1923 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1924 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1925 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1926 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1927 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1928 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1929 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1930 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1931 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1937 mod->numframes = 2; // regular and alternate animation
1940 // set up the submodels (FIXME: this is confusing)
1942 for (i = 0;i < mod->numsubmodels;i++)
1944 bm = &mod->submodels[i];
1946 mod->hulls[0].firstclipnode = bm->headnode[0];
1947 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1949 mod->hulls[j].firstclipnode = bm->headnode[j];
1950 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
1953 mod->firstmodelsurface = bm->firstface;
1954 mod->nummodelsurfaces = bm->numfaces;
1956 VectorCopy (bm->maxs, mod->maxs);
1957 VectorCopy (bm->mins, mod->mins);
1959 mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1961 mod->numleafs = bm->visleafs;
1963 if (isworldmodel && i < (mod->numsubmodels - 1)) // LordHavoc: only register submodels if it is the world (prevents bsp models from replacing world submodels)
1964 { // duplicate the basic information
1967 sprintf (name, "*%i", i+1);
1968 loadmodel = Mod_FindName (name);
1970 strcpy (loadmodel->name, name);