diff --git a/bsputil/bsputil.cc b/bsputil/bsputil.cc index 4a9951da..4754bb33 100644 --- a/bsputil/bsputil.cc +++ b/bsputil/bsputil.cc @@ -529,7 +529,8 @@ main(int argc, char **argv) printf("---- bsputil / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n"); if (argc == 1) { printf("usage: bsputil [--extract-entities] [--extract-textures] [--convert bsp29|bsp2|bsp2rmq|q2bsp] [--check] [--modelinfo]\n" - "[--check] [--compare otherbsp] [--findfaces x y z nx ny nz] [--settexinfo facenum texinfonum] [--decompile] bspfile\n"); + "[--check] [--compare otherbsp] [--findfaces x y z nx ny nz] [--settexinfo facenum texinfonum]\n" + "[--decompile] [--decompile-geomonly] bspfile\n"); exit(1); } @@ -676,7 +677,9 @@ main(int argc, char **argv) WriteBSPFile(source, &bspdata); return 0; - } else if (!strcmp(argv[i], "--decompile")) { + } else if (!strcmp(argv[i], "--decompile") || !strcmp(argv[i], "--decompile-geomonly")) { + const bool geomOnly = !strcmp(argv[i], "--decompile-geomonly"); + StripExtension(source); DefaultExtension(source, "-decompile.map"); printf("-> writing %s... ", source); @@ -685,7 +688,10 @@ main(int argc, char **argv) if (!f) Error("couldn't open %s for writing\n", source); - DecompileBSP(bsp, f); + decomp_options options; + options.geometryOnly = geomOnly; + + DecompileBSP(bsp, options, f); fclose(f); return 0; diff --git a/bsputil/decompile.cpp b/bsputil/decompile.cpp index 81e3c03f..17960d8c 100644 --- a/bsputil/decompile.cpp +++ b/bsputil/decompile.cpp @@ -632,6 +632,26 @@ DecompileLeaf(const std::vector* planestack, const mbsp_t *bsp, result->push_back({*planestack, leaf}); } +static std::string +DecompileLeafTaskGeometryOnly(const mbsp_t *bsp, const leaf_decompile_task& task) +{ + const mleaf_t *leaf = task.leaf; + + fmt::memory_buffer file; + fmt::format_to(file, "{{\n"); + for (const auto& side : task.allPlanes) { + PrintPlanePoints(bsp, side, file); + + // print a default face + fmt::format_to(file, " {} ", DefaultTextureForContents(leaf->contents).c_str()); + WriteNullTexdef(bsp, file); + fmt::format_to(file, "\n"); + } + fmt::format_to(file, "}}\n"); + + return fmt::to_string(file); +} + static std::string DecompileLeafTask(const mbsp_t *bsp, const leaf_decompile_task& task) { @@ -767,7 +787,7 @@ AddMapBoundsToStack(std::vector* planestack, const mbsp_t *bsp, } static void -DecompileEntity(const mbsp_t *bsp, FILE* file, const entdict_t& dict, bool isWorld) +DecompileEntity(const mbsp_t *bsp, const decomp_options& options, FILE* file, const entdict_t& dict, bool isWorld) { // we use -1 to indicate it's not a brush model int modelNum = -1; @@ -811,7 +831,11 @@ DecompileEntity(const mbsp_t *bsp, FILE* file, const entdict_t& dict, bool isWor std::vector leafStrings; leafStrings.resize(tasks.size()); tbb::parallel_for(static_cast(0), tasks.size(), [&](const size_t i) { - leafStrings[i] = DecompileLeafTask(bsp, tasks[i]); + if (options.geometryOnly) { + leafStrings[i] = DecompileLeafTaskGeometryOnly(bsp, tasks[i]); + } else { + leafStrings[i] = DecompileLeafTask(bsp, tasks[i]); + } }); // finally print out the leafs @@ -824,12 +848,12 @@ DecompileEntity(const mbsp_t *bsp, FILE* file, const entdict_t& dict, bool isWor } void -DecompileBSP(const mbsp_t *bsp, FILE* file) +DecompileBSP(const mbsp_t *bsp, const decomp_options& options, FILE* file) { auto entdicts = EntData_Parse(bsp->dentdata); for (size_t i = 0; i < entdicts.size(); ++i) { // entity 0 is implicitly worldspawn (model 0) - DecompileEntity(bsp, file, entdicts[i], i == 0); + DecompileEntity(bsp, options, file, entdicts[i], i == 0); } } diff --git a/bsputil/decompile.h b/bsputil/decompile.h index b20bf984..f41d9704 100644 --- a/bsputil/decompile.h +++ b/bsputil/decompile.h @@ -5,4 +5,14 @@ struct mbsp_t; struct bsp2_dnode_t; -void DecompileBSP(const mbsp_t *bsp, FILE* file); +struct decomp_options { + /** + * If true, use a simplified algorithm that just dumps the planes bounding each leaf, + * without attempting to reconstruct faces or discard redundant planes. + * + * For debugging (there's not much that can go wrong). + */ + bool geometryOnly = false; +}; + +void DecompileBSP(const mbsp_t *bsp, const decomp_options& options, FILE* file);