qbsp: use mapfile.cc for .map file parsing
BP loading is broken by this commit, will need to re-introduce loading the texture sizes in mapfile.
This commit is contained in:
parent
9985d6c8fd
commit
c714ce597a
|
|
@ -414,14 +414,45 @@ inline std::tuple<qvec3d, qvec3d> compute_axis_base(const qvec3d &normal_unsanit
|
|||
|
||||
void brush_side_t::set_texinfo(const texdef_bp_t &texdef)
|
||||
{
|
||||
#if 0
|
||||
const auto &texture = map.load_image_meta(mapface.texname.c_str());
|
||||
const int32_t width = texture ? texture->width : 64;
|
||||
const int32_t height = texture ? texture->height : 64;
|
||||
// FIXME:
|
||||
const int32_t texWidth = 64;
|
||||
const int32_t texHeight = 64;
|
||||
|
||||
SetTexinfo_BrushPrimitives(texMat, plane.normal, width, height, tx->vecs);
|
||||
#endif
|
||||
FError("todo BP");
|
||||
const auto [texX, texY] = compute_axis_base(plane.normal);
|
||||
const auto texMat = texdef.axis;
|
||||
|
||||
/*
|
||||
derivation of the conversion below:
|
||||
|
||||
classic BSP texture vecs to texture coordinates:
|
||||
|
||||
u = (dot(vert, out->vecs[0]) + out->vecs[3]) / texWidth
|
||||
|
||||
brush primitives: (starting with q3map2 code, then rearranging it to look like the classic formula)
|
||||
|
||||
u = (texMat[0][0] * dot(vert, texX)) + (texMat[0][1] * dot(vert, texY)) + texMat[0][2]
|
||||
|
||||
factor out vert:
|
||||
|
||||
u = (vert[0] * (texX[0] * texMat[0][0] + texY[0] * texMat[0][1]))
|
||||
+ (vert[1] * (texX[1] * texMat[0][0] + texY[1] * texMat[0][1]))
|
||||
+ (vert[2] * (texX[2] * texMat[0][0] + texY[2] * texMat[0][1]))
|
||||
+ texMat[0][2];
|
||||
|
||||
multiplying that by 1 = (texWidth / texWidth) gives us something in the same shape as the classic formula,
|
||||
so we can get out->vecs.
|
||||
|
||||
*/
|
||||
|
||||
vecs.at(0, 0) = texWidth * ((texX[0] * texMat.at(0, 0)) + (texY[0] * texMat.at(0, 1)));
|
||||
vecs.at(0, 1) = texWidth * ((texX[1] * texMat.at(0, 0)) + (texY[1] * texMat.at(0, 1)));
|
||||
vecs.at(0, 2) = texWidth * ((texX[2] * texMat.at(0, 0)) + (texY[2] * texMat.at(0, 1)));
|
||||
vecs.at(0, 3) = texWidth * texMat.at(0, 2);
|
||||
|
||||
vecs.at(1, 0) = texHeight * ((texX[0] * texMat.at(1, 0)) + (texY[0] * texMat.at(1, 1)));
|
||||
vecs.at(1, 1) = texHeight * ((texX[1] * texMat.at(1, 0)) + (texY[1] * texMat.at(1, 1)));
|
||||
vecs.at(1, 2) = texHeight * ((texX[2] * texMat.at(1, 0)) + (texY[2] * texMat.at(1, 1)));
|
||||
vecs.at(1, 3) = texHeight * texMat.at(1, 2);
|
||||
}
|
||||
|
||||
void brush_side_t::parse_texture_def(parser_t &parser, texcoord_style_t base_format)
|
||||
|
|
@ -1203,4 +1234,13 @@ void map_file_t::convert_to(texcoord_style_t style, const gamedef_t *game, const
|
|||
}
|
||||
}
|
||||
|
||||
map_file_t parse(const std::string_view &view, parser_source_location base_location)
|
||||
{
|
||||
parser_t parser(view, base_location);
|
||||
|
||||
map_file_t result;
|
||||
result.parse(parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mapfile
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ See file, 'COPYING', for details.
|
|||
#include <string>
|
||||
#include <variant>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
// this file declares some names that clash with names elsewhere in the project and lead to ODR violations
|
||||
// (e.g. texdef_valve_t). For now just wrap everything in a namespace to avoid issues.
|
||||
|
|
@ -209,4 +210,6 @@ struct map_file_t
|
|||
void convert_to(texcoord_style_t style, const gamedef_t *game, const settings::common_settings &options);
|
||||
};
|
||||
|
||||
map_file_t parse(const std::string_view &view, parser_source_location base_location);
|
||||
|
||||
} // namespace mapfile
|
||||
|
|
|
|||
|
|
@ -87,19 +87,12 @@ struct mapface_t
|
|||
const qbsp_plane_t &get_positive_plane() const;
|
||||
};
|
||||
|
||||
enum class brushformat_t
|
||||
{
|
||||
NORMAL,
|
||||
BRUSH_PRIMITIVES
|
||||
};
|
||||
|
||||
class mapentity_t;
|
||||
|
||||
class mapbrush_t
|
||||
{
|
||||
public:
|
||||
std::vector<mapface_t> faces;
|
||||
brushformat_t format = brushformat_t::NORMAL;
|
||||
aabb3d bounds{};
|
||||
std::optional<uint32_t> outputnumber; /* only set for original brushes */
|
||||
parser_source_location line;
|
||||
|
|
@ -302,7 +295,10 @@ struct texture_def_issues_t : logging::stat_tracker_t
|
|||
true);
|
||||
};
|
||||
|
||||
bool ParseEntity(parser_t &parser, mapentity_t &entity, texture_def_issues_t &issues_stats);
|
||||
namespace mapfile {
|
||||
struct map_entity_t;
|
||||
}
|
||||
void ParseEntity(const mapfile::map_entity_t &in_entity, mapentity_t &entity, texture_def_issues_t &issue_stats);
|
||||
|
||||
void ProcessExternalMapEntity(mapentity_t &entity);
|
||||
void ProcessAreaPortal(mapentity_t &entity);
|
||||
|
|
@ -314,9 +310,6 @@ void ProcessMapBrushes();
|
|||
|
||||
struct quark_tx_info_t
|
||||
{
|
||||
bool quark_tx1 = false;
|
||||
bool quark_tx2 = false;
|
||||
|
||||
std::optional<extended_texinfo_t> info;
|
||||
};
|
||||
|
||||
|
|
|
|||
329
qbsp/map.cc
329
qbsp/map.cc
|
|
@ -315,26 +315,6 @@ void mapdata_t::reset()
|
|||
*this = mapdata_t{};
|
||||
}
|
||||
|
||||
struct old_texdef_valve_t
|
||||
{
|
||||
qmat<double, 2, 3> axis{};
|
||||
qvec2d scale{};
|
||||
qvec2d shift{};
|
||||
};
|
||||
|
||||
struct old_texdef_quake_ed_t
|
||||
{
|
||||
double rotate = 0;
|
||||
qvec2d scale{};
|
||||
qvec2d shift{};
|
||||
};
|
||||
|
||||
struct old_texdef_quake_ed_noshift_t
|
||||
{
|
||||
double rotate = 0;
|
||||
qvec2d scale{};
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
CalculateBrushBounds
|
||||
|
|
@ -380,14 +360,6 @@ inline void CalculateBrushBounds(mapbrush_t &ob)
|
|||
}
|
||||
}
|
||||
|
||||
using texdef_brush_primitives_t = qmat<double, 2, 3>;
|
||||
|
||||
static old_texdef_valve_t TexDef_BSPToValve(const texvecf &in_vecs);
|
||||
static qvec2f projectToAxisPlane(const qvec3d &snapped_normal, const qvec3d &point);
|
||||
static old_texdef_quake_ed_noshift_t Reverse_QuakeEd(qmat2x2f M, const qbsp_plane_t &plane, bool preserveX);
|
||||
static void SetTexinfo_QuakeEd_New(
|
||||
const qbsp_plane_t &plane, const qvec2d &shift, double rotate, const qvec2d &scale, texvecf &out_vecs);
|
||||
|
||||
static void AddAnimTex(const char *name)
|
||||
{
|
||||
int i, j, frame;
|
||||
|
|
@ -840,6 +812,7 @@ static surfflags_t SurfFlagsForEntity(
|
|||
return flags;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void ParseEpair(parser_t &parser, mapentity_t &entity)
|
||||
{
|
||||
std::string key = parser.token;
|
||||
|
|
@ -1552,47 +1525,6 @@ static void ComputeAxisBase(const qvec3d &normal_unsanitized, qvec3d &texX, qvec
|
|||
texY[2] = -cos(RotY);
|
||||
}
|
||||
|
||||
static void SetTexinfo_BrushPrimitives(
|
||||
const qmat<double, 2, 3> &texMat, const qvec3d &faceNormal, int texWidth, int texHeight, texvecf &vecs)
|
||||
{
|
||||
qvec3d texX, texY;
|
||||
|
||||
ComputeAxisBase(faceNormal, texX, texY);
|
||||
|
||||
/*
|
||||
derivation of the conversion below:
|
||||
|
||||
classic BSP texture vecs to texture coordinates:
|
||||
|
||||
u = (dot(vert, out->vecs[0]) + out->vecs[3]) / texWidth
|
||||
|
||||
brush primitives: (starting with q3map2 code, then rearranging it to look like the classic formula)
|
||||
|
||||
u = (texMat[0][0] * dot(vert, texX)) + (texMat[0][1] * dot(vert, texY)) + texMat[0][2]
|
||||
|
||||
factor out vert:
|
||||
|
||||
u = (vert[0] * (texX[0] * texMat[0][0] + texY[0] * texMat[0][1]))
|
||||
+ (vert[1] * (texX[1] * texMat[0][0] + texY[1] * texMat[0][1]))
|
||||
+ (vert[2] * (texX[2] * texMat[0][0] + texY[2] * texMat[0][1]))
|
||||
+ texMat[0][2];
|
||||
|
||||
multiplying that by 1 = (texWidth / texWidth) gives us something in the same shape as the classic formula,
|
||||
so we can get out->vecs.
|
||||
|
||||
*/
|
||||
|
||||
vecs.at(0, 0) = texWidth * ((texX[0] * texMat.at(0, 0)) + (texY[0] * texMat.at(0, 1)));
|
||||
vecs.at(0, 1) = texWidth * ((texX[1] * texMat.at(0, 0)) + (texY[1] * texMat.at(0, 1)));
|
||||
vecs.at(0, 2) = texWidth * ((texX[2] * texMat.at(0, 0)) + (texY[2] * texMat.at(0, 1)));
|
||||
vecs.at(0, 3) = texWidth * texMat.at(0, 2);
|
||||
|
||||
vecs.at(1, 0) = texHeight * ((texX[0] * texMat.at(1, 0)) + (texY[0] * texMat.at(1, 1)));
|
||||
vecs.at(1, 1) = texHeight * ((texX[1] * texMat.at(1, 0)) + (texY[1] * texMat.at(1, 1)));
|
||||
vecs.at(1, 2) = texHeight * ((texX[2] * texMat.at(1, 0)) + (texY[2] * texMat.at(1, 1)));
|
||||
vecs.at(1, 3) = texHeight * texMat.at(1, 2);
|
||||
}
|
||||
|
||||
// From FaceToBrushPrimitFace in GtkRadiant
|
||||
static texdef_brush_primitives_t TexDef_BSPToBrushPrimitives(
|
||||
const qplane3d &plane, const int texSize[2], const texvecf &in_vecs)
|
||||
|
|
@ -1702,17 +1634,26 @@ static void ParseBrushPrimTX(parser_t &parser, qmat<double, 2, 3> &texMat)
|
|||
parse_error:
|
||||
FError("{}: couldn't parse Brush Primitives texture info", parser.location);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ParseTextureDef(const mapentity_t &entity, parser_t &parser, mapface_t &mapface, const mapbrush_t &brush,
|
||||
static void ParseTextureDef(const mapentity_t &entity, const mapfile::brush_side_t &input_side, mapface_t &mapface, const mapbrush_t &brush,
|
||||
maptexinfo_t *tx, std::array<qvec3d, 3> &planepts, const qplane3d &plane, texture_def_issues_t &issue_stats)
|
||||
{
|
||||
double rotate;
|
||||
qmat<double, 2, 3> texMat, axis;
|
||||
qvec2d shift, scale;
|
||||
old_texcoord_style_t tx_type;
|
||||
|
||||
quark_tx_info_t extinfo;
|
||||
mapface.texname = input_side.texture;
|
||||
|
||||
// copy in Q2 attributes if present
|
||||
if (input_side.extended_info) {
|
||||
extinfo.info = {extended_texinfo_t{}};
|
||||
|
||||
extinfo.info->contents_native = input_side.extended_info->contents;
|
||||
extinfo.info->flags = input_side.extended_info->flags;
|
||||
extinfo.info->value = input_side.extended_info->value;
|
||||
|
||||
mapface.raw_info = extinfo.info;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (brush.format == brushformat_t::BRUSH_PRIMITIVES) {
|
||||
ParseBrushPrimTX(parser, texMat);
|
||||
tx_type = TX_BRUSHPRIM;
|
||||
|
|
@ -1762,6 +1703,7 @@ static void ParseTextureDef(const mapentity_t &entity, parser_t &parser, mapface
|
|||
} else {
|
||||
FError("{}: Bad brush format", parser.location);
|
||||
}
|
||||
#endif
|
||||
|
||||
// if we have texture defs, see if we should remap this one
|
||||
if (auto it = qbsp_options.loaded_texture_defs.find(mapface.texname);
|
||||
|
|
@ -1872,6 +1814,9 @@ static void ParseTextureDef(const mapentity_t &entity, parser_t &parser, mapface
|
|||
old_contents.to_string(qbsp_options.target_game), mapface.contents.to_string(qbsp_options.target_game));
|
||||
}
|
||||
|
||||
tx->vecs = input_side.vecs;
|
||||
|
||||
#if 0
|
||||
switch (tx_type) {
|
||||
case TX_QUARK_TYPE1:
|
||||
case TX_QUARK_TYPE2: SetTexinfo_QuArK(parser, planepts, tx_type, tx); break;
|
||||
|
|
@ -1887,6 +1832,7 @@ static void ParseTextureDef(const mapentity_t &entity, parser_t &parser, mapface
|
|||
case TX_QUAKED:
|
||||
default: SetTexinfo_QuakeEd(plane, planepts, shift, rotate, scale, tx); break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mapface_t::set_planepts(const std::array<qvec3d, 3> &pts)
|
||||
|
|
@ -1935,6 +1881,7 @@ const qbsp_plane_t &mapface_t::get_positive_plane() const
|
|||
return map.get_plane(planenum & ~1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec)
|
||||
{
|
||||
// TODO: This doesn't match how light does it (TexSpaceToWorld)
|
||||
|
|
@ -1978,26 +1925,22 @@ static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx, text
|
|||
Q_assert(IsValidTextureProjection(mapface, tx));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::optional<mapface_t> ParseBrushFace(
|
||||
parser_t &parser, const mapbrush_t &brush, const mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
const mapfile::brush_side_t &input_side, const mapbrush_t &brush, const mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
{
|
||||
std::array<qvec3d, 3> planepts;
|
||||
bool normal_ok;
|
||||
maptexinfo_t tx;
|
||||
int i, j;
|
||||
mapface_t face;
|
||||
|
||||
face.line = parser.location;
|
||||
face.line = input_side.location;
|
||||
|
||||
ParsePlaneDef(parser, planepts);
|
||||
const bool normal_ok = face.set_planepts(input_side.planepts);
|
||||
|
||||
normal_ok = face.set_planepts(planepts);
|
||||
|
||||
ParseTextureDef(entity, parser, face, brush, &tx, face.planepts, face.get_plane(), issue_stats);
|
||||
ParseTextureDef(entity, input_side, face, brush, &tx, face.planepts, face.get_plane(), issue_stats);
|
||||
|
||||
if (!normal_ok) {
|
||||
logging::print("WARNING: {}: Brush plane with no normal\n", parser.location);
|
||||
logging::print("WARNING: {}: Brush plane with no normal\n", input_side.location);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
@ -2009,19 +1952,6 @@ static std::optional<mapface_t> ParseBrushFace(
|
|||
temp.plane = face.get_plane();
|
||||
temp.set_texinfo(mapfile::texdef_quake_ed_t{ { 0, 0 }, 0, { 1, 1 }});
|
||||
tx.vecs = temp.vecs;
|
||||
} else {
|
||||
// ericw -- round texture vector values that are within ZERO_EPSILON of integers,
|
||||
// to attempt to attempt to work around corrupted lightmap sizes in DarkPlaces
|
||||
// (it uses 32 bit precision in CalcSurfaceExtents)
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
double r = Q_rint(tx.vecs.at(i, j));
|
||||
if (fabs(tx.vecs.at(i, j) - r) < ZERO_EPSILON)
|
||||
tx.vecs.at(i, j) = r;
|
||||
}
|
||||
}
|
||||
|
||||
ValidateTextureProjection(face, &tx, issue_stats);
|
||||
}
|
||||
|
||||
face.texinfo = FindTexinfo(tx, face.get_plane());
|
||||
|
|
@ -2510,7 +2440,6 @@ static mapbrush_t CloneBrush(const mapbrush_t &input, bool faces = false)
|
|||
mapbrush_t brush;
|
||||
|
||||
brush.contents = input.contents;
|
||||
brush.format = input.format;
|
||||
brush.line = input.line;
|
||||
|
||||
if (faces) {
|
||||
|
|
@ -2529,45 +2458,16 @@ static mapbrush_t CloneBrush(const mapbrush_t &input, bool faces = false)
|
|||
return brush;
|
||||
}
|
||||
|
||||
static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
static mapbrush_t ParseBrush(const mapfile::brush_t &in, mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
{
|
||||
mapbrush_t brush;
|
||||
|
||||
// ericw -- brush primitives
|
||||
if (!parser.parse_token(PARSE_PEEK))
|
||||
FError("{}: unexpected EOF after {{ beginning brush", parser.location);
|
||||
|
||||
if (parser.token == "(" || parser.token == "}") {
|
||||
brush.format = brushformat_t::NORMAL;
|
||||
} else {
|
||||
parser.parse_token();
|
||||
brush.format = brushformat_t::BRUSH_PRIMITIVES;
|
||||
|
||||
// optional
|
||||
if (parser.token == "brushDef") {
|
||||
if (!parser.parse_token())
|
||||
FError("{}: Brush primitives: unexpected EOF (nothing after brushDef)", parser.location);
|
||||
}
|
||||
|
||||
// mandatory
|
||||
if (parser.token != "{")
|
||||
FError("{}: Brush primitives: expected second {{ at beginning of brush, got \"{}\"", parser.location, parser.token);
|
||||
}
|
||||
// ericw -- end brush primitives
|
||||
brush.line = in.location;
|
||||
|
||||
bool is_hint = false;
|
||||
|
||||
while (parser.parse_token()) {
|
||||
|
||||
// set linenum after first parsed token
|
||||
if (!brush.line) {
|
||||
brush.line = parser.location;
|
||||
}
|
||||
|
||||
if (parser.token == "}")
|
||||
break;
|
||||
|
||||
std::optional<mapface_t> face = ParseBrushFace(parser, brush, entity, issue_stats);
|
||||
for (const auto &in_face : in.faces) {
|
||||
std::optional<mapface_t> face = ParseBrushFace(in_face, brush, entity, issue_stats);
|
||||
|
||||
if (!face) {
|
||||
continue;
|
||||
|
|
@ -2577,13 +2477,13 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_
|
|||
bool discardFace = false;
|
||||
for (auto &check : brush.faces) {
|
||||
if (qv::epsilonEqual(check.get_plane(), face->get_plane())) {
|
||||
logging::print("{}: Brush with duplicate plane\n", parser.location);
|
||||
logging::print("{}: Brush with duplicate plane\n", in_face.location);
|
||||
discardFace = true;
|
||||
continue;
|
||||
}
|
||||
if (qv::epsilonEqual(-check.get_plane(), face->get_plane())) {
|
||||
/* FIXME - this is actually an invalid brush */
|
||||
logging::print("{}: Brush with duplicate plane\n", parser.location);
|
||||
logging::print("{}: Brush with duplicate plane\n", in_face.location);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -2625,13 +2525,13 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_
|
|||
// check for region/antiregion brushes
|
||||
if (is_antiregion) {
|
||||
if (!map.is_world_entity(entity)) {
|
||||
FError("Region brush at {} isn't part of the world entity", parser.token);
|
||||
FError("Region brush at {} isn't part of the world entity", in.location);
|
||||
}
|
||||
|
||||
map.antiregions.push_back(CloneBrush(brush, true));
|
||||
} else if (is_region) {
|
||||
if (!map.is_world_entity(entity)) {
|
||||
FError("Region brush at {} isn't part of the world entity", parser.token);
|
||||
FError("Region brush at {} isn't part of the world entity", in.location);
|
||||
}
|
||||
|
||||
// construct region brushes
|
||||
|
|
@ -2690,7 +2590,7 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_
|
|||
if (!map.region) {
|
||||
map.region = std::move(brush);
|
||||
} else {
|
||||
FError("Multiple region brushes detected; newest at {}", parser.token);
|
||||
FError("Multiple region brushes detected; newest at {}", in.location);
|
||||
}
|
||||
|
||||
return brush;
|
||||
|
|
@ -2709,70 +2609,35 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_
|
|||
}
|
||||
}
|
||||
|
||||
// ericw -- brush primitives - there should be another closing }
|
||||
if (brush.format == brushformat_t::BRUSH_PRIMITIVES) {
|
||||
if (!parser.parse_token())
|
||||
FError("Brush primitives: unexpected EOF (no closing brace)");
|
||||
if (parser.token != "}")
|
||||
FError("Brush primitives: Expected }}, got: {}", parser.token);
|
||||
}
|
||||
// ericw -- end brush primitives
|
||||
|
||||
brush.contents = Brush_GetContents(entity, brush);
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
bool ParseEntity(parser_t &parser, mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
void ParseEntity(const mapfile::map_entity_t &in_entity, mapentity_t &entity, texture_def_issues_t &issue_stats)
|
||||
{
|
||||
entity.location = parser.location;
|
||||
entity.location = in_entity.location;
|
||||
entity.epairs = in_entity.epairs;
|
||||
|
||||
if (!parser.parse_token()) {
|
||||
return false;
|
||||
// cache origin key
|
||||
if (in_entity.epairs.has("origin")) {
|
||||
in_entity.epairs.get_vector("origin", entity.origin);
|
||||
}
|
||||
|
||||
if (parser.token != "{") {
|
||||
FError("{}: Invalid entity format, {{ not found", parser.location);
|
||||
}
|
||||
|
||||
entity.mapbrushes.clear();
|
||||
|
||||
|
||||
// _omitbrushes 1 just discards all brushes in the entity.
|
||||
// could be useful for geometry guides, selective compilation, etc.
|
||||
bool omit = false;
|
||||
bool omit = in_entity.epairs.get_int("_omitbrushes");
|
||||
|
||||
bool first_brush = false;
|
||||
if (!omit) {
|
||||
for (const mapfile::brush_t &in_brush : in_entity.brushes) {
|
||||
// once we run into the first brush, set up textures state.
|
||||
EnsureTexturesLoaded();
|
||||
|
||||
do {
|
||||
if (!parser.parse_token())
|
||||
FError("Unexpected EOF (no closing brace)");
|
||||
if (parser.token == "}")
|
||||
break;
|
||||
else if (parser.token == "{") {
|
||||
if (!first_brush) {
|
||||
// once we run into the first brush, set up textures state.
|
||||
EnsureTexturesLoaded();
|
||||
first_brush = true;
|
||||
|
||||
omit = entity.epairs.get_int("_omitbrushes");
|
||||
if (auto brush = ParseBrush(in_brush, entity, issue_stats); brush.faces.size()) {
|
||||
entity.mapbrushes.push_back(std::move(brush));
|
||||
}
|
||||
|
||||
if (omit) {
|
||||
// skip until a } since we don't care to load brushes on this entity
|
||||
do {
|
||||
if (!parser.parse_token()) {
|
||||
FError("Unexpected EOF (no closing brace)");
|
||||
}
|
||||
} while (parser.token != "}");
|
||||
} else {
|
||||
if (auto brush = ParseBrush(parser, entity, issue_stats); brush.faces.size()) {
|
||||
entity.mapbrushes.push_back(std::move(brush));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ParseEpair(parser, entity);
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// replace aliases
|
||||
auto alias_it = qbsp_options.loaded_entity_defs.find(entity.epairs.get("classname"));
|
||||
|
|
@ -2784,8 +2649,6 @@ bool ParseEntity(parser_t &parser, mapentity_t &entity, texture_def_issues_t &is
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ScaleMapFace(mapface_t &face, const qvec3d &scale)
|
||||
|
|
@ -2895,27 +2758,25 @@ static mapentity_t LoadExternalMap(const std::string &filename)
|
|||
FError("Couldn't load external map file \"{}\".\n", filename);
|
||||
}
|
||||
|
||||
parser_t parser(file, {filename});
|
||||
auto in_map = mapfile::parse(std::string_view(reinterpret_cast<const char*>(file->data()), file->size()), parser_source_location{filename});
|
||||
texture_def_issues_t issue_stats;
|
||||
|
||||
// parse the worldspawn
|
||||
if (!ParseEntity(parser, dest, issue_stats)) {
|
||||
FError("'{}': Couldn't parse worldspawn entity\n", filename);
|
||||
}
|
||||
ParseEntity(in_map.entities.at(0), dest, issue_stats);
|
||||
|
||||
const std::string &classname = dest.epairs.get("classname");
|
||||
if (Q_strcasecmp("worldspawn", classname)) {
|
||||
FError("'{}': Expected first entity to be worldspawn, got: '{}'\n", filename, classname);
|
||||
}
|
||||
|
||||
// parse any subsequent entities, move any brushes to worldspawn
|
||||
mapentity_t dummy{};
|
||||
while (ParseEntity(parser, dummy, issue_stats)) {
|
||||
for (size_t i = 1; i < map.entities.size(); ++i) {
|
||||
mapentity_t dummy{};
|
||||
ParseEntity(in_map.entities[i], dummy, issue_stats);
|
||||
|
||||
// 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()));
|
||||
|
||||
// clear for the next loop iteration
|
||||
dummy = mapentity_t();
|
||||
}
|
||||
|
||||
if (!dest.mapbrushes.size()) {
|
||||
|
|
@ -3405,17 +3266,14 @@ void LoadMapFile()
|
|||
|
||||
parser_t parser(file, {qbsp_options.map_path.string()});
|
||||
|
||||
for (;;) {
|
||||
mapfile::map_file_t parsed_map;
|
||||
parsed_map.parse(parser);
|
||||
|
||||
for (const mapfile::map_entity_t &in_entity : parsed_map.entities) {
|
||||
mapentity_t &entity = map.entities.emplace_back();
|
||||
|
||||
if (!ParseEntity(parser, entity, issue_stats)) {
|
||||
break;
|
||||
}
|
||||
ParseEntity(in_entity, entity, issue_stats);
|
||||
}
|
||||
|
||||
// Remove dummy entity inserted above
|
||||
assert(!map.entities.back().epairs.size());
|
||||
map.entities.pop_back();
|
||||
}
|
||||
|
||||
// -add function
|
||||
|
|
@ -3428,13 +3286,13 @@ void LoadMapFile()
|
|||
}
|
||||
|
||||
parser_t parser(file, {qbsp_options.add.value()});
|
||||
auto input_map = mapfile::map_file_t{};
|
||||
input_map.parse(parser);
|
||||
|
||||
for (;;) {
|
||||
for (const auto &in_entity : input_map.entities) {
|
||||
mapentity_t &entity = map.entities.emplace_back();
|
||||
|
||||
if (!ParseEntity(parser, entity, issue_stats)) {
|
||||
break;
|
||||
}
|
||||
ParseEntity(in_entity, entity,issue_stats);
|
||||
|
||||
if (entity.epairs.get("classname") == "worldspawn") {
|
||||
// The easiest way to get the additional map's worldspawn brushes
|
||||
|
|
@ -3442,9 +3300,6 @@ void LoadMapFile()
|
|||
entity.epairs.set("classname", "func_group");
|
||||
}
|
||||
}
|
||||
// Remove dummy entity inserted above
|
||||
assert(!map.entities.back().epairs.size());
|
||||
map.entities.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3466,6 +3321,7 @@ void LoadMapFile()
|
|||
logging::print(logging::flag::STAT, "\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static old_texdef_valve_t TexDef_BSPToValve(const texvecf &in_vecs)
|
||||
{
|
||||
old_texdef_valve_t res;
|
||||
|
|
@ -3630,11 +3486,26 @@ static void ConvertEntity(std::ofstream &f, const mapentity_t &entity, const con
|
|||
}
|
||||
f << "}\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConvertMapFile()
|
||||
{
|
||||
logging::funcheader();
|
||||
|
||||
auto file = fs::load(qbsp_options.map_path);
|
||||
|
||||
if (!file) {
|
||||
FError("Couldn't load map file \"{}\".\n", qbsp_options.map_path);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse the map
|
||||
parser_t parser(file, {qbsp_options.map_path.string()});
|
||||
|
||||
mapfile::map_file_t parsed_map;
|
||||
parsed_map.parse(parser);
|
||||
|
||||
// choose output filename
|
||||
std::string append;
|
||||
|
||||
switch (qbsp_options.convertmapformat.value()) {
|
||||
|
|
@ -3648,14 +3519,38 @@ void ConvertMapFile()
|
|||
fs::path filename = qbsp_options.bsp_path;
|
||||
filename.replace_filename(qbsp_options.bsp_path.stem().string() + append).replace_extension(".map");
|
||||
|
||||
// do conversion
|
||||
conversion_t target = qbsp_options.convertmapformat.value();
|
||||
switch (target) {
|
||||
case conversion_t::quake:
|
||||
parsed_map.convert_to(mapfile::texcoord_style_t::quaked, qbsp_options.target_game, qbsp_options);
|
||||
break;
|
||||
case conversion_t::quake2:
|
||||
parsed_map.convert_to(mapfile::texcoord_style_t::quaked, qbsp_options.target_game, qbsp_options);
|
||||
break;
|
||||
case conversion_t::valve:
|
||||
parsed_map.convert_to(mapfile::texcoord_style_t::valve_220, qbsp_options.target_game, qbsp_options);
|
||||
break;
|
||||
case conversion_t::bp:
|
||||
parsed_map.convert_to(mapfile::texcoord_style_t::brush_primitives, qbsp_options.target_game, qbsp_options);
|
||||
break;
|
||||
default: FError("Internal error: unknown conversion_t\n");
|
||||
}
|
||||
|
||||
// clear q2 attributes
|
||||
// FIXME: should have a way to convert to Q2 Valve
|
||||
if (target != conversion_t::quake2)
|
||||
for (mapfile::map_entity_t &ent : parsed_map.entities)
|
||||
for (mapfile::brush_t &brush : ent.brushes)
|
||||
for (mapfile::brush_side_t &side : brush.faces)
|
||||
side.extended_info = std::nullopt;
|
||||
|
||||
// write out
|
||||
std::ofstream f(filename);
|
||||
|
||||
if (!f)
|
||||
FError("Couldn't open file\n");
|
||||
|
||||
for (const mapentity_t &entity : map.entities) {
|
||||
ConvertEntity(f, entity, qbsp_options.convertmapformat.value());
|
||||
}
|
||||
parsed_map.write(f);
|
||||
|
||||
logging::print("Conversion saved to {}\n", filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1639,13 +1639,14 @@ ProcessFile
|
|||
*/
|
||||
void ProcessFile()
|
||||
{
|
||||
// load brushes and entities
|
||||
LoadMapFile();
|
||||
|
||||
if (qbsp_options.convertmapformat.value() != conversion_t::none) {
|
||||
ConvertMapFile();
|
||||
return;
|
||||
}
|
||||
|
||||
// load brushes and entities
|
||||
LoadMapFile();
|
||||
|
||||
if (qbsp_options.onlyents.value()) {
|
||||
UpdateEntLump();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <common/fs.hh>
|
||||
#include <common/bsputils.hh>
|
||||
#include <common/decompile.hh>
|
||||
#include <common/mapfile.hh>
|
||||
#include <common/prtfile.hh>
|
||||
#include <common/qvec.hh>
|
||||
#include <common/log.hh>
|
||||
|
|
@ -63,13 +64,13 @@ mapentity_t &LoadMap(const char *map, size_t length)
|
|||
qbsp_options.target_version = &bspver_q1;
|
||||
qbsp_options.target_game = qbsp_options.target_version->game;
|
||||
|
||||
parser_t parser(map, length, {doctest::getContextOptions()->currentTest->m_name});
|
||||
|
||||
mapentity_t &entity = ::map.entities.emplace_back();
|
||||
texture_def_issues_t issue_stats;
|
||||
parser_source_location base_location {doctest::getContextOptions()->currentTest->m_name};
|
||||
mapfile::map_file_t m = mapfile::parse(std::string_view(map, length), base_location);
|
||||
|
||||
// FIXME: adds the brush to the global map...
|
||||
Q_assert(ParseEntity(parser, entity, issue_stats));
|
||||
texture_def_issues_t issue_stats;
|
||||
mapentity_t &entity = ::map.entities.emplace_back();
|
||||
ParseEntity(m.entities.at(0), entity, issue_stats);
|
||||
|
||||
CalculateWorldExtent();
|
||||
|
||||
|
|
@ -416,13 +417,16 @@ TEST_CASE("InvalidTextureProjection" * doctest::test_suite("qbsp"))
|
|||
}
|
||||
)";
|
||||
|
||||
mapentity_t &worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.mapbrushes.size());
|
||||
mapfile::map_file_t m;
|
||||
parser_t p(map, parser_source_location());
|
||||
m.parse(p);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrushes.front().faces[5];
|
||||
REQUIRE("skip" == face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
|
||||
REQUIRE(1 == m.entities[0].brushes.size());
|
||||
|
||||
const auto *face = &m.entities[0].brushes.front().faces[5];
|
||||
REQUIRE("skip" == face->texture);
|
||||
|
||||
CHECK(face->is_valid_texture_projection());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -446,13 +450,16 @@ TEST_CASE("InvalidTextureProjection2" * doctest::test_suite("qbsp"))
|
|||
}
|
||||
)";
|
||||
|
||||
mapentity_t &worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.mapbrushes.size());
|
||||
mapfile::map_file_t m;
|
||||
parser_t p(map, parser_source_location());
|
||||
m.parse(p);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrushes.front().faces[5];
|
||||
REQUIRE("skip" == face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
|
||||
REQUIRE(1 == m.entities[0].brushes.size());
|
||||
|
||||
const auto *face = &m.entities[0].brushes.front().faces[5];
|
||||
REQUIRE("skip" == face->texture);
|
||||
|
||||
CHECK(face->is_valid_texture_projection());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -477,13 +484,16 @@ TEST_CASE("InvalidTextureProjection3" * doctest::test_suite("qbsp"))
|
|||
}
|
||||
)";
|
||||
|
||||
mapentity_t &worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.mapbrushes.size());
|
||||
mapfile::map_file_t m;
|
||||
parser_t p(map, parser_source_location());
|
||||
m.parse(p);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrushes.front().faces[3];
|
||||
REQUIRE("*lava1" == face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
CHECK(IsValidTextureProjection(face->get_plane().get_normal(), texvecs.row(0), texvecs.row(1)));
|
||||
REQUIRE(1 == m.entities[0].brushes.size());
|
||||
|
||||
const auto *face = &m.entities[0].brushes.front().faces[3];
|
||||
REQUIRE("*lava1" == face->texture);
|
||||
|
||||
CHECK(face->is_valid_texture_projection());
|
||||
}
|
||||
|
||||
TEST_SUITE("mathlib")
|
||||
|
|
|
|||
Loading…
Reference in New Issue