Revert "Instead of calculating brush extents globally, do it per brush creation"
This reverts commit 069720078f.
This commit is contained in:
parent
069720078f
commit
d076920665
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
158
qbsp/map.cc
158
qbsp/map.cc
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
10
qbsp/qbsp.cc
10
qbsp/qbsp.cc
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue