bevel
This commit is contained in:
parent
e14c2772a6
commit
9ca28dff61
|
|
@ -39,12 +39,12 @@ struct bspbrush_t;
|
|||
|
||||
struct mapface_t
|
||||
{
|
||||
//qbsp_plane_t plane{};
|
||||
size_t planenum;
|
||||
std::array<qvec3d, 3> planepts{};
|
||||
std::string texname{};
|
||||
int texinfo = 0;
|
||||
int linenum = 0;
|
||||
bool bevel = false;
|
||||
|
||||
surfflags_t flags{};
|
||||
|
||||
|
|
@ -55,6 +55,8 @@ struct mapface_t
|
|||
// for convert
|
||||
std::optional<extended_texinfo_t> raw_info;
|
||||
|
||||
winding_t winding;
|
||||
|
||||
bool set_planepts(const std::array<qvec3d, 3> &pts);
|
||||
|
||||
const texvecf &get_texvecs() const;
|
||||
|
|
@ -76,6 +78,7 @@ public:
|
|||
int numfaces = 0;
|
||||
brushformat_t format = brushformat_t::NORMAL;
|
||||
int contents = 0;
|
||||
aabb3d bounds {};
|
||||
|
||||
const mapface_t &face(int i) const;
|
||||
};
|
||||
|
|
@ -94,6 +97,8 @@ public:
|
|||
|
||||
int firstmapbrush = 0;
|
||||
int nummapbrushes = 0;
|
||||
size_t numboxbevels = 0;
|
||||
size_t numedgebevels = 0;
|
||||
|
||||
// key/value pairs in the order they were parsed
|
||||
entdict_t epairs;
|
||||
|
|
|
|||
|
|
@ -687,6 +687,12 @@ std::optional<bspbrush_t> LoadBrush(const mapentity_t *src, const mapbrush_t *ma
|
|||
|
||||
static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int hullnum, content_stats_base_t &stats)
|
||||
{
|
||||
// _omitbrushes 1 just discards all brushes in the entity.
|
||||
// could be useful for geometry guides, selective compilation, etc.
|
||||
if (src->epairs.get_int("_omitbrushes")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mapbrush_t *mapbrush;
|
||||
qvec3d rotate_offset{};
|
||||
int i;
|
||||
|
|
@ -694,6 +700,7 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
|
|||
bool all_detail, all_detail_fence, all_detail_illusionary;
|
||||
|
||||
const std::string &classname = src->epairs.get("classname");
|
||||
|
||||
/* Origin brush support */
|
||||
rotation_t rottype = rotation_t::none;
|
||||
|
||||
|
|
@ -770,11 +777,6 @@ static void Brush_LoadEntity(mapentity_t *dst, const mapentity_t *src, const int
|
|||
|
||||
const bool func_illusionary_visblocker = (0 == Q_strcasecmp(classname, "func_illusionary_visblocker"));
|
||||
|
||||
// _omitbrushes 1 just discards all brushes in the entity.
|
||||
// could be useful for geometry guides, selective compilation, etc.
|
||||
if (src->epairs.get_int("_omitbrushes"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < src->nummapbrushes; i++, mapbrush++) {
|
||||
logging::percent(i, src->nummapbrushes);
|
||||
mapbrush = &src->mapbrush(i);
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ static void EmitFaceFragment(face_t *face, face_fragment_t *fragment)
|
|||
GrowNodeRegion
|
||||
==============
|
||||
*/
|
||||
static void GrowNodeRegion(node_t *node)
|
||||
static void EmitFaceFragments_R(node_t *node)
|
||||
{
|
||||
if (node->is_leaf)
|
||||
return;
|
||||
|
|
@ -253,8 +253,8 @@ static void GrowNodeRegion(node_t *node)
|
|||
|
||||
node->numfaces = static_cast<int>(map.bsp.dfaces.size()) - node->firstface;
|
||||
|
||||
GrowNodeRegion(node->children[0].get());
|
||||
GrowNodeRegion(node->children[1].get());
|
||||
EmitFaceFragments_R(node->children[0].get());
|
||||
EmitFaceFragments_R(node->children[1].get());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -271,8 +271,8 @@ int MakeFaceEdges(node_t *headnode)
|
|||
firstface = static_cast<int>(map.bsp.dfaces.size());
|
||||
MakeFaceEdges_r(headnode);
|
||||
|
||||
logging::header("GrowRegions");
|
||||
GrowNodeRegion(headnode);
|
||||
logging::header("EmitFaceFragments");
|
||||
EmitFaceFragments_R(headnode);
|
||||
|
||||
return firstface;
|
||||
}
|
||||
|
|
|
|||
274
qbsp/map.cc
274
qbsp/map.cc
|
|
@ -421,11 +421,12 @@ int FindTexinfo(const maptexinfo_t &texinfo)
|
|||
return num_texinfo;
|
||||
}
|
||||
|
||||
static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapentity_t *entity)
|
||||
static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapentity_t &entity)
|
||||
{
|
||||
surfflags_t flags{};
|
||||
const char *texname = map.miptex.at(texinfo.miptex).name.c_str();
|
||||
const int shadow = entity->epairs.get_int("_shadow");
|
||||
const int shadow = entity.epairs.get_int("_shadow");
|
||||
|
||||
// These flags are pulled from surf flags in Q2.
|
||||
// TODO: the Q1 version of this block can now be moved into texinfo
|
||||
// loading by shoving them inside of texinfo.flags like
|
||||
|
|
@ -452,13 +453,13 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
}
|
||||
if (IsNoExpandName(texname))
|
||||
flags.no_expand = true;
|
||||
if (entity->epairs.get_int("_dirt") == -1)
|
||||
if (entity.epairs.get_int("_dirt") == -1)
|
||||
flags.no_dirt = true;
|
||||
if (entity->epairs.get_int("_bounce") == -1)
|
||||
if (entity.epairs.get_int("_bounce") == -1)
|
||||
flags.no_bounce = true;
|
||||
if (entity->epairs.get_int("_minlight") == -1)
|
||||
if (entity.epairs.get_int("_minlight") == -1)
|
||||
flags.no_minlight = true;
|
||||
if (entity->epairs.get_int("_lightignore") == 1)
|
||||
if (entity.epairs.get_int("_lightignore") == 1)
|
||||
flags.light_ignore = true;
|
||||
|
||||
// "_minlight_exclude", "_minlight_exclude2", "_minlight_exclude3"...
|
||||
|
|
@ -468,7 +469,7 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
key += std::to_string(i);
|
||||
}
|
||||
|
||||
const std::string &excludeTex = entity->epairs.get(key.c_str());
|
||||
const std::string &excludeTex = entity.epairs.get(key.c_str());
|
||||
if (!excludeTex.empty() && !Q_strcasecmp(texname, excludeTex)) {
|
||||
flags.no_minlight = true;
|
||||
}
|
||||
|
|
@ -476,7 +477,7 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
|
||||
if (shadow == -1)
|
||||
flags.no_shadow = true;
|
||||
if (!Q_strcasecmp("func_detail_illusionary", entity->epairs.get("classname"))) {
|
||||
if (!Q_strcasecmp("func_detail_illusionary", entity.epairs.get("classname"))) {
|
||||
/* Mark these entities as TEX_NOSHADOW unless the mapper set "_shadow" "1" */
|
||||
if (shadow != 1) {
|
||||
flags.no_shadow = true;
|
||||
|
|
@ -484,8 +485,8 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
}
|
||||
|
||||
// handle "_phong" and "_phong_angle" and "_phong_angle_concave"
|
||||
vec_t phongangle = entity->epairs.get_float("_phong_angle");
|
||||
const int phong = entity->epairs.get_int("_phong");
|
||||
vec_t phongangle = entity.epairs.get_float("_phong_angle");
|
||||
const int phong = entity.epairs.get_int("_phong");
|
||||
|
||||
if (phong && (phongangle == 0.0)) {
|
||||
phongangle = 89.0; // default _phong_angle
|
||||
|
|
@ -495,11 +496,11 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
flags.phong_angle = clamp(phongangle, 0.0, 360.0);
|
||||
}
|
||||
|
||||
const vec_t phong_angle_concave = entity->epairs.get_float("_phong_angle_concave");
|
||||
const vec_t phong_angle_concave = entity.epairs.get_float("_phong_angle_concave");
|
||||
flags.phong_angle_concave = clamp(phong_angle_concave, 0.0, 360.0);
|
||||
|
||||
// handle "_minlight"
|
||||
const vec_t minlight = entity->epairs.get_float("_minlight");
|
||||
const vec_t minlight = entity.epairs.get_float("_minlight");
|
||||
if (minlight > 0) {
|
||||
// CHECK: allow > 510 now that we're float? or is it not worth it since it will
|
||||
// be beyond max?
|
||||
|
|
@ -510,9 +511,9 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
{
|
||||
qvec3d mincolor{};
|
||||
|
||||
entity->epairs.get_vector("_mincolor", mincolor);
|
||||
entity.epairs.get_vector("_mincolor", mincolor);
|
||||
if (qv::epsilonEmpty(mincolor, EQUAL_EPSILON)) {
|
||||
entity->epairs.get_vector("_minlight_color", mincolor);
|
||||
entity.epairs.get_vector("_minlight_color", mincolor);
|
||||
}
|
||||
|
||||
mincolor = qv::normalize_color_format(mincolor);
|
||||
|
|
@ -524,7 +525,7 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti
|
|||
}
|
||||
|
||||
// handle "_light_alpha"
|
||||
const vec_t lightalpha = entity->epairs.get_float("_light_alpha");
|
||||
const vec_t lightalpha = entity.epairs.get_float("_light_alpha");
|
||||
if (lightalpha != 0.0) {
|
||||
flags.light_alpha = clamp(lightalpha, 0.0, 1.0);
|
||||
}
|
||||
|
|
@ -1394,7 +1395,7 @@ parse_error:
|
|||
FError("line {}: couldn't parse Brush Primitives texture info", parser.linenum);
|
||||
}
|
||||
|
||||
static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush_t *brush, maptexinfo_t *tx,
|
||||
static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush_t &brush, maptexinfo_t *tx,
|
||||
std::array<qvec3d, 3> &planepts, const qplane3d &plane)
|
||||
{
|
||||
vec_t rotate;
|
||||
|
|
@ -1404,7 +1405,7 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush
|
|||
|
||||
quark_tx_info_t extinfo;
|
||||
|
||||
if (brush->format == brushformat_t::BRUSH_PRIMITIVES) {
|
||||
if (brush.format == brushformat_t::BRUSH_PRIMITIVES) {
|
||||
ParseBrushPrimTX(parser, texMat);
|
||||
tx_type = TX_BRUSHPRIM;
|
||||
|
||||
|
|
@ -1415,7 +1416,7 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush
|
|||
extinfo = ParseExtendedTX(parser);
|
||||
|
||||
mapface.raw_info = extinfo.info;
|
||||
} else if (brush->format == brushformat_t::NORMAL) {
|
||||
} else if (brush.format == brushformat_t::NORMAL) {
|
||||
parser.parse_token(PARSE_SAMELINE);
|
||||
mapface.texname = parser.token;
|
||||
|
||||
|
|
@ -1608,24 +1609,24 @@ static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx)
|
|||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<mapface_t> ParseBrushFace(parser_t &parser, const mapbrush_t *brush, const mapentity_t *entity)
|
||||
static std::optional<mapface_t> ParseBrushFace(parser_t &parser, const mapbrush_t &brush, const mapentity_t &entity)
|
||||
{
|
||||
std::array<qvec3d, 3> planepts;
|
||||
bool normal_ok;
|
||||
maptexinfo_t tx;
|
||||
int i, j;
|
||||
std::unique_ptr<mapface_t> face = std::make_unique<mapface_t>();
|
||||
mapface_t face;
|
||||
|
||||
face->linenum = parser.linenum;
|
||||
face.linenum = parser.linenum;
|
||||
ParsePlaneDef(parser, planepts);
|
||||
|
||||
normal_ok = face->set_planepts(planepts);
|
||||
normal_ok = face.set_planepts(planepts);
|
||||
|
||||
ParseTextureDef(parser, *face, brush, &tx, face->planepts, face->get_plane());
|
||||
ParseTextureDef(parser, face, brush, &tx, face.planepts, face.get_plane());
|
||||
|
||||
if (!normal_ok) {
|
||||
logging::print("WARNING: line {}: Brush plane with no normal\n", parser.linenum);
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// ericw -- round texture vector values that are within ZERO_EPSILON of integers,
|
||||
|
|
@ -1639,15 +1640,218 @@ static std::unique_ptr<mapface_t> ParseBrushFace(parser_t &parser, const mapbrus
|
|||
}
|
||||
}
|
||||
|
||||
ValidateTextureProjection(*face, &tx);
|
||||
ValidateTextureProjection(face, &tx);
|
||||
|
||||
tx.flags = SurfFlagsForEntity(tx, entity);
|
||||
face->texinfo = FindTexinfo(tx);
|
||||
face.texinfo = FindTexinfo(tx);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
|
||||
|
||||
/*
|
||||
================
|
||||
CalculateBrushBounds
|
||||
================
|
||||
*/
|
||||
inline void CalculateBrushBounds(mapbrush_t &ob)
|
||||
{
|
||||
ob.bounds = {};
|
||||
|
||||
for (size_t i = 0; i < ob.numfaces; i++) {
|
||||
const auto &plane = ob.face(i).get_plane();
|
||||
std::optional<winding_t> w = BaseWindingForPlane(plane);
|
||||
|
||||
for (size_t j = 0; j < ob.numfaces && w; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
if (ob.face(j).bevel) {
|
||||
continue;
|
||||
}
|
||||
const auto &plane = map.get_plane(ob.face(j).planenum ^ 1);
|
||||
w = w->clip(plane, 0)[SIDE_FRONT]; //CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
const_cast<mapface_t &>(ob.face(i)).winding = w.value();
|
||||
//side->visible = true;
|
||||
for (auto &p : w.value()) {
|
||||
ob.bounds += p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (ob.bounds.mins()[0] < -qbsp_options.worldextent.value() || ob.bounds.maxs()[0] > qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: entity xxx, brush yyy: bounds out of range\n");
|
||||
}
|
||||
if (ob.bounds.mins()[0] > qbsp_options.worldextent.value() || ob.bounds.maxs()[0] < -qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: entity xxx, brush yyy: no visible sides on brush\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
AddBrushBevels
|
||||
|
||||
Adds any additional planes necessary to allow the brush to be expanded
|
||||
against axial bounding boxes
|
||||
=================
|
||||
*/
|
||||
inline void AddBrushBevels(mapentity_t &e, mapbrush_t &b)
|
||||
{
|
||||
//
|
||||
// add the axial planes
|
||||
//
|
||||
int32_t order = 0;
|
||||
for (int32_t axis = 0; axis < 3; axis++) {
|
||||
for (int32_t dir = -1; dir <= 1; dir += 2, order++) {
|
||||
// see if the plane is already present
|
||||
int32_t i;
|
||||
|
||||
for (i = 0; i < b.numfaces; i++) {
|
||||
auto &s = b.face(i);
|
||||
|
||||
if (map.get_plane(s.planenum).get_normal()[axis] == dir) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == b.numfaces) {
|
||||
// add a new side
|
||||
b.numfaces++;
|
||||
mapface_t &s = map.faces.emplace_back();
|
||||
qplane3d plane{};
|
||||
plane.normal[axis] = dir;
|
||||
if (dir == 1) {
|
||||
plane.dist = b.bounds.maxs()[axis];
|
||||
} else {
|
||||
plane.dist = -b.bounds.mins()[axis];
|
||||
}
|
||||
s.planenum = map.add_or_find_plane(plane);
|
||||
s.texinfo = b.face(0).texinfo;
|
||||
s.contents = b.face(0).contents;
|
||||
// fixme: why did we need to store all this stuff again, isn't
|
||||
// it in texinfo?
|
||||
s.raw_info = b.face(0).raw_info;
|
||||
s.flags = b.face(0).flags;
|
||||
s.texname = b.face(0).texname;
|
||||
s.value = b.face(0).value;
|
||||
|
||||
s.bevel = true;
|
||||
e.numboxbevels++;
|
||||
}
|
||||
|
||||
// if the plane is not in it canonical order, swap it
|
||||
if (i != order) {
|
||||
std::swap(const_cast<mapface_t &>(b.face(order)), const_cast<mapface_t &>(b.face(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// add the edge bevels
|
||||
//
|
||||
if (b.numfaces == 6) {
|
||||
return; // pure axial
|
||||
}
|
||||
|
||||
// test the non-axial plane edges
|
||||
for (size_t i = 6; i < b.numfaces; i++) {
|
||||
auto &s = b.face(i);
|
||||
auto &w = s.winding;
|
||||
|
||||
if (!w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < w.size(); j++) {
|
||||
size_t k = (j + 1) % w.size();
|
||||
qvec3d vec = w[j] - w[k];
|
||||
|
||||
if (qv::normalizeInPlace(vec) < 0.5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec = qv::Snap(vec);
|
||||
|
||||
for (k = 0 ; k < 3; k++) {
|
||||
if (vec[k] == -1 || vec[k] == 1) {
|
||||
break; // axial
|
||||
}
|
||||
}
|
||||
|
||||
if (k != 3) {
|
||||
continue; // only test non-axial edges
|
||||
}
|
||||
|
||||
// try the six possible slanted axials from this edge
|
||||
for (size_t axis = 0; axis < 3; axis++) {
|
||||
for (size_t dir = -1; dir <= 1; dir += 2) {
|
||||
// construct a plane
|
||||
qplane3d plane {};
|
||||
plane.normal[axis] = dir;
|
||||
plane.normal = qv::cross(vec, plane.normal);
|
||||
if (qv::normalizeInPlace(plane.normal) < 0.5) {
|
||||
continue;
|
||||
}
|
||||
plane.dist = qv::dot(w[j], plane.normal);
|
||||
|
||||
// if all the points on all the sides are
|
||||
// behind this plane, it is a proper edge bevel
|
||||
for (k = 0; k < b.numfaces; k++) {
|
||||
// if this plane has allready been used, skip it
|
||||
if (qv::epsilonEqual(b.face(k).get_plane(), plane)) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto &w2 = b.face(k).winding;
|
||||
|
||||
if (!w2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t l = 0;
|
||||
for (; l < w2.size(); l++) {
|
||||
vec_t d = qv::dot(w2[l], plane.normal) - plane.dist;
|
||||
if (d > 0.1) {
|
||||
break; // point in front
|
||||
}
|
||||
}
|
||||
|
||||
if (l != w2.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (k != b.numfaces) {
|
||||
continue; // wasn't part of the outer hull
|
||||
}
|
||||
|
||||
// add this plane
|
||||
b.numfaces++;
|
||||
mapface_t &s = map.faces.emplace_back();
|
||||
s.planenum = map.add_or_find_plane(plane);
|
||||
s.texinfo = b.face(0).texinfo;
|
||||
s.contents = b.face(0).contents;
|
||||
// fixme: why did we need to store all this stuff again, isn't
|
||||
// it in texinfo?
|
||||
s.raw_info = b.face(0).raw_info;
|
||||
s.flags = b.face(0).flags;
|
||||
s.texname = b.face(0).texname;
|
||||
s.value = b.face(0).value;
|
||||
s.bevel = true;
|
||||
e.numedgebevels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
||||
{
|
||||
mapbrush_t brush;
|
||||
|
||||
|
|
@ -1677,9 +1881,11 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
|
|||
if (parser.token == "}")
|
||||
break;
|
||||
|
||||
std::unique_ptr<mapface_t> face = ParseBrushFace(parser, &brush, entity);
|
||||
if (face.get() == nullptr)
|
||||
std::optional<mapface_t> face = ParseBrushFace(parser, brush, entity);
|
||||
|
||||
if (!face) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for duplicate planes */
|
||||
bool discardFace = false;
|
||||
|
|
@ -1707,7 +1913,7 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
|
|||
}
|
||||
|
||||
brush.numfaces++;
|
||||
map.faces.push_back(*face);
|
||||
map.faces.emplace_back(std::move(face.value()));
|
||||
}
|
||||
|
||||
// ericw -- brush primitives - there should be another closing }
|
||||
|
|
@ -1719,6 +1925,12 @@ mapbrush_t ParseBrush(parser_t &parser, const mapentity_t *entity)
|
|||
}
|
||||
// ericw -- end brush primitives
|
||||
|
||||
// calculate brush bounds
|
||||
CalculateBrushBounds(brush);
|
||||
|
||||
// add the brush bevels
|
||||
AddBrushBevels(entity, brush);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
|
|
@ -1740,7 +1952,7 @@ bool ParseEntity(parser_t &parser, mapentity_t *entity)
|
|||
// once we run into the first brush, set up textures state.
|
||||
EnsureTexturesLoaded();
|
||||
|
||||
mapbrush_t brush = ParseBrush(parser, entity);
|
||||
mapbrush_t brush = ParseBrush(parser, *entity);
|
||||
|
||||
if (!entity->nummapbrushes)
|
||||
entity->firstmapbrush = map.brushes.size();
|
||||
|
|
|
|||
135
qbsp/qbsp.cc
135
qbsp/qbsp.cc
|
|
@ -317,135 +317,6 @@ static void ExportBrushList_r(const mapentity_t *entity, node_t *node)
|
|||
ExportBrushList_r(entity, node->children[1].get());
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
AddBrushBevels
|
||||
|
||||
Adds any additional planes necessary to allow the brush to be expanded
|
||||
against axial bounding boxes
|
||||
=================
|
||||
*/
|
||||
static std::vector<std::tuple<size_t, const side_t *>> AddBrushBevels(const bspbrush_t &b)
|
||||
{
|
||||
// add already-present planes
|
||||
std::vector<std::tuple<size_t, const side_t *>> planes;
|
||||
|
||||
for (auto &f : b.sides) {
|
||||
const qplane3d &plane = f.get_plane();
|
||||
int32_t outputplanenum = ExportMapPlane(plane);
|
||||
planes.emplace_back(outputplanenum, &f);
|
||||
}
|
||||
|
||||
//
|
||||
// add the axial planes
|
||||
//
|
||||
int32_t order = 0;
|
||||
for (int32_t axis = 0; axis < 3; axis++) {
|
||||
for (int32_t dir = -1; dir <= 1; dir += 2, order++) {
|
||||
size_t i;
|
||||
// see if the plane is allready present
|
||||
for (i = 0; i < planes.size(); i++) {
|
||||
if (map.bsp.dplanes[std::get<0>(planes[i])].normal[axis] == dir)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == planes.size()) {
|
||||
// add a new side
|
||||
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 outputplanenum = ExportMapPlane(new_plane);
|
||||
planes.emplace_back(outputplanenum, &b.sides.front());
|
||||
}
|
||||
|
||||
// if the plane is not in it canonical order, swap it
|
||||
if (i != order)
|
||||
std::swap(planes[i], planes[order]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// add the edge bevels
|
||||
//
|
||||
if (planes.size() == 6)
|
||||
return planes; // pure axial
|
||||
|
||||
// test the non-axial plane edges
|
||||
size_t edges_to_test = planes.size();
|
||||
for (size_t i = 6; i < edges_to_test; i++) {
|
||||
auto &s = std::get<1>(planes[i]);
|
||||
if (!s)
|
||||
continue;
|
||||
auto &w = s->w;
|
||||
if (!w.size())
|
||||
continue;
|
||||
for (size_t j = 0; j < w.size(); j++) {
|
||||
size_t k = (j + 1) % w.size();
|
||||
qvec3d vec = w[j] - w[k];
|
||||
if (qv::normalizeInPlace(vec) < 0.5)
|
||||
continue;
|
||||
vec = qv::Snap(vec);
|
||||
for (k = 0; k < 3; k++)
|
||||
if (vec[k] == -1 || vec[k] == 1)
|
||||
break; // axial
|
||||
if (k != 3)
|
||||
continue; // only test non-axial edges
|
||||
|
||||
// try the six possible slanted axials from this edge
|
||||
for (int32_t axis = 0; axis < 3; axis++) {
|
||||
for (int32_t dir = -1; dir <= 1; dir += 2) {
|
||||
qvec3d vec2{};
|
||||
// construct a plane
|
||||
vec2[axis] = dir;
|
||||
qplane3d current;
|
||||
current.normal = qv::cross(vec, vec2);
|
||||
if (qv::normalizeInPlace(current.normal) < 0.5)
|
||||
continue;
|
||||
current.dist = qv::dot(w[j], current.normal);
|
||||
|
||||
auto it = b.sides.begin();
|
||||
|
||||
// if all the points on all the sides are
|
||||
// behind this plane, it is a proper edge bevel
|
||||
for (; it != b.sides.end(); it++) {
|
||||
auto &f = *it;
|
||||
const qplane3d &plane = f.get_plane();
|
||||
|
||||
// if this plane has allready been used, skip it
|
||||
if (qv::epsilonEqual(current, plane))
|
||||
break;
|
||||
|
||||
auto &w2 = f.w;
|
||||
if (!w2.size())
|
||||
continue;
|
||||
size_t l;
|
||||
for (l = 0; l < w2.size(); l++) {
|
||||
vec_t d = current.distance_to(w2[l]);
|
||||
if (d > 0.1)
|
||||
break; // point in front
|
||||
}
|
||||
if (l != w2.size())
|
||||
break;
|
||||
}
|
||||
|
||||
if (it != b.sides.end())
|
||||
continue; // wasn't part of the outer hull
|
||||
|
||||
// add this plane
|
||||
int32_t outputplanenum = ExportMapPlane(current);
|
||||
planes.emplace_back(outputplanenum, &b.sides.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return planes;
|
||||
}
|
||||
|
||||
static void ExportBrushList(mapentity_t *entity, node_t *node)
|
||||
{
|
||||
logging::funcheader();
|
||||
|
|
@ -458,11 +329,9 @@ static void ExportBrushList(mapentity_t *entity, node_t *node)
|
|||
dbrush_t &brush = map.bsp.dbrushes.emplace_back(
|
||||
dbrush_t{static_cast<int32_t>(map.bsp.dbrushsides.size()), 0, b->contents.native});
|
||||
|
||||
auto bevels = AddBrushBevels(*b);
|
||||
|
||||
for (auto &plane : bevels) {
|
||||
for (auto &side : b->sides) {
|
||||
map.bsp.dbrushsides.push_back(
|
||||
{(uint32_t)std::get<0>(plane), (int32_t)ExportMapTexinfo(std::get<1>(plane)->texinfo)});
|
||||
{(uint32_t) side.planenum, (int32_t)ExportMapTexinfo(side.texinfo)});
|
||||
brush.numsides++;
|
||||
brush_state.total_brush_sides++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue