Revert "Instead of calculating brush extents globally, do it per brush creation"

This reverts commit 069720078f.
This commit is contained in:
Jonathan 2022-01-27 01:52:08 -05:00
parent 069720078f
commit d076920665
11 changed files with 117 additions and 103 deletions

View File

@ -97,7 +97,6 @@ struct gamedef_q1_like_t : public gamedef_t
gamedef_q1_like_t(const char *base_dir = "ID1") : gamedef_t(base_dir) gamedef_q1_like_t(const char *base_dir = "ID1") : gamedef_t(base_dir)
{ {
this->id = ID; this->id = ID;
hull_extents = 64;
} }
bool surf_is_lightmapped(const surfflags_t &flags) const { return !(flags.native & TEX_SPECIAL); } bool surf_is_lightmapped(const surfflags_t &flags) const { return !(flags.native & TEX_SPECIAL); }
@ -348,7 +347,7 @@ struct gamedef_q1_like_t : public gamedef_t
struct gamedef_h2_t : public gamedef_q1_like_t<GAME_HEXEN_II> struct gamedef_h2_t : public gamedef_q1_like_t<GAME_HEXEN_II>
{ {
gamedef_h2_t() : gamedef_q1_like_t("DATA1") { hull_extents = 40; } gamedef_h2_t() : gamedef_q1_like_t("DATA1") { }
const std::initializer_list<aabb3d> &get_hull_sizes() const const std::initializer_list<aabb3d> &get_hull_sizes() const
{ {
@ -403,7 +402,7 @@ struct gamedef_h2_t : public gamedef_q1_like_t<GAME_HEXEN_II>
struct gamedef_hl_t : public gamedef_q1_like_t<GAME_HALF_LIFE> struct gamedef_hl_t : public gamedef_q1_like_t<GAME_HALF_LIFE>
{ {
gamedef_hl_t() : gamedef_q1_like_t("VALVE") { has_rgb_lightmap = true; hull_extents = 36; } gamedef_hl_t() : gamedef_q1_like_t("VALVE") { has_rgb_lightmap = true; }
const std::initializer_list<aabb3d> &get_hull_sizes() const const std::initializer_list<aabb3d> &get_hull_sizes() const
{ {

View File

@ -29,7 +29,6 @@ class aabb
{ {
public: public:
using value_type = qvec<V, N>; using value_type = qvec<V, N>;
using value_value_type = typename value_type::value_type;
class intersection_t class intersection_t
{ {
@ -184,20 +183,6 @@ public:
constexpr value_type centroid() const { return (m_mins + m_maxs) * 0.5; } constexpr value_type centroid() const { return (m_mins + m_maxs) * 0.5; }
constexpr value_value_type extents() const
{
value_value_type extent = -std::numeric_limits<value_value_type>::infinity();
for (auto &v : m_mins) {
extent = max(extent, v);
}
for (auto &v : m_maxs) {
extent = max(extent, v);
}
return extent;
}
// stream support // stream support
auto stream_data() { return std::tie(m_mins, m_maxs); } auto stream_data() { return std::tie(m_mins, m_maxs); }
}; };

View File

@ -1766,12 +1766,7 @@ struct gamedef_t
size_t max_entity_key = 32; size_t max_entity_key = 32;
size_t max_entity_value = 128; size_t max_entity_value = 128;
// maximum extent of hulls; used for world extent calculations gamedef_t(const char *default_base_dir) : default_base_dir(default_base_dir) { }
vec_t hull_extents = 0;
gamedef_t(const char *default_base_dir) : default_base_dir(default_base_dir)
{
}
virtual bool surf_is_lightmapped(const surfflags_t &flags) const = 0; virtual bool surf_is_lightmapped(const surfflags_t &flags) const = 0;
virtual bool surf_is_subdivided(const surfflags_t &flags) const = 0; virtual bool surf_is_subdivided(const surfflags_t &flags) const = 0;

View File

@ -24,17 +24,16 @@
#include <qbsp/winding.hh> #include <qbsp/winding.hh>
#include <common/aabb.hh> #include <common/aabb.hh>
class mapbrush_t;
struct brush_t struct brush_t
{ {
const mapbrush_t *src;
aabb3d bounds; aabb3d bounds;
std::vector<face_t> faces; std::vector<face_t> faces;
contentflags_t contents; /* BSP contents */ contentflags_t contents; /* BSP contents */
short lmshift; /* lightmap scaling (qu/lightmap pixel), passed to the light util */ short lmshift; /* lightmap scaling (qu/lightmap pixel), passed to the light util */
}; };
class mapbrush_t;
qplane3d Face_Plane(const face_t *face); qplane3d Face_Plane(const face_t *face);
enum class rotation_t enum class rotation_t

View File

@ -71,7 +71,6 @@ public:
int numfaces = 0; int numfaces = 0;
brushformat_t format = brushformat_t::NORMAL; brushformat_t format = brushformat_t::NORMAL;
int contents = 0; int contents = 0;
vec_t extents = 0;
const mapface_t &face(int i) const; const mapface_t &face(int i) const;
}; };
@ -159,6 +158,8 @@ struct mapdata_t
extern mapdata_t map; extern mapdata_t map;
void CalculateWorldExtent(void);
extern mapentity_t *pWorldEnt(); extern mapentity_t *pWorldEnt();
bool ParseEntity(parser_t &parser, mapentity_t *entity); bool ParseEntity(parser_t &parser, mapentity_t *entity);

View File

@ -24,3 +24,5 @@
#include "common/polylib.hh" #include "common/polylib.hh"
using winding_t = polylib::winding_base_t<MAXEDGES>; using winding_t = polylib::winding_base_t<MAXEDGES>;
winding_t BaseWindingForPlane(const qplane3d &p);

View File

@ -91,6 +91,10 @@ static void CheckFace(face_t *face, const mapface_t &sourceface)
const qvec3d &p1 = face->w[i]; const qvec3d &p1 = face->w[i];
const qvec3d &p2 = face->w[(i + 1) % face->w.size()]; const qvec3d &p2 = face->w[(i + 1) % face->w.size()];
for (auto &v : p1)
if (v > options.worldExtent || v < -options.worldExtent)
FError("line {}: coordinate out of range ({})", sourceface.linenum, v);
/* check the point is on the face plane */ /* check the point is on the face plane */
vec_t dist = plane.distance_to(p1); vec_t dist = plane.distance_to(p1);
if (dist < -ON_EPSILON || dist > ON_EPSILON) if (dist < -ON_EPSILON || dist > ON_EPSILON)
@ -305,7 +309,7 @@ static std::vector<face_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
continue; continue;
} }
w = winding_t::from_plane(mapface.plane, hullbrush->srcbrush->extents); w = BaseWindingForPlane(mapface.plane);
for (auto &mapface2 : hullbrush->faces) { for (auto &mapface2 : hullbrush->faces) {
if (&mapface == &mapface2) if (&mapface == &mapface2)
@ -702,8 +706,6 @@ std::optional<brush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbr
const qvec3d &rotate_offset, const rotation_t rottype, const int hullnum) const qvec3d &rotate_offset, const rotation_t rottype, const int hullnum)
{ {
hullbrush_t hullbrush; hullbrush_t hullbrush;
hullbrush.srcbrush = mapbrush;
std::vector<face_t> facelist; std::vector<face_t> facelist;
// create the faces // create the faces

View File

@ -40,67 +40,6 @@
#include <common/qvec.hh> #include <common/qvec.hh>
/*
=================
GetBrushExtents
=================
*/
inline std::optional<qvec3d> GetIntersection(const qbsp_plane_t &p1, const qbsp_plane_t &p2, const qbsp_plane_t &p3)
{
const vec_t denom = qv::dot(p1.normal, qv::cross(p2.normal, p3.normal));
if (denom == 0.f) {
return std::nullopt;
}
return (qv::cross(p2.normal, p3.normal) * p1.dist - qv::cross(p3.normal, p1.normal) * -p2.dist - qv::cross(p1.normal, p2.normal) * -p3.dist) / denom;
}
#include "tbb/parallel_for.h"
#include <mutex>
inline vec_t CalculateBrushExtents(const mapbrush_t &hullbrush)
{
vec_t extents = -std::numeric_limits<vec_t>::infinity();
for (int32_t i = 0; i < hullbrush.numfaces - 2; i++) {
for (int32_t j = i; j < hullbrush.numfaces - 1; j++) {
for (int32_t k = j; k < hullbrush.numfaces; k++) {
if (i == j || j == k || k == i) {
continue;
}
auto &fi = hullbrush.face(i);
auto &fj = hullbrush.face(j);
auto &fk = hullbrush.face(k);
bool legal = true;
auto vertex = GetIntersection(fi.plane, fj.plane, fk.plane);
if (!vertex) {
continue;
}
for (int32_t m = 0; m < hullbrush.numfaces; m++) {
if (hullbrush.face(m).plane.distance_to(*vertex) > NORMAL_EPSILON) {
legal = false;
break;
}
}
if (legal) {
for (auto &p : *vertex) {
extents = max(extents, fabs(p));
}
}
}
}
}
return extents + options.target_game->hull_extents;
}
#define info_player_start 1 #define info_player_start 1
#define info_player_deathmatch 2 #define info_player_deathmatch 2
#define info_player_coop 4 #define info_player_coop 4
@ -1634,13 +1573,6 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
} }
// ericw -- end brush primitives // ericw -- end brush primitives
// calculate extents, if required
if (!options.worldExtent) {
brush.extents = CalculateBrushExtents(brush);
} else {
brush.extents = options.worldExtent;
}
return brush; return brush;
} }
@ -2229,6 +2161,94 @@ void WriteEntitiesToString()
} }
} }
//====================================================================
inline std::optional<qvec3d> GetIntersection(const qbsp_plane_t &p1, const qbsp_plane_t &p2, const qbsp_plane_t &p3)
{
const vec_t denom = qv::dot(p1.normal, qv::cross(p2.normal, p3.normal));
if (denom == 0.f) {
return std::nullopt;
}
return (qv::cross(p2.normal, p3.normal) * p1.dist - qv::cross(p3.normal, p1.normal) * -p2.dist - qv::cross(p1.normal, p2.normal) * -p3.dist) / denom;
}
/*
=================
GetBrushExtents
=================
*/
inline vec_t GetBrushExtents(const mapbrush_t &hullbrush)
{
vec_t extents = -std::numeric_limits<vec_t>::infinity();
for (int32_t i = 0; i < hullbrush.numfaces - 2; i++) {
for (int32_t j = i; j < hullbrush.numfaces - 1; j++) {
for (int32_t k = j; k < hullbrush.numfaces; k++) {
if (i == j || j == k || k == i) {
continue;
}
auto &fi = hullbrush.face(i);
auto &fj = hullbrush.face(j);
auto &fk = hullbrush.face(k);
bool legal = true;
auto vertex = GetIntersection(fi.plane, fj.plane, fk.plane);
if (!vertex) {
continue;
}
for (int32_t m = 0; m < hullbrush.numfaces; m++) {
if (hullbrush.face(m).plane.distance_to(*vertex) > NORMAL_EPSILON) {
legal = false;
break;
}
}
if (legal) {
for (auto &p : *vertex) {
extents = max(extents, fabs(p));
}
}
}
}
}
return extents;
}
#include "tbb/parallel_for.h"
#include <mutex>
void CalculateWorldExtent(void)
{
LogPrint("Calculating world extents... ");
std::atomic<vec_t> extents = -std::numeric_limits<vec_t>::infinity();
tbb::parallel_for(static_cast<size_t>(0), static_cast<size_t>(map.numbrushes()), [&](const size_t &i) {
const auto &brush = map.brushes[i];
const vec_t brushExtents = max(extents.load(), GetBrushExtents(brush));
vec_t currentExtents = extents;
while (currentExtents < brushExtents && !extents.compare_exchange_weak(currentExtents, brushExtents));
});
vec_t hull_extents = 0;
for (auto &hull : options.target_game->get_hull_sizes()) {
for (auto &v : hull.size()) {
hull_extents = max(hull_extents, fabs(v));
}
}
options.worldExtent = extents + hull_extents;
LogPrint("{} units\n", options.worldExtent);
}
/* /*
================== ==================
WriteBspBrushMap WriteBspBrushMap
@ -2256,7 +2276,7 @@ void WriteBspBrushMap(const std::filesystem::path &name, const std::vector<brush
plane = -plane; plane = -plane;
} }
winding_t w = winding_t::from_plane(plane, brush.src->extents); winding_t w = BaseWindingForPlane(plane);
fmt::print(f, "( {} ) ", w[0]); fmt::print(f, "( {} ) ", w[0]);
fmt::print(f, "( {} ) ", w[1]); fmt::print(f, "( {} ) ", w[1]);

View File

@ -364,7 +364,6 @@ static void MakeHeadnodePortals(const mapentity_t *entity, node_t *node)
// pad with some space so there will never be null volume leafs // pad with some space so there will never be null volume leafs
aabb3d bounds = entity->bounds.grow(SIDESPACE); aabb3d bounds = entity->bounds.grow(SIDESPACE);
vec_t extents = bounds.extents() + options.target_game->hull_extents;
outside_node.planenum = PLANENUM_LEAF; outside_node.planenum = PLANENUM_LEAF;
outside_node.contents = options.target_game->create_solid_contents(); outside_node.contents = options.target_game->create_solid_contents();
@ -390,7 +389,7 @@ static void MakeHeadnodePortals(const mapentity_t *entity, node_t *node)
} }
p->planenum = FindPlane(pl, &side); p->planenum = FindPlane(pl, &side);
p->winding = winding_t::from_plane(pl, extents); p->winding = BaseWindingForPlane(pl);
if (side) if (side)
AddPortalToNodes(p, &outside_node, node); AddPortalToNodes(p, &outside_node, node);
else else
@ -528,7 +527,7 @@ static void CutNodePortals_r(node_t *node, portal_state_t *state)
new_portal = new portal_t{}; new_portal = new portal_t{};
new_portal->planenum = node->planenum; new_portal->planenum = node->planenum;
std::optional<winding_t> winding = winding_t::from_plane(plane, node->bounds.extents() + options.target_game->hull_extents); std::optional<winding_t> winding = BaseWindingForPlane(plane);
for (portal = node->portals; portal; portal = portal->next[side]) { for (portal = node->portals; portal; portal = portal->next[side]) {
clipplane = map.planes[portal->planenum]; clipplane = map.planes[portal->planenum];
if (portal->nodes[0] == node) if (portal->nodes[0] == node)

View File

@ -472,6 +472,11 @@ static void EmitAreaPortals(node_t *headnode)
LogPrint(LOG_STAT, "{:5} numareaportals\n", map.bsp.dareaportals.size()); LogPrint(LOG_STAT, "{:5} numareaportals\n", map.bsp.dareaportals.size());
} }
winding_t BaseWindingForPlane(const qplane3d &p)
{
return winding_t::from_plane(p, options.worldExtent);
}
/* /*
=============== ===============
ProcessEntity ProcessEntity
@ -985,6 +990,11 @@ static void ProcessFile(void)
log_mask &= ~((1 << LOG_STAT) | (1 << LOG_PROGRESS)); log_mask &= ~((1 << LOG_STAT) | (1 << LOG_PROGRESS));
} }
// calculate extents, if required
if (!options.worldExtent) {
CalculateWorldExtent();
}
// create hulls! // create hulls!
CreateHulls(); CreateHulls();

View File

@ -29,6 +29,8 @@ static mapentity_t LoadMap(const char *map)
// FIXME: adds the brush to the global map... // FIXME: adds the brush to the global map...
Q_assert(ParseEntity(parser, &worldspawn)); Q_assert(ParseEntity(parser, &worldspawn));
CalculateWorldExtent();
return worldspawn; return worldspawn;
} }