qbsp: wip import MarkVisibleSides from qbsp3

This commit is contained in:
Eric Wasylishen 2022-06-19 13:42:13 -06:00
parent 59d6169b3d
commit 4f3ca8c252
6 changed files with 167 additions and 4 deletions

View File

@ -358,6 +358,28 @@ public:
}
}
contentflags_t visible_contents(const contentflags_t &a, const contentflags_t &b) const override
{
if (a.equals(this, b)) {
return create_empty_contents();
}
int32_t a_pri = contents_priority(a);
int32_t b_pri = contents_priority(b);
if (a_pri > b_pri) {
return a;
} else {
return b;
}
// fixme-brushbsp: support detail-illusionary intersecting liquids
}
bool contents_contains(const contentflags_t &a, const contentflags_t &b) const override
{
return a.equals(this, b);
}
std::string get_contents_display(const contentflags_t &contents) const override
{
std::string base;
@ -850,6 +872,9 @@ struct gamedef_q2_t : public gamedef_t
return true;
}
/**
* Returns the single content bit of the strongest visible content present
*/
constexpr int32_t visible_contents(const int32_t &contents) const
{
for (int32_t i = 1; i <= Q2_LAST_VISIBLE_CONTENTS; i <<= 1) {
@ -907,6 +932,18 @@ struct gamedef_q2_t : public gamedef_t
return {a.native | b.native};
}
contentflags_t visible_contents(const contentflags_t &a, const contentflags_t &b) const override
{
int viscontents = visible_contents(a.native ^ b.native);
return {viscontents};
}
bool contents_contains(const contentflags_t &a, const contentflags_t &b) const override
{
return (a.native & b.native) != 0;
}
std::string get_contents_display(const contentflags_t &contents) const override
{
if (!contents.native) {

View File

@ -292,6 +292,8 @@ struct gamedef_t
virtual bool contents_seals_map(const contentflags_t &contents) const = 0;
virtual contentflags_t contents_remap_for_export(const contentflags_t &contents) const = 0;
virtual contentflags_t combine_contents(const contentflags_t &a, const contentflags_t &b) const = 0;
virtual contentflags_t visible_contents(const contentflags_t &a, const contentflags_t &b) const = 0;
virtual bool contents_contains(const contentflags_t &a, const contentflags_t &b) const = 0;
virtual std::string get_contents_display(const contentflags_t &contents) const = 0;
virtual void contents_make_valid(contentflags_t &contents) const = 0;
virtual const std::initializer_list<aabb3d> &get_hull_sizes() const = 0;

View File

@ -34,6 +34,7 @@ struct portal_t
portal_t *next[2]; // [0] = next portal in nodes[0]'s list of portals
std::optional<winding_t> winding;
bool sidefound; // false if ->side hasn't been checked
face_t *side; // NULL = non-visible // fixme-brushbsp: change to side_t
face_t *face[2]; // output face in bsp file
};
@ -56,3 +57,4 @@ void MakeTreePortals(tree_t *tree);
void FreeTreePortals_r(node_t *node);
void AssertNoPortals(node_t *node);
void MakeHeadnodePortals(tree_t *tree);
void MarkVisibleSides(tree_t *tree, mapentity_t* entity);

View File

@ -426,3 +426,119 @@ void FreeTreePortals_r(node_t *node)
}
node->portals = nullptr;
}
//==============================================================
/*
============
FindPortalSide
Finds a brush side to use for texturing the given portal
============
*/
static void FindPortalSide(portal_t *p)
{
// decide which content change is strongest
// solid > lava > water, etc
contentflags_t viscontents = options.target_game->visible_contents(p->nodes[0]->contents, p->nodes[1]->contents);
if (viscontents.is_empty(options.target_game))
return;
int planenum = p->onnode->planenum;
face_t *bestside = nullptr;
float bestdot = 0;
for (int j = 0; j < 2; j++)
{
node_t *n = p->nodes[j];
auto p1 = map.planes.at(p->onnode->planenum);
for (brush_t *brush : n->original_brushes)
{
if (!options.target_game->contents_contains(brush->contents, viscontents))
continue;
for (face_t &side : brush->faces)
{
// fixme-brushbsp: port these
// if (side.bevel)
// continue;
// if (side.texinfo == TEXINFO_NODE)
// continue; // non-visible
if (side.planenum == planenum)
{ // exact match
bestside = &side;
goto gotit;
}
// see how close the match is
auto p2 = map.planes.at(side.planenum);
float dot = qv::dot(p1.normal, p2.normal);
if (dot > bestdot)
{
bestdot = dot;
bestside = &side;
}
}
}
}
gotit:
if (!bestside)
logging::print("WARNING: side not found for portal\n");
p->sidefound = true;
p->side = bestside;
}
/*
===============
MarkVisibleSides_r
===============
*/
static void MarkVisibleSides_r(node_t *node)
{
if (node->planenum != PLANENUM_LEAF)
{
MarkVisibleSides_r(node->children[0]);
MarkVisibleSides_r(node->children[1]);
return;
}
// empty leafs are never boundary leafs
if (node->contents.is_empty(options.target_game))
return;
// see if there is a visible face
int s;
for (portal_t *p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (!p->onnode)
continue; // edge of world
if (!p->sidefound)
FindPortalSide(p);
if (p->side)
p->side->visible = true;
}
}
/*
=============
MarkVisibleSides
=============
*/
void MarkVisibleSides(tree_t *tree, mapentity_t* entity)
{
logging::print("--- {} ---\n", __func__);
// clear all the visible flags
for (auto &brush : entity->brushes) {
for (auto &face : brush->faces) {
face.visible = false;
}
}
// set visible flags on the sides that are used by portals
MarkVisibleSides_r (tree->headnode);
}

View File

@ -902,7 +902,8 @@ static void ProcessEntity(mapentity_t *entity, const int hullnum)
MakeTreePortals(tree);
MakeVisibleFaces(entity, tree->headnode);
MarkVisibleSides(tree, entity);
MakeFaces(tree->headnode);
if (hullnum <= 0 && entity == map.world_entity() && !map.leakfile) {
WritePortalFile(tree);

View File

@ -750,10 +750,12 @@ static face_t *FaceFromPortal(portal_t *p, int pside)
f->planenum = side->planenum;
f->planeside = static_cast<side_t>(pside);
f->portal = p;
f->lmshift = side->lmshift;
// don't show insides of windows
if (!side->contents[1].is_mirrored(options.target_game))
return nullptr;
// fixme-brushbsp: restore this?
// if (!side->contents[1].is_mirrored(options.target_game))
// return nullptr;
if (pside)
{
@ -766,6 +768,9 @@ static face_t *FaceFromPortal(portal_t *p, int pside)
f->w = *p->winding;
f->contents[1] = p->nodes[0]->contents;
}
UpdateFaceSphere(f);
return f;
}
@ -812,7 +817,7 @@ static void MakeFaces_r(node_t *node, makefaces_stats_t& stats)
face_t *f = FaceFromPortal(p, s);
if (f)
{
c_nodefaces++;
stats.c_nodefaces++;
p->face[s] = f;
p->onnode->facelist.push_back(f);
}