parent
fd18fc154c
commit
a7de4bdae2
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 { };
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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..)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
817
qbsp/brush.cc
817
qbsp/brush.cc
File diff suppressed because it is too large
Load Diff
28
qbsp/csg4.cc
28
qbsp/csg4.cc
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
10
qbsp/map.cc
10
qbsp/map.cc
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
29
qbsp/qbsp.cc
29
qbsp/qbsp.cc
|
|
@ -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(¤t, &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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
15
vis/flow.cc
15
vis/flow.cc
|
|
@ -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
|
||||
|
|
|
|||
199
vis/vis.cc
199
vis/vis.cc
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue