diff --git a/changelog.txt b/changelog.txt index cb497cd2..a1fcb473 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ * qbsp: respect floating point texture rotation and shift in map files * qbsp: support for Valve's 220 map format used in later Worldcraft/Hammer +* qbsp: support func_group entities used by Radiant and similar editors * light: fixed a race condition in multithreaded coloured light processing * light: fixed bug preventing use of all 4 light styles in a common case * light: implemented attenutation formulae "delay" 4+5, ala Bengt's tools diff --git a/qbsp/brush.c b/qbsp/brush.c index 0f9f6fff..42830e5c 100644 --- a/qbsp/brush.c +++ b/qbsp/brush.c @@ -849,8 +849,9 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) * 3. detail solid * 4. solid * - * We can always just put water on the head of the list, but will need to - * insert solid brushes between any existing water and solids on the list. + * We will add func_group brushes first and detail brushes last, so we can + * always just put water on the head of the list, but will need to insert + * solid brushes between any existing water and solids on the list. */ solid = NULL; water = dst->brushes; diff --git a/qbsp/map.c b/qbsp/map.c index 174ac630..6d13f247 100644 --- a/qbsp/map.c +++ b/qbsp/map.c @@ -556,6 +556,23 @@ PreParseFile(const char *buf) texinfo->count = map.maxfaces; } +/* + * Special world entities are entities which have their brushes added to the + * world before being removed from the map. Currently func_detail and + * func_group. + */ +static bool +IsWorldBrushEntity(const mapentity_t *entity) +{ + const char *classname = ValueForKey(entity, "classname"); + + if (!strcmp(classname, "func_detail")) + return true; + if (!strcmp(classname, "func_group")) + return true; + return false; +} + void LoadMapFile(void) @@ -565,7 +582,7 @@ LoadMapFile(void) int i, j, length, cAxis; void *pTemp; struct lumpdata *texinfo; - mapentity_t *ent; + mapentity_t *entity; mapbrush_t *brush; mapface_t *face, *face2; @@ -576,16 +593,15 @@ LoadMapFile(void) ParserInit(&parser, buf); map.numfaces = map.numbrushes = map.numentities = 0; - ent = map.entities; - while (ParseEntity(&parser, ent)) { + entity = map.entities; + while (ParseEntity(&parser, entity)) { /* Allocate memory for the bmodel, if needed. */ - const char *classname = ValueForKey(ent, "classname"); - if (strcmp(classname, "func_detail") && ent->nummapbrushes) { - ent->lumps[BSPMODEL].data = AllocMem(BSPMODEL, 1, true); - ent->lumps[BSPMODEL].count = 1; + if (!IsWorldBrushEntity(entity) && entity->nummapbrushes) { + entity->lumps[BSPMODEL].data = AllocMem(BSPMODEL, 1, true); + entity->lumps[BSPMODEL].count = 1; } map.numentities++; - ent++; + entity++; } /* Double check the entity count matches our pre-parse count */ @@ -741,7 +757,6 @@ WriteEntitiesToString(void) int cLen; struct lumpdata *entities; const mapentity_t *ent; - const char *classname; map.cTotal[BSPENT] = 0; @@ -749,8 +764,7 @@ WriteEntitiesToString(void) entities = &map.entities[i].lumps[BSPENT]; /* Check if entity needs to be removed */ - classname = ValueForKey(ent, "classname"); - if (!ent->epairs || !strcmp(classname, "func_detail")) { + if (!ent->epairs || IsWorldBrushEntity(ent)) { entities->count = 0; entities->data = NULL; continue; diff --git a/qbsp/qbsp.c b/qbsp/qbsp.c index 3711dead..04d39ee4 100644 --- a/qbsp/qbsp.c +++ b/qbsp/qbsp.c @@ -40,15 +40,20 @@ ProcessEntity(mapentity_t *ent, const int hullnum) int i, numportals; surface_t *surfs; node_t *nodes; - const char *class; + const char *classname; /* No map brushes means non-bmodel entity */ if (!ent->nummapbrushes) return; - /* func_detail entities get their brushes added to the worldspawn */ - class = ValueForKey(ent, "classname"); - if (!strcmp(class, "func_detail")) + /* + * func_group and func_detail entities get their brushes added to the + * worldspawn + */ + classname = ValueForKey(ent, "classname"); + if (!strcmp(classname, "func_group")) + return; + if (!strcmp(classname, "func_detail")) return; if (ent != pWorldEnt) { @@ -84,23 +89,38 @@ ProcessEntity(mapentity_t *ent, const int hullnum) PrintEntity(ent); Error(errNoValidBrushes); } - Message(msgStat, "%5i brushes", ent->numbrushes); /* - * If this is the world entity, find all func_detail entities and - * add their brushes with the detail flag set. + * If this is the world entity, find all func_group and func_detail + * entities and add their brushes with the appropriate contents flag set. */ if (ent == pWorldEnt) { - const mapentity_t *detail; - const int detailstart = ent->numbrushes; + const mapentity_t *source; + int detailcount; - detail = map.entities + 1; - for (i = 1; i < map.numentities; i++, detail++) { - class = ValueForKey(detail, "classname"); - if (!strcmp(class, "func_detail")) - Brush_LoadEntity(ent, detail, hullnum); + /* Add func_group brushes first */ + source = map.entities + 1; + for (i = 1; i < map.numentities; i++, source++) { + classname = ValueForKey(source, "classname"); + if (!strcmp(classname, "func_group")) + Brush_LoadEntity(ent, source, hullnum); } - Message(msgStat, "%5i detail", ent->numbrushes - detailstart); + + /* Add detail brushes next */ + detailcount = 0; + source = map.entities + 1; + for (i = 1; i < map.numentities; i++, source++) { + classname = ValueForKey(source, "classname"); + if (!strcmp(classname, "func_detail")) { + int detailstart = ent->numbrushes; + Brush_LoadEntity(ent, source, hullnum); + detailcount += ent->numbrushes - detailstart; + } + } + Message(msgStat, "%5i brushes", ent->numbrushes - detailcount); + Message(msgStat, "%5i detail", detailcount); + } else { + Message(msgStat, "%5i brushes", ent->numbrushes); } /*