remove hullbrush_t; just directly work via the bspbrush_t since we have the bevels pre-calculated in mapbrush_t
track the mapbrush we were created from in bspbrush_t; we use this later for outputting the collision brush for q2bsp. bevels are busted though..
This commit is contained in:
parent
24168c8e40
commit
58d1e5230e
|
|
@ -62,13 +62,13 @@ struct bspbrush_t
|
||||||
* fixme-brushbsp: this is supposed to be a mapbrush_t
|
* fixme-brushbsp: this is supposed to be a mapbrush_t
|
||||||
*/
|
*/
|
||||||
bspbrush_t *original;
|
bspbrush_t *original;
|
||||||
|
const mapbrush_t *mapbrush;
|
||||||
uint32_t file_order;
|
uint32_t file_order;
|
||||||
aabb3d bounds;
|
aabb3d bounds;
|
||||||
int side, testside; // side of node during construction
|
int side, testside; // side of node during construction
|
||||||
std::vector<side_t> sides;
|
std::vector<side_t> sides;
|
||||||
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 */
|
||||||
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
|
||||||
mapentity_t *func_areaportal;
|
mapentity_t *func_areaportal;
|
||||||
|
|
||||||
qvec3d sphere_origin;
|
qvec3d sphere_origin;
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ public:
|
||||||
brushformat_t format = brushformat_t::NORMAL;
|
brushformat_t format = brushformat_t::NORMAL;
|
||||||
int contents = 0;
|
int contents = 0;
|
||||||
aabb3d bounds {};
|
aabb3d bounds {};
|
||||||
|
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lumpdata
|
struct lumpdata
|
||||||
|
|
@ -90,6 +91,15 @@ struct lumpdata
|
||||||
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{};
|
||||||
|
|
||||||
std::list<mapbrush_t> mapbrushes;
|
std::list<mapbrush_t> mapbrushes;
|
||||||
|
|
@ -333,6 +343,7 @@ bool IsWorldBrushEntity(const mapentity_t *entity);
|
||||||
bool IsNonRemoveWorldBrushEntity(const mapentity_t *entity);
|
bool IsNonRemoveWorldBrushEntity(const mapentity_t *entity);
|
||||||
void LoadMapFile(void);
|
void LoadMapFile(void);
|
||||||
void ConvertMapFile(void);
|
void ConvertMapFile(void);
|
||||||
|
void ProcessMapBrushes();
|
||||||
|
|
||||||
struct quark_tx_info_t
|
struct quark_tx_info_t
|
||||||
{
|
{
|
||||||
|
|
|
||||||
341
qbsp/brush.cc
341
qbsp/brush.cc
|
|
@ -53,27 +53,6 @@ std::unique_ptr<bspbrush_t> bspbrush_t::copy_unique() const
|
||||||
return std::make_unique<bspbrush_t>(*this);
|
return std::make_unique<bspbrush_t>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Beveled clipping hull can generate many extra faces
|
|
||||||
*/
|
|
||||||
constexpr size_t MAX_FACES = 128;
|
|
||||||
constexpr size_t MAX_HULL_POINTS = 512;
|
|
||||||
constexpr size_t MAX_HULL_EDGES = 1024;
|
|
||||||
|
|
||||||
struct hullbrush_t
|
|
||||||
{
|
|
||||||
const mapbrush_t *srcbrush;
|
|
||||||
contentflags_t contents;
|
|
||||||
aabb3d bounds;
|
|
||||||
|
|
||||||
std::vector<mapface_t> faces;
|
|
||||||
std::vector<qvec3d> points;
|
|
||||||
std::vector<qvec3d> corners;
|
|
||||||
std::vector<std::tuple<int, int>> edges;
|
|
||||||
|
|
||||||
int linenum;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Face_Plane
|
Face_Plane
|
||||||
|
|
@ -105,7 +84,7 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
||||||
} else if (face->w.size() == 1) {
|
} else if (face->w.size() == 1) {
|
||||||
logging::print("WARNING: line {}: too few points (1): ({})\n", sourceface.linenum, face->w[0]);
|
logging::print("WARNING: line {}: too few points (1): ({})\n", sourceface.linenum, face->w[0]);
|
||||||
} else {
|
} else {
|
||||||
logging::print("WARNING: line {}: too few points ({})", sourceface.linenum, face->w.size());
|
logging::print("WARNING: line {}: too few points ({})\n", sourceface.linenum, face->w.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
face->w.clear();
|
face->w.clear();
|
||||||
|
|
@ -122,7 +101,7 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
||||||
for (auto &v : p1) {
|
for (auto &v : p1) {
|
||||||
if (fabs(v) > qbsp_options.worldextent.value()) {
|
if (fabs(v) > qbsp_options.worldextent.value()) {
|
||||||
// this is fatal because a point should never lay outside the world
|
// this is fatal because a point should never lay outside the world
|
||||||
FError("line {}: coordinate out of range ({})", sourceface.linenum, v);
|
FError("line {}: coordinate out of range ({})\n", sourceface.linenum, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,15 +197,6 @@ qvec3d FixRotateOrigin(mapentity_t *entity)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Brush_IsHint(const hullbrush_t &brush)
|
|
||||||
{
|
|
||||||
for (auto &f : brush.faces)
|
|
||||||
if (f.flags.is_hint)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MapBrush_IsHint(const mapbrush_t &brush)
|
static bool MapBrush_IsHint(const mapbrush_t &brush)
|
||||||
{
|
{
|
||||||
for (auto &f : brush.faces) {
|
for (auto &f : brush.faces) {
|
||||||
|
|
@ -237,84 +207,6 @@ static bool MapBrush_IsHint(const mapbrush_t &brush)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
CreateBrushFaces
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, const int hullnum)
|
|
||||||
{
|
|
||||||
vec_t r;
|
|
||||||
std::optional<winding_t> w;
|
|
||||||
qplane3d plane;
|
|
||||||
std::vector<side_t> facelist;
|
|
||||||
qvec3d point;
|
|
||||||
vec_t max, min;
|
|
||||||
|
|
||||||
min = VECT_MAX;
|
|
||||||
max = -VECT_MAX;
|
|
||||||
|
|
||||||
hullbrush->bounds = {};
|
|
||||||
|
|
||||||
for (auto &mapface : hullbrush->faces) {
|
|
||||||
if (hullnum <= 0 && Brush_IsHint(*hullbrush)) {
|
|
||||||
/* Don't generate hintskip faces */
|
|
||||||
const maptexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
|
||||||
|
|
||||||
if (qbsp_options.target_game->texinfo_is_hintskip(texinfo.flags, map.miptexTextureName(texinfo.miptex)))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
w = BaseWindingForPlane(mapface.get_plane());
|
|
||||||
|
|
||||||
for (auto &mapface2 : hullbrush->faces) {
|
|
||||||
if (&mapface == &mapface2)
|
|
||||||
continue;
|
|
||||||
if (!w)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// flip the plane, because we want to keep the back side
|
|
||||||
plane = -mapface2.get_plane();
|
|
||||||
|
|
||||||
w = w->clip(plane, qbsp_options.epsilon.value(), false)[SIDE_FRONT];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!w) {
|
|
||||||
continue; // overconstrained plane
|
|
||||||
}
|
|
||||||
|
|
||||||
// this face is a keeper
|
|
||||||
side_t &f = facelist.emplace_back();
|
|
||||||
|
|
||||||
f.w.resize(w->size());
|
|
||||||
|
|
||||||
for (size_t j = 0; j < w->size(); j++) {
|
|
||||||
for (size_t k = 0; k < 3; k++) {
|
|
||||||
point[k] = w->at(j)[k];
|
|
||||||
r = Q_rint(point[k]);
|
|
||||||
if (fabs(point[k] - r) < ZERO_EPSILON)
|
|
||||||
f.w[j][k] = r;
|
|
||||||
else
|
|
||||||
f.w[j][k] = point[k];
|
|
||||||
|
|
||||||
if (f.w[j][k] < min)
|
|
||||||
min = f.w[j][k];
|
|
||||||
if (f.w[j][k] > max)
|
|
||||||
max = f.w[j][k];
|
|
||||||
}
|
|
||||||
|
|
||||||
hullbrush->bounds += f.w[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
f.texinfo = hullnum > 0 ? 0 : mapface.texinfo;
|
|
||||||
f.planenum = mapface.planenum;
|
|
||||||
|
|
||||||
CheckFace(&f, mapface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return facelist;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=====================
|
=====================
|
||||||
FreeBrushes
|
FreeBrushes
|
||||||
|
|
@ -325,189 +217,28 @@ void FreeBrushes(mapentity_t *ent)
|
||||||
ent->brushes.clear();
|
ent->brushes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#if 0
|
||||||
==============================================================================
|
if (hullnum <= 0 && Brush_IsHint(*hullbrush)) {
|
||||||
|
/* Don't generate hintskip faces */
|
||||||
|
const maptexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo);
|
||||||
|
|
||||||
BEVELED CLIPPING HULL GENERATION
|
if (qbsp_options.target_game->texinfo_is_hintskip(texinfo.flags, map.miptexTextureName(texinfo.miptex)))
|
||||||
|
continue;
|
||||||
This is done by brute force, and could easily get a lot faster if anyone cares.
|
|
||||||
==============================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
AddBrushPlane
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static void AddBrushPlane(hullbrush_t *hullbrush, const qbsp_plane_t &plane)
|
|
||||||
{
|
|
||||||
vec_t len = qv::length(plane.get_normal());
|
|
||||||
|
|
||||||
if (len < 1.0 - NORMAL_EPSILON || len > 1.0 + NORMAL_EPSILON)
|
|
||||||
FError("invalid normal (vector length {:.4})", len);
|
|
||||||
|
|
||||||
for (auto &mapface : hullbrush->faces) {
|
|
||||||
if (qv::epsilonEqual(mapface.get_plane(), plane, EQUAL_EPSILON, qbsp_options.epsilon.value())) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
|
||||||
if (hullbrush->faces.size() == MAX_FACES) {
|
|
||||||
FError(
|
|
||||||
"brush->faces >= MAX_FACES ({}), source brush on line {}", MAX_FACES, hullbrush->srcbrush->faces[0].linenum);
|
|
||||||
}
|
|
||||||
|
|
||||||
mapface_t &mapface = hullbrush->faces.emplace_back();
|
|
||||||
mapface.planenum = map.add_or_find_plane(plane);
|
|
||||||
mapface.texinfo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
TestAddPlane
|
|
||||||
|
|
||||||
Adds the given plane to the brush description if all of the original brush
|
|
||||||
vertexes can be put on the front side
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static void TestAddPlane(hullbrush_t *hullbrush, qbsp_plane_t &plane)
|
|
||||||
{
|
|
||||||
vec_t d;
|
|
||||||
int points_front, points_back;
|
|
||||||
|
|
||||||
/* see if the plane has already been added */
|
|
||||||
for (auto &mapface : hullbrush->faces) {
|
|
||||||
if (qv::epsilonEqual(plane, mapface.get_plane()))
|
|
||||||
return;
|
|
||||||
if (qv::epsilonEqual(-plane, mapface.get_plane()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check all the corner points */
|
|
||||||
points_front = 0;
|
|
||||||
points_back = 0;
|
|
||||||
|
|
||||||
for (auto &corner : hullbrush->corners) {
|
|
||||||
d = plane.distance_to(corner);
|
|
||||||
if (d < -qbsp_options.epsilon.value()) {
|
|
||||||
if (points_front)
|
|
||||||
return;
|
|
||||||
points_back = 1;
|
|
||||||
} else if (d > qbsp_options.epsilon.value()) {
|
|
||||||
if (points_back)
|
|
||||||
return;
|
|
||||||
points_front = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the plane is a seperator
|
|
||||||
if (points_front) {
|
|
||||||
plane = -plane;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddBrushPlane(hullbrush, plane);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
AddHullPoint
|
|
||||||
|
|
||||||
Doesn't add if duplicated
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static int AddHullPoint(hullbrush_t *hullbrush, const qvec3d &p, const aabb3d &hull_size)
|
|
||||||
{
|
|
||||||
for (auto &pt : hullbrush->points)
|
|
||||||
if (qv::epsilonEqual(p, pt, EQUAL_EPSILON))
|
|
||||||
return &pt - hullbrush->points.data();
|
|
||||||
|
|
||||||
if (hullbrush->points.size() == MAX_HULL_POINTS)
|
|
||||||
FError("hullbrush->numpoints == MAX_HULL_POINTS ({}), "
|
|
||||||
"source brush on line {}",
|
|
||||||
MAX_HULL_POINTS, hullbrush->srcbrush->faces[0].linenum);
|
|
||||||
|
|
||||||
int i = hullbrush->points.size();
|
|
||||||
hullbrush->points.emplace_back(p);
|
|
||||||
|
|
||||||
for (size_t x = 0; x < 2; x++)
|
|
||||||
for (size_t y = 0; y < 2; y++)
|
|
||||||
for (size_t z = 0; z < 2; z++) {
|
|
||||||
hullbrush->corners.emplace_back(p[0] + hull_size[x][0], p[1] + hull_size[y][1], p[2] + hull_size[z][2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
AddHullEdge
|
|
||||||
|
|
||||||
Creates all of the hull planes around the given edge, if not done allready
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static void AddHullEdge(hullbrush_t *hullbrush, const qvec3d &p1, const qvec3d &p2, const aabb3d &hull_size)
|
|
||||||
{
|
|
||||||
int pt1, pt2;
|
|
||||||
int a, b, c, d, e;
|
|
||||||
qbsp_plane_t plane;
|
|
||||||
vec_t length;
|
|
||||||
|
|
||||||
pt1 = AddHullPoint(hullbrush, p1, hull_size);
|
|
||||||
pt2 = AddHullPoint(hullbrush, p2, hull_size);
|
|
||||||
|
|
||||||
for (auto &edge : hullbrush->edges)
|
|
||||||
if ((edge == std::make_tuple(pt1, pt2)) || (edge == std::make_tuple(pt2, pt1)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (hullbrush->edges.size() == MAX_HULL_EDGES)
|
|
||||||
FError("hullbrush->numedges == MAX_HULL_EDGES ({}), "
|
|
||||||
"source brush on line {}",
|
|
||||||
MAX_HULL_EDGES, hullbrush->srcbrush->faces[0].linenum);
|
|
||||||
|
|
||||||
hullbrush->edges.emplace_back(pt1, pt2);
|
|
||||||
|
|
||||||
qvec3d edgevec = qv::normalize(p1 - p2);
|
|
||||||
|
|
||||||
for (a = 0; a < 3; a++) {
|
|
||||||
b = (a + 1) % 3;
|
|
||||||
c = (a + 2) % 3;
|
|
||||||
|
|
||||||
qvec3d planevec{};
|
|
||||||
planevec[a] = 1;
|
|
||||||
plane.set_normal(qv::normalize(qv::cross(planevec, edgevec), length));
|
|
||||||
|
|
||||||
/* If this edge is almost parallel to the hull edge, skip it. */
|
|
||||||
if (length < ANGLEEPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (d = 0; d <= 1; d++) {
|
|
||||||
for (e = 0; e <= 1; e++) {
|
|
||||||
qvec3d planeorg = p1;
|
|
||||||
planeorg[b] += hull_size[d][b];
|
|
||||||
planeorg[c] += hull_size[e][c];
|
|
||||||
plane.get_dist() = qv::dot(planeorg, plane.get_normal());
|
|
||||||
TestAddPlane(hullbrush, plane);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
ExpandBrush
|
ExpandBrush
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static void ExpandBrush(hullbrush_t *hullbrush, const aabb3d &hull_size, std::vector<side_t> &facelist)
|
static void ExpandBrush(bspbrush_t &hullbrush, const aabb3d &hull_size)
|
||||||
{
|
{
|
||||||
int x, s;
|
int x, s;
|
||||||
qbsp_plane_t plane;
|
qbsp_plane_t plane;
|
||||||
int cBevEdge = 0;
|
int cBevEdge = 0;
|
||||||
|
|
||||||
hullbrush->points.clear();
|
|
||||||
hullbrush->corners.clear();
|
|
||||||
hullbrush->edges.clear();
|
|
||||||
|
|
||||||
// create all the hull points
|
// create all the hull points
|
||||||
for (auto &f : facelist)
|
for (auto &f : facelist)
|
||||||
for (size_t i = 0; i < f.w.size(); i++) {
|
for (size_t i = 0; i < f.w.size(); i++) {
|
||||||
|
|
@ -550,6 +281,7 @@ static void ExpandBrush(hullbrush_t *hullbrush, const aabb3d &hull_size, std::ve
|
||||||
for (size_t i = 0; i < f.w.size(); i++)
|
for (size_t i = 0; i < f.w.size(); i++)
|
||||||
AddHullEdge(hullbrush, f.w[i], f.w[(i + 1) % f.w.size()], hull_size);
|
AddHullEdge(hullbrush, f.w[i], f.w[(i + 1) % f.w.size()], hull_size);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
|
@ -597,44 +329,45 @@ Converts a mapbrush to a bsp brush
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
|
std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const contentflags_t &contents,
|
||||||
const qvec3d &rotate_offset, const rotation_t rottype, const int hullnum)
|
const int hullnum)
|
||||||
{
|
{
|
||||||
hullbrush_t hullbrush;
|
// create the brush
|
||||||
std::vector<side_t> facelist;
|
bspbrush_t brush{};
|
||||||
|
brush.contents = contents;
|
||||||
|
brush.sides.reserve(mapbrush->faces.size());
|
||||||
|
|
||||||
// create the faces
|
for (size_t i = 0; i < mapbrush->faces.size(); i++) {
|
||||||
|
auto &src = mapbrush->faces[i];
|
||||||
|
|
||||||
hullbrush.linenum = mapbrush->faces[0].linenum;
|
if (src.bevel) {
|
||||||
if (mapbrush->faces.size() > MAX_FACES)
|
continue;
|
||||||
FError("brush->faces >= MAX_FACES ({}), source brush on line {}", MAX_FACES, hullbrush.linenum);
|
}
|
||||||
|
|
||||||
hullbrush.contents = contents;
|
auto &dst = brush.sides.emplace_back();
|
||||||
hullbrush.srcbrush = mapbrush;
|
|
||||||
hullbrush.faces.reserve(mapbrush->faces.size());
|
dst.texinfo = hullnum > 0 ? 0 : src.texinfo;
|
||||||
for (auto &face : mapbrush->faces) {
|
dst.planenum = src.planenum;
|
||||||
hullbrush.faces.emplace_back(face);
|
dst.bevel = src.bevel;
|
||||||
|
|
||||||
|
// TEMP
|
||||||
|
dst.w = src.winding;
|
||||||
|
|
||||||
|
CheckFace(&dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
facelist = CreateBrushFaces(src, &hullbrush, hullnum);
|
// todo: expand planes, recalculate bounds & windings
|
||||||
|
brush.bounds = mapbrush->bounds;
|
||||||
if (facelist.empty()) {
|
|
||||||
logging::print("WARNING: Couldn't create brush faces\n");
|
|
||||||
logging::print("^ brush at line {} of .map file\n", hullbrush.linenum);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (hullnum > 0) {
|
if (hullnum > 0) {
|
||||||
auto &hulls = qbsp_options.target_game->get_hull_sizes();
|
auto &hulls = qbsp_options.target_game->get_hull_sizes();
|
||||||
Q_assert(hullnum < hulls.size());
|
Q_assert(hullnum < hulls.size());
|
||||||
ExpandBrush(&hullbrush, *(hulls.begin() + hullnum), facelist);
|
ExpandBrush(&hullbrush, *(hulls.begin() + hullnum), facelist);
|
||||||
facelist = CreateBrushFaces(src, &hullbrush, hullnum);
|
facelist = CreateBrushFaces(src, &hullbrush, hullnum);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// create the brush
|
brush.mapbrush = mapbrush;
|
||||||
bspbrush_t brush{};
|
|
||||||
brush.contents = contents;
|
|
||||||
brush.sides = std::move(facelist);
|
|
||||||
brush.bounds = hullbrush.bounds;
|
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
329
qbsp/map.cc
329
qbsp/map.cc
|
|
@ -1634,50 +1634,6 @@ static std::optional<mapface_t> ParseBrushFace(parser_t &parser, const mapbrush_
|
||||||
return face;
|
return face;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
CalculateBrushBounds
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
inline void CalculateBrushBounds(mapbrush_t &ob)
|
|
||||||
{
|
|
||||||
ob.bounds = {};
|
|
||||||
|
|
||||||
for (size_t i = 0; i < ob.faces.size(); i++) {
|
|
||||||
const auto &plane = ob.faces[i].get_plane();
|
|
||||||
std::optional<winding_t> w = BaseWindingForPlane(plane);
|
|
||||||
|
|
||||||
for (size_t j = 0; j < ob.faces.size() && w; j++) {
|
|
||||||
if (i == j) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ob.faces[j].bevel) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto &plane = map.get_plane(ob.faces[j].planenum ^ 1);
|
|
||||||
w = w->clip(plane, 0)[SIDE_FRONT]; //CLIP_EPSILON);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w) {
|
|
||||||
ob.faces[i].winding = w.value();
|
|
||||||
//side->visible = true;
|
|
||||||
for (auto &p : w.value()) {
|
|
||||||
ob.bounds += p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 3; i++) {
|
|
||||||
if (ob.bounds.mins()[0] < -qbsp_options.worldextent.value() || ob.bounds.maxs()[0] > qbsp_options.worldextent.value()) {
|
|
||||||
logging::print("WARNING: entity xxx, brush yyy: bounds out of range\n");
|
|
||||||
}
|
|
||||||
if (ob.bounds.mins()[0] > qbsp_options.worldextent.value() || ob.bounds.maxs()[0] < -qbsp_options.worldextent.value()) {
|
|
||||||
logging::print("WARNING: entity xxx, brush yyy: no visible sides on brush\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
AddBrushBevels
|
AddBrushBevels
|
||||||
|
|
@ -2202,6 +2158,179 @@ bool IsNonRemoveWorldBrushEntity(const mapentity_t *entity)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CalculateBrushBounds
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
inline void CalculateBrushBounds(mapbrush_t &ob)
|
||||||
|
{
|
||||||
|
ob.bounds = {};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ob.faces.size(); i++) {
|
||||||
|
const auto &plane = ob.faces[i].get_plane();
|
||||||
|
std::optional<winding_t> w = BaseWindingForPlane(plane);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < ob.faces.size() && w; j++) {
|
||||||
|
if (i == j) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ob.faces[j].bevel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto &plane = map.get_plane(ob.faces[j].planenum ^ 1);
|
||||||
|
w = w->clip(plane, 0)[SIDE_FRONT]; //CLIP_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w) {
|
||||||
|
ob.faces[i].winding = w.value();
|
||||||
|
//side->visible = true;
|
||||||
|
for (auto &p : w.value()) {
|
||||||
|
ob.bounds += p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
if (ob.bounds.mins()[0] < -qbsp_options.worldextent.value() || ob.bounds.maxs()[0] > qbsp_options.worldextent.value()) {
|
||||||
|
logging::print("WARNING: entity xxx, brush yyy: bounds out of range\n");
|
||||||
|
}
|
||||||
|
if (ob.bounds.mins()[0] > qbsp_options.worldextent.value() || ob.bounds.maxs()[0] < -qbsp_options.worldextent.value()) {
|
||||||
|
logging::print("WARNING: entity xxx, brush yyy: no visible sides on brush\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMapBrushes()
|
||||||
|
{
|
||||||
|
logging::funcheader();
|
||||||
|
|
||||||
|
// calculate extents, if required
|
||||||
|
if (!qbsp_options.worldextent.value()) {
|
||||||
|
CalculateWorldExtent();
|
||||||
|
}
|
||||||
|
|
||||||
|
map.total_brushes = 0;
|
||||||
|
|
||||||
|
size_t num_faces = 0, num_bevels = 0, num_removed = 0, num_offset = 0;
|
||||||
|
|
||||||
|
// calculate brush extents and brush bevels
|
||||||
|
for (auto &entity : map.entities) {
|
||||||
|
|
||||||
|
/* Origin brush support */
|
||||||
|
rotation_t rottype = rotation_t::none;
|
||||||
|
|
||||||
|
for (auto it = entity.mapbrushes.begin(); it != entity.mapbrushes.end(); ) {
|
||||||
|
auto &brush = *it;
|
||||||
|
|
||||||
|
// calculate brush bounds
|
||||||
|
CalculateBrushBounds(brush);
|
||||||
|
|
||||||
|
const contentflags_t contents = Brush_GetContents(&brush);
|
||||||
|
|
||||||
|
// origin brushes are removed, and the origin of the entity is overwritten
|
||||||
|
// with its centroid.
|
||||||
|
if (contents.is_origin(qbsp_options.target_game)) {
|
||||||
|
if (&entity == map.world_entity()) {
|
||||||
|
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
||||||
|
} else if (entity.epairs.has("origin")) {
|
||||||
|
logging::print("WARNING: Entity at line {} has multiple origin brushes\n", entity.mapbrushes.front().faces[0].linenum);
|
||||||
|
} else {
|
||||||
|
entity.origin = brush.bounds.centroid();
|
||||||
|
entity.epairs.set("origin", qv::to_string(entity.origin));
|
||||||
|
}
|
||||||
|
|
||||||
|
num_removed++;
|
||||||
|
it = entity.mapbrushes.erase(it);
|
||||||
|
rottype = rotation_t::origin_brush;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t old_num_faces = brush.faces.size();
|
||||||
|
num_faces += old_num_faces;
|
||||||
|
|
||||||
|
// add the brush bevels
|
||||||
|
AddBrushBevels(entity, brush);
|
||||||
|
|
||||||
|
num_bevels += brush.faces.size() - old_num_faces;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.total_brushes += entity.mapbrushes.size();
|
||||||
|
|
||||||
|
/* Hipnotic rotation */
|
||||||
|
if (rottype == rotation_t::none) {
|
||||||
|
if (!Q_strncasecmp(entity.epairs.get("classname"), "rotate_", 7)) {
|
||||||
|
entity.origin = FixRotateOrigin(&entity);
|
||||||
|
rottype = rotation_t::hipnotic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// offset brush bounds
|
||||||
|
if (rottype != rotation_t::none) {
|
||||||
|
for (auto &brush : entity.mapbrushes) {
|
||||||
|
brush.bounds = brush.bounds.translate(-entity.origin);
|
||||||
|
|
||||||
|
for (auto &f : brush.faces) {
|
||||||
|
// account for texture offset, from txqbsp-xt
|
||||||
|
if (!qbsp_options.oldrottex.value()) {
|
||||||
|
maptexinfo_t texInfoNew = map.mtexinfos.at(f.texinfo);
|
||||||
|
texInfoNew.outputnum = std::nullopt;
|
||||||
|
|
||||||
|
texInfoNew.vecs.at(0, 3) += qv::dot(entity.origin, texInfoNew.vecs.row(0).xyz());
|
||||||
|
texInfoNew.vecs.at(1, 3) += qv::dot(entity.origin, texInfoNew.vecs.row(1).xyz());
|
||||||
|
|
||||||
|
f.texinfo = FindTexinfo(texInfoNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
qplane3d plane = f.get_plane();
|
||||||
|
plane.dist -= qv::dot(plane.normal, entity.origin);
|
||||||
|
f.planenum = map.add_or_find_plane(plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-calculate brush bounds
|
||||||
|
CalculateBrushBounds(brush);
|
||||||
|
|
||||||
|
num_offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
// Rotatable objects must have a bounding box big enough to
|
||||||
|
// account for all its rotations
|
||||||
|
|
||||||
|
// if -wrbrushes is in use, don't do this for the clipping hulls because it depends on having
|
||||||
|
// the actual non-hacked bbox (it doesn't write axial planes).
|
||||||
|
|
||||||
|
// Hexen2 also doesn't want the bbox expansion, it's handled in engine (see: SV_LinkEdict)
|
||||||
|
|
||||||
|
// Only do this for hipnotic rotation. For origin brushes in Quake, it breaks some of their
|
||||||
|
// uses (e.g. func_train). This means it's up to the mapper to expand the model bounds with
|
||||||
|
// clip brushes if they're going to rotate a model in vanilla Quake and not use hipnotic rotation.
|
||||||
|
// The idea behind the bounds expansion was to avoid incorrect vis culling (AFAIK).
|
||||||
|
const bool shouldExpand = (rotate_offset[0] != 0.0 || rotate_offset[1] != 0.0 || rotate_offset[2] != 0.0) &&
|
||||||
|
rottype == rotation_t::hipnotic &&
|
||||||
|
(hullnum >= 0) // hullnum < 0 corresponds to -wrbrushes clipping hulls
|
||||||
|
&& qbsp_options.target_game->id != GAME_HEXEN_II; // never do this in Hexen 2
|
||||||
|
|
||||||
|
if (shouldExpand) {
|
||||||
|
vec_t delta = std::max(fabs(max), fabs(min));
|
||||||
|
hullbrush->bounds = {-delta, delta};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
logging::print(logging::flag::STAT, " {:8} brushes\n", map.total_brushes);
|
||||||
|
logging::print(logging::flag::STAT, " {:8} faces\n", num_faces);
|
||||||
|
logging::print(logging::flag::STAT, " {:8} bevel faces\n", num_bevels);
|
||||||
|
if (num_removed) {
|
||||||
|
logging::print(logging::flag::STAT, " {:8} utility brushes removed\n", num_removed);
|
||||||
|
}
|
||||||
|
if (num_offset) {
|
||||||
|
logging::print(logging::flag::STAT, " {:8} brushes translated from origins\n", num_offset);
|
||||||
|
}
|
||||||
|
logging::print(logging::flag::STAT, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
void LoadMapFile(void)
|
void LoadMapFile(void)
|
||||||
{
|
{
|
||||||
logging::funcheader();
|
logging::funcheader();
|
||||||
|
|
@ -2260,118 +2389,6 @@ void LoadMapFile(void)
|
||||||
map.entities.pop_back();
|
map.entities.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate extents, if required
|
|
||||||
if (!qbsp_options.worldextent.value()) {
|
|
||||||
CalculateWorldExtent();
|
|
||||||
}
|
|
||||||
|
|
||||||
map.total_brushes = 0;
|
|
||||||
|
|
||||||
size_t num_faces = 0, num_bevels = 0;
|
|
||||||
|
|
||||||
// calculate brush extents and brush bevels
|
|
||||||
for (auto &entity : map.entities) {
|
|
||||||
|
|
||||||
for (auto it = entity.mapbrushes.begin(); it != entity.mapbrushes.end(); ) {
|
|
||||||
auto &brush = *it;
|
|
||||||
|
|
||||||
// calculate brush bounds
|
|
||||||
CalculateBrushBounds(brush);
|
|
||||||
|
|
||||||
const contentflags_t contents = Brush_GetContents(&brush);
|
|
||||||
|
|
||||||
// origin brushes are removed, and the origin of the entity is overwritten
|
|
||||||
// with its centroid.
|
|
||||||
if (contents.is_origin(qbsp_options.target_game)) {
|
|
||||||
if (&entity == map.world_entity()) {
|
|
||||||
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
|
||||||
} else if (entity.epairs.has("origin")) {
|
|
||||||
logging::print("WARNING: Entity at line {} has multiple origin brushes\n", entity.mapbrushes.front().faces[0].linenum);
|
|
||||||
} else {
|
|
||||||
entity.origin = brush.bounds.centroid();
|
|
||||||
entity.epairs.set("origin", qv::to_string(entity.origin));
|
|
||||||
}
|
|
||||||
|
|
||||||
it = entity.mapbrushes.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t old_num_faces = brush.faces.size();
|
|
||||||
num_faces += old_num_faces;
|
|
||||||
|
|
||||||
// add the brush bevels
|
|
||||||
AddBrushBevels(entity, brush);
|
|
||||||
|
|
||||||
num_bevels += brush.faces.size() - old_num_faces;
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
map.total_brushes += entity.mapbrushes.size();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
qvec3d rotate_offset{};
|
|
||||||
|
|
||||||
/* Origin brush support */
|
|
||||||
rotation_t rottype = rotation_t::none;
|
|
||||||
|
|
||||||
for (auto &mapbrush : src->mapbrushes) {
|
|
||||||
const contentflags_t contents = Brush_GetContents(&mapbrush);
|
|
||||||
|
|
||||||
if (contents.is_origin(qbsp_options.target_game)) {
|
|
||||||
if (dst == map.world_entity()) {
|
|
||||||
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<bspbrush_t> brush = LoadBrush(src, &mapbrush, contents, {}, rotation_t::none, 0);
|
|
||||||
|
|
||||||
if (brush) {
|
|
||||||
rotate_offset = brush->bounds.centroid();
|
|
||||||
|
|
||||||
dst->epairs.set("origin", qv::to_string(rotate_offset));
|
|
||||||
|
|
||||||
rottype = rotation_t::origin_brush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hipnotic rotation */
|
|
||||||
if (rottype == rotation_t::none) {
|
|
||||||
if (!Q_strncasecmp(classname, "rotate_", 7)) {
|
|
||||||
rotate_offset = FixRotateOrigin(dst);
|
|
||||||
rottype = rotation_t::hipnotic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Rotatable objects must have a bounding box big enough to
|
|
||||||
// account for all its rotations
|
|
||||||
|
|
||||||
// if -wrbrushes is in use, don't do this for the clipping hulls because it depends on having
|
|
||||||
// the actual non-hacked bbox (it doesn't write axial planes).
|
|
||||||
|
|
||||||
// Hexen2 also doesn't want the bbox expansion, it's handled in engine (see: SV_LinkEdict)
|
|
||||||
|
|
||||||
// Only do this for hipnotic rotation. For origin brushes in Quake, it breaks some of their
|
|
||||||
// uses (e.g. func_train). This means it's up to the mapper to expand the model bounds with
|
|
||||||
// clip brushes if they're going to rotate a model in vanilla Quake and not use hipnotic rotation.
|
|
||||||
// The idea behind the bounds expansion was to avoid incorrect vis culling (AFAIK).
|
|
||||||
const bool shouldExpand = (rotate_offset[0] != 0.0 || rotate_offset[1] != 0.0 || rotate_offset[2] != 0.0) &&
|
|
||||||
rottype == rotation_t::hipnotic &&
|
|
||||||
(hullnum >= 0) // hullnum < 0 corresponds to -wrbrushes clipping hulls
|
|
||||||
&& qbsp_options.target_game->id != GAME_HEXEN_II; // never do this in Hexen 2
|
|
||||||
|
|
||||||
if (shouldExpand) {
|
|
||||||
vec_t delta = std::max(fabs(max), fabs(min));
|
|
||||||
hullbrush->bounds = {-delta, delta};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
logging::print(logging::flag::STAT, " {:8} brushes\n", map.total_brushes);
|
|
||||||
logging::print(logging::flag::STAT, " {:8} faces\n", num_faces);
|
|
||||||
logging::print(logging::flag::STAT, " {:8} bevel faces\n", num_bevels);
|
|
||||||
|
|
||||||
logging::print(logging::flag::STAT, " {:8} entities\n", map.entities.size());
|
logging::print(logging::flag::STAT, " {:8} entities\n", map.entities.size());
|
||||||
logging::print(logging::flag::STAT, " {:8} unique texnames\n", map.miptex.size());
|
logging::print(logging::flag::STAT, " {:8} unique texnames\n", map.miptex.size());
|
||||||
logging::print(logging::flag::STAT, " {:8} texinfo\n", map.mtexinfos.size());
|
logging::print(logging::flag::STAT, " {:8} texinfo\n", map.mtexinfos.size());
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
||||||
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_brushes) {
|
||||||
map.bsp.dleafbrushes.push_back(b->outputnumber.value());
|
map.bsp.dleafbrushes.push_back(b->mapbrush->outputnumber.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,14 +324,14 @@ static void ExportBrushList(mapentity_t *entity, node_t *node)
|
||||||
brush_state = {};
|
brush_state = {};
|
||||||
|
|
||||||
for (auto &b : entity->brushes) {
|
for (auto &b : entity->brushes) {
|
||||||
b->outputnumber = {static_cast<uint32_t>(map.bsp.dbrushes.size())};
|
const_cast<mapbrush_t *>(b->mapbrush)->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->sides) {
|
for (auto &side : b->sides) {
|
||||||
map.bsp.dbrushsides.push_back(
|
map.bsp.dbrushsides.push_back(
|
||||||
{(uint32_t) side.planenum, (int32_t)ExportMapTexinfo(side.texinfo)});
|
{(uint32_t) ExportMapPlane(side.get_plane()), (int32_t)ExportMapTexinfo(side.texinfo)});
|
||||||
brush.numsides++;
|
brush.numsides++;
|
||||||
brush_state.total_brush_sides++;
|
brush_state.total_brush_sides++;
|
||||||
}
|
}
|
||||||
|
|
@ -928,6 +928,9 @@ void ProcessFile()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle load time operation on the .map
|
||||||
|
ProcessMapBrushes();
|
||||||
|
|
||||||
// initialize secondary textures
|
// initialize secondary textures
|
||||||
LoadSecondaryTextures();
|
LoadSecondaryTextures();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -607,7 +607,6 @@ static std::list<std::vector<size_t>> RetopologizeFace(const face_t *f, const st
|
||||||
|
|
||||||
for (; end != wrap; end = (end + 1) % input.size()) {
|
for (; end != wrap; end = (end + 1) % input.size()) {
|
||||||
auto v0 = input[seed];
|
auto v0 = input[seed];
|
||||||
auto v1 = input[(end - 1) < 0 ? (input.size() - 1) : (end - 1)];
|
|
||||||
auto v2 = input[end];
|
auto v2 = input[end];
|
||||||
|
|
||||||
// if the next point lays on the edge of v0-v2, this next
|
// if the next point lays on the edge of v0-v2, this next
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,6 @@ static mapentity_t LoadMap(const char *map)
|
||||||
|
|
||||||
mapentity_t worldspawn;
|
mapentity_t worldspawn;
|
||||||
|
|
||||||
mapentity_t &entity = ::map.entities.emplace_back();
|
|
||||||
|
|
||||||
// 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));
|
||||||
|
|
||||||
|
|
@ -55,6 +53,7 @@ static mapentity_t LoadMap(const char *map)
|
||||||
|
|
||||||
#include <common/bspinfo.hh>
|
#include <common/bspinfo.hh>
|
||||||
|
|
||||||
|
#if 0
|
||||||
static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmapRef(const std::filesystem::path &name)
|
static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmapRef(const std::filesystem::path &name)
|
||||||
{
|
{
|
||||||
const char *destdir = test_quake2_maps_dir;
|
const char *destdir = test_quake2_maps_dir;
|
||||||
|
|
@ -166,7 +165,7 @@ static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmapRe
|
||||||
std::move(bspdata.bspx.entries),
|
std::move(bspdata.bspx.entries),
|
||||||
std::move(prtfile));
|
std::move(prtfile));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmap(const std::filesystem::path &name, std::vector<std::string> extra_args = {})
|
static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmap(const std::filesystem::path &name, std::vector<std::string> extra_args = {})
|
||||||
{
|
{
|
||||||
|
|
@ -275,6 +274,7 @@ static void CheckFilled(const mbsp_t &bsp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static mbsp_t LoadBsp(const std::filesystem::path &path_in)
|
static mbsp_t LoadBsp(const std::filesystem::path &path_in)
|
||||||
{
|
{
|
||||||
std::filesystem::path path = path_in;
|
std::filesystem::path path = path_in;
|
||||||
|
|
@ -286,6 +286,7 @@ static mbsp_t LoadBsp(const std::filesystem::path &path_in)
|
||||||
|
|
||||||
return std::get<mbsp_t>(bspdata.bsp);
|
return std::get<mbsp_t>(bspdata.bsp);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static std::map<std::string, std::vector<const mface_t *>> MakeTextureToFaceMap(const mbsp_t &bsp)
|
static std::map<std::string, std::vector<const mface_t *>> MakeTextureToFaceMap(const mbsp_t &bsp)
|
||||||
{
|
{
|
||||||
|
|
@ -1175,7 +1176,7 @@ TEST_CASE("qbsp_func_detail various types", "[testmaps_q1]") {
|
||||||
const qvec3d in_func_detail_illusionary{56, -216, 120};
|
const qvec3d in_func_detail_illusionary{56, -216, 120};
|
||||||
const qvec3d in_func_detail_illusionary_mirrorinside{56, -296, 120};
|
const qvec3d in_func_detail_illusionary_mirrorinside{56, -296, 120};
|
||||||
|
|
||||||
const double floor_z = 96;
|
//const double floor_z = 96;
|
||||||
|
|
||||||
// detail clips away world faces, others don't
|
// detail clips away world faces, others don't
|
||||||
CHECK(nullptr == BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], in_func_detail - qvec3d(0,0,24), {0, 0, 1}));
|
CHECK(nullptr == BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], in_func_detail - qvec3d(0,0,24), {0, 0, 1}));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue