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 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
25 cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
26 cvar_t halflifebsp = {0, "halflifebsp", "0"};
27 cvar_t r_novis = {0, "r_novis", "0"};
28 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
29 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
30 cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"};
37 void Mod_BrushInit (void)
39 Cvar_RegisterVariable(&r_subdivide_size);
40 Cvar_RegisterVariable(&halflifebsp);
41 Cvar_RegisterVariable(&r_novis);
42 Cvar_RegisterVariable(&r_miplightmaps);
43 Cvar_RegisterVariable(&r_lightmaprgba);
44 Cvar_RegisterVariable(&r_vertexsurfacesthreshold);
45 memset(mod_novis, 0xff, sizeof(mod_novis));
48 void Mod_Brush_SERAddEntity(void)
50 R_Clip_AddBox(currentrenderentity->mins, currentrenderentity->maxs, R_Entity_Callback, currentrenderentity, NULL);
58 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
62 Mod_CheckLoaded(model);
63 // if (!model || !model->nodes)
64 // Sys_Error ("Mod_PointInLeaf: bad model");
66 // LordHavoc: modified to start at first clip node,
67 // in other words: first node of the (sub)model
68 node = model->nodes + model->hulls[0].firstclipnode;
69 while (node->contents == 0)
70 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
72 return (mleaf_t *)node;
75 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
77 if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
78 pos[0]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
79 pos[0]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
81 pos[1]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
82 pos[1]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
84 pos[2]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
85 pos[2]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
90 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
96 if (!model || !model->nodes)
97 Sys_Error ("Mod_PointInLeaf: bad model");
102 if (node->contents < 0)
103 return (mleaf_t *)node;
105 d = DotProduct (p,plane->normal) - plane->dist;
107 node = node->children[0];
109 node = node->children[1];
112 return NULL; // never reached
121 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
123 static qbyte decompressed[MAX_MAP_LEAFS/8];
128 row = (model->numleafs+7)>>3;
133 { // no vis info, so make all visible
158 } while (out - decompressed < row);
163 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
165 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
167 return Mod_DecompressVis (leaf->compressed_vis, model);
170 void Mod_SetupNoTexture(void)
173 qbyte pix[16][16][4];
175 for (y = 0;y < 16;y++)
177 for (x = 0;x < 16;x++)
179 if ((y < 8) ^ (x < 8))
196 memset(&loadmodel->notexture, 0, sizeof(texture_t));
197 strcpy(loadmodel->notexture.name, "notexture");
198 loadmodel->notexture.width = 16;
199 loadmodel->notexture.height = 16;
200 loadmodel->notexture.flags = 0;
201 loadmodel->notexture.texture = R_LoadTexture(loadmodel->texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP);
209 static void Mod_LoadTextures (lump_t *l)
211 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs;
213 texture_t *tx, *tx2, *anims[10], *altanims[10];
215 qbyte *data, *mtdata, *data2;
218 Mod_SetupNoTexture();
222 loadmodel->textures = NULL;
226 m = (dmiptexlump_t *)(mod_base + l->fileofs);
228 m->nummiptex = LittleLong (m->nummiptex);
230 loadmodel->numtextures = m->nummiptex;
231 loadmodel->textures = Mem_Alloc(loadmodel->mempool, m->nummiptex * sizeof(*loadmodel->textures));
233 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
235 for (i = 0;i < m->nummiptex;i++)
237 dofs[i] = LittleLong(dofs[i]);
240 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
241 mtwidth = LittleLong (dmiptex->width);
242 mtheight = LittleLong (dmiptex->height);
244 j = LittleLong (dmiptex->offsets[0]);
248 if (j < 40 || j + mtwidth * mtheight > l->filelen)
249 Host_Error ("Texture %s is corrupt or incomplete\n", dmiptex->name);
250 mtdata = (qbyte *)dmiptex + j;
253 if ((mtwidth & 15) || (mtheight & 15))
254 Host_Error ("Texture %s is not 16 aligned", dmiptex->name);
255 // LordHavoc: rewriting the map texture loader for GLQuake
256 tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t));
257 memset(tx, 0, sizeof(texture_t));
259 tx->alternate_anims = NULL;
260 loadmodel->textures[i] = tx;
262 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
263 for (j = 0;dmiptex->name[j] && j < 15;j++)
265 if (dmiptex->name[j] >= 'A' && dmiptex->name[j] <= 'Z')
266 tx->name[j] = dmiptex->name[j] + ('a' - 'A');
268 tx->name[j] = dmiptex->name[j];
275 Con_Printf("warning: unnamed texture in %s\n", loadmodel->name);
276 sprintf(tx->name, "unnamed%i", i);
280 tx->height = mtheight;
282 tx->glowtexture = NULL;
283 tx->fogtexture = NULL;
285 if (!loadmodel->ishlbsp && !strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128) // LordHavoc: HL sky textures are entirely unrelated
287 data = loadimagepixels(tx->name, false, 0, 0);
290 if (image_width == 256 && image_height == 128)
292 if (loadmodel->isworldmodel)
299 Host_Error("Mod_LoadTextures: replacement sky image must be 256x128 pixels\n");
302 else if (loadmodel->isworldmodel)
303 R_InitSky (mtdata, 1);
305 else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
307 tx->fogtexture = image_masktex;
308 strcpy(name, tx->name);
309 strcat(name, "_glow");
310 tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
314 if (loadmodel->ishlbsp)
316 if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
319 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
320 if (R_TextureHasAlpha(tx->texture))
323 for (j = 0;j < image_width * image_height;j++)
324 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
325 strcpy(name, tx->name);
326 strcat(name, "_fog");
327 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
331 else if ((data = W_GetTexture(tx->name)))
333 // get the size from the wad texture
334 tx->width = image_width;
335 tx->height = image_height;
336 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
337 if (R_TextureHasAlpha(tx->texture))
340 for (j = 0;j < image_width * image_height;j++)
341 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
342 strcpy(name, tx->name);
343 strcat(name, "_fog");
344 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
352 tx->texture = loadmodel->notexture.texture;
357 if (mtdata) // texture included
362 if (r_fullbrights.value && tx->name[0] != '*')
364 for (j = 0;j < tx->width*tx->height;j++)
366 if (data[j] >= 224) // fullbright
375 data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height);
376 for (j = 0;j < tx->width*tx->height;j++)
377 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
378 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
379 strcpy(name, tx->name);
380 strcat(name, "_glow");
381 for (j = 0;j < tx->width*tx->height;j++)
382 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
383 tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
387 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
389 else // no texture, and no external replacement texture was found
393 tx->texture = loadmodel->notexture.texture;
398 if (tx->name[0] == '*')
400 tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES);
401 // LordHavoc: some turbulent textures should be fullbright and solid
402 if (!strncmp(tx->name,"*lava",5)
403 || !strncmp(tx->name,"*teleport",9)
404 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
405 tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
407 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
408 tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID);
411 tx->flags |= SURF_LIGHTMAP;
412 if (!R_TextureHasAlpha(tx->texture))
413 tx->flags |= SURF_CLIPSOLID;
418 // sequence the animations
420 for (i = 0;i < m->nummiptex;i++)
422 tx = loadmodel->textures[i];
423 if (!tx || tx->name[0] != '+')
426 continue; // already sequenced
428 // find the number of frames in the animation
429 memset (anims, 0, sizeof(anims));
430 memset (altanims, 0, sizeof(altanims));
433 for (j = i;j < m->nummiptex;j++)
435 tx2 = loadmodel->textures[j];
436 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
440 if (num >= '0' && num <= '9')
441 anims[num - '0'] = tx2;
442 else if (num >= 'a' && num <= 'j')
443 altanims[num - 'a'] = tx2;
445 Host_Error ("Bad animating texture %s", tx->name);
448 for (j = 0;j < 10;j++)
450 if (anims[j] != NULL)
452 if (altanims[j] != NULL)
456 // link them all together
457 for (j = 0;j < max;j++)
461 Host_Error ("Missing frame %i of %s", j, tx->name);
462 tx2->anim_total = max;
463 tx2->alternate_anims = altanims[0]; // NULL if there is no alternate
464 for (k = 0;k < 10;k++)
465 tx2->anim_frames[k] = anims[k];
468 for (j = 0;j < altmax;j++)
472 Host_Error ("Missing frame %i of %s", j, tx->name);
473 tx2->anim_total = altmax;
474 tx2->alternate_anims = anims[0]; // NULL if there is no alternate
475 for (k = 0;k < 10;k++)
476 tx2->anim_frames[k] = altanims[k];
486 static void Mod_LoadLighting (lump_t *l)
489 qbyte *in, *out, *data, d;
490 char litfilename[1024];
491 loadmodel->lightdata = NULL;
492 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
494 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
495 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
497 else // LordHavoc: bsp version 29 (normal white lighting)
499 // LordHavoc: hope is not lost yet, check for a .lit file to load
500 strcpy(litfilename, loadmodel->name);
501 COM_StripExtension(litfilename, litfilename);
502 strcat(litfilename, ".lit");
503 data = (qbyte*) COM_LoadFile (litfilename, false);
506 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
508 i = LittleLong(((int *)data)[1]);
511 Con_DPrintf("%s loaded", litfilename);
512 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
513 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
519 Con_Printf("Unknown .lit file version (%d)\n", i);
526 Con_Printf("Empty .lit file, ignoring\n");
528 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
532 // LordHavoc: oh well, expand the white lighting data
535 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
536 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
537 out = loadmodel->lightdata;
538 memcpy (in, mod_base + l->fileofs, l->filelen);
539 for (i = 0;i < l->filelen;i++)
549 void Mod_LoadLightList(void)
552 char lightsfilename[1024], *s, *t, *lightsstring;
555 strcpy(lightsfilename, loadmodel->name);
556 COM_StripExtension(lightsfilename, lightsfilename);
557 strcat(lightsfilename, ".lights");
558 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
564 while (*s && *s != '\n')
568 Mem_Free(lightsstring);
569 Host_Error("lights file must end with a newline\n");
574 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
577 while (*s && n < numlights)
580 while (*s && *s != '\n')
584 Mem_Free(lightsstring);
585 Host_Error("misparsed lights file!\n");
587 e = loadmodel->lights + n;
589 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->style);
593 Mem_Free(lightsstring);
594 Host_Error("invalid lights file, found %d parameters on line %i, should be 13 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone style)\n", a, n + 1);
601 Mem_Free(lightsstring);
602 Host_Error("misparsed lights file!\n");
604 loadmodel->numlights = numlights;
605 Mem_Free(lightsstring);
615 static void Mod_LoadVisibility (lump_t *l)
619 loadmodel->visdata = NULL;
622 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
623 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
626 // used only for HalfLife maps
627 void Mod_ParseWadsFromEntityLump(char *data)
629 char key[128], value[4096];
634 data = COM_Parse(data);
637 if (com_token[0] != '{')
641 data = COM_Parse(data);
644 if (com_token[0] == '}')
645 break; // end of worldspawn
646 if (com_token[0] == '_')
647 strcpy(key, com_token + 1);
649 strcpy(key, com_token);
650 while (key[strlen(key)-1] == ' ') // remove trailing spaces
651 key[strlen(key)-1] = 0;
652 data = COM_Parse(data);
655 strcpy(value, com_token);
656 if (!strcmp("wad", key)) // for HalfLife maps
658 if (loadmodel->ishlbsp)
661 for (i = 0;i < 4096;i++)
662 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
668 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
669 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
671 else if (value[i] == ';' || value[i] == 0)
675 strcpy(wadname, "textures/");
676 strcat(wadname, &value[j]);
677 W_LoadTextureWadFile (wadname, false);
694 static void Mod_LoadEntities (lump_t *l)
698 loadmodel->entities = NULL;
701 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
702 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
703 if (loadmodel->ishlbsp)
704 Mod_ParseWadsFromEntityLump(loadmodel->entities);
713 static void Mod_LoadVertexes (lump_t *l)
719 in = (void *)(mod_base + l->fileofs);
720 if (l->filelen % sizeof(*in))
721 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
722 count = l->filelen / sizeof(*in);
723 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
725 loadmodel->vertexes = out;
726 loadmodel->numvertexes = count;
728 for ( i=0 ; i<count ; i++, in++, out++)
730 out->position[0] = LittleFloat (in->point[0]);
731 out->position[1] = LittleFloat (in->point[1]);
732 out->position[2] = LittleFloat (in->point[2]);
741 static void Mod_LoadSubmodels (lump_t *l)
747 in = (void *)(mod_base + l->fileofs);
748 if (l->filelen % sizeof(*in))
749 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
750 count = l->filelen / sizeof(*in);
751 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
753 loadmodel->submodels = out;
754 loadmodel->numsubmodels = count;
756 for ( i=0 ; i<count ; i++, in++, out++)
758 for (j=0 ; j<3 ; j++)
760 // spread the mins / maxs by a pixel
761 out->mins[j] = LittleFloat (in->mins[j]) - 1;
762 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
763 out->origin[j] = LittleFloat (in->origin[j]);
765 for (j=0 ; j<MAX_MAP_HULLS ; j++)
766 out->headnode[j] = LittleLong (in->headnode[j]);
767 out->visleafs = LittleLong (in->visleafs);
768 out->firstface = LittleLong (in->firstface);
769 out->numfaces = LittleLong (in->numfaces);
778 static void Mod_LoadEdges (lump_t *l)
784 in = (void *)(mod_base + l->fileofs);
785 if (l->filelen % sizeof(*in))
786 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
787 count = l->filelen / sizeof(*in);
788 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
790 loadmodel->edges = out;
791 loadmodel->numedges = count;
793 for ( i=0 ; i<count ; i++, in++, out++)
795 out->v[0] = (unsigned short)LittleShort(in->v[0]);
796 out->v[1] = (unsigned short)LittleShort(in->v[1]);
805 static void Mod_LoadTexinfo (lump_t *l)
812 in = (void *)(mod_base + l->fileofs);
813 if (l->filelen % sizeof(*in))
814 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
815 count = l->filelen / sizeof(*in);
816 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
818 loadmodel->texinfo = out;
819 loadmodel->numtexinfo = count;
821 for (i = 0;i < count;i++, in++, out++)
823 for (k = 0;k < 2;k++)
824 for (j = 0;j < 4;j++)
825 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
827 miptex = LittleLong (in->miptex);
828 out->flags = LittleLong (in->flags);
830 if (!loadmodel->textures)
831 out->texture = &loadmodel->notexture;
835 Host_Error ("miptex < 0");
836 if (miptex >= loadmodel->numtextures)
837 Host_Error ("miptex >= loadmodel->numtextures");
838 out->texture = loadmodel->textures[miptex];
841 out->texture = &loadmodel->notexture;
849 Fills in s->texturemins[] and s->extents[]
852 static void CalcSurfaceExtents (msurface_t *s)
854 float mins[2], maxs[2], val;
858 int bmins[2], bmaxs[2];
860 mins[0] = mins[1] = 999999999;
861 maxs[0] = maxs[1] = -999999999;
865 for (i=0 ; i<s->numedges ; i++)
867 e = loadmodel->surfedges[s->firstedge+i];
869 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
871 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
873 for (j=0 ; j<2 ; j++)
875 val = v->position[0] * tex->vecs[j][0] +
876 v->position[1] * tex->vecs[j][1] +
877 v->position[2] * tex->vecs[j][2] +
886 for (i=0 ; i<2 ; i++)
888 bmins[i] = floor(mins[i]/16);
889 bmaxs[i] = ceil(maxs[i]/16);
891 s->texturemins[i] = bmins[i] * 16;
892 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
897 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
902 mins[0] = mins[1] = mins[2] = 9999;
903 maxs[0] = maxs[1] = maxs[2] = -9999;
905 for (i = 0;i < numverts;i++)
907 for (j = 0;j < 3;j++, v++)
917 #define MAX_SUBDIVPOLYTRIANGLES 4096
918 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
920 static int subdivpolyverts, subdivpolytriangles;
921 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
922 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
924 static int subdivpolylookupvert(vec3_t v)
927 for (i = 0;i < subdivpolyverts;i++)
928 if (subdivpolyvert[i][0] == v[0]
929 && subdivpolyvert[i][1] == v[1]
930 && subdivpolyvert[i][2] == v[2])
932 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
933 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
934 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
935 return subdivpolyverts++;
938 static void SubdividePolygon (int numverts, float *verts)
940 int i, i1, i2, i3, f, b, c, p;
941 vec3_t mins, maxs, front[256], back[256];
942 float m, *pv, *cv, dist[256], frac;
945 Host_Error ("SubdividePolygon: ran out of verts in buffer");
947 BoundPoly (numverts, verts, mins, maxs);
949 for (i = 0;i < 3;i++)
951 m = (mins[i] + maxs[i]) * 0.5;
952 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
959 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
963 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
967 VectorCopy (pv, front[f]);
972 VectorCopy (pv, back[b]);
975 if (dist[p] == 0 || dist[c] == 0)
977 if ( (dist[p] > 0) != (dist[c] > 0) )
980 frac = dist[p] / (dist[p] - dist[c]);
981 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
982 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
983 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
989 SubdividePolygon (f, front[0]);
990 SubdividePolygon (b, back[0]);
994 i1 = subdivpolylookupvert(verts);
995 i2 = subdivpolylookupvert(verts + 3);
996 for (i = 2;i < numverts;i++)
998 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1000 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1004 i3 = subdivpolylookupvert(verts + i * 3);
1005 subdivpolyindex[subdivpolytriangles][0] = i1;
1006 subdivpolyindex[subdivpolytriangles][1] = i2;
1007 subdivpolyindex[subdivpolytriangles][2] = i3;
1009 subdivpolytriangles++;
1015 Mod_GenerateWarpMesh
1017 Breaks a polygon up along axial 64 unit
1018 boundaries so that turbulent and sky warps
1019 can be done reasonably.
1022 void Mod_GenerateWarpMesh (msurface_t *surf)
1028 subdivpolytriangles = 0;
1029 subdivpolyverts = 0;
1030 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1033 mesh->numverts = subdivpolyverts;
1034 mesh->numtriangles = subdivpolytriangles;
1035 if (mesh->numtriangles < 1)
1036 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1037 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1038 mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
1039 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1041 for (i = 0;i < mesh->numtriangles;i++)
1043 for (j = 0;j < 3;j++)
1045 mesh->index[i*3+j] = subdivpolyindex[i][j];
1046 //if (mesh->index[i] < 0 || mesh->index[i] >= mesh->numverts)
1047 // Host_Error("Mod_GenerateWarpMesh: invalid index generated\n");
1051 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1053 VectorCopy(subdivpolyvert[i], v->v);
1054 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1055 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1059 void Mod_GenerateVertexLitMesh (msurface_t *surf)
1061 int i, is, it, *index, smax, tmax;
1066 //surf->flags |= SURF_LIGHTMAP;
1067 smax = surf->extents[0] >> 4;
1068 tmax = surf->extents[1] >> 4;
1069 surf->lightmaptexturestride = 0;
1070 surf->lightmaptexture = NULL;
1073 mesh->numverts = surf->poly_numverts;
1074 mesh->numtriangles = surf->poly_numverts - 2;
1075 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1076 mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
1077 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1079 index = mesh->index;
1080 for (i = 0;i < mesh->numtriangles;i++)
1087 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1089 VectorCopy (in, out->v);
1091 s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1092 t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1094 out->st[0] = s / surf->texinfo->texture->width;
1095 out->st[1] = t / surf->texinfo->texture->height;
1097 s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1098 t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1100 // lightmap coordinates
1104 // LordHavoc: calc lightmap data offset for vertex lighting to use
1107 is = bound(0, is, smax);
1108 it = bound(0, it, tmax);
1109 out->lightmapoffset = ((it * (smax+1) + is) * 3);
1113 void Mod_GenerateLightmappedMesh (msurface_t *surf)
1115 int i, is, it, *index, smax, tmax;
1116 float *in, s, t, xbase, ybase, xscale, yscale;
1120 surf->flags |= SURF_LIGHTMAP;
1121 smax = surf->extents[0] >> 4;
1122 tmax = surf->extents[1] >> 4;
1123 if (r_miplightmaps.integer)
1125 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1126 surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL, NULL, 0);
1130 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1131 surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL, NULL, 0);
1133 // surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
1134 // surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_PRECACHE);
1135 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale);
1136 xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1137 yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1140 mesh->numverts = surf->poly_numverts;
1141 mesh->numtriangles = surf->poly_numverts - 2;
1142 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1143 mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
1144 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1146 index = mesh->index;
1147 for (i = 0;i < mesh->numtriangles;i++)
1154 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1156 VectorCopy (in, out->v);
1158 s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1159 t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1161 out->st[0] = s / surf->texinfo->texture->width;
1162 out->st[1] = t / surf->texinfo->texture->height;
1164 s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1165 t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1167 // lightmap coordinates
1168 out->uv[0] = s * xscale + xbase;
1169 out->uv[1] = t * yscale + ybase;
1171 // LordHavoc: calc lightmap data offset for vertex lighting to use
1174 is = bound(0, is, smax);
1175 it = bound(0, it, tmax);
1176 out->lightmapoffset = ((it * (smax+1) + is) * 3);
1180 void Mod_GenerateVertexMesh (msurface_t *surf)
1187 surf->lightmaptexturestride = 0;
1188 surf->lightmaptexture = NULL;
1191 mesh->numverts = surf->poly_numverts;
1192 mesh->numtriangles = surf->poly_numverts - 2;
1193 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1194 mesh->vertex = (surfvertex_t *)((qbyte *) mesh->index + mesh->numtriangles * sizeof(int[3]));
1195 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1197 index = mesh->index;
1198 for (i = 0;i < mesh->numtriangles;i++)
1205 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1207 VectorCopy (in, out->v);
1208 out->st[0] = (DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) / surf->texinfo->texture->width;
1209 out->st[1] = (DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) / surf->texinfo->texture->height;
1213 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1220 // convert edges back to a normal polygon
1221 surf->poly_numverts = surf->numedges;
1222 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1223 for (i = 0;i < surf->numedges;i++)
1225 lindex = loadmodel->surfedges[surf->firstedge + i];
1227 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1229 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1230 VectorCopy (vec, vert);
1240 static void Mod_LoadFaces (lump_t *l)
1244 int i, count, surfnum, planenum, side, ssize, tsize;
1246 in = (void *)(mod_base + l->fileofs);
1247 if (l->filelen % sizeof(*in))
1248 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1249 count = l->filelen / sizeof(*in);
1250 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1252 loadmodel->surfaces = out;
1253 loadmodel->numsurfaces = count;
1255 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1257 // FIXME: validate edges, texinfo, etc?
1258 out->firstedge = LittleLong(in->firstedge);
1259 out->numedges = LittleShort(in->numedges);
1261 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
1262 out->flags = out->texinfo->texture->flags;
1264 planenum = LittleShort(in->planenum);
1265 side = LittleShort(in->side);
1267 out->flags |= SURF_PLANEBACK;
1269 out->plane = loadmodel->planes + planenum;
1271 // clear lightmap (filled in later)
1272 out->lightmaptexture = NULL;
1274 // force lightmap upload on first time seeing the surface
1275 out->cached_dlight = true;
1276 out->cached_ambient = -1000;
1277 out->cached_lightscalebit = -1000;
1279 CalcSurfaceExtents (out);
1281 ssize = (out->extents[0] >> 4) + 1;
1282 tsize = (out->extents[1] >> 4) + 1;
1285 for (i = 0;i < MAXLIGHTMAPS;i++)
1286 out->styles[i] = in->styles[i];
1287 i = LittleLong(in->lightofs);
1289 out->samples = NULL;
1290 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1291 out->samples = loadmodel->lightdata + i;
1292 else // LordHavoc: white lighting (bsp version 29)
1293 out->samples = loadmodel->lightdata + (i * 3);
1295 Mod_GenerateSurfacePolygon(out);
1297 if (out->texinfo->texture->flags & SURF_DRAWSKY)
1299 out->shader = &Cshader_sky;
1300 out->samples = NULL;
1301 Mod_GenerateWarpMesh (out);
1305 if (out->texinfo->texture->flags & SURF_DRAWTURB)
1307 out->shader = &Cshader_water;
1309 for (i=0 ; i<2 ; i++)
1311 out->extents[i] = 16384*1024;
1312 out->texturemins[i] = -8192*1024;
1315 out->samples = NULL;
1316 Mod_GenerateWarpMesh (out);
1320 if (!R_TextureHasAlpha(out->texinfo->texture->texture))
1321 out->flags |= SURF_CLIPSOLID;
1322 if (out->texinfo->flags & TEX_SPECIAL)
1324 // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb
1325 out->shader = &Cshader_water;
1326 out->shader = &Cshader_water;
1327 out->samples = NULL;
1328 Mod_GenerateWarpMesh (out);
1330 else if ((out->extents[0]+1) > (256*16) || (out->extents[1]+1) > (256*16))
1332 Con_Printf ("Bad surface extents, converting to fullbright polygon");
1333 out->shader = &Cshader_wall_fullbright;
1334 out->samples = NULL;
1335 Mod_GenerateVertexMesh(out);
1339 // stainmap for permanent marks on walls
1340 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1342 memset(out->stainsamples, 255, ssize * tsize * 3);
1343 if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
1345 out->shader = &Cshader_wall_vertex;
1346 Mod_GenerateVertexLitMesh(out);
1350 out->shader = &Cshader_wall_lightmap;
1351 Mod_GenerateLightmappedMesh(out);
1357 static model_t *sortmodel;
1359 static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
1361 const msurface_t *a, *b;
1362 a = *((const msurface_t **)voida);
1363 b = *((const msurface_t **)voidb);
1364 if (a->shader != b->shader)
1365 return (qbyte *) a->shader - (qbyte *) b->shader;
1366 if (a->texinfo->texture != b->texinfo->texture);
1367 return a->texinfo->texture - b->texinfo->texture;
1371 static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool)
1375 sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *));
1376 for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++)
1377 sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface];
1379 qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare);
1388 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1390 node->parent = parent;
1391 if (node->contents < 0)
1393 Mod_SetParent (node->children[0], node);
1394 Mod_SetParent (node->children[1], node);
1402 static void Mod_LoadNodes (lump_t *l)
1408 in = (void *)(mod_base + l->fileofs);
1409 if (l->filelen % sizeof(*in))
1410 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1411 count = l->filelen / sizeof(*in);
1412 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1414 loadmodel->nodes = out;
1415 loadmodel->numnodes = count;
1417 for ( i=0 ; i<count ; i++, in++, out++)
1419 for (j=0 ; j<3 ; j++)
1421 out->mins[j] = LittleShort (in->mins[j]);
1422 out->maxs[j] = LittleShort (in->maxs[j]);
1425 p = LittleLong(in->planenum);
1426 out->plane = loadmodel->planes + p;
1428 out->firstsurface = LittleShort (in->firstface);
1429 out->numsurfaces = LittleShort (in->numfaces);
1431 for (j=0 ; j<2 ; j++)
1433 p = LittleShort (in->children[j]);
1435 out->children[j] = loadmodel->nodes + p;
1437 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1441 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1449 static void Mod_LoadLeafs (lump_t *l)
1455 in = (void *)(mod_base + l->fileofs);
1456 if (l->filelen % sizeof(*in))
1457 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1458 count = l->filelen / sizeof(*in);
1459 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1461 loadmodel->leafs = out;
1462 loadmodel->numleafs = count;
1464 for ( i=0 ; i<count ; i++, in++, out++)
1466 for (j=0 ; j<3 ; j++)
1468 out->mins[j] = LittleShort (in->mins[j]);
1469 out->maxs[j] = LittleShort (in->maxs[j]);
1472 p = LittleLong(in->contents);
1475 out->firstmarksurface = loadmodel->marksurfaces +
1476 LittleShort(in->firstmarksurface);
1477 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1479 p = LittleLong(in->visofs);
1481 out->compressed_vis = NULL;
1483 out->compressed_vis = loadmodel->visdata + p;
1485 for (j=0 ; j<4 ; j++)
1486 out->ambient_sound_level[j] = in->ambient_level[j];
1488 // gl underwater warp
1489 // LordHavoc: disabled underwater warping
1491 if (out->contents != CONTENTS_EMPTY)
1493 for (j=0 ; j<out->nummarksurfaces ; j++)
1494 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
1505 static void Mod_LoadClipnodes (lump_t *l)
1507 dclipnode_t *in, *out;
1511 in = (void *)(mod_base + l->fileofs);
1512 if (l->filelen % sizeof(*in))
1513 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1514 count = l->filelen / sizeof(*in);
1515 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1517 loadmodel->clipnodes = out;
1518 loadmodel->numclipnodes = count;
1520 if (loadmodel->ishlbsp)
1522 hull = &loadmodel->hulls[1];
1523 hull->clipnodes = out;
1524 hull->firstclipnode = 0;
1525 hull->lastclipnode = count-1;
1526 hull->planes = loadmodel->planes;
1527 hull->clip_mins[0] = -16;
1528 hull->clip_mins[1] = -16;
1529 hull->clip_mins[2] = -36;
1530 hull->clip_maxs[0] = 16;
1531 hull->clip_maxs[1] = 16;
1532 hull->clip_maxs[2] = 36;
1533 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1535 hull = &loadmodel->hulls[2];
1536 hull->clipnodes = out;
1537 hull->firstclipnode = 0;
1538 hull->lastclipnode = count-1;
1539 hull->planes = loadmodel->planes;
1540 hull->clip_mins[0] = -32;
1541 hull->clip_mins[1] = -32;
1542 hull->clip_mins[2] = -32;
1543 hull->clip_maxs[0] = 32;
1544 hull->clip_maxs[1] = 32;
1545 hull->clip_maxs[2] = 32;
1546 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1548 hull = &loadmodel->hulls[3];
1549 hull->clipnodes = out;
1550 hull->firstclipnode = 0;
1551 hull->lastclipnode = count-1;
1552 hull->planes = loadmodel->planes;
1553 hull->clip_mins[0] = -16;
1554 hull->clip_mins[1] = -16;
1555 hull->clip_mins[2] = -18;
1556 hull->clip_maxs[0] = 16;
1557 hull->clip_maxs[1] = 16;
1558 hull->clip_maxs[2] = 18;
1559 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1563 hull = &loadmodel->hulls[1];
1564 hull->clipnodes = out;
1565 hull->firstclipnode = 0;
1566 hull->lastclipnode = count-1;
1567 hull->planes = loadmodel->planes;
1568 hull->clip_mins[0] = -16;
1569 hull->clip_mins[1] = -16;
1570 hull->clip_mins[2] = -24;
1571 hull->clip_maxs[0] = 16;
1572 hull->clip_maxs[1] = 16;
1573 hull->clip_maxs[2] = 32;
1574 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1576 hull = &loadmodel->hulls[2];
1577 hull->clipnodes = out;
1578 hull->firstclipnode = 0;
1579 hull->lastclipnode = count-1;
1580 hull->planes = loadmodel->planes;
1581 hull->clip_mins[0] = -32;
1582 hull->clip_mins[1] = -32;
1583 hull->clip_mins[2] = -24;
1584 hull->clip_maxs[0] = 32;
1585 hull->clip_maxs[1] = 32;
1586 hull->clip_maxs[2] = 64;
1587 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1590 for (i=0 ; i<count ; i++, out++, in++)
1592 out->planenum = LittleLong(in->planenum);
1593 out->children[0] = LittleShort(in->children[0]);
1594 out->children[1] = LittleShort(in->children[1]);
1595 if (out->children[0] >= count || out->children[1] >= count)
1596 Host_Error("Corrupt clipping hull (out of range child)\n");
1604 Duplicate the drawing hull structure as a clipping hull
1607 static void Mod_MakeHull0 (void)
1614 hull = &loadmodel->hulls[0];
1616 in = loadmodel->nodes;
1617 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1619 hull->clipnodes = out;
1620 hull->firstclipnode = 0;
1621 hull->lastclipnode = loadmodel->numnodes - 1;
1622 hull->planes = loadmodel->planes;
1624 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1626 out->planenum = in->plane - loadmodel->planes;
1627 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1628 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1634 Mod_LoadMarksurfaces
1637 static void Mod_LoadMarksurfaces (lump_t *l)
1642 in = (void *)(mod_base + l->fileofs);
1643 if (l->filelen % sizeof(*in))
1644 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1645 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1646 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
1648 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1650 j = (unsigned) LittleShort(in[i]);
1651 if (j >= loadmodel->numsurfaces)
1652 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1653 loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
1662 static void Mod_LoadSurfedges (lump_t *l)
1667 in = (void *)(mod_base + l->fileofs);
1668 if (l->filelen % sizeof(*in))
1669 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1670 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1671 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1673 for (i = 0;i < loadmodel->numsurfedges;i++)
1674 loadmodel->surfedges[i] = LittleLong (in[i]);
1683 static void Mod_LoadPlanes (lump_t *l)
1689 in = (void *)(mod_base + l->fileofs);
1690 if (l->filelen % sizeof(*in))
1691 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1693 loadmodel->numplanes = l->filelen / sizeof(*in);
1694 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1696 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1698 out->normal[0] = LittleFloat (in->normal[0]);
1699 out->normal[1] = LittleFloat (in->normal[1]);
1700 out->normal[2] = LittleFloat (in->normal[2]);
1701 out->dist = LittleFloat (in->dist);
1703 // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
1704 // out->type = LittleLong (in->type);
1709 #define MAX_POINTS_ON_WINDING 64
1715 double points[8][3]; // variable sized
1724 static winding_t *NewWinding (int points)
1729 if (points > MAX_POINTS_ON_WINDING)
1730 Sys_Error("NewWinding: too many points\n");
1732 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1733 w = Mem_Alloc(loadmodel->mempool, size);
1734 memset (w, 0, size);
1739 static void FreeWinding (winding_t *w)
1749 static winding_t *BaseWindingForPlane (mplane_t *p)
1751 double org[3], vright[3], vup[3], normal[3];
1754 VectorCopy(p->normal, normal);
1755 VectorVectorsDouble(normal, vright, vup);
1757 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1758 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1760 // project a really big axis aligned box onto the plane
1763 VectorScale (p->normal, p->dist, org);
1765 VectorSubtract (org, vright, w->points[0]);
1766 VectorAdd (w->points[0], vup, w->points[0]);
1768 VectorAdd (org, vright, w->points[1]);
1769 VectorAdd (w->points[1], vup, w->points[1]);
1771 VectorAdd (org, vright, w->points[2]);
1772 VectorSubtract (w->points[2], vup, w->points[2]);
1774 VectorSubtract (org, vright, w->points[3]);
1775 VectorSubtract (w->points[3], vup, w->points[3]);
1786 Clips the winding to the plane, returning the new winding on the positive side
1787 Frees the input winding.
1788 If keepon is true, an exactly on-plane winding will be saved, otherwise
1789 it will be clipped away.
1792 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1794 double dists[MAX_POINTS_ON_WINDING + 1];
1795 int sides[MAX_POINTS_ON_WINDING + 1];
1804 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1806 // determine sides for each point
1807 for (i = 0;i < in->numpoints;i++)
1809 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1810 if (dot > ON_EPSILON)
1811 sides[i] = SIDE_FRONT;
1812 else if (dot < -ON_EPSILON)
1813 sides[i] = SIDE_BACK;
1818 sides[i] = sides[0];
1819 dists[i] = dists[0];
1821 if (keepon && !counts[0] && !counts[1])
1832 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1833 if (maxpts > MAX_POINTS_ON_WINDING)
1834 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1836 neww = NewWinding (maxpts);
1838 for (i = 0;i < in->numpoints;i++)
1840 if (neww->numpoints >= maxpts)
1841 Sys_Error ("ClipWinding: points exceeded estimate");
1845 if (sides[i] == SIDE_ON)
1847 VectorCopy (p1, neww->points[neww->numpoints]);
1852 if (sides[i] == SIDE_FRONT)
1854 VectorCopy (p1, neww->points[neww->numpoints]);
1858 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1861 // generate a split point
1862 p2 = in->points[(i+1)%in->numpoints];
1864 dot = dists[i] / (dists[i]-dists[i+1]);
1865 for (j = 0;j < 3;j++)
1866 { // avoid round off error when possible
1867 if (split->normal[j] == 1)
1868 mid[j] = split->dist;
1869 else if (split->normal[j] == -1)
1870 mid[j] = -split->dist;
1872 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1875 VectorCopy (mid, neww->points[neww->numpoints]);
1879 // free the original winding
1883 //Mem_CheckSentinels(neww);
1893 Divides a winding by a plane, producing one or two windings. The
1894 original winding is not damaged or freed. If only on one side, the
1895 returned winding will be the input winding. If on both sides, two
1896 new windings will be created.
1899 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1901 double dists[MAX_POINTS_ON_WINDING + 1];
1902 int sides[MAX_POINTS_ON_WINDING + 1];
1911 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1913 // determine sides for each point
1914 for (i = 0;i < in->numpoints;i++)
1916 dot = DotProduct (in->points[i], split->normal);
1919 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1920 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1921 else sides[i] = SIDE_ON;
1924 sides[i] = sides[0];
1925 dists[i] = dists[0];
1927 *front = *back = NULL;
1940 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1942 if (maxpts > MAX_POINTS_ON_WINDING)
1943 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1945 *front = f = NewWinding (maxpts);
1946 *back = b = NewWinding (maxpts);
1948 for (i = 0;i < in->numpoints;i++)
1950 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
1951 Sys_Error ("DivideWinding: points exceeded estimate");
1955 if (sides[i] == SIDE_ON)
1957 VectorCopy (p1, f->points[f->numpoints]);
1959 VectorCopy (p1, b->points[b->numpoints]);
1964 if (sides[i] == SIDE_FRONT)
1966 VectorCopy (p1, f->points[f->numpoints]);
1969 else if (sides[i] == SIDE_BACK)
1971 VectorCopy (p1, b->points[b->numpoints]);
1975 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1978 // generate a split point
1979 p2 = in->points[(i+1)%in->numpoints];
1981 dot = dists[i] / (dists[i]-dists[i+1]);
1982 for (j = 0;j < 3;j++)
1983 { // avoid round off error when possible
1984 if (split->normal[j] == 1)
1985 mid[j] = split->dist;
1986 else if (split->normal[j] == -1)
1987 mid[j] = -split->dist;
1989 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1992 VectorCopy (mid, f->points[f->numpoints]);
1994 VectorCopy (mid, b->points[b->numpoints]);
1999 //Mem_CheckSentinels(f);
2000 //Mem_CheckSentinels(b);
2003 typedef struct portal_s
2006 mnode_t *nodes[2]; // [0] = front side of plane
2007 struct portal_s *next[2];
2009 struct portal_s *chain; // all portals are linked into a list
2013 static portal_t *portalchain;
2020 static portal_t *AllocPortal (void)
2023 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2024 //memset(p, 0, sizeof(portal_t));
2025 p->chain = portalchain;
2030 static void FreePortal(portal_t *p)
2035 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2037 // calculate children first
2038 if (node->children[0]->contents >= 0)
2039 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2040 if (node->children[1]->contents >= 0)
2041 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2043 // make combined bounding box from children
2044 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2045 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2046 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2047 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2048 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2049 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2052 static void Mod_FinalizePortals(void)
2054 int i, j, numportals, numpoints;
2055 portal_t *p, *pnext;
2058 mleaf_t *leaf, *endleaf;
2061 //Mem_CheckSentinelsGlobal();
2063 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2064 leaf = loadmodel->leafs;
2065 endleaf = leaf + loadmodel->numleafs;
2066 for (;leaf < endleaf;leaf++)
2068 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2069 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2076 for (i = 0;i < 2;i++)
2078 leaf = (mleaf_t *)p->nodes[i];
2080 for (j = 0;j < w->numpoints;j++)
2082 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2083 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2084 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2085 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2086 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2087 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2094 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2096 //Mem_CheckSentinelsGlobal();
2098 // tally up portal and point counts
2104 // note: this check must match the one below or it will usually corrupt memory
2105 // 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
2106 if (p->winding && p->nodes[0] != p->nodes[1]
2107 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2108 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2111 numpoints += p->winding->numpoints * 2;
2115 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2116 loadmodel->numportals = numportals;
2117 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2118 loadmodel->numportalpoints = numpoints;
2119 // clear all leaf portal chains
2120 for (i = 0;i < loadmodel->numleafs;i++)
2121 loadmodel->leafs[i].portals = NULL;
2122 // process all portals in the global portal chain, while freeing them
2123 portal = loadmodel->portals;
2124 point = loadmodel->portalpoints;
2133 // note: this check must match the one above or it will usually corrupt memory
2134 // 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
2135 if (p->nodes[0] != p->nodes[1]
2136 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2137 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2139 // first make the back to front portal (forward portal)
2140 portal->points = point;
2141 portal->numpoints = p->winding->numpoints;
2142 portal->plane.dist = p->plane.dist;
2143 VectorCopy(p->plane.normal, portal->plane.normal);
2144 portal->here = (mleaf_t *)p->nodes[1];
2145 portal->past = (mleaf_t *)p->nodes[0];
2147 for (j = 0;j < portal->numpoints;j++)
2149 VectorCopy(p->winding->points[j], point->position);
2152 PlaneClassify(&portal->plane);
2154 // link into leaf's portal chain
2155 portal->next = portal->here->portals;
2156 portal->here->portals = portal;
2158 // advance to next portal
2161 // then make the front to back portal (backward portal)
2162 portal->points = point;
2163 portal->numpoints = p->winding->numpoints;
2164 portal->plane.dist = -p->plane.dist;
2165 VectorNegate(p->plane.normal, portal->plane.normal);
2166 portal->here = (mleaf_t *)p->nodes[0];
2167 portal->past = (mleaf_t *)p->nodes[1];
2169 for (j = portal->numpoints - 1;j >= 0;j--)
2171 VectorCopy(p->winding->points[j], point->position);
2174 PlaneClassify(&portal->plane);
2176 // link into leaf's portal chain
2177 portal->next = portal->here->portals;
2178 portal->here->portals = portal;
2180 // advance to next portal
2183 FreeWinding(p->winding);
2189 //Mem_CheckSentinelsGlobal();
2197 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2200 Host_Error ("AddPortalToNodes: NULL front node");
2202 Host_Error ("AddPortalToNodes: NULL back node");
2203 if (p->nodes[0] || p->nodes[1])
2204 Host_Error ("AddPortalToNodes: already included");
2205 // 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
2207 p->nodes[0] = front;
2208 p->next[0] = (portal_t *)front->portals;
2209 front->portals = (mportal_t *)p;
2212 p->next[1] = (portal_t *)back->portals;
2213 back->portals = (mportal_t *)p;
2218 RemovePortalFromNode
2221 static void RemovePortalFromNodes(portal_t *portal)
2225 void **portalpointer;
2227 for (i = 0;i < 2;i++)
2229 node = portal->nodes[i];
2231 portalpointer = (void **) &node->portals;
2236 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2240 if (portal->nodes[0] == node)
2242 *portalpointer = portal->next[0];
2243 portal->nodes[0] = NULL;
2245 else if (portal->nodes[1] == node)
2247 *portalpointer = portal->next[1];
2248 portal->nodes[1] = NULL;
2251 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2255 if (t->nodes[0] == node)
2256 portalpointer = (void **) &t->next[0];
2257 else if (t->nodes[1] == node)
2258 portalpointer = (void **) &t->next[1];
2260 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2265 static void Mod_RecursiveNodePortals (mnode_t *node)
2268 mnode_t *front, *back, *other_node;
2269 mplane_t clipplane, *plane;
2270 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2271 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2273 // CheckLeafPortalConsistancy (node);
2275 // if a leaf, we're done
2279 plane = node->plane;
2281 front = node->children[0];
2282 back = node->children[1];
2284 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2286 // create the new portal by generating a polygon for the node plane,
2287 // and clipping it by all of the other portals (which came from nodes above this one)
2288 nodeportal = AllocPortal ();
2289 nodeportal->plane = *node->plane;
2291 nodeportalwinding = BaseWindingForPlane (node->plane);
2292 //Mem_CheckSentinels(nodeportalwinding);
2293 side = 0; // shut up compiler warning
2294 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2296 clipplane = portal->plane;
2297 if (portal->nodes[0] == portal->nodes[1])
2298 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2299 if (portal->nodes[0] == node)
2301 else if (portal->nodes[1] == node)
2303 clipplane.dist = -clipplane.dist;
2304 VectorNegate (clipplane.normal, clipplane.normal);
2308 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2310 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2311 if (!nodeportalwinding)
2313 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2318 if (nodeportalwinding)
2320 // if the plane was not clipped on all sides, there was an error
2321 nodeportal->winding = nodeportalwinding;
2322 AddPortalToNodes (nodeportal, front, back);
2325 // split the portals of this node along this node's plane and assign them to the children of this node
2326 // (migrating the portals downward through the tree)
2327 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2329 if (portal->nodes[0] == portal->nodes[1])
2330 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2331 if (portal->nodes[0] == node)
2333 else if (portal->nodes[1] == node)
2336 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2337 nextportal = portal->next[side];
2339 other_node = portal->nodes[!side];
2340 RemovePortalFromNodes (portal);
2342 // cut the portal into two portals, one on each side of the node plane
2343 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2348 AddPortalToNodes (portal, back, other_node);
2350 AddPortalToNodes (portal, other_node, back);
2356 AddPortalToNodes (portal, front, other_node);
2358 AddPortalToNodes (portal, other_node, front);
2362 // the winding is split
2363 splitportal = AllocPortal ();
2364 temp = splitportal->chain;
2365 *splitportal = *portal;
2366 splitportal->chain = temp;
2367 splitportal->winding = backwinding;
2368 FreeWinding (portal->winding);
2369 portal->winding = frontwinding;
2373 AddPortalToNodes (portal, front, other_node);
2374 AddPortalToNodes (splitportal, back, other_node);
2378 AddPortalToNodes (portal, other_node, front);
2379 AddPortalToNodes (splitportal, other_node, back);
2383 Mod_RecursiveNodePortals(front);
2384 Mod_RecursiveNodePortals(back);
2388 void Mod_MakeOutsidePortals(mnode_t *node)
2391 portal_t *p, *portals[6];
2392 mnode_t *outside_node;
2394 outside_node = Mem_Alloc(loadmodel->mempool, sizeof(mnode_t));
2395 outside_node->contents = CONTENTS_SOLID;
2396 outside_node->portals = NULL;
2398 for (i = 0;i < 3;i++)
2400 for (j = 0;j < 2;j++)
2402 portals[j*3 + i] = p = AllocPortal ();
2403 memset (&p->plane, 0, sizeof(mplane_t));
2404 p->plane.normal[i] = j ? -1 : 1;
2405 p->plane.dist = -65536;
2406 p->winding = BaseWindingForPlane (&p->plane);
2408 AddPortalToNodes (p, outside_node, node);
2410 AddPortalToNodes (p, node, outside_node);
2414 // clip the basewindings by all the other planes
2415 for (i = 0;i < 6;i++)
2417 for (j = 0;j < 6;j++)
2421 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
2427 static void Mod_MakePortals(void)
2429 // Con_Printf("building portals for %s\n", loadmodel->name);
2432 // Mod_MakeOutsidePortals (loadmodel->nodes);
2433 Mod_RecursiveNodePortals (loadmodel->nodes);
2434 Mod_FinalizePortals();
2442 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2447 mempool_t *mainmempool;
2450 mod->type = mod_brush;
2452 header = (dheader_t *)buffer;
2454 i = LittleLong (header->version);
2455 if (i != BSPVERSION && i != 30)
2456 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
2457 mod->ishlbsp = i == 30;
2458 if (loadmodel->isworldmodel)
2459 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2461 // swap all the lumps
2462 mod_base = (qbyte *)header;
2464 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2465 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2469 // store which lightmap format to use
2470 mod->lightmaprgba = r_lightmaprgba.integer;
2472 // Mem_CheckSentinelsGlobal();
2473 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
2474 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2475 // Mem_CheckSentinelsGlobal();
2476 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2477 // Mem_CheckSentinelsGlobal();
2478 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2479 // Mem_CheckSentinelsGlobal();
2480 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2481 // Mem_CheckSentinelsGlobal();
2482 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2483 // Mem_CheckSentinelsGlobal();
2484 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2485 // Mem_CheckSentinelsGlobal();
2486 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2487 // Mem_CheckSentinelsGlobal();
2488 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2489 // Mem_CheckSentinelsGlobal();
2490 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2491 // Mem_CheckSentinelsGlobal();
2492 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2493 // Mem_CheckSentinelsGlobal();
2494 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2495 // Mem_CheckSentinelsGlobal();
2496 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2497 // Mem_CheckSentinelsGlobal();
2498 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2499 // Mem_CheckSentinelsGlobal();
2500 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2501 // Mem_CheckSentinelsGlobal();
2502 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2503 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2504 // Mem_CheckSentinelsGlobal();
2507 // Mem_CheckSentinelsGlobal();
2509 // Mem_CheckSentinelsGlobal();
2511 mod->numframes = 2; // regular and alternate animation
2513 mainmempool = mod->mempool;
2514 loadname = mod->name;
2516 Mod_LoadLightList ();
2519 // set up the submodels (FIXME: this is confusing)
2521 for (i = 0;i < mod->numsubmodels;i++)
2524 float dist, modelyawradius, modelradius, *vec;
2527 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2528 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2532 bm = &mod->submodels[i];
2534 mod->hulls[0].firstclipnode = bm->headnode[0];
2535 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2537 mod->hulls[j].firstclipnode = bm->headnode[j];
2538 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2541 mod->firstmodelsurface = bm->firstface;
2542 mod->nummodelsurfaces = bm->numfaces;
2544 mod->DrawSky = NULL;
2545 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2546 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2548 // we only need to have a drawsky function if it is used (usually only on world model)
2549 if (surf->shader == &Cshader_sky)
2550 mod->DrawSky = R_DrawBrushModelSky;
2551 for (k = 0;k < surf->numedges;k++)
2553 l = mod->surfedges[k + surf->firstedge];
2555 vec = mod->vertexes[mod->edges[l].v[0]].position;
2557 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2558 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2559 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2560 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2561 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2562 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2563 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2564 dist = vec[0]*vec[0]+vec[1]*vec[1];
2565 if (modelyawradius < dist)
2566 modelyawradius = dist;
2567 dist += vec[2]*vec[2];
2568 if (modelradius < dist)
2572 modelyawradius = sqrt(modelyawradius);
2573 modelradius = sqrt(modelradius);
2574 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2575 mod->yawmins[2] = mod->normalmins[2];
2576 mod->yawmaxs[2] = mod->normalmaxs[2];
2577 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2578 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2579 // mod->modelradius = modelradius;
2580 // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
2581 if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
2583 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2584 VectorClear(mod->normalmins);
2585 VectorClear(mod->normalmaxs);
2586 VectorClear(mod->yawmins);
2587 VectorClear(mod->yawmaxs);
2588 VectorClear(mod->rotatedmins);
2589 VectorClear(mod->rotatedmaxs);
2590 //mod->modelradius = 0;
2593 // VectorCopy (bm->maxs, mod->maxs);
2594 // VectorCopy (bm->mins, mod->mins);
2596 // mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
2598 mod->numleafs = bm->visleafs;
2600 mod->SERAddEntity = Mod_Brush_SERAddEntity;
2601 mod->Draw = R_DrawBrushModelNormal;
2602 mod->DrawShadow = NULL;
2604 Mod_BrushSortedSurfaces(mod, mainmempool);
2606 // LordHavoc: only register submodels if it is the world
2607 // (prevents bsp models from replacing world submodels)
2608 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2611 // duplicate the basic information
2612 sprintf (name, "*%i", i+1);
2613 loadmodel = Mod_FindName (name);
2615 strcpy (loadmodel->name, name);
2616 // textures and memory belong to the main model
2617 loadmodel->texturepool = NULL;
2618 loadmodel->mempool = NULL;
2622 // Mem_CheckSentinelsGlobal();