going back to using planenums, but going for the qbsp3-esque system

This commit is contained in:
Jonathan 2022-08-02 14:17:59 -04:00
parent 93655913c0
commit 1ad0eb530d
4 changed files with 83 additions and 36 deletions

View File

@ -39,7 +39,8 @@ struct bspbrush_t;
struct mapface_t
{
qbsp_plane_t plane{};
//qbsp_plane_t plane{};
size_t planenum;
std::array<qvec3d, 3> planepts{};
std::string texname{};
int texinfo = 0;
@ -58,6 +59,8 @@ struct mapface_t
const texvecf &get_texvecs() const;
void set_texvecs(const texvecf &vecs);
const qbsp_plane_t &get_plane() const;
};
enum class brushformat_t
@ -139,7 +142,46 @@ struct mapdata_t
std::vector<mapface_t> faces;
std::vector<mapbrush_t> brushes;
std::vector<mapentity_t> entities;
// this vector stores all of the planes that can potentially be
// output in the BSP, from the map's own sides. The positive planes
// come first (are even-numbered, with 0 being even) and the negative
// planes are odd-numbered.
std::vector<mapplane_t> planes;
// add the specified plane to the list
inline size_t add_plane(const qplane3d &plane)
{
planes.reserve(planes.size() + 2);
auto &positive = planes.emplace_back(plane);
auto &negative = planes.emplace_back(-plane);
if (positive.get_normal()[static_cast<int32_t>(positive.get_type()) % 3] < 0.0) {
std::swap(positive, negative);
return planes.size() - 1;
}
return planes.size() - 2;
}
// find the specified plane in the list if it exists, or
// return a new one
inline size_t add_or_find_plane(const qplane3d &plane)
{
for (size_t i = 0; i < planes.size(); i++) {
if (qv::epsilonEqual(planes[i], plane)) {
return i;
}
}
return add_plane(plane);
}
inline const qbsp_plane_t &get_plane(size_t pnum)
{
return planes[pnum];
}
std::vector<maptexdata_t> miptex;
std::vector<maptexinfo_t> mtexinfos;
@ -221,12 +263,6 @@ struct mapdata_t
const std::string &texinfoTextureName(int texinfo) const { return miptexTextureName(mtexinfos.at(texinfo).miptex); }
inline qbsp_plane_t get_plane(int pnum)
{
std::shared_lock lock(map_planes_lock);
return planes.at(pnum);
}
int skip_texinfo;
mapentity_t *world_entity();

View File

@ -268,7 +268,7 @@ static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
continue;
}
w = BaseWindingForPlane(mapface.plane);
w = BaseWindingForPlane(mapface.get_plane());
for (auto &mapface2 : hullbrush->faces) {
if (&mapface == &mapface2)
@ -277,7 +277,7 @@ static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
break;
// flip the plane, because we want to keep the back side
plane = -mapface2.plane;
plane = -mapface2.get_plane();
w = w->clip(plane, qbsp_options.epsilon.value(), false)[SIDE_FRONT];
}
@ -320,8 +320,8 @@ static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
mapface.texinfo = FindTexinfo(texInfoNew);
}
plane.normal = mapface.plane.get_normal();
point = mapface.plane.get_normal() * mapface.plane.get_dist();
plane.normal = mapface.get_plane().get_normal();
point = mapface.get_plane().get_normal() * mapface.get_plane().get_dist();
point -= rotate_offset;
plane.dist = qv::dot(plane.normal, point);
@ -388,7 +388,7 @@ static void AddBrushPlane(hullbrush_t *hullbrush, const qbsp_plane_t &plane)
FError("invalid normal (vector length {:.4})", len);
for (auto &mapface : hullbrush->faces) {
if (qv::epsilonEqual(mapface.plane, plane, EQUAL_EPSILON, qbsp_options.epsilon.value())) {
if (qv::epsilonEqual(mapface.get_plane(), plane, EQUAL_EPSILON, qbsp_options.epsilon.value())) {
return;
}
}
@ -399,7 +399,7 @@ static void AddBrushPlane(hullbrush_t *hullbrush, const qbsp_plane_t &plane)
}
mapface_t &mapface = hullbrush->faces.emplace_back();
mapface.plane = plane;
mapface.planenum = map.add_or_find_plane(plane);
mapface.texinfo = 0;
}
@ -418,9 +418,9 @@ static void TestAddPlane(hullbrush_t *hullbrush, qbsp_plane_t &plane)
/* see if the plane has already been added */
for (auto &mapface : hullbrush->faces) {
if (qv::epsilonEqual(plane, mapface.plane))
if (qv::epsilonEqual(plane, mapface.get_plane()))
return;
if (qv::epsilonEqual(-plane, mapface.plane))
if (qv::epsilonEqual(-plane, mapface.get_plane()))
return;
}
@ -562,12 +562,14 @@ static void ExpandBrush(hullbrush_t *hullbrush, const aabb3d &hull_size, std::ve
continue;
qvec3d corner{};
for (x = 0; x < 3; x++) {
if (mapface.plane.get_normal()[x] > 0)
if (mapface.get_plane().get_normal()[x] > 0)
corner[x] = hull_size[1][x];
else if (mapface.plane.get_normal()[x] < 0)
else if (mapface.get_plane().get_normal()[x] < 0)
corner[x] = hull_size[0][x];
}
mapface.plane.get_dist() += qv::dot(corner, mapface.plane.get_normal());
qplane3d plane = mapface.get_plane();
plane.dist += qv::dot(corner, plane.normal);
mapface.planenum = map.add_or_find_plane(plane);
}
// add any axis planes not contained in the brush to bevel off corners

View File

@ -1540,9 +1540,10 @@ bool mapface_t::set_planepts(const std::array<qvec3d, 3> &pts)
qvec3d cb = planepts[2] - planepts[1];
vec_t length;
plane.set_normal(qv::normalize(qv::cross(ab, cb), length));
plane.get_dist() = qv::dot(planepts[1], plane.get_normal());
qvec3d normal = qv::normalize(qv::cross(ab, cb), length);
vec_t dist = qv::dot(planepts[1], normal);
planenum = map.add_or_find_plane({ normal, dist });
return length >= NORMAL_EPSILON;
}
@ -1561,6 +1562,11 @@ void mapface_t::set_texvecs(const texvecf &vecs)
this->texinfo = FindTexinfo(texInfoNew);
}
const qbsp_plane_t &mapface_t::get_plane() const
{
return map.get_plane(planenum);
}
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec)
{
// TODO: This doesn't match how light does it (TexSpaceToWorld)
@ -1582,7 +1588,7 @@ bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, con
inline bool IsValidTextureProjection(const mapface_t &mapface, const maptexinfo_t *tx)
{
return IsValidTextureProjection(mapface.plane.get_normal(), tx->vecs.row(0).xyz(), tx->vecs.row(1).xyz());
return IsValidTextureProjection(mapface.get_plane().get_normal(), tx->vecs.row(0).xyz(), tx->vecs.row(1).xyz());
}
static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx)
@ -1596,7 +1602,7 @@ static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx)
const std::array<vec_t, 2> shift{0, 0};
const vec_t rotate = 0;
const std::array<vec_t, 2> scale = {1, 1};
SetTexinfo_QuakeEd(mapface.plane, mapface.planepts, shift, rotate, scale, tx);
SetTexinfo_QuakeEd(mapface.get_plane(), mapface.planepts, shift, rotate, scale, tx);
Q_assert(IsValidTextureProjection(mapface, tx));
}
@ -1615,7 +1621,7 @@ static std::unique_ptr<mapface_t> ParseBrushFace(parser_t &parser, const mapbrus
normal_ok = face->set_planepts(planepts);
ParseTextureDef(parser, *face, brush, &tx, face->planepts, face->plane);
ParseTextureDef(parser, *face, brush, &tx, face->planepts, face->get_plane());
if (!normal_ok) {
logging::print("WARNING: line {}: Brush plane with no normal\n", parser.linenum);
@ -1679,24 +1685,27 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
bool discardFace = false;
for (int i = 0; i < brush.numfaces; i++) {
const mapface_t &check = brush.face(i);
if (qv::epsilonEqual(check.plane, face->plane)) {
if (qv::epsilonEqual(check.get_plane(), face->get_plane())) {
logging::print("line {}: Brush with duplicate plane\n", parser.linenum);
discardFace = true;
continue;
}
if (qv::epsilonEqual(-check.plane, face->plane)) {
if (qv::epsilonEqual(-check.get_plane(), face->get_plane())) {
/* FIXME - this is actually an invalid brush */
logging::print("line {}: Brush with duplicate plane\n", parser.linenum);
continue;
}
}
if (discardFace)
if (discardFace) {
continue;
}
/* Save the face, update progress */
if (0 == brush.numfaces)
if (!brush.numfaces) {
brush.firstface = map.faces.size();
}
brush.numfaces++;
map.faces.push_back(*face);
}
@ -2154,7 +2163,7 @@ static void ConvertMapFace(std::ofstream &f, const mapface_t &mapface, const con
case conversion_t::quake:
case conversion_t::quake2: {
const texdef_quake_ed_t quakeed =
TexDef_BSPToQuakeEd(mapface.plane, texture, texinfo.vecs, mapface.planepts);
TexDef_BSPToQuakeEd(mapface.get_plane(), texture, texinfo.vecs, mapface.planepts);
fmt::print(f, "{} ", mapface.texname);
fprintDoubleAndSpc(f, quakeed.shift[0]);
@ -2199,7 +2208,7 @@ static void ConvertMapFace(std::ofstream &f, const mapface_t &mapface, const con
texSize[0] = texture ? texture->width : 64;
texSize[1] = texture ? texture->height : 64;
const texdef_brush_primitives_t bp = TexDef_BSPToBrushPrimitives(mapface.plane, texSize, texinfo.vecs);
const texdef_brush_primitives_t bp = TexDef_BSPToBrushPrimitives(mapface.get_plane(), texSize, texinfo.vecs);
f << "( ( ";
fprintDoubleAndSpc(f, bp.at(0, 0));
fprintDoubleAndSpc(f, bp.at(0, 1));
@ -2360,14 +2369,14 @@ inline vec_t GetBrushExtents(const mapbrush_t &hullbrush)
auto &fk = hullbrush.face(k);
bool legal = true;
auto vertex = GetIntersection(fi.plane, fj.plane, fk.plane);
auto vertex = GetIntersection(fi.get_plane(), fj.get_plane(), fk.get_plane());
if (!vertex) {
continue;
}
for (int32_t m = 0; m < hullbrush.numfaces; m++) {
if (hullbrush.face(m).plane.distance_to(*vertex) > NORMAL_EPSILON) {
if (hullbrush.face(m).get_plane().distance_to(*vertex) > NORMAL_EPSILON) {
legal = false;
break;
}

View File

@ -432,7 +432,7 @@ TEST_CASE("InvalidTextureProjection", "[qbsp]")
const mapface_t *face = &worldspawn.mapbrush(0).face(5);
REQUIRE("skip" == face->texname);
const auto texvecs = face->get_texvecs();
CHECK(IsValidTextureProjection(face->plane.get_normal(), texvecs.row(0), texvecs.row(1)));
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
}
/**
@ -462,7 +462,7 @@ TEST_CASE("InvalidTextureProjection2", "[qbsp]")
const mapface_t *face = &worldspawn.mapbrush(0).face(5);
REQUIRE("skip" == face->texname);
const auto texvecs = face->get_texvecs();
CHECK(IsValidTextureProjection(face->plane.get_normal(), texvecs.row(0), texvecs.row(1)));
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
}
/**
@ -493,7 +493,7 @@ TEST_CASE("InvalidTextureProjection3", "[qbsp]")
const mapface_t *face = &worldspawn.mapbrush(0).face(3);
REQUIRE("*lava1" == face->texname);
const auto texvecs = face->get_texvecs();
CHECK(IsValidTextureProjection(face->plane.get_normal(), texvecs.row(0), texvecs.row(1)));
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
}
TEST_CASE("WindingArea", "[mathlib]")