decompile: wip brush creation code

This commit is contained in:
Eric Wasylishen 2021-02-05 22:31:59 -07:00
parent f0e2f4ba96
commit 9ae2f8678e
1 changed files with 158 additions and 111 deletions

View File

@ -245,62 +245,6 @@ PrintPlanePoints(const mbsp_t *bsp, const decomp_plane_t& decompplane, FILE* fil
PrintPoint(p.point2, file);
}
static std::vector<const bsp2_dface_t *>
GatherAllFacesOnNodes(const std::vector<decomp_plane_t>* planestack, const mbsp_t *bsp)
{
std::vector<const bsp2_dface_t *> result;
for (const decomp_plane_t& decompplane : *planestack) {
if (decompplane.node == nullptr) {
continue;
}
const bsp2_dnode_t* node = decompplane.node;
for (int i=0; i<node->numfaces; i++) {
const bsp2_dface_t *face = BSP_GetFace(bsp, node->firstface + i);
result.push_back(face);
}
}
return result;
}
/**
* We can't use the markfaces from the .bsp file, because those are only
* set on empty leaves, and we need this to work on solid leaves.
*
* The passed-in planestack is used to help locate faces on the given leaf.
*/
static std::vector<const bsp2_dface_t *>
FindFacesOnLeaf(const std::vector<decomp_plane_t>* planestack, const mbsp_t *bsp, const mleaf_t *leaf)
{
// First, gather _all_ faces we encountered on the path to enclose the leaf
// This will include lots that aren't actually touching the leaf
// const std::vector<const bsp2_dface_t *> allFaces = GatherAllFacesOnNodes(planestack, bsp);
std::vector<const bsp2_dface_t *> result;
for (const decomp_plane_t& decompplane : *planestack) {
if (decompplane.node == nullptr) {
continue;
}
const bsp2_dnode_t* node = decompplane.node;
for (int i=0; i<node->numfaces; i++) {
const bsp2_dface_t *face = BSP_GetFace(bsp, node->firstface + i);
result.push_back(face);
// printf("face side: %d\n", face->side);
// WriteFaceTexdef(bsp, face, stdout);
// printf("\n");
}
}
return result;
}
static std::vector<const bsp2_dface_t *>
FindFacesOnNode(const bsp2_dnode_t* node, const mbsp_t *bsp)
{
@ -335,18 +279,92 @@ static std::string DefaultTextureForContents(int contents)
// structures representing a brush
#if 0
struct decomp_brush_face_t {
/**
* The currently clipped section of the face
* The currently clipped section of the face.
* May be null to indicate it was clipped away.
*/
std::unique_ptr<winding_t> winding;
winding_t *winding;
/**
* The face we were originally derived from
*/
const bsp2_dface_t *original_face;
public: // rule of three
~decomp_brush_face_t() {
free(winding);
}
decomp_brush_face_t(const decomp_brush_face_t& other) : // copy constructor
winding(CopyWinding(other.winding)),
original_face(other.original_face) {}
decomp_brush_face_t& operator=(const decomp_brush_face_t& other) { // copy assignment
winding = CopyWinding(other.winding);
original_face = other.original_face;
return *this;
}
public:
decomp_brush_face_t() :
winding(nullptr),
original_face(nullptr) {}
decomp_brush_face_t(const mbsp_t *bsp, const bsp2_dface_t *face) :
winding(WindingFromFace(bsp, face)),
original_face(face) {}
decomp_brush_face_t(winding_t* windingToTakeOwnership, const bsp2_dface_t *face) :
winding(windingToTakeOwnership),
original_face(face) {}
/**
* Returns the { front, back } after the clip.
*/
std::pair<decomp_brush_face_t, decomp_brush_face_t> clipToPlane(const qvec3d& normal, double distance) const {
vec3_t pnormal;
glm_to_vec3_t(normal, pnormal);
winding_t *temp = CopyWinding(winding);
winding_t *front = nullptr;
winding_t *back = nullptr;
ClipWinding(temp, pnormal, distance, &front, &back); // frees temp
// front or back may be null (if fully clipped).
// these constructors take ownership of the winding.
return std::make_pair(decomp_brush_face_t(front, original_face),
decomp_brush_face_t(back, original_face));
}
};
/**
* Builds the initial list of faces on the node
*/
static std::vector<decomp_brush_face_t>
BuildDecompFacesOnPlane(const mbsp_t *bsp, const decomp_plane_t& plane)
{
if (plane.node == nullptr) {
return {};
}
const bsp2_dnode_t* node = plane.node;
std::vector<decomp_brush_face_t> result;
result.reserve(static_cast<size_t>(node->numfaces));
for (int i=0; i<node->numfaces; i++) {
const bsp2_dface_t *face = BSP_GetFace(bsp, node->firstface + i);
const bool faceOnBack = face->side;
if (faceOnBack == plane.nodefront) {
continue; // mismatch
}
result.emplace_back(bsp, face);
}
return result;
}
struct decomp_brush_side_t {
/**
* During decompilation, we can have multiple faces on a single plane of the brush.
@ -355,11 +373,44 @@ struct decomp_brush_side_t {
std::vector<decomp_brush_face_t> faces;
decomp_plane_t plane;
decomp_brush_side_t(const mbsp_t *bsp, const decomp_plane_t& planeIn) :
faces(BuildDecompFacesOnPlane(bsp, plane)),
plane(planeIn) {}
decomp_brush_side_t(std::vector<decomp_brush_face_t> facesIn, const decomp_plane_t& planeIn) :
faces(std::move(facesIn)),
plane(planeIn) {}
/**
* Returns the { front, back } after the clip.
*/
std::tuple<decomp_brush_side_t, decomp_brush_side_t> clipToPlane(const qvec3d& normal, double distance) 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);
if (faceFront.winding) {
frontfaces.push_back(std::move(faceFront));
}
if (faceBack.winding) {
backfaces.push_back(std::move(faceBack));
}
}
return {decomp_brush_side_t(std::move(frontfaces), plane),
decomp_brush_side_t(std::move(backfaces), plane)};
}
};
struct decomp_brush_t {
std::vector<decomp_brush_side_t> sides;
decomp_brush_t(std::vector<decomp_brush_side_t> sidesIn) :
sides(std::move(sidesIn)) {}
std::unique_ptr<decomp_brush_t> clone() const {
return std::unique_ptr<decomp_brush_t>(new decomp_brush_t(*this));
}
@ -381,55 +432,50 @@ struct decomp_brush_t {
}
// general case.
return {nullptr, nullptr};
}
};
/***
* Preconditions: planes are exactly the planes that define the brush
*
* @returns a brush object which has the faces from the .bsp clipped to
* the parts that lie on the brush.
*/
static decomp_brush_t
BuildInitialBrush(const mbsp_t *bsp, std::vector<decomp_plane_t> planes)
BuildInitialBrush(const mbsp_t *bsp, const std::vector<decomp_plane_t>& planes)
{
std::vector<decomp_plane_t> result;
std::vector<decomp_brush_side_t> sides;
for (const decomp_plane_t &plane : planes) {
// outward-facing plane
vec3_t normal;
glm_to_vec3_t(plane.normal, normal);
winding_t *winding = BaseWindingForPlane(normal, plane.distance);
auto side = decomp_brush_side_t(bsp, plane);
// clip `winding` by all of the other planes, flipped
// clip `side` by all of the other planes, and keep the back portion
for (const decomp_plane_t &plane2 : planes) {
if (&plane2 == &plane)
continue;
// get flipped plane
vec3_t plane2normal;
glm_to_vec3_t(plane2.normal * -1.0, plane2normal);
float plane2dist = -plane2.distance;
auto [front, back] = side.clipToPlane(plane2.normal, plane2.distance);
// frees winding.
winding_t *front = nullptr;
winding_t *back = nullptr;
ClipWinding(winding, plane2normal, plane2dist, &front, &back);
// discard the back, continue clipping the front part
free(back);
winding = front;
// check if everything was clipped away
if (winding == nullptr)
break;
side = back;
}
if (winding != nullptr) {
// this plane is not redundant
result.push_back(plane);
}
// NOTE: side may have had all of its faces clipped away, but we still need to keep it
// as it's one of the final boundaries of the brush
free(winding);
sides.push_back(std::move(side));
}
return result;
return decomp_brush_t(sides);
}
std::vector<decomp_brush_t>
SplitDifferentTexturedPartsOfBrush(const mbsp_t *bsp, decomp_brush_t brush)
{
// FIXME: implement
return { brush };
}
#endif
/**
* Preconditions:
@ -453,40 +499,41 @@ DecompileLeaf(const std::vector<decomp_plane_t>* planestack, const mbsp_t *bsp,
// At this point, we should gather all of the faces on `reducedPlanes` and clip away the
// parts that are outside of our brush. (keeping track of which of the nodes they belonged to)
// AFAIK it's possible that the faces are half-overlapping the leaf, so we may have to cut the
// It's possible that the faces are half-overlapping the leaf, so we may have to cut the
// faces in half.
auto initialBrush = BuildInitialBrush(bsp, reducedPlanes);
// Next, for each plane in reducedPlanes, if there are 2+ faces on the plane with non-equal
// texinfo, we need to clip the brush perpendicular to the face until there are no longer
// 2+ faces on a plane with non-equal texinfo.
auto finalBrushes = SplitDifferentTexturedPartsOfBrush(bsp, initialBrush);
fprintf(file, "{\n");
for (const auto& decompplane : reducedPlanes) {
PrintPlanePoints(bsp, decompplane, file);
for (const decomp_brush_t& brush : finalBrushes) {
fprintf(file, "{\n");
for (const auto& side : brush.sides) {
PrintPlanePoints(bsp, side.plane, file);
// see if we have a face
auto faces = FindFacesOnNode(decompplane.node, bsp);
if (!faces.empty()) {
const bsp2_dface_t *face = faces.at(0);
const char* name = Face_TextureName(bsp, face);
if (0 == strlen(name)) {
// see if we have a face
auto faces = FindFacesOnNode(side.plane.node, bsp);
if (!faces.empty()) {
const bsp2_dface_t *face = faces.at(0);
const char *name = Face_TextureName(bsp, face);
if (0 == strlen(name)) {
fprintf(file, " %s ", DefaultTextureForContents(leaf->contents).c_str());
WriteNullTexdef(bsp, file);
} else {
fprintf(file, " %s ", name);
WriteFaceTexdef(bsp, face, file);
}
} else {
// print a default face
fprintf(file, " %s ", DefaultTextureForContents(leaf->contents).c_str());
WriteNullTexdef(bsp, file);
} else {
fprintf(file, " %s ", name);
WriteFaceTexdef(bsp, face, file);
}
} else {
// print a default face
fprintf(file, " %s ", DefaultTextureForContents(leaf->contents).c_str());
WriteNullTexdef(bsp, file);
fprintf(file, "\n");
}
fprintf(file, "\n");
fprintf(file, "}\n");
}
fprintf(file, "}\n");
// auto faces = FindFacesOnLeaf(planestack, bsp, leaf);
// printf("got leaf contents %d with %d faces\n", leaf->contents, static_cast<int>(faces.size()));
}
/**