track a shared pointer for `map_source_location` instead of memory pointer, so that we can allocate it as we go
use it for brushes and faces
This commit is contained in:
parent
9af74ce083
commit
627428756c
|
|
@ -48,29 +48,61 @@ struct map_source_location
|
|||
// to be. note that because the locations only live for the lifetime
|
||||
// of the object it is belonging to, whatever this string
|
||||
// points to must out-live the object.
|
||||
std::string_view source_name;
|
||||
std::shared_ptr<std::string> source_name = nullptr;
|
||||
|
||||
// the line number that this location is associated to, if any. Synthetic
|
||||
// locations may not necessarily have an associated line number.
|
||||
std::optional<size_t> line_number;
|
||||
std::optional<size_t> line_number = std::nullopt;
|
||||
|
||||
// reference to a location of the object that derived us. this is mainly
|
||||
// for synthetic locations; ie a bspbrush_t's sides aren't themselves generated
|
||||
// by a source or line, but they are derived from a mapbrush_t which does have
|
||||
// a location. The object it points to must outlive this object.
|
||||
const std::optional<std::reference_wrapper<map_source_location>> derivative;
|
||||
// a location. The object it points to must outlive this object. this is mainly
|
||||
// for debugging.
|
||||
std::optional<std::reference_wrapper<const map_source_location>> derivative = std::nullopt;
|
||||
|
||||
explicit operator bool() const { return source_name != nullptr; }
|
||||
|
||||
// return a modified source location with only the line changeed
|
||||
inline map_source_location on_line(size_t new_line) const
|
||||
{
|
||||
return { source_name, new_line, derivative };
|
||||
}
|
||||
|
||||
// if we update to C++20 we could use this to track where location objects come from:
|
||||
// std::source_location created_location;
|
||||
};
|
||||
|
||||
// FMT support
|
||||
template<>
|
||||
struct fmt::formatter<map_source_location>
|
||||
{
|
||||
constexpr auto parse(format_parse_context &ctx) -> decltype(ctx.begin()) { return ctx.end(); }
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const map_source_location &v, FormatContext &ctx) -> decltype(ctx.out())
|
||||
{
|
||||
if (v.source_name) {
|
||||
format_to(ctx.out(), "{}", *v.source_name.get());
|
||||
} else {
|
||||
format_to(ctx.out(), "unknown/unset location");
|
||||
}
|
||||
|
||||
if (v.line_number.has_value()) {
|
||||
format_to(ctx.out(), "[line {}]", v.line_number.value());
|
||||
}
|
||||
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
struct mapface_t
|
||||
{
|
||||
size_t planenum;
|
||||
std::array<qvec3d, 3> planepts{};
|
||||
std::string texname{};
|
||||
int texinfo = 0;
|
||||
int linenum = 0;
|
||||
map_source_location line;
|
||||
bool bevel = false;
|
||||
bool visible = false;
|
||||
winding_t winding; // winding used to calculate bevels
|
||||
|
|
@ -105,7 +137,7 @@ public:
|
|||
brushformat_t format = brushformat_t::NORMAL;
|
||||
aabb3d bounds {};
|
||||
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
||||
size_t entitynum = 0, linenum = 0;
|
||||
map_source_location line;
|
||||
};
|
||||
|
||||
struct lumpdata
|
||||
|
|
@ -370,7 +402,7 @@ extern mapdata_t map;
|
|||
|
||||
void CalculateWorldExtent(void);
|
||||
|
||||
bool ParseEntity(parser_t &parser, mapentity_t *entity);
|
||||
bool ParseEntity(parser_t &parser, mapentity_t *entity, const map_source_location &map_source);
|
||||
|
||||
void ProcessExternalMapEntity(mapentity_t *entity);
|
||||
void ProcessAreaPortal(mapentity_t *entity);
|
||||
|
|
|
|||
|
|
@ -80,11 +80,11 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
|||
if (face->w.size() < 3) {
|
||||
if (face->w.size() == 2) {
|
||||
logging::print(
|
||||
"WARNING: line {}: partially clipped into degenerate polygon @ ({}) - ({})\n", sourceface.linenum, face->w[0], face->w[1]);
|
||||
"WARNING: {}: partially clipped into degenerate polygon @ ({}) - ({})\n", sourceface.line, face->w[0], face->w[1]);
|
||||
} else if (face->w.size() == 1) {
|
||||
logging::print("WARNING: line {}: partially clipped into degenerate polygon @ ({})\n", sourceface.linenum, face->w[0]);
|
||||
logging::print("WARNING: {}: partially clipped into degenerate polygon @ ({})\n", sourceface.line, face->w[0]);
|
||||
} else {
|
||||
logging::print("WARNING: line {}: completely clipped away\n", sourceface.linenum);
|
||||
logging::print("WARNING: {}: completely clipped away\n", sourceface.line);
|
||||
}
|
||||
|
||||
face->w.clear();
|
||||
|
|
@ -101,7 +101,7 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
|||
for (auto &v : p1) {
|
||||
if (fabs(v) > qbsp_options.worldextent.value()) {
|
||||
// this is fatal because a point should never lay outside the world
|
||||
FError("line {}: coordinate out of range ({})\n", sourceface.linenum, v);
|
||||
FError("{}: coordinate out of range ({})\n", sourceface.line, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
|||
{
|
||||
vec_t dist = face->get_plane().distance_to(p1);
|
||||
if (fabs(dist) > qbsp_options.epsilon.value()) {
|
||||
logging::print("WARNING: Line {}: Point ({:.3} {:.3} {:.3}) off plane by {:2.4}\n", sourceface.linenum,
|
||||
logging::print("WARNING: {}: Point ({:.3} {:.3} {:.3}) off plane by {:2.4}\n", sourceface.line,
|
||||
p1[0], p1[1], p1[2], dist);
|
||||
}
|
||||
}
|
||||
|
|
@ -118,8 +118,8 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
|||
qvec3d edgevec = p2 - p1;
|
||||
vec_t length = qv::length(edgevec);
|
||||
if (length < qbsp_options.epsilon.value()) {
|
||||
logging::print("WARNING: Line {}: Healing degenerate edge ({}) at ({:.3f} {:.3} {:.3})\n",
|
||||
sourceface.linenum, length, p1[0], p1[1], p1[2]);
|
||||
logging::print("WARNING: {}: Healing degenerate edge ({}) at ({:.3f} {:.3} {:.3})\n",
|
||||
sourceface.line, length, p1[0], p1[1], p1[2]);
|
||||
for (size_t j = i + 1; j < face->w.size(); j++)
|
||||
face->w[j - 1] = face->w[j];
|
||||
face->w.resize(face->w.size() - 1);
|
||||
|
|
@ -137,8 +137,8 @@ static void CheckFace(side_t *face, const mapface_t &sourceface)
|
|||
continue;
|
||||
vec_t dist = qv::dot(face->w[j], edgenormal);
|
||||
if (dist > edgedist) {
|
||||
logging::print("WARNING: line {}: Found a non-convex face (error size {}, point: {})\n",
|
||||
sourceface.linenum, dist - edgedist, face->w[j]);
|
||||
logging::print("WARNING: {}: Found a non-convex face (error size {}, point: {})\n",
|
||||
sourceface.line, dist - edgedist, face->w[j]);
|
||||
face->w.clear();
|
||||
return;
|
||||
}
|
||||
|
|
@ -252,9 +252,8 @@ contentflags_t Brush_GetContents(const mapbrush_t *mapbrush)
|
|||
}
|
||||
|
||||
if (!contents.types_equal(base_contents, qbsp_options.target_game)) {
|
||||
logging::print("mixed face contents ({} != {}) at line {}\n",
|
||||
base_contents.to_string(qbsp_options.target_game), contents.to_string(qbsp_options.target_game),
|
||||
mapface.linenum);
|
||||
logging::print("WARNING: {}: mixed face contents ({} != {})\n",
|
||||
mapface.line, base_contents.to_string(qbsp_options.target_game), contents.to_string(qbsp_options.target_game));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -629,11 +628,12 @@ void bspbrush_t::update_bounds()
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
// todo: map_source_location in bspbrush_t
|
||||
if (this->bounds.mins()[0] <= -qbsp_options.worldextent.value() || this->bounds.maxs()[0] >= qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: line {}: brush bounds out of range\n", mapbrush->linenum);
|
||||
logging::print("WARNING: {}: brush bounds out of range\n", mapbrush ? mapbrush->line : map_source_location());
|
||||
}
|
||||
if (this->bounds.mins()[0] >= qbsp_options.worldextent.value() || this->bounds.maxs()[0] <= -qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: line {}: no visible sides on brush\n", mapbrush->linenum);
|
||||
logging::print("WARNING: {}: no visible sides on brush\n", mapbrush ? mapbrush->line : map_source_location());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1072,10 +1072,12 @@ static std::unique_ptr<tree_t> BrushBSP(mapentity_t *entity, std::vector<std::un
|
|||
for (const auto &b : brushlist) {
|
||||
c_brushes++;
|
||||
|
||||
// fixme-brushbsp: why does this just print and do nothing? should
|
||||
// the brush be removed?
|
||||
double volume = BrushVolume(*b);
|
||||
if (volume < qbsp_options.microvolume.value()) {
|
||||
logging::print("WARNING: line {}: microbrush\n",
|
||||
b->original->mapbrush->linenum);
|
||||
logging::print("WARNING: {}: microbrush\n",
|
||||
b->original->mapbrush->line);
|
||||
}
|
||||
|
||||
for (side_t &side : b->sides) {
|
||||
|
|
|
|||
50
qbsp/map.cc
50
qbsp/map.cc
|
|
@ -1475,14 +1475,14 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush
|
|||
if (!(extinfo.info->flags.native & (Q2_SURF_TRANS33 | Q2_SURF_TRANS66))) {
|
||||
extinfo.info->contents.native |= Q2_CONTENTS_DETAIL;
|
||||
|
||||
logging::print("WARNING: face at line {}: swapped TRANSLUCENT for DETAIL\n", mapface.linenum);
|
||||
logging::print("WARNING: {}: swapped TRANSLUCENT for DETAIL\n", mapface.line);
|
||||
}
|
||||
}
|
||||
|
||||
// This fixes a bug in some old maps.
|
||||
if ((extinfo.info->flags.native & (Q2_SURF_SKY | Q2_SURF_NODRAW)) == (Q2_SURF_SKY | Q2_SURF_NODRAW)) {
|
||||
extinfo.info->flags.native &= ~Q2_SURF_NODRAW;
|
||||
logging::print("WARNING: face at line {}: SKY | NODRAW mixed. Removing NODRAW.\n", mapface.linenum);
|
||||
logging::print("WARNING: {}: SKY | NODRAW mixed. Removing NODRAW.\n", mapface.line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1497,7 +1497,7 @@ static void ParseTextureDef(parser_t &parser, mapface_t &mapface, const mapbrush
|
|||
if (!contents.is_valid(qbsp_options.target_game, false)) {
|
||||
auto old_contents = contents;
|
||||
qbsp_options.target_game->contents_make_valid(contents);
|
||||
logging::print("WARNING: line {}: face has invalid contents {}, remapped to {}\n", mapface.linenum,
|
||||
logging::print("WARNING: {}: face has invalid contents {}, remapped to {}\n", mapface.line,
|
||||
old_contents.to_string(qbsp_options.target_game), contents.to_string(qbsp_options.target_game));
|
||||
}
|
||||
|
||||
|
|
@ -1581,8 +1581,8 @@ inline bool IsValidTextureProjection(const mapface_t &mapface, const maptexinfo_
|
|||
static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx)
|
||||
{
|
||||
if (!IsValidTextureProjection(mapface, tx)) {
|
||||
logging::print("WARNING: repairing invalid texture projection on line {} (\"{}\" near {} {} {})\n",
|
||||
mapface.linenum, mapface.texname, (int)mapface.planepts[0][0], (int)mapface.planepts[0][1],
|
||||
logging::print("WARNING: {}: repairing invalid texture projection (\"{}\" near {} {} {})\n",
|
||||
mapface.line, mapface.texname, (int)mapface.planepts[0][0], (int)mapface.planepts[0][1],
|
||||
(int)mapface.planepts[0][2]);
|
||||
|
||||
// Reset texturing to sensible defaults
|
||||
|
|
@ -1603,7 +1603,8 @@ static std::optional<mapface_t> ParseBrushFace(parser_t &parser, const mapbrush_
|
|||
int i, j;
|
||||
mapface_t face;
|
||||
|
||||
face.linenum = parser.linenum;
|
||||
face.line = brush.line.on_line(parser.linenum);
|
||||
|
||||
ParsePlaneDef(parser, planepts);
|
||||
|
||||
normal_ok = face.set_planepts(planepts);
|
||||
|
|
@ -1789,13 +1790,13 @@ inline void AddBrushBevels(mapentity_t &e, mapbrush_t &b)
|
|||
}
|
||||
}
|
||||
|
||||
static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
||||
static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, const map_source_location &entity_source)
|
||||
{
|
||||
mapbrush_t brush;
|
||||
|
||||
// ericw -- brush primitives
|
||||
if (!parser.parse_token(PARSE_PEEK))
|
||||
FError("Unexpected EOF after { beginning brush");
|
||||
FError("{}: unexpected EOF after { beginning brush", entity_source);
|
||||
|
||||
if (parser.token == "(") {
|
||||
brush.format = brushformat_t::NORMAL;
|
||||
|
|
@ -1818,8 +1819,8 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
|||
while (parser.parse_token()) {
|
||||
|
||||
// set linenum after first parsed token
|
||||
if (!brush.linenum) {
|
||||
brush.linenum = parser.linenum;
|
||||
if (!brush.line) {
|
||||
brush.line = entity_source.on_line(parser.linenum);
|
||||
}
|
||||
|
||||
if (parser.token == "}")
|
||||
|
|
@ -1866,13 +1867,16 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity)
|
|||
return brush;
|
||||
}
|
||||
|
||||
bool ParseEntity(parser_t &parser, mapentity_t *entity)
|
||||
bool ParseEntity(parser_t &parser, mapentity_t *entity, const map_source_location &map_source)
|
||||
{
|
||||
if (!parser.parse_token())
|
||||
return false;
|
||||
|
||||
if (parser.token != "{")
|
||||
FError("line {}: Invalid entity format, { not found", parser.linenum);
|
||||
map_source_location entity_source = map_source.on_line(parser.linenum);
|
||||
|
||||
if (parser.token != "{") {
|
||||
FError("{}: Invalid entity format, { not found", entity_source);
|
||||
}
|
||||
|
||||
entity->mapbrushes.clear();
|
||||
|
||||
|
|
@ -1885,7 +1889,7 @@ bool ParseEntity(parser_t &parser, mapentity_t *entity)
|
|||
// once we run into the first brush, set up textures state.
|
||||
EnsureTexturesLoaded();
|
||||
|
||||
entity->mapbrushes.emplace_back(ParseBrush(parser, *entity));
|
||||
entity->mapbrushes.emplace_back(ParseBrush(parser, *entity, entity_source));
|
||||
} else {
|
||||
ParseEpair(parser, entity);
|
||||
}
|
||||
|
|
@ -2007,9 +2011,10 @@ static mapentity_t LoadExternalMap(const std::string &filename)
|
|||
}
|
||||
|
||||
parser_t parser(file->data(), file->size());
|
||||
map_source_location entity_source { std::make_shared<std::string>(filename), parser.linenum };
|
||||
|
||||
// parse the worldspawn
|
||||
if (!ParseEntity(parser, &dest)) {
|
||||
if (!ParseEntity(parser, &dest, entity_source)) {
|
||||
FError("'{}': Couldn't parse worldspawn entity\n", filename);
|
||||
}
|
||||
const std::string &classname = dest.epairs.get("classname");
|
||||
|
|
@ -2019,7 +2024,7 @@ static mapentity_t LoadExternalMap(const std::string &filename)
|
|||
|
||||
// parse any subsequent entities, move any brushes to worldspawn
|
||||
mapentity_t dummy{};
|
||||
while (ParseEntity(parser, &dummy)) {
|
||||
while (ParseEntity(parser, &dummy, entity_source = entity_source.on_line(parser.linenum))) {
|
||||
// move the brushes to the worldspawn
|
||||
dest.mapbrushes.insert(dest.mapbrushes.end(), std::make_move_iterator(dummy.mapbrushes.begin()), std::make_move_iterator(dummy.mapbrushes.end()));
|
||||
|
||||
|
|
@ -2198,10 +2203,10 @@ inline void CalculateBrushBounds(mapbrush_t &ob)
|
|||
|
||||
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: line {}: brush bounds out of range\n", ob.linenum);
|
||||
logging::print("WARNING: {}: brush bounds out of range\n", ob.line);
|
||||
}
|
||||
if (ob.bounds.mins()[0] >= qbsp_options.worldextent.value() || ob.bounds.maxs()[0] <= -qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: line {}: no visible sides on brush\n", ob.linenum);
|
||||
logging::print("WARNING: {}: no visible sides on brush\n", ob.line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2239,7 +2244,8 @@ void ProcessMapBrushes()
|
|||
if (&entity == map.world_entity()) {
|
||||
logging::print("WARNING: Ignoring origin brush in worldspawn\n");
|
||||
} else if (entity.epairs.has("origin")) {
|
||||
logging::print("WARNING: Entity at line {} has multiple origin brushes\n", entity.mapbrushes.front().faces[0].linenum);
|
||||
// fixme-brushbsp: entity.line
|
||||
logging::print("WARNING: Entity at {} has multiple origin brushes\n", entity.mapbrushes.front().faces[0].line);
|
||||
} else {
|
||||
entity.origin = brush.bounds.centroid();
|
||||
entity.epairs.set("origin", qv::to_string(entity.origin));
|
||||
|
|
@ -2350,11 +2356,12 @@ void LoadMapFile(void)
|
|||
}
|
||||
|
||||
parser_t parser(file->data(), file->size());
|
||||
map_source_location entity_source { std::make_shared<std::string>(qbsp_options.map_path.string()) };
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
mapentity_t &entity = map.entities.emplace_back();
|
||||
|
||||
if (!ParseEntity(parser, &entity)) {
|
||||
if (!ParseEntity(parser, &entity, entity_source.on_line(parser.linenum))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2375,11 +2382,12 @@ void LoadMapFile(void)
|
|||
}
|
||||
|
||||
parser_t parser(file->data(), file->size());
|
||||
map_source_location entity_source { std::make_shared<std::string>(qbsp_options.add.value()) };
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
mapentity_t &entity = map.entities.emplace_back();
|
||||
|
||||
if (!ParseEntity(parser, &entity)) {
|
||||
if (!ParseEntity(parser, &entity, entity_source.on_line(parser.linenum))) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,10 +44,12 @@ static mapentity_t LoadMap(const char *map)
|
|||
// FIXME: ???
|
||||
mapentity_t &entity = ::map.entities.emplace_back();
|
||||
|
||||
map_source_location entity_source { std::make_shared<std::string>(Catch::getResultCapture().getCurrentTestName()), 0 };
|
||||
|
||||
mapentity_t worldspawn;
|
||||
|
||||
// FIXME: adds the brush to the global map...
|
||||
Q_assert(ParseEntity(parser, &worldspawn));
|
||||
Q_assert(ParseEntity(parser, &worldspawn, entity_source));
|
||||
|
||||
CalculateWorldExtent();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue