Merge remote-tracking branch 'upstream/master'

This commit is contained in:
hhalen 2019-06-25 15:21:48 -07:00
commit 8aebb1eb2a
77 changed files with 1046 additions and 913 deletions

3
.dockerignore Normal file
View File

@ -0,0 +1,3 @@
.dockerignore
Dockerfile
sdk

9
.gitattributes vendored
View File

@ -1,5 +1,14 @@
# FBX SDK
*.a filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.lib filter=lfs diff=lfs merge=lfs -text
# TEST FILES
*.glb filter=lfs diff=lfs merge=lfs -text *.glb filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text *.fbx filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text *.tga filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text

63
.travis.yml Normal file
View File

@ -0,0 +1,63 @@
git:
lfs_skip_smudge: true
matrix:
include:
- os: linux
dist: xenial
env:
- APP_NAME="FBX2glTF-linux-x64"
- CONAN_CONFIG="-s compiler.libcxx=libstdc++11"
- FBXSDK_TARBALL="https://github.com/zellski/FBXSDK-Linux/archive/2019.2.tar.gz"
- TAR_WILDCARDS="--wildcards"
- os: osx
osx_image: xcode10.2
env:
- APP_NAME="FBX2glTF-darwin-x64"
- CONAN_CONFIG="-s compiler=apple-clang -s compiler.version=10.0 -s compiler.libcxx=libc++"
- FBXSDK_TARBALL="https://github.com/zellski/FBXSDK-Darwin/archive/2019.2.tar.gz"
- TAR_WILDCARDS=""
compiler: gcc
language: generic
#disabled for now
#cache:
# directories:
# - ${HOME}/.conan
addons:
apt:
packages: zstd
homebrew:
packages: zstd
install:
- curl -sL "${FBXSDK_TARBALL}" | tar xz --strip-components=1 ${TAR_WILDCARDS} */sdk
- zstd -d -r --rm sdk
- git clone --depth 1 git://github.com/astropy/ci-helpers.git
- source ci-helpers/travis/setup_conda.sh
- conda config --set always_yes yes
- conda info -a
- conda create -n travis_env python=3.7 pip
- conda activate travis_env
- pip install conan
- conan user
- conan remote add --force bincrafters https://api.bintray.com/conan/bincrafters/public-conan
script:
- conan install . -i build -s build_type=Release ${CONAN_CONFIG}
- conan build . -bf build
- mv build/FBX2glTF build/${APP_NAME}
notifications:
webhooks:
- "https://code.facebook.com/travis/webhook/"
deploy:
provider: releases
api_key:
secure: V9CTmZKM7yvsT/WCesJ/tLTuapSf0oIp73zyZrwID7zQtXaq1QJSna4tWM2T0qeZIYhniH1/mqEr2jZVW1txmYn9ZxUMH1Nmp9zzOGl/q+JlRrJUi6HRUWWhCMz003L90whngyOcGI+T7rHtcVcby4owVsze15SrQqqV74NXI8DYNIbNgQR1Nwmqsrg0QirFPEBaIKDAiKonnRDWKPy2P8vqnN9fLhj00uHLwuvahlKAnWFEbNnFbiRScKifB+Mlo6Pf6r64iikrxS2jBxAgSsvPLkuemWLmaHTeGbJMM82aqh5vGSvgYcExvZi+0RdXeIcBdv/jaivM/xge4aZ+4P+IJoX32ZNCcYFMsqES+a6TztkywMs2k1r5gV6LrTjeXJsINSW+BDFdmrwmkudETc4gelQgkMmEkdCwFHENtZGl65z8HJDQKcu9F8NQlhNU7Z5rwQNLmYccvktSDhwbFSG5eq2kFFfcbVx3ovvn1voRTNnyhhVD2ZnLepSQInAVkZbaLkE90bQ+t9icf8uDdHDn17zOQaAZuecPlSW1y4XUCJnZCi0JPLhdSmQYiF60LHYI6xDneC8pmIz8kCUbk921zu8bJBy7zKHmfHy2vqNlPKuRULRIs5QzY31jf2PVZHzB5zX3KSqx9Dd+3DtgbLX2HLaZnANbkQc0rr1X2kk=
file: build/${APP_NAME}
skip_cleanup: true
on:
repo: facebookincubator/FBX2glTF
tags: true

View File

@ -1,10 +1,15 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project(FBX2glTF) project(FBX2glTF)
set(typical_usage_str
"Example usage:\n\
> mkdir -p build_debug\n\
> conan install . -i build_debug -s build_type=Debug -e FBXSDK_SDKS=/home/zell/FBXSDK\n\
> conan build . -bf build_debug")
if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR message(FATAL_ERROR
"Building from within the source tree is not supported.\n" "Building from within the source tree is not supported! ${typical_usage_str}")
"Hint: mkdir -p build; cmake -H. -Bbuild; make -Cbuild\n")
endif () endif ()
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
@ -28,35 +33,27 @@ if (NOT FBXSDK_FOUND)
) )
endif() endif()
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan_paths.cmake")
message(FATAL_ERROR
"The Conan package manager must run ('install') first. ${typical_usage_str}")
endif()
include("${CMAKE_BINARY_DIR}/conan_paths.cmake")
set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(Iconv QUIET)
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_BINARY_DIR}")
# stuff we get from Conan
find_package(boost_filesystem MODULE REQUIRED)
find_package(boost_optional MODULE REQUIRED)
find_package(libxml2 MODULE REQUIRED)
find_package(zlib MODULE REQUIRED)
find_package(fmt MODULE REQUIRED)
# create a compilation database for e.g. clang-tidy # create a compilation database for e.g. clang-tidy
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if (WIN32)
# this will suffice for now; don't really care about 32-bit
set(LIBXML2_INCLUDE_DIRS ${FBXSDK_INCLUDE_DIR})
set(LIBXML2_LIBRARIES ${FBXSDK_ROOT}/lib/vs2017/x64/release/libxml2-mt.lib)
set(LIBXML2_LIBRARIES_DEBUG ${FBXSDK_ROOT}/lib/vs2017/x64/debug/libxml2-mt.lib)
if (NOT LIBXML2_INCLUDE_DIRS OR NOT LIBXML2_LIBRARIES)
message(FATAL_ERROR "Cannot find libxml2.lib in the expected location.")
endif()
set(ZLIB_INCLUDE_DIRS ${FBXSDK_INCLUDE_DIR})
set(ZLIB_LIBRARIES ${FBXSDK_ROOT}/lib/vs2017/x64/release/zlib-mt.lib)
set(ZLIB_LIBRARIES_DEBUG ${FBXSDK_ROOT}/lib/vs2017/x64/debug/zlib-mt.lib)
if (NOT ZLIB_LIBRARIES)
message(FATAL_ERROR "Cannot find zlib.lib in the expected location.")
endif()
else()
find_package(LibXml2 REQUIRED)
find_package(ZLIB REQUIRED)
endif()
# DRACO # DRACO
ExternalProject_Add(Draco ExternalProject_Add(Draco
GIT_REPOSITORY https://github.com/google/draco GIT_REPOSITORY https://github.com/google/draco
@ -110,22 +107,6 @@ ExternalProject_Add(CPPCodec
) )
set(CPPCODEC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/cppcodec/src/CPPCodec") set(CPPCODEC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/cppcodec/src/CPPCodec")
# FMT
ExternalProject_Add(Fmt
PREFIX fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG 4.0.0
CMAKE_CACHE_ARGS "-DFMT_DOC:BOOL=OFF" "-DFMT_INSTALL:BOOL=ON" "-DFMT_TEST:BOOL=OFF"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
)
set(FMT_INCLUDE_DIR "${CMAKE_BINARY_DIR}/fmt/include")
if (WIN32)
set(FMT_LIB "${CMAKE_BINARY_DIR}/fmt/lib/fmt.lib")
else()
set(FMT_LIB "${CMAKE_BINARY_DIR}/fmt/lib/libfmt.a")
endif()
if (APPLE) if (APPLE)
find_library(CF_FRAMEWORK CoreFoundation) find_library(CF_FRAMEWORK CoreFoundation)
message("CoreFoundation Framework: ${CF_FRAMEWORK}") message("CoreFoundation Framework: ${CF_FRAMEWORK}")
@ -190,7 +171,6 @@ set(LIB_SOURCE_FILES
src/utils/File_Utils.hpp src/utils/File_Utils.hpp
src/utils/Image_Utils.cpp src/utils/Image_Utils.cpp
src/utils/Image_Utils.hpp src/utils/Image_Utils.hpp
src/utils/String_Utils.cpp
src/utils/String_Utils.hpp src/utils/String_Utils.hpp
third_party/CLI11/CLI11.hpp third_party/CLI11/CLI11.hpp
) )
@ -205,7 +185,6 @@ add_dependencies(libFBX2glTF
MathFu MathFu
FiFoMap FiFoMap
CPPCodec CPPCodec
Fmt
) )
if (NOT MSVC) if (NOT MSVC)
@ -222,51 +201,40 @@ endif()
target_link_libraries(libFBX2glTF target_link_libraries(libFBX2glTF
${FRAMEWORKS} ${FRAMEWORKS}
boost_filesystem::boost_filesystem
boost_optional::boost_optional
${DRACO_LIB} ${DRACO_LIB}
${FMT_LIB}
optimized ${FBXSDK_LIBRARY} optimized ${FBXSDK_LIBRARY}
debug ${FBXSDK_LIBRARY_DEBUG} debug ${FBXSDK_LIBRARY_DEBUG}
fmt::fmt
libxml2::libxml2
zlib::zlib
${CMAKE_DL_LIBS} ${CMAKE_DL_LIBS}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if (WIN32) if (APPLE)
target_link_libraries(libFBX2glTF find_package(Iconv MODULE REQUIRED)
optimized ${LIBXML2_LIBRARIES} target_link_libraries(libFBX2glTF Iconv)
debug ${LIBXML2_LIBRARIES_DEBUG}
optimized ${ZLIB_LIBRARIES}
debug ${ZLIB_LIBRARIES_DEBUG}
)
else() else()
target_link_libraries(libFBX2glTF find_package(libiconv MODULE REQUIRED)
${LIBXML2_LIBRARIES} target_link_libraries(libFBX2glTF libiconv::libiconv)
${ZLIB_LIBRARIES}
)
endif() endif()
target_include_directories(libFBX2glTF SYSTEM PUBLIC target_include_directories(libFBX2glTF PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src
"third_party/stb"
"third_party/json"
) )
target_include_directories(libFBX2glTF SYSTEM PUBLIC target_include_directories(libFBX2glTF SYSTEM PUBLIC
Iconv::Iconv "third_party/stb"
"third_party/json"
${FBXSDK_INCLUDE_DIR} ${FBXSDK_INCLUDE_DIR}
${DRACO_INCLUDE_DIR} ${DRACO_INCLUDE_DIR}
${MATHFU_INCLUDE_DIRS} ${MATHFU_INCLUDE_DIRS}
${FIFO_MAP_INCLUDE_DIR} ${FIFO_MAP_INCLUDE_DIR}
${CPPCODEC_INCLUDE_DIR} ${CPPCODEC_INCLUDE_DIR}
${FMT_INCLUDE_DIR}
${LIBXML2_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
) )
if (Iconv_FOUND)
target_link_libraries(libFBX2glTF Iconv::Iconv)
target_include_directories(libFBX2glTF SYSTEM PUBLIC Iconv::Iconv)
endif()
target_include_directories(appFBX2glTF PUBLIC target_include_directories(appFBX2glTF PUBLIC
"third_party/CLI11" "third_party/CLI11"
) )

29
Dockerfile Normal file
View File

@ -0,0 +1,29 @@
FROM ubuntu:16.04
RUN apt-get update && \
apt-get install -y software-properties-common && \
add-apt-repository ppa:jonathonf/python-3.6 && \
add-apt-repository ppa:git-core/ppa && \
apt-get update && \
apt-get install -y python3.6 curl build-essential cmake libxml2-dev zlib1g-dev git && \
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py && \
pip install conan && \
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
# Install FBX SDK
RUN mkdir -p /fbx2gltf/sdk/Linux/2019.2 && \
curl -L https://www.autodesk.com/content/dam/autodesk/www/adn/fbx/20192/fbx20192_fbxsdk_linux.tar.gz -o fbx20192_fbxsdk_linux.tar.gz && \
tar -xvf fbx20192_fbxsdk_linux.tar.gz && \
echo "yes\nn" | ./fbx20192_fbxsdk_linux /fbx2gltf/sdk/Linux/2019.2 && \
rm -rf /fbxsdktemp
COPY . /fbx2gltf
WORKDIR /fbx2gltf
# Build and install
RUN conan install . -i docker-build -s build_type=Release -s compiler=gcc -s compiler.version=5 -s compiler.libcxx=libstdc++11 && \
conan build -bf docker-build . && \
cp docker-build/FBX2glTF /usr/bin && \
cd / && \
rm -rf /fbx2gltf /root/.conan

View File

@ -24,28 +24,23 @@ else()
endif() endif()
if (NOT DEFINED FBXSDK_VERSION) if (NOT DEFINED FBXSDK_VERSION)
set(FBXSDK_VERSION "2018.1.1") set(FBXSDK_VERSION "2019.2")
endif() endif()
set(_fbxsdk_vstudio_version "vs2017") set(_fbxsdk_vstudio_version "vs2017")
message("Looking for FBX SDK version: ${FBXSDK_VERSION}") message("Looking for FBX SDK version: ${FBXSDK_VERSION}")
if (DEFINED FBXSDK_SDKS) if (NOT DEFINED FBXSDK_SDKS)
get_filename_component(FBXSDK_SDKS_ABS ${FBXSDK_SDKS} ABSOLUTE) set(FBXSDK_SDKS "${CMAKE_CURRENT_SOURCE_DIR}/sdk")
set(FBXSDK_APPLE_ROOT "${FBXSDK_SDKS_ABS}/Darwin/${FBXSDK_VERSION}")
set(FBXSDK_LINUX_ROOT "${FBXSDK_SDKS_ABS}/Linux/${FBXSDK_VERSION}")
set(FBXSDK_WINDOWS_ROOT "${FBXSDK_SDKS_ABS}/Windows/${FBXSDK_VERSION}")
else()
set(FBXSDK_APPLE_ROOT
"/Applications/Autodesk/FBX SDK/${FBXSDK_VERSION}")
set(FBXSDK_LINUX_ROOT
"/usr")
set(FBXSDK_WINDOWS_ROOT
"C:/Program Files/Autodesk/FBX/FBX SDK/${FBXSDK_VERSION}")
endif() endif()
get_filename_component(FBXSDK_SDKS_ABS ${FBXSDK_SDKS} ABSOLUTE)
set(FBXSDK_APPLE_ROOT "${FBXSDK_SDKS_ABS}/Darwin/${FBXSDK_VERSION}")
set(FBXSDK_LINUX_ROOT "${FBXSDK_SDKS_ABS}/Linux/${FBXSDK_VERSION}")
set(FBXSDK_WINDOWS_ROOT "${FBXSDK_SDKS_ABS}/Windows/${FBXSDK_VERSION}")
if (APPLE) if (APPLE)
set(_fbxsdk_root "${FBXSDK_APPLE_ROOT}") set(_fbxsdk_root "${FBXSDK_APPLE_ROOT}")
set(_fbxsdk_libdir_debug "lib/clang/debug") set(_fbxsdk_libdir_debug "lib/clang/debug")

View File

@ -2,7 +2,7 @@ BSD License
For FBX2glTF software For FBX2glTF software
Copyright (c) 2014-present, Facebook, Inc. All rights reserved. Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:

33
PATENTS
View File

@ -1,33 +0,0 @@
Additional Grant of Patent Rights Version 2
"Software" means the FBX2glTF software contributed by Facebook, Inc.
Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
(subject to the termination provision below) license under any Necessary
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
transfer the Software. For avoidance of doubt, no license is granted under
Facebooks rights in any patent claims that are infringed by (i) modifications
to the Software made by you or any third party or (ii) the Software in
combination with any software or other technology.
The license granted hereunder will terminate, automatically and without notice,
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
directly or indirectly, or take a direct financial interest in, any Patent
Assertion: (i) against Facebook or any of its subsidiaries or corporate
affiliates, (ii) against any party if such Patent Assertion arises in whole or
in part from any software, technology, product or service of Facebook or any of
its subsidiaries or corporate affiliates, or (iii) against any party relating
to the Software. Notwithstanding the foregoing, if Facebook or any of its
subsidiaries or corporate affiliates files a lawsuit alleging patent
infringement against you in the first instance, and you respond by filing a
patent infringement counterclaim in that lawsuit against that party that is
unrelated to the Software, the license granted hereunder will not terminate
under section (i) of this paragraph due to such counterclaim.
A "Necessary Claim" is a claim of a patent owned by Facebook that is
necessarily infringed by the Software standing alone.
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
or contributory infringement or inducement to infringe any patent, including a
cross-claim or counterclaim.

156
README.md
View File

@ -1,4 +1,5 @@
# FBX2glTF # FBX2glTF
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
This is a command line tool for converting 3D model assets on Autodesk's This is a command line tool for converting 3D model assets on Autodesk's
venerable [FBX](https://www.autodesk.com/products/fbx/overview) format to venerable [FBX](https://www.autodesk.com/products/fbx/overview) format to
@ -8,7 +9,10 @@ a modern runtime asset delivery format.
Precompiled binaries releases for Windows, Mac OS X and Linux may be Precompiled binaries releases for Windows, Mac OS X and Linux may be
found [here](https://github.com/facebookincubator/FBX2glTF/releases). found [here](https://github.com/facebookincubator/FBX2glTF/releases).
Bleeding-edge binaries are periodically built and publicly available [here](https://dev.azure.com/parwinzell/FBX2glTF/): click a build (usually the most recent), then the 'Artefacts' dropdown in the upper right. Bleeding-edge binaries for Windows may be found [here](https://ci.appveyor.com/project/Facebook/fbx2gltf/build/artifacts). Linux and Mac OS X to come; meanwhile, you can [build your own](#building-it-on-your-own).
[![Build Status](https://travis-ci.com/facebookincubator/FBX2glTF.svg?branch=master)](https://travis-ci.com/facebookincubator/FBX2glTF)
[![Build status](https://ci.appveyor.com/api/projects/status/5mq4vbc44vmyec4w?svg=true)](https://ci.appveyor.com/project/Facebook/fbx2gltf)
## Running ## Running
@ -28,47 +32,66 @@ Or perhaps, as part of a more complex pipeline:
You can always run the binary with --help to see what options it takes: You can always run the binary with --help to see what options it takes:
``` ```
FBX2glTF 2.0: Generate a glTF 2.0 representation of an FBX model. FBX2glTF 0.9.6: Generate a glTF 2.0 representation of an FBX model.
Usage: Usage: FBX2glTF [OPTIONS] [FBX Model]
FBX2glTF [OPTION...] [<FBX File>]
-i, --input arg The FBX model to convert. Positionals:
-o, --output arg Where to generate the output, without suffix. FBX Model FILE The FBX model to convert.
-e, --embed Inline buffers as data:// URIs within
generated non-binary glTF. Options:
-b, --binary Output a single binary format .glb file. -h,--help Print this help message and exit
-d, --draco Apply Draco mesh compression to geometries. -v,--verbose Include blend shape tangents, if reported present by the FBX SDK.
--flip-u Flip all U texture coordinates. -V,--version
--flip-v Flip all V texture coordinates (default -i,--input FILE The FBX model to convert.
behaviour!) -o,--output TEXT Where to generate the output, without suffix.
--no-flip-v Suppress the default flipping of V texture -e,--embed Inline buffers as data:// URIs within generated non-binary glTF.
coordinates -b,--binary Output a single binary format .glb file.
--pbr-metallic-roughness Try to glean glTF 2.0 native PBR attributes --long-indices (never|auto|always)
from the FBX. Whether to use 32-bit indices.
--khr-materials-unlit Use KHR_materials_unlit extension to specify --compute-normals (never|broken|missing|always)
Unlit shader. When to compute vertex normals from mesh geometry.
--blend-shape-normals Include blend shape normals, if reported --anim-framerate (bake24|bake30|bake60)
present by the FBX SDK. Select baked animation framerate.
--blend-shape-tangents Include blend shape tangents, if reported --flip-u Flip all U texture coordinates.
present by the FBX SDK. --no-flip-u Don't flip U texture coordinates.
--long-indices arg Whether to use 32-bit indices --flip-v Flip all V texture coordinates.
(never|auto|always). --no-flip-v Don't flip V texture coordinates.
--compute-normals arg When to compute normals for vertices --no-khr-lights-punctual Don't use KHR_lights_punctual extension to export FBX lights.
(never|broken|missing|always). --user-properties Transcribe FBX User Properties into glTF node and material 'extras'.
-k, --keep-attribute arg Used repeatedly to build a limiting set of --blend-shape-normals Include blend shape normals, if reported present by the FBX SDK.
vertex attributes to keep. --blend-shape-tangents Include blend shape tangents, if reported present by the FBX SDK.
-v, --verbose Enable verbose output. -k,--keep-attribute (position|normal|tangent|binormial|color|uv0|uv1|auto) ...
-h, --help Show this help. Used repeatedly to build a limiting set of vertex attributes to keep.
-V, --version Display the current program version.
Materials:
--pbr-metallic-roughness Try to glean glTF 2.0 native PBR attributes from the FBX.
--khr-materials-unlit Use KHR_materials_unlit extension to request an unlit shader.
Draco:
-d,--draco Apply Draco mesh compression to geometries.
--draco-compression-level INT in [0 - 10]=7
The compression level to tune Draco to.
--draco-bits-for-position INT in [1 - 32]=14
How many bits to quantize position to.
--draco-bits-for-uv INT in [1 - 32]=10
How many bits to quantize UV coordinates to.
--draco-bits-for-normals INT in [1 - 32]=10
How many bits to quantize nornals to.
--draco-bits-for-colors INT in [1 - 32]=8
How many bits to quantize colors to.
--draco-bits-for-other INT in [1 - 32]=8
How many bits to quantize all other vertex attributes to.
``` ```
Some of these switches are not obvious: Some of these switches are not obvious:
- `--embed` is the way to get a single distributable file without using the - `--embed` is the way to get a single distributable file without using the
binary format. It encodes the binary buffer(s) as a single enormous binary format. It encodes the binary buffer(s) as a single base64-encoded
base64-encoded `data://` URI. This is a very slow and space-consuming way to `data://` URI. This is a very slow and space-consuming way to accomplish what
accomplish what the binary format was invented to do simply and efficiently, the binary format was invented to do simply and efficiently, but it can be
but it can be useful e.g. for loaders that don't understand the .glb format. useful e.g. for loaders that don't understand the .glb format.
- `--flip-u` and `--flip-v`, when enabled, will apply a `x -> (1.0 - x)` - `--flip-u` and `--flip-v`, when enabled, will apply a `x -> (1.0 - x)`
function to all `u` or `v` texture coordinates respectively. The `u` version function to all `u` or `v` texture coordinates respectively. The `u` version
is perhaps not commonly used, but flipping `v` is **the default behaviour**. is perhaps not commonly used, but flipping `v` is **the default behaviour**.
@ -104,49 +127,70 @@ Some of these switches are not obvious:
## Building it on your own ## Building it on your own
This build process has been tested on Linux, Mac OS X and Windows. It requires
CMake 3.5+ and a reasonably C++11 compliant toolchain.
We currently depend on the open source projects We currently depend on the open source projects
[Draco](https://github.com/google/draco), [Draco](https://github.com/google/draco),
[MathFu](https://github.com/google/mathfu), [MathFu](https://github.com/google/mathfu),
[Json](https://github.com/nlohmann/json), [Json](https://github.com/nlohmann/json),
[cppcodec](https://github.com/tplgy/cppcodec), [cppcodec](https://github.com/tplgy/cppcodec),
[cxxopts](https://github.com/jarro2783/cxxopts), [CLI11](https://github.com/CLIUtils/CLI11),
[stb](https://github.com/nothings/stb),
and [fmt](https://github.com/fmtlib/fmt); and [fmt](https://github.com/fmtlib/fmt);
all of which are automatically downloaded, configured and built. all of which are automatically downloaded and/or built.
You must manually download and install the **At present, only version 2019.2 of the FBX SDK is supported**. The
[Autodesk FBX SDK](https://www.autodesk.com/products/fbx/overview) and
accept its license agreement.
**At present, only version 2018.1.1 of the FBX SDK is supported**. The
build system will not successfully locate any other version. build system will not successfully locate any other version.
### Linux and MacOS X ### Linux and MacOS X
Compilation on Unix machines should be as simple as: Your development environment will need to have:
- build essentials (gcc for Linux, clang for Mac)
- cmake
- python 3.* and associated pip3/pip command
- zstd
Then, compilation on Unix machines will look something like:
``` ```
> cd <FBX2glTF directory> # Determine SDK location & build settings for Linux vs (Recent) Mac OS X
> cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release > if [[ "$OSTYPE" == "darwin" ]]; then
> make -Cbuild -j4 install export CONAN_CONFIG="-s compiler=apple-clang -s compiler.version=10.0 -s compiler.libcxx=libc++"
export FBXSDK_TARBALL="https://github.com/zellski/FBXSDK-Darwin/archive/2019.2.tar.gz"
else
export CONAN_CONFIG="-s compiler.libcxx=libstdc++11"
export FBXSDK_TARBALL="https://github.com/zellski/FBXSDK-Linux/archive/2019.2.tar.gz"
fi
# Fetch Project
> GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/facebookincubator/FBX2glTF.git
> cd FBX2glTF
# Fetch and unpack FBX SDK
> curl -sL "${FBXSDK_TARBALL}" | tar xz --strip-components=1 --wildcards */sdk
# Then decompress the contents
> zstd -d -r --rm sdk
# Install and configure Conan, if needed
> pip3 install conan # or sometimes just "pip"; you may need to install Python/PIP
> conan remote add --force bincrafters https://api.bintray.com/conan/bincrafters/public-conan
# Initialize & run build
> conan install . -i build -s build_type=Release ${CONAN_CONFIG}
> conan build . -bf build
``` ```
If all goes well, you will end up with a statically linked executable. If all goes well, you will end up with a statically linked executable in `./build/FBX2glTF`.
### Windows ### Windows
<TODO> the below is out of date
Windows users may [download](https://cmake.org/download) CMake for Windows, Windows users may [download](https://cmake.org/download) CMake for Windows,
install it and [run it](https://cmake.org/runningcmake/) on the FBX2glTF install it and [run it](https://cmake.org/runningcmake/) on the FBX2glTF
checkout (choose a build directory distinct from the source). checkout (choose a build directory distinct from the source).
As part of this process, you will be asked to choose which generator As part of this process, you will be asked to choose which generator
to use. **At present, only Visual Studio 2017 is supported.** Older to use. **At present, only Visual Studio 2017 or 2019 is supported.** Older
versions of the IDE are unlikely to successfully build the tool. versions of the IDE are unlikely to successfully build the tool.
*(MinGW support is plausible. The difficulty is linking statically against the
FBX SDK .lib file. Contributions welcome.)*
Note that the `CMAKE_BUILD_TYPE` variable from the Unix Makefile system is Note that the `CMAKE_BUILD_TYPE` variable from the Unix Makefile system is
entirely ignored here; it is when you open the generated solution that entirely ignored here; it is when you open the generated solution that
you will be choose one of the canonical build types — *Debug*, you will be choose one of the canonical build types — *Debug*,
@ -272,4 +316,4 @@ TODO items can be found
- Amanda Watson - Amanda Watson
## License ## License
FBX2glTF is BSD-licensed. We also provide an additional patent grant. FBX2glTF is licensed under the [3-clause BSD license](LICENSE).

58
appveyor.yml Normal file
View File

@ -0,0 +1,58 @@
# version format
version: 1.0.{build}
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
PYTHON: "C:\\Python36-x64"
FBXSDK_SDKS: sdk
stack: python %PYTHON%
#temporarily disabled
#cache:
# - C:\Users\appveyor\.conan\data -> appveyor.yml, conanfile.py
init:
- git config --global filter.lfs.required false
- git config --global filter.lfs.smudge "git-lfs smudge --skip %f"
- git config --global filter.lfs.process "git-lfs filter-process --skip"
install:
- cinst zstandard
- ps: Start-FileDownload 'https://github.com/zellski/FBXSDK-Windows/archive/2019.2.tar.gz'
- 7z e 2019.2.tar.gz
- 7z x 2019.2.tar
- ps: move -v .\FBXSDK-Windows-2019.2\sdk\ .
- ps: zstd -d -r --rm sdk
- cmd: echo "Downloading conan..."
- cmd: set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
- cmd: python --version
- cmd: python -m pip install --upgrade pip
- cmd: pip install conan
- cmd: conan user # Create the conan data directory
- cmd: conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
- cmd: conan --version
build_script:
- cmd: conan install . -i build -s build_type=Release -s compiler="Visual Studio" -s compiler.version=15
- cmd: conan build -bf build .
- cmd: move build\Release\FBX2glTF.exe build\Release\FBX2glTF-windows-x64.exe
test: off
artifacts:
- path: build/Release/FBX2glTF-windows-x64.exe
deploy:
tag: $(APPVEYOR_REPO_TAG_NAME)
description: ''
provider: GitHub
auth_token:
secure: OSvhQP0O9uaH+OFOJpbGiiBMRTOJ+H/VJHqVBhq39RNDnOfUEr/yjJNKh3JSdNqj
artifact: build/Release/FBX2glTF-windows-x64.exe
draft: true
prerelease: true
on:
branch: master
APPVEYOR_REPO_TAG: true

101
azure-pipelines.yml Normal file
View File

@ -0,0 +1,101 @@
# C/C++ with GCC
# Build your C/C++ project with GCC using make.
# Add steps that publish test results, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/c-cpp/gcc
jobs:
- job: Linux
pool:
vmImage: 'Ubuntu 16.04'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
architecture: 'x64'
- script: python -m pip install --upgrade pip setuptools wheel
displayName: 'Install Python tools'
- script: |
pip install conan
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
displayName: 'Install & configure Conan'
- script: |
conan install . -i build -s build_type=Release -e FBXSDK_SDKS=sdk
displayName: 'Resolve binary dependencies and build CMake files.'
- script: |
conan build -bf build .
mv build/FBX2glTF build/FBX2glTF-linux-x64
displayName: 'Build FBX2glTF'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: 'build/FBX2glTF-linux-x64'
artifactName: 'binaries'
- job: Mac
pool:
vmImage: 'macOS-10.14'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
architecture: 'x64'
- script: python -m pip install --upgrade pip setuptools wheel
displayName: 'Install Python tools'
- script: |
pip install conan
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
displayName: 'Install Conan'
- script: |
conan install . -i build -s compiler=apple-clang -s compiler=apple-clang -s compiler.version=10.0 -s compiler.libcxx=libc++ -s build_type=Release -e FBXSDK_SDKS=sdk
displayName: 'Resolve binary dependencies and build CMake files.'
- script: |
conan build -bf build .
mv build/FBX2glTF build/FBX2glTF-darwin-x64
displayName: 'Build FBX2glTF'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: 'build/FBX2glTF-darwin-x64'
artifactName: 'binaries'
- job: Windows
pool:
vmImage: 'vs2017-win2016'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
architecture: 'x64'
- script: python -m pip install --upgrade pip setuptools wheel
displayName: 'Install Python tools'
- script: |
pip install conan
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
displayName: 'Install Conan'
- script: |
conan install . -i build -s build_type=Release -e FBXSDK_SDKS=sdk
displayName: 'Resolve binary dependencies and build CMake files.'
- script: |
conan build -bf build .
move build\Release\FBX2glTF.exe build\Release\FBX2glTF-windows-x64.exe
displayName: 'Build FBX2glTF'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: 'build/Release/FBX2glTF-windows-x64.exe'
artifactName: 'binaries'

33
conanfile.py Normal file
View File

@ -0,0 +1,33 @@
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
#
import os
from conans import ConanFile, CMake
class FBX2glTFConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
requires = (
("boost_filesystem/1.69.0@bincrafters/stable"),
("libiconv/1.15@bincrafters/stable"),
("zlib/1.2.11@conan/stable"),
("libxml2/2.9.9@bincrafters/stable"),
("fmt/5.3.0@bincrafters/stable"),
)
generators = "cmake_find_package", "cmake_paths"
def configure(self):
if (
self.settings.compiler == "gcc"
and self.settings.compiler.libcxx == "libstdc++"
):
raise Exception(
"Rerun 'conan install' with argument: '-s compiler.libcxx=libstdc++11'"
)
def build(self):
cmake = CMake(self)
cmake.definitions["FBXSDK_SDKS"] = os.getenv("FBXSDK_SDKS", "sdk")
cmake.configure()
cmake.build()

5
docker-compose.yaml Normal file
View File

@ -0,0 +1,5 @@
version: '3.7'
services:
fbx2gltf:
build:
context: .

View File

@ -2,7 +2,7 @@ BSD License
For FBX2glTF software For FBX2glTF software
Copyright (c) 2014-present, Facebook, Inc. All rights reserved. Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:

View File

@ -1,33 +0,0 @@
Additional Grant of Patent Rights Version 2
"Software" means the FBX2glTF software contributed by Facebook, Inc.
Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
(subject to the termination provision below) license under any Necessary
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
transfer the Software. For avoidance of doubt, no license is granted under
Facebooks rights in any patent claims that are infringed by (i) modifications
to the Software made by you or any third party or (ii) the Software in
combination with any software or other technology.
The license granted hereunder will terminate, automatically and without notice,
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
directly or indirectly, or take a direct financial interest in, any Patent
Assertion: (i) against Facebook or any of its subsidiaries or corporate
affiliates, (ii) against any party if such Patent Assertion arises in whole or
in part from any software, technology, product or service of Facebook or any of
its subsidiaries or corporate affiliates, or (iii) against any party relating
to the Software. Notwithstanding the foregoing, if Facebook or any of its
subsidiaries or corporate affiliates files a lawsuit alleging patent
infringement against you in the first instance, and you respond by filing a
patent infringement counterclaim in that lawsuit against that party that is
unrelated to the Software, the license granted hereunder will not terminate
under section (i) of this paragraph due to such counterclaim.
A "Necessary Claim" is a claim of a patent owned by Facebook that is
necessarily infringed by the Software standing alone.
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
or contributory infringement or inducement to infringe any patent, including a
cross-claim or counterclaim.

View File

@ -1,5 +1,8 @@
# FBX2glTF # FBX2glTF
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
This is a command line tool for converting 3D model assets on the This is a command line tool for converting 3D model assets on the
well-established [FBX](https://www.autodesk.com/products/fbx/overview) format to well-established [FBX](https://www.autodesk.com/products/fbx/overview) format to
[glTF 2.0](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0), [glTF 2.0](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0),
@ -53,6 +56,9 @@ The home of this tool is [here](https://github.com/facebookincubator/FBX2glTF).
# Legal # Legal
FBX2glTF is licensed under the [3-clause BSD license](LICENSE).
```
This software contains Autodesk® FBX® code developed by Autodesk, Inc. Copyright This software contains Autodesk® FBX® code developed by Autodesk, Inc. Copyright
2017 Autodesk, Inc. All rights, reserved. Such code is provided “as is” and 2017 Autodesk, Inc. All rights, reserved. Such code is provided “as is” and
Autodesk, Inc. disclaims any and all warranties, whether express or implied, Autodesk, Inc. disclaims any and all warranties, whether express or implied,
@ -64,4 +70,4 @@ of substitute goods or services; loss of use, data, or profits; or business
interruption) however caused and on any theory of liability, whether in interruption) however caused and on any theory of liability, whether in
contract, strict liability, or tort (including negligence or otherwise) arising contract, strict liability, or tort (including negligence or otherwise) arising
in any way out of such code. in any way out of such code.
```

View File

@ -19,7 +19,6 @@
"homepage": "https://github.com/facebookincubator/FBX2glTF", "homepage": "https://github.com/facebookincubator/FBX2glTF",
"files": [ "files": [
"LICENSE", "LICENSE",
"PATENTS",
"README.md", "README.md",
"bin", "bin",
"index.js" "index.js"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include <fstream> #include <fstream>
@ -13,13 +12,6 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#if defined(__unix__) || defined(__APPLE__)
#include <sys/stat.h>
#define _stricmp strcasecmp
#endif
#include <CLI11.hpp> #include <CLI11.hpp>
#include "FBX2glTF.h" #include "FBX2glTF.h"
@ -103,6 +95,26 @@ int main(int argc, char* argv[]) {
"When to compute vertex normals from mesh geometry.") "When to compute vertex normals from mesh geometry.")
->type_name("(never|broken|missing|always)"); ->type_name("(never|broken|missing|always)");
app.add_option(
"--anim-framerate",
[&](std::vector<std::string> choices) -> bool {
for (const std::string choice : choices) {
if (choice == "bake24") {
gltfOptions.animationFramerate = AnimationFramerateOptions::BAKE24;
} else if (choice == "bake30") {
gltfOptions.animationFramerate = AnimationFramerateOptions::BAKE30;
} else if (choice == "bake60") {
gltfOptions.animationFramerate = AnimationFramerateOptions::BAKE60;
} else {
fmt::printf("Unknown --anim-framerate: %s\n", choice);
throw CLI::RuntimeError(1);
}
}
return true;
},
"Select baked animation framerate.")
->type_name("(bake24|bake30|bake60)");
const auto opt_flip_u = app.add_flag("--flip-u", "Flip all U texture coordinates."); const auto opt_flip_u = app.add_flag("--flip-u", "Flip all U texture coordinates.");
const auto opt_no_flip_u = app.add_flag("--no-flip-u", "Don't flip U texture coordinates."); const auto opt_no_flip_u = app.add_flag("--no-flip-u", "Don't flip U texture coordinates.");
const auto opt_flip_v = app.add_flag("--flip-v", "Flip all V texture coordinates."); const auto opt_flip_v = app.add_flag("--flip-v", "Flip all V texture coordinates.");
@ -284,10 +296,7 @@ int main(int argc, char* argv[]) {
if (outputPath.empty()) { if (outputPath.empty()) {
// if -o is not given, default to the basename of the .fbx // if -o is not given, default to the basename of the .fbx
outputPath = fmt::format( outputPath = "./" + FileUtils::GetFileBase(inputPath);
".{}{}",
(const char)StringUtils::GetPathSeparator(),
StringUtils::GetFileBaseString(inputPath));
} }
// the output folder in .gltf mode, not used for .glb // the output folder in .gltf mode, not used for .glb
std::string outputFolder; std::string outputFolder;
@ -295,14 +304,17 @@ int main(int argc, char* argv[]) {
// the path of the actual .glb or .gltf file // the path of the actual .glb or .gltf file
std::string modelPath; std::string modelPath;
if (gltfOptions.outputBinary) { if (gltfOptions.outputBinary) {
// in binary mode, we write precisely where we're asked const auto& suffix = FileUtils::GetFileSuffix(outputPath);
modelPath = outputPath + ".glb"; // add .glb to output path, unless it already ends in exactly that
if (suffix.has_value() && suffix.value() == "glb") {
modelPath = outputPath;
} else {
modelPath = outputPath + ".glb";
}
} else { } else {
// in gltf mode, we create a folder and write into that // in gltf mode, we create a folder and write into that
outputFolder = outputFolder = fmt::format("{}_out/", outputPath.c_str());
fmt::format("{}_out{}", outputPath.c_str(), (const char)StringUtils::GetPathSeparator()); modelPath = outputFolder + FileUtils::GetFileName(outputPath) + ".gltf";
modelPath = outputFolder + StringUtils::GetFileNameString(outputPath) + ".gltf";
} }
if (!FileUtils::CreatePath(modelPath.c_str())) { if (!FileUtils::CreatePath(modelPath.c_str())) {
fmt::fprintf(stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str()); fmt::fprintf(stderr, "ERROR: Failed to create folder: %s'\n", outputFolder.c_str());
@ -315,7 +327,7 @@ int main(int argc, char* argv[]) {
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Loading FBX File: %s\n", inputPath); fmt::printf("Loading FBX File: %s\n", inputPath);
} }
if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg")) { if (!LoadFBXFile(raw, inputPath, {"png", "jpg", "jpeg"}, gltfOptions)) {
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath); fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
return 1; return 1;
} }

View File

@ -1,17 +1,17 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include <climits>
#include <string> #include <string>
#if defined ( _WIN32 ) #if defined(_WIN32)
// Tell Windows not to define min() and max() macros // Tell Windows not to define min() and max() macros
#define NOMINMAX #define NOMINMAX
#include <Windows.h> #include <Windows.h>
@ -20,20 +20,22 @@
#define FBX2GLTF_VERSION std::string("0.9.6") #define FBX2GLTF_VERSION std::string("0.9.6")
#include <fmt/printf.h> #include <fmt/printf.h>
#include <fbxsdk.h> #include <fbxsdk.h>
#if defined ( _WIN32 ) #if defined(_WIN32)
// this is defined in fbxmath.h // this is defined in fbxmath.h
#undef isnan #undef isnan
#undef snprintf
#endif #endif
#include "mathfu.hpp" #include "mathfu.hpp"
// give all modules access to our tweaked JSON // give all modules access to our tweaked JSON
#include <json.hpp>
#include <fifo_map.hpp> #include <fifo_map.hpp>
#include <json.hpp>
template<class K, class V, class ignore, class A> template <class K, class V, class ignore, class A>
using workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>; using workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
using json = nlohmann::basic_json<workaround_fifo_map>; using json = nlohmann::basic_json<workaround_fifo_map>;
@ -41,70 +43,87 @@ using json = nlohmann::basic_json<workaround_fifo_map>;
extern bool verboseOutput; extern bool verboseOutput;
/** /**
* The variuos situations in which the user may wish for us to (re-)compute normals for our vertices. * Centralises all the laborious downcasting from your OS' 64-bit
*/ * index variables down to the uint32s that glTF is built out of.
*/
inline uint32_t to_uint32(size_t n) {
assert(n < UINT_MAX);
return static_cast<uint32_t>(n);
}
/**
* The variuos situations in which the user may wish for us to (re-)compute normals for our
* vertices.
*/
enum class ComputeNormalsOption { enum class ComputeNormalsOption {
NEVER, // do not ever compute any normals (results in broken glTF for some sources) NEVER, // do not ever compute any normals (results in broken glTF for some sources)
BROKEN, // replace zero-length normals in any mesh that has a normal layer BROKEN, // replace zero-length normals in any mesh that has a normal layer
MISSING, // if a mesh lacks normals, compute them all MISSING, // if a mesh lacks normals, compute them all
ALWAYS // compute a new normal for every vertex, obliterating whatever may have been there before ALWAYS // compute a new normal for every vertex, obliterating whatever may have been there before
}; };
enum class UseLongIndicesOptions { enum class UseLongIndicesOptions {
NEVER, // only ever use 16-bit indices NEVER, // only ever use 16-bit indices
AUTO, // use shorts or longs depending on vertex count AUTO, // use shorts or longs depending on vertex count
ALWAYS, // only ever use 32-bit indices ALWAYS, // only ever use 32-bit indices
};
enum class AnimationFramerateOptions {
BAKE24, // bake animations at 24 fps
BAKE30, // bake animations at 30 fps
BAKE60, // bake animations at 60 fps
}; };
/** /**
* User-supplied options that dictate the nature of the glTF being generated. * User-supplied options that dictate the nature of the glTF being generated.
*/ */
struct GltfOptions struct GltfOptions {
{ /**
/** * If negative, disabled. Otherwise, a bitfield of RawVertexAttributes that
* If negative, disabled. Otherwise, a bitfield of RawVertexAttributes that * specify the largest set of attributes that'll ever be kept for a vertex.
* specify the largest set of attributes that'll ever be kept for a vertex. * The special bit RAW_VERTEX_ATTRIBUTE_AUTO triggers smart mode, where the
* The special bit RAW_VERTEX_ATTRIBUTE_AUTO triggers smart mode, where the * attributes to keep are inferred from which textures are supplied.
* attributes to keep are inferred from which textures are supplied. */
*/ int keepAttribs{-1};
int keepAttribs { -1 }; /** Whether to output a .glb file, the binary format of glTF. */
/** Whether to output a .glb file, the binary format of glTF. */ bool outputBinary{false};
bool outputBinary { false }; /** If non-binary, whether to inline all resources, for a single (large) .glTF file. */
/** If non-binary, whether to inline all resources, for a single (large) .glTF file. */ bool embedResources{false};
bool embedResources { false };
/** Whether and how to use KHR_draco_mesh_compression to minimize static geometry size. */ /** Whether and how to use KHR_draco_mesh_compression to minimize static geometry size. */
struct { struct {
bool enabled = false; bool enabled = false;
int compressionLevel = 7; int compressionLevel = 7;
int quantBitsPosition = 14; int quantBitsPosition = 14;
int quantBitsTexCoord = 10; int quantBitsTexCoord = 10;
int quantBitsNormal = 10; int quantBitsNormal = 10;
int quantBitsColor = 8; int quantBitsColor = 8;
int quantBitsGeneric = 8; int quantBitsGeneric = 8;
} draco; } draco;
/** Whether to include FBX User Properties as 'extras' metadata in glTF nodes. */ /** Whether to include FBX User Properties as 'extras' metadata in glTF nodes. */
bool enableUserProperties { false }; bool enableUserProperties{false};
/** Whether to use KHR_materials_unlit to extend materials definitions. */ /** Whether to use KHR_materials_unlit to extend materials definitions. */
bool useKHRMatUnlit { false }; bool useKHRMatUnlit{false};
/** Whether to populate the pbrMetallicRoughness substruct in materials. */ /** Whether to populate the pbrMetallicRoughness substruct in materials. */
bool usePBRMetRough { false }; bool usePBRMetRough{false};
/** Whether to include lights through the KHR_punctual_lights extension. */ /** Whether to include lights through the KHR_punctual_lights extension. */
bool useKHRLightsPunctual { true }; bool useKHRLightsPunctual{true};
/** Whether to include blend shape normals, if present according to the SDK. */ /** Whether to include blend shape normals, if present according to the SDK. */
bool useBlendShapeNormals { false }; bool useBlendShapeNormals{false};
/** Whether to include blend shape tangents, if present according to the SDK. */ /** Whether to include blend shape tangents, if present according to the SDK. */
bool useBlendShapeTangents { false }; bool useBlendShapeTangents{false};
/** Whether to normalized skinning weights. */ /** Whether to normalized skinning weights. */
bool normalizeSkinningWeights { true }; bool normalizeSkinningWeights { true };
/** Maximum number of bone influences per vertex. */ /** Maximum number of bone influences per vertex. */
int maxSkinningWeights { 4 }; int maxSkinningWeights { 4 };
/** When to compute vertex normals from geometry. */ /** When to compute vertex normals from geometry. */
ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN; ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN;
/** When to use 32-bit indices. */ /** When to use 32-bit indices. */
UseLongIndicesOptions useLongIndices = UseLongIndicesOptions::AUTO; UseLongIndicesOptions useLongIndices = UseLongIndicesOptions::AUTO;
/** Select baked animation framerate. */
AnimationFramerateOptions animationFramerate = AnimationFramerateOptions::BAKE24;
}; };

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "Fbx2Raw.hpp" #include "Fbx2Raw.hpp"
@ -715,8 +714,19 @@ static void ReadNodeHierarchy(
} }
} }
static void ReadAnimations(RawModel& raw, FbxScene* pScene) { static void ReadAnimations(RawModel& raw, FbxScene* pScene, const GltfOptions& options) {
FbxTime::EMode eMode = FbxTime::eFrames24; FbxTime::EMode eMode = FbxTime::eFrames24;
switch (options.animationFramerate) {
case AnimationFramerateOptions::BAKE24:
eMode = FbxTime::eFrames24;
break;
case AnimationFramerateOptions::BAKE30:
eMode = FbxTime::eFrames30;
break;
case AnimationFramerateOptions::BAKE60:
eMode = FbxTime::eFrames60;
break;
}
const double epsilon = 1e-5f; const double epsilon = 1e-5f;
const int animationCount = pScene->GetSrcObjectCount<FbxAnimStack>(); const int animationCount = pScene->GetSrcObjectCount<FbxAnimStack>();
@ -726,24 +736,58 @@ static void ReadAnimations(RawModel& raw, FbxScene* pScene) {
pScene->SetCurrentAnimationStack(pAnimStack); pScene->SetCurrentAnimationStack(pAnimStack);
FbxTakeInfo* takeInfo = pScene->GetTakeInfo(animStackName); /**
if (takeInfo == nullptr) { * Individual animations are often concatenated on the timeline, and the
fmt::printf("Warning:: animation '%s' has no Take information. Skipping.\n", animStackName); * only certain way to identify precisely what interval they occupy is to
// not all animstacks have a take * depth-traverse the entire animation stack, and examine the actual keys.
continue; *
* There is a deprecated concept of an "animation take" which is meant to
* provide precisely this time interval information, but the data is not
* actually derived by the SDK from source-of-truth data structures, but
* rather provided directly by the FBX exporter, and not sanity checked.
*
* Some exporters calculate it correctly. Others do not. In any case, we
* now ignore it completely.
*/
FbxLongLong firstFrameIndex = -1;
FbxLongLong lastFrameIndex = -1;
for (int layerIx = 0; layerIx < pAnimStack->GetMemberCount(); layerIx++) {
FbxAnimLayer* layer = pAnimStack->GetMember<FbxAnimLayer>(layerIx);
for (int nodeIx = 0; nodeIx < layer->GetMemberCount(); nodeIx++) {
auto* node = layer->GetMember<FbxAnimCurveNode>(nodeIx);
FbxTimeSpan nodeTimeSpan;
// Multiple curves per curve node is not even supported by the SDK.
for (int curveIx = 0; curveIx < node->GetCurveCount(0); curveIx++) {
FbxAnimCurve* curve = node->GetCurve(0U, curveIx);
if (curve == nullptr) {
continue;
}
// simply take the interval as first key to last key
int firstKeyIndex = 0;
int lastKeyIndex = std::max(firstKeyIndex, curve->KeyGetCount() - 1);
FbxLongLong firstCurveFrame = curve->KeyGetTime(firstKeyIndex).GetFrameCount(eMode);
FbxLongLong lastCurveFrame = curve->KeyGetTime(lastKeyIndex).GetFrameCount(eMode);
// the final interval is the union of all node curve intervals
if (firstFrameIndex == -1 || firstCurveFrame < firstFrameIndex) {
firstFrameIndex = firstCurveFrame;
}
if (lastFrameIndex == -1 || lastCurveFrame > lastFrameIndex) {
lastFrameIndex = lastCurveFrame;
}
}
}
} }
RawAnimation animation;
animation.name = animStackName;
fmt::printf(
"Animation %s: [%lu - %lu]\n", std::string(animStackName), firstFrameIndex, lastFrameIndex);
if (verboseOutput) { if (verboseOutput) {
fmt::printf("animation %zu: %s (%d%%)", animIx, (const char*)animStackName, 0); fmt::printf("animation %zu: %s (%d%%)", animIx, (const char*)animStackName, 0);
} }
FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
RawAnimation animation;
animation.name = animStackName;
FbxLongLong firstFrameIndex = start.GetFrameCount(eMode);
FbxLongLong lastFrameIndex = end.GetFrameCount(eMode);
for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) { for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) {
FbxTime pTime; FbxTime pTime;
// first frame is always at t = 0.0 // first frame is always at t = 0.0
@ -910,39 +954,61 @@ static void ReadAnimations(RawModel& raw, FbxScene* pScene) {
} }
} }
static std::string GetInferredFileName( static std::string FindFileLoosely(
const std::string& fbxFileName, const std::string& fbxFileName,
const std::string& directory, const std::string& directory,
const std::vector<std::string>& directoryFileList) { const std::vector<std::string>& directoryFileList) {
if (FileUtils::FileExists(fbxFileName)) { if (FileUtils::FileExists(fbxFileName)) {
return fbxFileName; return fbxFileName;
} }
// Get the file name with file extension.
const std::string fileName = // From e.g. C:/Assets/Texture.jpg, extract 'Texture.jpg'
StringUtils::GetFileNameString(StringUtils::GetCleanPathString(fbxFileName)); const std::string fileName = FileUtils::GetFileName(fbxFileName);
// Try to find a match with extension. // Try to find a match with extension.
for (const auto& file : directoryFileList) { for (const auto& file : directoryFileList) {
if (StringUtils::CompareNoCase(fileName, file) == 0) { if (StringUtils::CompareNoCase(fileName, FileUtils::GetFileName(file)) == 0) {
return std::string(directory) + file; return directory + "/" + file;
} }
} }
// Get the file name without file extension. // Get the file name without file extension.
const std::string fileBase = StringUtils::GetFileBaseString(fileName); const std::string fileBase = FileUtils::GetFileBase(fileName);
// Try to find a match without file extension. // Try to find a match that ignores file extension
for (const auto& file : directoryFileList) { for (const auto& file : directoryFileList) {
// If the two extension-less base names match. if (StringUtils::CompareNoCase(fileBase, FileUtils::GetFileBase(file)) == 0) {
if (StringUtils::CompareNoCase(fileBase, StringUtils::GetFileBaseString(file)) == 0) { return directory + "/" + file;
// Return the name with extension of the file in the directory.
return std::string(directory) + file;
} }
} }
return ""; return "";
} }
/**
* Try to locate the best match to the given texture filename, as provided in the FBX,
* possibly searching through the provided folders for a reasonable-looking match.
*
* Returns empty string if no match can be found, else the absolute path of the file.
**/
static std::string FindFbxTexture(
const std::string& textureFileName,
const std::vector<std::string>& folders,
const std::vector<std::vector<std::string>>& folderContents) {
// it might exist exactly as-is on the running machine's filesystem
if (FileUtils::FileExists(textureFileName)) {
return textureFileName;
}
// else look in other designated folders
for (int ii = 0; ii < folders.size(); ii++) {
const auto& fileLocation = FindFileLoosely(textureFileName, folders[ii], folderContents[ii]);
if (!fileLocation.empty()) {
return FileUtils::GetAbsolutePath(fileLocation);
}
}
return "";
}
/* /*
The texture file names inside of the FBX often contain some long author-specific The texture file names inside of the FBX often contain some long author-specific
path with the wrong extensions. For instance, all of the art assets may be PSD path with the wrong extensions. For instance, all of the art assets may be PSD
@ -954,50 +1020,60 @@ static std::string GetInferredFileName(
*/ */
static void FindFbxTextures( static void FindFbxTextures(
FbxScene* pScene, FbxScene* pScene,
const char* fbxFileName, const std::string& fbxFileName,
const char* extensions, const std::set<std::string>& extensions,
std::map<const FbxTexture*, FbxString>& textureLocations) { std::map<const FbxTexture*, FbxString>& textureLocations) {
// Get the folder the FBX file is in. // figure out what folder the FBX file is in,
const std::string folder = StringUtils::GetFolderString(fbxFileName); const auto& fbxFolder = FileUtils::getFolder(fbxFileName);
std::vector<std::string> folders{
// first search filename.fbm folder which the SDK itself expands embedded textures into,
fbxFolder + "/" + FileUtils::GetFileBase(fbxFileName) + ".fbm", // filename.fbm
// then the FBX folder itself,
fbxFolder,
// then finally our working directory
FileUtils::GetCurrentFolder(),
};
// Check if there is a filename.fbm folder to which embedded textures were extracted. // List the contents of each of these folders (if they exist)
const std::string fbmFolderName = folder + StringUtils::GetFileBaseString(fbxFileName) + ".fbm/"; std::vector<std::vector<std::string>> folderContents;
for (const auto& folder : folders) {
// Search either in the folder with embedded textures or in the same folder as the FBX file. if (FileUtils::FolderExists(folder)) {
const std::string searchFolder = FileUtils::FolderExists(fbmFolderName) ? fbmFolderName : folder; folderContents.push_back(FileUtils::ListFolderFiles(folder, extensions));
} else {
// Get a list with all the texture files from either the folder with embedded textures or the same folderContents.push_back({});
// folder as the FBX file. }
std::vector<std::string> fileList = FileUtils::ListFolderFiles(searchFolder.c_str(), extensions); }
// Try to match the FBX texture names with the actual files on disk. // Try to match the FBX texture names with the actual files on disk.
for (int i = 0; i < pScene->GetTextureCount(); i++) { for (int i = 0; i < pScene->GetTextureCount(); i++) {
const FbxFileTexture* pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i)); const FbxFileTexture* pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i));
if (pFileTexture == nullptr) { if (pFileTexture != nullptr) {
continue; const std::string fileLocation =
FindFbxTexture(pFileTexture->GetFileName(), folders, folderContents);
// always extend the mapping (even for files we didn't find)
textureLocations.emplace(pFileTexture, fileLocation.c_str());
if (fileLocation.empty()) {
fmt::printf(
"Warning: could not find a image file for texture: %s.\n", pFileTexture->GetName());
} else if (verboseOutput) {
fmt::printf("Found texture '%s' at: %s\n", pFileTexture->GetName(), fileLocation);
}
} }
const std::string inferredName =
GetInferredFileName(pFileTexture->GetFileName(), searchFolder, fileList);
if (inferredName.empty()) {
fmt::printf(
"Warning: could not find a local image file for texture: %s.\n"
"Original filename: %s\n",
pFileTexture->GetName(),
pFileTexture->GetFileName());
}
// always extend the mapping, even for files we didn't find
textureLocations.emplace(pFileTexture, inferredName.c_str());
} }
} }
bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExtensions) { bool LoadFBXFile(
RawModel& raw,
const std::string fbxFileName,
const std::set<std::string>& textureExtensions,
const GltfOptions& options) {
FbxManager* pManager = FbxManager::Create(); FbxManager* pManager = FbxManager::Create();
FbxIOSettings* pIoSettings = FbxIOSettings::Create(pManager, IOSROOT); FbxIOSettings* pIoSettings = FbxIOSettings::Create(pManager, IOSROOT);
pManager->SetIOSettings(pIoSettings); pManager->SetIOSettings(pIoSettings);
FbxImporter* pImporter = FbxImporter::Create(pManager, ""); FbxImporter* pImporter = FbxImporter::Create(pManager, "");
if (!pImporter->Initialize(fbxFileName, -1, pManager->GetIOSettings())) { if (!pImporter->Initialize(fbxFileName.c_str(), -1, pManager->GetIOSettings())) {
if (verboseOutput) { if (verboseOutput) {
fmt::printf("%s\n", pImporter->GetStatus().GetErrorString()); fmt::printf("%s\n", pImporter->GetStatus().GetErrorString());
} }
@ -1036,7 +1112,7 @@ bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExte
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, ""); ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, "");
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations); ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
ReadAnimations(raw, pScene); ReadAnimations(raw, pScene, options);
pScene->Destroy(); pScene->Destroy();
pManager->Destroy(); pManager->Destroy();

View File

@ -1,16 +1,19 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include "raw/RawModel.hpp" #include "raw/RawModel.hpp"
bool LoadFBXFile(RawModel& raw, const char* fbxFileName, const char* textureExtensions); bool LoadFBXFile(
RawModel& raw,
const std::string fbxFileName,
const std::set<std::string>& textureExtensions,
const GltfOptions& options);
json TranscribeProperty(FbxProperty& prop); json TranscribeProperty(FbxProperty& prop);

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "FbxBlendShapesAccess.hpp" #include "FbxBlendShapesAccess.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -95,7 +94,7 @@ class FbxBlendShapesAccess {
} }
FbxAnimCurve* GetAnimation(size_t channelIx, size_t animIx) const { FbxAnimCurve* GetAnimation(size_t channelIx, size_t animIx) const {
return channels.at(channelIx).ExtractAnimation(animIx); return channels.at(channelIx).ExtractAnimation(to_uint32(animIx));
} }
private: private:

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include "FBX2glTF.h" #include "FBX2glTF.h"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "FbxSkinningAccess.hpp" #include "FbxSkinningAccess.hpp"
@ -28,7 +27,9 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
const int* clusterIndices = cluster->GetControlPointIndices(); const int* clusterIndices = cluster->GetControlPointIndices();
const double* clusterWeights = cluster->GetControlPointWeights(); const double* clusterWeights = cluster->GetControlPointWeights();
assert(cluster->GetLinkMode() == FbxCluster::eNormalize); assert(
cluster->GetLinkMode() == FbxCluster::eNormalize ||
cluster->GetLinkMode() == FbxCluster::eTotalOne);
// Transform link matrix. // Transform link matrix.
FbxAMatrix transformLinkMatrix; FbxAMatrix transformLinkMatrix;

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -43,7 +42,7 @@ class FbxSkinningAccess {
return jointNodes[jointIndex]; return jointNodes[jointIndex];
} }
const long GetJointId(const int jointIndex) const { const uint64_t GetJointId(const int jointIndex) const {
return jointIds[jointIndex]; return jointIds[jointIndex];
} }
@ -55,7 +54,7 @@ class FbxSkinningAccess {
return jointInverseGlobalTransforms[jointIndex]; return jointInverseGlobalTransforms[jointIndex];
} }
const long GetRootNode() const { const uint64_t GetRootNode() const {
assert(rootIndex != -1); assert(rootIndex != -1);
return jointIds[rootIndex]; return jointIds[rootIndex];
} }
@ -71,7 +70,7 @@ class FbxSkinningAccess {
private: private:
int rootIndex; int rootIndex;
int maxBoneInfluences; int maxBoneInfluences;
std::vector<long> jointIds; std::vector<uint64_t> jointIds;
std::vector<FbxNode*> jointNodes; std::vector<FbxNode*> jointNodes;
std::vector<FbxMatrix> jointSkinningTransforms; std::vector<FbxMatrix> jointSkinningTransforms;
std::vector<FbxMatrix> jointInverseGlobalTransforms; std::vector<FbxMatrix> jointInverseGlobalTransforms;

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "RoughnessMetallicMaterials.hpp" #include "RoughnessMetallicMaterials.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "fbx/Fbx2Raw.hpp" #include "fbx/Fbx2Raw.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "RoughnessMetallicMaterials.hpp" #include "RoughnessMetallicMaterials.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "TraditionalMaterials.hpp" #include "TraditionalMaterials.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "FbxMaterials.hpp" #include "FbxMaterials.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "GltfModel.hpp" #include "GltfModel.hpp"
@ -12,7 +11,7 @@
std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView( std::shared_ptr<BufferViewData> GltfModel::GetAlignedBufferView(
BufferData& buffer, BufferData& buffer,
const BufferViewData::GL_ArrayType target) { const BufferViewData::GL_ArrayType target) {
unsigned long bufferSize = this->binary->size(); uint32_t bufferSize = to_uint32(this->binary->size());
if ((bufferSize % 4) > 0) { if ((bufferSize % 4) > 0) {
bufferSize += (4 - (bufferSize % 4)); bufferSize += (4 - (bufferSize % 4));
this->binary->resize(bufferSize); this->binary->resize(bufferSize);
@ -27,7 +26,7 @@ GltfModel::AddRawBufferView(BufferData& buffer, const char* source, uint32_t byt
bufferView->byteLength = bytes; bufferView->byteLength = bytes;
// make space for the new bytes (possibly moving the underlying data) // make space for the new bytes (possibly moving the underlying data)
unsigned long bufferSize = this->binary->size(); uint32_t bufferSize = to_uint32(this->binary->size());
this->binary->resize(bufferSize + bytes); this->binary->resize(bufferSize + bytes);
// and copy them into place // and copy them into place
@ -52,7 +51,7 @@ std::shared_ptr<BufferViewData> GltfModel::AddBufferViewForFile(
std::vector<char> fileBuffer(size); std::vector<char> fileBuffer(size);
if (file.read(fileBuffer.data(), size)) { if (file.read(fileBuffer.data(), size)) {
result = AddRawBufferView(buffer, fileBuffer.data(), size); result = AddRawBufferView(buffer, fileBuffer.data(), to_uint32(size));
} else { } else {
fmt::printf("Warning: Couldn't read %lu bytes from %s, skipping file.\n", size, filename); fmt::printf("Warning: Couldn't read %lu bytes from %s, skipping file.\n", size, filename);
} }

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -44,7 +43,7 @@ template <typename T>
class Holder { class Holder {
public: public:
std::shared_ptr<T> hold(T* ptr) { std::shared_ptr<T> hold(T* ptr) {
ptr->ix = ptrs.size(); ptr->ix = to_uint32(ptrs.size());
ptrs.emplace_back(ptr); ptrs.emplace_back(ptr);
return ptrs.back(); return ptrs.back();
} }
@ -114,7 +113,7 @@ class GltfModel {
primitive.AddDracoAttrib(attrDef, attribArr); primitive.AddDracoAttrib(attrDef, attribArr);
accessor = accessors.hold(new AccessorData(attrDef.glType)); accessor = accessors.hold(new AccessorData(attrDef.glType));
accessor->count = attribArr.size(); accessor->count = to_uint32(attribArr.size());
} else { } else {
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER); auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string("")); accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "Raw2Gltf.hpp" #include "Raw2Gltf.hpp"
@ -256,29 +255,28 @@ ModelData* Raw2Gltf(
if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) { if (material.info->shadingModel == RAW_SHADING_MODEL_PBR_MET_ROUGH) {
/** /**
* PBR FBX Material -> PBR Met/Rough glTF. * PBR FBX Material -> PBR Met/Rough glTF.
*
* METALLIC and ROUGHNESS textures are packed in G and B channels of a rough/met texture.
* Other values translate directly.
*/ */
RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get(); RawMetRoughMatProps* props = (RawMetRoughMatProps*)material.info.get();
// diffuse and emissive are noncontroversial
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
diffuseFactor = props->diffuseFactor;
emissiveFactor = props->emissiveFactor;
emissiveIntensity = props->emissiveIntensity;
// we always send the metallic/roughness factors onto the glTF generator
metallic = props->metallic;
roughness = props->roughness;
// determine if we need to generate a combined map // determine if we need to generate a combined map
bool hasMetallicMap = material.textures[RAW_TEXTURE_USAGE_METALLIC] >= 0; bool hasMetallicMap = material.textures[RAW_TEXTURE_USAGE_METALLIC] >= 0;
bool hasRoughnessMap = material.textures[RAW_TEXTURE_USAGE_ROUGHNESS] >= 0; bool hasRoughnessMap = material.textures[RAW_TEXTURE_USAGE_ROUGHNESS] >= 0;
bool hasOcclusionMap = material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0; bool hasOcclusionMap = material.textures[RAW_TEXTURE_USAGE_OCCLUSION] >= 0;
bool atLeastTwoMaps = hasMetallicMap ? (hasRoughnessMap || hasOcclusionMap) bool atLeastTwoMaps = hasMetallicMap ? (hasRoughnessMap || hasOcclusionMap)
: (hasRoughnessMap && hasMetallicMap); : (hasRoughnessMap && hasMetallicMap);
if (atLeastTwoMaps) { if (!atLeastTwoMaps) {
// if there's at least two of metallic/roughness/occlusion, it makes sense to // this handles the case of 0 or 1 maps supplied
// merge them: occlusion into the red channel, metallic into blue channel, and aoMetRoughTex = hasMetallicMap
// roughness into the green. ? simpleTex(RAW_TEXTURE_USAGE_METALLIC)
: (hasRoughnessMap
? simpleTex(RAW_TEXTURE_USAGE_ROUGHNESS)
: (hasOcclusionMap ? simpleTex(RAW_TEXTURE_USAGE_OCCLUSION) : nullptr));
} else {
// otherwise merge occlusion into the red channel, metallic into blue channel, and
// roughness into the green, of a new combinatory texture
aoMetRoughTex = textureBuilder.combine( aoMetRoughTex = textureBuilder.combine(
{ {
material.textures[RAW_TEXTURE_USAGE_OCCLUSION], material.textures[RAW_TEXTURE_USAGE_OCCLUSION],
@ -289,27 +287,24 @@ ModelData* Raw2Gltf(
[&](const std::vector<const TextureBuilder::pixel*> pixels) [&](const std::vector<const TextureBuilder::pixel*> pixels)
-> TextureBuilder::pixel { -> TextureBuilder::pixel {
const float occlusion = (*pixels[0])[0]; const float occlusion = (*pixels[0])[0];
const float metallic = (*pixels[1])[0]; const float metallic = (*pixels[1])[0] * (hasMetallicMap ? 1 : props->metallic);
const float roughness = (*pixels[2])[0]; const float roughness =
(*pixels[2])[0] * (hasRoughnessMap ? 1 : props->roughness);
return {{occlusion, return {{occlusion,
props->invertRoughnessMap ? 1.0f - roughness : roughness, props->invertRoughnessMap ? 1.0f - roughness : roughness,
metallic, metallic,
1}}; 1}};
}, },
false); false);
if (hasOcclusionMap) {
// will only be true if there were actual non-trivial pixels
occlusionTexture = aoMetRoughTex.get();
}
} else {
// this handles the case of 0 or 1 maps supplied
if (hasMetallicMap) {
aoMetRoughTex = simpleTex(RAW_TEXTURE_USAGE_METALLIC);
} else if (hasRoughnessMap) {
aoMetRoughTex = simpleTex(RAW_TEXTURE_USAGE_ROUGHNESS);
}
// else only occlusion map is possible: that check is handled further below
} }
baseColorTex = simpleTex(RAW_TEXTURE_USAGE_ALBEDO);
diffuseFactor = props->diffuseFactor;
metallic = props->metallic;
roughness = props->roughness;
emissiveFactor = props->emissiveFactor;
emissiveIntensity = props->emissiveIntensity;
// this will set occlusionTexture to null, if no actual occlusion map exists
occlusionTexture = aoMetRoughTex.get();
} else { } else {
/** /**
* Traditional FBX Material -> PBR Met/Rough glTF. * Traditional FBX Material -> PBR Met/Rough glTF.
@ -393,7 +388,6 @@ ModelData* Raw2Gltf(
khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial()); khrCmnUnlitMat.reset(new KHRCmnUnlitMaterial());
} }
// after all the special cases have had a go, check if we need to look up occlusion map
if (!occlusionTexture) { if (!occlusionTexture) {
occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get(); occlusionTexture = simpleTex(RAW_TEXTURE_USAGE_OCCLUSION).get();
} }
@ -422,8 +416,6 @@ ModelData* Raw2Gltf(
const RawMaterial& rawMaterial = const RawMaterial& rawMaterial =
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex); surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
fmt::printf(
"Seeking material of id %ls, name %s...\n", rawMaterial.id, rawMaterial.name.c_str());
const MaterialData& mData = require(materialsById, rawMaterial.id); const MaterialData& mData = require(materialsById, rawMaterial.id);
MeshData* mesh = nullptr; MeshData* mesh = nullptr;
@ -447,11 +439,11 @@ ModelData* Raw2Gltf(
std::shared_ptr<PrimitiveData> primitive; std::shared_ptr<PrimitiveData> primitive;
if (options.draco.enabled) { if (options.draco.enabled) {
int triangleCount = surfaceModel.GetTriangleCount(); size_t triangleCount = surfaceModel.GetTriangleCount();
// initialize Draco mesh with vertex index information // initialize Draco mesh with vertex index information
auto dracoMesh(std::make_shared<draco::Mesh>()); auto dracoMesh(std::make_shared<draco::Mesh>());
dracoMesh->SetNumFaces(static_cast<size_t>(triangleCount)); dracoMesh->SetNumFaces(triangleCount);
dracoMesh->set_num_points(surfaceModel.GetVertexCount()); dracoMesh->set_num_points(surfaceModel.GetVertexCount());
for (uint32_t ii = 0; ii < triangleCount; ii++) { for (uint32_t ii = 0; ii < triangleCount; ii++) {
@ -464,7 +456,7 @@ ModelData* Raw2Gltf(
AccessorData& indexes = AccessorData& indexes =
*gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT)); *gltf->accessors.hold(new AccessorData(useLongIndices ? GLT_UINT : GLT_USHORT));
indexes.count = 3 * triangleCount; indexes.count = to_uint32(3 * triangleCount);
primitive.reset(new PrimitiveData(indexes, mData, dracoMesh)); primitive.reset(new PrimitiveData(indexes, mData, dracoMesh));
} else { } else {
const AccessorData& indexes = *gltf->AddAccessorWithView( const AccessorData& indexes = *gltf->AddAccessorWithView(
@ -499,11 +491,13 @@ ModelData* Raw2Gltf(
GLT_VEC3F, GLT_VEC3F,
draco::GeometryAttribute::NORMAL, draco::GeometryAttribute::NORMAL,
draco::DT_FLOAT32); draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL); const auto _ =
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
const AttributeDefinition<Vec4f> ATTR_TANGENT("TANGENT", &RawVertex::tangent, GLT_VEC4F); const AttributeDefinition<Vec4f> ATTR_TANGENT("TANGENT", &RawVertex::tangent, GLT_VEC4F);
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT); const auto _ = gltf->AddAttributeToPrimitive<Vec4f>(
buffer, surfaceModel, *primitive, ATTR_TANGENT);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
const AttributeDefinition<Vec4f> ATTR_COLOR( const AttributeDefinition<Vec4f> ATTR_COLOR(
@ -512,7 +506,8 @@ ModelData* Raw2Gltf(
GLT_VEC4F, GLT_VEC4F,
draco::GeometryAttribute::COLOR, draco::GeometryAttribute::COLOR,
draco::DT_FLOAT32); draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR); const auto _ =
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_COLOR);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV0) != 0) {
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0( const AttributeDefinition<Vec2f> ATTR_TEXCOORD_0(
@ -521,7 +516,8 @@ ModelData* Raw2Gltf(
GLT_VEC2F, GLT_VEC2F,
draco::GeometryAttribute::TEX_COORD, draco::GeometryAttribute::TEX_COORD,
draco::DT_FLOAT32); draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0); const auto _ = gltf->AddAttributeToPrimitive<Vec2f>(
buffer, surfaceModel, *primitive, ATTR_TEXCOORD_0);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_UV1) != 0) {
const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1( const AttributeDefinition<Vec2f> ATTR_TEXCOORD_1(
@ -530,7 +526,8 @@ ModelData* Raw2Gltf(
GLT_VEC2F, GLT_VEC2F,
draco::GeometryAttribute::TEX_COORD, draco::GeometryAttribute::TEX_COORD,
draco::DT_FLOAT32); draco::DT_FLOAT32);
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1); const auto _ = gltf->AddAttributeToPrimitive<Vec2f>(
buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1);
} }
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) { if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) {
for (int i = 0; i < surfaceModel.GetGlobalWeightCount(); i += 4) { for (int i = 0; i < surfaceModel.GetGlobalWeightCount(); i += 4) {
@ -639,7 +636,7 @@ ModelData* Raw2Gltf(
draco::Status status = encoder.EncodeMeshToBuffer(*primitive->dracoMesh, &dracoBuffer); draco::Status status = encoder.EncodeMeshToBuffer(*primitive->dracoMesh, &dracoBuffer);
assert(status.code() == draco::Status::OK); assert(status.code() == draco::Status::OK);
auto view = gltf->AddRawBufferView(buffer, dracoBuffer.data(), dracoBuffer.size()); auto view = gltf->AddRawBufferView(buffer, dracoBuffer.data(), to_uint32(dracoBuffer.size()));
primitive->NoteDracoBuffer(*view); primitive->NoteDracoBuffer(*view);
} }
mesh->AddPrimitive(primitive); mesh->AddPrimitive(primitive);
@ -741,7 +738,7 @@ ModelData* Raw2Gltf(
type = LightData::Type::Spot; type = LightData::Type::Spot;
break; break;
} }
gltf->lights.hold(new LightData( const auto _ = gltf->lights.hold(new LightData(
light.name, light.name,
type, type,
light.color, light.color,
@ -848,13 +845,13 @@ ModelData* Raw2Gltf(
gltfOutStream.write(glb2BinaryHeader, 8); gltfOutStream.write(glb2BinaryHeader, 8);
// append binary buffer directly to .glb file // append binary buffer directly to .glb file
uint32_t binaryLength = gltf->binary->size(); size_t binaryLength = gltf->binary->size();
gltfOutStream.write((const char*)&(*gltf->binary)[0], binaryLength); gltfOutStream.write((const char*)&(*gltf->binary)[0], binaryLength);
while ((binaryLength % 4) != 0) { while ((binaryLength % 4) != 0) {
gltfOutStream.put('\0'); gltfOutStream.put('\0');
binaryLength++; binaryLength++;
} }
uint32_t totalLength = (uint32_t)gltfOutStream.tellp(); uint32_t totalLength = to_uint32(gltfOutStream.tellp());
// seek back to sub-header for json chunk // seek back to sub-header for json chunk
gltfOutStream.seekp(8); gltfOutStream.seekp(8);

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -120,7 +119,7 @@ const GLType GLT_QUATF = {CT_FLOAT, 4, "VEC4"};
* The base of any indexed glTF entity. * The base of any indexed glTF entity.
*/ */
struct Holdable { struct Holdable {
uint32_t ix; uint32_t ix = UINT_MAX;
virtual json serialize() const = 0; virtual json serialize() const = 0;
}; };

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "TextureBuilder.hpp" #include "TextureBuilder.hpp"
@ -49,8 +48,7 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
if (rawTexIx >= 0) { if (rawTexIx >= 0) {
const RawTexture& rawTex = raw.GetTexture(rawTexIx); const RawTexture& rawTex = raw.GetTexture(rawTexIx);
const std::string& fileLoc = rawTex.fileLocation; const std::string& fileLoc = rawTex.fileLocation;
const std::string& name = const std::string& name = FileUtils::GetFileBase(FileUtils::GetFileName(fileLoc));
StringUtils::GetFileBaseString(StringUtils::GetFileNameString(fileLoc));
if (!fileLoc.empty()) { if (!fileLoc.empty()) {
info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0); info.pixels = stbi_load(fileLoc.c_str(), &info.width, &info.height, &info.channels, 0);
if (!info.pixels) { if (!info.pixels) {
@ -142,7 +140,7 @@ std::shared_ptr<TextureData> TextureBuilder::combine(
ImageData* image; ImageData* image;
if (options.outputBinary) { if (options.outputBinary) {
const auto bufferView = const auto bufferView =
gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), imgBuffer.size()); gltf.AddRawBufferView(*gltf.defaultBuffer, imgBuffer.data(), to_uint32(imgBuffer.size()));
image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg"); image = new ImageData(mergedName, *bufferView, png ? "image/png" : "image/jpeg");
} else { } else {
const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg"); const std::string imageFilename = mergedFilename + (png ? ".png" : ".jpg");
@ -180,20 +178,30 @@ std::shared_ptr<TextureData> TextureBuilder::simple(int rawTexIndex, const std::
} }
const RawTexture& rawTexture = raw.GetTexture(rawTexIndex); const RawTexture& rawTexture = raw.GetTexture(rawTexIndex);
const std::string textureName = StringUtils::GetFileBaseString(rawTexture.name); const std::string textureName = FileUtils::GetFileBase(rawTexture.name);
const std::string relativeFilename = StringUtils::GetFileNameString(rawTexture.fileLocation); const std::string relativeFilename = FileUtils::GetFileName(rawTexture.fileLocation);
ImageData* image = nullptr; ImageData* image = nullptr;
if (options.outputBinary) { if (options.outputBinary) {
auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation); auto bufferView = gltf.AddBufferViewForFile(*gltf.defaultBuffer, rawTexture.fileLocation);
if (bufferView) { if (bufferView) {
std::string suffix = StringUtils::GetFileSuffixString(rawTexture.fileLocation); const auto& suffix = FileUtils::GetFileSuffix(rawTexture.fileLocation);
image = new ImageData(relativeFilename, *bufferView, ImageUtils::suffixToMimeType(suffix)); std::string mimeType;
if (suffix) {
mimeType = ImageUtils::suffixToMimeType(suffix.value());
} else {
mimeType = "image/jpeg";
fmt::printf(
"Warning: Can't deduce mime type of texture '%s'; using %s.\n",
rawTexture.fileLocation,
mimeType);
}
image = new ImageData(relativeFilename, *bufferView, mimeType);
} }
} else if (!relativeFilename.empty()) { } else if (!relativeFilename.empty()) {
image = new ImageData(relativeFilename, relativeFilename); image = new ImageData(relativeFilename, relativeFilename);
std::string outputPath = outputFolder + StringUtils::NormalizePath(relativeFilename); std::string outputPath = outputFolder + "/" + relativeFilename;
if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) { if (FileUtils::CopyFile(rawTexture.fileLocation, outputPath, true)) {
if (verboseOutput) { if (verboseOutput) {
fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath); fmt::printf("Copied texture '%s' to output folder: %s\n", textureName, outputPath);

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "AccessorData.hpp" #include "AccessorData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "AnimationData.hpp" #include "AnimationData.hpp"
@ -24,7 +23,7 @@ void AnimationData::AddNodeChannel(
const AccessorData& accessor, const AccessorData& accessor,
std::string path) { std::string path) {
assert(channels.size() == samplers.size()); assert(channels.size() == samplers.size());
uint32_t ix = channels.size(); uint32_t ix = to_uint32(channels.size());
channels.emplace_back(channel_t(ix, node, std::move(path))); channels.emplace_back(channel_t(ix, node, std::move(path)));
samplers.emplace_back(sampler_t(timeAccessor, accessor.ix)); samplers.emplace_back(sampler_t(timeAccessor, accessor.ix));
} }

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include <cppcodec/base64_default_rfc4648.hpp> #include <cppcodec/base64_default_rfc4648.hpp>

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "BufferViewData.hpp" #include "BufferViewData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "CameraData.hpp" #include "CameraData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "ImageData.hpp" #include "ImageData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "LightData.hpp" #include "LightData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "MaterialData.hpp" #include "MaterialData.hpp"
@ -59,13 +58,15 @@ void to_json(json& j, const PBRMetallicRoughness& d) {
if (d.baseColorFactor.LengthSquared() > 0) { if (d.baseColorFactor.LengthSquared() > 0) {
j["baseColorFactor"] = toStdVec(d.baseColorFactor); j["baseColorFactor"] = toStdVec(d.baseColorFactor);
} }
// we always copy metallic/roughness straight to the glTF:
// - if there's a texture, they're linear multiplier
// - if there's no texture, they're constants
j["metallicFactor"] = d.metallic;
j["roughnessFactor"] = d.roughness;
if (d.metRoughTexture != nullptr) { if (d.metRoughTexture != nullptr) {
j["metallicRoughnessTexture"] = *d.metRoughTexture; j["metallicRoughnessTexture"] = *d.metRoughTexture;
// if a texture is provided, throw away metallic/roughness values
j["roughnessFactor"] = 1.0f;
j["metallicFactor"] = 1.0f;
} else {
// without a texture, however, use metallic/roughness as constants
j["metallicFactor"] = d.metallic;
j["roughnessFactor"] = d.roughness;
} }
} }

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "MeshData.hpp" #include "MeshData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "NodeData.hpp" #include "NodeData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "PrimitiveData.hpp" #include "PrimitiveData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
@ -49,7 +48,7 @@ struct PrimitiveData {
componentCount * draco::DataTypeLength(attribute.dracoComponentType), componentCount * draco::DataTypeLength(attribute.dracoComponentType),
0); 0);
const int dracoAttId = dracoMesh->AddAttribute(att, true, attribArr.size()); const int dracoAttId = dracoMesh->AddAttribute(att, true, to_uint32(attribArr.size()));
draco::PointAttribute* attPtr = dracoMesh->attribute(dracoAttId); draco::PointAttribute* attPtr = dracoMesh->attribute(dracoAttId);
std::vector<uint8_t> buf(sizeof(T)); std::vector<uint8_t> buf(sizeof(T));

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "SceneData.hpp" #include "SceneData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "SkinData.hpp" #include "SkinData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "TextureData.hpp" #include "TextureData.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,14 +1,15 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include <vector>
#include <fbxsdk.h> #include <fbxsdk.h>
#include <mathfu/matrix.h> #include <mathfu/matrix.h>

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "RawModel.hpp" #include "RawModel.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,180 +1,55 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "File_Utils.hpp" #include "File_Utils.hpp"
#include <fstream> #include <fstream>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#if defined(__unix__) || defined(__APPLE__)
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#define _getcwd getcwd
#define _mkdir(a) mkdir(a, 0777)
#elif defined(_WIN32)
#include <direct.h>
#include <process.h>
#else
#include <direct.h>
#include <process.h>
#endif
#include <sys/stat.h>
#include "FBX2glTF.h" #include "FBX2glTF.h"
#include "String_Utils.hpp" #include "String_Utils.hpp"
namespace FileUtils { namespace FileUtils {
std::string GetCurrentFolder() { std::vector<std::string> ListFolderFiles(
char cwd[StringUtils::MAX_PATH_LENGTH]; std::string folder,
if (!_getcwd(cwd, sizeof(cwd))) { const std::set<std::string>& matchExtensions) {
return std::string();
}
cwd[sizeof(cwd) - 1] = '\0';
StringUtils::GetCleanPath(cwd, cwd, StringUtils::PATH_UNIX);
const size_t length = strlen(cwd);
if (cwd[length - 1] != '/' && length < StringUtils::MAX_PATH_LENGTH - 1) {
cwd[length + 0] = '/';
cwd[length + 1] = '\0';
}
return std::string(cwd);
}
bool FileExists(const std::string& filePath) {
std::ifstream stream(filePath);
return stream.good();
}
bool FolderExists(const std::string& folderPath) {
#if defined(__unix__) || defined(__APPLE__)
DIR* dir = opendir(folderPath.c_str());
if (dir) {
closedir(dir);
return true;
}
return false;
#else
const DWORD ftyp = GetFileAttributesA(folderPath.c_str());
if (ftyp == INVALID_FILE_ATTRIBUTES) {
return false; // bad path
}
return (ftyp & FILE_ATTRIBUTE_DIRECTORY) != 0;
#endif
}
bool MatchExtension(const char* fileExtension, const char* matchExtensions) {
if (matchExtensions[0] == '\0') {
return true;
}
if (fileExtension[0] == '.') {
fileExtension++;
}
for (const char* end = matchExtensions; end[0] != '\0';) {
for (; end[0] == ';'; end++) {
}
const char* ext = end;
for (; end[0] != ';' && end[0] != '\0'; end++) {
}
#if defined(__unix__) || defined(__APPLE__)
if (strncasecmp(fileExtension, ext, end - ext) == 0)
#else
if (_strnicmp(fileExtension, ext, end - ext) == 0)
#endif
{
return true;
}
}
return false;
}
std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions) {
std::vector<std::string> fileList; std::vector<std::string> fileList;
#if defined(__unix__) || defined(__APPLE__) if (folder.empty()) {
DIR* dir = opendir(strlen(folder) > 0 ? folder : "."); folder = ".";
if (dir != nullptr) { }
for (;;) { for (const auto& entry : boost::filesystem::directory_iterator(folder)) {
struct dirent* dp = readdir(dir); const auto& suffix = FileUtils::GetFileSuffix(entry.path().string());
if (dp == nullptr) { if (suffix.has_value()) {
break; const auto& suffix_str = StringUtils::ToLower(suffix.value());
if (matchExtensions.find(suffix_str) != matchExtensions.end()) {
fileList.push_back(entry.path().filename().string());
} }
if (dp->d_type == DT_DIR) {
continue;
}
const char* fileName = dp->d_name;
const char* fileExt = strrchr(fileName, '.');
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
continue;
}
fileList.emplace_back(fileName);
} }
closedir(dir);
} }
#else
std::string pathStr = folder;
pathStr += "*";
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(pathStr.c_str(), &FindFileData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
std::string fileName = FindFileData.cFileName;
std::string::size_type extPos = fileName.rfind('.');
if (extPos != std::string::npos &&
MatchExtension(fileName.substr(extPos + 1).c_str(), matchExtensions)) {
fileList.push_back(fileName);
}
}
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
#endif
return fileList; return fileList;
} }
bool CreatePath(const char* path) { bool CreatePath(const std::string path) {
#if defined(__unix__) || defined(__APPLE__) const auto& parent = boost::filesystem::path(path).parent_path();
StringUtils::PathSeparator separator = StringUtils::PATH_UNIX; if (parent.empty()) {
#else // this is either CWD or boost::filesystem root; either way it exists
StringUtils::PathSeparator separator = StringUtils::PATH_WIN; return true;
#endif
std::string folder = StringUtils::GetFolderString(path);
std::string clean = StringUtils::GetCleanPathString(folder, separator);
std::string build = clean;
for (int i = 0; i < clean.length(); i++) {
if (clean[i] == separator && i > 0) {
build[i] = '\0';
if (i > 1 || build[1] != ':') {
if (_mkdir(build.c_str()) != 0 && errno != EEXIST) {
return false;
}
}
}
build[i] = clean[i];
} }
return true; if (boost::filesystem::exists(parent)) {
return boost::filesystem::is_directory(parent);
}
return boost::filesystem::create_directory(parent);
} }
bool CopyFile(const std::string& srcFilename, const std::string& dstFilename, bool createPath) { bool CopyFile(const std::string& srcFilename, const std::string& dstFilename, bool createPath) {

View File

@ -1,17 +1,20 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
namespace FileUtils { namespace FileUtils {
std::string GetCurrentFolder(); std::string GetCurrentFolder();
@ -19,13 +22,51 @@ std::string GetCurrentFolder();
bool FileExists(const std::string& folderPath); bool FileExists(const std::string& folderPath);
bool FolderExists(const std::string& folderPath); bool FolderExists(const std::string& folderPath);
bool MatchExtension(const char* fileExtension, const char* matchExtensions); std::vector<std::string> ListFolderFiles(
std::vector<std::string> ListFolderFiles(const char* folder, const char* matchExtensions); const std::string folder,
const std::set<std::string>& matchExtensions);
bool CreatePath(const char* path); bool CreatePath(std::string path);
bool CopyFile( bool CopyFile(
const std::string& srcFilename, const std::string& srcFilename,
const std::string& dstFilename, const std::string& dstFilename,
bool createPath = false); bool createPath = false);
inline std::string GetAbsolutePath(const std::string& filePath) {
return boost::filesystem::absolute(filePath).string();
}
inline std::string GetCurrentFolder() {
return boost::filesystem::current_path().string();
}
inline bool FileExists(const std::string& filePath) {
return boost::filesystem::exists(filePath) && boost::filesystem::is_regular_file(filePath);
}
inline bool FolderExists(const std::string& folderPath) {
return boost::filesystem::exists(folderPath) && boost::filesystem::is_directory(folderPath);
}
inline std::string getFolder(const std::string& path) {
return boost::filesystem::path(path).parent_path().string();
}
inline std::string GetFileName(const std::string& path) {
return boost::filesystem::path(path).filename().string();
}
inline std::string GetFileBase(const std::string& path) {
return boost::filesystem::path(path).stem().string();
}
inline boost::optional<std::string> GetFileSuffix(const std::string& path) {
const auto& extension = boost::filesystem::path(path).extension();
if (extension.empty()) {
return boost::none;
}
return extension.string().substr(1);
}
} // namespace FileUtils } // namespace FileUtils

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#include "Image_Utils.hpp" #include "Image_Utils.hpp"

View File

@ -1,10 +1,9 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once

View File

@ -1,80 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "String_Utils.hpp"
namespace StringUtils {
PathSeparator operator!(const PathSeparator& s) {
return (s == PATH_WIN) ? PATH_UNIX : PATH_WIN;
}
PathSeparator GetPathSeparator() {
#if defined(__unix__) || defined(__APPLE__)
return PATH_UNIX;
#else
return PATH_WIN;
#endif
}
const std::string NormalizePath(const std::string& path) {
PathSeparator separator = GetPathSeparator();
char replace;
if (separator == PATH_WIN) {
replace = PATH_UNIX;
} else {
replace = PATH_WIN;
}
std::string normalizedPath = path;
for (size_t s = normalizedPath.find(replace, 0); s != std::string::npos;
s = normalizedPath.find(replace, s)) {
normalizedPath[s] = separator;
}
return normalizedPath;
}
const std::string GetFolderString(const std::string& path) {
size_t s = path.rfind(PATH_WIN);
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
return path.substr(0, s + 1);
}
const std::string GetCleanPathString(const std::string& path, const PathSeparator separator) {
std::string cleanPath = path;
for (size_t s = cleanPath.find(!separator, 0); s != std::string::npos;
s = cleanPath.find(!separator, s)) {
cleanPath[s] = separator;
}
return cleanPath;
}
const std::string GetFileNameString(const std::string& path) {
size_t s = path.rfind(PATH_WIN);
s = (s != std::string::npos) ? s : path.rfind(PATH_UNIX);
return path.substr(s + 1, std::string::npos);
}
const std::string GetFileBaseString(const std::string& path) {
const std::string fileName = GetFileNameString(path);
return fileName.substr(0, fileName.rfind('.')).c_str();
}
const std::string GetFileSuffixString(const std::string& path) {
const std::string fileName = GetFileNameString(path);
size_t pos = fileName.rfind('.');
if (pos == std::string::npos) {
return "";
}
return fileName.substr(++pos);
}
int CompareNoCase(const std::string& s1, const std::string& s2) {
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
}
} // namespace StringUtils

View File

@ -1,14 +1,15 @@
/** /**
* Copyright (c) 2014-present, Facebook, Inc. * Copyright (c) Facebook, Inc. and its affiliates.
* All rights reserved. * All rights reserved.
* *
* This source code is licensed under the BSD-style license found in the * This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant * LICENSE file in the root directory of this source tree.
* of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once #pragma once
#include <algorithm>
#include <cctype>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -16,39 +17,17 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif #endif
namespace StringUtils { namespace StringUtils {
static const unsigned int MAX_PATH_LENGTH = 1024; inline std::string ToLower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](uint8_t c) { return std::tolower(c); });
enum PathSeparator { PATH_WIN = '\\', PATH_UNIX = '/' }; return s;
PathSeparator operator!(const PathSeparator& s);
PathSeparator GetPathSeparator();
const std::string NormalizePath(const std::string& path);
const std::string GetCleanPathString(
const std::string& path,
const PathSeparator separator = PATH_WIN);
template <size_t size>
void GetCleanPath(char (&dest)[size], const char* path, const PathSeparator separator = PATH_WIN) {
size_t len = size - 1;
strncpy(dest, path, len);
char* destPtr = dest;
while ((destPtr = strchr(destPtr, !separator)) != nullptr) {
*destPtr = separator;
}
} }
const std::string GetFolderString(const std::string& path); inline int CompareNoCase(const std::string& s1, const std::string& s2) {
const std::string GetFileNameString(const std::string& path); return strncasecmp(s1.c_str(), s2.c_str(), std::max(s1.length(), s2.length()));
const std::string GetFileBaseString(const std::string& path); }
const std::string GetFileSuffixString(const std::string& path);
int CompareNoCase(const std::string& s1, const std::string& s2);
} // namespace StringUtils } // namespace StringUtils