diff --git a/CMakeLists.txt b/CMakeLists.txt index d8ffcc6..9ffa368 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,17 +127,6 @@ ExternalProject_Add(CPPCodec ) set(CPPCODEC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/cppcodec/src/CPPCodec") -# CXXOPTS -ExternalProject_Add(CxxOpts - GIT_REPOSITORY https://github.com/jarro2783/cxxopts - GIT_TAG v1.4.4 - PREFIX cxxopts - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Skipping cxxopts configure step." - BUILD_COMMAND ${CMAKE_COMMAND} -E echo "Skipping cxxopts build step." - INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "Skipping cxxopts install step." -) -set(CXXOPTS_INCLUDE_DIR "${CMAKE_BINARY_DIR}/cxxopts/src/CxxOpts/include") - # FMT ExternalProject_Add(Fmt PREFIX fmt @@ -220,6 +209,7 @@ set(LIB_SOURCE_FILES src/utils/Image_Utils.hpp src/utils/String_Utils.cpp src/utils/String_Utils.hpp + third_party/CLI11/CLI11.hpp ) add_library(libFBX2glTF STATIC ${LIB_SOURCE_FILES}) @@ -233,7 +223,6 @@ add_dependencies(libFBX2glTF FiFoMap Json STB - CxxOpts CPPCodec Fmt ) @@ -297,7 +286,7 @@ if (Iconv_FOUND) endif() target_include_directories(appFBX2glTF PUBLIC - ${CXXOPTS_INCLUDE_DIR} + "third_party/CLI11" ) target_link_libraries(appFBX2glTF libFBX2glTF) diff --git a/src/FBX2glTF.cpp b/src/FBX2glTF.cpp index 3b0cbd1..c4ba952 100644 --- a/src/FBX2glTF.cpp +++ b/src/FBX2glTF.cpp @@ -7,310 +7,392 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#include -#include -#include -#include #include +#include +#include +#include +#include -#if defined( __unix__ ) || defined( __APPLE__ ) +#if defined(__unix__) || defined(__APPLE__) #include #define _stricmp strcasecmp #endif -#include +#include #include "FBX2glTF.h" -#include "utils/String_Utils.hpp" -#include "utils/File_Utils.hpp" #include "fbx/Fbx2Raw.hpp" #include "gltf/Raw2Gltf.hpp" +#include "utils/File_Utils.hpp" +#include "utils/String_Utils.hpp" bool verboseOutput = false; -int main(int argc, char *argv[]) -{ - cxxopts::Options options( - "FBX2glTF", - fmt::sprintf("FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.", FBX2GLTF_VERSION) - ); +int main(int argc, char* argv[]) { + GltfOptions gltfOptions; - std::string inputPath; - std::string outputPath; + CLI::App app{ + fmt::sprintf( + "FBX2glTF %s: Generate a glTF 2.0 representation of an FBX model.", + FBX2GLTF_VERSION), + "FBX2glTF"}; - std::vector> texturesTransforms; - - GltfOptions gltfOptions; - - options.positional_help("[]"); - options.add_options() - ( - "i,input", "The FBX model to convert.", - cxxopts::value(inputPath)) - ( - "o,output", "Where to generate the output, without suffix.", - cxxopts::value(outputPath)) - ( - "e,embed", "Inline buffers as data:// URIs within generated non-binary glTF.", - cxxopts::value(gltfOptions.embedResources)) - ( - "b,binary", "Output a single binary format .glb file.", - cxxopts::value(gltfOptions.outputBinary)) - ( - "long-indices", "Whether to use 32-bit indices (never|auto|always).", - cxxopts::value>()) - ( - "d,draco", "Apply Draco mesh compression to geometries.", - cxxopts::value(gltfOptions.draco.enabled)) - ( - "draco-compression-level", "The compression level to tune Draco to, from 0 to 10. (default: 7)", - cxxopts::value(gltfOptions.draco.compressionLevel)) - ( - "draco-bits-for-positions", "How many bits to quantize position to. (default: 14)", - cxxopts::value(gltfOptions.draco.quantBitsPosition)) - ( - "draco-bits-for-uv", "How many bits to quantize UV coordinates to. (default: 10)", - cxxopts::value(gltfOptions.draco.quantBitsTexCoord)) - ( - "draco-bits-for-normals", "How many bits to quantize normals to. (default: 10)", - cxxopts::value(gltfOptions.draco.quantBitsNormal)) - ( - "draco-bits-for-colors", "How many bits to quantize color to. (default: 8)", - cxxopts::value(gltfOptions.draco.quantBitsColor)) - ( - "draco-bits-for-other", "How many bits to quantize other vertex attributes to to. (default: 8)", - cxxopts::value(gltfOptions.draco.quantBitsGeneric)) - ( - "compute-normals", "When to compute normals for vertices (never|broken|missing|always).", - cxxopts::value>()) - ("flip-u", "Flip all U texture coordinates.") - ("flip-v", "Flip all V texture coordinates (default behaviour!)") - ("no-flip-v", "Suppress the default flipping of V texture coordinates") - ( - "pbr-metallic-roughness", "Try to glean glTF 2.0 native PBR attributes from the FBX.", - cxxopts::value(gltfOptions.usePBRMetRough)) - ( - "khr-materials-unlit", "Use KHR_materials_unlit extension to specify Unlit shader.", - cxxopts::value(gltfOptions.useKHRMatUnlit)) - ( - "no-khr-punctual-lights", "Don't use KHR_punctual_lights extension to export lights.", - cxxopts::value(gltfOptions.useKHRPunctualLights)) - ( - "user-properties", "Transcribe FBX User Properties into glTF node and material 'extras'.", - cxxopts::value(gltfOptions.enableUserProperties)) - ( - "blend-shape-normals", "Include blend shape normals, if reported present by the FBX SDK.", - cxxopts::value(gltfOptions.useBlendShapeNormals)) - ( - "blend-shape-tangents", "Include blend shape tangents, if reported present by the FBX SDK.", - cxxopts::value(gltfOptions.useBlendShapeTangents)) - ( - "k,keep-attribute", "Used repeatedly to build a limiting set of vertex attributes to keep.", - cxxopts::value>()) - ("v,verbose", "Enable verbose output.") - ("h,help", "Show this help.") - ("V,version", "Display the current program version."); - - try { - options.parse_positional("input"); - options.parse(argc, argv); - - } catch (const cxxopts::OptionException &e) { - fmt::printf(options.help()); - return 1; - } - - if (options.count("version")) { - fmt::printf("FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n", FBX2GLTF_VERSION); - return 0; - } - - if (options.count("help")) { - fmt::printf(options.help()); - return 0; - } - - if (!options.count("input")) { - fmt::printf("You must supply a FBX file to convert.\n"); - fmt::printf(options.help()); - return 1; - } - - if (options.count("verbose")) { - verboseOutput = true; - } - - if (!gltfOptions.useKHRMatUnlit && !gltfOptions.usePBRMetRough) { - if (verboseOutput) { - fmt::printf("Defaulting to --pbr-metallic-roughness material support.\n"); - } - gltfOptions.usePBRMetRough = true; - } - - if (gltfOptions.draco.compressionLevel != -1 && - (gltfOptions.draco.compressionLevel < 1 || gltfOptions.draco.compressionLevel > 10)) { - fmt::printf("Draco compression level must lie in [1, 10].\n"); - return 0; - } - - if (options.count("flip-u") > 0) { - texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); }); - } - if (options.count("flip-v") > 0) { - fmt::printf("Note: The --flip-v command switch is now default behaviour.\n"); - } - if (options.count("no-flip-v") == 0) { - texturesTransforms.emplace_back([](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); }); - } else if (verboseOutput) { - fmt::printf("Suppressing --flip-v transformation of texture coordinates.\n"); - } - - for (const std::string &choice : options["long-indices"].as>()) { - if (choice == "never") { - gltfOptions.useLongIndices = UseLongIndicesOptions::NEVER; - } else if (choice == "auto") { - gltfOptions.useLongIndices = UseLongIndicesOptions::AUTO; - } else if (choice == "always") { - gltfOptions.useLongIndices = UseLongIndicesOptions::ALWAYS; - } else { - fmt::printf("Unknown --long-indices: %s\n", choice); - fmt::printf(options.help()); - return 1; - } - } - - if (options.count("compute-normals") > 0) { - for (const std::string &choice : options["compute-normals"].as>()) { - if (choice == "never") { - gltfOptions.computeNormals = ComputeNormalsOption::NEVER; - } else if (choice == "broken") { - gltfOptions.computeNormals = ComputeNormalsOption::BROKEN; - } else if (choice == "missing") { - gltfOptions.computeNormals = ComputeNormalsOption::MISSING; - } else if (choice == "always") { - gltfOptions.computeNormals = ComputeNormalsOption::ALWAYS; - } else { - fmt::printf("Unknown --compute-normals: %s\n", choice); - fmt::printf(options.help()); - return 1; - } - } - } - - if (options.count("keep-attribute") > 0) { - gltfOptions.keepAttribs = RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; - for (std::string attribute : options["keep-attribute"].as>()) { - if (attribute == "position") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION; } - else if (attribute == "normal") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_NORMAL; } - else if (attribute == "tangent") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_TANGENT; } - else if (attribute == "binormal") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_BINORMAL; } - else if (attribute == "color") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_COLOR; } - else if (attribute == "uv0") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_UV0; } - else if (attribute == "uv1") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_UV1; } - else if (attribute == "auto") { gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_AUTO; } - else { - fmt::printf("Unknown --keep-attribute: %s\n", attribute); - fmt::printf("Valid choices are: position, normal, tangent, binormial, color, uv0, uv1, auto,\n"); - return 1; - } - } - } - - if (gltfOptions.embedResources && gltfOptions.outputBinary) { - fmt::printf("Note: Ignoring --embed; it's meaningless with --binary.\n"); - } - - if (options.count("output") == 0) { - // if -o is not given, default to the basename of the .fbx - outputPath = fmt::format(".{}{}", (const char)StringUtils::GetPathSeparator(), StringUtils::GetFileBaseString(inputPath)); - - fmt::printf("outputPath = %s\n", outputPath); - } - std::string outputFolder; // the output folder in .gltf mode, not used for .glb - std::string modelPath; // the path of the actual .glb or .gltf file - if (gltfOptions.outputBinary) { - // in binary mode, we write precisely where we're asked - modelPath = outputPath + ".glb"; - - } else { - // in gltf mode, we create a folder and write into that - outputFolder = fmt::format("{}_out{}", outputPath.c_str(), (const char)StringUtils::GetPathSeparator()); - modelPath = outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf"; - } - if (!FileUtils::CreatePath(modelPath.c_str())) { - fmt::fprintf(stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str()); - return 1; - } - - ModelData *data_render_model = nullptr; - RawModel raw; - - if (verboseOutput) { - fmt::printf("Loading FBX File: %s\n", inputPath); - } - if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg")) { - fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath); - return 1; - } - - if (!texturesTransforms.empty()) { - raw.TransformTextures(texturesTransforms); - } - raw.Condense(); - raw.TransformGeometry(gltfOptions.computeNormals); - - std::ofstream outStream; // note: auto-flushes in destructor - const auto streamStart = outStream.tellp(); - - outStream.open(modelPath, std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary); - if (outStream.fail()) { - fmt::fprintf(stderr, "ERROR:: Couldn't open file for writing: %s\n", modelPath.c_str()); - return 1; - } - data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions); - - if (gltfOptions.outputBinary) { - fmt::printf( - "Wrote %lu bytes of binary glTF to %s.\n", - (unsigned long) (outStream.tellp() - streamStart), modelPath); - delete data_render_model; - return 0; - } + app.add_flag( + "-v,--verbose", + verboseOutput, + "Include blend shape tangents, if reported present by the FBX SDK."); + app.add_flag_function("-V,--version", [&](size_t count) { fmt::printf( - "Wrote %lu bytes of glTF to %s.\n", - (unsigned long) (outStream.tellp() - streamStart), modelPath); + "FBX2glTF version %s\nCopyright (c) 2016-2018 Oculus VR, LLC.\n", + FBX2GLTF_VERSION); + exit(0); + }); - if (gltfOptions.embedResources) { - // we're done: everything was inlined into the glTF JSON - delete data_render_model; - return 0; - } + std::string inputPath; + app.add_option("FBX Model", inputPath, "The FBX model to convert.") + ->check(CLI::ExistingFile); + app.add_option("-i,--input", inputPath, "The FBX model to convert.") + ->check(CLI::ExistingFile); - assert(!outputFolder.empty()); + std::string outputPath; + app.add_option( + "-o,--output", + outputPath, + "Where to generate the output, without suffix."); - const std::string binaryPath = outputFolder + extBufferFilename; - FILE *fp = fopen(binaryPath.c_str(), "wb"); - if (fp == nullptr) { - fmt::fprintf(stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath); - return 1; - } + app.add_flag( + "-e,--embed", + gltfOptions.embedResources, + "Inline buffers as data:// URIs within generated non-binary glTF."); + app.add_flag( + "-b,--binary", + gltfOptions.outputBinary, + "Output a single binary format .glb file."); - if (data_render_model->binary->empty() == false) - { - const unsigned char *binaryData = &(*data_render_model->binary)[0]; - unsigned long binarySize = data_render_model->binary->size(); - if (fwrite(binaryData, binarySize, 1, fp) != 1) { - fmt::fprintf(stderr, "ERROR: Failed to write %lu bytes to file '%s'.\n", binarySize, binaryPath); - fclose(fp); - return 1; + app.add_option( + "--long-indices", + [&](std::vector choices) -> bool { + for (const std::string choice : choices) { + if (choice == "never") { + gltfOptions.useLongIndices = UseLongIndicesOptions::NEVER; + } else if (choice == "auto") { + gltfOptions.useLongIndices = UseLongIndicesOptions::AUTO; + } else if (choice == "always") { + gltfOptions.useLongIndices = UseLongIndicesOptions::ALWAYS; + } else { + fmt::printf("Unknown --long-indices: %s\n", choice); + throw CLI::RuntimeError(1); + } + } + return true; + }, + "Whether to use 32-bit indices.") + ->type_name("(never|auto|always)"); + + app.add_option( + "--compute-normals", + [&](std::vector choices) -> bool { + for (const std::string choice : choices) { + if (choice == "never") { + gltfOptions.computeNormals = ComputeNormalsOption::NEVER; + } else if (choice == "broken") { + gltfOptions.computeNormals = ComputeNormalsOption::BROKEN; + } else if (choice == "missing") { + gltfOptions.computeNormals = ComputeNormalsOption::MISSING; + } else if (choice == "always") { + gltfOptions.computeNormals = ComputeNormalsOption::ALWAYS; + } else { + fmt::printf("Unknown --compute-normals option: %s\n", choice); + throw CLI::RuntimeError(1); + } + } + return true; + }, + "When to compute vertex normals from mesh geometry.") + ->type_name("(never|broken|missing|always)"); + + std::vector> texturesTransforms; + app.add_flag_function( + "--flip-u", + [&](size_t count) { + if (count > 0) { + texturesTransforms.emplace_back( + [](Vec2f uv) { return Vec2f(1.0f - uv[0], uv[1]); }); + if (verboseOutput) { + fmt::printf("Flipping texture coordinates in the 'U' dimension.\n"); + } } - fclose(fp); - fmt::printf("Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath); - } + }, + "Flip all U texture coordinates."); + app.add_flag("--no-flip-u", "Don't flip U texture coordinates.") + ->excludes("--flip-u"); + + app.add_flag_function( + "--no-flip-v", + [&](size_t count) { + if (count > 0) { + texturesTransforms.emplace_back( + [](Vec2f uv) { return Vec2f(uv[0], 1.0f - uv[1]); }); + if (verboseOutput) { + fmt::printf("NOT flipping texture coordinates in the 'V' dimension.\n"); + } + } + }, + "Flip all V texture coordinates."); + app.add_flag("--flip-v", "Don't flip U texture coordinates.") + ->excludes("--no-flip-v"); + + app.add_flag( + "--pbr-metallic-rougnness", + gltfOptions.usePBRMetRough, + "Try to glean glTF 2.0 native PBR attributes from the FBX.") + ->group("Materials"); + + app.add_flag( + "--khr-materials-unlit", + gltfOptions.useKHRMatUnlit, + "Use KHR_materials_unlit extension to request an unlit shader.") + ->group("Materials"); + + app.add_flag( + "--khr-lights-punctual", + gltfOptions.useKHRLightsPunctual, + "Use KHR_lights_punctual extension to request an unlit shader."); + + app.add_flag( + "--user-properties", + gltfOptions.enableUserProperties, + "Transcribe FBX User Properties into glTF node and material 'extras'."); + + app.add_flag( + "--blend-shape-normals", + gltfOptions.useBlendShapeNormals, + "Include blend shape normals, if reported present by the FBX SDK."); + + app.add_flag( + "--blend-shape-tangents", + gltfOptions.useBlendShapeTangents, + "Include blend shape tangents, if reported present by the FBX SDK."); + + app.add_option( + "-k,--keep-attribute", + [&](std::vector attributes) -> bool { + gltfOptions.keepAttribs = RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | + RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS; + for (std::string attribute : attributes) { + if (attribute == "position") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION; + } else if (attribute == "normal") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_NORMAL; + } else if (attribute == "tangent") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_TANGENT; + } else if (attribute == "binormal") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_BINORMAL; + } else if (attribute == "color") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_COLOR; + } else if (attribute == "uv0") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_UV0; + } else if (attribute == "uv1") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_UV1; + } else if (attribute == "auto") { + gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_AUTO; + } else { + fmt::printf("Unknown --keep-attribute option: %s\n", attribute); + throw CLI::RuntimeError(1); + } + } + return true; + }, + "Used repeatedly to build a limiting set of vertex attributes to keep.") + ->type_size(-1) + ->type_name("(position|normal|tangent|binormial|color|uv0|uv1|auto)"); + + app.add_flag( + "-d,--draco", + gltfOptions.draco.enabled, + "Apply Draco mesh compression to geometries.") + ->group("Draco"); + + app.add_option( + "--draco-compression-level", + gltfOptions.draco.compressionLevel, + "The compression level to tune Draco to.", + true) + ->check(CLI::Range(0, 10)) + ->group("Draco"); + + app.add_option( + "--draco-bits-for-position", + gltfOptions.draco.quantBitsPosition, + "How many bits to quantize position to.", + true) + ->check(CLI::Range(1, 32)) + ->group("Draco"); + + app.add_option( + "--draco-bits-for-uv", + gltfOptions.draco.quantBitsTexCoord, + "How many bits to quantize UV coordinates to.", + true) + ->check(CLI::Range(1, 32)) + ->group("Draco"); + + app.add_option( + "--draco-bits-for-normals", + gltfOptions.draco.quantBitsNormal, + "How many bits to quantize nornals to.", + true) + ->check(CLI::Range(1, 32)) + ->group("Draco"); + + app.add_option( + "--draco-bits-for-colors", + gltfOptions.draco.quantBitsColor, + "How many bits to quantize colors to.", + true) + ->check(CLI::Range(1, 32)) + ->group("Draco"); + + app.add_option( + "--draco-bits-for-other", + gltfOptions.draco.quantBitsGeneric, + "How many bits to quantize all other vertex attributes to.", + true) + ->check(CLI::Range(1, 32)) + ->group("Draco"); + + CLI11_PARSE(app, argc, argv); + + if (inputPath.empty()) { + fmt::printf("You must supply a FBX file to convert.\n"); + exit(1); + } + + if (!gltfOptions.useKHRMatUnlit && !gltfOptions.usePBRMetRough) { + if (verboseOutput) { + fmt::printf("Defaulting to --pbr-metallic-roughness material support.\n"); + } + gltfOptions.usePBRMetRough = true; + } + + if (gltfOptions.embedResources && gltfOptions.outputBinary) { + fmt::printf("Note: Ignoring --embed; it's meaningless with --binary.\n"); + } + + if (outputPath.empty()) { + // if -o is not given, default to the basename of the .fbx + outputPath = fmt::format( + ".{}{}", + (const char)StringUtils::GetPathSeparator(), + StringUtils::GetFileBaseString(inputPath)); + } + // the output folder in .gltf mode, not used for .glb + std::string outputFolder; + + // the path of the actual .glb or .gltf file + std::string modelPath; + if (gltfOptions.outputBinary) { + // in binary mode, we write precisely where we're asked + modelPath = outputPath + ".glb"; + + } else { + // in gltf mode, we create a folder and write into that + outputFolder = fmt::format( + "{}_out{}", + outputPath.c_str(), + (const char)StringUtils::GetPathSeparator()); + modelPath = + outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf"; + } + if (!FileUtils::CreatePath(modelPath.c_str())) { + fmt::fprintf( + stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str()); + return 1; + } + + ModelData* data_render_model = nullptr; + RawModel raw; + + if (verboseOutput) { + fmt::printf("Loading FBX File: %s\n", inputPath); + } + if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg")) { + fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath); + return 1; + } + + if (!texturesTransforms.empty()) { + raw.TransformTextures(texturesTransforms); + } + raw.Condense(); + raw.TransformGeometry(gltfOptions.computeNormals); + + std::ofstream outStream; // note: auto-flushes in destructor + const auto streamStart = outStream.tellp(); + + outStream.open( + modelPath, + std::ios::trunc | std::ios::ate | std::ios::out | std::ios::binary); + if (outStream.fail()) { + fmt::fprintf( + stderr, + "ERROR:: Couldn't open file for writing: %s\n", + modelPath.c_str()); + return 1; + } + data_render_model = Raw2Gltf(outStream, outputFolder, raw, gltfOptions); + + if (gltfOptions.outputBinary) { + fmt::printf( + "Wrote %lu bytes of binary glTF to %s.\n", + (unsigned long)(outStream.tellp() - streamStart), + modelPath); delete data_render_model; return 0; + } + + fmt::printf( + "Wrote %lu bytes of glTF to %s.\n", + (unsigned long)(outStream.tellp() - streamStart), + modelPath); + + if (gltfOptions.embedResources) { + // we're done: everything was inlined into the glTF JSON + delete data_render_model; + return 0; + } + + assert(!outputFolder.empty()); + + const std::string binaryPath = outputFolder + extBufferFilename; + FILE* fp = fopen(binaryPath.c_str(), "wb"); + if (fp == nullptr) { + fmt::fprintf( + stderr, "ERROR:: Couldn't open file '%s' for writing.\n", binaryPath); + return 1; + } + + if (data_render_model->binary->empty() == false) { + const unsigned char* binaryData = &(*data_render_model->binary)[0]; + unsigned long binarySize = data_render_model->binary->size(); + if (fwrite(binaryData, binarySize, 1, fp) != 1) { + fmt::fprintf( + stderr, + "ERROR: Failed to write %lu bytes to file '%s'.\n", + binarySize, + binaryPath); + fclose(fp); + return 1; + } + fclose(fp); + fmt::printf( + "Wrote %lu bytes of binary data to %s.\n", binarySize, binaryPath); + } + + delete data_render_model; + return 0; } diff --git a/src/FBX2glTF.h b/src/FBX2glTF.h index 97a5bd6..5d3f07a 100644 --- a/src/FBX2glTF.h +++ b/src/FBX2glTF.h @@ -76,12 +76,12 @@ struct GltfOptions /** Whether and how to use KHR_draco_mesh_compression to minimize static geometry size. */ struct { bool enabled = false; - int compressionLevel = -1; - int quantBitsPosition = -1; - int quantBitsTexCoord = -1; - int quantBitsNormal = -1; - int quantBitsColor = -1; - int quantBitsGeneric = -1; + int compressionLevel = 7; + int quantBitsPosition = 14; + int quantBitsTexCoord = 10; + int quantBitsNormal = 10; + int quantBitsColor = 8; + int quantBitsGeneric = 8; } draco; /** Whether to include FBX User Properties as 'extras' metadata in glTF nodes. */ @@ -93,7 +93,7 @@ struct GltfOptions bool usePBRMetRough { false }; /** Whether to include lights through the KHR_punctual_lights extension. */ - bool useKHRPunctualLights { true }; + bool useKHRLightsPunctual { true }; /** Whether to include blend shape normals, if present according to the SDK. */ bool useBlendShapeNormals { false }; diff --git a/src/gltf/Raw2Gltf.cpp b/src/gltf/Raw2Gltf.cpp index 612144f..55988e9 100644 --- a/src/gltf/Raw2Gltf.cpp +++ b/src/gltf/Raw2Gltf.cpp @@ -631,7 +631,7 @@ ModelData *Raw2Gltf( // lights // std::vector khrPunctualLights; - if (options.useKHRPunctualLights) { + if (options.useKHRLightsPunctual) { for (int i = 0; i < raw.GetLightCount(); i ++) { const RawLight &light = raw.GetLight(i); LightData::Type type;