remove "brushes" from mapentity_t - it is now local to the ProcessEntity process
"node_t::original_brushes" is now only used during construction and cleared on Prune; original_mapbrushes is used to track the map brushes on nodes post-construction calculate and cache contents on mapbrush_t
This commit is contained in:
parent
4c15e6f717
commit
4ec30e02a2
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include <qbsp/winding.hh>
|
#include <qbsp/winding.hh>
|
||||||
#include <qbsp/qbsp.hh>
|
#include <qbsp/qbsp.hh>
|
||||||
#include <qbsp/map.hh>
|
|
||||||
#include <common/aabb.hh>
|
#include <common/aabb.hh>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
|
@ -58,10 +57,8 @@ class mapbrush_t;
|
||||||
struct bspbrush_t
|
struct bspbrush_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The brushes in the mapentity_t::brushes vector are considered originals. Brush fragments created during
|
* The brushes in main brush vectors are considered originals. Brush fragments created during
|
||||||
* the BrushBSP will have this pointing back to the original brush in mapentity_t::brushes.
|
* the BrushBSP will have this pointing back to the original brush in the list.
|
||||||
*
|
|
||||||
* fixme-brushbsp: this is supposed to be a mapbrush_t
|
|
||||||
*/
|
*/
|
||||||
bspbrush_t *original;
|
bspbrush_t *original;
|
||||||
const mapbrush_t *mapbrush;
|
const mapbrush_t *mapbrush;
|
||||||
|
|
@ -81,10 +78,10 @@ struct bspbrush_t
|
||||||
std::unique_ptr<bspbrush_t> copy_unique() const;
|
std::unique_ptr<bspbrush_t> copy_unique() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using bspbrush_vector_t = std::vector<std::unique_ptr<bspbrush_t>>;
|
||||||
|
|
||||||
qplane3d Face_Plane(const face_t *face);
|
qplane3d Face_Plane(const face_t *face);
|
||||||
qplane3d Face_Plane(const side_t *face);
|
qplane3d Face_Plane(const side_t *face);
|
||||||
|
|
||||||
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
|
bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents, const int hullnum);
|
||||||
contentflags_t Brush_GetContents(const mapbrush_t *mapbrush);
|
|
||||||
void CreateBrushWindings(bspbrush_t *brush);
|
void CreateBrushWindings(bspbrush_t *brush);
|
||||||
void FreeBrushes(mapentity_t *ent);
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <qbsp/winding.hh>
|
#include <qbsp/winding.hh>
|
||||||
#include <common/qvec.hh>
|
#include <common/qvec.hh>
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
@ -39,6 +40,4 @@ constexpr vec_t EDGE_LENGTH_EPSILON = 0.2;
|
||||||
|
|
||||||
bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
|
bool WindingIsTiny(const winding_t &w, double size = EDGE_LENGTH_EPSILON);
|
||||||
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
|
std::unique_ptr<bspbrush_t> BrushFromBounds(const aabb3d &bounds);
|
||||||
|
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const bspbrush_vector_t &brushes, std::optional<bool> forced_quick_tree);
|
||||||
// compatibility version
|
|
||||||
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::optional<bool> forced_quick_tree);
|
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <common/qvec.hh>
|
#include <common/qvec.hh>
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct bspbrush_t;
|
|
||||||
struct face_t;
|
struct face_t;
|
||||||
struct side_t;
|
struct side_t;
|
||||||
|
|
||||||
|
|
@ -37,4 +37,4 @@ std::unique_ptr<face_t> CopyFace(const face_t *in);
|
||||||
std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
||||||
std::unique_ptr<face_t> in, const qplane3d &split);
|
std::unique_ptr<face_t> in, const qplane3d &split);
|
||||||
void UpdateFaceSphere(face_t *in);
|
void UpdateFaceSphere(face_t *in);
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> MakeBspBrushList(mapentity_t *entity);
|
bspbrush_vector_t MakeBspBrushList(const bspbrush_vector_t &brushes);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qbsp/qbsp.hh>
|
#include <qbsp/qbsp.hh>
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
#include <common/bspfile.hh>
|
#include <common/bspfile.hh>
|
||||||
#include <common/parser.hh>
|
#include <common/parser.hh>
|
||||||
|
|
@ -80,6 +81,7 @@ public:
|
||||||
aabb3d bounds {};
|
aabb3d bounds {};
|
||||||
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
||||||
parser_source_location line;
|
parser_source_location line;
|
||||||
|
contentflags_t contents {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lumpdata
|
struct lumpdata
|
||||||
|
|
@ -99,15 +101,6 @@ enum class rotation_t
|
||||||
class mapentity_t
|
class mapentity_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef _MSC_VER
|
|
||||||
// FIXME: this is to allow MSVC to compile
|
|
||||||
mapentity_t() = default;
|
|
||||||
mapentity_t(mapentity_t &&) noexcept = default;
|
|
||||||
mapentity_t(const mapentity_t &) = delete;
|
|
||||||
mapentity_t &operator=(const mapentity_t &) = delete;
|
|
||||||
mapentity_t &operator=(mapentity_t &&) noexcept = default;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
qvec3d origin{};
|
qvec3d origin{};
|
||||||
rotation_t rotation;
|
rotation_t rotation;
|
||||||
|
|
||||||
|
|
@ -120,7 +113,6 @@ public:
|
||||||
entdict_t epairs;
|
entdict_t epairs;
|
||||||
|
|
||||||
aabb3d bounds;
|
aabb3d bounds;
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> brushes;
|
|
||||||
|
|
||||||
int firstoutputfacenumber = -1;
|
int firstoutputfacenumber = -1;
|
||||||
std::optional<size_t> outputmodelnumber = std::nullopt;
|
std::optional<size_t> outputmodelnumber = std::nullopt;
|
||||||
|
|
@ -383,7 +375,7 @@ qvec3d FixRotateOrigin(mapentity_t *entity);
|
||||||
constexpr int HULL_COLLISION = -1;
|
constexpr int HULL_COLLISION = -1;
|
||||||
|
|
||||||
/* Create BSP brushes from map brushes */
|
/* Create BSP brushes from map brushes */
|
||||||
void Brush_LoadEntity(mapentity_t *entity, const int hullnum);
|
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes);
|
||||||
|
|
||||||
std::list<face_t *> CSGFace(
|
std::list<face_t *> CSGFace(
|
||||||
face_t *srcface, const mapentity_t *srcentity, const bspbrush_t *srcbrush, const node_t *srcnode);
|
face_t *srcface, const mapentity_t *srcentity, const bspbrush_t *srcbrush, const node_t *srcnode);
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <qbsp/brush.hh>
|
||||||
|
|
||||||
class mapentity_t;
|
class mapentity_t;
|
||||||
struct node_t;
|
struct node_t;
|
||||||
struct tree_t;
|
struct tree_t;
|
||||||
|
|
||||||
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum);
|
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes);
|
||||||
std::vector<node_t *> FindOccupiedClusters(node_t *headnode);
|
std::vector<node_t *> FindOccupiedClusters(node_t *headnode);
|
||||||
|
|
||||||
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum);
|
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes);
|
||||||
|
|
|
||||||
|
|
@ -79,4 +79,4 @@ std::list<std::unique_ptr<buildportal_t>> MakeHeadnodePortals(tree_t *tree);
|
||||||
void MakePortalsFromBuildportals(tree_t *tree, std::list<std::unique_ptr<buildportal_t>> buildportals);
|
void MakePortalsFromBuildportals(tree_t *tree, std::list<std::unique_ptr<buildportal_t>> buildportals);
|
||||||
void EmitAreaPortals(node_t *headnode);
|
void EmitAreaPortals(node_t *headnode);
|
||||||
void FloodAreas(mapentity_t *entity, node_t *headnode);
|
void FloodAreas(mapentity_t *entity, node_t *headnode);
|
||||||
void MarkVisibleSides(tree_t *tree, mapentity_t *entity);
|
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes);
|
||||||
|
|
|
||||||
|
|
@ -614,6 +614,7 @@ namespace qv
|
||||||
|
|
||||||
struct bspbrush_t;
|
struct bspbrush_t;
|
||||||
struct side_t;
|
struct side_t;
|
||||||
|
class mapbrush_t;
|
||||||
|
|
||||||
struct bspbrush_t_less
|
struct bspbrush_t_less
|
||||||
{
|
{
|
||||||
|
|
@ -642,7 +643,6 @@ struct node_t
|
||||||
|
|
||||||
// information for leafs
|
// information for leafs
|
||||||
contentflags_t contents; // leaf nodes (0 for decision nodes)
|
contentflags_t contents; // leaf nodes (0 for decision nodes)
|
||||||
std::set<bspbrush_t *, bspbrush_t_less> original_brushes;
|
|
||||||
std::vector<face_t *> markfaces; // leaf nodes only, point to node faces
|
std::vector<face_t *> markfaces; // leaf nodes only, point to node faces
|
||||||
portal_t *portals;
|
portal_t *portals;
|
||||||
int visleafnum; // -1 = solid
|
int visleafnum; // -1 = solid
|
||||||
|
|
@ -656,6 +656,8 @@ struct node_t
|
||||||
uint32_t firstleafbrush; // Q2
|
uint32_t firstleafbrush; // Q2
|
||||||
uint32_t numleafbrushes;
|
uint32_t numleafbrushes;
|
||||||
int32_t area;
|
int32_t area;
|
||||||
|
std::set<bspbrush_t *, bspbrush_t_less> original_brushes; // FIXME: only valid during construction
|
||||||
|
std::unordered_set<const mapbrush_t *> original_mapbrushes;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitQBSP(int argc, const char **argv);
|
void InitQBSP(int argc, const char **argv);
|
||||||
|
|
|
||||||
|
|
@ -207,16 +207,6 @@ static bool MapBrush_IsHint(const mapbrush_t &brush)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
=====================
|
|
||||||
FreeBrushes
|
|
||||||
=====================
|
|
||||||
*/
|
|
||||||
void FreeBrushes(mapentity_t *ent)
|
|
||||||
{
|
|
||||||
ent->brushes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (hullnum <= 0 && Brush_IsHint(*hullbrush)) {
|
if (hullnum <= 0 && Brush_IsHint(*hullbrush)) {
|
||||||
/* Don't generate hintskip faces */
|
/* Don't generate hintskip faces */
|
||||||
|
|
@ -229,41 +219,6 @@ void FreeBrushes(mapentity_t *ent)
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
contentflags_t Brush_GetContents(const mapbrush_t *mapbrush)
|
|
||||||
{
|
|
||||||
bool base_contents_set = false;
|
|
||||||
contentflags_t base_contents = qbsp_options.target_game->create_empty_contents();
|
|
||||||
|
|
||||||
// validate that all of the sides have valid contents
|
|
||||||
for (auto &mapface : mapbrush->faces) {
|
|
||||||
const maptexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
|
||||||
|
|
||||||
contentflags_t contents =
|
|
||||||
qbsp_options.target_game->face_get_contents(mapface.texname.data(), texinfo.flags, mapface.contents);
|
|
||||||
|
|
||||||
if (contents.is_empty(qbsp_options.target_game)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the first non-empty as the base contents value
|
|
||||||
if (!base_contents_set) {
|
|
||||||
base_contents_set = true;
|
|
||||||
base_contents = contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!contents.types_equal(base_contents, qbsp_options.target_game)) {
|
|
||||||
logging::print("WARNING: {}: mixed face contents ({} != {})\n",
|
|
||||||
mapface.line, base_contents.to_string(qbsp_options.target_game), contents.to_string(qbsp_options.target_game));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we found a valid type
|
|
||||||
Q_assert(base_contents.is_valid(qbsp_options.target_game, false));
|
|
||||||
|
|
||||||
return base_contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
CreateBrushWindings
|
CreateBrushWindings
|
||||||
|
|
@ -399,7 +354,7 @@ bspbrush_t LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const c
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum, content_stats_base_t &stats)
|
static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum, content_stats_base_t &stats, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
// _omitbrushes 1 just discards all brushes in the entity.
|
// _omitbrushes 1 just discards all brushes in the entity.
|
||||||
// could be useful for geometry guides, selective compilation, etc.
|
// could be useful for geometry guides, selective compilation, etc.
|
||||||
|
|
@ -461,7 +416,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
|
||||||
for (i = 0; i < src->mapbrushes.size(); i++, it++) {
|
for (i = 0; i < src->mapbrushes.size(); i++, it++) {
|
||||||
logging::percent(i, src->mapbrushes.size());
|
logging::percent(i, src->mapbrushes.size());
|
||||||
auto &mapbrush = *it;
|
auto &mapbrush = *it;
|
||||||
contentflags_t contents = Brush_GetContents(&mapbrush);
|
contentflags_t contents = mapbrush.contents;
|
||||||
|
|
||||||
// per-brush settings
|
// per-brush settings
|
||||||
bool detail = false;
|
bool detail = false;
|
||||||
|
|
@ -570,7 +525,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
|
||||||
qbsp_options.target_game->count_contents_in_stats(brush.contents, stats);
|
qbsp_options.target_game->count_contents_in_stats(brush.contents, stats);
|
||||||
|
|
||||||
dst->bounds += brush.bounds;
|
dst->bounds += brush.bounds;
|
||||||
dst->brushes.push_back(std::make_unique<bspbrush_t>(std::move(brush)));
|
brushes.push_back(std::make_unique<bspbrush_t>(std::move(brush)));
|
||||||
}
|
}
|
||||||
|
|
||||||
logging::percent(src->mapbrushes.size(), src->mapbrushes.size(), src == map.world_entity());
|
logging::percent(src->mapbrushes.size(), src->mapbrushes.size(), src == map.world_entity());
|
||||||
|
|
@ -584,13 +539,13 @@ hullnum HULL_COLLISION should contain ALL brushes. (used by BSPX_CreateBrushList
|
||||||
hullnum 0 does not contain clip brushes.
|
hullnum 0 does not contain clip brushes.
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
void Brush_LoadEntity(mapentity_t *entity, const int hullnum)
|
void Brush_LoadEntity(mapentity_t *entity, const int hullnum, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
auto stats = qbsp_options.target_game->create_content_stats();
|
auto stats = qbsp_options.target_game->create_content_stats();
|
||||||
|
|
||||||
Brush_LoadEntity(entity, entity, hullnum, *stats);
|
Brush_LoadEntity(entity, entity, hullnum, *stats, brushes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the world entity, find all func_group and func_detail
|
* If this is the world entity, find all func_group and func_detail
|
||||||
|
|
@ -610,7 +565,7 @@ void Brush_LoadEntity(mapentity_t *entity, const int hullnum)
|
||||||
ProcessAreaPortal(source);
|
ProcessAreaPortal(source);
|
||||||
|
|
||||||
if (IsWorldBrushEntity(source) || IsNonRemoveWorldBrushEntity(source)) {
|
if (IsWorldBrushEntity(source) || IsNonRemoveWorldBrushEntity(source)) {
|
||||||
Brush_LoadEntity(entity, source, hullnum, *stats);
|
Brush_LoadEntity(entity, source, hullnum, *stats, brushes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -387,6 +387,7 @@ static void LeafNode(node_t *leafnode, std::vector<std::unique_ptr<bspbrush_t>>
|
||||||
for (auto &brush : brushes) {
|
for (auto &brush : brushes) {
|
||||||
Q_assert(brush->original != nullptr);
|
Q_assert(brush->original != nullptr);
|
||||||
leafnode->original_brushes.insert(brush->original);
|
leafnode->original_brushes.insert(brush->original);
|
||||||
|
leafnode->original_mapbrushes.insert(brush->original->mapbrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats);
|
qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats);
|
||||||
|
|
@ -1060,7 +1061,7 @@ static void BuildTree_r(node_t *node, std::vector<std::unique_ptr<bspbrush_t>> b
|
||||||
BrushBSP
|
BrushBSP
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::unique_ptr<bspbrush_t>> brushlist, std::optional<bool> forced_quick_tree)
|
static std::unique_ptr<tree_t> BrushBSP_internal(mapentity_t *entity, std::vector<std::unique_ptr<bspbrush_t>> brushlist, std::optional<bool> forced_quick_tree)
|
||||||
{
|
{
|
||||||
auto tree = std::make_unique<tree_t>();
|
auto tree = std::make_unique<tree_t>();
|
||||||
|
|
||||||
|
|
@ -1168,7 +1169,7 @@ static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::un
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::optional<bool> forced_quick_tree)
|
std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, const std::vector<std::unique_ptr<bspbrush_t>> &brushlist, std::optional<bool> forced_quick_tree)
|
||||||
{
|
{
|
||||||
return BrushBSP(entity, MakeBspBrushList(entity), forced_quick_tree);
|
return BrushBSP_internal(entity, MakeBspBrushList(brushlist), forced_quick_tree);
|
||||||
}
|
}
|
||||||
|
|
@ -121,11 +121,11 @@ std::tuple<std::unique_ptr<face_t>, std::unique_ptr<face_t>> SplitFace(
|
||||||
return {std::move(new_front), std::move(new_back)};
|
return {std::move(new_front), std::move(new_back)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> MakeBspBrushList(mapentity_t *entity)
|
std::vector<std::unique_ptr<bspbrush_t>> MakeBspBrushList(const bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
// set the original pointers
|
// set the original pointers
|
||||||
std::vector<std::unique_ptr<bspbrush_t>> brushcopies;
|
std::vector<std::unique_ptr<bspbrush_t>> brushcopies;
|
||||||
for (const auto &original : entity->brushes) {
|
for (const auto &original : brushes) {
|
||||||
auto copy = original->copy_unique();
|
auto copy = original->copy_unique();
|
||||||
copy->original = original.get();
|
copy->original = original.get();
|
||||||
brushcopies.push_back(std::move(copy));
|
brushcopies.push_back(std::move(copy));
|
||||||
|
|
|
||||||
50
qbsp/map.cc
50
qbsp/map.cc
|
|
@ -1790,6 +1790,41 @@ inline void AddBrushBevels(mapentity_t &e, mapbrush_t &b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static contentflags_t Brush_GetContents(const mapbrush_t &mapbrush)
|
||||||
|
{
|
||||||
|
bool base_contents_set = false;
|
||||||
|
contentflags_t base_contents = qbsp_options.target_game->create_empty_contents();
|
||||||
|
|
||||||
|
// validate that all of the sides have valid contents
|
||||||
|
for (auto &mapface : mapbrush.faces) {
|
||||||
|
const maptexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
||||||
|
|
||||||
|
contentflags_t contents =
|
||||||
|
qbsp_options.target_game->face_get_contents(mapface.texname.data(), texinfo.flags, mapface.contents);
|
||||||
|
|
||||||
|
if (contents.is_empty(qbsp_options.target_game)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the first non-empty as the base contents value
|
||||||
|
if (!base_contents_set) {
|
||||||
|
base_contents_set = true;
|
||||||
|
base_contents = contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contents.types_equal(base_contents, qbsp_options.target_game)) {
|
||||||
|
logging::print("WARNING: {}: mixed face contents ({} != {})\n",
|
||||||
|
mapface.line, base_contents.to_string(qbsp_options.target_game), contents.to_string(qbsp_options.target_game));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we found a valid type
|
||||||
|
Q_assert(base_contents.is_valid(qbsp_options.target_game, false));
|
||||||
|
|
||||||
|
return base_contents;
|
||||||
|
}
|
||||||
|
|
||||||
static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
||||||
{
|
{
|
||||||
mapbrush_t brush;
|
mapbrush_t brush;
|
||||||
|
|
@ -1864,6 +1899,8 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
||||||
}
|
}
|
||||||
// ericw -- end brush primitives
|
// ericw -- end brush primitives
|
||||||
|
|
||||||
|
brush.contents = Brush_GetContents(brush);
|
||||||
|
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2112,11 +2149,14 @@ void ProcessAreaPortal(mapentity_t *entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &brush : entity->mapbrushes) {
|
for (auto &brush : entity->mapbrushes) {
|
||||||
|
brush.contents.native = Q2_CONTENTS_AREAPORTAL;
|
||||||
|
|
||||||
for (auto &face : brush.faces) {
|
for (auto &face : brush.faces) {
|
||||||
face.contents.native = Q2_CONTENTS_AREAPORTAL;
|
face.contents.native = brush.contents.native;
|
||||||
face.texinfo = map.skip_texinfo;
|
face.texinfo = map.skip_texinfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entity->areaportalnum = ++map.numareaportals;
|
entity->areaportalnum = ++map.numareaportals;
|
||||||
// set the portal number as "style"
|
// set the portal number as "style"
|
||||||
entity->epairs.set("style", std::to_string(map.numareaportals));
|
entity->epairs.set("style", std::to_string(map.numareaportals));
|
||||||
|
|
@ -2235,16 +2275,14 @@ void ProcessMapBrushes()
|
||||||
// calculate brush bounds
|
// calculate brush bounds
|
||||||
CalculateBrushBounds(brush);
|
CalculateBrushBounds(brush);
|
||||||
|
|
||||||
const contentflags_t contents = Brush_GetContents(&brush);
|
|
||||||
|
|
||||||
// origin brushes are removed, and the origin of the entity is overwritten
|
// origin brushes are removed, and the origin of the entity is overwritten
|
||||||
// with its centroid.
|
// with its centroid.
|
||||||
if (contents.is_origin(qbsp_options.target_game)) {
|
if (brush.contents.is_origin(qbsp_options.target_game)) {
|
||||||
if (&entity == map.world_entity()) {
|
if (&entity == map.world_entity()) {
|
||||||
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
||||||
} else if (entity.epairs.has("origin")) {
|
} else if (entity.epairs.has("origin")) {
|
||||||
// fixme-brushbsp: entity.line
|
// fixme-brushbsp: entity.line
|
||||||
logging::print("WARNING: Entity at {} has multiple origin brushes\n", entity.mapbrushes.front().faces[0].line);
|
logging::print("WARNING: Entity at {} has multiple origin brushes\n", entity.mapbrushes.front().line);
|
||||||
} else {
|
} else {
|
||||||
entity.origin = brush.bounds.centroid();
|
entity.origin = brush.bounds.centroid();
|
||||||
entity.epairs.set("origin", qv::to_string(entity.origin));
|
entity.epairs.set("origin", qv::to_string(entity.origin));
|
||||||
|
|
@ -2366,7 +2404,6 @@ void LoadMapFile(void)
|
||||||
|
|
||||||
// Remove dummy entity inserted above
|
// Remove dummy entity inserted above
|
||||||
assert(!map.entities.back().epairs.size());
|
assert(!map.entities.back().epairs.size());
|
||||||
assert(map.entities.back().brushes.empty());
|
|
||||||
map.entities.pop_back();
|
map.entities.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2396,7 +2433,6 @@ void LoadMapFile(void)
|
||||||
}
|
}
|
||||||
// Remove dummy entity inserted above
|
// Remove dummy entity inserted above
|
||||||
assert(!map.entities.back().epairs.size());
|
assert(!map.entities.back().epairs.size());
|
||||||
assert(map.entities.back().brushes.empty());
|
|
||||||
map.entities.pop_back();
|
map.entities.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -349,9 +349,9 @@ std::vector<node_t *> FindOccupiedClusters(node_t *headnode)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static void MarkBrushSidesInvisible(mapentity_t *entity)
|
static void MarkBrushSidesInvisible(mapentity_t *entity, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
for (auto &brush : entity->brushes) {
|
for (auto &brush : brushes) {
|
||||||
for (auto &face : brush->sides) {
|
for (auto &face : brush->sides) {
|
||||||
face.visible = false;
|
face.visible = false;
|
||||||
}
|
}
|
||||||
|
|
@ -599,7 +599,7 @@ get incorrectly marked as "invisible").
|
||||||
Special cases: structural fully covered by detail still needs to be marked "visible".
|
Special cases: structural fully covered by detail still needs to be marked "visible".
|
||||||
===========
|
===========
|
||||||
*/
|
*/
|
||||||
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum)
|
bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
node_t *node = tree->headnode.get();
|
node_t *node = tree->headnode.get();
|
||||||
|
|
||||||
|
|
@ -701,29 +701,32 @@ bool FillOutside(mapentity_t *entity, tree_t *tree, const int hullnum)
|
||||||
|
|
||||||
// See missing_face_simple.map for a test case with a brush that straddles between void and non-void
|
// See missing_face_simple.map for a test case with a brush that straddles between void and non-void
|
||||||
|
|
||||||
MarkBrushSidesInvisible(entity);
|
MarkBrushSidesInvisible(entity, brushes);
|
||||||
|
|
||||||
MarkVisibleBrushSides_R(node);
|
MarkVisibleBrushSides_R(node);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// FIXME: move somewhere else
|
||||||
if (qbsp_options.outsidedebug.value() && (qbsp_options.target_game->get_hull_sizes().size() == 0 || hullnum == 0)) {
|
if (qbsp_options.outsidedebug.value() && (qbsp_options.target_game->get_hull_sizes().size() == 0 || hullnum == 0)) {
|
||||||
fs::path path = qbsp_options.bsp_path;
|
fs::path path = qbsp_options.bsp_path;
|
||||||
path.replace_extension(".outside.map");
|
path.replace_extension(".outside.map");
|
||||||
|
|
||||||
WriteBspBrushMap(path, map.entities[0].brushes);
|
WriteBspBrushMap(path, map.entities[0].brushes);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
logging::print(logging::flag::STAT, " {:8} outleafs\n", outleafs);
|
logging::print(logging::flag::STAT, " {:8} outleafs\n", outleafs);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum)
|
void FillBrushEntity(mapentity_t *entity, tree_t *tree, const int hullnum, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
// Clear the outside filling state on all nodes
|
// Clear the outside filling state on all nodes
|
||||||
ClearOccupied_r(tree->headnode.get());
|
ClearOccupied_r(tree->headnode.get());
|
||||||
|
|
||||||
MarkBrushSidesInvisible(entity);
|
MarkBrushSidesInvisible(entity, brushes);
|
||||||
|
|
||||||
MarkVisibleBrushSides_R(tree->headnode.get());
|
MarkVisibleBrushSides_R(tree->headnode.get());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -912,12 +912,12 @@ MarkVisibleSides
|
||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void MarkVisibleSides(tree_t *tree, mapentity_t *entity)
|
void MarkVisibleSides(tree_t *tree, mapentity_t *entity, bspbrush_vector_t &brushes)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
||||||
// clear all the visible flags
|
// clear all the visible flags
|
||||||
for (auto &brush : entity->brushes) {
|
for (auto &brush : brushes) {
|
||||||
for (auto &face : brush->sides) {
|
for (auto &face : brush->sides) {
|
||||||
face.visible = false;
|
face.visible = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
89
qbsp/qbsp.cc
89
qbsp/qbsp.cc
|
|
@ -300,19 +300,20 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
||||||
{
|
{
|
||||||
if (node->is_leaf) {
|
if (node->is_leaf) {
|
||||||
if (node->contents.native) {
|
if (node->contents.native) {
|
||||||
if (node->original_brushes.size()) {
|
if (node->original_mapbrushes.size()) {
|
||||||
node->numleafbrushes = node->original_brushes.size();
|
node->numleafbrushes = node->original_mapbrushes.size();
|
||||||
brush_state.total_leaf_brushes += node->numleafbrushes;
|
brush_state.total_leaf_brushes += node->numleafbrushes;
|
||||||
node->firstleafbrush = map.bsp.dleafbrushes.size();
|
node->firstleafbrush = map.bsp.dleafbrushes.size();
|
||||||
for (auto &b : node->original_brushes) {
|
for (auto &b : node->original_mapbrushes) {
|
||||||
|
|
||||||
if (!b->mapbrush->outputnumber.has_value()) {
|
if (!b->outputnumber.has_value()) {
|
||||||
const_cast<mapbrush_t *>(b->mapbrush)->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
// FIXME
|
||||||
|
const_cast<mapbrush_t *>(b)->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
||||||
|
|
||||||
dbrush_t &brush = map.bsp.dbrushes.emplace_back(
|
dbrush_t &brush = map.bsp.dbrushes.emplace_back(
|
||||||
dbrush_t{static_cast<int32_t>(map.bsp.dbrushsides.size()), 0, b->contents.native});
|
dbrush_t{static_cast<int32_t>(map.bsp.dbrushsides.size()), 0, b->contents.native});
|
||||||
|
|
||||||
for (auto &side : b->mapbrush->faces) {
|
for (auto &side : b->faces) {
|
||||||
map.bsp.dbrushsides.push_back(
|
map.bsp.dbrushsides.push_back(
|
||||||
{(uint32_t) ExportMapPlane(side.get_plane()), (int32_t)ExportMapTexinfo(side.texinfo)});
|
{(uint32_t) ExportMapPlane(side.get_plane()), (int32_t)ExportMapTexinfo(side.texinfo)});
|
||||||
brush.numsides++;
|
brush.numsides++;
|
||||||
|
|
@ -322,7 +323,7 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
||||||
brush_state.total_brushes++;
|
brush_state.total_brushes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.bsp.dleafbrushes.push_back(b->mapbrush->outputnumber.value());
|
map.bsp.dleafbrushes.push_back(b->outputnumber.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -436,20 +437,22 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
entity->epairs.set("_lmscale", std::to_string(qbsp_options.lmscale.value()));
|
entity->epairs.set("_lmscale", std::to_string(qbsp_options.lmscale.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Init the entity
|
||||||
* Init the entity
|
|
||||||
*/
|
|
||||||
entity->brushes.clear();
|
|
||||||
entity->bounds = {};
|
entity->bounds = {};
|
||||||
|
|
||||||
|
// reserve enough brushes; we would only make less,
|
||||||
|
// never more
|
||||||
|
bspbrush_vector_t brushes;
|
||||||
|
brushes.reserve(entity->mapbrushes.size());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the map brushes (planes) into BSP brushes (polygons)
|
* Convert the map brushes (planes) into BSP brushes (polygons)
|
||||||
*/
|
*/
|
||||||
Brush_LoadEntity(entity, hullnum);
|
Brush_LoadEntity(entity, hullnum, brushes);
|
||||||
|
|
||||||
// assign brush file order
|
// assign brush file order
|
||||||
for (size_t i = 0; i < entity->brushes.size(); ++i) {
|
for (size_t i = 0; i < brushes.size(); ++i) {
|
||||||
entity->brushes[i]->file_order = i;
|
brushes[i]->file_order = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// entity->brushes = ChopBrushes(entity->brushes);
|
// entity->brushes = ChopBrushes(entity->brushes);
|
||||||
|
|
@ -465,7 +468,6 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
|
|
||||||
// we're discarding the brush
|
// we're discarding the brush
|
||||||
if (discarded_trigger) {
|
if (discarded_trigger) {
|
||||||
entity->brushes.clear();
|
|
||||||
entity->epairs.set("mins", fmt::to_string(entity->bounds.mins()));
|
entity->epairs.set("mins", fmt::to_string(entity->bounds.mins()));
|
||||||
entity->epairs.set("maxs", fmt::to_string(entity->bounds.maxs()));
|
entity->epairs.set("maxs", fmt::to_string(entity->bounds.maxs()));
|
||||||
return;
|
return;
|
||||||
|
|
@ -473,17 +475,17 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
|
|
||||||
std::unique_ptr<tree_t> tree = nullptr;
|
std::unique_ptr<tree_t> tree = nullptr;
|
||||||
if (hullnum > 0) {
|
if (hullnum > 0) {
|
||||||
tree = BrushBSP(entity, true);
|
tree = BrushBSP(entity, brushes, true);
|
||||||
if (entity == map.world_entity() && !qbsp_options.nofill.value()) {
|
if (entity == map.world_entity() && !qbsp_options.nofill.value()) {
|
||||||
// assume non-world bmodels are simple
|
// assume non-world bmodels are simple
|
||||||
MakeTreePortals(tree.get());
|
MakeTreePortals(tree.get());
|
||||||
if (FillOutside(entity, tree.get(), hullnum)) {
|
if (FillOutside(entity, tree.get(), hullnum, brushes)) {
|
||||||
// make a really good tree
|
// make a really good tree
|
||||||
tree = BrushBSP(entity, false);
|
tree = BrushBSP(entity, brushes, false);
|
||||||
|
|
||||||
// fill again so PruneNodes works
|
// fill again so PruneNodes works
|
||||||
MakeTreePortals(tree.get());
|
MakeTreePortals(tree.get());
|
||||||
FillOutside(entity, tree.get(), hullnum);
|
FillOutside(entity, tree.get(), hullnum, brushes);
|
||||||
PruneNodes(tree->headnode.get());
|
PruneNodes(tree->headnode.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -492,9 +494,9 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
// fixme-brushbsp: return here?
|
// fixme-brushbsp: return here?
|
||||||
} else {
|
} else {
|
||||||
if (qbsp_options.forcegoodtree.value()) {
|
if (qbsp_options.forcegoodtree.value()) {
|
||||||
tree = BrushBSP(entity, false);
|
tree = BrushBSP(entity, brushes, false);
|
||||||
} else {
|
} else {
|
||||||
tree = BrushBSP(entity, entity == map.world_entity() ? std::nullopt : std::optional<bool>(false));
|
tree = BrushBSP(entity, brushes, entity == map.world_entity() ? std::nullopt : std::optional<bool>(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// build all the portals in the bsp tree
|
// build all the portals in the bsp tree
|
||||||
|
|
@ -506,15 +508,15 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
// marks brush sides which are *only* touching void;
|
// marks brush sides which are *only* touching void;
|
||||||
// we can skip using them as BSP splitters on the "really good tree"
|
// we can skip using them as BSP splitters on the "really good tree"
|
||||||
// (effectively expanding those brush sides outwards).
|
// (effectively expanding those brush sides outwards).
|
||||||
if (!qbsp_options.nofill.value() && FillOutside(entity, tree.get(), hullnum)) {
|
if (!qbsp_options.nofill.value() && FillOutside(entity, tree.get(), hullnum, brushes)) {
|
||||||
// make a really good tree
|
// make a really good tree
|
||||||
tree = BrushBSP(entity, false);
|
tree = BrushBSP(entity, brushes, false);
|
||||||
|
|
||||||
// make the real portals for vis tracing
|
// make the real portals for vis tracing
|
||||||
MakeTreePortals(tree.get());
|
MakeTreePortals(tree.get());
|
||||||
|
|
||||||
// fill again so PruneNodes works
|
// fill again so PruneNodes works
|
||||||
FillOutside(entity, tree.get(), hullnum);
|
FillOutside(entity, tree.get(), hullnum, brushes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Area portals
|
// Area portals
|
||||||
|
|
@ -523,15 +525,15 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
EmitAreaPortals(tree->headnode.get());
|
EmitAreaPortals(tree->headnode.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FillBrushEntity(entity, tree.get(), hullnum);
|
FillBrushEntity(entity, tree.get(), hullnum, brushes);
|
||||||
|
|
||||||
// rebuild BSP now that we've marked invisible brush sides
|
// rebuild BSP now that we've marked invisible brush sides
|
||||||
tree = BrushBSP(entity, false);
|
tree = BrushBSP(entity, brushes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeTreePortals(tree.get());
|
MakeTreePortals(tree.get());
|
||||||
|
|
||||||
MarkVisibleSides(tree.get(), entity);
|
MarkVisibleSides(tree.get(), entity, brushes);
|
||||||
MakeFaces(tree->headnode.get());
|
MakeFaces(tree->headnode.get());
|
||||||
|
|
||||||
FreeTreePortals(tree.get());
|
FreeTreePortals(tree.get());
|
||||||
|
|
@ -566,8 +568,6 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
|
||||||
|
|
||||||
ExportDrawNodes(entity, tree->headnode.get(), entity->firstoutputfacenumber);
|
ExportDrawNodes(entity, tree->headnode.get(), entity->firstoutputfacenumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeBrushes(entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -651,7 +651,7 @@ hull sizes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void BSPX_Brushes_AddModel(
|
static void BSPX_Brushes_AddModel(
|
||||||
struct bspxbrushes_s *ctx, int modelnum, std::vector<std::unique_ptr<bspbrush_t>> &brushes)
|
struct bspxbrushes_s *ctx, int modelnum, const std::list<mapbrush_t> &brushes)
|
||||||
{
|
{
|
||||||
std::shared_lock lock(map_planes_lock);
|
std::shared_lock lock(map_planes_lock);
|
||||||
|
|
||||||
|
|
@ -659,7 +659,7 @@ static void BSPX_Brushes_AddModel(
|
||||||
|
|
||||||
for (auto &b : brushes) {
|
for (auto &b : brushes) {
|
||||||
permodel.numbrushes++;
|
permodel.numbrushes++;
|
||||||
for (auto &f : b->sides) {
|
for (auto &f : b.faces) {
|
||||||
/*skip axial*/
|
/*skip axial*/
|
||||||
const auto &plane = f.get_plane();
|
const auto &plane = f.get_plane();
|
||||||
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
||||||
|
|
@ -677,7 +677,7 @@ static void BSPX_Brushes_AddModel(
|
||||||
for (auto &b : brushes) {
|
for (auto &b : brushes) {
|
||||||
bspxbrushes_perbrush perbrush{};
|
bspxbrushes_perbrush perbrush{};
|
||||||
|
|
||||||
for (auto &f : b->sides) {
|
for (auto &f : b.faces) {
|
||||||
/*skip axial*/
|
/*skip axial*/
|
||||||
const auto &plane = f.get_plane();
|
const auto &plane = f.get_plane();
|
||||||
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
||||||
|
|
@ -685,9 +685,11 @@ static void BSPX_Brushes_AddModel(
|
||||||
perbrush.numfaces++;
|
perbrush.numfaces++;
|
||||||
}
|
}
|
||||||
|
|
||||||
perbrush.bounds = b->bounds;
|
perbrush.bounds = b.bounds;
|
||||||
|
|
||||||
switch (b->contents.native) {
|
const auto &contents = b.contents;
|
||||||
|
|
||||||
|
switch (contents.native) {
|
||||||
// contents should match the engine.
|
// contents should match the engine.
|
||||||
case CONTENTS_EMPTY: // really an error, but whatever
|
case CONTENTS_EMPTY: // really an error, but whatever
|
||||||
case CONTENTS_SOLID: // these are okay
|
case CONTENTS_SOLID: // these are okay
|
||||||
|
|
@ -695,21 +697,21 @@ static void BSPX_Brushes_AddModel(
|
||||||
case CONTENTS_SLIME:
|
case CONTENTS_SLIME:
|
||||||
case CONTENTS_LAVA:
|
case CONTENTS_LAVA:
|
||||||
case CONTENTS_SKY:
|
case CONTENTS_SKY:
|
||||||
if (b->contents.is_clip(qbsp_options.target_game)) {
|
if (contents.is_clip(qbsp_options.target_game)) {
|
||||||
perbrush.contents = -8;
|
perbrush.contents = -8;
|
||||||
} else {
|
} else {
|
||||||
perbrush.contents = b->contents.native;
|
perbrush.contents = contents.native;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// case CONTENTS_LADDER:
|
// case CONTENTS_LADDER:
|
||||||
// perbrush.contents = -16;
|
// perbrush.contents = -16;
|
||||||
// break;
|
// break;
|
||||||
default: {
|
default: {
|
||||||
if (b->contents.is_clip(qbsp_options.target_game)) {
|
if (contents.is_clip(qbsp_options.target_game)) {
|
||||||
perbrush.contents = -8;
|
perbrush.contents = -8;
|
||||||
} else {
|
} else {
|
||||||
logging::print("WARNING: Unknown contents: {}. Translating to solid.\n",
|
logging::print("WARNING: Unknown contents: {}. Translating to solid.\n",
|
||||||
b->contents.to_string(qbsp_options.target_game));
|
contents.to_string(qbsp_options.target_game));
|
||||||
perbrush.contents = CONTENTS_SOLID;
|
perbrush.contents = CONTENTS_SOLID;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -718,7 +720,7 @@ static void BSPX_Brushes_AddModel(
|
||||||
|
|
||||||
str <= perbrush;
|
str <= perbrush;
|
||||||
|
|
||||||
for (auto &f : b->sides) {
|
for (auto &f : b.faces) {
|
||||||
/*skip axial*/
|
/*skip axial*/
|
||||||
const auto &plane = f.get_plane();
|
const auto &plane = f.get_plane();
|
||||||
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
||||||
|
|
@ -755,15 +757,10 @@ static void BSPX_CreateBrushList(void)
|
||||||
modelnum = std::stoi(mod.substr(1));
|
modelnum = std::stoi(mod.substr(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->brushes.clear();
|
if (ent->mapbrushes.empty())
|
||||||
|
|
||||||
Brush_LoadEntity(ent, HULL_COLLISION);
|
|
||||||
|
|
||||||
if (ent->brushes.empty())
|
|
||||||
continue; // non-bmodel entity
|
continue; // non-bmodel entity
|
||||||
|
|
||||||
BSPX_Brushes_AddModel(&ctx, modelnum, ent->brushes);
|
BSPX_Brushes_AddModel(&ctx, modelnum, ent->mapbrushes);
|
||||||
FreeBrushes(ent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BSPX_Brushes_Finalize(&ctx);
|
BSPX_Brushes_Finalize(&ctx);
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,10 @@ void FreeTreePortals(tree_t *tree)
|
||||||
static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
||||||
{
|
{
|
||||||
// merge the children's brush lists
|
// merge the children's brush lists
|
||||||
node->original_brushes = node->children[0]->original_brushes;
|
node->original_mapbrushes = node->children[0]->original_mapbrushes;
|
||||||
node->original_brushes.insert(node->children[1]->original_brushes.begin(), node->children[1]->original_brushes.end());
|
node->original_mapbrushes.insert(node->children[1]->original_mapbrushes.begin(), node->children[1]->original_mapbrushes.end());
|
||||||
|
|
||||||
|
node->original_brushes.clear();
|
||||||
|
|
||||||
node->is_leaf = true;
|
node->is_leaf = true;
|
||||||
|
|
||||||
|
|
@ -84,6 +86,7 @@ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
||||||
static void PruneNodes_R(node_t *node, std::atomic<int32_t> &count_pruned)
|
static void PruneNodes_R(node_t *node, std::atomic<int32_t> &count_pruned)
|
||||||
{
|
{
|
||||||
if (node->is_leaf) {
|
if (node->is_leaf) {
|
||||||
|
node->original_brushes.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +100,8 @@ static void PruneNodes_R(node_t *node, std::atomic<int32_t> &count_pruned)
|
||||||
// This discards any faces on-node. Should be safe (?)
|
// This discards any faces on-node. Should be safe (?)
|
||||||
ConvertNodeToLeaf(node, qbsp_options.target_game->create_solid_contents());
|
ConvertNodeToLeaf(node, qbsp_options.target_game->create_solid_contents());
|
||||||
++count_pruned;
|
++count_pruned;
|
||||||
|
} else {
|
||||||
|
node->original_brushes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// DarkPlaces has an assertion that fails if both children are
|
// DarkPlaces has an assertion that fails if both children are
|
||||||
|
|
|
||||||
|
|
@ -399,7 +399,6 @@ TEST_CASE("duplicatePlanes", "[qbsp]")
|
||||||
|
|
||||||
mapentity_t worldspawn = LoadMap(mapWithDuplicatePlanes);
|
mapentity_t worldspawn = LoadMap(mapWithDuplicatePlanes);
|
||||||
REQUIRE(1 == worldspawn.mapbrushes.size());
|
REQUIRE(1 == worldspawn.mapbrushes.size());
|
||||||
CHECK(0 == worldspawn.brushes.size());
|
|
||||||
CHECK(6 == worldspawn.mapbrushes.front().faces.size());
|
CHECK(6 == worldspawn.mapbrushes.front().faces.size());
|
||||||
|
|
||||||
bspbrush_t brush = LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
|
bspbrush_t brush = LoadBrush(&worldspawn, &worldspawn.mapbrushes.front(), {CONTENTS_SOLID}, 0);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue