common: structured bspxbrushes reading/writing
This commit is contained in:
parent
de0f66c16e
commit
ad9fd7fc59
|
|
@ -49,43 +49,32 @@ static std::string hex_string(const uint8_t *bytes, const size_t count)
|
|||
/**
|
||||
* returns a JSON array of models
|
||||
*/
|
||||
json serialize_bspxbrushlist(const std::vector<uint8_t> &lump)
|
||||
static json serialize_bspxbrushlist(const std::vector<uint8_t> &lump)
|
||||
{
|
||||
json j = json::array();
|
||||
|
||||
imemstream p(lump.data(), lump.size(), std::ios_base::in | std::ios_base::binary);
|
||||
|
||||
p >> endianness<std::endian::little>;
|
||||
bspxbrushes structured;
|
||||
p >= structured;
|
||||
|
||||
while (true) {
|
||||
bspxbrushes_permodel src_model;
|
||||
p >= src_model;
|
||||
|
||||
if (!p) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const bspxbrushes_permodel &src_model : structured.models) {
|
||||
json &model = j.insert(j.end(), json::object()).value();
|
||||
model["ver"] = src_model.ver;
|
||||
model["modelnum"] = src_model.modelnum;
|
||||
model["numbrushes"] = src_model.numbrushes;
|
||||
model["numbrushes"] = src_model.brushes.size();
|
||||
model["numfaces"] = src_model.numfaces;
|
||||
json &brushes = (model.emplace("brushes", json::array())).first.value();
|
||||
|
||||
for (int32_t i = 0; i < src_model.numbrushes; ++i) {
|
||||
bspxbrushes_perbrush src_brush;
|
||||
p >= src_brush;
|
||||
|
||||
for (const bspxbrushes_perbrush &src_brush : src_model.brushes) {
|
||||
json &brush = brushes.insert(brushes.end(), json::object()).value();
|
||||
brush.push_back({"mins", src_brush.bounds.mins()});
|
||||
brush.push_back({"maxs", src_brush.bounds.maxs()});
|
||||
brush.push_back({"contents", src_brush.contents});
|
||||
json &faces = (brush.emplace("faces", json::array())).first.value();
|
||||
|
||||
for (int32_t j = 0; j < src_brush.numfaces; ++j) {
|
||||
bspxbrushes_perface src_face;
|
||||
p >= std::tie(src_face.normal, src_face.dist);
|
||||
|
||||
for (const bspxbrushes_perface &src_face : src_brush.faces) {
|
||||
json &face = faces.insert(faces.end(), json::object()).value();
|
||||
face.push_back({"normal", src_face.normal});
|
||||
face.push_back({"dist", src_face.dist});
|
||||
|
|
|
|||
|
|
@ -50,28 +50,97 @@ void bspx_lump_t::stream_read(std::istream &s)
|
|||
s >= std::tie(lumpname, fileofs, filelen);
|
||||
}
|
||||
|
||||
// bspxbrushes_permodel
|
||||
|
||||
void bspxbrushes_permodel::stream_write(std::ostream &s) const
|
||||
{
|
||||
s <= std::tie(ver, modelnum, numbrushes, numfaces);
|
||||
}
|
||||
|
||||
void bspxbrushes_permodel::stream_read(std::istream &s)
|
||||
{
|
||||
s >= std::tie(ver, modelnum, numbrushes, numfaces);
|
||||
}
|
||||
|
||||
// bspxbrushes_perbrush
|
||||
|
||||
void bspxbrushes_perbrush::stream_write(std::ostream &s) const
|
||||
{
|
||||
s <= std::tie(bounds, contents, numfaces);
|
||||
void bspxbrushes_perbrush::stream_write(std::ostream &s) const {
|
||||
s <= bounds;
|
||||
s <= contents;
|
||||
s <= static_cast<int32_t>(faces.size());
|
||||
|
||||
for (auto &face : faces) {
|
||||
s <= face;
|
||||
}
|
||||
}
|
||||
|
||||
void bspxbrushes_perbrush::stream_read(std::istream &s)
|
||||
{
|
||||
s >= std::tie(bounds, contents, numfaces);
|
||||
s >= bounds;
|
||||
s >= contents;
|
||||
|
||||
int32_t numfaces = 0;
|
||||
s >= numfaces;
|
||||
|
||||
faces.resize(numfaces);
|
||||
|
||||
for (auto &face : faces) {
|
||||
s >= face;
|
||||
}
|
||||
}
|
||||
|
||||
// bspxbrushes_permodel
|
||||
|
||||
void bspxbrushes_permodel::stream_write(std::ostream &s) const
|
||||
{
|
||||
s <= ver;
|
||||
s <= modelnum;
|
||||
s <= static_cast<int32_t>(brushes.size());
|
||||
// count faces (ignore numfaces)
|
||||
int32_t faces = 0;
|
||||
for (auto &brush : brushes) {
|
||||
faces += static_cast<int32_t>(brush.faces.size());
|
||||
}
|
||||
s <= faces;
|
||||
|
||||
// next serialize all of the brushes
|
||||
for (auto &brush : brushes) {
|
||||
s <= brush;
|
||||
}
|
||||
}
|
||||
|
||||
void bspxbrushes_permodel::stream_read(std::istream &s)
|
||||
{
|
||||
s >= ver;
|
||||
if (!s) {
|
||||
// we need to handle end-of-stream due to the bspx lump containing an unknown number
|
||||
// of bspxbrushes_permodel objects
|
||||
return;
|
||||
}
|
||||
|
||||
s >= modelnum;
|
||||
|
||||
int32_t numbrushes;
|
||||
s >= numbrushes;
|
||||
s >= numfaces;
|
||||
|
||||
brushes.resize(numbrushes);
|
||||
for (auto &brush : brushes) {
|
||||
s >= brush;
|
||||
}
|
||||
}
|
||||
|
||||
// bspxbrushes
|
||||
|
||||
void bspxbrushes::stream_write(std::ostream &s) const
|
||||
{
|
||||
for (auto &model : models) {
|
||||
s <= model;
|
||||
}
|
||||
}
|
||||
|
||||
void bspxbrushes::stream_read(std::istream &s)
|
||||
{
|
||||
models.clear();
|
||||
|
||||
while (true) {
|
||||
bspxbrushes_permodel model;
|
||||
s >= model;
|
||||
|
||||
if (!s) {
|
||||
break;
|
||||
}
|
||||
|
||||
models.push_back(std::move(model));
|
||||
}
|
||||
}
|
||||
|
||||
// bspxfacenormals_per_vert
|
||||
|
|
|
|||
|
|
@ -728,3 +728,9 @@ void q_aligned_free(void *ptr)
|
|||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<uint8_t> StringToVector(const std::string &str)
|
||||
{
|
||||
std::vector<uint8_t> result(str.begin(), str.end());
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#include "common/imglib.hh"
|
||||
#include "common/qvec.hh"
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -46,5 +44,3 @@ struct full_atlas_t
|
|||
full_atlas_t build_lightmap_atlas(const mbsp_t &bsp, const bspxentries_t &bspx, const std::vector<uint8_t> &litdata, bool use_bspx, bool use_decoupled);
|
||||
|
||||
void serialize_bsp(const bspdata_t &bspdata, const mbsp_t &bsp, const fs::path &name);
|
||||
|
||||
nlohmann::json serialize_bspxbrushlist(const std::vector<uint8_t> &lump);
|
||||
|
|
|
|||
|
|
@ -53,11 +53,26 @@ struct bspx_lump_t
|
|||
};
|
||||
|
||||
// BRUSHLIST BSPX lump
|
||||
using bspxbrushes_perface = qplane3f;
|
||||
|
||||
struct bspxbrushes_perbrush
|
||||
{
|
||||
aabb3f bounds;
|
||||
int16_t contents;
|
||||
// non-axial faces only
|
||||
std::vector<bspxbrushes_perface> faces;
|
||||
|
||||
// serialize for streams
|
||||
void stream_write(std::ostream &s) const;
|
||||
void stream_read(std::istream &s);
|
||||
};
|
||||
|
||||
struct bspxbrushes_permodel
|
||||
{
|
||||
int32_t ver;
|
||||
int32_t modelnum;
|
||||
int32_t numbrushes;
|
||||
std::vector<bspxbrushes_perbrush> brushes;
|
||||
// ignored when writing
|
||||
int32_t numfaces;
|
||||
|
||||
// serialize for streams
|
||||
|
|
@ -65,19 +80,14 @@ struct bspxbrushes_permodel
|
|||
void stream_read(std::istream &s);
|
||||
};
|
||||
|
||||
struct bspxbrushes_perbrush
|
||||
{
|
||||
aabb3f bounds;
|
||||
int16_t contents;
|
||||
uint16_t numfaces;
|
||||
struct bspxbrushes {
|
||||
std::vector<bspxbrushes_permodel> models;
|
||||
|
||||
// serialize for streams
|
||||
void stream_write(std::ostream &s) const;
|
||||
void stream_read(std::istream &s);
|
||||
};
|
||||
|
||||
using bspxbrushes_perface = qplane3f;
|
||||
|
||||
struct bspxfacenormals_per_vert
|
||||
{
|
||||
// these are all indices into bspxfacenormals::normals
|
||||
|
|
|
|||
|
|
@ -570,3 +570,16 @@ struct omemsizestream : virtual omemsizebuf, std::ostream
|
|||
void CRC_Init(uint16_t &crcvalue);
|
||||
void CRC_ProcessByte(uint16_t &crcvalue, uint8_t data);
|
||||
uint16_t CRC_Block(const uint8_t *start, int count);
|
||||
|
||||
std::vector<uint8_t> StringToVector(const std::string &str);
|
||||
|
||||
template <class T>
|
||||
T deserialize(const std::vector<uint8_t> &bytes)
|
||||
{
|
||||
auto stream = imemstream(bytes.data(), bytes.size());
|
||||
stream >> endianness<std::endian::little>;
|
||||
|
||||
T result;
|
||||
stream >= result;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,14 +338,6 @@ size_t EmitFaces(node_t *headnode);
|
|||
void EmitVertices(node_t *headnode);
|
||||
void ExportClipNodes(mapentity_t &entity, node_t *headnode, hull_index_t::value_type hullnum);
|
||||
void ExportDrawNodes(mapentity_t &entity, node_t *headnode, int firstface);
|
||||
|
||||
struct bspxbrushes_s
|
||||
{
|
||||
std::vector<uint8_t> lumpdata;
|
||||
};
|
||||
void BSPX_Brushes_Finalize(struct bspxbrushes_s *ctx);
|
||||
void BSPX_Brushes_Init(struct bspxbrushes_s *ctx);
|
||||
|
||||
void WriteBspBrushMap(std::string_view filename_suffix, const bspbrush_t::container &list);
|
||||
|
||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec);
|
||||
|
|
|
|||
|
|
@ -34,12 +34,7 @@
|
|||
#include <common/prtfile.hh>
|
||||
#include <common/parallel.hh>
|
||||
#include <common/qvec.hh>
|
||||
|
||||
static std::vector<uint8_t> StringToVector(const std::string &str)
|
||||
{
|
||||
std::vector<uint8_t> result(str.begin(), str.end());
|
||||
return result;
|
||||
}
|
||||
#include <common/cmdlib.hh>
|
||||
|
||||
static aabb3f LightGridBounds(const mbsp_t &bsp)
|
||||
{
|
||||
|
|
|
|||
68
qbsp/qbsp.cc
68
qbsp/qbsp.cc
|
|
@ -1298,57 +1298,18 @@ static void UpdateEntLump(void)
|
|||
UpdateBSPFileEntitiesLump();
|
||||
}
|
||||
|
||||
/*
|
||||
Actually writes out the final bspx BRUSHLIST lump
|
||||
This lump replaces the clipnodes stuff for custom collision sizes.
|
||||
*/
|
||||
void BSPX_Brushes_Finalize(struct bspxbrushes_s *ctx)
|
||||
{
|
||||
// Actually written in WriteBSPFile()
|
||||
map.exported_bspxbrushes = std::move(ctx->lumpdata);
|
||||
}
|
||||
void BSPX_Brushes_Init(struct bspxbrushes_s *ctx)
|
||||
{
|
||||
ctx->lumpdata.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
WriteBrushes
|
||||
Generates a submodel's direct brush information to a separate file, so the engine doesn't need to depend upon specific
|
||||
hull sizes
|
||||
*/
|
||||
|
||||
static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, const std::vector<mapbrush_t *> &brushes)
|
||||
static bspxbrushes_permodel BSPX_Brushes_AddModel(int modelnum, const std::vector<mapbrush_t *> &brushes)
|
||||
{
|
||||
bspxbrushes_permodel permodel{1, modelnum};
|
||||
bspxbrushes_permodel permodel{.ver = 1, .modelnum = modelnum};
|
||||
|
||||
for (auto &b : brushes) {
|
||||
permodel.numbrushes++;
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
const auto &plane = f.get_plane();
|
||||
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
||||
continue;
|
||||
permodel.numfaces++;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream str(std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
str << endianness<std::endian::little>;
|
||||
|
||||
str <= permodel;
|
||||
|
||||
for (auto &b : brushes) {
|
||||
bspxbrushes_perbrush perbrush{};
|
||||
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
const auto &plane = f.get_plane();
|
||||
if (plane.get_type() < plane_type_t::PLANE_ANYX)
|
||||
continue;
|
||||
perbrush.numfaces++;
|
||||
}
|
||||
bspxbrushes_perbrush &perbrush = permodel.brushes.emplace_back();
|
||||
|
||||
perbrush.bounds = b->bounds;
|
||||
|
||||
|
|
@ -1383,8 +1344,6 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, const
|
|||
}
|
||||
}
|
||||
|
||||
str <= perbrush;
|
||||
|
||||
for (auto &f : b->faces) {
|
||||
/*skip axial*/
|
||||
const auto &plane = f.get_plane();
|
||||
|
|
@ -1392,24 +1351,21 @@ static void BSPX_Brushes_AddModel(struct bspxbrushes_s *ctx, int modelnum, const
|
|||
continue;
|
||||
|
||||
bspxbrushes_perface perface = qplane3f(plane.get_normal(), plane.get_dist());
|
||||
str <= std::tie(perface.normal, perface.dist);
|
||||
perbrush.faces.push_back(perface);
|
||||
}
|
||||
}
|
||||
|
||||
std::string data = str.str();
|
||||
ctx->lumpdata.insert(ctx->lumpdata.end(), (uint8_t *)data.data(), ((uint8_t *)data.data()) + data.size());
|
||||
return permodel;
|
||||
}
|
||||
|
||||
/* for generating BRUSHLIST bspx lump */
|
||||
static void BSPX_CreateBrushList(void)
|
||||
static void BSPX_CreateBrushList()
|
||||
{
|
||||
struct bspxbrushes_s ctx;
|
||||
bspxbrushes ctx;
|
||||
|
||||
if (!qbsp_options.wrbrushes.value())
|
||||
return;
|
||||
|
||||
BSPX_Brushes_Init(&ctx);
|
||||
|
||||
for (size_t entnum = 0; entnum < map.entities.size(); ++entnum) {
|
||||
mapentity_t &ent = map.entities.at(entnum);
|
||||
size_t modelnum;
|
||||
|
|
@ -1437,14 +1393,12 @@ static void BSPX_CreateBrushList(void)
|
|||
}
|
||||
|
||||
if (modelnum == 0) {
|
||||
|
||||
for (size_t e = 1; e < map.entities.size(); ++e) {
|
||||
mapentity_t &bent = map.entities.at(e);
|
||||
|
||||
brushes.reserve(brushes.size() + ent.mapbrushes.size());
|
||||
|
||||
if (IsWorldBrushEntity(bent)) {
|
||||
|
||||
for (auto &b : bent.mapbrushes) {
|
||||
brushes.push_back(&b);
|
||||
}
|
||||
|
|
@ -1453,11 +1407,15 @@ static void BSPX_CreateBrushList(void)
|
|||
}
|
||||
|
||||
if (!brushes.empty()) {
|
||||
BSPX_Brushes_AddModel(&ctx, modelnum, brushes);
|
||||
ctx.models.push_back(BSPX_Brushes_AddModel(modelnum, brushes));
|
||||
}
|
||||
}
|
||||
|
||||
BSPX_Brushes_Finalize(&ctx);
|
||||
// Actually written in WriteBSPFile()
|
||||
std::ostringstream str(std::ios_base::out | std::ios_base::binary);
|
||||
str << endianness<std::endian::little>;
|
||||
str <= ctx;
|
||||
map.exported_bspxbrushes = StringToVector(str.str());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ mapentity_t &LoadMapPath(const std::filesystem::path &name)
|
|||
}
|
||||
|
||||
#include <common/bspinfo.hh>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
std::tuple<mbsp_t, bspxentries_t, std::optional<prtfile_t>> LoadTestmap(
|
||||
const std::filesystem::path &name, std::vector<std::string> extra_args)
|
||||
|
|
@ -1998,21 +1997,14 @@ TEST_CASE("wrbrushes + misc_external_map")
|
|||
{
|
||||
const auto [bsp, bspx, prt] = LoadTestmap("q1_external_map_base.map", {"-wrbrushes"});
|
||||
|
||||
auto models_json = serialize_bspxbrushlist(bspx.at("BRUSHLIST"));
|
||||
logging::print("{}\n", to_string(models_json));
|
||||
bspxbrushes lump = deserialize<bspxbrushes>(bspx.at("BRUSHLIST"));
|
||||
|
||||
REQUIRE(models_json.size() == 1);
|
||||
REQUIRE(lump.models.size() == 1);
|
||||
|
||||
auto &model_json = models_json.at(0);
|
||||
REQUIRE(model_json.at("brushes").size() == 1);
|
||||
auto &model = lump.models.at(0);
|
||||
REQUIRE(model.brushes.size() == 1);
|
||||
|
||||
auto &brush_json = model_json.at("brushes").at(0);
|
||||
REQUIRE(brush_json.at("maxs") == nlohmann::json::array({nlohmann::json::number_float_t(64),
|
||||
nlohmann::json::number_float_t(64),
|
||||
nlohmann::json::number_float_t(16)
|
||||
}));
|
||||
REQUIRE(brush_json.at("mins") == nlohmann::json::array({nlohmann::json::number_float_t(-64),
|
||||
nlohmann::json::number_float_t(-64),
|
||||
nlohmann::json::number_float_t(-16)
|
||||
}));
|
||||
auto &brush = model.brushes.at(0);
|
||||
REQUIRE(brush.bounds.maxs() == qvec3f{64,64,16});
|
||||
REQUIRE(brush.bounds.mins() == qvec3f{-64,-64,-16});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue