feat: add optional gltfpack compression
This commit is contained in:
parent
b454f18a02
commit
003b9306e7
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,3 +8,7 @@ temp/
|
||||
# pixi environments
|
||||
.pixi/
|
||||
output/
|
||||
*.stp
|
||||
*.stl
|
||||
*.step
|
||||
*.glb
|
||||
@ -73,6 +73,7 @@ set(SOURCES
|
||||
src/config_utils.cpp
|
||||
src/http_server.cpp
|
||||
src/http_downloader.cpp
|
||||
src/compression_utils.cpp
|
||||
src/geom/Color.cpp
|
||||
src/cadit/occt/step_tree.cpp
|
||||
src/cadit/occt/debug.cpp
|
||||
@ -89,6 +90,7 @@ set(HEADERS
|
||||
src/config_structs.h
|
||||
src/http_server.h
|
||||
src/http_downloader.h
|
||||
src/compression_utils.h
|
||||
src/geom/Color.h
|
||||
src/cadit/occt/step_tree.h
|
||||
src/cadit/occt/convert.h
|
||||
|
||||
99
src/compression_utils.cpp
Normal file
99
src/compression_utils.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "compression_utils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
|
||||
std::string quote_arg(const std::string& value) {
|
||||
std::string escaped;
|
||||
escaped.reserve(value.size());
|
||||
for (char c : value) {
|
||||
if (c == '"') {
|
||||
escaped += "\\\"";
|
||||
} else {
|
||||
escaped.push_back(c);
|
||||
}
|
||||
}
|
||||
return '"' + escaped + '"';
|
||||
}
|
||||
|
||||
std::string quote_path(const std::filesystem::path& path) {
|
||||
return quote_arg(path.string());
|
||||
}
|
||||
|
||||
void ensure_parent_directory(const std::filesystem::path& path) {
|
||||
const auto parent = path.parent_path();
|
||||
if (!parent.empty() && !std::filesystem::exists(parent)) {
|
||||
std::filesystem::create_directories(parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void apply_gltfpack_compression(const GlobalConfig& config) {
|
||||
if (!config.compress_glb) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path input_glb = config.glbFile;
|
||||
if (!std::filesystem::exists(input_glb)) {
|
||||
throw std::runtime_error("GLB file does not exist, cannot run gltfpack: " + input_glb.string());
|
||||
}
|
||||
|
||||
std::filesystem::path target_output = config.compressed_glb_path.empty() ? input_glb : config.compressed_glb_path;
|
||||
ensure_parent_directory(target_output);
|
||||
|
||||
bool overwrite_original = target_output == input_glb;
|
||||
std::filesystem::path gltfpack_output;
|
||||
if (overwrite_original) {
|
||||
gltfpack_output = target_output;
|
||||
gltfpack_output += ".tmp";
|
||||
gltfpack_output.replace_extension(".glb");
|
||||
} else {
|
||||
gltfpack_output = target_output;
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(gltfpack_output)) {
|
||||
std::filesystem::remove(gltfpack_output);
|
||||
}
|
||||
|
||||
std::ostringstream command;
|
||||
const bool path_needs_quotes = config.gltfpack_path.find_first_of(" \t\"") != std::string::npos;
|
||||
if (path_needs_quotes) {
|
||||
command << quote_arg(config.gltfpack_path);
|
||||
} else {
|
||||
command << config.gltfpack_path;
|
||||
}
|
||||
if (!config.gltfpack_args.empty()) {
|
||||
command << ' ' << config.gltfpack_args;
|
||||
}
|
||||
command << " -i " << quote_path(input_glb);
|
||||
command << " -o " << quote_path(gltfpack_output);
|
||||
|
||||
std::cout << "Running gltfpack compression..." << std::endl;
|
||||
const int exit_code = std::system(command.str().c_str());
|
||||
if (exit_code != 0) {
|
||||
if (std::filesystem::exists(gltfpack_output)) {
|
||||
std::filesystem::remove(gltfpack_output);
|
||||
}
|
||||
std::ostringstream err;
|
||||
err << "gltfpack failed with exit code: " << exit_code;
|
||||
throw std::runtime_error(err.str());
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(gltfpack_output)) {
|
||||
throw std::runtime_error("gltfpack did not produce the expected output: " + gltfpack_output.string());
|
||||
}
|
||||
|
||||
if (overwrite_original) {
|
||||
std::filesystem::remove(input_glb);
|
||||
std::filesystem::rename(gltfpack_output, input_glb);
|
||||
}
|
||||
|
||||
std::cout << "gltfpack compression finished." << std::endl;
|
||||
}
|
||||
8
src/compression_utils.h
Normal file
8
src/compression_utils.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef COMPRESSION_UTILS_H
|
||||
#define COMPRESSION_UTILS_H
|
||||
|
||||
#include "config_structs.h"
|
||||
|
||||
void apply_gltfpack_compression(const GlobalConfig& config);
|
||||
|
||||
#endif
|
||||
@ -7,9 +7,10 @@
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
struct BuildConfig {
|
||||
bool build_bspline_surf;
|
||||
bool build_bspline_surf = false;
|
||||
};
|
||||
|
||||
struct ServerConfig {
|
||||
@ -46,6 +47,12 @@ struct GlobalConfig {
|
||||
// HTTP download tracking
|
||||
bool is_downloaded_from_url = false;
|
||||
std::string original_url;
|
||||
|
||||
// GLB compression settings
|
||||
bool compress_glb = false;
|
||||
std::filesystem::path compressed_glb_path{};
|
||||
std::string gltfpack_path = "gltfpack";
|
||||
std::string gltfpack_args = "-cc -tc -kn -km -vpf";
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -76,6 +76,11 @@ GlobalConfig process_parameters(CLI::App& app)
|
||||
const auto filter_names_exclude_input = app.get_option("--filter-names-exclude")->as<std::string>();
|
||||
const auto filter_names_file_exclude = app.get_option("--filter-names-file-exclude")->as<std::string>();
|
||||
|
||||
const bool compress_glb = app.get_option("--compress-glb")->as<bool>();
|
||||
const auto compressed_glb_value = app.get_option("--compressed-glb")->as<std::string>();
|
||||
const auto gltfpack_path_value = app.get_option("--gltfpack-path")->as<std::string>();
|
||||
const auto gltfpack_args_value = app.get_option("--gltfpack-args")->as<std::string>();
|
||||
|
||||
// Process include and exclude filter names
|
||||
const auto filter_names_include = process_filter_names(filter_names_include_input, filter_names_file_include);
|
||||
const auto filter_names_exclude = process_filter_names(filter_names_exclude_input, filter_names_file_exclude);
|
||||
@ -139,9 +144,7 @@ GlobalConfig process_parameters(CLI::App& app)
|
||||
.tessellation_timout = app.get_option("--tessellation-timeout")->as<int>(),
|
||||
.filter_names_include = filter_names_include,
|
||||
.filter_names_exclude = filter_names_exclude,
|
||||
.buildConfig = {
|
||||
.build_bspline_surf = false
|
||||
},
|
||||
.buildConfig = {},
|
||||
.serverConfig = {
|
||||
.enable_server = app.get_option("--server")->as<bool>(),
|
||||
.port = app.get_option("--port")->as<int>(),
|
||||
@ -150,6 +153,10 @@ GlobalConfig process_parameters(CLI::App& app)
|
||||
.temp_dir = "./temp"
|
||||
},
|
||||
.is_downloaded_from_url = isDownloadedFromUrl,
|
||||
.original_url = originalUrl
|
||||
.original_url = originalUrl,
|
||||
.compress_glb = compress_glb,
|
||||
.compressed_glb_path = compressed_glb_value.empty() ? std::filesystem::path{} : std::filesystem::path(compressed_glb_value),
|
||||
.gltfpack_path = gltfpack_path_value,
|
||||
.gltfpack_args = gltfpack_args_value
|
||||
};
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "cadit/occt/convert.h"
|
||||
#include "cadit/occt/debug.h"
|
||||
#include "http_downloader.h"
|
||||
#include "compression_utils.h"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
@ -95,6 +96,26 @@ void start_http_server(const GlobalConfig& base_config) {
|
||||
config.max_geometry_num = std::stoi(req.form.get_field("maxGeometryNum"));
|
||||
}
|
||||
|
||||
if (req.form.has_field("compressGlb")) {
|
||||
config.compress_glb = req.form.get_field("compressGlb") == "true";
|
||||
}
|
||||
if (req.form.has_field("gltfpackPath")) {
|
||||
config.gltfpack_path = req.form.get_field("gltfpackPath");
|
||||
}
|
||||
if (req.form.has_field("gltfpackArgs")) {
|
||||
config.gltfpack_args = req.form.get_field("gltfpackArgs");
|
||||
}
|
||||
if (req.form.has_field("compressedGlb")) {
|
||||
std::string compressed_value = req.form.get_field("compressedGlb");
|
||||
if (!compressed_value.empty()) {
|
||||
fs::path compressed_path = compressed_value;
|
||||
if (!compressed_path.is_absolute()) {
|
||||
compressed_path = fs::path(config.serverConfig.output_dir) / compressed_path;
|
||||
}
|
||||
config.compressed_glb_path = compressed_path;
|
||||
}
|
||||
}
|
||||
|
||||
std::string base_filename = generate_unique_filename("");
|
||||
std::string stp_filename = base_filename + ".stp";
|
||||
std::string glb_filename = base_filename + ".glb";
|
||||
@ -132,16 +153,25 @@ void start_http_server(const GlobalConfig& base_config) {
|
||||
convert_stp_to_glb(config);
|
||||
}
|
||||
|
||||
apply_gltfpack_compression(config);
|
||||
|
||||
if (config.compress_glb && !config.compressed_glb_path.empty() && config.compressed_glb_path != glb_path && fs::exists(glb_path)) {
|
||||
fs::remove(glb_path);
|
||||
}
|
||||
|
||||
const auto stop = std::chrono::high_resolution_clock::now();
|
||||
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
|
||||
const double seconds = static_cast<double>(duration.count()) / 1e6;
|
||||
|
||||
std::cout << "Conversion completed in " << std::fixed << std::setprecision(2) << seconds << " seconds" << "\n";
|
||||
std::cout << "Output saved: " << glb_path << "\n";
|
||||
fs::path final_glb_path = config.compress_glb && !config.compressed_glb_path.empty() ? config.compressed_glb_path : glb_path;
|
||||
|
||||
std::cout << "Output saved: " << final_glb_path << "\n";
|
||||
|
||||
fs::remove(stp_path);
|
||||
|
||||
std::string response = "{\"success\":true,\"output_file\":\"" + glb_filename + "\",\"output_path\":\"" + glb_path.string() + "\",\"conversion_time\":" + std::to_string(seconds) + "}";
|
||||
std::string final_filename = final_glb_path.filename().string();
|
||||
std::string response = "{\"success\":true,\"output_file\":\"" + final_filename + "\",\"output_path\":\"" + final_glb_path.string() + "\",\"conversion_time\":" + std::to_string(seconds) + "}";
|
||||
res.set_content(response, "application/json");
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
@ -149,6 +179,9 @@ void start_http_server(const GlobalConfig& base_config) {
|
||||
|
||||
if (fs::exists(stp_path)) fs::remove(stp_path);
|
||||
if (fs::exists(glb_path)) fs::remove(glb_path);
|
||||
if (config.compress_glb && !config.compressed_glb_path.empty() && fs::exists(config.compressed_glb_path)) {
|
||||
fs::remove(config.compressed_glb_path);
|
||||
}
|
||||
|
||||
res.status = 500;
|
||||
std::string error_msg = "{\"success\":false,\"error\":\"" + std::string(ex.what()) + "\"}";
|
||||
|
||||
24
src/main.cpp
24
src/main.cpp
@ -15,6 +15,7 @@
|
||||
#include "cadit/occt/helpers.h"
|
||||
#include "config_utils.h"
|
||||
#include "http_server.h"
|
||||
#include "compression_utils.h"
|
||||
|
||||
void print_status(const GlobalConfig& config) {
|
||||
std::cout << "STP2GLB Converter" << "\n";
|
||||
@ -30,6 +31,14 @@ void print_status(const GlobalConfig& config) {
|
||||
std::cout << "Max Geometry Num: " << config.max_geometry_num << "\n";
|
||||
std::cout << "Tessellation Timeout: " << config.tessellation_timout << "\n\n";
|
||||
|
||||
std::cout << "Compression: " << (config.compress_glb ? "enabled" : "disabled") << "\n";
|
||||
if (config.compress_glb) {
|
||||
std::cout << "gltfpack Path: " << config.gltfpack_path << "\n";
|
||||
std::cout << "gltfpack Args: " << config.gltfpack_args << "\n\n";
|
||||
} else {
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// Debug output
|
||||
if (!config.filter_names_include.empty())
|
||||
{
|
||||
@ -73,6 +82,10 @@ int main(int argc, char* argv[])
|
||||
app.add_option("--filter-names-exclude", "Exclude Filter name. Command separated list")->default_val("");
|
||||
app.add_option("--filter-names-file-exclude", "Exclude Filter name file")->default_val("");
|
||||
app.add_option("--tessellation-timeout", "Tessellation timeout")->default_val(30);
|
||||
app.add_flag("--compress-glb", "Enable glTF compression using gltfpack");
|
||||
app.add_option("--compressed-glb", "Optional output path for compressed GLB (defaults to original)")->default_val("");
|
||||
app.add_option("--gltfpack-path", "Path to gltfpack executable")->default_val("gltfpack");
|
||||
app.add_option("--gltfpack-args", "Arguments passed to gltfpack")->default_val("-cc -tc -kn -km -vpf");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
@ -95,6 +108,15 @@ int main(int argc, char* argv[])
|
||||
config.serverConfig.temp_dir = "./temp";
|
||||
config.serverConfig.output_dir = "./output";
|
||||
|
||||
config.compress_glb = app.get_option("--compress-glb")->as<bool>();
|
||||
config.gltfpack_path = app.get_option("--gltfpack-path")->as<std::string>();
|
||||
config.gltfpack_args = app.get_option("--gltfpack-args")->as<std::string>();
|
||||
|
||||
const auto compressed_glb_cli = app.get_option("--compressed-glb")->as<std::string>();
|
||||
if (!compressed_glb_cli.empty()) {
|
||||
std::cout << "Warning: --compressed-glb is ignored in server mode." << "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
start_http_server(config);
|
||||
} catch (const std::exception& ex) {
|
||||
@ -130,6 +152,8 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
convert_stp_to_glb(config);
|
||||
}
|
||||
|
||||
apply_gltfpack_compression(config);
|
||||
} catch (std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
return 1;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user