From 77f3da30bf2d6daeca0bea8c7773ccad45bab8b5 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Fri, 9 Jun 2017 15:03:56 -0600 Subject: [PATCH] qbsp: add func_detail_fence --- include/qbsp/map.hh | 2 +- include/qbsp/qbsp.hh | 2 ++ qbsp/brush.cc | 20 +++++++++++++++++++- qbsp/csg4.cc | 10 +++++++++- qbsp/map.cc | 2 ++ qbsp/qbsp.cc | 8 ++++++++ qbsp/solidbsp.cc | 31 ++++++++++++++++++++++++------- qbsp/writebsp.cc | 21 ++++++++++++++++++--- 8 files changed, 83 insertions(+), 13 deletions(-) diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index fac4378e..3760ee60 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -63,7 +63,7 @@ typedef struct mapentity_s { int nummapbrushes; // Temporary lists used to build `brushes` in the correct order. - brush_t *solid, *sky, *detail, *detail_illusionary, *liquid; + brush_t *solid, *sky, *detail, *detail_illusionary, *detail_fence, *liquid; epair_t *epairs; vec3_t mins, maxs; diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index f93101b3..e6c30bbe 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -109,6 +109,7 @@ #define CONTENTS_ORIGIN -9 /* compiler internal use only */ #define CONTENTS_DETAIL -10 /* compiler internal use only */ #define CONTENTS_DETAIL_ILLUSIONARY -11 /* compiler internal use only */ +#define CONTENTS_DETAIL_FENCE -12 /* compiler internal use only */ // Special contents flags for the compiler only #define CFLAGS_STRUCTURAL_COVERED_BY_DETAIL (1U << 0) @@ -349,6 +350,7 @@ typedef struct options_s { bool fOmitDetail; bool fOmitDetailWall; bool fOmitDetailIllusionary; + bool fOmitDetailFence; bool fForcePRT1; } options_t; diff --git a/qbsp/brush.cc b/qbsp/brush.cc index b0fbfa7c..532efc27 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -944,6 +944,11 @@ Entity_SortBrushes(mapentity_t *dst) *nextLink = dst->liquid; nextLink = &last->next; } + if (dst->detail_fence) { + brush_t *last = Brush_ListTail(dst->detail_fence); + *nextLink = dst->detail_fence; + nextLink = &last->next; + } if (dst->detail) { brush_t *last = Brush_ListTail(dst->detail); *nextLink = dst->detail; @@ -977,12 +982,13 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) vec3_t rotate_offset; int i, contents, cflags = 0; int lmshift; - bool detail, detail_illusionary; + bool detail, detail_fence, detail_illusionary; /* * The brush list needs to be ordered (lowest to highest priority): * - detail_illusionary (which is saved as empty) * - liquid + * - detail_fence * - detail (which is solid) * - sky * - solid @@ -1039,6 +1045,11 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) cflags |= CFLAGS_DETAIL_WALL; } + detail_fence = false; + if (!Q_strcasecmp(classname, "func_detail_fence") && !options.fNodetail) { + detail_fence = true; + } + detail_illusionary = false; if (!Q_strcasecmp(classname, "func_detail_illusionary") && !options.fNodetail) { detail_illusionary = true; @@ -1069,6 +1080,8 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) continue; if (options.fOmitDetailIllusionary && detail_illusionary) continue; + if (options.fOmitDetailFence && detail_fence) + continue; /* turn solid brushes into detail, if we're in hull0 */ if (hullnum == 0 && contents == CONTENTS_SOLID) { @@ -1076,6 +1089,8 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) contents = CONTENTS_DETAIL; } else if (detail_illusionary) { contents = CONTENTS_DETAIL_ILLUSIONARY; + } else if (detail_fence) { + contents = CONTENTS_DETAIL_FENCE; } } @@ -1143,6 +1158,9 @@ Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum) } else if (brush->contents == CONTENTS_DETAIL_ILLUSIONARY) { brush->next = dst->detail_illusionary; dst->detail_illusionary = brush; + } else if (brush->contents == CONTENTS_DETAIL_FENCE) { + brush->next = dst->detail_fence; + dst->detail_fence = brush; } else { brush->next = dst->liquid; dst->liquid = brush; diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 8dc46c73..7265d993 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -351,6 +351,7 @@ SaveFacesToPlaneList(face_t *facelist, bool mirror, std::map &pla // want the face. So just set the texinfo to "skip" so it gets deleted. if (face->contents[1] == CONTENTS_DETAIL || face->contents[1] == CONTENTS_DETAIL_ILLUSIONARY + || face->contents[1] == CONTENTS_DETAIL_FENCE || (face->cflags[1] & CFLAGS_WAS_ILLUSIONARY)) { newface->texinfo = MakeSkipTexinfo(); } @@ -590,6 +591,12 @@ CSGFaces(const mapentity_t *entity) */ continue; } + + if (clipbrush->contents == CONTENTS_DETAIL_FENCE + && brush->contents != CONTENTS_DETAIL_FENCE) { + /* CONTENTS_DETAIL_FENCE never clips anything but itself */ + continue; + } /* check bounding box first */ for (i = 0; i < 3; i++) { @@ -631,7 +638,8 @@ CSGFaces(const mapentity_t *entity) && clipbrush->contents != CONTENTS_SKY && clipbrush->contents != CONTENTS_DETAIL)) || (IsLiquid(brush->contents) && clipbrush->contents == CONTENTS_DETAIL_ILLUSIONARY) - || (brush->contents == CONTENTS_DETAIL_ILLUSIONARY && IsLiquid(clipbrush->contents))) + || (brush->contents == CONTENTS_DETAIL_ILLUSIONARY && IsLiquid(clipbrush->contents)) + || (brush->contents == CONTENTS_DETAIL_FENCE && IsLiquid(clipbrush->contents))) { SaveInsideFaces(inside, clipbrush, &outside); } else { diff --git a/qbsp/map.cc b/qbsp/map.cc index da553f87..cfa1436d 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -1530,6 +1530,8 @@ IsWorldBrushEntity(const mapentity_t *entity) return true; if (!Q_strcasecmp(classname, "func_detail_wall")) return true; + if (!Q_strcasecmp(classname, "func_detail_fence")) + return true; return false; } diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index dcfa6b33..8eebef04 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -76,6 +76,7 @@ ProcessEntity(mapentity_t *entity, const int hullnum) entity->sky = NULL; entity->detail = NULL; entity->detail_illusionary = NULL; + entity->detail_fence = NULL; entity->liquid = NULL; entity->numbrushes = 0; for (i = 0; i < 3; i++) { @@ -113,6 +114,7 @@ ProcessEntity(mapentity_t *entity, const int hullnum) int detail_all_count = Brush_ListCount(entity->detail); /* including CFLAGS_DETAIL_WALL */ int detail_wall_count = Brush_ListCountWithCFlags(entity->detail, CFLAGS_DETAIL_WALL); int detail_illusionarycount = Brush_ListCount(entity->detail_illusionary); + int detail_fence_count = Brush_ListCount(entity->detail_fence); int liquidcount = Brush_ListCount(entity->liquid); int nondetailcount = (solidcount + skycount + liquidcount); @@ -125,6 +127,9 @@ ProcessEntity(mapentity_t *entity, const int hullnum) if (detail_wall_count > 0) { Message(msgStat, "%8d detail wall", detail_wall_count); } + if (detail_fence_count > 0) { + Message(msgStat, "%8d detail fence", detail_fence_count); + } if (detail_illusionarycount > 0) { Message(msgStat, "%8d detail illusionary", detail_illusionarycount); } @@ -655,6 +660,7 @@ PrintOptions(void) " -omitdetail func_detail brushes are omitted from the compile\n" " -omitdetailwall func_detail_wall brushes are omitted from the compile\n" " -omitdetailillusionary func_detail_illusionary brushes are omitted from the compile\n" + " -omitdetailfence func_detail_fence brushes are omitted from the compile\n" " -convert Convert a .MAP to a different .MAP format. fmt can be: quake, quake2, valve, bp (brush primitives).\n" " sourcefile .MAP file to process\n" " destfile .BSP file to output\n"); @@ -841,6 +847,8 @@ ParseOptions(char *szOptions) options.fOmitDetailWall = true; } else if (!Q_strcasecmp(szTok, "omitdetailillusionary")) { options.fOmitDetailIllusionary = true; + } else if (!Q_strcasecmp(szTok, "omitdetailfence")) { + options.fOmitDetailFence = true; } else if (!Q_strcasecmp(szTok, "convert")) { szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd); if (!szTok2) diff --git a/qbsp/solidbsp.cc b/qbsp/solidbsp.cc index 915adc98..c48c395b 100644 --- a/qbsp/solidbsp.cc +++ b/qbsp/solidbsp.cc @@ -27,7 +27,7 @@ int splitnodes; static int leaffaces; static int nodefaces; -static int c_solid, c_empty, c_water, c_detail, c_detail_illusionary; +static int c_solid, c_empty, c_water, c_detail, c_detail_illusionary, c_detail_fence; static bool usemidsplit; //============================================================================ @@ -64,6 +64,9 @@ DetailToSolid(node_t *node) } else if (node->contents == CONTENTS_DETAIL_ILLUSIONARY) { node->contents = CONTENTS_EMPTY; } + /* N.B.: CONTENTS_DETAIL_FENCE is not remapped to CONTENTS_SOLID until the very last moment, + * because we want to generate a leaf (if we set it to CONTENTS_SOLID now it would use leaf 0). + */ return; } else { DetailToSolid(node->children[0]); @@ -559,6 +562,10 @@ CalcSurfaceInfo(surface_t *surf) || (f->contents[1] == CONTENTS_DETAIL_ILLUSIONARY)) faceIsDetail = true; + if ((f->contents[0] == CONTENTS_DETAIL_FENCE) + || (f->contents[1] == CONTENTS_DETAIL_FENCE)) + faceIsDetail = true; + if ((f->cflags[0] & CFLAGS_WAS_ILLUSIONARY) || (f->cflags[1] & CFLAGS_WAS_ILLUSIONARY)) faceIsDetail = true; @@ -732,10 +739,13 @@ GetContentsName( int Contents ) { case CONTENTS_DETAIL: return "Detail"; - + case CONTENTS_DETAIL_ILLUSIONARY: return "DetailIllusionary"; - + + case CONTENTS_DETAIL_FENCE: + return "DetailFence"; + default: return "Error"; } @@ -744,12 +754,14 @@ GetContentsName( int Contents ) { static int Contents_Priority(int contents) { switch (contents) { - case CONTENTS_SOLID: return 6; + case CONTENTS_SOLID: return 7; - case CONTENTS_SKY: return 5; + case CONTENTS_SKY: return 6; + + case CONTENTS_DETAIL: return 5; + + case CONTENTS_DETAIL_FENCE: return 4; - case CONTENTS_DETAIL: return 4; - case CONTENTS_DETAIL_ILLUSIONARY: return 3; case CONTENTS_WATER: return 2; @@ -831,6 +843,9 @@ LinkConvexFaces(surface_t *planelist, node_t *leafnode) case CONTENTS_DETAIL_ILLUSIONARY: c_detail_illusionary++; break; + case CONTENTS_DETAIL_FENCE: + c_detail_fence++; + break; default: Error("Bad contents in face (%s)", __func__); } @@ -1015,6 +1030,7 @@ SolidBSP(const mapentity_t *entity, surface_t *surfhead, bool midsplit) c_water = 0; c_detail = 0; c_detail_illusionary = 0; + c_detail_fence = 0; PartitionSurfaces(surfhead, headnode); @@ -1024,6 +1040,7 @@ SolidBSP(const mapentity_t *entity, surface_t *surfhead, bool midsplit) Message(msgStat, "%8d water leafs", c_water); Message(msgStat, "%8d detail leafs", c_detail); Message(msgStat, "%8d detail illusionary leafs", c_detail_illusionary); + Message(msgStat, "%8d detail fence leafs", c_detail_fence); Message(msgStat, "%8d leaffaces", leaffaces); Message(msgStat, "%8d nodefaces", nodefaces); diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index 51190a3f..5cffbf8b 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -39,6 +39,21 @@ AssertVanillaContentType(int content) } } +static int +RemapContentsForExport(int content) +{ + if (content == CONTENTS_DETAIL_FENCE) { + /* + * This is for func_detail_wall.. we want to write a solid leaf that has faces, + * because it may be possible to see inside (fence textures). + * + * Normally solid leafs are not written and just referenced as leaf 0. + */ + return CONTENTS_SOLID; + } + return content; +} + static void ExportNodePlanes_r(node_t *node, int *planemap) { @@ -362,7 +377,7 @@ ExportLeaf_BSP29(mapentity_t *entity, node_t *node) leaves->index++; map.cTotal[LUMP_LEAFS]++; - dleaf->contents = node->contents; + dleaf->contents = RemapContentsForExport(node->contents); AssertVanillaContentType(dleaf->contents); /* @@ -412,7 +427,7 @@ ExportLeaf_BSP2(mapentity_t *entity, node_t *node) leaves->index++; map.cTotal[LUMP_LEAFS]++; - dleaf->contents = node->contents; + dleaf->contents = RemapContentsForExport(node->contents); AssertVanillaContentType(dleaf->contents); /* @@ -462,7 +477,7 @@ ExportLeaf_BSP2rmq(mapentity_t *entity, node_t *node) leaves->index++; map.cTotal[LUMP_LEAFS]++; - dleaf->contents = node->contents; + dleaf->contents = RemapContentsForExport(node->contents); AssertVanillaContentType(dleaf->contents); /*