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 = {"gl_subdivide_size", "128", true};
28 cvar_t halflifebsp = {"halflifebsp", "0"};
35 void Mod_BrushInit (void)
37 Cvar_RegisterVariable (&gl_subdivide_size);
38 Cvar_RegisterVariable (&halflifebsp);
39 memset (mod_novis, 0xff, sizeof(mod_novis));
47 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
51 // if (!model || !model->nodes)
52 // Sys_Error ("Mod_PointInLeaf: bad model");
55 if (node->contents < 0)
56 return (mleaf_t *)node;
59 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
60 if (node->contents < 0)
61 return (mleaf_t *)node;
64 return NULL; // never reached
67 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
73 if (!model || !model->nodes)
74 Sys_Error ("Mod_PointInLeaf: bad model");
79 if (node->contents < 0)
80 return (mleaf_t *)node;
82 d = DotProduct (p,plane->normal) - plane->dist;
84 node = node->children[0];
86 node = node->children[1];
89 return NULL; // never reached
98 byte *Mod_DecompressVis (byte *in, model_t *model)
100 static byte decompressed[MAX_MAP_LEAFS/8];
105 row = (model->numleafs+7)>>3;
109 { // no vis info, so make all visible
133 } while (out - decompressed < row);
138 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
140 if (leaf == model->leafs)
142 return Mod_DecompressVis (leaf->compressed_vis, model);
145 extern byte *mod_base;
147 extern cvar_t r_fullbrights;
149 rtexture_t *r_notexture;
150 texture_t r_notexture_mip;
152 void Mod_SetupNoTexture()
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 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 loadmodel->textures[i] = tx;
242 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
243 for (j = 0;dmiptex->name[j] && j < 15;j++)
245 if (dmiptex->name[j] >= 'A' && dmiptex->name[j] <= 'Z')
246 tx->name[j] = dmiptex->name[j] + ('a' - 'A');
248 tx->name[j] = dmiptex->name[j];
253 tx->transparent = false;
254 data = loadimagepixels(tx->name, false, 0, 0);
257 if (!hlbsp && !strncmp(tx->name,"sky",3) && image_width == 256 && image_height == 128) // LordHavoc: HL sky textures are entirely unrelated
261 tx->transparent = false;
263 tx->glowtexture = NULL;
269 tx->height = mtheight;
270 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
271 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
272 tx->glowtexture = NULL;
280 if (mtdata) // texture included
282 data = W_ConvertWAD3Texture(dmiptex);
286 tx->height = mtheight;
287 tx->transparent = Image_CheckAlpha(data, mtwidth * mtheight, true);
288 tx->texture = R_LoadTexture (tx->name, mtwidth, mtheight, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
289 tx->glowtexture = NULL;
295 data = W_GetTexture(tx->name);
296 // get the size from the wad texture
299 tx->width = image_width;
300 tx->height = image_height;
301 tx->transparent = Image_CheckAlpha(data, image_width * image_height, true);
302 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | (tx->transparent ? TEXF_ALPHA : 0) | TEXF_RGBA | TEXF_PRECACHE);
303 tx->glowtexture = NULL;
311 tx->transparent = false;
312 tx->texture = r_notexture;
313 tx->glowtexture = NULL;
318 if (!strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128)
321 tx->height = mtheight;
322 tx->transparent = false;
324 tx->glowtexture = NULL;
325 R_InitSky (mtdata, 1);
329 if (mtdata) // texture included
334 tx->height = mtheight;
335 tx->transparent = false;
337 if (r_fullbrights.value && tx->name[0] != '*')
339 for (j = 0;j < tx->width*tx->height;j++)
341 if (data[j] >= 224) // fullbright
352 data2 = qmalloc(tx->width*tx->height);
353 for (j = 0;j < tx->width*tx->height;j++)
354 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
355 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
356 strcpy(name, tx->name);
357 strcat(name, "_glow");
358 for (j = 0;j < tx->width*tx->height;j++)
359 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
360 tx->glowtexture = R_LoadTexture (name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
365 tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data, TEXF_MIPMAP | TEXF_PRECACHE);
366 tx->glowtexture = NULL;
369 else // no texture, and no external replacement texture was found
373 tx->transparent = false;
374 tx->texture = r_notexture;
375 tx->glowtexture = NULL;
383 // sequence the animations
385 for (i = 0;i < m->nummiptex;i++)
387 tx = loadmodel->textures[i];
388 if (!tx || tx->name[0] != '+')
391 continue; // already sequenced
393 // find the number of frames in the animation
394 memset (anims, 0, sizeof(anims));
395 memset (altanims, 0, sizeof(altanims));
399 if (max >= '0' && max <= '9')
406 else if (max >= 'a' && max <= 'j')
410 altanims[altmax] = tx;
414 Host_Error ("Bad animating texture %s", tx->name);
416 for (j = i + 1;j < m->nummiptex;j++)
418 tx2 = loadmodel->textures[j];
419 if (!tx2 || tx2->name[0] != '+')
421 if (strcmp (tx2->name+2, tx->name+2))
425 if (num >= '0' && num <= '9')
432 else if (num >= 'a' && num <= 'j')
440 Host_Error ("Bad animating texture %s", tx->name);
443 // link them all together
444 for (j = 0;j < max;j++)
448 Host_Error ("Missing frame %i of %s", j, tx->name);
449 tx2->anim_total = max;
451 tx2->alternate_anims = altanims[0];
452 for (k = 0;k < 10;k++)
453 tx2->anim_frames[k] = anims[j];
455 for (j = 0;j < altmax;j++)
459 Host_Error ("Missing frame %i of %s", j, tx->name);
460 tx2->anim_total = altmax;
462 tx2->alternate_anims = anims[0];
463 for (k = 0;k < 10;k++)
464 tx2->anim_frames[k] = altanims[j];
474 void Mod_LoadLighting (lump_t *l)
477 byte *in, *out, *data;
479 char litfilename[1024];
480 loadmodel->lightdata = NULL;
481 if (hlbsp) // LordHavoc: load the colored lighting data straight
483 loadmodel->lightdata = Hunk_AllocName ( l->filelen, va("%s lightmaps", loadname));
484 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
486 else // LordHavoc: bsp version 29 (normal white lighting)
488 // LordHavoc: hope is not lost yet, check for a .lit file to load
489 strcpy(litfilename, loadmodel->name);
490 COM_StripExtension(litfilename, litfilename);
491 strcat(litfilename, ".lit");
492 data = (byte*) COM_LoadHunkFile (litfilename, false);
495 if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
497 i = LittleLong(((int *)data)[1]);
500 Con_DPrintf("%s loaded", litfilename);
501 loadmodel->lightdata = data + 8;
505 Con_Printf("Unknown .lit file version (%d)\n", i);
508 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
510 // LordHavoc: oh well, expand the white lighting data
513 loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, va("%s lightmaps", loadname));
514 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
515 out = loadmodel->lightdata;
516 memcpy (in, mod_base + l->fileofs, l->filelen);
517 for (i = 0;i < l->filelen;i++)
533 void Mod_LoadVisibility (lump_t *l)
537 loadmodel->visdata = NULL;
540 loadmodel->visdata = Hunk_AllocName ( l->filelen, va("%s visdata", loadname));
541 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
544 void CL_ParseEntityLump(char *entdata);
546 extern qboolean isworldmodel;
553 void Mod_LoadEntities (lump_t *l)
557 loadmodel->entities = NULL;
560 loadmodel->entities = Hunk_AllocName ( l->filelen, va("%s entities", loadname));
561 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
564 CL_ParseEntityLump(loadmodel->entities);
573 void Mod_LoadVertexes (lump_t *l)
579 in = (void *)(mod_base + l->fileofs);
580 if (l->filelen % sizeof(*in))
581 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
582 count = l->filelen / sizeof(*in);
583 out = Hunk_AllocName ( count*sizeof(*out), va("%s vertices", loadname));
585 loadmodel->vertexes = out;
586 loadmodel->numvertexes = count;
588 for ( i=0 ; i<count ; i++, in++, out++)
590 out->position[0] = LittleFloat (in->point[0]);
591 out->position[1] = LittleFloat (in->point[1]);
592 out->position[2] = LittleFloat (in->point[2]);
601 void Mod_LoadSubmodels (lump_t *l)
607 in = (void *)(mod_base + l->fileofs);
608 if (l->filelen % sizeof(*in))
609 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
610 count = l->filelen / sizeof(*in);
611 out = Hunk_AllocName ( count*sizeof(*out), va("%s submodels", loadname));
613 loadmodel->submodels = out;
614 loadmodel->numsubmodels = count;
616 for ( i=0 ; i<count ; i++, in++, out++)
618 for (j=0 ; j<3 ; j++)
619 { // spread the mins / maxs by a pixel
620 out->mins[j] = LittleFloat (in->mins[j]) - 1;
621 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
622 out->origin[j] = LittleFloat (in->origin[j]);
624 for (j=0 ; j<MAX_MAP_HULLS ; j++)
625 out->headnode[j] = LittleLong (in->headnode[j]);
626 out->visleafs = LittleLong (in->visleafs);
627 out->firstface = LittleLong (in->firstface);
628 out->numfaces = LittleLong (in->numfaces);
637 void Mod_LoadEdges (lump_t *l)
643 in = (void *)(mod_base + l->fileofs);
644 if (l->filelen % sizeof(*in))
645 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
646 count = l->filelen / sizeof(*in);
647 out = Hunk_AllocName ( (count + 1) * sizeof(*out), va("%s edges", loadname));
649 loadmodel->edges = out;
650 loadmodel->numedges = count;
652 for ( i=0 ; i<count ; i++, in++, out++)
654 out->v[0] = (unsigned short)LittleShort(in->v[0]);
655 out->v[1] = (unsigned short)LittleShort(in->v[1]);
664 void Mod_LoadTexinfo (lump_t *l)
671 in = (void *)(mod_base + l->fileofs);
672 if (l->filelen % sizeof(*in))
673 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
674 count = l->filelen / sizeof(*in);
675 out = Hunk_AllocName ( count*sizeof(*out), va("%s texinfo", loadname));
677 loadmodel->texinfo = out;
678 loadmodel->numtexinfo = count;
680 for ( i=0 ; i<count ; i++, in++, out++)
682 for (k=0 ; k<2 ; k++)
683 for (j=0 ; j<4 ; j++)
684 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
686 miptex = LittleLong (in->miptex);
687 out->flags = LittleLong (in->flags);
689 if (!loadmodel->textures)
691 out->texture = &r_notexture_mip; // checkerboard texture
696 if (miptex >= loadmodel->numtextures)
697 Host_Error ("miptex >= loadmodel->numtextures");
698 out->texture = loadmodel->textures[miptex];
701 out->texture = &r_notexture_mip; // checkerboard texture
712 Fills in s->texturemins[] and s->extents[]
715 void CalcSurfaceExtents (msurface_t *s)
717 float mins[2], maxs[2], val;
721 int bmins[2], bmaxs[2];
723 mins[0] = mins[1] = 999999;
724 maxs[0] = maxs[1] = -99999;
728 for (i=0 ; i<s->numedges ; i++)
730 e = loadmodel->surfedges[s->firstedge+i];
732 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
734 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
736 for (j=0 ; j<2 ; j++)
738 val = v->position[0] * tex->vecs[j][0] +
739 v->position[1] * tex->vecs[j][1] +
740 v->position[2] * tex->vecs[j][2] +
749 for (i=0 ; i<2 ; i++)
751 bmins[i] = floor(mins[i]/16);
752 bmaxs[i] = ceil(maxs[i]/16);
754 s->texturemins[i] = bmins[i] * 16;
755 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
756 // if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
757 if ((tex->flags & TEX_SPECIAL) == 0 && (s->extents[i]+1) > (256*16))
758 Host_Error ("Bad surface extents");
762 void GL_SubdivideSurface (msurface_t *fa);
764 extern char skyname[];
771 void Mod_LoadFaces (lump_t *l)
775 int i, count, surfnum;
778 in = (void *)(mod_base + l->fileofs);
779 if (l->filelen % sizeof(*in))
780 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
781 count = l->filelen / sizeof(*in);
782 out = Hunk_AllocName ( count*sizeof(*out), va("%s faces", loadname));
784 loadmodel->surfaces = out;
785 loadmodel->numsurfaces = count;
787 for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
789 out->firstedge = LittleLong(in->firstedge);
790 out->numedges = LittleShort(in->numedges);
793 planenum = LittleShort(in->planenum);
794 side = LittleShort(in->side);
796 out->flags |= SURF_PLANEBACK;
798 out->plane = loadmodel->planes + planenum;
800 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
802 CalcSurfaceExtents (out);
806 for (i=0 ; i<MAXLIGHTMAPS ; i++)
807 out->styles[i] = in->styles[i];
808 i = LittleLong(in->lightofs);
811 else if (hlbsp) // LordHavoc: HalfLife map (bsp version 30)
812 out->samples = loadmodel->lightdata + i;
813 else // LordHavoc: white lighting (bsp version 29)
814 out->samples = loadmodel->lightdata + (i * 3);
816 // set the drawing flags flag
818 // if (!strncmp(out->texinfo->texture->name,"sky",3)) // sky
819 // LordHavoc: faster check
820 if ((out->texinfo->texture->name[0] == 's' || out->texinfo->texture->name[0] == 'S')
821 && (out->texinfo->texture->name[1] == 'k' || out->texinfo->texture->name[1] == 'K')
822 && (out->texinfo->texture->name[2] == 'y' || out->texinfo->texture->name[2] == 'Y'))
824 // LordHavoc: for consistency reasons, mark sky as fullbright and solid as well
825 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA);
826 GL_SubdivideSurface (out); // cut up polygon for warps
830 // if (!strncmp(out->texinfo->texture->name,"*",1)) // turbulent
831 if (out->texinfo->texture->name[0] == '*') // LordHavoc: faster check
833 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED | SURF_LIGHTBOTHSIDES);
834 // LordHavoc: some turbulent textures should be fullbright and solid
835 if (!strncmp(out->texinfo->texture->name,"*lava",5)
836 || !strncmp(out->texinfo->texture->name,"*teleport",9)
837 || !strncmp(out->texinfo->texture->name,"*rift",5)) // Scourge of Armagon texture
838 out->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA);
839 for (i=0 ; i<2 ; i++)
841 out->extents[i] = 16384;
842 out->texturemins[i] = -8192;
844 GL_SubdivideSurface (out); // cut up polygon for warps
857 void Mod_SetParent (mnode_t *node, mnode_t *parent)
859 node->parent = parent;
860 if (node->contents < 0)
862 Mod_SetParent (node->children[0], node);
863 Mod_SetParent (node->children[1], node);
871 void Mod_LoadNodes (lump_t *l)
877 in = (void *)(mod_base + l->fileofs);
878 if (l->filelen % sizeof(*in))
879 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
880 count = l->filelen / sizeof(*in);
881 out = Hunk_AllocName ( count*sizeof(*out), va("%s nodes", loadname));
883 loadmodel->nodes = out;
884 loadmodel->numnodes = count;
886 for ( i=0 ; i<count ; i++, in++, out++)
888 for (j=0 ; j<3 ; j++)
890 out->mins[j] = LittleShort (in->mins[j]);
891 out->maxs[j] = LittleShort (in->maxs[j]);
894 p = LittleLong(in->planenum);
895 out->plane = loadmodel->planes + p;
897 out->firstsurface = LittleShort (in->firstface);
898 out->numsurfaces = LittleShort (in->numfaces);
900 for (j=0 ; j<2 ; j++)
902 p = LittleShort (in->children[j]);
904 out->children[j] = loadmodel->nodes + p;
906 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
910 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
918 void Mod_LoadLeafs (lump_t *l)
924 in = (void *)(mod_base + l->fileofs);
925 if (l->filelen % sizeof(*in))
926 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
927 count = l->filelen / sizeof(*in);
928 out = Hunk_AllocName ( count*sizeof(*out), va("%s leafs", loadname));
930 loadmodel->leafs = out;
931 loadmodel->numleafs = count;
933 for ( i=0 ; i<count ; i++, in++, out++)
935 for (j=0 ; j<3 ; j++)
937 out->mins[j] = LittleShort (in->mins[j]);
938 out->maxs[j] = LittleShort (in->maxs[j]);
941 p = LittleLong(in->contents);
944 out->firstmarksurface = loadmodel->marksurfaces +
945 LittleShort(in->firstmarksurface);
946 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
948 p = LittleLong(in->visofs);
950 out->compressed_vis = NULL;
952 out->compressed_vis = loadmodel->visdata + p;
953 // out->efrags = NULL;
955 for (j=0 ; j<4 ; j++)
956 out->ambient_sound_level[j] = in->ambient_level[j];
958 // gl underwater warp
959 // LordHavoc: disabled underwater warping
961 if (out->contents != CONTENTS_EMPTY)
963 for (j=0 ; j<out->nummarksurfaces ; j++)
964 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
975 void Mod_LoadClipnodes (lump_t *l)
977 dclipnode_t *in, *out;
981 in = (void *)(mod_base + l->fileofs);
982 if (l->filelen % sizeof(*in))
983 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
984 count = l->filelen / sizeof(*in);
985 out = Hunk_AllocName ( count*sizeof(*out), va("%s clipnodes", loadname));
987 loadmodel->clipnodes = out;
988 loadmodel->numclipnodes = count;
992 hull = &loadmodel->hulls[1];
993 hull->clipnodes = out;
994 hull->firstclipnode = 0;
995 hull->lastclipnode = count-1;
996 hull->planes = loadmodel->planes;
997 hull->clip_mins[0] = -16;
998 hull->clip_mins[1] = -16;
999 hull->clip_mins[2] = -36;
1000 hull->clip_maxs[0] = 16;
1001 hull->clip_maxs[1] = 16;
1002 hull->clip_maxs[2] = 36;
1004 hull = &loadmodel->hulls[2];
1005 hull->clipnodes = out;
1006 hull->firstclipnode = 0;
1007 hull->lastclipnode = count-1;
1008 hull->planes = loadmodel->planes;
1009 hull->clip_mins[0] = -32;
1010 hull->clip_mins[1] = -32;
1011 hull->clip_mins[2] = -32;
1012 hull->clip_maxs[0] = 32;
1013 hull->clip_maxs[1] = 32;
1014 hull->clip_maxs[2] = 32;
1016 hull = &loadmodel->hulls[3];
1017 hull->clipnodes = out;
1018 hull->firstclipnode = 0;
1019 hull->lastclipnode = count-1;
1020 hull->planes = loadmodel->planes;
1021 hull->clip_mins[0] = -16;
1022 hull->clip_mins[1] = -16;
1023 hull->clip_mins[2] = -18;
1024 hull->clip_maxs[0] = 16;
1025 hull->clip_maxs[1] = 16;
1026 hull->clip_maxs[2] = 18;
1030 hull = &loadmodel->hulls[1];
1031 hull->clipnodes = out;
1032 hull->firstclipnode = 0;
1033 hull->lastclipnode = count-1;
1034 hull->planes = loadmodel->planes;
1035 hull->clip_mins[0] = -16;
1036 hull->clip_mins[1] = -16;
1037 hull->clip_mins[2] = -24;
1038 hull->clip_maxs[0] = 16;
1039 hull->clip_maxs[1] = 16;
1040 hull->clip_maxs[2] = 32;
1042 hull = &loadmodel->hulls[2];
1043 hull->clipnodes = out;
1044 hull->firstclipnode = 0;
1045 hull->lastclipnode = count-1;
1046 hull->planes = loadmodel->planes;
1047 hull->clip_mins[0] = -32;
1048 hull->clip_mins[1] = -32;
1049 hull->clip_mins[2] = -24;
1050 hull->clip_maxs[0] = 32;
1051 hull->clip_maxs[1] = 32;
1052 hull->clip_maxs[2] = 64;
1055 for (i=0 ; i<count ; i++, out++, in++)
1057 out->planenum = LittleLong(in->planenum);
1058 out->children[0] = LittleShort(in->children[0]);
1059 out->children[1] = LittleShort(in->children[1]);
1060 if (out->children[0] >= count || out->children[1] >= count)
1061 Host_Error("Corrupt clipping hull (out of range child)\n");
1069 Duplicate the drawing hull structure as a clipping hull
1072 void Mod_MakeHull0 (void)
1079 hull = &loadmodel->hulls[0];
1081 in = loadmodel->nodes;
1082 count = loadmodel->numnodes;
1083 out = Hunk_AllocName ( count*sizeof(*out), va("%s hull0", loadname));
1085 hull->clipnodes = out;
1086 hull->firstclipnode = 0;
1087 hull->lastclipnode = count - 1;
1088 hull->planes = loadmodel->planes;
1090 for (i = 0;i < count;i++, out++, in++)
1092 out->planenum = in->plane - loadmodel->planes;
1093 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1094 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1100 Mod_LoadMarksurfaces
1103 void Mod_LoadMarksurfaces (lump_t *l)
1109 in = (void *)(mod_base + l->fileofs);
1110 if (l->filelen % sizeof(*in))
1111 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1112 count = l->filelen / sizeof(*in);
1113 out = Hunk_AllocName ( count*sizeof(*out), va("%s marksurfaces", loadname));
1115 loadmodel->marksurfaces = out;
1116 loadmodel->nummarksurfaces = count;
1118 for ( i=0 ; i<count ; i++)
1120 j = LittleShort(in[i]);
1121 if (j >= loadmodel->numsurfaces)
1122 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1123 out[i] = loadmodel->surfaces + j;
1132 void Mod_LoadSurfedges (lump_t *l)
1137 in = (void *)(mod_base + l->fileofs);
1138 if (l->filelen % sizeof(*in))
1139 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1140 count = l->filelen / sizeof(*in);
1141 out = Hunk_AllocName ( count*sizeof(*out), va("%s surfedges", loadname));
1143 loadmodel->surfedges = out;
1144 loadmodel->numsurfedges = count;
1146 for ( i=0 ; i<count ; i++)
1147 out[i] = LittleLong (in[i]);
1156 void Mod_LoadPlanes (lump_t *l)
1164 in = (void *)(mod_base + l->fileofs);
1165 if (l->filelen % sizeof(*in))
1166 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1167 count = l->filelen / sizeof(*in);
1168 out = Hunk_AllocName ( count*2*sizeof(*out), va("%s planes", loadname));
1170 loadmodel->planes = out;
1171 loadmodel->numplanes = count;
1173 for ( i=0 ; i<count ; i++, in++, out++)
1176 for (j=0 ; j<3 ; j++)
1178 out->normal[j] = LittleFloat (in->normal[j]);
1179 // if (out->normal[j] < 0)
1183 out->dist = LittleFloat (in->dist);
1184 out->type = LittleLong (in->type);
1185 // out->signbits = bits;
1186 BoxOnPlaneSideClassify(out);
1190 #define MAX_POINTS_ON_WINDING 64
1195 vec3_t points[8]; // variable sized
1204 winding_t *NewWinding (int points)
1209 if (points > MAX_POINTS_ON_WINDING)
1210 Host_Error("NewWinding: too many points\n");
1212 size = (int)((winding_t *)0)->points[points];
1214 memset (w, 0, size);
1219 void FreeWinding (winding_t *w)
1229 winding_t *BaseWindingForPlane (mplane_t *p)
1231 vec3_t org, vright, vup;
1234 VectorVectors(p->normal, vright, vup);
1236 VectorScale (vup, 65536, vup);
1237 VectorScale (vright, 65536, vright);
1239 // project a really big axis aligned box onto the plane
1242 VectorScale (p->normal, p->dist, org);
1244 VectorSubtract (org, vright, w->points[0]);
1245 VectorAdd (w->points[0], vup, w->points[0]);
1247 VectorAdd (org, vright, w->points[1]);
1248 VectorAdd (w->points[1], vup, w->points[1]);
1250 VectorAdd (org, vright, w->points[2]);
1251 VectorSubtract (w->points[2], vup, w->points[2]);
1253 VectorSubtract (org, vright, w->points[3]);
1254 VectorSubtract (w->points[3], vup, w->points[3]);
1265 Clips the winding to the plane, returning the new winding on the positive side
1266 Frees the input winding.
1267 If keepon is true, an exactly on-plane winding will be saved, otherwise
1268 it will be clipped away.
1271 winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1273 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1274 int sides[MAX_POINTS_ON_WINDING + 1];
1283 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1285 // determine sides for each point
1286 for (i = 0;i < in->numpoints;i++)
1288 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1289 if (dot > ON_EPSILON)
1290 sides[i] = SIDE_FRONT;
1291 else if (dot < -ON_EPSILON)
1292 sides[i] = SIDE_BACK;
1297 sides[i] = sides[0];
1298 dists[i] = dists[0];
1300 if (keepon && !counts[0] && !counts[1])
1311 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1312 neww = NewWinding (maxpts);
1314 for (i = 0;i < in->numpoints;i++)
1318 if (sides[i] == SIDE_ON)
1320 VectorCopy (p1, neww->points[neww->numpoints]);
1325 if (sides[i] == SIDE_FRONT)
1327 VectorCopy (p1, neww->points[neww->numpoints]);
1331 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1334 // generate a split point
1335 p2 = in->points[(i+1)%in->numpoints];
1337 dot = dists[i] / (dists[i]-dists[i+1]);
1338 for (j = 0;j < 3;j++)
1339 { // avoid round off error when possible
1340 if (split->normal[j] == 1)
1341 mid[j] = split->dist;
1342 else if (split->normal[j] == -1)
1343 mid[j] = -split->dist;
1345 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1348 VectorCopy (mid, neww->points[neww->numpoints]);
1352 if (neww->numpoints > maxpts)
1353 Host_Error ("ClipWinding: points exceeded estimate");
1355 // free the original winding
1366 Divides a winding by a plane, producing one or two windings. The
1367 original winding is not damaged or freed. If only on one side, the
1368 returned winding will be the input winding. If on both sides, two
1369 new windings will be created.
1372 void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1374 vec_t dists[MAX_POINTS_ON_WINDING + 1];
1375 int sides[MAX_POINTS_ON_WINDING + 1];
1384 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1386 // determine sides for each point
1387 for (i = 0;i < in->numpoints;i++)
1389 dot = DotProduct (in->points[i], split->normal);
1392 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1393 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1394 else sides[i] = SIDE_ON;
1397 sides[i] = sides[0];
1398 dists[i] = dists[0];
1400 *front = *back = NULL;
1413 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1415 *front = f = NewWinding (maxpts);
1416 *back = b = NewWinding (maxpts);
1418 for (i = 0;i < in->numpoints;i++)
1422 if (sides[i] == SIDE_ON)
1424 VectorCopy (p1, f->points[f->numpoints]);
1426 VectorCopy (p1, b->points[b->numpoints]);
1431 if (sides[i] == SIDE_FRONT)
1433 VectorCopy (p1, f->points[f->numpoints]);
1436 else if (sides[i] == SIDE_BACK)
1438 VectorCopy (p1, b->points[b->numpoints]);
1442 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1445 // generate a split point
1446 p2 = in->points[(i+1)%in->numpoints];
1448 dot = dists[i] / (dists[i]-dists[i+1]);
1449 for (j = 0;j < 3;j++)
1450 { // avoid round off error when possible
1451 if (split->normal[j] == 1)
1452 mid[j] = split->dist;
1453 else if (split->normal[j] == -1)
1454 mid[j] = -split->dist;
1456 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1459 VectorCopy (mid, f->points[f->numpoints]);
1461 VectorCopy (mid, b->points[b->numpoints]);
1465 if (f->numpoints > maxpts || b->numpoints > maxpts)
1466 Host_Error ("DivideWinding: points exceeded estimate");
1469 typedef struct portal_s
1472 mnode_t *nodes[2]; // [0] = front side of plane
1473 struct portal_s *next[2];
1475 struct portal_s *chain; // all portals are linked into a list
1479 static portal_t *portalchain;
1486 portal_t *AllocPortal (void)
1489 p = malloc(sizeof(portal_t));
1490 memset(p, 0, sizeof(portal_t));
1491 p->chain = portalchain;
1496 void Mod_FinalizePortals()
1498 int i, j, numportals, numpoints;
1499 portal_t *p, *pnext;
1507 if (p->winding && p->nodes[0] != p->nodes[1] && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID)
1510 numpoints += p->winding->numpoints * 2;
1514 loadmodel->portals = Hunk_AllocName(numportals * sizeof(mportal_t), va("%s portals", loadmodel->name));
1515 loadmodel->numportals = numportals;
1516 loadmodel->portalpoints = Hunk_AllocName(numpoints * sizeof(mvertex_t), va("%s portals", loadmodel->name));
1517 loadmodel->numportalpoints = numpoints;
1518 // clear all leaf portal chains
1519 for (i = 0;i < loadmodel->numleafs;i++)
1520 loadmodel->leafs[i].portals = NULL;
1521 // process all portals in the global portal chain, while freeing them
1522 portal = loadmodel->portals;
1523 point = loadmodel->portalpoints;
1532 // 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
1533 if (p->nodes[0] != p->nodes[1] && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID)
1535 // first make the back to front portal (forward portal)
1536 portal->points = point;
1537 portal->numpoints = p->winding->numpoints;
1538 portal->plane.dist = p->plane.dist;
1539 VectorCopy(p->plane.normal, portal->plane.normal);
1540 portal->here = (mleaf_t *)p->nodes[1];
1541 portal->past = (mleaf_t *)p->nodes[0];
1543 for (j = 0;j < portal->numpoints;j++)
1545 VectorCopy(p->winding->points[j], point->position);
1549 // link into leaf's portal chain
1550 portal->next = portal->here->portals;
1551 portal->here->portals = portal;
1553 // advance to next portal
1556 // then make the front to back portal (backward portal)
1557 portal->points = point;
1558 portal->numpoints = p->winding->numpoints;
1559 portal->plane.dist = -p->plane.dist;
1560 VectorNegate(p->plane.normal, portal->plane.normal);
1561 portal->here = (mleaf_t *)p->nodes[0];
1562 portal->past = (mleaf_t *)p->nodes[1];
1564 for (j = portal->numpoints - 1;j >= 0;j--)
1566 VectorCopy(p->winding->points[j], point->position);
1570 // link into leaf's portal chain
1571 portal->next = portal->here->portals;
1572 portal->here->portals = portal;
1574 // advance to next portal
1577 FreeWinding(p->winding);
1589 void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
1592 Host_Error ("AddPortalToNodes: NULL front node");
1594 Host_Error ("AddPortalToNodes: NULL back node");
1595 if (p->nodes[0] || p->nodes[1])
1596 Host_Error ("AddPortalToNodes: already included");
1597 // 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
1599 p->nodes[0] = front;
1600 p->next[0] = (portal_t *)front->portals;
1601 front->portals = (mportal_t *)p;
1604 p->next[1] = (portal_t *)back->portals;
1605 back->portals = (mportal_t *)p;
1610 RemovePortalFromNode
1613 void RemovePortalFromNodes(portal_t *portal)
1617 void **portalpointer;
1619 for (i = 0;i < 2;i++)
1621 node = portal->nodes[i];
1623 portalpointer = &node->portals;
1628 Host_Error ("RemovePortalFromNodes: portal not in leaf");
1632 if (portal->nodes[0] == node)
1634 *portalpointer = portal->next[0];
1635 portal->nodes[0] = NULL;
1637 else if (portal->nodes[1] == node)
1639 *portalpointer = portal->next[1];
1640 portal->nodes[1] = NULL;
1643 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1647 if (t->nodes[0] == node)
1648 portalpointer = &t->next[0];
1649 else if (t->nodes[1] == node)
1650 portalpointer = &t->next[1];
1652 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
1657 void Mod_RecursiveNodePortals (mnode_t *node)
1660 mnode_t *front, *back, *other_node;
1661 mplane_t clipplane, *plane;
1662 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
1663 winding_t *nodeportalwinding, *frontwinding, *backwinding;
1665 // CheckLeafPortalConsistancy (node);
1667 // if a leaf, we're done
1671 plane = node->plane;
1673 front = node->children[0];
1674 back = node->children[1];
1676 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
1678 // create the new portal by generating a polygon for the node plane,
1679 // and clipping it by all of the other portals (which came from nodes above this one)
1680 nodeportal = AllocPortal ();
1681 nodeportal->plane = *node->plane;
1683 nodeportalwinding = BaseWindingForPlane (node->plane);
1684 side = 0; // shut up compiler warning
1685 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
1687 clipplane = portal->plane;
1688 if (portal->nodes[0] == portal->nodes[1])
1689 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
1690 if (portal->nodes[0] == node)
1692 else if (portal->nodes[1] == node)
1694 clipplane.dist = -clipplane.dist;
1695 VectorNegate (clipplane.normal, clipplane.normal);
1699 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1701 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
1702 if (!nodeportalwinding)
1704 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
1709 if (nodeportalwinding)
1711 // if the plane was not clipped on all sides, there was an error
1712 nodeportal->winding = nodeportalwinding;
1713 AddPortalToNodes (nodeportal, front, back);
1716 // split the portals of this node along this node's plane and assign them to the children of this node
1717 // (migrating the portals downward through the tree)
1718 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
1720 if (portal->nodes[0] == portal->nodes[1])
1721 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
1722 if (portal->nodes[0] == node)
1724 else if (portal->nodes[1] == node)
1727 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
1728 nextportal = portal->next[side];
1730 other_node = portal->nodes[!side];
1731 RemovePortalFromNodes (portal);
1733 // cut the portal into two portals, one on each side of the node plane
1734 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
1739 AddPortalToNodes (portal, back, other_node);
1741 AddPortalToNodes (portal, other_node, back);
1747 AddPortalToNodes (portal, front, other_node);
1749 AddPortalToNodes (portal, other_node, front);
1753 // the winding is split
1754 splitportal = AllocPortal ();
1755 temp = splitportal->chain;
1756 *splitportal = *portal;
1757 splitportal->chain = temp;
1758 splitportal->winding = backwinding;
1759 FreeWinding (portal->winding);
1760 portal->winding = frontwinding;
1764 AddPortalToNodes (portal, front, other_node);
1765 AddPortalToNodes (splitportal, back, other_node);
1769 AddPortalToNodes (portal, other_node, front);
1770 AddPortalToNodes (splitportal, other_node, back);
1774 Mod_RecursiveNodePortals(front);
1775 Mod_RecursiveNodePortals(back);
1779 void Mod_MakeOutsidePortals(mnode_t *node)
1782 portal_t *p, *portals[6];
1783 mnode_t *outside_node;
1785 outside_node = Hunk_AllocName(sizeof(mnode_t), loadmodel->name);
1786 outside_node->contents = CONTENTS_SOLID;
1787 outside_node->portals = NULL;
1789 for (i = 0;i < 3;i++)
1791 for (j = 0;j < 2;j++)
1793 portals[j*3 + i] = p = AllocPortal ();
1794 memset (&p->plane, 0, sizeof(mplane_t));
1795 p->plane.normal[i] = j ? -1 : 1;
1796 p->plane.dist = -65536;
1797 p->winding = BaseWindingForPlane (&p->plane);
1799 AddPortalToNodes (p, outside_node, node);
1801 AddPortalToNodes (p, node, outside_node);
1805 // clip the basewindings by all the other planes
1806 for (i = 0;i < 6;i++)
1808 for (j = 0;j < 6;j++)
1812 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
1818 void Mod_MakePortals()
1820 // Con_Printf("building portals for %s\n", loadmodel->name);
1823 // Mod_MakeOutsidePortals (loadmodel->nodes);
1824 Mod_RecursiveNodePortals (loadmodel->nodes);
1825 Mod_FinalizePortals();
1833 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1839 loadmodel->type = mod_brush;
1841 header = (dheader_t *)buffer;
1843 i = LittleLong (header->version);
1844 if (i != BSPVERSION && i != 30)
1845 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
1847 halflifebsp.value = hlbsp;
1849 // swap all the lumps
1850 mod_base = (byte *)header;
1852 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1853 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1857 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
1858 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1860 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1861 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1862 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1863 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1864 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1865 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1866 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1867 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1868 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1869 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1870 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1871 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1872 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1873 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1874 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1880 mod->numframes = 2; // regular and alternate animation
1883 // set up the submodels (FIXME: this is confusing)
1885 for (i = 0;i < mod->numsubmodels;i++)
1887 bm = &mod->submodels[i];
1889 mod->hulls[0].firstclipnode = bm->headnode[0];
1890 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1892 mod->hulls[j].firstclipnode = bm->headnode[j];
1893 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
1896 mod->firstmodelsurface = bm->firstface;
1897 mod->nummodelsurfaces = bm->numfaces;
1899 VectorCopy (bm->maxs, mod->maxs);
1900 VectorCopy (bm->mins, mod->mins);
1902 mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1904 mod->numleafs = bm->visleafs;
1906 if (isworldmodel && i < (mod->numsubmodels - 1)) // LordHavoc: only register submodels if it is the world (prevents bsp models from replacing world submodels)
1907 { // duplicate the basic information
1910 sprintf (name, "*%i", i+1);
1911 loadmodel = Mod_FindName (name);
1913 strcpy (loadmodel->name, name);