2020-05-17 08:42:43 -07:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "VoxConvert.h"
|
|
|
|
#include "core/Color.h"
|
2021-12-15 12:34:30 -08:00
|
|
|
#include "core/GameConfig.h"
|
2021-11-30 12:18:28 -08:00
|
|
|
#include "core/StringUtil.h"
|
2021-12-15 13:31:35 -08:00
|
|
|
#include "core/Tokenizer.h"
|
2020-05-17 08:42:43 -07:00
|
|
|
#include "core/Var.h"
|
2020-08-30 13:36:16 -07:00
|
|
|
#include "command/Command.h"
|
2021-12-17 06:46:55 -08:00
|
|
|
#include "core/collection/DynamicArray.h"
|
|
|
|
#include "core/collection/Set.h"
|
2021-11-30 12:18:28 -08:00
|
|
|
#include "image/Image.h"
|
2021-12-03 11:26:26 -08:00
|
|
|
#include "io/FileStream.h"
|
2020-08-30 13:16:13 -07:00
|
|
|
#include "io/Filesystem.h"
|
2020-08-30 12:49:29 -07:00
|
|
|
#include "metric/Metric.h"
|
2020-05-17 08:42:43 -07:00
|
|
|
#include "core/EventBus.h"
|
|
|
|
#include "core/TimeProvider.h"
|
|
|
|
#include "voxel/MaterialColor.h"
|
2021-12-17 14:31:50 -08:00
|
|
|
#include "voxel/RawVolume.h"
|
2020-08-04 09:02:29 -07:00
|
|
|
#include "voxelformat/VolumeFormat.h"
|
2021-12-03 11:26:26 -08:00
|
|
|
#include "voxelformat/Format.h"
|
2021-12-17 14:31:50 -08:00
|
|
|
#include "voxelformat/VoxelVolumes.h"
|
2021-12-15 13:31:35 -08:00
|
|
|
#include "voxelgenerator/LUAGenerator.h"
|
2021-12-15 12:08:09 -08:00
|
|
|
#include "voxelutil/ImageUtils.h"
|
2020-05-22 11:53:28 -07:00
|
|
|
#include "voxelutil/VolumeRescaler.h"
|
2021-12-17 14:31:50 -08:00
|
|
|
#include "voxelutil/VolumeRotator.h"
|
2020-05-17 08:42:43 -07:00
|
|
|
|
|
|
|
VoxConvert::VoxConvert(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider) :
|
|
|
|
Super(metric, filesystem, eventBus, timeProvider) {
|
|
|
|
init(ORGANISATION, "voxconvert");
|
|
|
|
}
|
|
|
|
|
2020-08-30 13:46:21 -07:00
|
|
|
app::AppState VoxConvert::onConstruct() {
|
|
|
|
const app::AppState state = Super::onConstruct();
|
2021-12-16 10:24:35 -08:00
|
|
|
registerArg("--export-palette").setDescription("Export the used palette data into an image. Use in combination with --src-palette");
|
2021-12-17 07:49:49 -08:00
|
|
|
registerArg("--filter").setDescription("Layer filter. For example '1-4,6'");
|
2021-12-16 10:24:35 -08:00
|
|
|
registerArg("--force").setShort("-f").setDescription("Overwrite existing files");
|
2021-12-21 08:07:34 -08:00
|
|
|
registerArg("--input").setShort("-i").setDescription("Allow to specify input files");
|
2020-05-18 06:38:44 -07:00
|
|
|
registerArg("--merge").setShort("-m").setDescription("Merge layers into one volume");
|
2021-12-17 14:31:50 -08:00
|
|
|
registerArg("--mirror").setDescription("Mirror by the given axis (x, y or z)");
|
2021-12-21 08:07:34 -08:00
|
|
|
registerArg("--output").setShort("-o").setDescription("Allow to specify the output file");
|
2021-12-17 14:35:22 -08:00
|
|
|
registerArg("--rotate").setDescription("Rotate by 90 degree at the given axis (x, y or z)");
|
2020-05-22 11:53:28 -07:00
|
|
|
registerArg("--scale").setShort("-s").setDescription("Scale layer to 50% of its original size");
|
2021-12-15 13:31:35 -08:00
|
|
|
registerArg("--script").setDefaultValue("script.lua").setDescription("Apply the given lua script to the output volume");
|
2021-12-16 10:24:35 -08:00
|
|
|
registerArg("--src-palette").setShort("-p").setDescription("Keep the source palette and don't perform quantization");
|
2021-12-21 08:50:19 -08:00
|
|
|
registerArg("--translate").setShort("-t").setDescription("Translate the volumes by x (right), y (up), z (back)");
|
2020-06-07 11:12:08 -07:00
|
|
|
|
2021-12-15 12:34:30 -08:00
|
|
|
_mergeQuads = core::Var::get(cfg::VoxformatMergequads, "true", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_mergeQuads->setHelp("Merge similar quads to optimize the mesh");
|
2021-12-15 12:34:30 -08:00
|
|
|
_reuseVertices = core::Var::get(cfg::VoxformatReusevertices, "true", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_reuseVertices->setHelp("Reuse vertices or always create new ones");
|
2021-12-15 12:34:30 -08:00
|
|
|
_ambientOcclusion = core::Var::get(cfg::VoxformatAmbientocclusion, "false", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_ambientOcclusion->setHelp("Extra vertices for ambient occlusion");
|
2021-12-15 12:34:30 -08:00
|
|
|
_scale = core::Var::get(cfg::VoxformatScale, "1.0", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_scale->setHelp("Scale the vertices by the given factor");
|
2021-12-15 12:34:30 -08:00
|
|
|
_quads = core::Var::get(cfg::VoxformatQuads, "true", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_quads->setHelp("Export as quads. If this false, triangles will be used.");
|
2021-12-15 12:34:30 -08:00
|
|
|
_withColor = core::Var::get(cfg::VoxformatWithcolor, "true", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_withColor->setHelp("Export with vertex colors");
|
2021-12-15 12:34:30 -08:00
|
|
|
_withTexCoords = core::Var::get(cfg::VoxformatWithtexcoords, "true", core::CV_NOPERSIST);
|
2020-10-01 09:16:21 -07:00
|
|
|
_withTexCoords->setHelp("Export with uv coordinates of the palette image");
|
2020-06-07 11:12:08 -07:00
|
|
|
_palette = core::Var::get("palette", voxel::getDefaultPaletteName());
|
2020-10-01 09:16:21 -07:00
|
|
|
_palette->setHelp("This is the NAME part of palette-<NAME>.png or absolute png file to use (1x256)");
|
2020-06-07 11:12:08 -07:00
|
|
|
|
2021-12-15 13:31:35 -08:00
|
|
|
if (!filesystem()->registerPath("scripts/")) {
|
|
|
|
Log::warn("Failed to register lua generator script path");
|
|
|
|
}
|
|
|
|
|
2020-05-18 06:38:44 -07:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2021-12-08 10:19:47 -08:00
|
|
|
void VoxConvert::usage() const {
|
|
|
|
Super::usage();
|
|
|
|
Log::info("Load support:");
|
|
|
|
for (const io::FormatDescription *desc = voxelformat::SUPPORTED_VOXEL_FORMATS_LOAD; desc->ext != nullptr; ++desc) {
|
|
|
|
Log::info(" * %s (*.%s)", desc->name, desc->ext);
|
|
|
|
}
|
|
|
|
Log::info("Save support:");
|
|
|
|
for (const io::FormatDescription *desc = voxelformat::SUPPORTED_VOXEL_FORMATS_SAVE; desc->ext != nullptr; ++desc) {
|
|
|
|
Log::info(" * %s (*.%s)", desc->name, desc->ext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-30 13:46:21 -07:00
|
|
|
app::AppState VoxConvert::onInit() {
|
|
|
|
const app::AppState state = Super::onInit();
|
|
|
|
if (state != app::AppState::Running) {
|
2020-05-17 08:42:43 -07:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_argc < 2) {
|
|
|
|
_logLevelVar->setVal(SDL_LOG_PRIORITY_INFO);
|
|
|
|
Log::init();
|
|
|
|
usage();
|
2020-08-30 13:46:21 -07:00
|
|
|
return app::AppState::InitFailure;
|
2020-05-17 08:42:43 -07:00
|
|
|
}
|
|
|
|
|
2021-12-21 08:07:34 -08:00
|
|
|
core::String infilesstr;
|
|
|
|
core::DynamicArray<core::String> infiles;
|
|
|
|
if (hasArg("--input")) {
|
|
|
|
int argn = 0;
|
|
|
|
for (;;) {
|
|
|
|
const core::String &val = getArgVal("--input", "", &argn);
|
|
|
|
if (val.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
infiles.push_back(val);
|
|
|
|
if (!infilesstr.empty()) {
|
|
|
|
infilesstr += ", ";
|
|
|
|
}
|
|
|
|
infilesstr += val;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Log::warn("You are not using --input - this is deprecated and will get removed in a later version");
|
|
|
|
infiles.push_back(_argv[_argc - 2]);
|
|
|
|
infilesstr += _argv[_argc - 2];
|
|
|
|
}
|
|
|
|
core::String outfile;
|
|
|
|
if (hasArg("--output")) {
|
|
|
|
outfile = getArgVal("--output");
|
|
|
|
} else {
|
|
|
|
Log::warn("You are not using --output - this is deprecated and will get removed in a later version");
|
|
|
|
outfile = _argv[_argc - 1];
|
|
|
|
}
|
2020-05-17 08:42:43 -07:00
|
|
|
|
2021-12-20 12:31:20 -08:00
|
|
|
const bool mergeVolumes = hasArg("--merge");
|
|
|
|
const bool scaleVolumes = hasArg("--scale");
|
2021-12-21 10:47:48 -08:00
|
|
|
const bool mirrorVolumes = hasArg("--mirror");
|
|
|
|
const bool rotateVolumes = hasArg("--rotate");
|
|
|
|
const bool translateVolumes = hasArg("--translate");
|
2021-12-20 12:31:20 -08:00
|
|
|
const bool srcPalette = hasArg("--src-palette");
|
2021-11-30 12:18:28 -08:00
|
|
|
const bool exportPalette = hasArg("--export-palette");
|
2020-10-01 09:16:42 -07:00
|
|
|
|
|
|
|
Log::info("Options");
|
|
|
|
if (voxelformat::isMeshFormat(outfile)) {
|
|
|
|
Log::info("* palette: - %s", _palette->strVal().c_str());
|
|
|
|
Log::info("* mergeQuads: - %s", _mergeQuads->strVal().c_str());
|
|
|
|
Log::info("* reuseVertices: - %s", _reuseVertices->strVal().c_str());
|
|
|
|
Log::info("* ambientOcclusion: - %s", _ambientOcclusion->strVal().c_str());
|
|
|
|
Log::info("* scale: - %s", _scale->strVal().c_str());
|
|
|
|
Log::info("* quads: - %s", _quads->strVal().c_str());
|
|
|
|
Log::info("* withColor: - %s", _withColor->strVal().c_str());
|
|
|
|
Log::info("* withTexCoords: - %s", _withTexCoords->strVal().c_str());
|
|
|
|
}
|
2021-12-21 08:07:34 -08:00
|
|
|
Log::info("* input files: - %s", infilesstr.c_str());
|
|
|
|
Log::info("* output files: - %s", outfile.c_str());
|
2021-12-15 13:31:35 -08:00
|
|
|
core::String scriptParameters;
|
|
|
|
if (hasArg("--script")) {
|
|
|
|
scriptParameters = getArgVal("--script");
|
|
|
|
Log::info("* script: - %s", scriptParameters.c_str());
|
|
|
|
}
|
2021-11-30 12:18:28 -08:00
|
|
|
Log::info("* merge volumes: - %s", (mergeVolumes ? "true" : "false"));
|
|
|
|
Log::info("* scale volumes: - %s", (scaleVolumes ? "true" : "false"));
|
2021-12-21 10:47:48 -08:00
|
|
|
Log::info("* mirror volumes: - %s", (mirrorVolumes ? "true" : "false"));
|
|
|
|
Log::info("* translate volumes: - %s", (translateVolumes ? "true" : "false"));
|
|
|
|
Log::info("* rotate volumes: - %s", (rotateVolumes ? "true" : "false"));
|
2021-11-30 12:18:28 -08:00
|
|
|
Log::info("* use source file palette: - %s", (srcPalette ? "true" : "false"));
|
|
|
|
Log::info("* export used palette as image: - %s", (exportPalette ? "true" : "false"));
|
2020-05-17 08:42:43 -07:00
|
|
|
|
2021-11-30 11:39:06 -08:00
|
|
|
io::FilePtr paletteFile = filesystem()->open(core::string::format("palette-%s.png", _palette->strVal().c_str()));
|
|
|
|
if (!paletteFile->exists()) {
|
|
|
|
paletteFile = filesystem()->open(_palette->strVal());
|
|
|
|
}
|
|
|
|
if (!voxel::initMaterialColors(paletteFile, io::FilePtr())) {
|
|
|
|
Log::error("Failed to init default material colors");
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
|
|
|
|
2021-12-19 09:58:45 -08:00
|
|
|
const bool outfileExists = filesystem()->open(outfile)->exists();
|
|
|
|
if (outfileExists) {
|
2021-12-20 12:31:20 -08:00
|
|
|
if (!hasArg("--force")) {
|
2020-06-11 10:37:59 -07:00
|
|
|
Log::error("Given output file '%s' already exists", outfile.c_str());
|
2020-08-30 13:46:21 -07:00
|
|
|
return app::AppState::InitFailure;
|
2020-06-11 10:37:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-19 10:01:07 -08:00
|
|
|
const io::FilePtr outputFile = filesystem()->open(outfile, io::FileMode::SysWrite);
|
|
|
|
if (!outputFile->validHandle()) {
|
|
|
|
Log::error("Could not open target file: %s", outfile.c_str());
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
|
|
|
|
2020-06-11 10:37:59 -07:00
|
|
|
voxel::VoxelVolumes volumes;
|
2021-12-21 08:07:34 -08:00
|
|
|
for (const core::String& infile : infiles) {
|
|
|
|
const io::FilePtr inputFile = filesystem()->open(infile, io::FileMode::SysRead);
|
|
|
|
if (!inputFile->exists()) {
|
|
|
|
Log::error("Given input file '%s' does not exist", infile.c_str());
|
|
|
|
_exitCode = 127;
|
2021-12-15 12:08:09 -08:00
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
2021-12-21 08:07:34 -08:00
|
|
|
const bool inputIsImage = inputFile->isAnyOf(io::format::images());
|
|
|
|
if (!inputIsImage && srcPalette) {
|
|
|
|
core::Array<uint32_t, 256> palette;
|
|
|
|
io::FileStream palStream(inputFile.get());
|
|
|
|
const size_t numColors = voxelformat::loadPalette(inputFile->name(), palStream, palette);
|
|
|
|
if (numColors == 0) {
|
|
|
|
Log::error("Failed to load palette from input file");
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
|
|
|
if (!voxel::initMaterialColors((const uint8_t*)palette.begin(), numColors, "")) {
|
|
|
|
Log::error("Failed to initialize material colors from input file");
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exportPalette) {
|
|
|
|
const core::String &paletteFile = core::string::stripExtension(infile) + ".png";
|
|
|
|
image::Image img(paletteFile);
|
|
|
|
img.loadRGBA((const uint8_t*)palette.begin(), (int)numColors * 4, (int)numColors, 1);
|
|
|
|
if (!img.writePng()) {
|
|
|
|
Log::warn("Failed to write the palette file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inputIsImage) {
|
|
|
|
Log::info("Generate from heightmap");
|
|
|
|
const image::ImagePtr& image = image::loadImage(inputFile, false);
|
|
|
|
if (!image || !image->isLoaded()) {
|
|
|
|
Log::error("Couldn't load image %s", infile.c_str());
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
|
|
|
voxel::Region region(0, 0, 0, image->width(), 255, image->height());
|
|
|
|
voxel::RawVolume* volume = new voxel::RawVolume(region);
|
|
|
|
volumes.push_back(voxel::VoxelVolume(volume, infile, true, glm::ivec3(0)));
|
|
|
|
voxel::RawVolumeWrapper wrapper(volume);
|
|
|
|
voxelutil::importHeightmap(wrapper, image);
|
|
|
|
} else {
|
|
|
|
io::FileStream inputFileStream(inputFile.get());
|
|
|
|
if (!voxelformat::loadFormat(inputFile->name(), inputFileStream, volumes)) {
|
|
|
|
Log::error("Failed to load given input file");
|
|
|
|
return app::AppState::InitFailure;
|
|
|
|
}
|
2021-12-15 12:08:09 -08:00
|
|
|
}
|
2020-05-17 08:42:43 -07:00
|
|
|
|
2021-12-21 08:07:34 -08:00
|
|
|
filterVolumes(volumes);
|
2020-05-22 11:53:28 -07:00
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (mergeVolumes) {
|
|
|
|
Log::info("Merge layers");
|
|
|
|
voxel::RawVolume* merged = volumes.merge();
|
|
|
|
if (merged == nullptr) {
|
|
|
|
Log::error("Failed to merge volumes");
|
|
|
|
return app::AppState::InitFailure;
|
2021-12-15 13:31:35 -08:00
|
|
|
}
|
2021-12-21 10:47:48 -08:00
|
|
|
voxelformat::clearVolumes(volumes);
|
|
|
|
volumes.push_back(voxel::VoxelVolume(merged));
|
|
|
|
}
|
2021-12-15 13:31:35 -08:00
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (scaleVolumes) {
|
|
|
|
scale(volumes);
|
2021-12-15 13:31:35 -08:00
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (mirrorVolumes) {
|
2021-12-17 14:31:50 -08:00
|
|
|
mirror(getArgVal("--mirror"), volumes);
|
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (rotateVolumes) {
|
2021-12-17 14:35:22 -08:00
|
|
|
rotate(getArgVal("--rotate"), volumes);
|
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (translateVolumes) {
|
2021-12-21 08:50:19 -08:00
|
|
|
const core::String &arguments = getArgVal("--translate");
|
|
|
|
glm::ivec3 t(0);
|
|
|
|
if (SDL_sscanf(arguments.c_str(), "%i:%i:%i", &t.x, &t.y, &t.z) >= 1) {
|
|
|
|
translate(t, volumes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
if (!scriptParameters.empty()) {
|
|
|
|
script(scriptParameters, volumes);
|
|
|
|
}
|
|
|
|
|
2020-10-02 10:12:01 -07:00
|
|
|
Log::debug("Save");
|
2020-10-01 09:14:51 -07:00
|
|
|
if (!voxelformat::saveFormat(outputFile, volumes)) {
|
2020-05-17 08:42:43 -07:00
|
|
|
voxelformat::clearVolumes(volumes);
|
|
|
|
Log::error("Failed to write to output file '%s'", outfile.c_str());
|
2020-08-30 13:46:21 -07:00
|
|
|
return app::AppState::InitFailure;
|
2020-05-17 08:42:43 -07:00
|
|
|
}
|
2020-06-11 10:37:59 -07:00
|
|
|
Log::info("Wrote output file %s", outputFile->name().c_str());
|
2020-05-17 08:42:43 -07:00
|
|
|
|
|
|
|
voxelformat::clearVolumes(volumes);
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2021-12-21 10:47:48 -08:00
|
|
|
void VoxConvert::script(const core::String &scriptParameters, voxel::VoxelVolumes& volumes) {
|
|
|
|
voxelgenerator::LUAGenerator script;
|
|
|
|
if (!script.init()) {
|
|
|
|
Log::warn("Failed to initialize the script bindings");
|
|
|
|
} else {
|
|
|
|
core::DynamicArray<core::String> tokens;
|
|
|
|
core::string::splitString(scriptParameters, tokens);
|
|
|
|
const core::String &luaScript = script.load(tokens[0]);
|
|
|
|
if (luaScript.empty()) {
|
|
|
|
Log::error("Failed to load %s", tokens[0].c_str());
|
|
|
|
} else {
|
|
|
|
const voxel::Voxel voxel = voxel::createVoxel(voxel::VoxelType::Generic, 1);
|
|
|
|
core::DynamicArray<voxelgenerator::LUAParameterDescription> argsInfo;
|
|
|
|
if (!script.argumentInfo(luaScript, argsInfo)) {
|
|
|
|
Log::warn("Failed to get argument details");
|
|
|
|
}
|
|
|
|
core::DynamicArray<core::String> args(tokens.size() - 1);
|
|
|
|
for (size_t i = 1; i < tokens.size(); ++i) {
|
|
|
|
args[i - 1] = tokens[i];
|
|
|
|
}
|
|
|
|
Log::info("Execute script %s", tokens[0].c_str());
|
|
|
|
for (auto& v : volumes) {
|
|
|
|
voxel::RawVolumeWrapper wrapper(v.volume);
|
|
|
|
script.exec(luaScript, &wrapper, wrapper.region(), voxel, args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
script.shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoxConvert::scale(voxel::VoxelVolumes& volumes) {
|
|
|
|
Log::info("Scale layers");
|
|
|
|
for (auto& v : volumes) {
|
|
|
|
const voxel::Region srcRegion = v.volume->region();
|
|
|
|
const glm::ivec3& targetDimensionsHalf = (srcRegion.getDimensionsInVoxels() / 2) - 1;
|
|
|
|
const voxel::Region destRegion(srcRegion.getLowerCorner(), srcRegion.getLowerCorner() + targetDimensionsHalf);
|
|
|
|
if (destRegion.isValid()) {
|
|
|
|
voxel::RawVolume* destVolume = new voxel::RawVolume(destRegion);
|
|
|
|
rescaleVolume(*v.volume, *destVolume);
|
|
|
|
delete v.volume;
|
|
|
|
v.volume = destVolume;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 06:46:55 -08:00
|
|
|
void VoxConvert::filterVolumes(voxel::VoxelVolumes& volumes) {
|
2021-12-17 07:49:49 -08:00
|
|
|
const bool applyFilter = hasArg("--filter");
|
2021-12-17 06:46:55 -08:00
|
|
|
if (!applyFilter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-17 07:49:49 -08:00
|
|
|
const core::String &filter = getArgVal("--filter");
|
2021-12-17 06:46:55 -08:00
|
|
|
if (filter.empty()) {
|
|
|
|
Log::warn("No filter specified");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
core::Set<int> layers;
|
|
|
|
core::DynamicArray<core::String> tokens;
|
|
|
|
core::string::splitString(filter, tokens, ",");
|
|
|
|
for (const core::String& token : tokens) {
|
|
|
|
if (token.contains("-")) {
|
|
|
|
const int start = token.toInt();
|
|
|
|
const size_t index = token.find("-");
|
|
|
|
const core::String &endString = token.substr(index + 1);
|
|
|
|
const int end = endString.toInt();
|
|
|
|
for (int layer = start; layer <= end; ++layer) {
|
|
|
|
layers.insert(layer);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const int layer = token.toInt();
|
|
|
|
layers.insert(layer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < (int)volumes.size(); ++i) {
|
|
|
|
if (!layers.has(i)) {
|
|
|
|
delete volumes.volumes[i].volume;
|
|
|
|
volumes.volumes[i].volume = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 07:49:49 -08:00
|
|
|
Log::info("Filtered layers: %i", (int)layers.size());
|
2021-12-17 06:46:55 -08:00
|
|
|
}
|
|
|
|
|
2021-12-17 14:35:22 -08:00
|
|
|
static math::Axis toAxis(const core::String& axisStr) {
|
2021-12-17 14:31:50 -08:00
|
|
|
const char axisChr = core::string::toLower(axisStr[0]);
|
|
|
|
math::Axis axis = math::Axis::None;
|
|
|
|
switch (axisChr) {
|
|
|
|
case 'x':
|
|
|
|
axis = math::Axis::X;
|
|
|
|
break;
|
|
|
|
case 'y':
|
|
|
|
axis = math::Axis::Y;
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
axis = math::Axis::Z;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (axis == math::Axis::None) {
|
|
|
|
Log::warn("Invalid axis given (valid are x, y and z)");
|
2021-12-17 14:35:22 -08:00
|
|
|
}
|
|
|
|
return axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoxConvert::mirror(const core::String& axisStr, voxel::VoxelVolumes& volumes) {
|
|
|
|
const math::Axis axis = toAxis(axisStr);
|
|
|
|
if (axis == math::Axis::None) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-18 05:14:10 -08:00
|
|
|
Log::info("Mirror on axis %c", axisStr[0]);
|
2021-12-17 14:35:22 -08:00
|
|
|
for (voxel::VoxelVolume &v : volumes) {
|
|
|
|
voxel::RawVolume *old = v.volume;
|
|
|
|
if (old == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
v.volume = voxel::mirrorAxis(old, axis);
|
|
|
|
delete old;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VoxConvert::rotate(const core::String& axisStr, voxel::VoxelVolumes& volumes) {
|
|
|
|
const math::Axis axis = toAxis(axisStr);
|
|
|
|
if (axis == math::Axis::None) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-18 05:14:10 -08:00
|
|
|
Log::info("Rotate on axis %c", axisStr[0]);
|
2021-12-17 14:35:22 -08:00
|
|
|
for (voxel::VoxelVolume &v : volumes) {
|
|
|
|
voxel::RawVolume *old = v.volume;
|
|
|
|
if (old == nullptr) {
|
|
|
|
continue;
|
2021-12-17 14:31:50 -08:00
|
|
|
}
|
2021-12-17 14:35:22 -08:00
|
|
|
v.volume = voxel::rotateAxis(old, axis);
|
|
|
|
delete old;
|
2021-12-17 14:31:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-21 08:50:19 -08:00
|
|
|
void VoxConvert::translate(const glm::ivec3& pos, voxel::VoxelVolumes& volumes) {
|
|
|
|
Log::info("Translate by %i:%i:%i", pos.x, pos.y, pos.z);
|
|
|
|
for (voxel::VoxelVolume &v : volumes) {
|
|
|
|
if (v.volume == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
v.volume->translate(pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 08:42:43 -07:00
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
const core::EventBusPtr& eventBus = std::make_shared<core::EventBus>();
|
|
|
|
const io::FilesystemPtr& filesystem = std::make_shared<io::Filesystem>();
|
|
|
|
const core::TimeProviderPtr& timeProvider = std::make_shared<core::TimeProvider>();
|
|
|
|
const metric::MetricPtr& metric = std::make_shared<metric::Metric>();
|
|
|
|
VoxConvert app(metric, filesystem, eventBus, timeProvider);
|
|
|
|
return app.startMainLoop(argc, argv);
|
|
|
|
}
|