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 %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
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);
1031 if (subdivpolytriangles < 1)
1032 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1034 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1035 mesh->numverts = subdivpolyverts;
1036 mesh->numtriangles = subdivpolytriangles;
1037 mesh->vertex = (surfvertex_t *)(mesh + 1);
1038 mesh->index = (int *)(mesh->vertex + mesh->numverts);
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;
1072 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t));
1073 mesh->numverts = surf->poly_numverts;
1074 mesh->numtriangles = surf->poly_numverts - 2;
1075 mesh->vertex = (surfvertex_t *)(mesh + 1);
1076 mesh->index = (int *)(mesh->vertex + mesh->numverts);
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);
1139 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t));
1140 mesh->numverts = surf->poly_numverts;
1141 mesh->numtriangles = surf->poly_numverts - 2;
1142 mesh->vertex = (surfvertex_t *)(mesh + 1);
1143 mesh->index = (int *)(mesh->vertex + mesh->numverts);
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;
1190 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t));
1191 mesh->numverts = surf->poly_numverts;
1192 mesh->numtriangles = surf->poly_numverts - 2;
1193 mesh->vertex = (surfvertex_t *)(mesh + 1);
1194 mesh->index = (int *)(mesh->vertex + mesh->numverts);
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);
1235 static void Mod_SplitSurfMeshIfTooBig(msurface_t *s)
1237 int j, base, tricount, newvertexcount, *index, *vertexremap;
1238 surfmesh_t *newmesh, *oldmesh, *firstmesh;
1239 if (s->mesh->numtriangles > 1000)
1241 vertexremap = Mem_Alloc(tempmempool, s->mesh->numverts * sizeof(int));
1242 memset(vertexremap, -1, s->mesh->numverts * sizeof(int));
1247 while (base < s->mesh->numtriangles)
1249 tricount = s->mesh->numtriangles - base;
1250 if (tricount > 1000)
1252 index = s->mesh->index + base * 3;
1256 for (j = 0;j < tricount * 3;j++)
1257 if (vertexremap[index[j]] < 0)
1258 vertexremap[index[j]] = newvertexcount++;
1260 newmesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + newvertexcount * sizeof(surfvertex_t) + tricount * sizeof(int[3]));
1261 newmesh->chain = NULL;
1262 newmesh->numverts = newvertexcount;
1263 newmesh->numtriangles = tricount;
1264 newmesh->vertex = (surfvertex_t *)(newmesh + 1);
1265 newmesh->index = (int *)(newmesh->vertex + newvertexcount);
1266 for (j = 0;j < tricount * 3;j++)
1268 newmesh->index[j] = vertexremap[index[j]];
1269 // yes this copies the same vertex multiple times in many cases... but that's ok...
1270 memcpy(&newmesh->vertex[newmesh->index[j]], &s->mesh->vertex[index[j]], sizeof(surfvertex_t));
1273 oldmesh->chain = newmesh;
1275 firstmesh = newmesh;
1278 Mem_Free(vertexremap);
1280 s->mesh = firstmesh;
1289 static void Mod_LoadFaces (lump_t *l)
1293 int i, count, surfnum, planenum, side, ssize, tsize;
1295 in = (void *)(mod_base + l->fileofs);
1296 if (l->filelen % sizeof(*in))
1297 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1298 count = l->filelen / sizeof(*in);
1299 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1301 loadmodel->surfaces = out;
1302 loadmodel->numsurfaces = count;
1304 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1306 // FIXME: validate edges, texinfo, etc?
1307 out->firstedge = LittleLong(in->firstedge);
1308 out->numedges = LittleShort(in->numedges);
1310 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
1311 out->flags = out->texinfo->texture->flags;
1313 planenum = LittleShort(in->planenum);
1314 side = LittleShort(in->side);
1316 out->flags |= SURF_PLANEBACK;
1318 out->plane = loadmodel->planes + planenum;
1320 // clear lightmap (filled in later)
1321 out->lightmaptexture = NULL;
1323 // force lightmap upload on first time seeing the surface
1324 out->cached_dlight = true;
1325 out->cached_ambient = -1000;
1326 out->cached_lightscalebit = -1000;
1328 CalcSurfaceExtents (out);
1330 ssize = (out->extents[0] >> 4) + 1;
1331 tsize = (out->extents[1] >> 4) + 1;
1334 for (i = 0;i < MAXLIGHTMAPS;i++)
1335 out->styles[i] = in->styles[i];
1336 i = LittleLong(in->lightofs);
1338 out->samples = NULL;
1339 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1340 out->samples = loadmodel->lightdata + i;
1341 else // LordHavoc: white lighting (bsp version 29)
1342 out->samples = loadmodel->lightdata + (i * 3);
1344 Mod_GenerateSurfacePolygon(out);
1346 if (out->texinfo->texture->flags & SURF_DRAWSKY)
1348 out->shader = &Cshader_sky;
1349 out->samples = NULL;
1350 Mod_GenerateWarpMesh (out);
1352 else if (out->texinfo->texture->flags & SURF_DRAWTURB)
1354 out->shader = &Cshader_water;
1356 for (i=0 ; i<2 ; i++)
1358 out->extents[i] = 16384*1024;
1359 out->texturemins[i] = -8192*1024;
1362 out->samples = NULL;
1363 Mod_GenerateWarpMesh (out);
1367 if (!R_TextureHasAlpha(out->texinfo->texture->texture))
1368 out->flags |= SURF_CLIPSOLID;
1369 if (out->texinfo->flags & TEX_SPECIAL)
1371 // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb
1372 out->shader = &Cshader_water;
1373 out->shader = &Cshader_water;
1374 out->samples = NULL;
1375 Mod_GenerateWarpMesh (out);
1377 else if ((out->extents[0]+1) > (256*16) || (out->extents[1]+1) > (256*16))
1379 Con_Printf ("Bad surface extents, converting to fullbright polygon");
1380 out->shader = &Cshader_wall_fullbright;
1381 out->samples = NULL;
1382 Mod_GenerateVertexMesh(out);
1386 // stainmap for permanent marks on walls
1387 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1389 memset(out->stainsamples, 255, ssize * tsize * 3);
1390 if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
1392 out->shader = &Cshader_wall_vertex;
1393 Mod_GenerateVertexLitMesh(out);
1397 out->shader = &Cshader_wall_lightmap;
1398 Mod_GenerateLightmappedMesh(out);
1402 Mod_SplitSurfMeshIfTooBig(out);
1406 static model_t *sortmodel;
1408 static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
1410 const msurface_t *a, *b;
1411 a = *((const msurface_t **)voida);
1412 b = *((const msurface_t **)voidb);
1413 if (a->shader != b->shader)
1414 return (qbyte *) a->shader - (qbyte *) b->shader;
1415 if (a->texinfo->texture != b->texinfo->texture);
1416 return a->texinfo->texture - b->texinfo->texture;
1420 static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool)
1424 sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *));
1425 for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++)
1426 sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface];
1428 qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare);
1437 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1439 node->parent = parent;
1440 if (node->contents < 0)
1442 Mod_SetParent (node->children[0], node);
1443 Mod_SetParent (node->children[1], node);
1451 static void Mod_LoadNodes (lump_t *l)
1457 in = (void *)(mod_base + l->fileofs);
1458 if (l->filelen % sizeof(*in))
1459 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1460 count = l->filelen / sizeof(*in);
1461 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1463 loadmodel->nodes = out;
1464 loadmodel->numnodes = count;
1466 for ( i=0 ; i<count ; i++, in++, out++)
1468 for (j=0 ; j<3 ; j++)
1470 out->mins[j] = LittleShort (in->mins[j]);
1471 out->maxs[j] = LittleShort (in->maxs[j]);
1474 p = LittleLong(in->planenum);
1475 out->plane = loadmodel->planes + p;
1477 out->firstsurface = LittleShort (in->firstface);
1478 out->numsurfaces = LittleShort (in->numfaces);
1480 for (j=0 ; j<2 ; j++)
1482 p = LittleShort (in->children[j]);
1484 out->children[j] = loadmodel->nodes + p;
1486 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1490 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1498 static void Mod_LoadLeafs (lump_t *l)
1504 in = (void *)(mod_base + l->fileofs);
1505 if (l->filelen % sizeof(*in))
1506 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1507 count = l->filelen / sizeof(*in);
1508 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1510 loadmodel->leafs = out;
1511 loadmodel->numleafs = count;
1513 for ( i=0 ; i<count ; i++, in++, out++)
1515 for (j=0 ; j<3 ; j++)
1517 out->mins[j] = LittleShort (in->mins[j]);
1518 out->maxs[j] = LittleShort (in->maxs[j]);
1521 p = LittleLong(in->contents);
1524 out->firstmarksurface = loadmodel->marksurfaces +
1525 LittleShort(in->firstmarksurface);
1526 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1528 p = LittleLong(in->visofs);
1530 out->compressed_vis = NULL;
1532 out->compressed_vis = loadmodel->visdata + p;
1534 for (j=0 ; j<4 ; j++)
1535 out->ambient_sound_level[j] = in->ambient_level[j];
1537 // gl underwater warp
1538 // LordHavoc: disabled underwater warping
1540 if (out->contents != CONTENTS_EMPTY)
1542 for (j=0 ; j<out->nummarksurfaces ; j++)
1543 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
1554 static void Mod_LoadClipnodes (lump_t *l)
1556 dclipnode_t *in, *out;
1560 in = (void *)(mod_base + l->fileofs);
1561 if (l->filelen % sizeof(*in))
1562 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1563 count = l->filelen / sizeof(*in);
1564 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1566 loadmodel->clipnodes = out;
1567 loadmodel->numclipnodes = count;
1569 if (loadmodel->ishlbsp)
1571 hull = &loadmodel->hulls[1];
1572 hull->clipnodes = out;
1573 hull->firstclipnode = 0;
1574 hull->lastclipnode = count-1;
1575 hull->planes = loadmodel->planes;
1576 hull->clip_mins[0] = -16;
1577 hull->clip_mins[1] = -16;
1578 hull->clip_mins[2] = -36;
1579 hull->clip_maxs[0] = 16;
1580 hull->clip_maxs[1] = 16;
1581 hull->clip_maxs[2] = 36;
1582 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1584 hull = &loadmodel->hulls[2];
1585 hull->clipnodes = out;
1586 hull->firstclipnode = 0;
1587 hull->lastclipnode = count-1;
1588 hull->planes = loadmodel->planes;
1589 hull->clip_mins[0] = -32;
1590 hull->clip_mins[1] = -32;
1591 hull->clip_mins[2] = -32;
1592 hull->clip_maxs[0] = 32;
1593 hull->clip_maxs[1] = 32;
1594 hull->clip_maxs[2] = 32;
1595 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1597 hull = &loadmodel->hulls[3];
1598 hull->clipnodes = out;
1599 hull->firstclipnode = 0;
1600 hull->lastclipnode = count-1;
1601 hull->planes = loadmodel->planes;
1602 hull->clip_mins[0] = -16;
1603 hull->clip_mins[1] = -16;
1604 hull->clip_mins[2] = -18;
1605 hull->clip_maxs[0] = 16;
1606 hull->clip_maxs[1] = 16;
1607 hull->clip_maxs[2] = 18;
1608 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1612 hull = &loadmodel->hulls[1];
1613 hull->clipnodes = out;
1614 hull->firstclipnode = 0;
1615 hull->lastclipnode = count-1;
1616 hull->planes = loadmodel->planes;
1617 hull->clip_mins[0] = -16;
1618 hull->clip_mins[1] = -16;
1619 hull->clip_mins[2] = -24;
1620 hull->clip_maxs[0] = 16;
1621 hull->clip_maxs[1] = 16;
1622 hull->clip_maxs[2] = 32;
1623 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1625 hull = &loadmodel->hulls[2];
1626 hull->clipnodes = out;
1627 hull->firstclipnode = 0;
1628 hull->lastclipnode = count-1;
1629 hull->planes = loadmodel->planes;
1630 hull->clip_mins[0] = -32;
1631 hull->clip_mins[1] = -32;
1632 hull->clip_mins[2] = -24;
1633 hull->clip_maxs[0] = 32;
1634 hull->clip_maxs[1] = 32;
1635 hull->clip_maxs[2] = 64;
1636 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1639 for (i=0 ; i<count ; i++, out++, in++)
1641 out->planenum = LittleLong(in->planenum);
1642 out->children[0] = LittleShort(in->children[0]);
1643 out->children[1] = LittleShort(in->children[1]);
1644 if (out->children[0] >= count || out->children[1] >= count)
1645 Host_Error("Corrupt clipping hull (out of range child)\n");
1653 Duplicate the drawing hull structure as a clipping hull
1656 static void Mod_MakeHull0 (void)
1663 hull = &loadmodel->hulls[0];
1665 in = loadmodel->nodes;
1666 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1668 hull->clipnodes = out;
1669 hull->firstclipnode = 0;
1670 hull->lastclipnode = loadmodel->numnodes - 1;
1671 hull->planes = loadmodel->planes;
1673 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1675 out->planenum = in->plane - loadmodel->planes;
1676 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1677 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1683 Mod_LoadMarksurfaces
1686 static void Mod_LoadMarksurfaces (lump_t *l)
1691 in = (void *)(mod_base + l->fileofs);
1692 if (l->filelen % sizeof(*in))
1693 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1694 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1695 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
1697 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1699 j = (unsigned) LittleShort(in[i]);
1700 if (j >= loadmodel->numsurfaces)
1701 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1702 loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
1711 static void Mod_LoadSurfedges (lump_t *l)
1716 in = (void *)(mod_base + l->fileofs);
1717 if (l->filelen % sizeof(*in))
1718 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1719 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1720 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1722 for (i = 0;i < loadmodel->numsurfedges;i++)
1723 loadmodel->surfedges[i] = LittleLong (in[i]);
1732 static void Mod_LoadPlanes (lump_t *l)
1738 in = (void *)(mod_base + l->fileofs);
1739 if (l->filelen % sizeof(*in))
1740 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1742 loadmodel->numplanes = l->filelen / sizeof(*in);
1743 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1745 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1747 out->normal[0] = LittleFloat (in->normal[0]);
1748 out->normal[1] = LittleFloat (in->normal[1]);
1749 out->normal[2] = LittleFloat (in->normal[2]);
1750 out->dist = LittleFloat (in->dist);
1752 // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
1753 // out->type = LittleLong (in->type);
1758 #define MAX_POINTS_ON_WINDING 64
1764 double points[8][3]; // variable sized
1773 static winding_t *NewWinding (int points)
1778 if (points > MAX_POINTS_ON_WINDING)
1779 Sys_Error("NewWinding: too many points\n");
1781 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1782 w = Mem_Alloc(loadmodel->mempool, size);
1783 memset (w, 0, size);
1788 static void FreeWinding (winding_t *w)
1798 static winding_t *BaseWindingForPlane (mplane_t *p)
1800 double org[3], vright[3], vup[3], normal[3];
1803 VectorCopy(p->normal, normal);
1804 VectorVectorsDouble(normal, vright, vup);
1806 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1807 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1809 // project a really big axis aligned box onto the plane
1812 VectorScale (p->normal, p->dist, org);
1814 VectorSubtract (org, vright, w->points[0]);
1815 VectorAdd (w->points[0], vup, w->points[0]);
1817 VectorAdd (org, vright, w->points[1]);
1818 VectorAdd (w->points[1], vup, w->points[1]);
1820 VectorAdd (org, vright, w->points[2]);
1821 VectorSubtract (w->points[2], vup, w->points[2]);
1823 VectorSubtract (org, vright, w->points[3]);
1824 VectorSubtract (w->points[3], vup, w->points[3]);
1835 Clips the winding to the plane, returning the new winding on the positive side
1836 Frees the input winding.
1837 If keepon is true, an exactly on-plane winding will be saved, otherwise
1838 it will be clipped away.
1841 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1843 double dists[MAX_POINTS_ON_WINDING + 1];
1844 int sides[MAX_POINTS_ON_WINDING + 1];
1853 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1855 // determine sides for each point
1856 for (i = 0;i < in->numpoints;i++)
1858 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1859 if (dot > ON_EPSILON)
1860 sides[i] = SIDE_FRONT;
1861 else if (dot < -ON_EPSILON)
1862 sides[i] = SIDE_BACK;
1867 sides[i] = sides[0];
1868 dists[i] = dists[0];
1870 if (keepon && !counts[0] && !counts[1])
1881 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1882 if (maxpts > MAX_POINTS_ON_WINDING)
1883 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1885 neww = NewWinding (maxpts);
1887 for (i = 0;i < in->numpoints;i++)
1889 if (neww->numpoints >= maxpts)
1890 Sys_Error ("ClipWinding: points exceeded estimate");
1894 if (sides[i] == SIDE_ON)
1896 VectorCopy (p1, neww->points[neww->numpoints]);
1901 if (sides[i] == SIDE_FRONT)
1903 VectorCopy (p1, neww->points[neww->numpoints]);
1907 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1910 // generate a split point
1911 p2 = in->points[(i+1)%in->numpoints];
1913 dot = dists[i] / (dists[i]-dists[i+1]);
1914 for (j = 0;j < 3;j++)
1915 { // avoid round off error when possible
1916 if (split->normal[j] == 1)
1917 mid[j] = split->dist;
1918 else if (split->normal[j] == -1)
1919 mid[j] = -split->dist;
1921 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1924 VectorCopy (mid, neww->points[neww->numpoints]);
1928 // free the original winding
1932 //Mem_CheckSentinels(neww);
1942 Divides a winding by a plane, producing one or two windings. The
1943 original winding is not damaged or freed. If only on one side, the
1944 returned winding will be the input winding. If on both sides, two
1945 new windings will be created.
1948 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1950 double dists[MAX_POINTS_ON_WINDING + 1];
1951 int sides[MAX_POINTS_ON_WINDING + 1];
1960 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1962 // determine sides for each point
1963 for (i = 0;i < in->numpoints;i++)
1965 dot = DotProduct (in->points[i], split->normal);
1968 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1969 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1970 else sides[i] = SIDE_ON;
1973 sides[i] = sides[0];
1974 dists[i] = dists[0];
1976 *front = *back = NULL;
1989 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1991 if (maxpts > MAX_POINTS_ON_WINDING)
1992 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1994 *front = f = NewWinding (maxpts);
1995 *back = b = NewWinding (maxpts);
1997 for (i = 0;i < in->numpoints;i++)
1999 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2000 Sys_Error ("DivideWinding: points exceeded estimate");
2004 if (sides[i] == SIDE_ON)
2006 VectorCopy (p1, f->points[f->numpoints]);
2008 VectorCopy (p1, b->points[b->numpoints]);
2013 if (sides[i] == SIDE_FRONT)
2015 VectorCopy (p1, f->points[f->numpoints]);
2018 else if (sides[i] == SIDE_BACK)
2020 VectorCopy (p1, b->points[b->numpoints]);
2024 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2027 // generate a split point
2028 p2 = in->points[(i+1)%in->numpoints];
2030 dot = dists[i] / (dists[i]-dists[i+1]);
2031 for (j = 0;j < 3;j++)
2032 { // avoid round off error when possible
2033 if (split->normal[j] == 1)
2034 mid[j] = split->dist;
2035 else if (split->normal[j] == -1)
2036 mid[j] = -split->dist;
2038 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2041 VectorCopy (mid, f->points[f->numpoints]);
2043 VectorCopy (mid, b->points[b->numpoints]);
2048 //Mem_CheckSentinels(f);
2049 //Mem_CheckSentinels(b);
2052 typedef struct portal_s
2055 mnode_t *nodes[2]; // [0] = front side of plane
2056 struct portal_s *next[2];
2058 struct portal_s *chain; // all portals are linked into a list
2062 static portal_t *portalchain;
2069 static portal_t *AllocPortal (void)
2072 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2073 //memset(p, 0, sizeof(portal_t));
2074 p->chain = portalchain;
2079 static void FreePortal(portal_t *p)
2084 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2086 // calculate children first
2087 if (node->children[0]->contents >= 0)
2088 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2089 if (node->children[1]->contents >= 0)
2090 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2092 // make combined bounding box from children
2093 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2094 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2095 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2096 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2097 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2098 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2101 static void Mod_FinalizePortals(void)
2103 int i, j, numportals, numpoints;
2104 portal_t *p, *pnext;
2107 mleaf_t *leaf, *endleaf;
2110 //Mem_CheckSentinelsGlobal();
2112 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2113 leaf = loadmodel->leafs;
2114 endleaf = leaf + loadmodel->numleafs;
2115 for (;leaf < endleaf;leaf++)
2117 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2118 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2125 for (i = 0;i < 2;i++)
2127 leaf = (mleaf_t *)p->nodes[i];
2129 for (j = 0;j < w->numpoints;j++)
2131 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2132 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2133 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2134 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2135 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2136 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2143 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2145 //Mem_CheckSentinelsGlobal();
2147 // tally up portal and point counts
2153 // note: this check must match the one below or it will usually corrupt memory
2154 // 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
2155 if (p->winding && p->nodes[0] != p->nodes[1]
2156 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2157 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2160 numpoints += p->winding->numpoints * 2;
2164 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2165 loadmodel->numportals = numportals;
2166 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2167 loadmodel->numportalpoints = numpoints;
2168 // clear all leaf portal chains
2169 for (i = 0;i < loadmodel->numleafs;i++)
2170 loadmodel->leafs[i].portals = NULL;
2171 // process all portals in the global portal chain, while freeing them
2172 portal = loadmodel->portals;
2173 point = loadmodel->portalpoints;
2182 // note: this check must match the one above or it will usually corrupt memory
2183 // 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
2184 if (p->nodes[0] != p->nodes[1]
2185 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2186 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2188 // first make the back to front portal (forward portal)
2189 portal->points = point;
2190 portal->numpoints = p->winding->numpoints;
2191 portal->plane.dist = p->plane.dist;
2192 VectorCopy(p->plane.normal, portal->plane.normal);
2193 portal->here = (mleaf_t *)p->nodes[1];
2194 portal->past = (mleaf_t *)p->nodes[0];
2196 for (j = 0;j < portal->numpoints;j++)
2198 VectorCopy(p->winding->points[j], point->position);
2201 PlaneClassify(&portal->plane);
2203 // link into leaf's portal chain
2204 portal->next = portal->here->portals;
2205 portal->here->portals = portal;
2207 // advance to next portal
2210 // then make the front to back portal (backward portal)
2211 portal->points = point;
2212 portal->numpoints = p->winding->numpoints;
2213 portal->plane.dist = -p->plane.dist;
2214 VectorNegate(p->plane.normal, portal->plane.normal);
2215 portal->here = (mleaf_t *)p->nodes[0];
2216 portal->past = (mleaf_t *)p->nodes[1];
2218 for (j = portal->numpoints - 1;j >= 0;j--)
2220 VectorCopy(p->winding->points[j], point->position);
2223 PlaneClassify(&portal->plane);
2225 // link into leaf's portal chain
2226 portal->next = portal->here->portals;
2227 portal->here->portals = portal;
2229 // advance to next portal
2232 FreeWinding(p->winding);
2238 //Mem_CheckSentinelsGlobal();
2246 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2249 Host_Error ("AddPortalToNodes: NULL front node");
2251 Host_Error ("AddPortalToNodes: NULL back node");
2252 if (p->nodes[0] || p->nodes[1])
2253 Host_Error ("AddPortalToNodes: already included");
2254 // 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
2256 p->nodes[0] = front;
2257 p->next[0] = (portal_t *)front->portals;
2258 front->portals = (mportal_t *)p;
2261 p->next[1] = (portal_t *)back->portals;
2262 back->portals = (mportal_t *)p;
2267 RemovePortalFromNode
2270 static void RemovePortalFromNodes(portal_t *portal)
2274 void **portalpointer;
2276 for (i = 0;i < 2;i++)
2278 node = portal->nodes[i];
2280 portalpointer = (void **) &node->portals;
2285 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2289 if (portal->nodes[0] == node)
2291 *portalpointer = portal->next[0];
2292 portal->nodes[0] = NULL;
2294 else if (portal->nodes[1] == node)
2296 *portalpointer = portal->next[1];
2297 portal->nodes[1] = NULL;
2300 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2304 if (t->nodes[0] == node)
2305 portalpointer = (void **) &t->next[0];
2306 else if (t->nodes[1] == node)
2307 portalpointer = (void **) &t->next[1];
2309 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2314 static void Mod_RecursiveNodePortals (mnode_t *node)
2317 mnode_t *front, *back, *other_node;
2318 mplane_t clipplane, *plane;
2319 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2320 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2322 // CheckLeafPortalConsistancy (node);
2324 // if a leaf, we're done
2328 plane = node->plane;
2330 front = node->children[0];
2331 back = node->children[1];
2333 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2335 // create the new portal by generating a polygon for the node plane,
2336 // and clipping it by all of the other portals (which came from nodes above this one)
2337 nodeportal = AllocPortal ();
2338 nodeportal->plane = *node->plane;
2340 nodeportalwinding = BaseWindingForPlane (node->plane);
2341 //Mem_CheckSentinels(nodeportalwinding);
2342 side = 0; // shut up compiler warning
2343 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2345 clipplane = portal->plane;
2346 if (portal->nodes[0] == portal->nodes[1])
2347 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2348 if (portal->nodes[0] == node)
2350 else if (portal->nodes[1] == node)
2352 clipplane.dist = -clipplane.dist;
2353 VectorNegate (clipplane.normal, clipplane.normal);
2357 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2359 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2360 if (!nodeportalwinding)
2362 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2367 if (nodeportalwinding)
2369 // if the plane was not clipped on all sides, there was an error
2370 nodeportal->winding = nodeportalwinding;
2371 AddPortalToNodes (nodeportal, front, back);
2374 // split the portals of this node along this node's plane and assign them to the children of this node
2375 // (migrating the portals downward through the tree)
2376 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2378 if (portal->nodes[0] == portal->nodes[1])
2379 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2380 if (portal->nodes[0] == node)
2382 else if (portal->nodes[1] == node)
2385 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2386 nextportal = portal->next[side];
2388 other_node = portal->nodes[!side];
2389 RemovePortalFromNodes (portal);
2391 // cut the portal into two portals, one on each side of the node plane
2392 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2397 AddPortalToNodes (portal, back, other_node);
2399 AddPortalToNodes (portal, other_node, back);
2405 AddPortalToNodes (portal, front, other_node);
2407 AddPortalToNodes (portal, other_node, front);
2411 // the winding is split
2412 splitportal = AllocPortal ();
2413 temp = splitportal->chain;
2414 *splitportal = *portal;
2415 splitportal->chain = temp;
2416 splitportal->winding = backwinding;
2417 FreeWinding (portal->winding);
2418 portal->winding = frontwinding;
2422 AddPortalToNodes (portal, front, other_node);
2423 AddPortalToNodes (splitportal, back, other_node);
2427 AddPortalToNodes (portal, other_node, front);
2428 AddPortalToNodes (splitportal, other_node, back);
2432 Mod_RecursiveNodePortals(front);
2433 Mod_RecursiveNodePortals(back);
2437 void Mod_MakeOutsidePortals(mnode_t *node)
2440 portal_t *p, *portals[6];
2441 mnode_t *outside_node;
2443 outside_node = Mem_Alloc(loadmodel->mempool, sizeof(mnode_t));
2444 outside_node->contents = CONTENTS_SOLID;
2445 outside_node->portals = NULL;
2447 for (i = 0;i < 3;i++)
2449 for (j = 0;j < 2;j++)
2451 portals[j*3 + i] = p = AllocPortal ();
2452 memset (&p->plane, 0, sizeof(mplane_t));
2453 p->plane.normal[i] = j ? -1 : 1;
2454 p->plane.dist = -65536;
2455 p->winding = BaseWindingForPlane (&p->plane);
2457 AddPortalToNodes (p, outside_node, node);
2459 AddPortalToNodes (p, node, outside_node);
2463 // clip the basewindings by all the other planes
2464 for (i = 0;i < 6;i++)
2466 for (j = 0;j < 6;j++)
2470 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
2476 static void Mod_MakePortals(void)
2478 // Con_Printf("building portals for %s\n", loadmodel->name);
2481 // Mod_MakeOutsidePortals (loadmodel->nodes);
2482 Mod_RecursiveNodePortals (loadmodel->nodes);
2483 Mod_FinalizePortals();
2491 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2496 mempool_t *mainmempool;
2499 mod->type = mod_brush;
2501 header = (dheader_t *)buffer;
2503 i = LittleLong (header->version);
2504 if (i != BSPVERSION && i != 30)
2505 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
2506 mod->ishlbsp = i == 30;
2507 if (loadmodel->isworldmodel)
2508 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2510 // swap all the lumps
2511 mod_base = (qbyte *)header;
2513 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2514 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2518 // store which lightmap format to use
2519 mod->lightmaprgba = r_lightmaprgba.integer;
2521 // Mem_CheckSentinelsGlobal();
2522 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
2523 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2524 // Mem_CheckSentinelsGlobal();
2525 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2526 // Mem_CheckSentinelsGlobal();
2527 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2528 // Mem_CheckSentinelsGlobal();
2529 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2530 // Mem_CheckSentinelsGlobal();
2531 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2532 // Mem_CheckSentinelsGlobal();
2533 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2534 // Mem_CheckSentinelsGlobal();
2535 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2536 // Mem_CheckSentinelsGlobal();
2537 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2538 // Mem_CheckSentinelsGlobal();
2539 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2540 // Mem_CheckSentinelsGlobal();
2541 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2542 // Mem_CheckSentinelsGlobal();
2543 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2544 // Mem_CheckSentinelsGlobal();
2545 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2546 // Mem_CheckSentinelsGlobal();
2547 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2548 // Mem_CheckSentinelsGlobal();
2549 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2550 // Mem_CheckSentinelsGlobal();
2551 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2552 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2553 // Mem_CheckSentinelsGlobal();
2556 // Mem_CheckSentinelsGlobal();
2558 // Mem_CheckSentinelsGlobal();
2560 mod->numframes = 2; // regular and alternate animation
2562 mainmempool = mod->mempool;
2563 loadname = mod->name;
2565 Mod_LoadLightList ();
2568 // set up the submodels (FIXME: this is confusing)
2570 for (i = 0;i < mod->numsubmodels;i++)
2573 float dist, modelyawradius, modelradius, *vec;
2576 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2577 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2581 bm = &mod->submodels[i];
2583 mod->hulls[0].firstclipnode = bm->headnode[0];
2584 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2586 mod->hulls[j].firstclipnode = bm->headnode[j];
2587 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2590 mod->firstmodelsurface = bm->firstface;
2591 mod->nummodelsurfaces = bm->numfaces;
2593 mod->DrawSky = NULL;
2594 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2595 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2597 // we only need to have a drawsky function if it is used (usually only on world model)
2598 if (surf->shader == &Cshader_sky)
2599 mod->DrawSky = R_DrawBrushModelSky;
2600 for (k = 0;k < surf->numedges;k++)
2602 l = mod->surfedges[k + surf->firstedge];
2604 vec = mod->vertexes[mod->edges[l].v[0]].position;
2606 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2607 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2608 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2609 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2610 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2611 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2612 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2613 dist = vec[0]*vec[0]+vec[1]*vec[1];
2614 if (modelyawradius < dist)
2615 modelyawradius = dist;
2616 dist += vec[2]*vec[2];
2617 if (modelradius < dist)
2621 modelyawradius = sqrt(modelyawradius);
2622 modelradius = sqrt(modelradius);
2623 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2624 mod->yawmins[2] = mod->normalmins[2];
2625 mod->yawmaxs[2] = mod->normalmaxs[2];
2626 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2627 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2628 // mod->modelradius = modelradius;
2629 // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
2630 if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
2632 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2633 VectorClear(mod->normalmins);
2634 VectorClear(mod->normalmaxs);
2635 VectorClear(mod->yawmins);
2636 VectorClear(mod->yawmaxs);
2637 VectorClear(mod->rotatedmins);
2638 VectorClear(mod->rotatedmaxs);
2639 //mod->modelradius = 0;
2642 // VectorCopy (bm->maxs, mod->maxs);
2643 // VectorCopy (bm->mins, mod->mins);
2645 // mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
2647 mod->numleafs = bm->visleafs;
2649 mod->SERAddEntity = Mod_Brush_SERAddEntity;
2650 mod->Draw = R_DrawBrushModelNormal;
2651 mod->DrawShadow = NULL;
2653 Mod_BrushSortedSurfaces(mod, mainmempool);
2655 // LordHavoc: only register submodels if it is the world
2656 // (prevents bsp models from replacing world submodels)
2657 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2660 // duplicate the basic information
2661 sprintf (name, "*%i", i+1);
2662 loadmodel = Mod_FindName (name);
2664 strcpy (loadmodel->name, name);
2665 // textures and memory belong to the main model
2666 loadmodel->texturepool = NULL;
2667 loadmodel->mempool = NULL;
2671 // Mem_CheckSentinelsGlobal();