Merge branch 'brushbsp' of https://github.com/ericwa/ericw-tools into brushbsp
This commit is contained in:
commit
292d5afb5e
|
|
@ -37,9 +37,6 @@ struct side_t
|
|||
|
||||
int16_t lmshift;
|
||||
|
||||
qvec3d origin;
|
||||
vec_t radius;
|
||||
|
||||
bool onnode; // has this face been used as a BSP node plane yet?
|
||||
bool visible = true; // can any part of this side be seen from non-void parts of the level?
|
||||
// non-visible means we can discard the brush side
|
||||
|
|
|
|||
|
|
@ -36,6 +36,5 @@ face_t *CopyFace(const face_t *in);
|
|||
face_t *MirrorFace(const face_t *face);
|
||||
std::tuple<face_t *, face_t *> SplitFace(face_t *in, const qplane3d &split);
|
||||
void UpdateFaceSphere(face_t *in);
|
||||
void UpdateFaceSphere(side_t *in);
|
||||
bool BrushGE(const bspbrush_t &a, const bspbrush_t &b);
|
||||
std::vector<std::unique_ptr<bspbrush_t>> ChopBrushes(const std::vector<std::unique_ptr<bspbrush_t>> &input);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
Copyright (C) 1997 Greg Lewis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct node_t;
|
||||
|
||||
void DetailToSolid(node_t *node);
|
||||
void PruneNodes(node_t *node);
|
||||
|
|
@ -9,7 +9,8 @@ set(QBSP_INCLUDES
|
|||
${CMAKE_SOURCE_DIR}/include/qbsp/portals.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/prtfile.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/brushbsp.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/surfaces.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/faces.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/tree.hh
|
||||
${CMAKE_SOURCE_DIR}/include/qbsp/writebsp.hh)
|
||||
|
||||
set(QBSP_SOURCES
|
||||
|
|
@ -22,8 +23,9 @@ set(QBSP_SOURCES
|
|||
${CMAKE_SOURCE_DIR}/qbsp/prtfile.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/qbsp.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/brushbsp.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/surfaces.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/faces.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/tjunc.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/tree.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/writebsp.cc
|
||||
${CMAKE_SOURCE_DIR}/qbsp/exportobj.cc
|
||||
${QBSP_INCLUDES})
|
||||
|
|
|
|||
|
|
@ -459,7 +459,6 @@ static std::vector<side_t> CreateBrushFaces(const mapentity_t *src, hullbrush_t
|
|||
f.planenum = FindPositivePlane(plane, &f.planeside);
|
||||
|
||||
CheckFace(&f, mapface);
|
||||
UpdateFaceSphere(&f);
|
||||
}
|
||||
|
||||
// Rotatable objects must have a bounding box big enough to
|
||||
|
|
|
|||
|
|
@ -45,96 +45,6 @@ static bool usemidsplit;
|
|||
*/
|
||||
static int mapbrushes;
|
||||
|
||||
//============================================================================
|
||||
|
||||
void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
||||
{
|
||||
// merge the children's brush lists
|
||||
node->original_brushes = concat(
|
||||
node->children[0]->original_brushes,
|
||||
node->children[1]->original_brushes);
|
||||
sort_and_remove_duplicates(node->original_brushes);
|
||||
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
delete node->children[i];
|
||||
node->children[i] = nullptr;
|
||||
}
|
||||
for (auto *face : node->facelist) {
|
||||
delete face;
|
||||
}
|
||||
node->facelist = {};
|
||||
|
||||
node->contents = contents;
|
||||
|
||||
Q_assert(node->markfaces.empty());
|
||||
}
|
||||
|
||||
void DetailToSolid(node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF) {
|
||||
if (options.target_game->id == GAME_QUAKE_II) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to remap CONTENTS_DETAIL to a standard quake content type
|
||||
if (node->contents.is_detail_solid(options.target_game)) {
|
||||
node->contents = options.target_game->create_solid_contents();
|
||||
} else if (node->contents.is_detail_illusionary(options.target_game)) {
|
||||
node->contents = options.target_game->create_empty_contents();
|
||||
}
|
||||
/* N.B.: CONTENTS_DETAIL_FENCE is not remapped to CONTENTS_SOLID until the very last moment,
|
||||
* because we want to generate a leaf (if we set it to CONTENTS_SOLID now it would use leaf 0).
|
||||
*/
|
||||
return;
|
||||
} else {
|
||||
DetailToSolid(node->children[0]);
|
||||
DetailToSolid(node->children[1]);
|
||||
|
||||
// If both children are solid, we can merge the two leafs into one.
|
||||
// DarkPlaces has an assertion that fails if both children are
|
||||
// solid.
|
||||
if (node->children[0]->contents.is_solid(options.target_game) &&
|
||||
node->children[1]->contents.is_solid(options.target_game)) {
|
||||
// This discards any faces on-node. Should be safe (?)
|
||||
ConvertNodeToLeaf(node, options.target_game->create_solid_contents());
|
||||
}
|
||||
// fixme-brushbsp: merge with PruneNodes
|
||||
}
|
||||
}
|
||||
|
||||
static void PruneNodes_R(node_t *node, int &count_pruned)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF) {
|
||||
return;
|
||||
}
|
||||
|
||||
PruneNodes_R(node->children[0], count_pruned);
|
||||
PruneNodes_R(node->children[1], count_pruned);
|
||||
|
||||
if (node->children[0]->planenum == PLANENUM_LEAF && node->children[0]->contents.is_solid(options.target_game) &&
|
||||
node->children[1]->planenum == PLANENUM_LEAF && node->children[1]->contents.is_solid(options.target_game)) {
|
||||
// This discards any faces on-node. Should be safe (?)
|
||||
ConvertNodeToLeaf(node, options.target_game->create_solid_contents());
|
||||
++count_pruned;
|
||||
}
|
||||
|
||||
// fixme-brushbsp: corner case where two solid leafs shouldn't merge is two noclipfaces fence brushes touching
|
||||
// fixme-brushbsp: also merge other content types
|
||||
// fixme-brushbsp: maybe merge if same content type, and all faces on node are invisible?
|
||||
}
|
||||
|
||||
void PruneNodes(node_t *node)
|
||||
{
|
||||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
int count_pruned = 0;
|
||||
PruneNodes_R(node, count_pruned);
|
||||
|
||||
logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
FaceSide
|
||||
|
|
@ -201,14 +111,7 @@ inline int FaceSide(const face_t *in, const qbsp_plane_t &split)
|
|||
|
||||
inline int FaceSide(const side_t *in, const qbsp_plane_t &split)
|
||||
{
|
||||
vec_t dist = split.distance_to(in->origin);
|
||||
|
||||
if (dist > in->radius)
|
||||
return SIDE_FRONT;
|
||||
else if (dist < -in->radius)
|
||||
return SIDE_BACK;
|
||||
else
|
||||
return FaceSide__(in->w, split);
|
||||
return FaceSide__(in->w, split);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
10
qbsp/csg4.cc
10
qbsp/csg4.cc
|
|
@ -80,16 +80,6 @@ void UpdateFaceSphere(face_t *in)
|
|||
in->radius = sqrt(in->radius);
|
||||
}
|
||||
|
||||
void UpdateFaceSphere(side_t *in)
|
||||
{
|
||||
in->origin = in->w.center();
|
||||
in->radius = 0;
|
||||
for (size_t i = 0; i < in->w.size(); i++) {
|
||||
in->radius = max(in->radius, qv::distance2(in->w[i], in->origin));
|
||||
}
|
||||
in->radius = sqrt(in->radius);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SplitFace
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/csg4.hh>
|
||||
#include <qbsp/map.hh>
|
||||
#include <qbsp/surfaces.hh>
|
||||
#include <qbsp/faces.hh>
|
||||
|
||||
#ifdef PARANOID
|
||||
static void CheckColinear(face_t *f)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#include <qbsp/portals.hh>
|
||||
#include <qbsp/prtfile.hh>
|
||||
#include <qbsp/brushbsp.hh>
|
||||
#include <qbsp/surfaces.hh>
|
||||
#include <qbsp/faces.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
#include <qbsp/writebsp.hh>
|
||||
#include <qbsp/outside.hh>
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ static std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmap(c
|
|||
auto bsp_path = map_path;
|
||||
bsp_path.replace_extension(".bsp");
|
||||
|
||||
std::vector<std::string> args{"", "-nopercent"}; // first arg is the exe path, which we're ignoring in this case
|
||||
std::vector<std::string> args{"", "-noverbose"}; // first arg is the exe path, which we're ignoring in this case
|
||||
for (auto &arg : extra_args) {
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
|
@ -1608,7 +1608,7 @@ TEST_CASE("q1_wad_internal", "[testmaps_q1]") {
|
|||
* Test for WAD internal textures
|
||||
**/
|
||||
TEST_CASE("q1_wad_external", "[testmaps_q1]") {
|
||||
const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_simple.map", { "-xwadpath", "A:\\ericw-tools\\testmaps" });
|
||||
const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_simple.map", { "-xwadpath", std::string(testmaps_dir) });
|
||||
|
||||
CHECK(GAME_QUAKE == bsp.loadversion->game->id);
|
||||
|
||||
|
|
@ -1625,7 +1625,7 @@ TEST_CASE("q1_wad_external", "[testmaps_q1]") {
|
|||
CHECK(bsp.dtex.textures[3].data.size() == sizeof(dmiptex_t));
|
||||
}
|
||||
|
||||
TEST_CASE("winding", "[benchmark]") {
|
||||
TEST_CASE("winding", "[benchmark][.releaseonly]") {
|
||||
ankerl::nanobench::Bench bench;
|
||||
|
||||
bench.run("std::vector<double> reserve(3*4*6)", [&] {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
Copyright (C) 1997 Greg Lewis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See file, 'COPYING', for details.
|
||||
*/
|
||||
|
||||
#include <qbsp/tree.hh>
|
||||
|
||||
#include <common/vectorutils.hh>
|
||||
#include <qbsp/qbsp.hh>
|
||||
|
||||
//============================================================================
|
||||
|
||||
static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
|
||||
{
|
||||
// merge the children's brush lists
|
||||
node->original_brushes = concat(
|
||||
node->children[0]->original_brushes,
|
||||
node->children[1]->original_brushes);
|
||||
sort_and_remove_duplicates(node->original_brushes);
|
||||
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
delete node->children[i];
|
||||
node->children[i] = nullptr;
|
||||
}
|
||||
for (auto *face : node->facelist) {
|
||||
delete face;
|
||||
}
|
||||
node->facelist = {};
|
||||
|
||||
node->contents = contents;
|
||||
|
||||
Q_assert(node->markfaces.empty());
|
||||
}
|
||||
|
||||
void DetailToSolid(node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF) {
|
||||
if (options.target_game->id == GAME_QUAKE_II) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to remap CONTENTS_DETAIL to a standard quake content type
|
||||
if (node->contents.is_detail_solid(options.target_game)) {
|
||||
node->contents = options.target_game->create_solid_contents();
|
||||
} else if (node->contents.is_detail_illusionary(options.target_game)) {
|
||||
node->contents = options.target_game->create_empty_contents();
|
||||
}
|
||||
/* N.B.: CONTENTS_DETAIL_FENCE is not remapped to CONTENTS_SOLID until the very last moment,
|
||||
* because we want to generate a leaf (if we set it to CONTENTS_SOLID now it would use leaf 0).
|
||||
*/
|
||||
return;
|
||||
} else {
|
||||
DetailToSolid(node->children[0]);
|
||||
DetailToSolid(node->children[1]);
|
||||
|
||||
// If both children are solid, we can merge the two leafs into one.
|
||||
// DarkPlaces has an assertion that fails if both children are
|
||||
// solid.
|
||||
if (node->children[0]->contents.is_solid(options.target_game) &&
|
||||
node->children[1]->contents.is_solid(options.target_game)) {
|
||||
// This discards any faces on-node. Should be safe (?)
|
||||
ConvertNodeToLeaf(node, options.target_game->create_solid_contents());
|
||||
}
|
||||
// fixme-brushbsp: merge with PruneNodes
|
||||
}
|
||||
}
|
||||
|
||||
static void PruneNodes_R(node_t *node, int &count_pruned)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF) {
|
||||
return;
|
||||
}
|
||||
|
||||
PruneNodes_R(node->children[0], count_pruned);
|
||||
PruneNodes_R(node->children[1], count_pruned);
|
||||
|
||||
if (node->children[0]->planenum == PLANENUM_LEAF && node->children[0]->contents.is_solid(options.target_game) &&
|
||||
node->children[1]->planenum == PLANENUM_LEAF && node->children[1]->contents.is_solid(options.target_game)) {
|
||||
// This discards any faces on-node. Should be safe (?)
|
||||
ConvertNodeToLeaf(node, options.target_game->create_solid_contents());
|
||||
++count_pruned;
|
||||
}
|
||||
|
||||
// fixme-brushbsp: corner case where two solid leafs shouldn't merge is two noclipfaces fence brushes touching
|
||||
// fixme-brushbsp: also merge other content types
|
||||
// fixme-brushbsp: maybe merge if same content type, and all faces on node are invisible?
|
||||
}
|
||||
|
||||
void PruneNodes(node_t *node)
|
||||
{
|
||||
logging::print(logging::flag::PROGRESS, "---- {} ----\n", __func__);
|
||||
|
||||
int count_pruned = 0;
|
||||
PruneNodes_R(node, count_pruned);
|
||||
|
||||
logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned);
|
||||
}
|
||||
Loading…
Reference in New Issue