Remove unused thingies

Use qplane3 where we can
This commit is contained in:
Jonathan 2021-10-17 06:24:02 -04:00
parent fd18fc154c
commit a7de4bdae2
36 changed files with 510 additions and 1372 deletions

View File

@ -109,7 +109,22 @@ static void serialize_bsp(const bspdata_t &bspdata, const mbsp_t &bsp, const std
}
if (bsp.dvis.bits.size()) {
j["visdata"] = hex_string(bsp.dvis.bits.data(), bsp.dvis.bits.size());
if (bsp.dvis.bit_offsets.size()) {
json &visdata = (j.emplace("visdata", json::object())).first.value();
json &pvs = (visdata.emplace("pvs", json::array())).first.value();
json &phs = (visdata.emplace("pvs", json::array())).first.value();
for (auto &offset : bsp.dvis.bit_offsets) {
pvs.push_back(offset[VIS_PVS]);
phs.push_back(offset[VIS_PHS]);
}
visdata["bits"] = hex_string(bsp.dvis.bits.data(), bsp.dvis.bits.size());
} else {
j["visdata"] = hex_string(bsp.dvis.bits.data(), bsp.dvis.bits.size());
}
}
if (bsp.dlightdata.size()) {
@ -117,7 +132,7 @@ static void serialize_bsp(const bspdata_t &bspdata, const mbsp_t &bsp, const std
}
if (!bsp.dentdata.empty()) {
j["entdata"] = bsp.dentdata + '\0';
j["entdata"] = bsp.dentdata;
}
if (!bsp.dleafs.empty()) {
@ -324,10 +339,11 @@ int main(int argc, char **argv)
LoadBSPFile(source, &bsp);
PrintBSPFileSizes(&bsp);
source.replace_extension("bsp.json");
WriteBSPFile(std::filesystem::path(source).replace_extension("bsp.rewrite"), &bsp);
ConvertBSPFormat(&bsp, &bspver_generic);
serialize_bsp(bsp, std::get<mbsp_t>(bsp.bsp), source);
serialize_bsp(bsp, std::get<mbsp_t>(bsp.bsp), std::filesystem::path(source).replace_extension("bsp.json"));
printf("---------------------\n");
}

View File

@ -124,8 +124,7 @@ static void CheckBSPFacesPlanar(const mbsp_t *bsp)
dplane_t plane = bsp->dplanes[face->planenum];
if (face->side) {
VectorInverse(plane.normal);
plane.dist = -plane.dist;
plane = -plane;
}
for (size_t j = 0; j < face->numedges; j++) {

View File

@ -108,20 +108,15 @@ static void WriteNullTexdef(fmt::memory_buffer &file)
fmt::format_to(file, "[ {} {} {} {} ] [ {} {} {} {} ] {} {} {}", 1, 0, 0, 0, 0, 1, 0, 0, 0.0, 1, 1);
}
//
struct decomp_plane_t
// this should be an outward-facing plane
struct decomp_plane_t : qplane3d
{
const bsp2_dnode_t *node; // can be nullptr
bool nodefront; // only set if node is non-null. true = we are visiting the front side of the plane
// this should be an outward-facing plane
qvec3d normal;
double distance;
static decomp_plane_t make(const qvec3d &normalIn, double distanceIn)
{
return {nullptr, false, normalIn, distanceIn};
return {{ normalIn, distanceIn }, nullptr, false};
}
};
@ -142,7 +137,7 @@ std::vector<decomp_plane_t> RemoveRedundantPlanes(const std::vector<decomp_plane
for (const decomp_plane_t &plane : planes) {
// outward-facing plane
std::optional<winding_t> winding = winding_t::from_plane(plane.normal, plane.distance, 10e6);
std::optional<winding_t> winding = winding_t::from_plane(plane, 10e6);
// clip `winding` by all of the other planes, flipped
for (const decomp_plane_t &plane2 : planes) {
@ -150,12 +145,8 @@ std::vector<decomp_plane_t> RemoveRedundantPlanes(const std::vector<decomp_plane
continue;
// get flipped plane
vec3_t plane2normal;
VectorCopy(plane2.normal * -1.0, plane2normal);
float plane2dist = -plane2.distance;
// frees winding.
auto clipped = winding->clip(plane2normal, plane2dist);
auto clipped = winding->clip(-plane2);
// discard the back, continue clipping the front part
winding = clipped[0];
@ -210,13 +201,13 @@ std::tuple<qvec3d, qvec3d> MakeTangentAndBitangentUnnormalized(const qvec3d &nor
return {tangent, bitangent};
}
static planepoints NormalDistanceToThreePoints(const qvec3d &normal, const double dist)
static planepoints NormalDistanceToThreePoints(const qplane3d &plane)
{
std::tuple<qvec3d, qvec3d> tanBitan = MakeTangentAndBitangentUnnormalized(normal);
std::tuple<qvec3d, qvec3d> tanBitan = MakeTangentAndBitangentUnnormalized(plane.normal);
planepoints result;
result.point0 = normal * dist;
result.point0 = plane.normal * plane.dist;
result.point1 = result.point0 + std::get<1>(tanBitan);
result.point2 = result.point0 + std::get<0>(tanBitan);
@ -231,7 +222,7 @@ void PrintPoint(const qvec3d &v, fmt::memory_buffer &file)
static void PrintPlanePoints(const mbsp_t *bsp, const decomp_plane_t &decompplane, fmt::memory_buffer &file)
{
// we have a plane in (normal, distance) form;
const planepoints p = NormalDistanceToThreePoints(decompplane.normal, decompplane.distance);
const planepoints p = NormalDistanceToThreePoints(decompplane);
PrintPoint(p.point0, file);
fmt::format_to(file, " ");
@ -295,9 +286,9 @@ public:
/**
* Returns the { front, back } after the clip.
*/
std::pair<decomp_brush_face_t, decomp_brush_face_t> clipToPlane(const qvec3d &normal, double distance) const
std::pair<decomp_brush_face_t, decomp_brush_face_t> clipToPlane(const qplane3d &plane) const
{
auto clipped = winding->clip(normal, (float)distance);
auto clipped = winding->clip(plane);
// front or back may be null (if fully clipped).
// these constructors take ownership of the winding.
@ -377,14 +368,14 @@ struct decomp_brush_side_t
/**
* Returns the { front, back } after the clip.
*/
std::tuple<decomp_brush_side_t, decomp_brush_side_t> clipToPlane(const qvec3d &normal, double distance) const
std::tuple<decomp_brush_side_t, decomp_brush_side_t> clipToPlane(const decomp_plane_t &plane) const
{
// FIXME: assert normal/distance are not our plane
std::vector<decomp_brush_face_t> frontfaces, backfaces;
for (auto &face : faces) {
auto [faceFront, faceBack] = face.clipToPlane(normal, distance);
auto [faceFront, faceBack] = face.clipToPlane(plane);
if (faceFront.winding) {
frontfaces.emplace_back(std::move(faceFront));
}
@ -408,14 +399,14 @@ struct decomp_brush_t
/**
* Returns the front and back side after clipping to the given plane.
*/
std::tuple<decomp_brush_t, decomp_brush_t> clipToPlane(const qvec3d &normal, double distance) const
std::tuple<decomp_brush_t, decomp_brush_t> clipToPlane(const qplane3d &plane) const
{
// FIXME: this won't handle the the given plane is one of the brush planes
std::vector<decomp_brush_side_t> frontSides, backSides;
for (const auto &side : sides) {
auto [frontSide, backSide] = side.clipToPlane(normal, distance);
auto [frontSide, backSide] = side.clipToPlane({ plane });
frontSides.emplace_back(frontSide);
backSides.emplace_back(backSide);
}
@ -423,8 +414,8 @@ struct decomp_brush_t
// NOTE: the frontSides, backSides vectors will have redundant planes at this point. Should be OK..
// Now we need to add the splitting plane itself to the sides vectors
frontSides.emplace_back(-normal, -distance);
backSides.emplace_back(normal, distance);
frontSides.emplace_back(-plane.normal, -plane.dist);
backSides.emplace_back(plane.normal, plane.dist);
return {decomp_brush_t(frontSides), decomp_brush_t(backSides)};
}
@ -439,7 +430,7 @@ struct decomp_brush_t
for (auto &otherSide : sides) {
float distance = GLM_DistAbovePlane(
qvec4f(qvec3f(otherSide.plane.normal), (float)otherSide.plane.distance), point);
qvec4f(qvec3f(otherSide.plane.normal), (float)otherSide.plane.dist), point);
if (distance > 0.1) {
return false;
}
@ -469,7 +460,7 @@ static decomp_brush_t BuildInitialBrush(const mbsp_t *bsp, const std::vector<dec
if (&plane2 == &plane)
continue;
auto [front, back] = side.clipToPlane(plane2.normal, plane2.distance);
auto [front, back] = side.clipToPlane(plane2);
side = back;
}
@ -512,7 +503,7 @@ static qvec4f SuggestSplit(const mbsp_t *bsp, const decomp_brush_side_t &side)
for (const qvec4f &split : face.inwardFacingEdgePlanes) {
// this is a potential splitting plane.
auto [front, back] = side.clipToPlane(qvec3d(split.xyz()), split[3]);
auto [front, back] = side.clipToPlane(decomp_plane_t { qplane3d { split.xyz(), split[3] } });
// we only consider splits that have at least 1 face on the front and back
if (front.faces.empty()) {
@ -542,7 +533,7 @@ static void SplitDifferentTexturedPartsOfBrush_R(
if (SideNeedsSplitting(bsp, side)) {
qvec4f split = SuggestSplit(bsp, side);
auto [front, back] = brush.clipToPlane(qvec3d(split.xyz()), split[3]);
auto [front, back] = brush.clipToPlane({ split.xyz(), split[3] });
SplitDifferentTexturedPartsOfBrush_R(bsp, front, out);
SplitDifferentTexturedPartsOfBrush_R(bsp, back, out);
@ -667,23 +658,14 @@ static std::string DecompileLeafTask(const mbsp_t *bsp, const leaf_decompile_tas
*/
decomp_plane_t MakeDecompPlane(const mbsp_t *bsp, const bsp2_dnode_t *node, const bool front)
{
decomp_plane_t result;
const dplane_t &dplane = *BSP_GetPlane(bsp, node->planenum);
result.node = node;
result.nodefront = front;
const dplane_t *dplane = BSP_GetPlane(bsp, node->planenum);
result.normal = qvec3d(dplane->normal[0], dplane->normal[1], dplane->normal[2]);
result.distance = static_cast<double>(dplane->dist);
// flip the plane if we went down the front side, since we want the outward-facing plane
if (front) {
result.normal = result.normal * -1.0;
result.distance = result.distance * -1.0;
}
return result;
return {
// flip the plane if we went down the front side, since we want the outward-facing plane
front ? -dplane : dplane,
node,
front
};
}
/**

View File

@ -910,7 +910,7 @@ struct lump_reader
buffer.reserve(length = (lump.filelen / lumpspec.size));
} else {
buffer.reserve(length = lump.filelen);
buffer.resize(length = lump.filelen);
}
if (!lump.filelen)

View File

@ -118,24 +118,19 @@ const qvec3f &Face_PointAtIndex(const mbsp_t *bsp, const mface_t *f, int v)
qvec3d Face_Normal(const mbsp_t *bsp, const mface_t *f)
{
return Face_Plane(bsp, f).normal();
return Face_Plane(bsp, f).normal;
}
qplane3d Face_Plane(const mbsp_t *bsp, const mface_t *f)
{
Q_assert(f->planenum >= 0 && f->planenum < bsp->dplanes.size());
const dplane_t *dplane = &bsp->dplanes[f->planenum];
qplane3d result = bsp->dplanes[f->planenum];
plane_t result;
if (f->side) {
result.normal = -dplane->normal;
result.dist = -dplane->dist;
} else {
result.normal = dplane->normal;
result.dist = dplane->dist;
return -result;
}
return {result.normal, result.dist};
return result;
}
const gtexinfo_t *Face_Texinfo(const mbsp_t *bsp, const mface_t *face)
@ -323,6 +318,36 @@ bool Light_PointInWorld(const mbsp_t *bsp, const qvec3d &point)
return Light_PointInSolid(bsp, &bsp->dmodels[0], point);
}
static std::vector<qplane3d> Face_AllocInwardFacingEdgePlanes(const mbsp_t *bsp, const mface_t *face)
{
std::vector<qplane3d> out;
out.reserve(face->numedges);
const qplane3d faceplane = Face_Plane(bsp, face);
for (int i = 0; i < face->numedges; i++) {
const qvec3d &v0 = GetSurfaceVertexPoint(bsp, face, i);
const qvec3d &v1 = GetSurfaceVertexPoint(bsp, face, (i + 1) % face->numedges);
qvec3d edgevec = qv::normalize(v1 - v0);
qvec3d normal = qv::cross(edgevec, faceplane.normal);
out.emplace_back(normal, DotProduct(normal, v0));
}
return out;
}
static bool EdgePlanes_PointInside(const std::vector<qplane3d> &edgeplanes, const qvec3d &point)
{
for (auto &plane : edgeplanes) {
const vec_t planedist = DotProduct(point, plane.normal) - plane.dist;
if (planedist < 0) {
return false;
}
}
return true;
}
static const mface_t *BSP_FindFaceAtPoint_r(
const mbsp_t *bsp, const int nodenum, const qvec3d &point, const qvec3d &wantedNormal)
{
@ -351,9 +376,8 @@ static const mface_t *BSP_FindFaceAtPoint_r(
}
// Next test if it's within the boundaries of the face
plane_t *edgeplanes = Face_AllocInwardFacingEdgePlanes(bsp, face);
const bool insideFace = EdgePlanes_PointInside(face, edgeplanes, point);
delete[] edgeplanes;
auto edgeplanes = Face_AllocInwardFacingEdgePlanes(bsp, face);
const bool insideFace = EdgePlanes_PointInside(edgeplanes, point);
// Found a match?
if (insideFace) {
@ -376,37 +400,6 @@ const mface_t *BSP_FindFaceAtPoint(
return BSP_FindFaceAtPoint_r(bsp, model->headnode[0], point, wantedNormal);
}
plane_t *Face_AllocInwardFacingEdgePlanes(const mbsp_t *bsp, const mface_t *face)
{
plane_t *out = new plane_t[face->numedges];
const qplane3d faceplane = Face_Plane(bsp, face);
for (int i = 0; i < face->numedges; i++) {
plane_t *dest = &out[i];
const qvec3d &v0 = GetSurfaceVertexPoint(bsp, face, i);
const qvec3d &v1 = GetSurfaceVertexPoint(bsp, face, (i + 1) % face->numedges);
qvec3d edgevec = qv::normalize(v1 - v0);
CrossProduct(edgevec, faceplane.normal(), dest->normal);
dest->dist = DotProduct(dest->normal, v0);
}
return out;
}
bool EdgePlanes_PointInside(const mface_t *face, const plane_t *edgeplanes, const qvec3d &point)
{
for (int i = 0; i < face->numedges; i++) {
const vec_t planedist = DotProduct(point, edgeplanes[i].normal) - edgeplanes[i].dist;
if (planedist < 0) {
return false;
}
}
return true;
}
// glm stuff
std::vector<qvec3f> GLM_FacePoints(const mbsp_t *bsp, const mface_t *face)
{

View File

@ -287,7 +287,7 @@ long LoadFile(const std::filesystem::path &filename, void *destptr)
{
uint8_t **bufferptr = static_cast<uint8_t **>(destptr);
qfile_t file = SafeOpenRead(filename);
qfile_t file = SafeOpenRead(filename, true);
long length = Sys_FileLength(file);

View File

@ -32,16 +32,6 @@ using namespace polylib;
const vec3_t vec3_origin = {0, 0, 0};
plane_t FlipPlane(plane_t input)
{
plane_t result;
VectorScale(input.normal, -1, result.normal);
result.dist = -input.dist;
return result;
}
qmat3x3d RotateAboutX(double t)
{
// https://en.wikipedia.org/wiki/Rotation_matrix#Examples
@ -424,7 +414,7 @@ std::pair<std::vector<qvec3f>, std::vector<qvec3f>> GLM_ClipPoly(const std::vect
winding_t w = winding_t::from_winding_points(poly);
auto clipped = w.clip(qvec3f(plane), plane[3]);
auto clipped = w.clip({ plane.xyz(), plane[3] });
return make_pair(
clipped[0].value_or(winding_t{}).glm_winding_points(), clipped[1].value_or(winding_t{}).glm_winding_points());

View File

@ -278,6 +278,11 @@ struct miptex_t
virtual ~miptex_t() { }
virtual size_t stream_size() const
{
return sizeof(dmiptex_t) + width * height / 64 * 85;
}
virtual void stream_read(std::istream &stream)
{
auto start = stream.tellg();
@ -291,7 +296,7 @@ struct miptex_t
height = dtex.height;
for (size_t g = 0; g < MIPLEVELS; g++) {
if (dtex.offsets[g] < 0) {
if (dtex.offsets[g] <= 0) {
continue;
}
@ -305,8 +310,6 @@ struct miptex_t
virtual void stream_write(std::ostream &stream) const
{
Q_assert((bool)data[0]);
std::array<char, 16> as_array{};
memcpy(as_array.data(), name.c_str(), name.size());
@ -315,12 +318,18 @@ struct miptex_t
uint32_t header_end = sizeof(dmiptex_t);
for (size_t i = 0; i < MIPLEVELS; i++) {
stream <= header_end;
header_end += (width >> i) * (height >> i);
if (data[i] <= 0) {
stream <= (uint32_t) 0;
} else {
stream <= header_end;
header_end += (width >> i) * (height >> i);
}
}
for (size_t i = 0; i < MIPLEVELS; i++) {
stream.write(reinterpret_cast<char *>(data[i].get()), (width >> i) * (height >> i));
if (data[i]) {
stream.write(reinterpret_cast<char *>(data[i].get()), (width >> i) * (height >> i));
}
}
}
};
@ -335,6 +344,11 @@ struct miptexhl_t : miptex_t
// convert miptex_t to miptexhl_t
miptexhl_t(miptex_t &&move) : miptex_t(std::forward<miptex_t &&>(move)) { }
virtual size_t stream_size() const
{
return miptex_t::stream_size() + sizeof(uint16_t) + palette.size();
}
virtual void stream_read(std::istream &stream)
{
miptex_t::stream_read(stream);
@ -350,7 +364,7 @@ struct miptexhl_t : miptex_t
{
miptex_t::stream_write(stream);
stream <= static_cast<uint16_t>(palette.size());
stream <= static_cast<uint16_t>(palette.size() / 3);
stream.write(reinterpret_cast<const char *>(palette.data()), palette.size());
}
@ -402,9 +416,12 @@ struct dmiptexlump_t
void stream_write(std::ostream &stream) const
{
auto p = (size_t) stream.tellp();
stream <= static_cast<int32_t>(textures.size());
const size_t header_size = sizeof(int32_t) + (sizeof(int32_t) * textures.size());
size_t miptex_offset = 0;
for (auto &texture : textures) {
@ -413,11 +430,19 @@ struct dmiptexlump_t
continue;
}
stream <= static_cast<int32_t>(header_size + miptex_offset);
miptex_offset += sizeof(dmiptex_t) + texture.width * texture.height / 64 * 85;
miptex_offset += texture.stream_size();
if (p + miptex_offset % 4) {
miptex_offset += 4 - ((p + miptex_offset) % 4);
}
}
for (auto &texture : textures) {
if (texture.name[0]) {
if (stream.tellp() % 4) {
stream.seekp(stream.tellp() + (4 - (stream.tellp() % 4)));
}
texture.stream_write(stream);
}
}
@ -443,12 +468,12 @@ struct rgba_miptex_t
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
struct dplane_t
struct dplane_t : qplane3f
{
qvec3f normal;
float dist;
int32_t type;
[[nodiscard]] constexpr dplane_t operator-() const { return { qplane3f::operator-(), type }; }
// serialize for streams
auto stream_data() { return std::tie(normal, dist, type); }
};

View File

@ -61,8 +61,6 @@ bool Light_PointInWorld(const mbsp_t *bsp, const qvec3d &point);
*/
const mface_t *BSP_FindFaceAtPoint(
const mbsp_t *bsp, const dmodelh2_t *model, const qvec3d &point, const qvec3d &wantedNormal);
plane_t *Face_AllocInwardFacingEdgePlanes(const mbsp_t *bsp, const mface_t *face);
bool EdgePlanes_PointInside(const mface_t *face, const plane_t *edgeplanes, const qvec3d &point);
const qvec3f &Face_PointAtIndex(const mbsp_t *bsp, const mface_t *f);
const qvec3f &Vertex_GetPos(const mbsp_t *bsp, int num);

View File

@ -41,10 +41,14 @@ using vec_t = double;
constexpr vec_t VECT_MAX = std::numeric_limits<vec_t>::max();
/*
* The quality of the bsp output is highly sensitive to these epsilon values.
*/
constexpr vec_t ZERO_TRI_AREA_EPSILON = 0.05;
constexpr vec_t POINT_EQUAL_EPSILON = 0.05;
constexpr vec_t NORMAL_EPSILON = 0.000001;
constexpr vec_t DIST_EPSILON = 0.0001;
constexpr vec_t DEGREES_EPSILON = 0.001;
constexpr vec_t DEFAULT_ON_EPSILON = 0.1;

View File

@ -21,7 +21,7 @@ constexpr size_t MAX_POINTS_ON_WINDING = 96;
constexpr vec_t DEFAULT_BOGUS_RANGE = 65536.0;
using winding_edges_t = std::vector<plane_t>;
using winding_edges_t = std::vector<qplane3d>;
inline bool PointInWindingEdges(const winding_edges_t &wi, const qvec3d &point)
{
@ -404,29 +404,22 @@ public:
*this = std::move(temp);
}
plane_t plane() const
qplane3d plane() const
{
plane_t p;
qvec3d v1 = at(0) - at(1);
qvec3d v2 = at(2) - at(1);
qvec3d normal = qv::normalize(qv::cross(v1, v2));
for (size_t i = 0; i < 3; i++)
p.normal[i] = normal[i];
p.dist = qv::dot(at(0), normal);
return p;
return { normal, qv::dot(at(0), normal) };
}
static winding_base_t from_plane(const qvec3d &normal, const vec_t &dist, const vec_t &worldextent)
static winding_base_t from_plane(const qplane3d &plane, const vec_t &worldextent)
{
/* find the major axis */
vec_t max = -VECT_MAX;
int32_t x = -1;
for (size_t i = 0; i < 3; i++) {
vec_t v = fabs(normal[i]);
vec_t v = fabs(plane.normal[i]);
if (v > max) {
x = i;
@ -445,12 +438,12 @@ public:
case 2: vup[0] = 1; break;
}
vec_t v = qv::dot(vup, normal);
vup += normal * -v;
vec_t v = qv::dot(vup, plane.normal);
vup += plane.normal * -v;
vup = qv::normalize(vup);
qvec3d org = normal * dist;
qvec3d vright = qv::cross(vup, normal);
qvec3d org = plane.normal * plane.dist;
qvec3d vright = qv::cross(vup, plane.normal);
vup *= worldextent;
vright *= worldextent;
@ -475,7 +468,7 @@ public:
if (a < 1)
FError("{} area", a);
plane_t face = plane();
qplane3d face = plane();
for (size_t i = 0; i < count; i++) {
const qvec3d &p1 = at(i);
@ -520,36 +513,34 @@ public:
winding_edges_t winding_edges() const
{
plane_t p = plane();
qplane3d p = plane();
winding_edges_t result(count);
winding_edges_t result;
result.reserve(count);
for (size_t i = 0; i < count; i++) {
plane_t &dest = result[i];
const qvec3d &v0 = at(i);
const qvec3d &v1 = at((i + 1) % count);
qvec3d edgevec = qv::normalize(v1 - v0);
qvec3d normal = qv::cross(edgevec, p.normal);
for (size_t i = 0; i < 3; i++)
dest.normal[i] = normal[i];
dest.dist = qv::dot(normal, v0);
result.emplace_back(normal, qv::dot(normal, v0));
}
return result;
}
// dists/sides must have (size() + 1) reserved
inline void calc_sides(const qvec3d &normal, const vec_t &dist, vec_t *dists, side_t *sides, int32_t counts[3],
inline void calc_sides(const qplane3d &plane, vec_t *dists, side_t *sides, int32_t counts[3],
const vec_t &on_epsilon = DEFAULT_ON_EPSILON) const
{
/* determine sides for each point */
size_t i;
for (i = 0; i < count; i++) {
vec_t dot = qv::dot(at(i), normal);
dot -= dist;
vec_t dot = qv::dot(at(i), plane.normal);
dot -= plane.dist;
dists[i] = dot;
@ -576,14 +567,14 @@ public:
it will be clipped away.
==================
*/
std::array<std::optional<winding_base_t>, 2> clip(const qvec3d &normal, const vec_t &dist,
std::array<std::optional<winding_base_t>, 2> clip(const qplane3d &plane,
const vec_t &on_epsilon = DEFAULT_ON_EPSILON, const bool &keepon = false) const
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (count + 1));
side_t *sides = (side_t *)alloca(sizeof(side_t) * (count + 1));
int counts[3]{};
calc_sides(normal, dist, dists, sides, counts, on_epsilon);
calc_sides(plane, dists, sides, counts, on_epsilon);
if (keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK])
return {*this, std::nullopt};
@ -618,10 +609,10 @@ public:
qvec3d mid;
for (size_t j = 0; j < 3; j++) { /* avoid round off error when possible */
if (normal[j] == 1)
mid[j] = dist;
else if (normal[j] == -1)
mid[j] = -dist;
if (plane.normal[j] == 1)
mid[j] = plane.dist;
else if (plane.normal[j] == -1)
mid[j] = -plane.dist;
else
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
}
@ -636,16 +627,6 @@ public:
return {std::move(results[SIDE_FRONT]), std::move(results[SIDE_BACK])};
}
std::optional<winding_base_t> chop(
const qvec3d &normal, const vec_t &dist, const vec_t &on_epsilon = DEFAULT_ON_EPSILON)
{
auto clipped = clip(normal, dist, on_epsilon);
clear();
return clipped[0];
}
using save_fn_t = void (*)(winding_base_t &w, void *userinfo);
void dice(vec_t subdiv, save_fn_t save_fn, void *userinfo)
@ -670,10 +651,10 @@ public:
//
// split the winding
//
qvec3d split{};
split[i] = 1;
vec_t dist = subdiv * (1 + floor((b.mins()[i] + 1) / subdiv));
auto clipped = clip(split, dist);
qplane3d split{};
split.normal[i] = 1;
split.dist = subdiv * (1 + floor((b.mins()[i] + 1) / subdiv));
auto clipped = clip(split);
clear();
//

View File

@ -379,12 +379,17 @@ template<typename T>
return fmt::format("{}", v1);
}
template<typename T>
[[nodiscard]] bool epsilonEqual(const T &v1, const T &v2, T epsilon)
{
return fabs(v1 - v2) <= epsilon;
}
template<size_t N, class T>
[[nodiscard]] bool epsilonEqual(const qvec<T, N> &v1, const qvec<T, N> &v2, T epsilon)
{
for (size_t i = 0; i < N; i++) {
T diff = v1[i] - v2[i];
if (fabs(diff) > epsilon)
if (!epsilonEqual(v1[i], v2[i], epsilon))
return false;
}
return true;
@ -393,11 +398,7 @@ template<size_t N, class T>
template<size_t N, class T>
[[nodiscard]] bool epsilonEmpty(const qvec<T, N> &v1, T epsilon)
{
for (size_t i = 0; i < N; i++) {
if (fabs(v1[i]) > epsilon)
return false;
}
return true;
return epsilonEqual({}, v1, epsilon);
}
template<size_t N, class T>
@ -571,21 +572,21 @@ using qvec3s = qvec<int16_t, 3>;
template<class T>
class qplane3
{
public:
qvec<T, 3> normal;
T dist;
constexpr qplane3() = default;
constexpr qplane3(const qvec<T, 3> &normal, const T &dist) : normal(normal), dist(dist) { }
// convert from plane of a different type
template<typename T2>
constexpr qplane3(const qplane3<T2> &plane) : qplane3(plane.normal, static_cast<T2>(plane.dist)) { }
private:
qvec<T, 3> m_normal;
T m_dist;
auto as_tuple() const { return std::tie(normal, dist); }
public:
inline qplane3() = default;
constexpr qplane3(const qvec<T, 3> &normal, const T &dist) : m_normal(normal), m_dist(dist) { }
template<typename T2>
constexpr qplane3(const qplane3<T2> &plane) : qplane3(plane.normal(), plane.dist())
{
}
auto as_tuple() const { return std::tie(m_normal, m_dist); }
// Sort support
[[nodiscard]] constexpr bool operator<(const qplane3 &other) const { return as_tuple() < other.as_tuple(); }
[[nodiscard]] constexpr bool operator<=(const qplane3 &other) const { return as_tuple() <= other.as_tuple(); }
@ -594,19 +595,29 @@ public:
[[nodiscard]] constexpr bool operator==(const qplane3 &other) const { return as_tuple() == other.as_tuple(); }
[[nodiscard]] constexpr bool operator!=(const qplane3 &other) const { return as_tuple() != other.as_tuple(); }
[[nodiscard]] inline T distAbove(const qvec<T, 3> &pt) const { return qv::dot(pt, m_normal) - m_dist; }
[[nodiscard]] constexpr const qvec<T, 3> &normal() const { return m_normal; }
[[nodiscard]] constexpr const T dist() const { return m_dist; }
[[nodiscard]] inline T distAbove(const qvec<T, 3> &pt) const { return qv::dot(pt, normal) - dist; }
[[nodiscard]] constexpr const qvec<T, 4> vec4() const
{
return qvec<T, 4>(m_normal[0], m_normal[1], m_normal[2], m_dist);
return qvec<T, 4>(normal[0], normal[1], normal[2], dist);
}
[[nodiscard]] constexpr qplane3 operator-() const { return { -normal, -dist }; }
};
using qplane3f = qplane3<float>;
using qplane3d = qplane3<double>;
namespace qv
{
template<typename T>
[[nodiscard]] bool epsilonEqual(const qplane3<T> &p1, const qplane3<T> &p2, T normalEpsilon = NORMAL_EPSILON, T distEpsilon = DIST_EPSILON)
{
return epsilonEqual(p1.normal, p2.normal, normalEpsilon) &&
epsilonEqual(p1.dist, p2.dist, distEpsilon);
}
}
/**
* Row x Col matrix of T.
*/
@ -797,12 +808,6 @@ namespace qv
// "vec3" type. legacy; eventually will be replaced entirely
using vec3_t = vec_t[3];
struct plane_t
{
qvec3d normal;
vec_t dist;
};
extern const vec3_t vec3_origin;
template<typename T1, typename T2>
@ -885,8 +890,6 @@ constexpr void VectorClear(T &out)
out[2] = 0;
}
plane_t FlipPlane(plane_t input);
template<typename Ta, typename Tb, typename Tc>
constexpr void VectorMA(const Ta &va, vec_t scale, const Tb &vb, Tc &vc)
{

View File

@ -112,7 +112,7 @@ struct lightsurf_t
vec3_t minlight_color;
bool nodirt;
plane_t plane;
qplane3d plane;
vec3_t snormal;
vec3_t tnormal;
@ -174,7 +174,9 @@ enum debugmode_t
debugmode_bounce,
debugmode_bouncelights,
debugmode_debugoccluded,
debugmode_debugneighbours
debugmode_debugneighbours,
debugmode_phong_tangents,
debugmode_phong_bitangents
};
extern debugmode_t debugmode;

View File

@ -32,7 +32,7 @@ void Embree_TraceInit(const mbsp_t *bsp);
hitresult_t Embree_TestSky(const qvec3d &start, const qvec3d &dirn, const modelinfo_t *self, const mface_t **face_out);
hitresult_t Embree_TestLight(const qvec3d &start, const qvec3d &stop, const modelinfo_t *self);
hittype_t Embree_DirtTrace(const qvec3d &start, const qvec3d &dirn, vec_t dist, const modelinfo_t *self,
vec_t *hitdist_out, plane_t *hitplane_out, const mface_t **face_out);
vec_t *hitdist_out, qplane3d *hitplane_out, const mface_t **face_out);
raystream_occlusion_t *Embree_MakeOcclusionRayStream(int maxrays);
raystream_intersection_t *Embree_MakeIntersectionRayStream(int maxrays);

View File

@ -35,7 +35,7 @@ struct brush_t
class mapbrush_t;
plane_t Face_Plane(const face_t *face);
qplane3d Face_Plane(const face_t *face);
int Brush_ListCountWithCFlags(const brush_t *brush, int cflags);
int Brush_ListCount(const brush_t *brush);
@ -52,15 +52,6 @@ brush_t *LoadBrush(const mapentity_t *src, const mapbrush_t *mapbrush, const con
const qvec3d &rotate_offset, const rotation_t rottype, const int hullnum);
void FreeBrushes(mapentity_t *ent);
int FindPlane(const qvec3d &normal, const vec_t dist, int *side);
bool PlaneEqual(const plane_t *p1, const plane_t *p2);
bool PlaneInvEqual(const plane_t *p1, const plane_t *p2);
bool BoundBrush(brush_t *brush);
vec_t BrushVolume(const brush_t *brush);
int BrushMostlyOnSide(const brush_t *brush, const qvec3d &normal, vec_t dist);
void SplitBrush(const brush_t *brush, int planenum, int planeside, brush_t **front, brush_t **back);
void FilterStructuralBrushesIntoTree(const mapentity_t *e, node_t *headnode);
int FindPlane(const qplane3d &plane, int *side);
void FreeBrush(brush_t *brush);

View File

@ -26,5 +26,5 @@ extern int csgmergefaces;
// build surfaces is also used by GatherNodeFaces
surface_t *BuildSurfaces(const std::map<int, face_t *> &planefaces);
face_t *NewFaceFromFace(face_t *in);
void SplitFace(face_t *in, const qbsp_plane_t *split, face_t **front, face_t **back);
void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back);
void UpdateFaceSphere(face_t *in);

View File

@ -29,6 +29,14 @@
#include <utility>
#include <unordered_map>
struct qbsp_plane_t : qplane3d
{
int type = 0;
std::optional<size_t> outputplanenum = std::nullopt; // only valid after ExportNodePlanes
[[nodiscard]] constexpr qbsp_plane_t operator-() const { return { qplane3d::operator-(), type }; }
};
struct mapface_t
{
qbsp_plane_t plane { };

View File

@ -82,7 +82,6 @@ constexpr int32_t PLANENUM_LEAF = -1;
* ( TODO: re-check if CONTINUOUS_EPSILON is still directly related )
*/
#define ANGLEEPSILON 0.000001
#define DIST_EPSILON 0.0001
#define ZERO_EPSILON 0.0001
#define DISTEPSILON 0.0001
#define POINT_EPSILON 0.0001
@ -176,7 +175,6 @@ struct node_t
// information for decision nodes
int planenum; // -1 = leaf node
// outputplanenum moved to qbsp_plane_t
int firstface; // decision node only
int numfaces; // decision node only
node_t *children[2]; // children[0] = front side, children[1] = back side of plane. only valid for decision nodes

View File

@ -26,6 +26,5 @@
extern std::atomic<int> splitnodes;
void DetailToSolid(node_t *node);
void DivideFacet(face_t *in, qbsp_plane_t *split, face_t **front, face_t **back);
void CalcSurfaceInfo(surface_t *surf);
void SubdivideFace(face_t *f, face_t **prevptr);

View File

@ -22,14 +22,7 @@
#pragma once
#include "common/polylib.hh"
#include <optional>
struct qbsp_plane_t : plane_t
{
int type;
std::optional<size_t> outputplanenum; // only valid after ExportNodePlanes
};
using winding_t = polylib::winding_base_t<MAXEDGES>;
winding_t BaseWindingForPlane(const qbsp_plane_t *p);
winding_t BaseWindingForPlane(const qplane3d &p);

View File

@ -43,7 +43,7 @@ enum pstatus_t
struct portal_t
{
plane_t plane; // normal pointing into neighbor
qplane3d plane; // normal pointing into neighbor
int leaf; // neighbor
std::shared_ptr<struct winding_t> winding;
pstatus_t status;
@ -123,7 +123,7 @@ struct winding_t : polylib::winding_base_t<MAX_WINDING_FIXED>
struct sep_t
{
sep_t *next;
plane_t plane; // from portal is on positive side
qplane3d plane; // from portal is on positive side
};
struct passage_t
@ -153,15 +153,15 @@ struct pstack_t
portal_t *portal; // portal exiting
std::shared_ptr<winding_t> source, pass;
std::shared_ptr<winding_t> windings[STACK_WINDINGS]; // Fixed size windings
plane_t portalplane;
qplane3d portalplane;
leafbits_t *mightsee; // bit string
plane_t separators[2][MAX_SEPARATORS]; /* Separator cache */
qplane3d separators[2][MAX_SEPARATORS]; /* Separator cache */
int numseparators[2];
};
std::shared_ptr<winding_t> &AllocStackWinding(pstack_t *stack);
void FreeStackWinding(std::shared_ptr<winding_t> &w, pstack_t *stack);
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, plane_t *split);
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, qplane3d *split);
struct threaddata_t
{

View File

@ -55,7 +55,7 @@ public:
winding_t w;
vec3_t center;
vec3_t samplepoint; // 1 unit above center
plane_t plane;
qplane3d plane;
std::map<int, qvec3f> lightByStyle;
};
@ -203,7 +203,7 @@ static void *MakeBounceLightsThread(void *arg)
continue;
}
plane_t faceplane = winding.plane();
qplane3d faceplane = winding.plane();
qvec3d facemidpoint = winding.center();
facemidpoint += faceplane.normal; // lift 1 unit

View File

@ -935,6 +935,46 @@ static inline void WriteNormals(const mbsp_t &bsp, bspdata_t &bspdata)
}
bspdata.bspx.transfer("FACENORMALS", data, data_size);
ofstream obj("test.obj");
size_t index_id = 1;
for (auto &face : bsp.dfaces) {
auto &cache = FaceCacheForFNum(&face - bsp.dfaces.data());
/*bool keep = true;
for (size_t i = 0; i < cache.points().size(); i++) {
auto &pt = cache.points()[i];
if (qv::distance(pt, { -208, 6, 21 }) > 256) {
keep = false;
break;
}
}
if (!keep) {
continue;
}*/
for (size_t i = 0; i < cache.points().size(); i++) {
auto &pt = cache.points()[i];
auto &n = cache.normals()[i];
fmt::print(obj, "v {}\n", pt);
fmt::print(obj, "vn {}\n", n.normal);
}
for (size_t i = 1; i < cache.points().size() - 1; i++) {
size_t n1 = 0;
size_t n2 = i;
size_t n3 = (i + 1) % cache.points().size();
fmt::print(obj, "f {0}//{0} {1}//{1} {2}//{2}\n", index_id + n1, index_id + n2, index_id + n3);
}
index_id += cache.points().size();
}
}
/*

View File

@ -115,7 +115,7 @@ faceextents_t::faceextents_t(const mface_t *face, const mbsp_t *bsp, float lmsca
" surface {}, {} extents = {}, scale = {}\n"
" texture {} at ({})\n"
" surface normal ({})\n",
Face_GetNum(bsp, face), i ? "t" : "s", m_texsize[i], m_lightmapscale, texname, point, plane.normal());
Face_GetNum(bsp, face), i ? "t" : "s", m_texsize[i], m_lightmapscale, texname, point, plane.normal);
}
}
}
@ -211,10 +211,10 @@ qmat4x4f WorldToTexSpace(const mbsp_t *bsp, const mface_t *f)
// [?]
qmat4x4f T{
tex->vecs.at(0, 0), tex->vecs.at(1, 0), static_cast<float>(plane.normal()[0]), 0, // col 0
tex->vecs.at(0, 1), tex->vecs.at(1, 1), static_cast<float>(plane.normal()[1]), 0, // col 1
tex->vecs.at(0, 2), tex->vecs.at(1, 2), static_cast<float>(plane.normal()[2]), 0, // col 2
tex->vecs.at(0, 3), tex->vecs.at(1, 3), static_cast<float>(-plane.dist()), 1 // col 3
tex->vecs.at(0, 0), tex->vecs.at(1, 0), static_cast<float>(plane.normal[0]), 0, // col 0
tex->vecs.at(0, 1), tex->vecs.at(1, 1), static_cast<float>(plane.normal[1]), 0, // col 1
tex->vecs.at(0, 2), tex->vecs.at(1, 2), static_cast<float>(plane.normal[2]), 0, // col 2
tex->vecs.at(0, 3), tex->vecs.at(1, 3), static_cast<float>(-plane.dist), 1 // col 3
};
return T;
}
@ -758,12 +758,11 @@ static bool Lightsurf_Init(
}
/* Set up the plane, not including model offset */
plane_t *plane = &lightsurf->plane;
qplane3d *plane = &lightsurf->plane;
VectorCopy(bsp->dplanes[face->planenum].normal, plane->normal);
plane->dist = bsp->dplanes[face->planenum].dist;
if (face->side) {
VectorSubtract(vec3_origin, plane->normal, plane->normal);
plane->dist = -plane->dist;
*plane = -*plane;
}
/* Set up the texorg for coordinate transformation */
@ -1405,7 +1404,7 @@ static void LightFace_Entity(
{
const globalconfig_t &cfg = *lightsurf->cfg;
const modelinfo_t *modelinfo = lightsurf->modelinfo;
const plane_t *plane = &lightsurf->plane;
const qplane3d *plane = &lightsurf->plane;
const float planedist = DotProduct(entity->origin.vec3Value(), plane->normal) - plane->dist;
@ -1518,7 +1517,7 @@ static void LightFace_Sky(const sun_t *sun, const lightsurf_t *lightsurf, lightm
{
const globalconfig_t &cfg = *lightsurf->cfg;
const modelinfo_t *modelinfo = lightsurf->modelinfo;
const plane_t *plane = &lightsurf->plane;
const qplane3d *plane = &lightsurf->plane;
// FIXME: Normalized sun vector should be stored in the sun_t. Also clarify which way the vector points (towards or
// away..)

View File

@ -423,17 +423,12 @@ static void Embree_FilterFuncN(const struct RTCFilterFunctionNArguments *args)
// building faces for skip-textured bmodels
plane_t Node_Plane(const mbsp_t *bsp, const bsp2_dnode_t *node, bool side)
qplane3d Node_Plane(const mbsp_t *bsp, const bsp2_dnode_t *node, bool side)
{
const dplane_t *dplane = &bsp->dplanes[node->planenum];
plane_t plane;
VectorCopy(dplane->normal, plane.normal);
plane.dist = dplane->dist;
qplane3d plane = bsp->dplanes[node->planenum];
if (side) {
VectorScale(plane.normal, -1, plane.normal);
plane.dist *= -1.0f;
return -plane;
}
return plane;
@ -443,22 +438,20 @@ plane_t Node_Plane(const mbsp_t *bsp, const bsp2_dnode_t *node, bool side)
* `planes` all of the node planes that bound this leaf, facing inward.
*/
static void Leaf_MakeFaces(
const mbsp_t *bsp, const mleaf_t *leaf, const std::vector<plane_t> &planes, std::vector<winding_t> &result)
const mbsp_t *bsp, const mleaf_t *leaf, const std::vector<qplane3d> &planes, std::vector<winding_t> &result)
{
for (const plane_t &plane : planes) {
for (const qplane3d &plane : planes) {
// flip the inward-facing split plane to get the outward-facing plane of the face we're constructing
plane_t faceplane;
VectorScale(plane.normal, -1, faceplane.normal);
faceplane.dist = -plane.dist;
qplane3d faceplane = -plane;
std::optional<winding_t> winding = winding_t::from_plane(faceplane.normal, faceplane.dist, 10e6);
std::optional<winding_t> winding = winding_t::from_plane(faceplane, 10e6);
// clip `winding` by all of the other planes
for (const plane_t &plane2 : planes) {
for (const qplane3d &plane2 : planes) {
if (&plane2 == &plane)
continue;
auto clipped = winding->clip(plane2.normal, plane2.dist);
auto clipped = winding->clip(plane2);
// discard the back, continue clipping the front part
winding = clipped[0];
@ -476,7 +469,7 @@ static void Leaf_MakeFaces(
}
}
void MakeFaces_r(const mbsp_t *bsp, const int nodenum, std::vector<plane_t> *planes, std::vector<winding_t> &result)
void MakeFaces_r(const mbsp_t *bsp, const int nodenum, std::vector<qplane3d> *planes, std::vector<winding_t> &result)
{
if (nodenum < 0) {
const int leafnum = -nodenum - 1;
@ -492,21 +485,19 @@ void MakeFaces_r(const mbsp_t *bsp, const int nodenum, std::vector<plane_t> *pla
const bsp2_dnode_t *node = &bsp->dnodes[nodenum];
// go down the front side
const plane_t front = Node_Plane(bsp, node, false);
planes->push_back(front);
planes->push_back(Node_Plane(bsp, node, false));
MakeFaces_r(bsp, node->children[0], planes, result);
planes->pop_back();
// go down the back side
const plane_t back = Node_Plane(bsp, node, true);
planes->push_back(back);
planes->push_back(Node_Plane(bsp, node, true));
MakeFaces_r(bsp, node->children[1], planes, result);
planes->pop_back();
}
static void MakeFaces(const mbsp_t *bsp, const dmodelh2_t *model, std::vector<winding_t> &result)
{
std::vector<plane_t> planes;
std::vector<qplane3d> planes;
MakeFaces_r(bsp, model->headnode[0], &planes, result);
Q_assert(planes.empty());
}
@ -725,7 +716,7 @@ hitresult_t Embree_TestSky(const qvec3d &start, const qvec3d &dirn, const modeli
// public
hittype_t Embree_DirtTrace(const qvec3d &start, const qvec3d &dirn, vec_t dist, const modelinfo_t *self,
vec_t *hitdist_out, plane_t *hitplane_out, const mface_t **face_out)
vec_t *hitdist_out, qplane3d *hitplane_out, const mface_t **face_out)
{
RTCRayHit ray = SetupRay(0, start, dirn, dist);
ray_source_info ctx2(nullptr, self);

File diff suppressed because it is too large Load Diff

View File

@ -111,7 +111,7 @@ SplitFace
Frees in.
==================
*/
void SplitFace(face_t *in, const qbsp_plane_t *split, face_t **front, face_t **back)
void SplitFace(face_t *in, const qplane3d &split, face_t **front, face_t **back)
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (in->w.size() + 1));
side_t *sides = (side_t *)alloca(sizeof(side_t) * (in->w.size() + 1));
@ -125,7 +125,7 @@ void SplitFace(face_t *in, const qbsp_plane_t *split, face_t **front, face_t **b
Error("Attempting to split freed face");
/* Fast test */
dot = DotProduct(in->origin, split->normal) - split->dist;
dot = DotProduct(in->origin, split.normal) - split.dist;
if (dot > in->radius) {
counts[SIDE_FRONT] = 1;
counts[SIDE_BACK] = 0;
@ -133,7 +133,7 @@ void SplitFace(face_t *in, const qbsp_plane_t *split, face_t **front, face_t **b
counts[SIDE_FRONT] = 0;
counts[SIDE_BACK] = 1;
} else {
in->w.calc_sides(split->normal, split->dist, dists, sides, counts, ON_EPSILON);
in->w.calc_sides(split, dists, sides, counts, ON_EPSILON);
}
// Plane doesn't split this face after all
@ -177,10 +177,10 @@ void SplitFace(face_t *in, const qbsp_plane_t *split, face_t **front, face_t **b
dot = dists[i] / (dists[i] - dists[i + 1]);
for (j = 0; j < 3; j++) { // avoid round off error when possible
if (split->normal[j] == 1)
mid[j] = split->dist;
else if (split->normal[j] == -1)
mid[j] = -split->dist;
if (split.normal[j] == 1)
mid[j] = split.dist;
else if (split.normal[j] == -1)
mid[j] = -split.dist;
else
mid[j] = p1[j] + dot * (p2[j] - p1[j]);
}
@ -216,10 +216,9 @@ static void RemoveOutsideFaces(const brush_t *brush, face_t **inside, face_t **o
for (const face_t *clipface = brush->faces; clipface; clipface = clipface->next) {
qbsp_plane_t clipplane = map.planes[clipface->planenum];
if (!clipface->planeside) {
VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal);
clipplane.dist = -clipplane.dist;
clipplane = -clipplane;
}
w = w->clip(clipplane.normal, clipplane.dist, ON_EPSILON, true)[SIDE_FRONT];
w = w->clip(clipplane, ON_EPSILON, true)[SIDE_FRONT];
if (!w)
break;
}
@ -248,9 +247,8 @@ Faces exactly on the plane will stay inside unless overdrawn by later brush
static void ClipInside(const face_t *clipface, bool precedence, face_t **inside, face_t **outside)
{
face_t *face, *next, *frags[2];
const qbsp_plane_t *splitplane;
splitplane = &map.planes[clipface->planenum];
const qbsp_plane_t &splitplane = map.planes[clipface->planenum];
face = *inside;
*inside = NULL;
@ -265,7 +263,7 @@ static void ClipInside(const face_t *clipface, bool precedence, face_t **inside,
vec_t *dists = (vec_t *)malloc(sizeof(vec_t) * (face->w.size() + 1));
side_t *sides = (side_t *)malloc(sizeof(side_t) * (face->w.size() + 1));
int counts[3]{};
face->w.calc_sides(splitplane->normal, splitplane->dist, dists, sides, counts, ON_EPSILON);
face->w.calc_sides(splitplane, dists, sides, counts, ON_EPSILON);
free(dists);
free(sides);
@ -276,8 +274,8 @@ static void ClipInside(const face_t *clipface, bool precedence, face_t **inside,
/* Handle exactly on-plane faces */
if (face->planenum == clipface->planenum || spurious_onplane) {
const plane_t faceplane = Face_Plane(face);
const plane_t clipfaceplane = Face_Plane(clipface);
const qplane3d faceplane = Face_Plane(face);
const qplane3d clipfaceplane = Face_Plane(clipface);
const vec_t dp = DotProduct(faceplane.normal, clipfaceplane.normal);
const bool opposite = (dp < 0);

View File

@ -1651,12 +1651,12 @@ 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 (PlaneEqual(&check.plane, &face->plane)) {
if (qv::epsilonEqual(check.plane, face->plane)) {
LogPrint("line {}: Brush with duplicate plane", parser.linenum);
discardFace = true;
continue;
}
if (PlaneInvEqual(&check.plane, &face->plane)) {
if (qv::epsilonEqual(-check.plane, face->plane)) {
/* FIXME - this is actually an invalid brush */
LogPrint("line {}: Brush with duplicate plane", parser.linenum);
continue;
@ -2296,12 +2296,12 @@ void WriteBspBrushMap(const std::filesystem::path &name, const std::vector<const
for (const face_t *face = brush->faces; face; face = face->next) {
// FIXME: Factor out this mess
qbsp_plane_t plane = map.planes.at(face->planenum);
if (face->planeside) {
VectorScale(plane.normal, -1, plane.normal);
plane.dist = -plane.dist;
plane = -plane;
}
winding_t w = BaseWindingForPlane(&plane);
winding_t w = BaseWindingForPlane(plane);
fmt::print(f, "( {} ) ", w[0]);
fmt::print(f, "( {} ) ", w[1]);

View File

@ -100,7 +100,7 @@ static face_t *TryMerge(face_t *f1, face_t *f2)
plane = &map.planes[f1->planenum];
VectorCopy(plane->normal, planenormal);
if (f1->planeside)
VectorSubtract(vec3_origin, planenormal, planenormal);
VectorInverse(planenormal);
back = f1->w[(i + f1->w.size() - 1) % f1->w.size()];
VectorSubtract(p1, back, delta);

View File

@ -102,7 +102,7 @@ static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool cluster
std::optional<winding_t> w;
const qbsp_plane_t *pl;
int i, front, back;
plane_t plane2;
qplane3d plane2;
if (node->planenum != PLANENUM_LEAF && !node->detail_separator) {
WritePortals_r(node->children[0], portalFile, clusters);
@ -356,7 +356,7 @@ static void MakeHeadnodePortals(const mapentity_t *entity, node_t *node)
{
int i, j, n;
portal_t *p, *portals[6];
qbsp_plane_t bplanes[6], *pl;
qbsp_plane_t bplanes[6];
int side;
// pad with some space so there will never be null volume leafs
@ -375,16 +375,16 @@ static void MakeHeadnodePortals(const mapentity_t *entity, node_t *node)
p = new portal_t{};
portals[n] = p;
pl = &bplanes[n];
memset(pl, 0, sizeof(*pl));
qplane3d &pl = bplanes[n] = {};
if (j) {
pl->normal[i] = -1;
pl->dist = -bounds[j][i];
pl.normal[i] = -1;
pl.dist = -bounds[j][i];
} else {
pl->normal[i] = 1;
pl->dist = bounds[j][i];
pl.normal[i] = 1;
pl.dist = bounds[j][i];
}
p->planenum = FindPlane(pl->normal, pl->dist, &side);
p->planenum = FindPlane(pl, &side);
p->winding = BaseWindingForPlane(pl);
if (side)
@ -399,7 +399,7 @@ static void MakeHeadnodePortals(const mapentity_t *entity, node_t *node)
if (j == i)
continue;
portals[i]->winding =
portals[i]->winding->clip(bplanes[j].normal, bplanes[j].dist, ON_EPSILON, true)[SIDE_FRONT];
portals[i]->winding->clip(bplanes[j], ON_EPSILON, true)[SIDE_FRONT];
}
}
}
@ -496,7 +496,6 @@ CutNodePortals_r
*/
static void CutNodePortals_r(node_t *node, portal_state_t *state)
{
const qbsp_plane_t *plane;
qbsp_plane_t clipplane;
node_t *front, *back, *other_node;
portal_t *portal, *new_portal, *next_portal;
@ -514,7 +513,7 @@ static void CutNodePortals_r(node_t *node, portal_state_t *state)
if (node->detail_separator)
return;
plane = &map.planes[node->planenum];
const qbsp_plane_t &plane = map.planes[node->planenum];
front = node->children[SIDE_FRONT];
back = node->children[SIDE_BACK];
@ -531,13 +530,12 @@ static void CutNodePortals_r(node_t *node, portal_state_t *state)
if (portal->nodes[0] == node)
side = SIDE_FRONT;
else if (portal->nodes[1] == node) {
clipplane.dist = -clipplane.dist;
VectorSubtract(vec3_origin, clipplane.normal, clipplane.normal);
clipplane = -clipplane;
side = SIDE_BACK;
} else
FError("Mislinked portal");
winding = winding->clip(clipplane.normal, clipplane.dist, ON_EPSILON, true)[SIDE_FRONT];
winding = winding->clip(clipplane, ON_EPSILON, true)[SIDE_FRONT];
if (!winding) {
FLogPrint("WARNING: New portal was clipped away near ({:.3} {:.3} {:.3})\n", portal->winding->at(0)[0],
portal->winding->at(0)[1], portal->winding->at(0)[2]);
@ -566,7 +564,7 @@ static void CutNodePortals_r(node_t *node, portal_state_t *state)
RemovePortalFromNode(portal, portal->nodes[1]);
/* cut the portal into two portals, one on each side of the cut plane */
auto windings = portal->winding->clip(plane->normal, plane->dist, ON_EPSILON);
auto windings = portal->winding->clip(plane, ON_EPSILON);
if (!windings[SIDE_FRONT]) {
if (side == SIDE_FRONT)

View File

@ -127,10 +127,7 @@ static std::vector<std::tuple<size_t, face_t *>> AddBrushBevels(const brush_t *b
int32_t planenum = f->planenum;
if (f->planeside) {
auto flipped = map.planes[f->planenum];
flipped.dist = -flipped.dist;
VectorInverse(flipped.normal);
planenum = FindPlane(flipped.normal, flipped.dist, nullptr);
planenum = FindPlane(-map.planes[f->planenum], nullptr);
}
int32_t outputplanenum = ExportMapPlane(planenum);
@ -152,15 +149,14 @@ static std::vector<std::tuple<size_t, face_t *>> AddBrushBevels(const brush_t *b
if (i == planes.size()) {
// add a new side
plane_t new_plane;
VectorClear(new_plane.normal);
qplane3d new_plane { };
new_plane.normal[axis] = dir;
if (dir == 1)
new_plane.dist = b->bounds.maxs()[axis];
else
new_plane.dist = -b->bounds.mins()[axis];
int32_t planenum = FindPlane(new_plane.normal, new_plane.dist, nullptr);
int32_t planenum = FindPlane(new_plane, nullptr);
int32_t outputplanenum = ExportMapPlane(planenum);
planes.emplace_back(outputplanenum, b->faces);
}
@ -206,7 +202,7 @@ static std::vector<std::tuple<size_t, face_t *>> AddBrushBevels(const brush_t *b
// construct a plane
VectorClear(vec2);
vec2[axis] = dir;
plane_t current;
qplane3d current;
CrossProduct(vec, vec2, current.normal);
if (VectorNormalize(current.normal) < 0.5)
continue;
@ -218,17 +214,10 @@ static std::vector<std::tuple<size_t, face_t *>> AddBrushBevels(const brush_t *b
// behind this plane, it is a proper edge bevel
for (f = b->faces; f; f = f->next) {
auto &plane = map.planes[f->planenum];
plane_t temp;
VectorCopy(plane.normal, temp.normal);
temp.dist = plane.dist;
if (f->planeside) {
temp.dist = -temp.dist;
VectorInverse(temp.normal);
}
qplane3d temp = f->planeside ? -plane : plane;
// if this plane has allready been used, skip it
if (PlaneEqual(&current, &temp))
if (qv::epsilonEqual(current, temp))
break;
auto &w2 = f->w;
@ -248,7 +237,7 @@ static std::vector<std::tuple<size_t, face_t *>> AddBrushBevels(const brush_t *b
continue; // wasn't part of the outer hull
// add this plane
int32_t planenum = FindPlane(current.normal, current.dist, nullptr);
int32_t planenum = FindPlane(current, nullptr);
int32_t outputplanenum = ExportMapPlane(planenum);
planes.emplace_back(outputplanenum, b->faces);
}
@ -494,9 +483,9 @@ static void EmitAreaPortals(node_t *headnode)
}
#endif
winding_t BaseWindingForPlane(const qbsp_plane_t *p)
winding_t BaseWindingForPlane(const qplane3d &p)
{
return winding_t::from_plane(p->normal, p->dist, options.worldExtent);
return winding_t::from_plane(p, options.worldExtent);
}
/*

View File

@ -99,22 +99,22 @@ FaceSide
For BSP hueristic
==================
*/
static int FaceSide__(const face_t *in, const qbsp_plane_t *split)
static int FaceSide__(const face_t *in, const qbsp_plane_t &split)
{
bool have_front, have_back;
int i;
have_front = have_back = false;
if (split->type < 3) {
if (split.type < 3) {
/* shortcut for axial planes */
const vec_t *p = &in->w[0][split->type];
const vec_t *p = &in->w[0][split.type];
for (i = 0; i < in->w.size(); i++, p += 3) {
if (*p > split->dist + ON_EPSILON) {
if (*p > split.dist + ON_EPSILON) {
if (have_back)
return SIDE_ON;
have_front = true;
} else if (*p < split->dist - ON_EPSILON) {
} else if (*p < split.dist - ON_EPSILON) {
if (have_front)
return SIDE_ON;
have_back = true;
@ -124,7 +124,7 @@ static int FaceSide__(const face_t *in, const qbsp_plane_t *split)
/* sloping planes take longer */
const vec_t *p = &in->w[0][0];
for (i = 0; i < in->w.size(); i++, p += 3) {
const vec_t dot = DotProduct(p, split->normal) - split->dist;
const vec_t dot = DotProduct(p, split.normal) - split.dist;
if (dot > ON_EPSILON) {
if (have_back)
return SIDE_ON;
@ -145,20 +145,16 @@ static int FaceSide__(const face_t *in, const qbsp_plane_t *split)
return SIDE_ON;
}
static int FaceSide(const face_t *in, const qbsp_plane_t *split)
inline int FaceSide(const face_t *in, const qbsp_plane_t &split)
{
vec_t dist;
int ret;
vec_t dist = DotProduct(in->origin, split.normal) - split.dist;
dist = DotProduct(in->origin, split->normal) - split->dist;
if (dist > in->radius)
ret = SIDE_FRONT;
return SIDE_FRONT;
else if (dist < -in->radius)
ret = SIDE_BACK;
return SIDE_BACK;
else
ret = FaceSide__(in, split);
return ret;
return FaceSide__(in, split);
}
/*
@ -167,7 +163,7 @@ static int FaceSide(const face_t *in, const qbsp_plane_t *split)
* on that side of the plane. Therefore, if the split plane is
* non-axial, then the returned bounds will overlap.
*/
static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t *split, aabb3d &front_bounds, aabb3d &back_bounds)
static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t &split, aabb3d &front_bounds, aabb3d &back_bounds)
{
int a, b, c, i, j;
vec_t dist1, dist2, mid, split_mins, split_maxs;
@ -175,17 +171,17 @@ static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t *split, aab
front_bounds = back_bounds = in_bounds;
if (split->type < 3) {
if (split.type < 3) {
// CHECK: this escapes the immutability "sandbox" of aabb3d, is this a good idea?
// it'd take like 6 lines to otherwise reproduce this line.
front_bounds[0][split->type] = back_bounds[1][split->type] = split->dist;
front_bounds[0][split.type] = back_bounds[1][split.type] = split.dist;
return;
}
/* Make proper sloping cuts... */
for (a = 0; a < 3; ++a) {
/* Check for parallel case... no intersection */
if (fabs(split->normal[a]) < NORMAL_EPSILON)
if (fabs(split.normal[a]) < NORMAL_EPSILON)
continue;
b = (a + 1) % 3;
@ -199,10 +195,10 @@ static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t *split, aab
corner[c] = in_bounds[j][c];
corner[a] = in_bounds[0][a];
dist1 = DotProduct(corner, split->normal) - split->dist;
dist1 = DotProduct(corner, split.normal) - split.dist;
corner[a] = in_bounds[1][a];
dist2 = DotProduct(corner, split->normal) - split->dist;
dist2 = DotProduct(corner, split.normal) - split.dist;
mid = in_bounds[1][a] - in_bounds[0][a];
mid *= (dist1 / (dist1 - dist2));
@ -212,7 +208,7 @@ static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t *split, aab
split_maxs = min(max(mid, split_maxs), in_bounds.maxs()[a]);
}
}
if (split->normal[a] > 0) {
if (split.normal[a] > 0) {
front_bounds[0][a] = split_mins;
back_bounds[1][a] = split_maxs;
} else {
@ -225,12 +221,12 @@ static void DivideBounds(const aabb3d &in_bounds, const qbsp_plane_t *split, aab
/*
* Calculate the split plane metric for axial planes
*/
static vec_t SplitPlaneMetric_Axial(const qbsp_plane_t *p, const aabb3d &bounds)
inline vec_t SplitPlaneMetric_Axial(const qbsp_plane_t &p, const aabb3d &bounds)
{
vec_t value = 0;
for (int i = 0; i < 3; i++) {
if (i == p->type) {
const vec_t dist = p->dist * p->normal[i];
if (i == p.type) {
const vec_t dist = p.dist * p.normal[i];
value += (bounds.maxs()[i] - dist) * (bounds.maxs()[i] - dist);
value += (dist - bounds.mins()[i]) * (dist - bounds.mins()[i]);
} else {
@ -244,7 +240,7 @@ static vec_t SplitPlaneMetric_Axial(const qbsp_plane_t *p, const aabb3d &bounds)
/*
* Calculate the split plane metric for non-axial planes
*/
static vec_t SplitPlaneMetric_NonAxial(const qbsp_plane_t *p, const aabb3d &bounds)
inline vec_t SplitPlaneMetric_NonAxial(const qbsp_plane_t &p, const aabb3d &bounds)
{
aabb3d f, b;
vec_t value = 0.0;
@ -258,9 +254,9 @@ static vec_t SplitPlaneMetric_NonAxial(const qbsp_plane_t *p, const aabb3d &boun
return value;
}
inline vec_t SplitPlaneMetric(const qbsp_plane_t *p, const aabb3d &bounds)
inline vec_t SplitPlaneMetric(const qbsp_plane_t &p, const aabb3d &bounds)
{
if (p->type < 3)
if (p.type < 3)
return SplitPlaneMetric_Axial(p, bounds);
else
return SplitPlaneMetric_NonAxial(p, bounds);
@ -290,8 +286,8 @@ static surface_t *ChooseMidPlaneFromList(surface_t *surfaces, const aabb3d &boun
continue;
/* check for axis aligned surfaces */
const qbsp_plane_t *plane = &map.planes[surf->planenum];
if (!(plane->type < 3))
const qbsp_plane_t &plane = map.planes[surf->planenum];
if (!(plane.type < 3))
continue;
/* calculate the split metric, smaller values are better */
@ -313,7 +309,7 @@ static surface_t *ChooseMidPlaneFromList(surface_t *surfaces, const aabb3d &boun
if (!surf->has_struct && !pass)
continue;
const qbsp_plane_t *plane = &map.planes[surf->planenum];
const qbsp_plane_t &plane = map.planes[surf->planenum];
const vec_t metric = SplitPlaneMetric(plane, bounds);
if (metric < bestmetric) {
bestmetric = metric;
@ -377,14 +373,14 @@ static surface_t *ChoosePlaneFromList(surface_t *surfaces, const aabb3d &bounds)
if (!surf->has_struct && !pass)
continue;
const qbsp_plane_t *plane = &map.planes[surf->planenum];
const qbsp_plane_t &plane = map.planes[surf->planenum];
int splits = 0;
for (surface_t *surf2 = surfaces; surf2; surf2 = surf2->next) {
if (surf2 == surf || surf2->onnode)
continue;
const qbsp_plane_t *plane2 = &map.planes[surf2->planenum];
if (plane->type < 3 && plane->type == plane2->type)
const qbsp_plane_t &plane2 = map.planes[surf2->planenum];
if (plane.type < 3 && plane.type == plane2.type)
continue;
for (const face_t *face = surf2->faces; face; face = face->next) {
const surfflags_t &flags = map.mtexinfos.at(face->texinfo).flags;
@ -412,8 +408,8 @@ static surface_t *ChoosePlaneFromList(surface_t *surfaces, const aabb3d &bounds)
* if equal numbers axial planes win, otherwise decide on spatial
* subdivision
*/
if (splits < minsplits || (splits == minsplits && plane->type < 3)) {
if (plane->type < 3) {
if (splits < minsplits || (splits == minsplits && plane.type < 3)) {
if (plane.type < 3) {
const vec_t distribution = SplitPlaneMetric(plane, bounds);
if (distribution > bestdistribution && splits == minsplits)
continue;
@ -542,15 +538,15 @@ void CalcSurfaceInfo(surface_t *surf)
DividePlane
==================
*/
static void DividePlane(surface_t *in, const qbsp_plane_t *split, surface_t **front, surface_t **back)
static void DividePlane(surface_t *in, const qplane3d &split, surface_t **front, surface_t **back)
{
const qbsp_plane_t *inplane = &map.planes[in->planenum];
*front = *back = NULL;
// parallel case is easy
if (VectorCompare(inplane->normal, split->normal, EQUAL_EPSILON)) {
if (VectorCompare(inplane->normal, split.normal, EQUAL_EPSILON)) {
// check for exactly on node
if (inplane->dist == split->dist) {
if (inplane->dist == split.dist) {
face_t *facet = in->faces;
in->faces = NULL;
in->onnode = true;
@ -590,7 +586,7 @@ static void DividePlane(surface_t *in, const qbsp_plane_t *split, surface_t **fr
return;
}
if (inplane->dist > split->dist)
if (inplane->dist > split.dist)
*front = in;
else
*back = in;
@ -649,7 +645,7 @@ static void DividePlane(surface_t *in, const qbsp_plane_t *split, surface_t **fr
DivideNodeBounds
==================
*/
inline void DivideNodeBounds(node_t *node, const qbsp_plane_t *split)
inline void DivideNodeBounds(node_t *node, const qbsp_plane_t &split)
{
DivideBounds(node->bounds, split, node->children[0]->bounds, node->children[1]->bounds);
}
@ -807,7 +803,7 @@ static void PartitionSurfaces(surface_t *surfaces, node_t *node)
node->planenum = split->planenum;
node->detail_separator = split->detail_separator;
const qbsp_plane_t *splitplane = &map.planes[split->planenum];
const qbsp_plane_t &splitplane = map.planes[split->planenum];
DivideNodeBounds(node, splitplane);

View File

@ -103,7 +103,7 @@ void SubdivideFace(face_t *f, face_t **prevptr)
plane.dist = (mins + subdiv - 16) / v;
next = f->next;
SplitFace(f, &plane, &front, &back);
SplitFace(f, plane, &front, &back);
if (!front || !back) {
printf("didn't split\n");
break;

View File

@ -153,56 +153,6 @@ static brush_t *load128x128x32Brush()
return brush;
}
TEST(qbsp, BrushVolume)
{
brush_t *brush = load128x128x32Brush();
EXPECT_DOUBLE_EQ((128 * 128 * 32), BrushVolume(brush));
}
TEST(qbsp, BrushMostlyOnSide1)
{
brush_t *brush = load128x128x32Brush();
qvec3d plane1normal {-1, 0, 0};
vec_t plane1dist = -100;
EXPECT_EQ(SIDE_FRONT, BrushMostlyOnSide(brush, plane1normal, plane1dist));
FreeBrush(brush);
}
TEST(qbsp, BrushMostlyOnSide2)
{
brush_t *brush = load128x128x32Brush();
qvec3d plane1normal {1, 0, 0};
vec_t plane1dist = 100;
EXPECT_EQ(SIDE_BACK, BrushMostlyOnSide(brush, plane1normal, plane1dist));
FreeBrush(brush);
}
TEST(qbsp, BoundBrush)
{
brush_t *brush = load128x128x32Brush();
brush->bounds = {};
EXPECT_EQ(true, BoundBrush(brush));
EXPECT_DOUBLE_EQ(-64, brush->bounds.mins()[0]);
EXPECT_DOUBLE_EQ(-64, brush->bounds.mins()[1]);
EXPECT_DOUBLE_EQ(-16, brush->bounds.mins()[2]);
EXPECT_DOUBLE_EQ(64, brush->bounds.maxs()[0]);
EXPECT_DOUBLE_EQ(64, brush->bounds.maxs()[1]);
EXPECT_DOUBLE_EQ(16, brush->bounds.maxs()[2]);
FreeBrush(brush);
}
static void checkForAllCubeNormals(const brush_t *brush)
{
const vec3_t wanted[6] = {{-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
@ -213,7 +163,7 @@ static void checkForAllCubeNormals(const brush_t *brush)
}
for (const face_t *face = brush->faces; face; face = face->next) {
const plane_t faceplane = Face_Plane(face);
const qplane3d faceplane = Face_Plane(face);
for (int i = 0; i < 6; i++) {
if (VectorCompare(wanted[i], faceplane.normal, NORMAL_EPSILON)) {
@ -237,82 +187,6 @@ static void checkCube(const brush_t *brush)
EXPECT_EQ(contentflags_t{CONTENTS_SOLID}, brush->contents);
}
TEST(qbsp, SplitBrush)
{
brush_t *brush = load128x128x32Brush();
const qvec3d planenormal {-1, 0, 0};
int planeside;
const int planenum = FindPlane(planenormal, 0.0, &planeside);
brush_t *front, *back;
SplitBrush(brush, planenum, planeside, &front, &back);
ASSERT_NE(nullptr, front);
ASSERT_NE(nullptr, back);
// front
EXPECT_DOUBLE_EQ(-64, front->bounds.mins()[0]);
EXPECT_DOUBLE_EQ(-64, front->bounds.mins()[1]);
EXPECT_DOUBLE_EQ(-16, front->bounds.mins()[2]);
EXPECT_DOUBLE_EQ(0, front->bounds.maxs()[0]);
EXPECT_DOUBLE_EQ(64, front->bounds.maxs()[1]);
EXPECT_DOUBLE_EQ(16, front->bounds.maxs()[2]);
checkCube(front);
// back
EXPECT_DOUBLE_EQ(0, back->bounds.mins()[0]);
EXPECT_DOUBLE_EQ(-64, back->bounds.mins()[1]);
EXPECT_DOUBLE_EQ(-16, back->bounds.mins()[2]);
EXPECT_DOUBLE_EQ(64, back->bounds.maxs()[0]);
EXPECT_DOUBLE_EQ(64, back->bounds.maxs()[1]);
EXPECT_DOUBLE_EQ(16, back->bounds.maxs()[2]);
checkCube(back);
FreeBrush(brush);
delete front;
delete back;
}
TEST(qbsp, SplitBrushOnSide)
{
brush_t *brush = load128x128x32Brush();
const qvec3d planenormal {-1, 0, 0};
int planeside;
const int planenum = FindPlane(planenormal, -64.0, &planeside);
brush_t *front, *back;
SplitBrush(brush, planenum, planeside, &front, &back);
ASSERT_NE(nullptr, front);
checkCube(front);
EXPECT_EQ(nullptr, back);
}
#if 0
TEST(qbsp, MemLeaks) {
brush_t *brush = load128x128x32Brush();
const qvec3d planenormal { -1, 0, 0 };
int planeside;
const int planenum = FindPlane(planenormal, 0.0, &planeside);
for (int i=0; i<1000000; i++) {
brush_t *front, *back;
SplitBrush(brush, planenum, planeside, &front, &back);
FreeBrush(front);
FreeBrush(back);
}
}
#endif
/**
* Test that this skip face gets auto-corrected.
*/

View File

@ -28,11 +28,11 @@ static int c_leafskip;
pointer, was measurably faster
==============
*/
static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const plane_t src_pl,
static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const qplane3d src_pl,
const std::shared_ptr<winding_t> &pass, std::shared_ptr<winding_t> &target, unsigned int test, pstack_t *stack)
{
int i, j, k, l;
plane_t sep;
qplane3d sep;
vec3_t v1, v2;
vec_t d;
int count;
@ -76,8 +76,7 @@ static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const pla
// flip the plane if the source portal is backwards
//
if (fliptest) {
VectorSubtract(vec3_origin, sep.normal, sep.normal);
sep.dist = -sep.dist;
sep = -sep;
}
//
// if all of the pass portal points are now on the positive side,
@ -102,8 +101,7 @@ static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const pla
// flip the normal if we want the back side (tests 1 and 3)
//
if (test & 1) {
VectorSubtract(vec3_origin, sep.normal, sep.normal);
sep.dist = -sep.dist;
sep = -sep;
}
/* Cache separating planes for tests 0, 1 */
@ -146,7 +144,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
{
pstack_t stack;
portal_t *p;
plane_t backplane;
qplane3d backplane;
leaf_t *leaf;
int i, j, err, numblocks;
@ -222,8 +220,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
}
// get plane of portal, point normal into the neighbor leaf
stack.portalplane = p->plane;
VectorSubtract(vec3_origin, p->plane.normal, backplane.normal);
backplane.dist = -p->plane.dist;
backplane = -p->plane;
if (VectorCompare(prevstack->portalplane.normal, backplane.normal, EQUAL_EPSILON))
continue; // can't go out a coplanar face

View File

@ -162,7 +162,7 @@ void FreeStackWinding(std::shared_ptr<winding_t> &w, pstack_t *stack)
is returned.
==================
*/
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, plane_t *split)
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, qplane3d *split)
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (in->size() + 1));
int *sides = (int *)alloca(sizeof(int) * (in->size() + 1));
@ -714,196 +714,6 @@ void CalcVis(mbsp_t *bsp)
}
}
/*
============================================================================
PASSAGE CALCULATION (not used yet...)
============================================================================
*/
#if 0
int count_sep;
bool PlaneCompare(plane_t *p1, plane_t *p2)
{
int i;
if (fabs(p1->dist - p2->dist) > 0.01)
return false;
for (i = 0; i < 3; i++)
if (fabs(p1->normal[i] - p2->normal[i]) > 0.001)
return false;
return true;
}
sep_t *Findpassages(winding_t *source, winding_t *pass)
{
int i, j, k, l;
plane_t plane;
vec3_t v1, v2;
float d;
double length;
int counts[3];
bool fliptest;
sep_t *sep, *list;
list = NULL;
// check all combinations
for (i = 0; i < source->numpoints; i++) {
l = (i + 1) % source->numpoints;
VectorSubtract(source->points[l], source->points[i], v1);
// fing a vertex of pass that makes a plane that puts all of the
// vertexes of pass on the front side and all of the vertexes of
// source on the back side
for (j = 0; j < pass->numpoints; j++) {
VectorSubtract(pass->points[j], source->points[i], v2);
plane.normal[0] = v1[1] * v2[2] - v1[2] * v2[1];
plane.normal[1] = v1[2] * v2[0] - v1[0] * v2[2];
plane.normal[2] = v1[0] * v2[1] - v1[1] * v2[0];
// if points don't make a valid plane, skip it
length = plane.normal[0] * plane.normal[0] + plane.normal[1] * plane.normal[1] +
plane.normal[2] * plane.normal[2];
if (length < ON_EPSILON)
continue;
length = 1 / sqrt(length);
plane.normal[0] *= (vec_t)length;
plane.normal[1] *= (vec_t)length;
plane.normal[2] *= (vec_t)length;
plane.dist = DotProduct(pass->points[j], plane.normal);
//
// find out which side of the generated seperating plane has the
// source portal
//
fliptest = false;
for (k = 0; k < source->numpoints; k++) {
if (k == i || k == l)
continue;
d = DotProduct(source->points[k], plane.normal) - plane.dist;
if (d < -ON_EPSILON) { // source is on the negative side, so we want all
// pass and target on the positive side
fliptest = false;
break;
} else if (d > ON_EPSILON) { // source is on the positive side, so we want all
// pass and target on the negative side
fliptest = true;
break;
}
}
if (k == source->numpoints)
continue; // planar with source portal
//
// flip the normal if the source portal is backwards
//
if (fliptest) {
VectorSubtract(vec3_origin, plane.normal, plane.normal);
plane.dist = -plane.dist;
}
//
// if all of the pass portal points are now on the positive side,
// this is the seperating plane
//
counts[0] = counts[1] = counts[2] = 0;
for (k = 0; k < pass->numpoints; k++) {
if (k == j)
continue;
d = DotProduct(pass->points[k], plane.normal) - plane.dist;
if (d < -ON_EPSILON)
break;
else if (d > ON_EPSILON)
counts[0]++;
else
counts[2]++;
}
if (k != pass->numpoints)
continue; // points on negative side, not a seperating plane
if (!counts[0])
continue; // planar with pass portal
//
// save this out
//
count_sep++;
sep = new sep_t;
sep->next = list;
list = sep;
sep->plane = plane;
}
}
return list;
}
/*
============
CalcPassages
============
*/
void CalcPassages(void)
{
int i, j, k;
int count, count2;
leaf_t *l;
portal_t *p1, *p2;
sep_t *sep;
passage_t *passages;
LogPrint("building passages...\n");
count = count2 = 0;
for (i = 0; i < portalleafs; i++) {
l = &leafs[i];
for (j = 0; j < l->numportals; j++) {
p1 = l->portals[j];
for (k = 0; k < l->numportals; k++) {
if (k == j)
continue;
count++;
p2 = l->portals[k];
// definately can't see into a coplanar portal
if (PlaneCompare(&p1->plane, &p2->plane))
continue;
count2++;
sep = Findpassages(p1->winding, p2->winding);
if (!sep) {
// Error ("No seperating planes found in portal pair");
count_sep++;
sep = new sep_t;
sep->next = NULL;
sep->plane = p1->plane;
}
passages = new passage_t;
passages->planes = sep;
passages->from = p1->leaf;
passages->to = p2->leaf;
passages->next = l->passages;
l->passages = passages;
}
}
}
LogPrint("numpassages: {} ({})\n", count2, count);
LogPrint("total passages: {}\n", count_sep);
}
#endif
// ===========================================================================
/*
@ -920,7 +730,7 @@ static void LoadPortals(const std::filesystem::path &name, mbsp_t *bsp)
qfile_t f{nullptr, nullptr};
int numpoints;
int leafnums[2];
plane_t plane;
qplane3d plane;
if (name == "-")
f = {stdin, nullptr};
@ -1027,8 +837,7 @@ static void LoadPortals(const std::filesystem::path &name, mbsp_t *bsp)
l->portals[l->numportals] = p;
l->numportals++;
VectorSubtract(vec3_origin, plane.normal, p->plane.normal);
p->plane.dist = -plane.dist;
p->plane = -plane;
p->leaf = leafnums[1];
p->winding->SetWindingSphere();
p++;
@ -1196,8 +1005,6 @@ int main(int argc, char **argv)
uncompressed_q2 = new uint8_t[portalleafs * leafbytes]{};
}
// CalcPassages ();
CalcVis(&bsp);
LogPrint("c_noclip: {}\n", c_noclip);