├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── common ├── CMakeLists.txt ├── common.h ├── common_util.h ├── config.cc ├── config.h ├── logging.cc ├── logging.h ├── messages.inl ├── platform.cc ├── platform.h ├── scheduler.cc └── scheduler.h ├── convert ├── CMakeLists.txt ├── convert_common.h ├── convert_context.h ├── convert_util.cc ├── convert_util.h ├── converter.cc ├── converter.h ├── materializer.cc ├── materializer.h ├── package.cc ├── package.h ├── texturator.cc ├── texturator.h ├── tokens.cc └── tokens.h ├── gltf ├── CMakeLists.txt ├── cache.cc ├── cache.h ├── disk_stream.cc ├── disk_stream.h ├── disk_util.cc ├── disk_util.h ├── glb_stream.cc ├── glb_stream.h ├── gltf.cc ├── gltf.h ├── image_parsing.cc ├── image_parsing.h ├── internal_util.cc ├── internal_util.h ├── load.cc ├── load.h ├── memory_stream.cc ├── memory_stream.h ├── message.cc ├── message.h ├── messages.inl ├── stream.cc ├── stream.h ├── validate.cc └── validate.h ├── process ├── CMakeLists.txt ├── access.h ├── animation.cc ├── animation.h ├── color.cc ├── color.h ├── float_image.cc ├── float_image.h ├── image.cc ├── image.h ├── image_fallback.cc ├── image_fallback.h ├── image_gif.cc ├── image_gif.h ├── image_jpg.cc ├── image_jpg.h ├── image_png.cc ├── image_png.h ├── math.cc ├── math.h ├── mesh.cc ├── mesh.h ├── process_util.cc ├── process_util.h ├── skin.cc └── skin.h ├── testdata ├── ref.csv ├── samp_draco.csv ├── samp_embed.csv ├── samp_glb.csv ├── samp_gltf.csv └── samp_specgloss.csv ├── tools ├── ufgbatch │ ├── html_resources │ │ └── usdz_icon.png │ ├── ufgbatch.py │ ├── ufgcommon │ │ ├── __init__.py │ │ ├── deploy.py │ │ ├── diff.py │ │ ├── process.py │ │ ├── task.py │ │ └── util.py │ ├── ufgtest.py │ ├── ufgtest.pyproj │ ├── ufgvalidate.py │ └── ufgvalidate.pyproj ├── ufginstall │ ├── patches │ │ ├── giflib │ │ │ ├── CMakeLists.txt │ │ │ ├── giflib-config.cmake │ │ │ └── unistd.h │ │ ├── json │ │ │ ├── CMakeLists.txt │ │ │ └── json-config.cmake │ │ ├── stb_image │ │ │ ├── CMakeLists.txt │ │ │ ├── stb_image-config.cmake │ │ │ └── stb_image.cc │ │ └── tclap │ │ │ ├── CMakeLists.txt │ │ │ └── tclap-config.cmake │ └── ufginstall.py └── usdviewer.bat ├── ufg-config.cmake ├── ufg_plugin ├── CMakeLists.txt ├── plugInfo.json ├── ufg_plugin.cc └── ufg_plugin.h └── usd_from_gltf ├── CMakeLists.txt ├── args.cc ├── args.h └── usd_from_gltf.cc /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required (VERSION 3.0) 16 | project (usd_from_gltf) 17 | 18 | # We don't use Python in this tool, but when the USD library is built with 19 | # PXR_PYTHON_SUPPORT_ENABLED it references it anyway. 20 | if (EXISTS "${USD_DIR}/lib/python/") 21 | find_package(Python COMPONENTS Development) 22 | if (NOT Python_FOUND) 23 | message(FATAL_ERROR "Missing python libs.") 24 | endif (NOT Python_FOUND) 25 | endif (EXISTS "${USD_DIR}/lib/python/") 26 | 27 | set(USD_INCLUDE_DIRS 28 | "${USD_DIR}/include" 29 | "${USD_DIR}/include/boost-1_61" 30 | # Visual Studio 2017 requires boost 1.65.1. 31 | "${USD_DIR}/include/boost-1_65_1" 32 | ${Python_INCLUDE_DIRS} 33 | ) 34 | 35 | link_directories( 36 | "${USD_DIR}/lib" 37 | ${Python_LIBRARY_DIRS} 38 | ) 39 | 40 | if (MSVC) 41 | set(USD_LIBS 42 | gf.lib 43 | plug.lib 44 | sdf.lib 45 | tf.lib 46 | usd.lib 47 | usdGeom.lib 48 | usdShade.lib 49 | usdSkel.lib 50 | usdUtils.lib 51 | vt.lib 52 | ) 53 | elseif (APPLE) 54 | set(USD_LIBS 55 | ${Python_LIBRARIES} 56 | -lpthread 57 | libgf.dylib 58 | libplug.dylib 59 | libsdf.dylib 60 | libtf.dylib 61 | libusd.dylib 62 | libusdGeom.dylib 63 | libusdShade.dylib 64 | libusdSkel.dylib 65 | libusdUtils.dylib 66 | libvt.dylib 67 | ) 68 | if (Python_FOUND) 69 | list(APPEND USD_LIBS "${USD_DIR}/lib/libboost_python.dylib") 70 | endif (Python_FOUND) 71 | else () 72 | set(USD_LIBS 73 | ${Python_LIBRARIES} 74 | -lpthread 75 | libgf.so 76 | libplug.so 77 | libsdf.so 78 | libtf.so 79 | libusd.so 80 | libusdGeom.so 81 | libusdShade.so 82 | libusdSkel.so 83 | libusdUtils.so 84 | libvt.so 85 | ) 86 | if (Python_FOUND) 87 | list(APPEND USD_LIBS "${USD_DIR}/lib/libboost_python.so") 88 | endif (Python_FOUND) 89 | endif () 90 | 91 | if (MSVC) 92 | add_compile_definitions( 93 | _CRT_SECURE_NO_WARNINGS 94 | ) 95 | add_compile_options( 96 | /wd4996 # Call to 'std::copy' with parameters that may be unsafe 97 | ) 98 | 99 | # Use the release runtime for all builds so we can compile the library in Debug 100 | # without having to recompile dependencies. 101 | set(CompilerFlags 102 | CMAKE_CXX_FLAGS 103 | CMAKE_CXX_FLAGS_DEBUG 104 | CMAKE_CXX_FLAGS_RELEASE 105 | CMAKE_C_FLAGS 106 | CMAKE_C_FLAGS_DEBUG 107 | CMAKE_C_FLAGS_RELEASE 108 | ) 109 | foreach(CompilerFlag ${CompilerFlags}) 110 | string(REPLACE "/MDd" "/MD" ${CompilerFlag} "${${CompilerFlag}}") 111 | string(REPLACE "/RTC1" "" ${CompilerFlag} "${${CompilerFlag}}") 112 | endforeach() 113 | 114 | else (MSVC) 115 | add_compile_options( 116 | -Wno-deprecated # Silence deprecation warnings due to USD headers. 117 | -std=c++14 118 | ) 119 | 120 | endif (MSVC) 121 | 122 | # PIC is necessary for building the plugin shared library. 123 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 124 | 125 | # Set RPATH to locate USD shared libraries on Linux/OSX. 126 | set(CMAKE_INSTALL_RPATH "${USD_DIR}/lib") 127 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 128 | 129 | add_subdirectory(common) 130 | add_subdirectory(convert) 131 | add_subdirectory(gltf) 132 | add_subdirectory(process) 133 | add_subdirectory(usd_from_gltf) 134 | add_subdirectory(ufg_plugin) 135 | 136 | install(EXPORT ufglib DESTINATION lib/ufg) 137 | install(FILES ufg-config.cmake DESTINATION .) 138 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include_directories( 16 | .. 17 | ${USD_INCLUDE_DIRS} 18 | ) 19 | 20 | add_library(common 21 | common.h 22 | common_util.h 23 | config.cc 24 | config.h 25 | logging.cc 26 | logging.h 27 | messages.inl 28 | platform.cc 29 | platform.h 30 | ) 31 | 32 | file(GLOB COMMON_HEADERS "*.h") 33 | set_target_properties(common PROPERTIES PUBLIC_HEADER "${COMMON_HEADERS}") 34 | 35 | target_link_libraries(common gltf) 36 | 37 | install(TARGETS common EXPORT ufglib DESTINATION lib/ufg PUBLIC_HEADER DESTINATION include/ufg/common) 38 | -------------------------------------------------------------------------------- /common/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_COMMON_COMMON_H_ 18 | #define UFG_COMMON_COMMON_H_ 19 | 20 | #include 21 | #include "common/platform.h" 22 | 23 | // Disable warnings originating in the USD headers. 24 | #ifdef _MSC_VER 25 | #pragma warning(push) 26 | #pragma warning(disable : 4244) // Conversion from 'double' to 'float'. 27 | #pragma warning(disable : 4305) // Truncation from 'double' to 'float'. 28 | #endif // _MSC_VER 29 | #include "pxr/base/gf/bbox3d.h" 30 | #include "pxr/base/gf/matrix3d.h" 31 | #include "pxr/base/gf/matrix3f.h" 32 | #include "pxr/base/gf/matrix4d.h" 33 | #include "pxr/base/gf/matrix4f.h" 34 | #include "pxr/base/gf/quatd.h" 35 | #include "pxr/base/gf/quatf.h" 36 | #include "pxr/base/gf/quath.h" 37 | #include "pxr/base/gf/range3f.h" 38 | #include "pxr/base/gf/rotation.h" 39 | #include "pxr/base/gf/vec2d.h" 40 | #include "pxr/base/gf/vec2f.h" 41 | #include "pxr/base/gf/vec3d.h" 42 | #include "pxr/base/gf/vec3f.h" 43 | #include "pxr/base/gf/vec3h.h" 44 | #include "pxr/base/gf/vec4d.h" 45 | #include "pxr/base/gf/vec4f.h" 46 | #include "pxr/base/gf/vec4h.h" 47 | #ifdef _MSC_VER 48 | #pragma warning(pop) 49 | #endif // _MSC_VER 50 | 51 | // Enable asserts. 52 | // * This only increases executation time by ~5%, so it's enabled in all builds. 53 | #define UFG_ASSERTS 1 54 | 55 | #if _MSC_VER 56 | #define UFG_BREAK_ON_ASSERT (1 && UFG_ASSERTS) 57 | #else // _MSC_VER 58 | #define UFG_BREAK_ON_ASSERT 0 59 | #endif // _MSC_VER 60 | 61 | namespace ufg { 62 | // NOLINTNEXTLINE: Disable warning about old-style cast (it's not a cast!) 63 | template char(&ArraySizeHelper(T(&)[LEN]))[LEN]; 64 | #define UFG_ARRAY_SIZE(array) (sizeof(ufg::ArraySizeHelper(array))) 65 | 66 | #define UFG_CONST_STRLEN(s) (UFG_ARRAY_SIZE(s) - 1) 67 | 68 | template 69 | inline constexpr T Square(T a) { 70 | return a * a; 71 | } 72 | } // namespace ufg 73 | 74 | #endif // UFG_COMMON_COMMON_H_ 75 | -------------------------------------------------------------------------------- /common/common_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_COMMON_COMMON_UTIL_H_ 18 | #define UFG_COMMON_COMMON_UTIL_H_ 19 | 20 | #include 21 | #include 22 | #include "common/common.h" 23 | 24 | namespace ufg { 25 | // Return std::vector data, or null if the vector is empty. 26 | template 27 | inline typename Vector::value_type* GetDataOrNull(Vector& v) { 28 | return v.empty() ? nullptr : v.data(); 29 | } 30 | template 31 | inline const typename Vector::value_type* GetDataOrNull(const Vector& v) { 32 | return v.empty() ? nullptr : v.data(); 33 | } 34 | 35 | struct FileReference { 36 | std::string disk_path; 37 | std::string usd_path; 38 | friend bool operator<(const FileReference& a, const FileReference& b) { 39 | return a.usd_path < b.usd_path; 40 | } 41 | friend bool operator==(const FileReference& a, const FileReference& b) { 42 | return a.usd_path == b.usd_path; 43 | } 44 | friend bool operator!=(const FileReference& a, const FileReference& b) { 45 | return a.usd_path != b.usd_path; 46 | } 47 | }; 48 | 49 | inline std::string AppendNumber(const char* prefix, size_t prefix_len, 50 | size_t index) { 51 | const size_t len_max = prefix_len + 24; 52 | std::string text(len_max, 0); 53 | const size_t len = snprintf(&text[0], len_max, "%s%zu", prefix, index); 54 | text.resize(len); 55 | return text; 56 | } 57 | 58 | inline std::string AppendNumber(const char* prefix, size_t index) { 59 | return AppendNumber(prefix, strlen(prefix), index); 60 | } 61 | 62 | inline std::string AppendNumber(const std::string& prefix, size_t index) { 63 | return AppendNumber(prefix.c_str(), prefix.length(), index); 64 | } 65 | 66 | inline std::string AddFileNameSuffix(const std::string& path, 67 | const char* suffix) { 68 | const size_t last_dot_pos = path.rfind('.'); 69 | if (last_dot_pos == std::string::npos) { 70 | return path + suffix; 71 | } else { 72 | const char* const ext = path.c_str() + last_dot_pos; 73 | return path.substr(0, last_dot_pos) + suffix + ext; 74 | } 75 | } 76 | 77 | inline const char* GetFileName(const std::string& path) { 78 | const size_t last_slash_pos = path.find_last_of("\\/"); 79 | return last_slash_pos == std::string::npos 80 | ? path.c_str() 81 | : path.c_str() + last_slash_pos + 1; 82 | } 83 | 84 | inline std::string GetFileDirectory(const std::string& path) { 85 | const size_t last_slash_pos = path.find_last_of("\\/"); 86 | return last_slash_pos == std::string::npos 87 | ? std::string() 88 | : std::string(path.c_str(), last_slash_pos); 89 | } 90 | } // namespace ufg 91 | 92 | #endif // UFG_COMMON_COMMON_UTIL_H_ 93 | -------------------------------------------------------------------------------- /common/config.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "common/config.h" 18 | 19 | namespace ufg { 20 | const GfVec3f kColorBlack(0.0f, 0.0f, 0.0f); 21 | const GfVec4f kFallbackBase(1.0f, 0.0f, 1.0f, 1.0f); 22 | const GfVec3f kFallbackDiffuse(1.0f, 0.0f, 1.0f); 23 | const GfVec3f kFallbackNormal(0.0f, 0.0f, 1.0f); 24 | const GfVec3f kFallbackEmissive(0.5f, 0.0f, 0.5f); 25 | const GfVec3f kFallbackSpecular(1.0f, 0.0f, 1.0f); 26 | 27 | const ConvertSettings ConvertSettings::kDefault; 28 | } // namespace ufg 29 | -------------------------------------------------------------------------------- /common/logging.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "common/logging.h" 18 | 19 | namespace ufg { 20 | namespace { 21 | constexpr size_t kFormatTextMax = 8 * 1024; 22 | constexpr size_t kOnceNameMax = 3; 23 | 24 | constexpr Severity WHAT_SEVERITY_INFO = kSeverityNone; // NOLINT: unused 25 | constexpr Severity WHAT_SEVERITY_WARN = kSeverityWarning; 26 | constexpr Severity WHAT_SEVERITY_ERROR = kSeverityError; 27 | 28 | std::string GetAssertText(const char* file, int line, const char* expression) { 29 | char text[kFormatTextMax]; 30 | snprintf(text, sizeof(text), "%s(%d) : ASSERT(%s)", file, line, expression); 31 | return text; 32 | } 33 | } // namespace 34 | 35 | const WhatInfo kWhatInfos[UFG_WHAT_COUNT] = { 36 | #define UFG_MSG(severity, id, format) \ 37 | {WHAT_SEVERITY_##severity, "UFG_" #severity "_" #id, format}, 38 | #include "messages.inl" // NOLINT: Multiple inclusion. 39 | }; 40 | 41 | AssertException::AssertException(const char* file, int line, 42 | const char* expression) 43 | : std::runtime_error(GetAssertText(file, line, expression)), 44 | file_(file), 45 | line_(line), 46 | expression_(expression) {} 47 | 48 | ProfileSentry::ProfileSentry(const char* label, bool enable) 49 | : label_(enable ? label : nullptr) { 50 | if (label_) { 51 | time_begin_ = std::clock(); 52 | } 53 | } 54 | 55 | ProfileSentry::~ProfileSentry() { 56 | if (label_) { 57 | const std::clock_t time_end = std::clock(); 58 | const float elapsed = 59 | static_cast(time_end - time_begin_) / CLOCKS_PER_SEC; 60 | printf("%s: Completed in %.3f seconds.\n", label_, elapsed); 61 | } 62 | } 63 | } // namespace ufg 64 | -------------------------------------------------------------------------------- /common/messages.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_MSG0 18 | #define UFG_MSG0(severity, id, format, ...) UFG_MSG(severity, id, format) 19 | #define UFG_MSG1(severity, id, format, ...) UFG_MSG(severity, id, format) 20 | #define UFG_MSG2(severity, id, format, ...) UFG_MSG(severity, id, format) 21 | #define UFG_MSG3(severity, id, format, ...) UFG_MSG(severity, id, format) 22 | #define UFG_MSG4(severity, id, format, ...) UFG_MSG(severity, id, format) 23 | #define UFG_MSG5(severity, id, format, ...) UFG_MSG(severity, id, format) 24 | #define UFG_MSG6(severity, id, format, ...) UFG_MSG(severity, id, format) 25 | #endif // UFG_MSG0 26 | 27 | UFG_MSG3(ERROR, ASSERT , "%s(%d) : ASSERT(%s)", const char*, file, int, line, const char*, expression) 28 | UFG_MSG1(ERROR, LOAD_PLUGINS , "Unable to load USD plugins. %s", const char*, why) 29 | UFG_MSG1(ERROR, ARGUMENT_UNKNOWN , "Unknown flag: %s", const char*, text) 30 | UFG_MSG0(ERROR, ARGUMENT_PATHS , "Non-even number of paths. Expected: src dst [src dst ...].") 31 | UFG_MSG2(ERROR, ARGUMENT_EXCEPTION , "%s: %s", const char*, id, const char*, err) 32 | UFG_MSG1(ERROR, IO_WRITE_USD , "Cannot write USD: \"%s\"", const char*, path) 33 | UFG_MSG1(ERROR, IO_WRITE_IMAGE , "Cannot write image: \"%s\"", const char*, path) 34 | UFG_MSG1(WARN , IO_DELETE , "Cannot delete file: %s", const char*, path) 35 | UFG_MSG1(ERROR, STOMP , "Would stomp source file: \"%s\"", const char*, path) 36 | UFG_MSG4(WARN , NON_TRIANGLES , "Skipping unsupported %s primitive. Mesh: mesh[%zu].primitives[%zu], name=%s", const char*, prim_type, size_t, mesh_i, size_t, prim_i, const char*, name) 37 | UFG_MSG3(WARN , TEXTURE_LIMIT , "Can't make %zu texture(s) fit in decompressed limit (%zu bytes). Reducing to minimum (%zu bytes).", size_t, count, size_t, decompressed_limit, size_t, decompressed_total) 38 | UFG_MSG2(ERROR, LAYER_CREATE , "Cannot create layer '%s' at: %s", const char*, src_name, const char*, dst_path) 39 | UFG_MSG2(ERROR, USD , "USD: %s (%s)", const char*, commentary, const char*, function) 40 | UFG_MSG2(WARN , USD , "USD: %s (%s)", const char*, commentary, const char*, function) 41 | UFG_MSG2(INFO , USD , "USD: %s (%s)", const char*, commentary, const char*, function) 42 | UFG_MSG2(ERROR, USD_FATAL , "USD: FATAL: %s (%s)", const char*, commentary, const char*, function) 43 | UFG_MSG0(WARN , ALPHA_MASK_UNSUPPORTED , "Alpha mask currently unsupported.") 44 | UFG_MSG0(WARN , CAMERAS_UNSUPPORTED , "Cameras currently unsupported.") 45 | UFG_MSG0(WARN , MORPH_TARGETS_UNSUPPORTED , "Morph targets currently unsupported.") 46 | UFG_MSG0(WARN , MULTIPLE_UVSETS_UNSUPPORTED , "Multiple UV sets unsupported on iOS viewer.") 47 | UFG_MSG0(WARN , SECONDARY_UVSET_DISABLED , "Disabling secondary UV set.") 48 | UFG_MSG0(WARN , SPECULAR_WORKFLOW_UNSUPPORTED, "Specular workflow unsupported on iOS viewer.") 49 | UFG_MSG2(WARN , TEXTURE_WRAP_UNSUPPORTED , "Texture wrap mode [S=%s, T=%s] unsupported on iOS viewer.", const char*, s_mode, const char*, t_mode) 50 | UFG_MSG2(WARN , TEXTURE_FILTER_UNSUPPORTED , "Texture filter mode [min=%s, mag=%s] unsupported on iOS viewer.", const char*, min_filter, const char*, mag_filter) 51 | UFG_MSG0(WARN , VERTEX_COLORS_UNSUPPORTED , "Vertex colors currently unsupported.") 52 | UFG_MSG0(ERROR, IMAGE_FALLBACK_DECODE , "Failed decoding image with fallback decoder.") 53 | UFG_MSG1(ERROR, GIF_RECORD_TYPE , "GIF: Failed getting record type. Error code: %d", int, code) 54 | UFG_MSG1(ERROR, GIF_IMAGE_DESC , "GIF: Failed getting image desc. Error code: %d", int, code) 55 | UFG_MSG1(ERROR, GIF_EXTENSION , "GIF: Failed getting extension. Error code: %d", int, code) 56 | UFG_MSG0(ERROR, GIF_BAD_GCB , "GIF: Invalid Graphics Control Block (GCB).") 57 | UFG_MSG0(ERROR, GIF_NO_RECORDS , "GIF: No image records.") 58 | UFG_MSG1(ERROR, GIF_OPEN , "GIF: Failed opening with error code: %d", int, code) 59 | UFG_MSG2(ERROR, GIF_BAD_SIZE , "GIF: Unexpected image size: <%d, %d>", int, width, int, height) 60 | UFG_MSG6(ERROR, GIF_FRAME_BOUNDS , "GIF: Frame 0 bounds <%u, %u>-<%u, %u> exceeds image size <%u, %u>", uint32_t, x0, uint32_t, y0, uint32_t, x1, uint32_t, y1, uint32_t, width, uint32_t, height) 61 | UFG_MSG1(ERROR, JPG_DECODE_HEADER , "JPG: Failed decoding header with error: %s", const char*, info) 62 | UFG_MSG1(ERROR, JPG_DECOMPRESS , "JPG: Failed decompressing with error: %s", const char*, info) 63 | UFG_MSG1(ERROR, JPG_COMPRESS , "JPG: Failed compressing with error: %s", const char*, info) 64 | UFG_MSG1(ERROR, PNG_DECODE , "PNG: %s", const char*, info) 65 | UFG_MSG1(WARN , PNG_DECODE , "PNG: %s", const char*, info) 66 | UFG_MSG1(ERROR, PNG_ENCODE , "PNG: %s", const char*, info) 67 | UFG_MSG1(WARN , PNG_ENCODE , "PNG: %s", const char*, info) 68 | UFG_MSG0(ERROR, PNG_READ_INIT , "PNG: Failed to initialize for read.") 69 | UFG_MSG2(ERROR, PNG_READ_SHORT , "PNG: Attempt to read %zu bytes, only %zu remain.", size_t, size, size_t, remain) 70 | UFG_MSG0(ERROR, PNG_WRITE_INIT , "PNG: Failed to initialize for write.") 71 | UFG_MSG3(ERROR, DRACO_UNKNOWN , "Draco: Cannot determine geometry type for mesh: mesh[%zu].primitives[%zu], name=%s", size_t, mesh_i, size_t, prim_i, const char*, name) 72 | UFG_MSG3(ERROR, DRACO_LOAD , "Draco: Cannot load data for mesh: mesh[%zu].primitives[%zu], name=%s", size_t, mesh_i, size_t, prim_i, const char*, name) 73 | UFG_MSG3(ERROR, DRACO_DECODE , "Draco: Failed to decode mesh: mesh[%zu].primitives[%zu], name=%s", size_t, mesh_i, size_t, prim_i, const char*, name) 74 | UFG_MSG3(ERROR, DRACO_NON_TRIANGLES , "Draco: Non-triangular mesh: mesh[%zu].primitives[%zu], name=%s", size_t, mesh_i, size_t, prim_i, const char*, name) 75 | 76 | #undef UFG_MSG 77 | #undef UFG_MSG0 78 | #undef UFG_MSG1 79 | #undef UFG_MSG2 80 | #undef UFG_MSG3 81 | #undef UFG_MSG4 82 | #undef UFG_MSG5 83 | #undef UFG_MSG6 84 | -------------------------------------------------------------------------------- /common/platform.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "common/platform.h" 18 | 19 | #ifdef _MSC_VER 20 | #include 21 | #pragma warning(disable : 4996) // 'getcwd' POSIX name is deprecated. 22 | #else // _MSC_VER 23 | #include 24 | #include 25 | #include 26 | #endif // _MSC_VER 27 | 28 | namespace ufg { 29 | std::string GetCwd() { 30 | char buffer[4 * 1024]; 31 | const char* const dir = getcwd(buffer, sizeof(buffer)); 32 | return dir ? dir : std::string(); 33 | } 34 | 35 | void SetCwd(const char* dir) { 36 | if (dir && dir[0]) { 37 | chdir(dir); 38 | } 39 | } 40 | } // namespace ufg 41 | -------------------------------------------------------------------------------- /common/platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_COMMON_PLATFORM_H_ 18 | #define UFG_COMMON_PLATFORM_H_ 19 | 20 | #include 21 | 22 | // Used for DebugBreak. 23 | #ifdef _MSC_VER 24 | #define NOMINMAX 25 | #define WIN32_LEAN_AND_MEAN 26 | #include 27 | 28 | #ifdef ERROR 29 | #undef ERROR 30 | #endif // ERROR 31 | #endif // _MSC_VER 32 | 33 | namespace ufg { 34 | std::string GetCwd(); 35 | void SetCwd(const char* dir); 36 | } // namespace ufg 37 | 38 | #endif // UFG_COMMON_PLATFORM_H_ 39 | -------------------------------------------------------------------------------- /common/scheduler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "common/scheduler.h" 18 | 19 | #include "common/logging.h" 20 | 21 | namespace ufg { 22 | namespace { 23 | constexpr size_t kWorkerMax = 64; 24 | } // namespace 25 | 26 | Scheduler::Scheduler() : stopping_(false) { 27 | } 28 | 29 | void Scheduler::Start(size_t worker_count) { 30 | worker_count = std::min(worker_count, kWorkerMax); 31 | 32 | UFG_ASSERT_LOGIC(!stopping_); 33 | UFG_ASSERT_LOGIC(workers_.empty()); 34 | UFG_ASSERT_LOGIC(job_queue_.empty()); 35 | stopping_ = false; 36 | workers_.reserve(worker_count); 37 | for (size_t worker_index = 0; worker_index != worker_count; ++worker_index) { 38 | workers_.emplace_back(WorkerThread, this, worker_index); 39 | } 40 | } 41 | 42 | void Scheduler::Stop() { 43 | { 44 | std::unique_lock lock(mutex_); 45 | stopping_ = true; 46 | add_or_stop_event_.notify_all(); 47 | } 48 | for (std::thread& worker : workers_) { 49 | worker.join(); 50 | } 51 | if (!exceptions_.empty()) { 52 | std::rethrow_exception(exceptions_.front()); 53 | } 54 | workers_.clear(); 55 | UFG_ASSERT_LOGIC(job_queue_.empty()); 56 | } 57 | 58 | void Scheduler::WaitForAllComplete() { 59 | std::queue exceptions; 60 | for (;;) { 61 | std::unique_lock lock(mutex_); 62 | if (job_queue_.empty()) { 63 | exceptions.swap(exceptions_); 64 | break; 65 | } 66 | job_done_event_.wait(lock); 67 | } 68 | if (!exceptions.empty()) { 69 | std::rethrow_exception(exceptions.front()); 70 | } 71 | } 72 | 73 | void Scheduler::WorkerThread(Scheduler* scheduler, size_t index) { 74 | while (!scheduler->stopping_) { 75 | bool have_job = false; 76 | JobFunction func; 77 | { 78 | std::unique_lock lock(scheduler->mutex_); 79 | if (!scheduler->job_queue_.empty()) { 80 | func.swap(scheduler->job_queue_.front().func); 81 | scheduler->job_queue_.pop(); 82 | have_job = true; 83 | } else { 84 | // Wait for a job to become available, or the signal to stop. 85 | // * Don't wait if we're stopping so the event isn't prematurely cleared 86 | // (which could cause a deadlock). 87 | if (!scheduler->stopping_) { 88 | scheduler->add_or_stop_event_.wait(lock); 89 | if (scheduler->stopping_) { 90 | // Waiting on the event clears it, so we need to re-signal it to 91 | // ensure any remaining workers wake up to stop. 92 | scheduler->add_or_stop_event_.notify_all(); 93 | } 94 | } 95 | } 96 | } 97 | if (have_job) { 98 | try { 99 | func(); 100 | } catch (...) { 101 | std::unique_lock lock(scheduler->mutex_); 102 | scheduler->exceptions_.push(std::current_exception()); 103 | } 104 | scheduler->job_done_event_.notify_all(); 105 | } 106 | } 107 | } 108 | 109 | void Scheduler::AddJob(JobFunction&& func) { 110 | std::unique_lock lock(mutex_); 111 | job_queue_.push(Job(std::move(func))); 112 | add_or_stop_event_.notify_all(); 113 | } 114 | } // namespace ufg 115 | -------------------------------------------------------------------------------- /common/scheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_COMMON_SCHEDULER_H_ 18 | #define UFG_COMMON_SCHEDULER_H_ 19 | 20 | #include // NOLINT: Unapproved C++11 header. 21 | #include 22 | #include // NOLINT: Unapproved C++11 header. 23 | #include 24 | #include // NOLINT: Unapproved C++11 header. 25 | #include 26 | #include "common/common.h" 27 | #include "common/platform.h" 28 | 29 | namespace ufg { 30 | // Simple multithreaded job scheduler, used to run conversion tasks in parallel. 31 | class Scheduler { 32 | public: 33 | Scheduler(); 34 | 35 | // Start worker threads. 36 | // * If worker_count is 0, the scheduler runs jobs immediately in the calling 37 | // thread. 38 | void Start(size_t worker_count); 39 | 40 | // Stop worker threads. This will wait for all queued jobs to complete. 41 | void Stop(); 42 | 43 | // Schedule a function to run on a worker thread. 44 | // * The function should have a void() signature. 45 | template 46 | void Schedule(Func func) { 47 | if (workers_.empty()) { 48 | func(); 49 | } else { 50 | AddJob(JobFunction(func)); 51 | } 52 | } 53 | 54 | // Wait for all scheduled jobs to complete. 55 | void WaitForAllComplete(); 56 | 57 | private: 58 | using JobFunction = std::function; 59 | struct Job { 60 | JobFunction func; 61 | Job() {} 62 | explicit Job(JobFunction&& func) : func(func) {} 63 | }; 64 | bool stopping_; 65 | std::condition_variable add_or_stop_event_; 66 | std::condition_variable job_done_event_; 67 | std::mutex mutex_; 68 | std::vector workers_; 69 | std::queue job_queue_; 70 | std::queue exceptions_; 71 | 72 | static void WorkerThread(Scheduler* scheduler, size_t index); 73 | void AddJob(JobFunction&& func); 74 | }; 75 | } // namespace ufg 76 | #endif // UFG_COMMON_SCHEDULER_H_ 77 | -------------------------------------------------------------------------------- /convert/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include_directories( 16 | .. 17 | ${USD_INCLUDE_DIRS} 18 | ) 19 | 20 | add_library(convert 21 | tokens.cc 22 | tokens.h 23 | convert_common.h 24 | convert_context.h 25 | convert_util.cc 26 | convert_util.h 27 | converter.cc 28 | converter.h 29 | materializer.cc 30 | materializer.h 31 | package.cc 32 | package.h 33 | texturator.cc 34 | texturator.h 35 | ) 36 | 37 | file(GLOB CONVERT_HEADERS "*.h") 38 | set_target_properties(convert PROPERTIES PUBLIC_HEADER "${CONVERT_HEADERS}") 39 | 40 | target_link_libraries(convert process) 41 | 42 | install(TARGETS convert EXPORT ufglib DESTINATION lib/ufg PUBLIC_HEADER DESTINATION include/ufg/convert) 43 | -------------------------------------------------------------------------------- /convert/convert_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_CONVERT_COMMON_H_ 18 | #define UFG_CONVERT_CONVERT_COMMON_H_ 19 | 20 | #include "common/common.h" 21 | 22 | // Disable warnings originating in the USD headers. 23 | #ifdef _MSC_VER 24 | #pragma warning(push) 25 | // not enough actual parameters for macro 'BOOST_*' 26 | #pragma warning(disable : 4003) 27 | // conversion from 'Py_ssize_t' to 'unsigned int', possible loss of data 28 | #pragma warning(disable : 4244) 29 | // conversion from 'size_t' to 'int', possible loss of data 30 | #pragma warning(disable : 4267) 31 | #endif // _MSC_VER 32 | 33 | #include "pxr/usd/usdGeom/scope.h" 34 | #include "pxr/usd/usdGeom/xform.h" 35 | #include "pxr/usd/usdShade/material.h" 36 | #include "pxr/usd/usdShade/shader.h" 37 | 38 | #ifdef _MSC_VER 39 | #pragma warning(pop) 40 | #endif // _MSC_VER 41 | 42 | #endif // UFG_CONVERT_CONVERT_COMMON_H_ 43 | -------------------------------------------------------------------------------- /convert/convert_context.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_CONVERT_CONTEXT_H_ 18 | #define UFG_CONVERT_CONVERT_CONTEXT_H_ 19 | 20 | #include "common/common.h" 21 | #include "common/common_util.h" 22 | #include "common/config.h" 23 | #include "common/logging.h" 24 | #include "convert/convert_util.h" 25 | #include "gltf/cache.h" 26 | #include "gltf/gltf.h" 27 | 28 | namespace ufg { 29 | using PXR_NS::UsdStageRefPtr; 30 | 31 | struct ConvertContext { 32 | std::string src_dir; 33 | std::string dst_dir; 34 | ConvertSettings settings; 35 | const Gltf* gltf; 36 | PathTable path_table; 37 | GltfCache gltf_cache; 38 | Logger* logger; 39 | GltfOnceLogger once_logger; 40 | UsdStageRefPtr stage; 41 | SdfPath root_path; 42 | 43 | void Reset(Logger* logger) { 44 | src_dir.clear(); 45 | dst_dir.clear(); 46 | settings = ConvertSettings::kDefault; 47 | gltf = nullptr; 48 | path_table.Clear(); 49 | gltf_cache.Reset(); 50 | this->logger = logger; 51 | once_logger.Reset(logger); 52 | stage = UsdStageRefPtr(); 53 | root_path = SdfPath::EmptyPath(); 54 | } 55 | }; 56 | } // namespace ufg 57 | 58 | #endif // UFG_CONVERT_CONVERT_CONTEXT_H_ 59 | -------------------------------------------------------------------------------- /convert/convert_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "convert/convert_util.h" 18 | 19 | #include "common/common_util.h" 20 | #include "common/config.h" 21 | #include "pxr/base/tf/stringUtils.h" 22 | 23 | namespace ufg { 24 | std::string MakeValidUsdName(const char* prefix, const std::string& in, 25 | size_t index) { 26 | return in.empty() ? AppendNumber(prefix, index) 27 | : PXR_NS::TfMakeValidIdentifier(in); 28 | } 29 | 30 | UsdTimeCode GetTimeCode(float t) { 31 | const float s = kFps * t; 32 | const float r = std::roundf(s); 33 | return UsdTimeCode(std::abs(s - r) < kSnapTimeCodeTol ? r : s); 34 | } 35 | 36 | void PathTable::Clear() { 37 | paths_.clear(); 38 | } 39 | 40 | std::string PathTable::MakeUnique(const SdfPath& parent_path, 41 | const char* prefix, const std::string& in, 42 | size_t index) { 43 | const std::string orig_name = MakeValidUsdName(prefix, in, index); 44 | std::string name = orig_name; 45 | size_t duplicate_count = 0; 46 | for (;;) { 47 | const SdfPath path = parent_path.AppendElementString(name); 48 | const std::string& path_str = path.GetString(); 49 | const auto insert_result = paths_.insert(path_str); 50 | if (insert_result.second) { 51 | return path_str; 52 | } 53 | name = AppendNumber(orig_name + '_', ++duplicate_count); 54 | } 55 | } 56 | 57 | } // namespace ufg 58 | -------------------------------------------------------------------------------- /convert/convert_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_CONVERT_UTIL_H_ 18 | #define UFG_CONVERT_CONVERT_UTIL_H_ 19 | 20 | #include 21 | #include 22 | #include "convert/convert_common.h" 23 | #include "convert/tokens.h" 24 | #include "gltf/gltf.h" 25 | #include "pxr/base/tf/token.h" 26 | #include "pxr/usd/sdf/types.h" 27 | #include "pxr/usd/usd/timeCode.h" 28 | #include "pxr/usd/usdShade/shader.h" 29 | 30 | namespace ufg { 31 | using PXR_NS::TfToken; 32 | using PXR_NS::UsdShadeShader; 33 | using PXR_NS::UsdTimeCode; 34 | using PXR_NS::SdfPath; 35 | using PXR_NS::SdfValueTypeNames; 36 | 37 | std::string MakeValidUsdName(const char* prefix, const std::string& in, 38 | size_t index); 39 | 40 | inline std::string MakeValidUsdName(const char* prefix, const std::string& in, 41 | Gltf::Id id) { 42 | return MakeValidUsdName(prefix, in, Gltf::IdToIndex(id)); 43 | } 44 | 45 | template 46 | void CreateEnumInput(const TfToken& name_tok, T value, 47 | const TfToken& default_tok, UsdShadeShader* tex) { 48 | const TfToken& value_tok = ToToken(value); 49 | if (value_tok != default_tok) { 50 | tex->CreateInput(name_tok, SdfValueTypeNames->Token).Set(value_tok); 51 | } 52 | } 53 | 54 | UsdTimeCode GetTimeCode(float t); 55 | 56 | class PathTable { 57 | public: 58 | void Clear(); 59 | std::string MakeUnique(const SdfPath& parent_path, const char* prefix, 60 | const std::string& in, size_t index); 61 | 62 | private: 63 | std::unordered_set paths_; 64 | }; 65 | } // namespace ufg 66 | 67 | #endif // UFG_CONVERT_CONVERT_UTIL_H_ 68 | -------------------------------------------------------------------------------- /convert/converter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_CONVERTER_H_ 18 | #define UFG_CONVERT_CONVERTER_H_ 19 | 20 | #include 21 | #include 22 | #include "common/common_util.h" 23 | #include "common/config.h" 24 | #include "convert/convert_common.h" 25 | #include "convert/convert_context.h" 26 | #include "convert/convert_util.h" 27 | #include "convert/materializer.h" 28 | #include "gltf/gltf.h" 29 | #include "process/animation.h" 30 | #include "process/image.h" 31 | #include "process/mesh.h" 32 | #include "process/skin.h" 33 | #include "pxr/usd/sdf/layer.h" 34 | #include "pxr/usd/sdf/path.h" 35 | #include "pxr/base/tf/token.h" 36 | #include "pxr/base/vt/array.h" 37 | #include "pxr/usd/usd/stage.h" 38 | #include "pxr/usd/usdShade/material.h" 39 | #include "pxr/usd/usdShade/shader.h" 40 | 41 | namespace ufg { 42 | using PXR_NS::SdfLayerRefPtr; 43 | using PXR_NS::SdfPath; 44 | using PXR_NS::SdfValueTypeName; 45 | using PXR_NS::TfToken; 46 | using PXR_NS::UsdShadeMaterial; 47 | using PXR_NS::UsdShadeShader; 48 | using PXR_NS::UsdStageRefPtr; 49 | using PXR_NS::VtArray; 50 | 51 | class Converter { 52 | public: 53 | void Reset(Logger* logger); 54 | bool Convert(const ConvertSettings& settings, const Gltf& gltf, 55 | GltfStream* gltf_stream, const std::string& src_dir, 56 | const std::string& dst_dir, const std::string& dst_filename, 57 | const SdfLayerRefPtr& layer, Logger* logger); 58 | const std::vector& GetWritten() const { 59 | return materializer_.GetWritten(); 60 | } 61 | const std::vector& GetCreatedDirectories() const { 62 | return materializer_.GetCreatedDirectories(); 63 | } 64 | 65 | private: 66 | struct SkinnedMeshContext { 67 | SdfPath skeleton_path; 68 | SdfPath anim_path; 69 | const uint16_t* gjoint_to_ujoint_map; 70 | size_t gjoint_count; 71 | const GfMatrix3f* bake_norm_mats; // Null if not baking normals. 72 | }; 73 | 74 | ConvertContext cc_; 75 | Pass curr_pass_; 76 | Materializer materializer_; 77 | 78 | // TODO: A node can exist in multiple places in the hierarchy, so 79 | // each node could have multiple parents. I haven't found any models that 80 | // actually do this, though. 81 | std::vector node_parents_; 82 | 83 | NodeInfo root_node_info_; 84 | std::vector node_infos_; 85 | std::vector mesh_infos_; 86 | std::vector used_skin_infos_; 87 | std::vector gltf_skin_srcs_; 88 | AnimInfo anim_info_; 89 | UsdShadeMaterial debug_bone_material_; 90 | 91 | void CreateStage(const SdfLayerRefPtr& layer, 92 | const std::string& dst_filename); 93 | void CreateDebugBoneMesh(const SdfPath& parent_path, bool reverse_winding); 94 | void CreateSkeleton(const SdfPath& path, const SkinInfo& skin_info); 95 | GfVec3f CreateSkelAnim(const SdfPath& path, const SkinInfo& skin_info, 96 | const AnimInfo& anim_info, 97 | std::vector* out_frame0_rots, 98 | std::vector* out_frame0_scales); 99 | void CreateMesh(size_t mesh_index, const SdfPath& parent_path, 100 | bool reverse_winding, 101 | const SkinnedMeshContext* skinned_mesh_context); 102 | void CreateSkinnedMeshes(const SdfPath& parent_path, 103 | const std::vector& node_ids, 104 | bool reverse_winding); 105 | void CreateNodeHierarchy(Gltf::Id node_id, const SdfPath& parent_path, 106 | const GfMatrix4d& parent_world_mat); 107 | void CreateNodes(const std::vector& root_nodes); 108 | void CreateAnimation(const AnimInfo& anim_info); 109 | void ConvertImpl(const ConvertSettings& settings, const Gltf& gltf, 110 | GltfStream* gltf_stream, const std::string& src_dir, 111 | const std::string& dst_dir, const std::string& dst_filename, 112 | const SdfLayerRefPtr& layer, Logger* logger); 113 | }; 114 | 115 | } // namespace ufg 116 | 117 | #endif // UFG_CONVERT_CONVERTER_H_ 118 | -------------------------------------------------------------------------------- /convert/materializer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_MATERIALIZER_H_ 18 | #define UFG_CONVERT_MATERIALIZER_H_ 19 | 20 | #include 21 | #include "common/common_util.h" 22 | #include "common/config.h" 23 | #include "common/logging.h" 24 | #include "convert/convert_common.h" 25 | #include "convert/convert_context.h" 26 | #include "convert/convert_util.h" 27 | #include "convert/texturator.h" 28 | #include "gltf/cache.h" 29 | #include "gltf/gltf.h" 30 | #include "process/image.h" 31 | #include "pxr/usd/sdf/path.h" 32 | #include "pxr/usd/usdGeom/scope.h" 33 | #include "pxr/usd/usdShade/material.h" 34 | #include "pxr/usd/usdShade/shader.h" 35 | 36 | namespace ufg { 37 | using PXR_NS::SdfPath; 38 | using PXR_NS::SdfValueTypeName; 39 | using PXR_NS::TfToken; 40 | using PXR_NS::UsdGeomScope; 41 | using PXR_NS::UsdShadeMaterial; 42 | using PXR_NS::UsdShadeShader; 43 | using PXR_NS::UsdStageRefPtr; 44 | 45 | // Creates and caches USD materials. 46 | class Materializer { 47 | public: 48 | struct Uvset { 49 | UsdShadeShader shader; 50 | // TODO: It's possible for texture references in the material to 51 | // have different transforms but reference the same uvset. To handle this 52 | // properly, we'd need to duplicate the uvset and add a new plug for it in 53 | // the material. Since this isn't a common use-case, we can probably just 54 | // get away with forcing a uniform transform per uvset. 55 | Gltf::Material::Texture::Transform transform; 56 | }; 57 | using UvsetMap = std::map; 58 | 59 | struct Value { 60 | SdfPath path; 61 | UsdShadeMaterial material; 62 | UvsetMap uvsets; 63 | }; 64 | 65 | void Clear(); 66 | void Begin(ConvertContext* cc); 67 | void End(); 68 | const Value& FindOrCreate(Gltf::Id material_id); 69 | bool IsInvisible(Gltf::Id material_id); 70 | const std::vector& GetWritten() const { 71 | return texturator_.GetWritten(); 72 | } 73 | const std::vector& GetCreatedDirectories() const { 74 | return texturator_.GetCreatedDirectories(); 75 | } 76 | 77 | private: 78 | static const SdfPath kMaterialsPath; 79 | 80 | struct Key { 81 | Gltf::Material material; 82 | friend bool operator==(const Key& a, const Key& b) { 83 | return Gltf::Compare(a.material, b.material) == 0; 84 | } 85 | friend bool operator!=(const Key& a, const Key& b) { return !(a == b); } 86 | friend bool operator<(const Key& a, const Key& b) { 87 | return Gltf::Compare(a.material, b.material) < 0; 88 | } 89 | }; 90 | 91 | using Map = std::map; 92 | 93 | ConvertContext* cc_; 94 | UsdGeomScope scope_; 95 | Map materials_; 96 | Texturator texturator_; 97 | 98 | Texturator::Args GetDefaultTextureArgs() const; 99 | bool AddMaterialTextureUvset( 100 | Gltf::Id material_id, const SdfPath& material_path, 101 | const Gltf::Material::Texture& input, UvsetMap* uvsets); 102 | UsdShadeShader CreateTextureShader(uint32_t uvset_index, 103 | Gltf::Id sampler_id, 104 | const std::string& disk_path, 105 | const std::string& usd_path, 106 | const SdfPath& material_path, 107 | const UvsetMap& uvsets, const char* name); 108 | template 109 | void AttachTextureInputTo(const std::string& usd_name, Gltf::Id sampler_id, 110 | const Gltf::Material::Texture& input, 111 | const SdfPath& material_path, const char* tex_name, 112 | const TfToken& input_tok, 113 | const SdfValueTypeName& input_type, 114 | const Vec& scale, const Vec& fallback, 115 | const TfToken& connect_tok, 116 | const SdfValueTypeName& output_type, 117 | const bool is_normal, UvsetMap* uvsets, 118 | UsdShadeShader* pbr_shader); 119 | template 120 | void AttachTextureInput( 121 | const Texturator::Args& tex_args, const Gltf::Material::Texture& input, 122 | Gltf::Id material_id, const SdfPath& material_path, const char* tex_name, 123 | const TfToken& input_tok, const SdfValueTypeName& input_type, 124 | const Vec& fallback, const TfToken& connect_tok, 125 | const SdfValueTypeName& output_type, const bool is_normal, 126 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 127 | void AttachBaseTextureInput( 128 | const std::string* usd_name, const Texturator::Args& tex_args, 129 | const Gltf::Material::Texture& input, 130 | Gltf::Id material_id, const SdfPath& material_path, const TfToken& tok, 131 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 132 | void AttachBaseTextureInput( 133 | const Texturator::Args& tex_args, const Gltf::Material::Texture& input, 134 | Gltf::Id material_id, const SdfPath& material_path, const TfToken& tok, 135 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 136 | void AttachUnlitTextureInputs( 137 | Gltf::Id material_id, const SdfPath& material_path, 138 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 139 | void AttachMetallicRoughnessTextureInput( 140 | Gltf::Id material_id, const SdfPath& material_path, 141 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 142 | void AttachSpecularGlossinessTextureInput( 143 | Gltf::Id material_id, const SdfPath& material_path, 144 | UvsetMap* uvsets, UsdShadeShader* pbr_shader); 145 | }; 146 | 147 | } // namespace ufg 148 | 149 | #endif // UFG_CONVERT_MATERIALIZER_H_ 150 | -------------------------------------------------------------------------------- /convert/package.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_PACKAGE_H_ 18 | #define UFG_CONVERT_PACKAGE_H_ 19 | 20 | #include "common/common.h" 21 | #include "common/config.h" 22 | #include "common/logging.h" 23 | 24 | namespace ufg { 25 | // Register plugins at the given path. 26 | // This is optional - if it is not called, plugins are loaded using the system 27 | // path. 28 | bool RegisterPlugins(const std::string& path, Logger* logger); 29 | 30 | bool ConvertGltfToUsd(const char* src_gltf_path, const char* dst_usd_path, 31 | const ConvertSettings& settings, Logger* logger); 32 | } // namespace ufg 33 | 34 | #endif // UFG_CONVERT_PACKAGE_H_ 35 | -------------------------------------------------------------------------------- /convert/texturator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_TEXTURATOR_H_ 18 | #define UFG_CONVERT_TEXTURATOR_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "common/common_util.h" 25 | #include "convert/convert_context.h" 26 | #include "gltf/gltf.h" 27 | #include "process/color.h" 28 | #include "process/image.h" 29 | 30 | namespace ufg { 31 | // Performs texture reprocessing and caching. 32 | class Texturator { 33 | public: 34 | enum Usage : uint8_t { 35 | kUsageDefault, // Inputs: RGB:sRGB, A:linear 36 | kUsageLinear, // Inputs: RGB:sRGB, A:linear 37 | kUsageDiffToBase, // Inputs: RGB:sRGB, A:linear 38 | kUsageNorm, // Inputs: RGB:linear 39 | kUsageOccl, // Inputs: R:linear 40 | kUsageMetal, // Inputs: B:linear 41 | kUsageRough, // Inputs: G:linear 42 | kUsageSpec, // Inputs: RGB:sRGB 43 | kUsageSpecToMetal, // Inputs: RGB:sRGB 44 | kUsageGloss, // Inputs: A:linear 45 | kUsageGlossToRough, // Inputs: A:linear 46 | kUsageUnlitA, // Inputs: RGB:sRGB, A:linear 47 | kUsageCount 48 | }; 49 | 50 | enum Fallback : uint8_t { 51 | kFallbackBlack, 52 | kFallbackMagenta, 53 | kFallbackR0, 54 | kFallbackR1, 55 | kFallbackCount 56 | }; 57 | 58 | struct Args { 59 | Usage usage = kUsageDefault; 60 | Fallback fallback = kFallbackBlack; 61 | Gltf::Material::AlphaMode alpha_mode = Gltf::Material::kAlphaModeOpaque; 62 | float alpha_cutoff = 0.5f; 63 | float opacity = 1.f; 64 | ColorF scale = ColorF::kOne; 65 | ColorF bias = ColorF::kZero; 66 | ImageResizeSettings resize; 67 | }; 68 | 69 | void Clear(); 70 | void Begin(ConvertContext* cc); 71 | void End(); 72 | const std::string& Add(Gltf::Id image_id, const Args& args); 73 | void AddSpecToMetal(Gltf::Id spec_image_id, const Args& spec_args, 74 | Gltf::Id diff_image_id, const Args& diff_args, 75 | const std::string** out_metal_name, 76 | const std::string** out_base_name); 77 | 78 | // Get the constant alpha for an image, or -1 if the image has varying alpha. 79 | // * The image should already be added with Add(). 80 | // * Defaults to opaque alpha (Image::kComponentMax) if the source image 81 | // cannot be loaded. 82 | int GetSolidAlpha(Gltf::Id image_id); 83 | 84 | // Return true if textured alpha is effectively opaque. 85 | bool IsAlphaOpaque(Gltf::Id image_id, float scale, float bias); 86 | // Return true if textured alpha is fully transparent (solid 0). 87 | bool IsAlphaFullyTransparent(Gltf::Id image_id, float scale, float bias); 88 | 89 | const std::vector& GetWritten() const { return written_; } 90 | const std::vector& GetCreatedDirectories() const { 91 | return created_dirs_; 92 | } 93 | 94 | private: 95 | enum State : uint8_t { 96 | kStateNew, 97 | kStateLoaded, 98 | kStateMissing, 99 | }; 100 | 101 | enum NormalContent : uint8_t { 102 | kNormalUnknown, 103 | kNormalNormalized, 104 | kNormalNonNormalized, 105 | }; 106 | 107 | struct Src { 108 | std::string name; 109 | State state = kStateNew; 110 | Image::Content rgba_contents[kColorChannelCount] = {Image::kContentCount}; 111 | Image::Component solid_color[kColorChannelCount] = 112 | {0, 0, 0, Image::kComponentMax}; 113 | NormalContent normal_content = kNormalUnknown; 114 | std::unique_ptr image; 115 | }; 116 | 117 | using ColorId = int; 118 | static constexpr ColorId kColorIdIdentity = -1; 119 | 120 | using SrcMap = std::map; 121 | using ColorIdMap = std::map; 122 | 123 | // Conversion operation. 124 | struct Op { 125 | Gltf::Id image_id; 126 | Args args; 127 | const Src* src = nullptr; 128 | bool is_constant = false; 129 | bool is_new = false; 130 | bool direct_copy = false; 131 | bool need_copy = false; 132 | uint32_t pass_mask = 0; 133 | uint32_t resize_width = 0; 134 | uint32_t resize_height = 0; 135 | std::string dst_path; 136 | 137 | Op() {} 138 | Op(Gltf::Id image_id, const Args& args) : image_id(image_id), args(args) {} 139 | }; 140 | 141 | enum JobType : uint8_t { 142 | kJobAdd, 143 | kJobAddSpecToMetal, 144 | }; 145 | 146 | struct Job { 147 | JobType type; 148 | // Up to 2 ops for AddSpecToMetal. 149 | Op ops[2]; 150 | }; 151 | 152 | ConvertContext* cc_; 153 | SrcMap srcs_; 154 | std::set dsts_; 155 | ColorIdMap scale_ids_; 156 | ColorIdMap bias_ids_; 157 | std::vector jobs_; 158 | std::vector written_; 159 | std::vector created_dirs_; 160 | 161 | // Convert a color to a unique identifier from its quantized value, used to 162 | // uniquely name a transformed texture (without having to encode 4x floats 163 | // into the name). 164 | ColorId GetColorId(const ColorF& color, const ColorI& identity, 165 | ColorIdMap* color_id_map); 166 | 167 | std::string GetDstSuffix(const Texturator::Args& args, Gltf::Id image_id, 168 | Src* src, Op* op); 169 | const std::string& AddFallback(Fallback fallback); 170 | void LoadSrc(Gltf::Id image_id, Src* src) const; 171 | Src* FindOrAddSrc(Gltf::Id image_id); 172 | const std::string* AddDst(Gltf::Id image_id, const Args& args, Op* out_op); 173 | void EnsureComponentContent(Gltf::Id image_id, Src* src) const; 174 | Image::Content GetComponentContent(ColorChannel channel, Gltf::Id image_id, 175 | Src* src) const; 176 | bool NeedNormalization(Gltf::Id image_id, Src* src) const; 177 | uint32_t GetSrcWidth(Gltf::Id image_id, Src* src) const; 178 | uint32_t GetSrcHeight(Gltf::Id image_id, Src* src) const; 179 | bool GetResizeSize(Gltf::Id image_id, const ImageResizeSettings& resize, 180 | Src* src, uint32_t* out_width, uint32_t* out_height) const; 181 | size_t EstimateDecompressedJobSize(const Job& job, float global_scale) const; 182 | float ChooseGlobalScale() const; 183 | bool PrepareWrite(const std::string& dst_path); 184 | void ProcessAdd(const Op& op); 185 | void ProcessAddSpecToMetal(const Op& spec_op, const Op& diff_op); 186 | void ProcessJob(const Job& job); 187 | 188 | template 189 | inline void Log(Ts... args) const { 190 | ufg::Log(cc_->logger, "", args...); 191 | } 192 | }; 193 | } // namespace ufg 194 | 195 | #endif // UFG_CONVERT_TEXTURATOR_H_ 196 | -------------------------------------------------------------------------------- /convert/tokens.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "convert/tokens.h" 18 | 19 | namespace ufg { 20 | const TfToken kTokEmpty; 21 | 22 | const TfToken kTokColors("colors"); 23 | const TfToken kTokFallback("fallback"); 24 | const TfToken kTokFile("file"); 25 | const TfToken kTokFilterMin("minFilter"); 26 | const TfToken kTokFilterMag("magFilter"); 27 | const TfToken kTokPreviewSurface("UsdPreviewSurface"); 28 | const TfToken kTokPrimvarFloat2("UsdPrimvarReader_float2"); 29 | const TfToken kTokResult("result"); 30 | const TfToken kTokScale("scale"); 31 | const TfToken kTokBias("bias"); 32 | const TfToken kTokSt("st"); 33 | const TfToken kTokSurface("surface"); 34 | const TfToken kTokUvTexture("UsdUVTexture"); 35 | const TfToken kTokVarname("varname"); 36 | const TfToken kTokWrapS("wrapS"); 37 | const TfToken kTokWrapT("wrapT"); 38 | 39 | // Color components. 40 | const TfToken kTokR("r"); 41 | const TfToken kTokA("a"); 42 | const TfToken kTokRgb("rgb"); 43 | 44 | // PBR shader inputs. 45 | const TfToken kTokInputDiffuseColor("diffuseColor"); 46 | const TfToken kTokInputEmissiveColor("emissiveColor"); 47 | const TfToken kTokInputGlossiness("glossiness"); 48 | const TfToken kTokInputMetallic("metallic"); 49 | const TfToken kTokInputNormal("normal"); 50 | const TfToken kTokInputOcclusion("occlusion"); 51 | const TfToken kTokInputOpacity("opacity"); 52 | const TfToken kTokInputRoughness("roughness"); 53 | const TfToken kTokInputSpecularColor("specularColor"); 54 | const TfToken kTokInputUseSpecular("useSpecularWorkflow"); 55 | 56 | // Texture wrap states. 57 | const TfToken kTokWrapClamp("clamp"); 58 | const TfToken kTokWrapMirror("mirror"); 59 | const TfToken kTokWrapRepeat("repeat"); 60 | 61 | // Texture filter states. 62 | const TfToken kTokFilterNearest("nearest"); 63 | const TfToken kTokFilterLinear("linear"); 64 | const TfToken kTokFilterNearestMipmapNearest("nearestMipmapNearest"); 65 | const TfToken kTokFilterLinearMipmapNearest("linearMipmapNearest"); 66 | const TfToken kTokFilterNearestMipmapLinear("nearestMipmapLinear"); 67 | const TfToken kTokFilterLinearMipmapLinear("linearMipmapLinear"); 68 | 69 | const TfToken& ToToken(Gltf::Sampler::WrapMode wrap_mode) { 70 | switch (wrap_mode) { 71 | case Gltf::Sampler::kWrapClamp: 72 | return kTokWrapClamp; 73 | case Gltf::Sampler::kWrapMirror: 74 | return kTokWrapMirror; 75 | case Gltf::Sampler::kWrapRepeat: 76 | case Gltf::Sampler::kWrapUnset: 77 | default: 78 | return kTokWrapRepeat; 79 | } 80 | } 81 | 82 | const TfToken& ToToken(Gltf::Sampler::MinFilter filter) { 83 | switch (filter) { 84 | case Gltf::Sampler::kMinFilterNearest: 85 | return kTokFilterNearest; 86 | case Gltf::Sampler::kMinFilterLinear: 87 | return kTokFilterLinear; 88 | case Gltf::Sampler::kMinFilterNearestMipmapNearest: 89 | return kTokFilterNearestMipmapNearest; 90 | case Gltf::Sampler::kMinFilterLinearMipmapNearest: 91 | return kTokFilterLinearMipmapNearest; 92 | case Gltf::Sampler::kMinFilterNearestMipmapLinear: 93 | return kTokFilterNearestMipmapLinear; 94 | case Gltf::Sampler::kMinFilterLinearMipmapLinear: 95 | case Gltf::Sampler::kMinFilterUnset: 96 | default: 97 | return kTokFilterLinearMipmapLinear; 98 | } 99 | } 100 | 101 | const TfToken& ToToken(Gltf::Sampler::MagFilter filter) { 102 | switch (filter) { 103 | case Gltf::Sampler::kMagFilterNearest: 104 | return kTokFilterNearest; 105 | case Gltf::Sampler::kMagFilterLinear: 106 | case Gltf::Sampler::kMagFilterUnset: 107 | default: 108 | return kTokFilterLinear; 109 | } 110 | } 111 | 112 | } // namespace ufg 113 | -------------------------------------------------------------------------------- /convert/tokens.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_CONVERT_TOKENS_H_ 18 | #define UFG_CONVERT_TOKENS_H_ 19 | 20 | #include "common/common.h" 21 | #include "gltf/gltf.h" 22 | #include "pxr/base/tf/token.h" 23 | 24 | namespace ufg { 25 | using PXR_NS::TfToken; 26 | 27 | extern const TfToken kTokEmpty; 28 | 29 | extern const TfToken kTokColors; // "colors" 30 | extern const TfToken kTokFallback; // "fallback" 31 | extern const TfToken kTokFile; // "file" 32 | extern const TfToken kTokFilterMin; // "minFilter" 33 | extern const TfToken kTokFilterMag; // "magFilter" 34 | extern const TfToken kTokPreviewSurface; // "UsdPreviewSurface" 35 | extern const TfToken kTokPrimvarFloat2; // "UsdPrimvarReader_float2" 36 | extern const TfToken kTokResult; // "result" 37 | extern const TfToken kTokScale; // "scale" 38 | extern const TfToken kTokBias; // "bias" 39 | extern const TfToken kTokSt; // "st" 40 | extern const TfToken kTokSurface; // "surface" 41 | extern const TfToken kTokUvTexture; // "UsdUVTexture" 42 | extern const TfToken kTokVarname; // "varname" 43 | extern const TfToken kTokWrapS; // "wrapS" 44 | extern const TfToken kTokWrapT; // "wrapT" 45 | 46 | // Color components. 47 | extern const TfToken kTokR; // "r" 48 | extern const TfToken kTokA; // "a" 49 | extern const TfToken kTokRgb; // "rgb" 50 | 51 | // PBR shader inputs. 52 | extern const TfToken kTokInputDiffuseColor; // "diffuseColor" 53 | extern const TfToken kTokInputEmissiveColor; // "emissiveColor" 54 | extern const TfToken kTokInputGlossiness; // "glossiness" 55 | extern const TfToken kTokInputMetallic; // "metallic" 56 | extern const TfToken kTokInputNormal; // "normal" 57 | extern const TfToken kTokInputOcclusion; // "occlusion" 58 | extern const TfToken kTokInputOpacity; // "opacity" 59 | extern const TfToken kTokInputRoughness; // "roughness" 60 | extern const TfToken kTokInputSpecularColor; // "specularColor" 61 | extern const TfToken kTokInputUseSpecular; // "useSpecularWorkflow" 62 | 63 | // Texture wrap states. 64 | extern const TfToken kTokWrapClamp; // "clamp" 65 | extern const TfToken kTokWrapMirror; // "mirror" 66 | extern const TfToken kTokWrapRepeat; // "repeat" 67 | 68 | // Texture filter states. 69 | extern const TfToken kTokFilterNearest; // "nearest" 70 | extern const TfToken kTokFilterLinear; // "linear" 71 | extern const TfToken kTokFilterNearestMipmapNearest; // "nearestMipmapNearest" 72 | extern const TfToken kTokFilterLinearMipmapNearest; // "linearMipmapNearest" 73 | extern const TfToken kTokFilterNearestMipmapLinear; // "nearestMipmapLinear" 74 | extern const TfToken kTokFilterLinearMipmapLinear; // "linearMipmapLinear" 75 | 76 | const TfToken& ToToken(Gltf::Sampler::WrapMode wrap_mode); 77 | const TfToken& ToToken(Gltf::Sampler::MinFilter filter); 78 | const TfToken& ToToken(Gltf::Sampler::MagFilter filter); 79 | 80 | } // namespace ufg 81 | 82 | #endif // UFG_CONVERT_TOKENS_H_ 83 | -------------------------------------------------------------------------------- /gltf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | find_package(json) 16 | if (NOT json_FOUND) 17 | message(FATAL_ERROR "JSON package not found.") 18 | endif (NOT json_FOUND) 19 | 20 | include_directories( 21 | ${json_INCLUDE_DIR} 22 | ) 23 | 24 | add_library(gltf 25 | internal_util.cc 26 | internal_util.h 27 | load.cc 28 | load.h 29 | memory_stream.cc 30 | memory_stream.h 31 | message.cc 32 | message.h 33 | messages.inl 34 | stream.cc 35 | stream.h 36 | validate.cc 37 | validate.h 38 | cache.cc 39 | cache.h 40 | disk_stream.cc 41 | disk_stream.h 42 | disk_util.cc 43 | disk_util.h 44 | glb_stream.cc 45 | glb_stream.h 46 | gltf.cc 47 | gltf.h 48 | image_parsing.cc 49 | image_parsing.h 50 | ) 51 | 52 | file(GLOB GLTF_HEADERS "*.h") 53 | set_target_properties(gltf PROPERTIES PUBLIC_HEADER "${GLTF_HEADERS}") 54 | 55 | install(TARGETS gltf EXPORT ufglib DESTINATION lib/ufg PUBLIC_HEADER DESTINATION include/ufg/gltf) 56 | -------------------------------------------------------------------------------- /gltf/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_CACHE_H_ 18 | #define GLTF_CACHE_H_ 19 | 20 | #include 21 | #include 22 | #include "gltf.h" // NOLINT: Silence relative path warning. 23 | #include "message.h" // NOLINT: Silence relative path warning. 24 | #include "stream.h" // NOLINT: Silence relative path warning. 25 | 26 | // Utility to load and cache bin and image files. 27 | class GltfCache { 28 | public: 29 | explicit GltfCache(const Gltf* gltf = nullptr, GltfStream* stream = nullptr) 30 | : gltf_(nullptr), stream_(nullptr) { 31 | Reset(gltf, stream); 32 | } 33 | 34 | void Reset(const Gltf* gltf = nullptr, GltfStream* stream = nullptr); 35 | 36 | const uint8_t* GetBufferData(Gltf::Id buffer_id, size_t* out_size); 37 | const uint8_t* GetBufferData(Gltf::Id buffer_id) { 38 | size_t size; 39 | return GetBufferData(buffer_id, &size); 40 | } 41 | 42 | const uint8_t* GetViewData(Gltf::Id view_id, size_t* out_size); 43 | const uint8_t* GetImageData(Gltf::Id image_id, size_t* out_size, 44 | Gltf::Image::MimeType* out_mime_type); 45 | 46 | bool ImageExists(Gltf::Id image_id) const { 47 | return stream_->ImageExists(*gltf_, image_id); 48 | } 49 | 50 | bool IsImageAtPath(Gltf::Id image_id, const char* dir, 51 | const char* name) const { 52 | return stream_->IsImageAtPath(*gltf_, image_id, dir, name); 53 | } 54 | 55 | bool IsSourcePath(const char* path) const { 56 | return stream_->IsSourcePath(path); 57 | } 58 | 59 | bool CopyImage(Gltf::Id image_id, const std::string& dst_path); 60 | 61 | // Get accessor data as an array, reformatting if necessary. 62 | // * This returns an array of scalars with length 63 | // out_vec_count*out_component_count. 64 | template 65 | const Dst* Access(Gltf::Id accessor_id, 66 | size_t* out_vec_count, size_t* out_component_count); 67 | 68 | private: 69 | struct BufferEntry { 70 | bool loaded = false; 71 | std::vector data; 72 | }; 73 | 74 | struct ImageEntry { 75 | bool loaded = false; 76 | Gltf::Image::MimeType mime_type = Gltf::Image::kMimeUnset; 77 | std::vector data; 78 | }; 79 | 80 | struct Content { 81 | enum State : uint8_t { 82 | kStateUncached, 83 | kStateNull, 84 | kStateDirect, 85 | kStateReformatted, 86 | }; 87 | State state = kStateUncached; 88 | Gltf::Id direct_buffer_id = Gltf::Id::kNull; 89 | uint32_t direct_offset = 0; 90 | std::vector reformatted; 91 | }; 92 | 93 | struct AccessorEntry { 94 | Content contents[Gltf::Accessor::kComponentCount]; 95 | }; 96 | 97 | const Gltf* gltf_; 98 | GltfStream* stream_; 99 | std::vector buffer_entries_; 100 | std::vector image_entries_; 101 | std::vector accessor_entries_; 102 | 103 | template 104 | const Dst* GetContentAs(const Content& content) { 105 | const void* data; 106 | switch (content.state) { 107 | case Content::kStateDirect: 108 | data = GetBufferData(content.direct_buffer_id) + content.direct_offset; 109 | break; 110 | case Content::kStateReformatted: 111 | data = content.reformatted.data(); 112 | break; 113 | case Content::kStateNull: 114 | default: 115 | data = nullptr; 116 | } 117 | return static_cast(data); 118 | } 119 | 120 | template 121 | const Dst* GetViewContent( 122 | Gltf::Id view_id, size_t offset, 123 | Gltf::Accessor::ComponentType component_type, 124 | size_t vec_count, size_t component_count, 125 | bool normalized, bool need_reformat, 126 | Content* out_content); 127 | }; 128 | 129 | #endif // GLTF_CACHE_H_ 130 | -------------------------------------------------------------------------------- /gltf/disk_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_DISK_STREAM_H_ 18 | #define GLTF_DISK_STREAM_H_ 19 | 20 | #include 21 | #include 22 | #include "stream.h" // NOLINT: Silence relative path warning. 23 | 24 | // GltfStream implementation that reads from disk. 25 | class GltfDiskStream : public GltfStream { 26 | public: 27 | GltfDiskStream( 28 | GltfLogger* logger, const char* gltf_path, const char* resource_dir); 29 | 30 | std::unique_ptr GetGltfIStream() override; 31 | bool BufferExists(const Gltf& gltf, Gltf::Id buffer_id) const override; 32 | bool ImageExists(const Gltf& gltf, Gltf::Id image_id) const override; 33 | bool IsImageAtPath(const Gltf& gltf, Gltf::Id image_id, const char* dir, 34 | const char* name) const override; 35 | bool ReadBuffer( 36 | const Gltf& gltf, Gltf::Id buffer_id, size_t start, size_t limit, 37 | std::vector* out_data) override; 38 | bool ReadImage(const Gltf& gltf, Gltf::Id image_id, 39 | std::vector* out_data, 40 | Gltf::Image::MimeType* out_mime_type) override; 41 | ImageAttributes ReadImageAttributes( 42 | const Gltf& gltf, Gltf::Id image_id) override; 43 | bool CopyImage(const Gltf& gltf, Gltf::Id image_id, 44 | const char* dst_path) override; 45 | bool IsSourcePath(const char* path) const override; 46 | bool WriteBinary( 47 | const std::string& dst_path, const void* data, size_t size) override; 48 | 49 | bool GlbOpen(const char* path) override; 50 | bool GlbIsOpen() const override; 51 | size_t GlbGetFileSize() const override; 52 | size_t GlbRead(size_t size, void* out_data) override; 53 | bool GlbSeekRelative(size_t size) override; 54 | void GlbClose() override; 55 | 56 | // Get canonical absolute path. 57 | // * If comparable is true, the path is converted to lower-case for 58 | // case-insensitive IO on Windows. 59 | static std::string GetCanonicalPath(const char* path, bool comparable); 60 | 61 | // Like GetCanonicalPath, but also sanitizes invalid characters. 62 | static std::string GetCanonicalSanitizedPath( 63 | const char* dir, const char* name, bool comparable); 64 | 65 | // Compare two canonical sanitized paths (split into directory and name). 66 | static bool SanitizedPathsEqual(const char* dir0, const char* name0, 67 | const char* dir1, const char* name1); 68 | 69 | private: 70 | std::string gltf_path_; 71 | std::string path_prefix_; 72 | std::set src_paths_; 73 | FILE* glb_file_; 74 | 75 | // Read binary file, in the range [start, start+size). 76 | // * Set 'size' to -1 to read to the end of the file. 77 | bool ReadBinary(const char* rel_path, size_t start, ptrdiff_t size, 78 | std::vector* out_data); 79 | 80 | bool CopyBinary(const char* src_rel_path, const char* dst_path); 81 | }; 82 | 83 | #endif // GLTF_DISK_STREAM_H_ 84 | -------------------------------------------------------------------------------- /gltf/disk_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "disk_util.h" // NOLINT: Silence relative path warning. 18 | 19 | #include "internal_util.h" // NOLINT: Silence relative path warning. 20 | 21 | #ifdef _MSC_VER 22 | #define NOMINMAX 23 | #define WIN32_LEAN_AND_MEAN 24 | #include 25 | #else // _MSC_VER 26 | #include 27 | #endif // _MSC_VER 28 | 29 | namespace { 30 | bool DirectoryExists(const char* path) { 31 | #ifdef _MSC_VER 32 | const DWORD attr = GetFileAttributesA(path); 33 | return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); 34 | #else // _MSC_VER 35 | struct stat st; 36 | return stat(path, &st) == 0 && S_ISDIR(st.st_mode); 37 | #endif // _MSC_VER 38 | } 39 | 40 | size_t GetLengthOfExistingDirectoryForFile(const std::string& file_path) { 41 | for (size_t len = file_path.length(); len > 0; --len) { 42 | len = file_path.find_last_of("\\/", len); 43 | if (len == std::string::npos) { 44 | return 0; 45 | } 46 | const std::string dir = file_path.substr(0, len); 47 | if (DirectoryExists(dir.c_str())) { 48 | return len + 1; 49 | } 50 | } 51 | return 0; 52 | } 53 | } // namespace 54 | 55 | std::vector GltfDiskCreateDirectoryForFile( 56 | const std::string& file_path) { 57 | size_t pos = GetLengthOfExistingDirectoryForFile(file_path); 58 | std::vector created_dirs; 59 | for (;;) { 60 | pos = file_path.find_first_of("\\/", pos + 1); 61 | if (pos == std::string::npos) { 62 | break; 63 | } 64 | std::string dir = file_path.substr(0, pos); 65 | if (!dir.empty()) { 66 | #ifdef _MSC_VER 67 | CreateDirectoryA(dir.c_str(), NULL); 68 | #else // _MSC_VER 69 | mkdir(dir.c_str(), 0777); 70 | #endif // _MSC_VER 71 | created_dirs.emplace_back(std::move(dir)); 72 | } 73 | } 74 | return created_dirs; 75 | } 76 | 77 | bool GltfDiskWriteBinary(const std::string& dst_path, 78 | const void* data, size_t size) { 79 | GltfDiskFileSentry file(dst_path.c_str(), "wb"); 80 | return file.fp && fwrite(data, 1, size, file.fp) == size; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /gltf/disk_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_DISK_UTIL_H_ 18 | #define GLTF_DISK_UTIL_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | // Creates a directory for a file (including any necessary ancestors). Returns 25 | // paths of the directories created, in the order they were created. 26 | std::vector GltfDiskCreateDirectoryForFile( 27 | const std::string& file_path); 28 | 29 | // Write a whole binary file to disk. 30 | bool GltfDiskWriteBinary(const std::string& dst_path, 31 | const void* data, size_t size); 32 | 33 | struct GltfDiskFileSentry { 34 | FILE* fp; 35 | 36 | GltfDiskFileSentry() : fp(nullptr) {} 37 | 38 | GltfDiskFileSentry(const char* path, const char* mode) : fp(nullptr) { 39 | Open(path, mode); 40 | } 41 | 42 | ~GltfDiskFileSentry() { 43 | Close(); 44 | } 45 | 46 | void Close() { 47 | if (fp) { 48 | fclose(fp); 49 | fp = nullptr; 50 | } 51 | } 52 | 53 | bool Open(const char* path, const char* mode) { 54 | Close(); 55 | fp = fopen(path, mode); 56 | return fp != nullptr; 57 | } 58 | }; 59 | 60 | #endif // GLTF_DISK_UTIL_H_ 61 | -------------------------------------------------------------------------------- /gltf/glb_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_GLB_STREAM_H_ 18 | #define GLTF_GLB_STREAM_H_ 19 | 20 | #include "stream.h" // NOLINT: Silence relative path warning. 21 | 22 | struct GlbFileHeader { 23 | static constexpr uint32_t kMagic = 0x46546c67u; // 'glTF' 24 | static constexpr uint32_t kVersion = 2; 25 | uint32_t magic; 26 | uint32_t version; 27 | uint32_t length; 28 | }; 29 | 30 | struct GlbChunkHeader { 31 | static constexpr uint32_t kTypeBin = 0x004e4942u; // 'BIN' 32 | static constexpr uint32_t kTypeJson = 0x4e4f534au; // 'JSON' 33 | uint32_t length; 34 | uint32_t type; 35 | }; 36 | 37 | bool IsGlbFilePath(const char* path); 38 | 39 | // GltfStream implementation that reads from a GLB file. 40 | class GltfGlbStream : public GltfStream { 41 | public: 42 | // Open a GLB, wrapping another stream. 43 | GltfGlbStream(GltfStream* impl_stream, bool own_impl, const char* gltf_path); 44 | 45 | // Open a GLB from a file on disk. 46 | GltfGlbStream( 47 | GltfLogger* logger, const char* gltf_path, const char* resource_dir); 48 | 49 | // Open a GLB from a file in memory. 50 | GltfGlbStream( 51 | GltfLogger* logger, const void* data, size_t size, const char* log_name); 52 | 53 | ~GltfGlbStream() override; 54 | bool IsOpen() const; 55 | std::unique_ptr GetGltfIStream() override; 56 | bool BufferExists(const Gltf& gltf, Gltf::Id buffer_id) const override; 57 | bool ImageExists(const Gltf& gltf, Gltf::Id image_id) const override; 58 | bool IsImageAtPath(const Gltf& gltf, Gltf::Id image_id, const char* dir, 59 | const char* name) const override; 60 | bool ReadBuffer( 61 | const Gltf& gltf, Gltf::Id buffer_id, size_t start, size_t limit, 62 | std::vector* out_data) override; 63 | bool ReadImage(const Gltf& gltf, Gltf::Id image_id, 64 | std::vector* out_data, 65 | Gltf::Image::MimeType* out_mime_type) override; 66 | ImageAttributes ReadImageAttributes( 67 | const Gltf& gltf, Gltf::Id image_id) override; 68 | bool CopyImage(const Gltf& gltf, Gltf::Id image_id, 69 | const char* dst_path) override; 70 | bool IsSourcePath(const char* path) const override; 71 | bool WriteBinary(const std::string& dst_path, 72 | const void* data, size_t size) override; 73 | 74 | private: 75 | struct ChunkInfo { 76 | size_t start; 77 | size_t size; 78 | }; 79 | GltfStream* impl_stream_; 80 | bool own_impl_; 81 | std::string gltf_path_; 82 | ChunkInfo gltf_chunk_info_ = {}; 83 | std::vector bin_chunk_infos_; 84 | void Open(const char* gltf_path); 85 | bool ReadChunk(size_t start, size_t size, void* out_data); 86 | }; 87 | 88 | #endif // GLTF_GLB_STREAM_H_ 89 | -------------------------------------------------------------------------------- /gltf/image_parsing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_IMAGE_PARSING_H_ 18 | #define GLTF_IMAGE_PARSING_H_ 19 | 20 | #include "stream.h" // NOLINT: Silence relative path warning. 21 | 22 | // Parse image type and dimensions from a header in memory. 23 | Gltf::Image::MimeType GltfParseImage( 24 | const void* data, size_t data_size, const char* name, GltfLogger* logger, 25 | uint32_t* out_width, uint32_t* out_height); 26 | 27 | // Parse image type and dimensions from a file. 28 | Gltf::Image::MimeType GltfParseImage( 29 | FILE* fp, const char* name, GltfLogger* logger, 30 | uint32_t* out_width, uint32_t* out_height); 31 | 32 | // Parse image type and dimensions from a read callback. 33 | using GltfParseReadFP = bool (*)(void* user_context, size_t start, size_t limit, 34 | std::vector* out_data); 35 | Gltf::Image::MimeType GltfParseImage( 36 | GltfParseReadFP read, void* user_context, const char* name, 37 | GltfLogger* logger, uint32_t* out_width, uint32_t* out_height); 38 | 39 | #endif // GLTF_IMAGE_PARSING_H_ 40 | -------------------------------------------------------------------------------- /gltf/internal_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "internal_util.h" // NOLINT: Silence relative path warning. 18 | 19 | size_t GetFileSize(FILE* fp) { 20 | const long pos = ftell(fp); // NOLINT: ftell returns long. 21 | fseek(fp, 0, SEEK_END); 22 | const size_t file_size = ftell(fp); 23 | fseek(fp, pos, SEEK_SET); 24 | return file_size; 25 | } 26 | 27 | bool SeekAbsolute(FILE* fp, size_t offset) { 28 | // TODO: 64-bit version? 29 | const long offset_long = static_cast(offset); // NOLINT 30 | if (static_cast(offset_long) != offset) { 31 | return false; 32 | } 33 | return fseek(fp, offset_long, SEEK_SET) == 0; 34 | } 35 | -------------------------------------------------------------------------------- /gltf/internal_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_INTERNAL_UTIL_H_ 18 | #define GLTF_INTERNAL_UTIL_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "message.h" // NOLINT: Silence relative path warning. 24 | 25 | template 26 | char (&ArraySizeHelper(T (&)[LEN]))[LEN]; 27 | #define arraysize(array) (sizeof(ArraySizeHelper(array))) 28 | 29 | #define CONST_STRLEN(text) (arraysize(text) - 1) 30 | 31 | template 32 | inline T* PointerOffset(T* p, size_t offset) { 33 | return reinterpret_cast(reinterpret_cast(p) + offset); 34 | } 35 | 36 | template 37 | inline ptrdiff_t PointerDistance(Begin* begin, End* end) { 38 | return reinterpret_cast(end) - reinterpret_cast(begin); 39 | } 40 | 41 | size_t GetFileSize(FILE* fp); 42 | bool SeekAbsolute(FILE* fp, size_t offset); 43 | 44 | #endif // GLTF_INTERNAL_UTIL_H_ 45 | -------------------------------------------------------------------------------- /gltf/load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_LOAD_H_ 18 | #define GLTF_LOAD_H_ 19 | 20 | #include 21 | #include 22 | #include "gltf.h" // NOLINT: Silence relative path warning. 23 | #include "message.h" // NOLINT: Silence relative path warning. 24 | 25 | struct GltfLoadSettings { 26 | // Null terminated array used to disable warnings for unrecognized glTF 27 | // extensions. 28 | std::vector nowarn_extension_prefixes; 29 | }; 30 | 31 | // Load glTF from an input stream. 32 | bool GltfLoad(std::istream& is, const GltfLoadSettings& settings, 33 | Gltf* out_gltf, GltfLogger* logger); 34 | 35 | #endif // GLTF_LOAD_H_ 36 | -------------------------------------------------------------------------------- /gltf/memory_stream.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "memory_stream.h" // NOLINT: Silence relative path warning. 18 | 19 | #include 20 | 21 | GltfMemoryStream::GltfMemoryStream( 22 | GltfLogger* logger, const void* data, size_t size) 23 | : GltfStream(logger), 24 | data_(static_cast(data)), 25 | size_(size), 26 | pos_(0) {} 27 | 28 | bool GltfMemoryStream::GlbOpen(const char* path) { 29 | pos_ = 0; 30 | return true; 31 | } 32 | 33 | bool GltfMemoryStream::GlbIsOpen() const { 34 | return true; 35 | } 36 | 37 | size_t GltfMemoryStream::GlbGetFileSize() const { 38 | return size_; 39 | } 40 | 41 | size_t GltfMemoryStream::GlbRead(size_t size, void* out_data) { 42 | const size_t space = size_ - pos_; 43 | const size_t read_size = std::min(space, size); 44 | memcpy(out_data, data_ + pos_, read_size); 45 | const size_t new_pos = pos_ + size; 46 | pos_ = std::min(new_pos, size_); 47 | return read_size; 48 | } 49 | 50 | bool GltfMemoryStream::GlbSeekRelative(size_t size) { 51 | const size_t new_pos = pos_ + size; 52 | pos_ = std::min(new_pos, size_); 53 | return new_pos <= size_; 54 | } 55 | 56 | void GltfMemoryStream::GlbClose() { 57 | } 58 | -------------------------------------------------------------------------------- /gltf/memory_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_MEMORY_STREAM_H_ 18 | #define GLTF_MEMORY_STREAM_H_ 19 | 20 | #include "stream.h" // NOLINT: Silence relative path warning. 21 | 22 | // GltfStream implementation that reads from memory. 23 | class GltfMemoryStream : public GltfStream { 24 | public: 25 | GltfMemoryStream(GltfLogger* logger, const void* data, size_t size); 26 | bool GlbOpen(const char* path) override; 27 | bool GlbIsOpen() const override; 28 | size_t GlbGetFileSize() const override; 29 | size_t GlbRead(size_t size, void* out_data) override; 30 | bool GlbSeekRelative(size_t size) override; 31 | void GlbClose() override; 32 | 33 | private: 34 | const uint8_t* data_; 35 | size_t size_; 36 | size_t pos_; 37 | }; 38 | 39 | #endif // GLTF_MEMORY_STREAM_H_ 40 | -------------------------------------------------------------------------------- /gltf/stream.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "stream.h" // NOLINT: Silence relative path warning. 18 | 19 | #include "disk_stream.h" // NOLINT: Silence relative path warning. 20 | #include "glb_stream.h" // NOLINT: Silence relative path warning. 21 | 22 | std::unique_ptr GltfStream::Open( 23 | GltfLogger* logger, const char* gltf_path, const char* resource_dir) { 24 | if (IsGlbFilePath(gltf_path)) { 25 | std::unique_ptr stream( 26 | new GltfGlbStream(logger, gltf_path, resource_dir)); 27 | return stream->IsOpen() ? 28 | std::unique_ptr(stream.release()) : nullptr; 29 | } else { 30 | return std::unique_ptr( 31 | new GltfDiskStream(logger, gltf_path, resource_dir)); 32 | } 33 | } 34 | 35 | std::unique_ptr GltfStream::GetGltfIStream() { 36 | Log("GetGltfIStream"); 37 | return nullptr; 38 | } 39 | 40 | bool GltfStream::BufferExists(const Gltf& gltf, Gltf::Id buffer_id) const { 41 | Log("BufferExists"); 42 | return false; 43 | } 44 | 45 | bool GltfStream::ImageExists(const Gltf& gltf, Gltf::Id image_id) const { 46 | Log("ImageExists"); 47 | return false; 48 | } 49 | 50 | bool GltfStream::IsImageAtPath( 51 | const Gltf& gltf, Gltf::Id image_id, 52 | const char* dir, const char* name) const { 53 | Log("IsImageAtPath"); 54 | return false; 55 | } 56 | 57 | bool GltfStream::ReadBuffer( 58 | const Gltf& gltf, Gltf::Id buffer_id, size_t start, size_t limit, 59 | std::vector* out_data) { 60 | Log("ReadBuffer"); 61 | return false; 62 | } 63 | 64 | bool GltfStream::ReadImage( 65 | const Gltf& gltf, Gltf::Id image_id, 66 | std::vector* out_data, Gltf::Image::MimeType* out_mime_type) { 67 | Log("ReadImage"); 68 | return false; 69 | } 70 | 71 | GltfStream::ImageAttributes GltfStream::ReadImageAttributes( 72 | const Gltf& gltf, Gltf::Id image_id) { 73 | Log("ReadImageAttributes"); 74 | return GltfStream::ImageAttributes(); 75 | } 76 | 77 | bool GltfStream::CopyImage( 78 | const Gltf& gltf, Gltf::Id image_id, const char* dst_path) { 79 | Log("CopyImage"); 80 | return false; 81 | } 82 | 83 | bool GltfStream::IsSourcePath(const char* path) const { 84 | Log("IsSourcePath"); 85 | return false; 86 | } 87 | 88 | bool GltfStream::WriteBinary( 89 | const std::string& dst_path, const void* data, size_t size) { 90 | Log("WriteBinary"); 91 | return false; 92 | } 93 | 94 | bool GltfStream::GlbOpen(const char* path) { 95 | Log("GlbOpen"); 96 | return false; 97 | } 98 | 99 | bool GltfStream::GlbIsOpen() const { 100 | Log("GlbIsOpen"); 101 | return false; 102 | } 103 | 104 | size_t GltfStream::GlbGetFileSize() const { 105 | Log("GlbGetFileSize"); 106 | return 0; 107 | } 108 | 109 | size_t GltfStream::GlbRead(size_t size, void* out_data) { 110 | Log("GlbRead"); 111 | return 0; 112 | } 113 | 114 | bool GltfStream::GlbSeekRelative(size_t size) { 115 | Log("GlbSeekRelative"); 116 | return false; 117 | } 118 | 119 | void GltfStream::GlbClose() { 120 | Log("GlbClose"); 121 | } 122 | -------------------------------------------------------------------------------- /gltf/stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_STREAM_H_ 18 | #define GLTF_STREAM_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "gltf.h" // NOLINT: Silence relative path warning. 27 | #include "message.h" // NOLINT: Silence relative path warning. 28 | 29 | // Stream interface to abstract access to bin and image files. 30 | class GltfStream { 31 | public: 32 | struct ImageAttributes { 33 | // True if the image data actually exists (whether or not it contains valid 34 | // image data). 35 | bool exists = false; 36 | // The type of the image indicated by its file name (or MIME type in the 37 | // glTF for embedded images). 38 | Gltf::Image::MimeType file_type = Gltf::Image::kMimeUnset; 39 | // The real image type as indicated by header data. If this doesn't match 40 | // file_type, this is not a compliant glTF (though usd_from_gltf and some 41 | // renderers may handle it anyway). 42 | Gltf::Image::MimeType real_type = Gltf::Image::kMimeUnset; 43 | // Image width. 44 | uint32_t width = 0; 45 | // Image height. 46 | uint32_t height = 0; 47 | // File size of the compressed source image. 48 | size_t file_size = 0; 49 | // Relative path of the image. Only set if the image is path-based (as 50 | // opposed to embedded in a data URI or GLB). 51 | std::string path; 52 | // If the path had to be sanitized to be located, this is set to the 53 | // original unsanitized path. 54 | std::string unsanitized_path; 55 | }; 56 | 57 | // Open a stream from either a glTF on disk or packed in a GLB. 58 | static std::unique_ptr Open( 59 | GltfLogger* logger, const char* gltf_path, const char* resource_dir); 60 | 61 | virtual ~GltfStream() {} 62 | 63 | virtual std::unique_ptr GetGltfIStream(); 64 | virtual bool BufferExists(const Gltf& gltf, Gltf::Id buffer_id) const; 65 | virtual bool ImageExists(const Gltf& gltf, Gltf::Id image_id) const; 66 | virtual bool IsImageAtPath( 67 | const Gltf& gltf, Gltf::Id image_id, 68 | const char* dir, const char* name) const; 69 | 70 | virtual bool ReadBuffer( 71 | const Gltf& gltf, Gltf::Id buffer_id, size_t start, size_t limit, 72 | std::vector* out_data); 73 | virtual bool ReadImage( 74 | const Gltf& gltf, Gltf::Id image_id, 75 | std::vector* out_data, Gltf::Image::MimeType* out_mime_type); 76 | virtual ImageAttributes ReadImageAttributes( 77 | const Gltf& gltf, Gltf::Id image_id); 78 | virtual bool CopyImage( 79 | const Gltf& gltf, Gltf::Id image_id, const char* dst_path); 80 | 81 | virtual bool IsSourcePath(const char* path) const; 82 | 83 | virtual bool WriteBinary(const std::string& dst_path, 84 | const void* data, size_t size); 85 | 86 | // Open/Read/Close the backing GLB file. 87 | // This is used by GlbStream to decode GLB packets from another stream (from 88 | // disk or in memory). 89 | virtual bool GlbOpen(const char* path); 90 | virtual bool GlbIsOpen() const; 91 | virtual size_t GlbGetFileSize() const; 92 | virtual size_t GlbRead(size_t size, void* out_data); 93 | virtual bool GlbSeekRelative(size_t size); 94 | virtual void GlbClose(); 95 | 96 | struct GlbSentry { 97 | GltfStream* stream; 98 | explicit GlbSentry(GltfStream* stream, const char* path) : stream(stream) { 99 | stream->GlbOpen(path); 100 | } 101 | ~GlbSentry() { 102 | if (stream->GlbIsOpen()) { 103 | stream->GlbClose(); 104 | } 105 | } 106 | }; 107 | 108 | template 109 | void Log(Ts... args) const { 110 | logger_->Add(GltfGetMessage("", args...)); 111 | } 112 | 113 | GltfLogger* GetLogger() const { return logger_; } 114 | 115 | protected: 116 | GltfLogger* logger_; 117 | 118 | explicit GltfStream(GltfLogger* logger) : logger_(logger) {} 119 | }; 120 | 121 | #endif // GLTF_STREAM_H_ 122 | -------------------------------------------------------------------------------- /gltf/validate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef GLTF_VALIDATE_H_ 18 | #define GLTF_VALIDATE_H_ 19 | 20 | #include "gltf.h" // NOLINT: Silence relative path warning. 21 | #include "load.h" // NOLINT: Silence relative path warning. 22 | #include "message.h" // NOLINT: Silence relative path warning. 23 | #include "stream.h" // NOLINT: Silence relative path warning. 24 | 25 | // Perform glTF structure validation. 26 | // 27 | // This performs a thorough check for issues that are likely to cause conversion 28 | // issues, rather than a strict enforcement of the schema. 29 | // 30 | // Notable exceptions are: 31 | // 1) Any validation done earlier in GltfLoad is not repeated here. 32 | // 2) It does not perform inspection of binary resources (including Draco- 33 | // compressed meshes). 34 | // 3) Recoverable issues are treated as warnings rather than errors. 35 | // 4) Fields extraneous to conversion may be ignored. 36 | bool GltfValidate(const Gltf& gltf, GltfLogger* logger); 37 | 38 | bool GltfLoadAndValidate( 39 | GltfStream* gltf_stream, const char* name, const GltfLoadSettings& settings, 40 | Gltf* out_gltf, GltfLogger* logger); 41 | 42 | #endif // GLTF_VALIDATE_H_ 43 | -------------------------------------------------------------------------------- /process/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(draco) 2 | if (NOT draco_FOUND) 3 | message(FATAL_ERROR "Draco package not found.") 4 | endif (NOT draco_FOUND) 5 | 6 | find_package(giflib) 7 | if (NOT giflib_FOUND) 8 | message(FATAL_ERROR "Giflib package not found.") 9 | endif (NOT giflib_FOUND) 10 | 11 | find_package(stb_image) 12 | if (NOT stb_image_FOUND) 13 | message(FATAL_ERROR "STB Image package not found.") 14 | endif (NOT stb_image_FOUND) 15 | 16 | get_filename_component(PARENT_DIR ${stb_image_LIBRARY_DIR} DIRECTORY) 17 | if (APPLE) 18 | set(ZLIB_LIBRARIES ${PARENT_DIR}/src/zlib-1.2.11/libz.dylib) 19 | elseif (WIN32) 20 | set(ZLIB_LIBRARIES ${PARENT_DIR}/src/zlib-1.2.11/Release/zlib.lib) 21 | else () 22 | set(ZLIB_LIBRARIES ${PARENT_DIR}/src/zlib-1.2.11/libz.so) 23 | endif () 24 | 25 | include_directories( 26 | .. 27 | ${USD_INCLUDE_DIRS} 28 | ${draco_INCLUDE_DIR}/.. 29 | ${giflib_INCLUDE_DIR} 30 | ${stb_image_INCLUDE_DIR} 31 | ) 32 | 33 | add_library(process 34 | image_png.h 35 | math.cc 36 | math.h 37 | mesh.cc 38 | mesh.h 39 | process_util.cc 40 | process_util.h 41 | skin.cc 42 | skin.h 43 | access.h 44 | animation.cc 45 | animation.h 46 | color.cc 47 | color.h 48 | float_image.cc 49 | float_image.h 50 | image.cc 51 | image.h 52 | image_fallback.cc 53 | image_fallback.h 54 | image_gif.cc 55 | image_gif.h 56 | image_jpg.cc 57 | image_jpg.h 58 | image_png.cc 59 | ) 60 | 61 | file(GLOB PROCESS_HEADERS "*.h") 62 | set_target_properties(process PROPERTIES PUBLIC_HEADER "${PROCESS_HEADERS}") 63 | 64 | # Libpng and libturbojpeg do not define library directories. We need to search 65 | # for them because on different distros, they appear in different locations. 66 | set(INSTALLED_LIBRARY_DIR ${stb_image_LIBRARY_DIR}) 67 | find_library(PNG_LIBRARY 68 | NAMES libpng16.a libpng16_static.lib 69 | HINTS ${stb_image_LIBRARY_DIR} ${PARENT_DIR}/lib64 70 | ) 71 | if (NOT PNG_LIBRARY) 72 | message(FATAL_ERROR "Libpng not found.") 73 | endif (NOT PNG_LIBRARY) 74 | 75 | find_library(TURBOJPEG_LIBRARY 76 | NAMES libturbojpeg.a turbojpeg-static.lib 77 | HINTS ${stb_image_LIBRARY_DIR} ${PARENT_DIR}/lib64 78 | ) 79 | if (NOT TURBOJPEG_LIBRARY) 80 | message(FATAL_ERROR "Libturbojpeg not found.") 81 | endif (NOT TURBOJPEG_LIBRARY) 82 | 83 | if (MSVC) 84 | target_link_libraries(process 85 | common 86 | "${draco_LIBRARY_DIR}/dracodec.lib" 87 | "${giflib_LIBRARY_DIR}/giflib.lib" 88 | "${stb_image_LIBRARY_DIR}/stb_image.lib" 89 | "${PNG_LIBRARY}" 90 | "${ZLIB_LIBRARIES}" 91 | "${TURBOJPEG_LIBRARY}" 92 | ) 93 | else (MSVC) 94 | 95 | target_link_libraries(process 96 | common 97 | "${draco_LIBRARY_DIR}/libdracodec.a" 98 | "${giflib_LIBRARY_DIR}/libgiflib.a" 99 | "${stb_image_LIBRARY_DIR}/libstb_image.a" 100 | "${PNG_LIBRARY}" 101 | "${ZLIB_LIBRARIES}" 102 | "${TURBOJPEG_LIBRARY}" 103 | ) 104 | endif (MSVC) 105 | 106 | install(TARGETS process EXPORT ufglib DESTINATION lib/ufg PUBLIC_HEADER DESTINATION include/ufg/process) 107 | -------------------------------------------------------------------------------- /process/access.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_ACCESS_H_ 18 | #define UFG_PROCESS_ACCESS_H_ 19 | 20 | #include 21 | #include "common/common.h" 22 | #include "common/logging.h" 23 | #include "gltf/cache.h" 24 | #include "gltf/gltf.h" 25 | #include "process/math.h" 26 | #include "pxr/base/vt/array.h" 27 | 28 | namespace ufg { 29 | using PXR_NS::VtArray; 30 | 31 | template 32 | void ToVtArray(const std::vector& in, VtArray* out) { 33 | const size_t count = in.size(); 34 | out->resize(count); 35 | for (size_t i = 0; i != count; ++i) { 36 | (*out)[i] = Out(in[i]); 37 | } 38 | } 39 | 40 | template struct CopyAccessorHandler; 41 | 42 | template <> struct CopyAccessorHandler { 43 | static constexpr size_t kComponentCount = 1; 44 | static constexpr Gltf::Accessor::Type kGltfType = Gltf::Accessor::kTypeScalar; 45 | static void CopyVec(const float* src, float* dst) { *dst = src[0]; } 46 | }; 47 | 48 | template <> struct CopyAccessorHandler { 49 | static constexpr size_t kComponentCount = 3; 50 | static constexpr Gltf::Accessor::Type kGltfType = Gltf::Accessor::kTypeVec3; 51 | static void CopyVec(const float* src, GfVec3f* dst) { 52 | *dst = GfVec3f(src[0], src[1], src[2]); 53 | } 54 | }; 55 | 56 | template <> struct CopyAccessorHandler { 57 | static constexpr size_t kComponentCount = 4; 58 | static constexpr Gltf::Accessor::Type kGltfType = Gltf::Accessor::kTypeVec4; 59 | static void CopyVec(const float* src, GfQuatf* dst) { 60 | *dst = GfQuatf(src[3], src[0], src[1], src[2]); 61 | } 62 | }; 63 | 64 | template <> struct CopyAccessorHandler { 65 | static constexpr size_t kComponentCount = 16; 66 | static constexpr Gltf::Accessor::Type kGltfType = Gltf::Accessor::kTypeMat4; 67 | static void CopyVec(const float* src, GfMatrix4f* dst) { 68 | *dst = ToMatrix4f(src); 69 | } 70 | }; 71 | 72 | template 73 | size_t CopyAccessorToScalars( 74 | const Gltf& gltf, Gltf::Id accessor_id, const std::vector& used, 75 | GltfCache* gltf_cache, std::vector* out_scalars) { 76 | size_t src_vec_count, component_count; 77 | const Dst* src = 78 | gltf_cache->Access(accessor_id, &src_vec_count, &component_count); 79 | if (!src) { 80 | return 0; 81 | } 82 | UFG_ASSERT_FORMAT(src_vec_count == used.size()); 83 | std::vector scalars(src_vec_count * component_count); 84 | std::vector dst_buffer(src_vec_count * component_count); 85 | Dst* dst = scalars.data(); 86 | for (size_t i = 0; i != src_vec_count; ++i, src += component_count) { 87 | if (!used[i]) { 88 | continue; 89 | } 90 | std::copy(src, src + component_count, dst); 91 | dst += component_count; 92 | } 93 | scalars.resize(dst - scalars.data()); 94 | if (scalars.empty()) { 95 | return 0; 96 | } 97 | out_scalars->swap(scalars); 98 | return component_count; 99 | } 100 | 101 | template 102 | size_t CopyAccessorToScalars( 103 | const Gltf& gltf, const Gltf::Mesh::AttributeSet& attrs, 104 | const Gltf::Mesh::Attribute& key, const std::vector& used, 105 | GltfCache* gltf_cache, std::vector* out_scalars) { 106 | const auto found = attrs.find(key); 107 | if (found == attrs.end()) { 108 | return 0; 109 | } 110 | return CopyAccessorToScalars( 111 | gltf, found->accessor, used, gltf_cache, out_scalars); 112 | } 113 | 114 | template 115 | void CopyAccessorToVectors( 116 | const Gltf& gltf, Gltf::Id accessor_id, 117 | GltfCache* gltf_cache, std::vector* out_vecs) { 118 | using Handler = CopyAccessorHandler; 119 | size_t vec_count, component_count; 120 | const float* const scalars = gltf_cache->Access( 121 | accessor_id, &vec_count, &component_count); 122 | UFG_ASSERT_FORMAT(component_count == Handler::kComponentCount); 123 | out_vecs->resize(vec_count); 124 | const float* src = scalars; 125 | DstVec* dst = out_vecs->data(); 126 | for (size_t i = 0; i != vec_count; ++i) { 127 | Handler::CopyVec(src, dst); 128 | src += component_count; 129 | ++dst; 130 | } 131 | } 132 | 133 | template 134 | void CopyAccessorToVectors( 135 | const Gltf& gltf, Gltf::Id accessor_id, const std::vector& used, 136 | GltfCache* gltf_cache, Array* out_vecs) { 137 | using Vec = typename Array::value_type; 138 | using Scalar = typename Vec::ScalarType; 139 | static_assert(sizeof(Vec) / sizeof(Scalar) == Vec::dimension, ""); 140 | size_t src_vec_count, component_count; 141 | const Scalar* const scalars = gltf_cache->Access( 142 | accessor_id, &src_vec_count, &component_count); 143 | UFG_ASSERT_LOGIC(component_count == Vec::dimension); 144 | const Scalar* src = scalars; 145 | out_vecs->resize(src_vec_count); 146 | if (src_vec_count > 0) { 147 | Scalar* dst = out_vecs->data()->data(); 148 | for (size_t i = 0; i != src_vec_count; ++i, src += component_count) { 149 | if (!used[i]) { 150 | continue; 151 | } 152 | std::copy(src, src + component_count, dst); 153 | dst += component_count; 154 | } 155 | const size_t dst_scalar_count = dst - out_vecs->data()->data(); 156 | const size_t dst_vec_count = dst_scalar_count / Vec::dimension; 157 | out_vecs->resize(dst_vec_count); 158 | } 159 | } 160 | 161 | template 162 | bool CopyAccessorToVectors( 163 | const Gltf& gltf, const Gltf::Mesh::AttributeSet& attrs, 164 | const Gltf::Mesh::Attribute& key, const std::vector& used, 165 | GltfCache* gltf_cache, Array* out_vecs) { 166 | const auto found = attrs.find(key); 167 | if (found == attrs.end()) { 168 | return false; 169 | } 170 | Array vecs; 171 | CopyAccessorToVectors(gltf, found->accessor, used, gltf_cache, &vecs); 172 | if (vecs.empty()) { 173 | return false; 174 | } 175 | out_vecs->swap(vecs); 176 | return true; 177 | } 178 | 179 | inline size_t GetAttributeComponentCount( 180 | const Gltf& gltf, const Gltf::Mesh::AttributeSet& attrs, 181 | const Gltf::Mesh::Attribute& key) { 182 | const auto found = attrs.find(key); 183 | if (found == attrs.end()) { 184 | return 0; 185 | } 186 | const Gltf::Accessor* const accessor = 187 | Gltf::GetById(gltf.accessors, found->accessor); 188 | return accessor ? Gltf::GetComponentCount(accessor->type) : 0; 189 | } 190 | } // namespace ufg 191 | 192 | #endif // UFG_PROCESS_ACCESS_H_ 193 | -------------------------------------------------------------------------------- /process/color.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "process/color.h" 18 | 19 | #include "process/math.h" 20 | 21 | namespace ufg { 22 | const ColorF ColorF::kZero = { { { 0.0f, 0.0f, 0.0f, 0.0f } } }; 23 | const ColorF ColorF::kOne = { { { 1.0f, 1.0f, 1.0f, 1.0f } } }; 24 | 25 | // Specular+diffuse --> metallic+base conversion based on: 26 | // https://github.com/bghgary/glTF-Tools-for-Unity/blob/master/UnityProject/Assets/Gltf/PbrUtilities.cs#L24 27 | // Linked from here: https://github.com/AnalyticalGraphicsInc/gltf-pipeline/issues/331 28 | constexpr float kSpecDielectric = 0.04f; 29 | constexpr float kSpecMetalZeroTol = 0.000001f; 30 | 31 | static float GetPerceivedBrightness(float r, float g, float b) { 32 | return 0.299f * r + 0.587f * g + 0.114f * b; 33 | } 34 | 35 | static float SolveMetallic(float dielectric_spec, float diffuse, 36 | float spec_bright, float inv_spec_max) { 37 | if (spec_bright < dielectric_spec) { 38 | return 0.0f; 39 | } 40 | const float a = dielectric_spec; 41 | const float b = diffuse * inv_spec_max / (1 - dielectric_spec) + spec_bright - 42 | 2.0f * dielectric_spec; 43 | const float c = dielectric_spec - spec_bright; 44 | const float det = b * b - 4.0f * a * c; 45 | const float result = (-b + std::sqrt(det)) / (2.0f * a); 46 | return Clamp(result, 0.0f, 1.0f); 47 | } 48 | 49 | void SpecDiffToMetalBase( 50 | const float* spec, const float* diff, float* out_metal, float* out_base) { 51 | const float spec_r = spec[kColorChannelR]; 52 | const float spec_g = spec[kColorChannelG]; 53 | const float spec_b = spec[kColorChannelB]; 54 | const float diff_r = diff[kColorChannelR]; 55 | const float diff_g = diff[kColorChannelG]; 56 | const float diff_b = diff[kColorChannelB]; 57 | 58 | const float spec_max = Max3(spec_r, spec_g, spec_b); 59 | const float spec_bright = GetPerceivedBrightness(spec_r, spec_g, spec_b); 60 | const float inv_spec_max = 1.0f - spec_max; 61 | const float diff_bright = GetPerceivedBrightness(diff_r, diff_g, diff_b); 62 | const float metal = 63 | SolveMetallic(kSpecDielectric, diff_bright, spec_bright, inv_spec_max); 64 | const float inv_metal = 1.0f - metal; 65 | const float metal_sq = metal * metal; 66 | const float a = 67 | (1.0f - metal_sq) * inv_spec_max / 68 | ((1.0f - kSpecDielectric) * std::max(inv_metal, kSpecMetalZeroTol)); 69 | const float b = metal_sq / std::max(metal, kSpecMetalZeroTol); 70 | const float c = -kSpecDielectric * inv_metal * b; 71 | const float base_r = diff_r * a + spec_r * b + c; 72 | const float base_g = diff_g * a + spec_g * b + c; 73 | const float base_b = diff_b * a + spec_b * b + c; 74 | 75 | *out_metal = metal; 76 | out_base[kColorChannelR] = base_r; 77 | out_base[kColorChannelG] = base_g; 78 | out_base[kColorChannelB] = base_b; 79 | } 80 | } // namespace ufg 81 | -------------------------------------------------------------------------------- /process/color.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_COLOR_H_ 18 | #define UFG_PROCESS_COLOR_H_ 19 | 20 | #include "common/common.h" 21 | #include "common/config.h" 22 | #include "common/logging.h" 23 | 24 | namespace ufg { 25 | // Channel indices, indicating RGBA component ordering in the uncompressed 26 | // buffer. 27 | enum ColorChannel : uint8_t { 28 | kColorChannelR, 29 | kColorChannelG, 30 | kColorChannelB, 31 | kColorChannelA, 32 | kColorChannelCount 33 | }; 34 | 35 | // Floating-point color. 36 | struct ColorF { 37 | union { 38 | float c[kColorChannelCount]; 39 | struct { 40 | float r, g, b, a; 41 | }; 42 | }; 43 | 44 | static const ColorF kZero; 45 | static const ColorF kOne; 46 | 47 | void Assign(float r, float g, float b, float a) { 48 | this->r = r; 49 | this->g = g; 50 | this->b = b; 51 | this->a = a; 52 | } 53 | 54 | void Assign(const float (&rgb)[3], float a) { 55 | this->r = rgb[kColorChannelR]; 56 | this->g = rgb[kColorChannelG]; 57 | this->b = rgb[kColorChannelB]; 58 | this->a = a; 59 | } 60 | 61 | void Assign(const float (&rgba)[4]) { 62 | this->r = rgba[kColorChannelR]; 63 | this->g = rgba[kColorChannelG]; 64 | this->b = rgba[kColorChannelB]; 65 | this->a = rgba[kColorChannelA]; 66 | } 67 | 68 | template 69 | void SetChannels(const float (&f)[kCount]) { 70 | static_assert(kCount <= kColorChannelCount, ""); 71 | for (size_t i = 0; i != kCount; ++i) { 72 | c[i] = f[i]; 73 | } 74 | } 75 | 76 | ColorF& operator=(float f) { 77 | r = f; 78 | g = f; 79 | b = f; 80 | a = f; 81 | return *this; 82 | } 83 | 84 | GfVec4f ToVec4() const { 85 | return GfVec4f(c[kColorChannelR], c[kColorChannelG], c[kColorChannelB], 86 | c[kColorChannelA]); 87 | } 88 | GfVec3f ToVec3() const { 89 | return GfVec3f(c[kColorChannelR], c[kColorChannelG], c[kColorChannelB]); 90 | } 91 | }; 92 | 93 | template Vec ColorToVec(const ColorF& color); 94 | template <> 95 | inline GfVec4f ColorToVec(const ColorF& color) { 96 | return color.ToVec4(); 97 | } 98 | template <> 99 | inline GfVec3f ColorToVec(const ColorF& color) { 100 | return color.ToVec3(); 101 | } 102 | template <> 103 | inline float ColorToVec(const ColorF& color) { 104 | return color.r; 105 | } 106 | 107 | // Integer color. 108 | struct ColorI { 109 | int c[kColorChannelCount]; 110 | 111 | static ColorI FromFloat(const float (&color)[4], uint32_t units); 112 | 113 | static bool Equal(const ColorI& a, const ColorI& b, size_t count) { 114 | UFG_ASSERT_LOGIC(count <= UFG_ARRAY_SIZE(a.c)); 115 | for (size_t i = 0; i != count; ++i) { 116 | if (a.c[i] != b.c[i]) { 117 | return false; 118 | } 119 | } 120 | return true; 121 | } 122 | 123 | // Defines a strict less-than ordering, for use with comparison operators. 124 | static bool Less(const ColorI& a, const ColorI& b, size_t count) { 125 | UFG_ASSERT_LOGIC(count <= UFG_ARRAY_SIZE(a.c)); 126 | for (size_t i = 0; i != count; ++i) { 127 | const int ac = a.c[i]; 128 | const int bc = b.c[i]; 129 | if (ac != bc) { 130 | return ac < bc; 131 | } 132 | } 133 | return false; 134 | } 135 | 136 | friend bool operator==(const ColorI& a, const ColorI& b) { 137 | return Equal(a, b, UFG_ARRAY_SIZE(a.c)); 138 | } 139 | 140 | friend bool operator!=(const ColorI& a, const ColorI& b) { 141 | return !(a == b); 142 | } 143 | 144 | friend bool operator<(const ColorI& a, const ColorI& b) { 145 | return Less(a, b, UFG_ARRAY_SIZE(a.c)); 146 | } 147 | }; 148 | 149 | void SpecDiffToMetalBase( 150 | const float* spec, const float* diff, float* out_metal, float* out_base); 151 | } // namespace ufg 152 | 153 | #endif // UFG_PROCESS_COLOR_H_ 154 | -------------------------------------------------------------------------------- /process/float_image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_FLOAT_IMAGE_H_ 18 | #define UFG_PROCESS_FLOAT_IMAGE_H_ 19 | 20 | #include 21 | #include "process/image.h" 22 | 23 | namespace ufg { 24 | enum ColorSpace : uint8_t { 25 | kColorSpaceLinear, 26 | kColorSpaceSrgb, 27 | }; 28 | 29 | // Image data stored as linear floating-point values, for use in texture 30 | // reprocessing. 31 | class FloatImage { 32 | public: 33 | FloatImage(); 34 | FloatImage(const Image& src, ColorSpace src_color_space); 35 | 36 | bool IsValid() const { return width_ != 0; } 37 | uint32_t GetWidth() const { return width_; } 38 | uint32_t GetHeight() const { return height_; } 39 | uint32_t GetChannelCount() const { return channel_count_; } 40 | 41 | // Copy quantized image into this image, converting sRGB->linear if necessary. 42 | void CopyFrom(const Image& src, ColorSpace src_color_space); 43 | 44 | // Copy this image into a quantized image, converting linear->sRGB if 45 | // necessary. 46 | void CopyTo(ColorSpace dst_color_space, Image* dst) const; 47 | 48 | // Scale and bias pixel colors. 49 | void ScaleBias(const ColorF& scale, const ColorF& bias); 50 | 51 | // Scale and bias normal-map values in normal vector space ([0,1] -> [-1,1]), 52 | // and rescaling as necessary to prevent quantization clamping. 53 | void ScaleBiasNormals(const ColorF& scale, const ColorF& bias); 54 | 55 | // Convert specular+diffuse --> metallic+base. 56 | // * Diffuse is converted to base in-place, preserving the alpha channel if it 57 | // exists. 58 | static void ConvertSpecDiffToMetalBase( 59 | const FloatImage& in_spec, 60 | FloatImage* in_diff_out_base, FloatImage* out_metal); 61 | 62 | // Filtered image resize. 63 | void Resize(size_t width, size_t height, bool premul_alpha); 64 | 65 | private: 66 | uint32_t width_; 67 | uint32_t height_; 68 | uint32_t channel_count_; 69 | std::vector pixels_; 70 | 71 | void Reset(size_t width, size_t height, size_t channel_count) { 72 | width_ = static_cast(width); 73 | height_ = static_cast(height); 74 | channel_count_ = static_cast(channel_count); 75 | pixels_.clear(); 76 | pixels_.resize(width * height * channel_count); 77 | } 78 | }; 79 | } // namespace ufg 80 | #endif // UFG_PROCESS_FLOAT_IMAGE_H_ 81 | -------------------------------------------------------------------------------- /process/image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_IMAGE_H_ 18 | #define UFG_PROCESS_IMAGE_H_ 19 | 20 | #include 21 | #include 22 | #include "common/common.h" 23 | #include "common/config.h" 24 | #include "common/logging.h" 25 | #include "gltf/gltf.h" 26 | #include "process/color.h" 27 | 28 | namespace ufg { 29 | class Image { 30 | public: 31 | enum FileType : uint8_t { 32 | kFileTypeJpg, 33 | kFileTypePng, 34 | }; 35 | 36 | // A single component (R, G, B, or A). 37 | using Component = uint8_t; 38 | 39 | struct Transform { 40 | enum Type { 41 | kTypeNone, // Copy channel as-is. 42 | kTypeInvert, // 1.0 - channel 43 | }; 44 | Type type; 45 | static const Transform kNone; 46 | static const Transform kInvert; 47 | }; 48 | 49 | static constexpr Image::Component kComponentMax = 50 | std::numeric_limits::max(); 51 | static constexpr float kComponentToFloatScale = 1.0f / kComponentMax; 52 | 53 | inline static constexpr float ComponentToFloat(Image::Component c) { 54 | return c * kComponentToFloatScale; 55 | } 56 | 57 | inline static constexpr Image::Component FloatToComponent(float f) { 58 | return f <= 0.0f ? 59 | 0 : (f >= 1.0f ? kComponentMax : 60 | static_cast(f * kComponentMax + 0.5f)); 61 | } 62 | 63 | template 64 | inline static void ComponentToFloat(const Image::Component (&c)[kCount], 65 | float (&out_f)[kCount]) { 66 | for (size_t i = 0; i != kCount; ++i) { 67 | out_f[i] = ComponentToFloat(c[i]); 68 | } 69 | } 70 | 71 | template 72 | inline static void FloatToComponent(const float (&f)[kCount], 73 | Image::Component (&out_c)[kCount]) { 74 | for (size_t i = 0; i != kCount; ++i) { 75 | out_c[i] = FloatToComponent(f[i]); 76 | } 77 | } 78 | 79 | Image(); 80 | ~Image(); 81 | 82 | bool IsValid() const { return width_ != 0; } 83 | uint32_t GetWidth() const { return width_; } 84 | uint32_t GetHeight() const { return height_; } 85 | uint32_t GetChannelCount() const { return channel_count_; } 86 | const Component* GetData() const { return buffer_.data(); } 87 | Component* ModifyData() { return buffer_.data(); } 88 | 89 | void Clear(); 90 | bool Read( 91 | const void* buffer, size_t size, Gltf::Image::MimeType mime_type, 92 | Logger* logger); 93 | bool Write( 94 | const char* path, const ConvertSettings& settings, 95 | Logger* logger, bool is_norm = false) const; 96 | 97 | void CreateFromChannel( 98 | const Image& src, ColorChannel channel, const Transform& transform); 99 | void CreateFromRgb(const Image& src); 100 | void CreateFromRgba(const Image& src, Component default_alpha); 101 | void CreateFromMasked(const Image& src, 102 | const Component (&keep_mask)[kColorChannelCount], 103 | const Component (&replace_value)[kColorChannelCount]); 104 | 105 | bool ChannelEquals(ColorChannel channel, Component value) const; 106 | 107 | std::vector ToFloat(bool srgb_to_linear) const; 108 | void CreateFromFloat(const float* data, size_t width, size_t height, 109 | size_t channel_count, bool linear_to_srgb); 110 | 111 | void Create1x1(const Component *color, size_t channel_count); 112 | void CreateWxH(size_t width, size_t height, 113 | const Component* color, size_t channel_count); 114 | 115 | template 116 | void Create1x1(const Component (&color)[kCount]) { 117 | Create1x1(color, kCount); 118 | } 119 | 120 | void CreateR1x1(Component r) { 121 | Create1x1(&r, 1); 122 | } 123 | 124 | enum Content : uint8_t { 125 | kContentSolid0, // All values 0.0. 126 | kContentSolid1, // All values 1.0. 127 | kContentSolid, // All values constant in the closed range (0.0, 1.0). 128 | kContentBinary, // All values 0.0 or 1.0. 129 | kContentVarying, // Values vary over the open range [0.0, 1.0]. 130 | kContentCount 131 | }; 132 | 133 | static bool IsSolid(Content content) { 134 | return content == kContentSolid0 || content == kContentSolid1 || 135 | content == kContentSolid; 136 | } 137 | 138 | static bool IsBinary(Content content) { 139 | return content == kContentSolid0 || content == kContentSolid1 || 140 | content == kContentBinary; 141 | } 142 | 143 | static bool AreChannelsSolid( 144 | size_t channel_mask, const Content (&content)[kColorChannelCount]) { 145 | uint32_t bit = 1; 146 | for (uint32_t i = 0; i != kColorChannelCount; ++i) { 147 | if ((channel_mask & bit) && !IsSolid(content[i])) { 148 | return false; 149 | } 150 | bit = bit << 1; 151 | } 152 | return true; 153 | } 154 | 155 | // * If fix_accidental_alpha is set, ignore edge pixels for RGBA images to 156 | // work around accidental transparency (e.g. transparency introduced due to 157 | // resizing in Photoshop). 158 | void GetContents(Content (&out_content)[kColorChannelCount], 159 | bool fix_accidental_alpha, 160 | Component (&out_solid_color)[kColorChannelCount]) const; 161 | 162 | bool AreChannelsSolid( 163 | bool fix_accidental_alpha, 164 | Component (&out_solid_color)[kColorChannelCount]) const { 165 | Content content[kColorChannelCount]; 166 | GetContents(content, fix_accidental_alpha, out_solid_color); 167 | const size_t channel_mask = (1 << channel_count_) - 1; 168 | return AreChannelsSolid(channel_mask, content); 169 | } 170 | 171 | // Normalize normal map vectors. 172 | void NormalizeNormals(); 173 | 174 | // Apply alpha cutoff so all alpha values >= cutoff are 1.0, and 0.0 175 | // otherwise. 176 | void ApplyAlphaCutoff(Component cutoff); 177 | 178 | // Invert (1.0-src) each color component. 179 | void Invert(); 180 | 181 | private: 182 | uint32_t width_; 183 | uint32_t height_; 184 | uint8_t channel_count_; 185 | std::vector buffer_; 186 | }; 187 | } // namespace ufg 188 | #endif // UFG_PROCESS_IMAGE_H_ 189 | -------------------------------------------------------------------------------- /process/image_fallback.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "process/image_png.h" 18 | 19 | #include "stb_image.h" // NOLINT: Silence relative path warning. 20 | 21 | namespace ufg { 22 | bool ImageFallbackRead( 23 | const void* src, size_t src_size, 24 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 25 | std::vector* out_buffer, Logger* logger) { 26 | const int len = static_cast(src_size); 27 | UFG_ASSERT_FORMAT(static_cast(len) == src_size); 28 | int width, height, channel_count; 29 | stbi_uc* const data = stbi_load_from_memory( 30 | static_cast(src), len, 31 | &width, &height, &channel_count, 0); 32 | if (!data) { 33 | Log(logger, ""); 34 | return false; 35 | } 36 | const size_t buffer_size = width * height * channel_count; 37 | out_buffer->assign(data, data + buffer_size); 38 | stbi_image_free(data); 39 | *out_width = width; 40 | *out_height = height; 41 | *out_channel_count = channel_count; 42 | return true; 43 | } 44 | } // namespace ufg 45 | -------------------------------------------------------------------------------- /process/image_fallback.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_IMAGE_FALLBACK_H_ 18 | #define UFG_PROCESS_IMAGE_FALLBACK_H_ 19 | 20 | #include "process/image.h" 21 | 22 | // Fallback support for various input-only image formats. 23 | namespace ufg { 24 | bool ImageFallbackRead(const void* src, size_t src_size, 25 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 26 | std::vector* out_buffer, Logger* logger); 27 | } // namespace ufg 28 | 29 | #endif // UFG_PROCESS_IMAGE_FALLBACK_H_ 30 | -------------------------------------------------------------------------------- /process/image_gif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_IMAGE_GIF_H_ 18 | #define UFG_PROCESS_IMAGE_GIF_H_ 19 | 20 | #include "process/image.h" 21 | 22 | // Read GIF files via libgif. 23 | namespace ufg { 24 | bool HasGifHeader(const void* src, size_t src_size); 25 | bool GifRead( 26 | const void* src, size_t src_size, 27 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 28 | std::vector* out_buffer, Logger* logger); 29 | } // namespace ufg 30 | 31 | #endif // UFG_PROCESS_IMAGE_GIF_H_ 32 | -------------------------------------------------------------------------------- /process/image_jpg.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "process/image_jpg.h" 18 | 19 | #include "gltf/disk_util.h" 20 | #include "gltf/stream.h" 21 | #include "process/math.h" 22 | #include "turbojpeg.h" // NOLINT: Silence relative path warning. 23 | 24 | namespace ufg { 25 | namespace { 26 | struct JpgDecompressor { 27 | tjhandle handle; 28 | JpgDecompressor() : handle(tjInitDecompress()) {} 29 | ~JpgDecompressor() { tjDestroy(handle); } 30 | }; 31 | 32 | struct JpgCompressor { 33 | tjhandle handle; 34 | JpgCompressor() : handle(tjInitCompress()) {} 35 | ~JpgCompressor() { tjDestroy(handle); } 36 | }; 37 | 38 | const char* JpgGetErrorStr(tjhandle handle) { 39 | // TODO: Use tjGetErrorStr2(handle), which is thread-safe but only 40 | // available in newer versions of the library. 41 | return tjGetErrorStr(); 42 | } 43 | } // namespace 44 | 45 | bool HasJpgHeader(const void* src, size_t src_size) { 46 | // JPEG doesn't have a fixed header signature, but the first two bytes should 47 | // always be FF D8. Checking just these two bytes isn't completely accurate, 48 | // but is unique amongst the image formats we support. 49 | // See: https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format 50 | if (src_size < 2) { 51 | return false; 52 | } 53 | const uint8_t* const header = static_cast(src); 54 | return header[0] == 0xff && header[1] == 0xd8; 55 | } 56 | 57 | bool JpgRead( 58 | const void* src, size_t src_size, 59 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 60 | std::vector* out_buffer, Logger* logger) { 61 | JpgDecompressor decompressor; 62 | int width, height, subsamp, colorspace; 63 | const int header_result = tjDecompressHeader3(decompressor.handle, 64 | static_cast(src), 65 | static_cast(src_size), // NOLINT 66 | &width, &height, &subsamp, &colorspace); 67 | if (header_result != 0) { 68 | Log( 69 | logger, "", JpgGetErrorStr(decompressor.handle)); 70 | return false; 71 | } 72 | constexpr int kJpgChannelCount = 3; 73 | const int pitch = width * kJpgChannelCount; 74 | const int kFormat = TJPF_RGB; 75 | const int kFlags = 0; 76 | const size_t dst_size = pitch * height; 77 | out_buffer->resize(dst_size); 78 | const int decompress_result = tjDecompress2(decompressor.handle, 79 | static_cast(src), 80 | static_cast(src_size), // NOLINT 81 | out_buffer->data(), width, pitch, height, kFormat, kFlags); 82 | if (decompress_result != 0) { 83 | Log( 84 | logger, "", JpgGetErrorStr(decompressor.handle)); 85 | return false; 86 | } 87 | *out_width = width; 88 | *out_height = height; 89 | *out_channel_count = kJpgChannelCount; 90 | return true; 91 | } 92 | 93 | bool JpgWrite( 94 | const char* path, uint32_t width, uint32_t height, uint8_t channel_count, 95 | const Image::Component* data, int quality, int subsamp, Logger* logger) { 96 | // Choose quality and chroma subsampling method. 97 | quality = Clamp(quality, 1, 100); 98 | static_assert(TJSAMP_444 == 0 && TJSAMP_422 == 1 && TJSAMP_420 == 2, ""); 99 | subsamp = channel_count == 1 ? TJSAMP_GRAY : Clamp(subsamp, 0, 2); 100 | 101 | // Determine input format. 102 | // * JPG only supports 1- or 3-channel textures. For 4-channel we discard 103 | // alpha, and 2-channel is not used by this library. 104 | UFG_ASSERT_LOGIC( 105 | channel_count == 1 || channel_count == 3 || channel_count == 4); 106 | const int format = channel_count == 1 ? 107 | TJPF_GRAY : (channel_count == 4 ? TJPF_RGBX : TJPF_RGB); 108 | 109 | const int pitch = width * channel_count; 110 | unsigned char* jpg_data = nullptr; 111 | unsigned long jpg_size = 0; // NOLINT 112 | JpgCompressor compressor; 113 | bool success = tjCompress2( 114 | compressor.handle, data, width, pitch, height, format, 115 | &jpg_data, &jpg_size, subsamp, quality, TJFLAG_FASTDCT) == 0; 116 | if (!success) { 117 | Log(logger, "", JpgGetErrorStr(compressor.handle)); 118 | } 119 | if (success) { 120 | success = GltfDiskWriteBinary(path, jpg_data, jpg_size); 121 | if (!success) { 122 | Log(logger, "", path); 123 | } 124 | } 125 | tjFree(jpg_data); 126 | return success; 127 | } 128 | } // namespace ufg 129 | -------------------------------------------------------------------------------- /process/image_jpg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_IMAGE_JPG_H_ 18 | #define UFG_PROCESS_IMAGE_JPG_H_ 19 | 20 | #include "process/image.h" 21 | 22 | // Read/write JPG files via libjpeg-turbo. 23 | namespace ufg { 24 | bool HasJpgHeader(const void* src, size_t src_size); 25 | bool JpgRead( 26 | const void* src, size_t src_size, 27 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 28 | std::vector* out_buffer, Logger* logger); 29 | 30 | // * quality: JPG compression quality [1=worst, 100=best]. 31 | // * subsamp: JPG chroma subsampling method [0=best, 2=worst]. 32 | bool JpgWrite( 33 | const char* path, uint32_t width, uint32_t height, uint8_t channel_count, 34 | const Image::Component* data, int quality, int subsamp, Logger* logger); 35 | } // namespace ufg 36 | 37 | #endif // UFG_PROCESS_IMAGE_JPG_H_ 38 | -------------------------------------------------------------------------------- /process/image_png.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_IMAGE_PNG_H_ 18 | #define UFG_PROCESS_IMAGE_PNG_H_ 19 | 20 | #include "process/image.h" 21 | 22 | // Read/write PNG files via libpng. 23 | namespace ufg { 24 | bool HasPngHeader(const void* src, size_t src_size); 25 | bool PngRead( 26 | const void* src, size_t src_size, 27 | uint32_t* out_width, uint32_t* out_height, uint8_t* out_channel_count, 28 | std::vector* out_buffer, Logger* logger); 29 | 30 | // * level: PNG compression level [0=fastest, 9=smallest]. 31 | bool PngWrite( 32 | const char* path, uint32_t width, uint32_t height, uint8_t channel_count, 33 | const Image::Component* data, int level, Logger* logger); 34 | } // namespace ufg 35 | 36 | #endif // UFG_PROCESS_IMAGE_PNG_H_ 37 | -------------------------------------------------------------------------------- /process/mesh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_MESH_H_ 18 | #define UFG_PROCESS_MESH_H_ 19 | 20 | #include 21 | #include "common/common.h" 22 | #include "common/logging.h" 23 | #include "gltf/cache.h" 24 | #include "gltf/gltf.h" 25 | #include "process/math.h" 26 | #include "pxr/base/vt/array.h" 27 | 28 | namespace ufg { 29 | using PXR_NS::VtArray; 30 | 31 | constexpr uint32_t kNoIndex = std::numeric_limits::max(); 32 | 33 | size_t GetUsedPoints( 34 | size_t pos_count, const uint32_t* indices, size_t count, 35 | std::vector* out_used); 36 | 37 | void GetTriIndices( 38 | const std::vector& pos_to_point_map, 39 | const uint32_t* indices, size_t count, 40 | VtArray* out_vert_counts, VtArray* out_vert_indices); 41 | 42 | template 43 | void ReverseTriWinding(T* indices, size_t count) { 44 | UFG_ASSERT_LOGIC(count % 3 == 0); 45 | T* const end = indices + count; 46 | for (T* it = indices; it != end; it += 3) { 47 | const T i1 = it[1]; 48 | const T i2 = it[2]; 49 | it[1] = i2; 50 | it[2] = i1; 51 | } 52 | } 53 | 54 | struct PrimInfo { 55 | using Uvset = VtArray; 56 | using UvsetMap = std::map; 57 | VtArray tri_vert_counts; 58 | VtArray tri_vert_indices; 59 | VtArray pos; 60 | VtArray norm; 61 | UvsetMap uvs; 62 | uint8_t color_stride = 0; 63 | uint8_t skin_index_stride = 0; 64 | uint8_t skin_weight_stride = 0; 65 | VtArray color3; 66 | VtArray color4; 67 | std::vector skin_indices; 68 | std::vector skin_weights; 69 | 70 | void Swap(PrimInfo* other); 71 | }; 72 | 73 | struct MeshInfo { 74 | std::vector prims; 75 | }; 76 | 77 | void GetMeshInfo(const Gltf& gltf, Gltf::Id mesh_id, GltfCache* gltf_cache, 78 | MeshInfo* out_info, Logger* logger); 79 | } // namespace ufg 80 | 81 | #endif // UFG_PROCESS_MESH_H_ 82 | -------------------------------------------------------------------------------- /process/process_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "process/process_util.h" 18 | 19 | #include "common/logging.h" 20 | 21 | namespace ufg { 22 | namespace { 23 | bool IsIncludedNode(const Gltf& gltf, Gltf::Id node_id, 24 | const std::vector& remove_node_prefixes) { 25 | if (remove_node_prefixes.empty()) { 26 | return true; 27 | } 28 | const Gltf::Node& node = *UFG_VERIFY(Gltf::GetById(gltf.nodes, node_id)); 29 | return !Gltf::StringBeginsWithAnyCI( 30 | node.name.c_str(), node.name.length(), remove_node_prefixes); 31 | } 32 | 33 | void MarkUsedDescendants( 34 | const Gltf& gltf, const Gltf::Id root_id, 35 | const std::vector& remove_node_prefixes, 36 | std::vector* nodes_used) { 37 | if (!IsIncludedNode(gltf, root_id, remove_node_prefixes)) { 38 | return; 39 | } 40 | const Gltf::Node& root_node = *UFG_VERIFY(Gltf::GetById(gltf.nodes, root_id)); 41 | (*nodes_used)[Gltf::IdToIndex(root_id)] = true; 42 | for (const Gltf::Id child_id : root_node.children) { 43 | MarkUsedDescendants(gltf, child_id, remove_node_prefixes, nodes_used); 44 | } 45 | } 46 | } // namespace 47 | 48 | std::vector GetNodeParents(const std::vector& nodes) { 49 | const size_t node_count = nodes.size(); 50 | std::vector node_parents(node_count, Gltf::Id::kNull); 51 | for (size_t node_index = 0; node_index != node_count; ++node_index) { 52 | const Gltf::Node& node = nodes[node_index]; 53 | for (const Gltf::Id child_id : node.children) { 54 | // TODO: Is it possible for a node to be reused in multiple 55 | // places in the hierarchy? Not sure if there's a way to express this in 56 | // USD. 57 | const size_t child_index = Gltf::IdToIndex(child_id); 58 | UFG_ASSERT_FORMAT(node_parents[child_index] == Gltf::Id::kNull); 59 | node_parents[child_index] = static_cast(node_index); 60 | } 61 | } 62 | return node_parents; 63 | } 64 | 65 | Gltf::Id GetCommonAncestor( 66 | const Gltf::Id* node_parents, Gltf::Id node_id0, Gltf::Id node_id1) { 67 | if (node_id0 != node_id1) { 68 | const size_t depth0 = GetDepth(node_parents, node_id0); 69 | const size_t depth1 = GetDepth(node_parents, node_id1); 70 | const size_t depth_min = std::min(depth0, depth1); 71 | node_id0 = TraverseUp(node_parents, node_id0, depth0 - depth_min); 72 | node_id1 = TraverseUp(node_parents, node_id1, depth1 - depth_min); 73 | while (node_id0 != node_id1) { 74 | node_id0 = node_parents[Gltf::IdToIndex(node_id0)]; 75 | node_id1 = node_parents[Gltf::IdToIndex(node_id1)]; 76 | } 77 | } 78 | return node_id0; 79 | } 80 | 81 | std::vector GetJointRoots( 82 | const Gltf::Id* node_parents, size_t node_count, 83 | const std::vector& joint_to_node_map) { 84 | std::vector nodes_used(node_count, false); 85 | for (const Gltf::Id node_id : joint_to_node_map) { 86 | nodes_used[Gltf::IdToIndex(node_id)] = true; 87 | } 88 | 89 | std::vector joint_roots; 90 | const size_t joint_count = joint_to_node_map.size(); 91 | for (size_t joint_index = 0; joint_index != joint_count; ++joint_index) { 92 | const Gltf::Id node_id = joint_to_node_map[joint_index]; 93 | Gltf::Id ancestor_node_id = node_parents[Gltf::IdToIndex(node_id)]; 94 | while (ancestor_node_id != Gltf::Id::kNull) { 95 | if (nodes_used[Gltf::IdToIndex(ancestor_node_id)]) { 96 | break; 97 | } 98 | ancestor_node_id = node_parents[Gltf::IdToIndex(ancestor_node_id)]; 99 | } 100 | if (ancestor_node_id == Gltf::Id::kNull) { 101 | joint_roots.push_back(static_cast(joint_index)); 102 | } 103 | } 104 | return joint_roots; 105 | } 106 | 107 | void MarkAffectedNodes( 108 | const std::vector& nodes, Gltf::Id node_id, 109 | std::vector* affected_node_ids) { 110 | const size_t node_index = Gltf::IdToIndex(node_id); 111 | if ((*affected_node_ids)[node_index]) { 112 | return; 113 | } 114 | (*affected_node_ids)[node_index] = true; 115 | const Gltf::Node& node = nodes[node_index]; 116 | for (const Gltf::Id child_node_id : node.children) { 117 | MarkAffectedNodes(nodes, child_node_id, affected_node_ids); 118 | } 119 | } 120 | 121 | std::vector GetSceneRootNodes( 122 | const Gltf& gltf, Gltf::Id scene_id, const Gltf::Id* node_parents, 123 | const std::vector& remove_node_prefixes) { 124 | // Flag used roots. 125 | const size_t node_count = gltf.nodes.size(); 126 | std::vector root_nodes_used(node_count, false); 127 | if (scene_id == Gltf::Id::kNull) { 128 | // Get all root nodes. 129 | for (size_t node_index = 0; node_index != node_count; ++node_index) { 130 | if (node_parents[node_index] == Gltf::Id::kNull) { 131 | const Gltf::Id node_id = Gltf::IndexToId(node_index); 132 | if (IsIncludedNode(gltf, node_id, remove_node_prefixes)) { 133 | root_nodes_used[node_index] = true; 134 | } 135 | } 136 | } 137 | } else { 138 | // Get root nodes for a single scene. 139 | const Gltf::Scene& scene = 140 | *UFG_VERIFY(Gltf::GetById(gltf.scenes, scene_id)); 141 | for (const Gltf::Id node_id : scene.nodes) { 142 | if (IsIncludedNode(gltf, node_id, remove_node_prefixes)) { 143 | root_nodes_used[Gltf::IdToIndex(node_id)] = true; 144 | } 145 | } 146 | } 147 | 148 | // Get the list of used roots. 149 | std::vector root_nodes; 150 | for (size_t node_index = 0; node_index != node_count; ++node_index) { 151 | if (root_nodes_used[node_index]) { 152 | root_nodes.push_back(Gltf::IndexToId(node_index)); 153 | } 154 | } 155 | return root_nodes; 156 | } 157 | 158 | std::vector GetNodesUnderRoots( 159 | const Gltf& gltf, const std::vector& root_nodes, 160 | const std::vector& remove_node_prefixes) { 161 | const size_t node_count = gltf.nodes.size(); 162 | std::vector nodes_used(node_count, false); 163 | for (const Gltf::Id root_id : root_nodes) { 164 | MarkUsedDescendants(gltf, root_id, remove_node_prefixes, &nodes_used); 165 | } 166 | 167 | size_t used_count = 0; 168 | for (const bool used : nodes_used) { 169 | if (used) { 170 | ++used_count; 171 | } 172 | } 173 | 174 | std::vector used_nodes; 175 | used_nodes.reserve(used_count); 176 | for (size_t node_index = 0; node_index != node_count; ++node_index) { 177 | if (nodes_used[node_index]) { 178 | used_nodes.push_back(Gltf::IndexToId(node_index)); 179 | } 180 | } 181 | return used_nodes; 182 | } 183 | } // namespace ufg 184 | -------------------------------------------------------------------------------- /process/process_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_PROCESS_UTIL_H_ 18 | #define UFG_PROCESS_PROCESS_UTIL_H_ 19 | 20 | #include 21 | #include "common/common.h" 22 | #include "common/logging.h" 23 | #include "gltf/gltf.h" 24 | #include "pxr/base/vt/array.h" 25 | 26 | namespace ufg { 27 | using PXR_NS::VtArray; 28 | 29 | std::vector GetNodeParents(const std::vector& nodes); 30 | 31 | // Recursively mark this node and its descendants as affected. 32 | void MarkAffectedNodes( 33 | const std::vector& nodes, Gltf::Id node_id, 34 | std::vector* affected_node_ids); 35 | 36 | std::vector GetSceneRootNodes( 37 | const Gltf& gltf, Gltf::Id scene_id, const Gltf::Id* node_parents, 38 | const std::vector& remove_node_prefixes); 39 | std::vector GetNodesUnderRoots( 40 | const Gltf& gltf, const std::vector& root_nodes, 41 | const std::vector& remove_node_prefixes); 42 | 43 | inline size_t GetDepth(const Gltf::Id* node_parents, Gltf::Id node_id) { 44 | size_t depth = 0; 45 | while (node_id != Gltf::Id::kNull) { 46 | ++depth; 47 | node_id = node_parents[Gltf::IdToIndex(node_id)]; 48 | } 49 | return depth; 50 | } 51 | 52 | inline Gltf::Id TraverseUp( 53 | const Gltf::Id* node_parents, Gltf::Id node_id, size_t height) { 54 | for (; height; --height) { 55 | node_id = node_parents[Gltf::IdToIndex(node_id)]; 56 | } 57 | return node_id; 58 | } 59 | 60 | inline Gltf::Id GetRoot(const Gltf::Id* node_parents, Gltf::Id node_id) { 61 | while (node_id != Gltf::Id::kNull) { 62 | node_id = node_parents[Gltf::IdToIndex(node_id)]; 63 | } 64 | return node_id; 65 | } 66 | 67 | inline bool IsEqualOrUnder( 68 | const Gltf::Id* node_parents, Gltf::Id ancestor_id, Gltf::Id node_id) { 69 | while (node_id != Gltf::Id::kNull) { 70 | if (node_id == ancestor_id) { 71 | return true; 72 | } 73 | node_id = node_parents[Gltf::IdToIndex(node_id)]; 74 | } 75 | return false; 76 | } 77 | 78 | Gltf::Id GetCommonAncestor( 79 | const Gltf::Id* node_parents, Gltf::Id node_id0, Gltf::Id node_id1); 80 | 81 | // Get indices of root joints (i.e. joints that are not a child of another 82 | // joint). 83 | std::vector GetJointRoots( 84 | const Gltf::Id* node_parents, size_t node_count, 85 | const std::vector& joint_to_node_map); 86 | 87 | // Get the full path of a node from the root. 88 | // * The path is filled-in from end to begin. The caller provides the end, and 89 | // the function returns the begin. 90 | inline Gltf::Id* GetNodePath( 91 | const Gltf::Id* node_parents, Gltf::Id node_id, Gltf::Id* out_end) { 92 | Gltf::Id* begin = out_end; 93 | while (node_id != Gltf::Id::kNull) { 94 | *--begin = node_id; 95 | node_id = node_parents[Gltf::IdToIndex(node_id)]; 96 | } 97 | return begin; 98 | } 99 | 100 | struct NodeIdTreeLess { 101 | const Gltf::Id* node_parents; 102 | mutable std::vector path0_buffer; 103 | mutable std::vector path1_buffer; 104 | NodeIdTreeLess(const Gltf::Id* node_parents, size_t node_count) 105 | : node_parents(node_parents), 106 | path0_buffer(node_count), 107 | path1_buffer(node_count) {} 108 | 109 | inline bool operator()(Gltf::Id node_id0, Gltf::Id node_id1) const { 110 | Gltf::Id* const path0_end = path0_buffer.data() + path0_buffer.size(); 111 | Gltf::Id* const path1_end = path1_buffer.data() + path1_buffer.size(); 112 | const Gltf::Id* const path0 = 113 | GetNodePath(node_parents, node_id0, path0_end); 114 | const Gltf::Id* const path1 = 115 | GetNodePath(node_parents, node_id1, path1_end); 116 | const size_t path0_len = path0_end - path0; 117 | const size_t path1_len = path1_end - path1; 118 | const size_t min_len = std::min(path0_len, path1_len); 119 | for (size_t i = 0; i != min_len; ++i) { 120 | if (path0[i] != path1[i]) { 121 | return path0[i] < path1[i]; 122 | } 123 | } 124 | return path0_len < path1_len; 125 | } 126 | }; 127 | 128 | } // namespace ufg 129 | 130 | #endif // UFG_PROCESS_PROCESS_UTIL_H_ 131 | -------------------------------------------------------------------------------- /process/skin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef UFG_PROCESS_SKIN_H_ 18 | #define UFG_PROCESS_SKIN_H_ 19 | 20 | #include 21 | #include "common/common.h" 22 | #include "process/access.h" 23 | #include "process/mesh.h" 24 | 25 | namespace ufg { 26 | using PXR_NS::TfToken; 27 | 28 | struct SkinInfluence { 29 | static constexpr uint16_t kUnused = 0xffffu; 30 | 31 | // GCC work-around. Some STL functions are taking a reference to kUnused 32 | // causing 'ODR-use', which means the value needs to be externally defined. 33 | // But since it's constexpr, we can't externally define it. So for these 34 | // cases we use a wrapper function to prevent the variable reference. 35 | // See: https://en.cppreference.com/w/cpp/language/definition#ODR-use 36 | // And: https://stackoverflow.com/questions/40690260/undefined-reference-error-for-static-constexpr-member 37 | static uint16_t Unused() { 38 | return kUnused; 39 | } 40 | 41 | uint16_t index; 42 | float weight; 43 | }; 44 | 45 | struct SkinBinding { 46 | static constexpr size_t kInfluenceMax = 4; 47 | SkinInfluence influences[kInfluenceMax]; 48 | 49 | // Sort weights greatest-to-least. 50 | void SortInfluencesByWeight(); 51 | 52 | void Normalize(size_t joint_count); 53 | void Assign( 54 | const int* indices, size_t index_count, 55 | const float* weights, size_t weight_count, size_t joint_count); 56 | size_t CountUsed() const; 57 | }; 58 | 59 | // Get skin information from glTF. 60 | struct SkinInfo { 61 | std::string name; 62 | Gltf::Id root_node_id; 63 | std::vector ujoint_to_node_map; 64 | VtArray ujoint_names; 65 | VtArray rest_mats; 66 | VtArray bind_mats; 67 | }; 68 | void GetSkinInfo( 69 | const Gltf& gltf, const std::vector& mesh_infos, Gltf::Id skin_id, 70 | const Gltf::Id* node_parents, const std::vector& scene_nodes, 71 | const std::vector* force_nodes_used, GltfCache* gltf_cache, 72 | SkinInfo* out_skin_info, 73 | std::vector* out_gjoint_to_ujoint_map); 74 | 75 | // Get the set of skin information for skins used in the scene, merging if 76 | // necessary. 77 | struct SkinSrc { 78 | uint32_t used_skin_index = ~0u; 79 | std::vector gjoint_to_ujoint_map; 80 | }; 81 | void GetUsedSkinInfos( 82 | const Gltf& gltf, const std::vector& mesh_infos, 83 | const Gltf::Id* node_parents, const std::vector& scene_nodes, 84 | const std::vector* force_nodes_used, bool merge, 85 | GltfCache* gltf_cache, 86 | std::vector* out_used_skin_infos, 87 | std::vector* out_gltf_skin_srcs); 88 | 89 | // Get skin data for a mesh. 90 | struct SkinData { 91 | uint8_t influence_count; 92 | bool is_rigid; 93 | std::vector bindings; 94 | }; 95 | bool GetSkinData( 96 | const int* indices, size_t index_stride, 97 | const float* weights, size_t weight_stride, 98 | size_t node_count, size_t vert_count, 99 | const uint16_t* gjoint_to_ujoint_map, size_t gjoint_count, 100 | SkinData* out_skin_data); 101 | 102 | // Get matrices used to animate skinned mesh normals. These transform vertices 103 | // from the bind-pose to object-space for the given animation joint rotations 104 | // and scales. 105 | void GetSkinJointMatricesForNormals( 106 | const SkinInfo& skin_info, size_t node_count, const Gltf::Id* node_parents, 107 | size_t ujoint_count, const GfQuatf* rots, const GfVec3f* scales, 108 | GfMatrix3f* out_norm_mats); 109 | 110 | // Skin vertex normals. 111 | // * norm_joint_mats is contains per-joint skinning matrices, inverse-transposed 112 | // for normal vector transformation. 113 | void SkinNormals( 114 | const GfMatrix3f* norm_joint_mats, const GfVec3f* norms, size_t norm_count, 115 | const SkinBinding* skin_bindings, 116 | GfVec3f* out_norms); 117 | 118 | } // namespace ufg 119 | 120 | #endif // UFG_PROCESS_SKIN_H_ 121 | -------------------------------------------------------------------------------- /testdata/samp_draco.csv: -------------------------------------------------------------------------------- 1 | @2.0 Samples - Draco 2 | 2CylinderEngine_draco, 2.0/2CylinderEngine/glTF-Draco/2CylinderEngine.gltf, 2.0/gltf_draco/2CylinderEngine 3 | Avocado_draco, 2.0/Avocado/glTF-Draco/Avocado.gltf, 2.0/gltf_draco/Avocado 4 | BarramundiFish_draco, 2.0/BarramundiFish/glTF-Draco/BarramundiFish.gltf, 2.0/gltf_draco/BarramundiFish 5 | BoomBox_draco, 2.0/BoomBox/glTF-Draco/BoomBox.gltf, 2.0/gltf_draco/BoomBox 6 | Box_draco, 2.0/Box/glTF-Draco/Box.gltf, 2.0/gltf_draco/Box 7 | BrainStem_draco, 2.0/BrainStem/glTF-Draco/BrainStem.gltf, 2.0/gltf_draco/BrainStem 8 | Buggy_draco, 2.0/Buggy/glTF-Draco/Buggy.gltf, 2.0/gltf_draco/Buggy 9 | CesiumMan_draco, 2.0/CesiumMan/glTF-Draco/CesiumMan.gltf, 2.0/gltf_draco/CesiumMan 10 | CesiumMilkTruck_draco, 2.0/CesiumMilkTruck/glTF-Draco/CesiumMilkTruck.gltf, 2.0/gltf_draco/CesiumMilkTruck 11 | Corset_draco, 2.0/Corset/glTF-Draco/Corset.gltf, 2.0/gltf_draco/Corset 12 | Duck_draco, 2.0/Duck/glTF-Draco/Duck.gltf, 2.0/gltf_draco/Duck 13 | GearboxAssy_draco, 2.0/GearboxAssy/glTF-Draco/GearboxAssy.gltf, 2.0/gltf_draco/GearboxAssy 14 | Lantern_draco, 2.0/Lantern/glTF-Draco/Lantern.gltf, 2.0/gltf_draco/Lantern 15 | Monster_draco, 2.0/Monster/glTF-Draco/Monster.gltf, 2.0/gltf_draco/Monster 16 | MorphPrimitivesTest_draco, 2.0/MorphPrimitivesTest/glTF-Draco/MorphPrimitivesTest.glb, 2.0/gltf_draco/MorphPrimitivesTest 17 | ReciprocatingSaw_draco, 2.0/ReciprocatingSaw/glTF-Draco/ReciprocatingSaw.gltf, 2.0/gltf_draco/ReciprocatingSaw 18 | RiggedFigure_draco, 2.0/RiggedFigure/glTF-Draco/RiggedFigure.gltf, 2.0/gltf_draco/RiggedFigure 19 | RiggedSimple_draco, 2.0/RiggedSimple/glTF-Draco/RiggedSimple.gltf, 2.0/gltf_draco/RiggedSimple 20 | VC_draco, 2.0/VC/glTF-Draco/VC.gltf, 2.0/gltf_draco/VC 21 | WaterBottle_draco, 2.0/WaterBottle/glTF-Draco/WaterBottle.gltf, 2.0/gltf_draco/WaterBottle 22 | -------------------------------------------------------------------------------- /testdata/samp_embed.csv: -------------------------------------------------------------------------------- 1 | @2.0 Samples - Embedded 2 | 2CylinderEngine_embed, 2.0/2CylinderEngine/glTF-Embedded/2CylinderEngine.gltf, 2.0/gltf_embed/2CylinderEngine 3 | AlphaBlendModeTest_embed, 2.0/AlphaBlendModeTest/glTF-Embedded/AlphaBlendModeTest.gltf, 2.0/gltf_embed/AlphaBlendModeTest 4 | AnimatedTriangle_embed, 2.0/AnimatedTriangle/glTF-Embedded/AnimatedTriangle.gltf, 2.0/gltf_embed/AnimatedTriangle 5 | Box_embed, 2.0/Box/glTF-Embedded/Box.gltf, 2.0/gltf_embed/Box 6 | BoxAnimated_embed, 2.0/BoxAnimated/glTF-Embedded/BoxAnimated.gltf, 2.0/gltf_embed/BoxAnimated 7 | BoxInterleaved_embed, 2.0/BoxInterleaved/glTF-Embedded/BoxInterleaved.gltf, 2.0/gltf_embed/BoxInterleaved 8 | BoxTextured_embed, 2.0/BoxTextured/glTF-Embedded/BoxTextured.gltf, 2.0/gltf_embed/BoxTextured 9 | BoxTexturedNonPowerOfTwo_embed, 2.0/BoxTexturedNonPowerOfTwo/glTF-Embedded/BoxTexturedNonPowerOfTwo.gltf, 2.0/gltf_embed/BoxTexturedNonPowerOfTwo 10 | BoxVertexColors_embed, 2.0/BoxVertexColors/glTF-Embedded/BoxVertexColors.gltf, 2.0/gltf_embed/BoxVertexColors 11 | BrainStem_embed, 2.0/BrainStem/glTF-Embedded/BrainStem.gltf, 2.0/gltf_embed/BrainStem 12 | Buggy_embed, 2.0/Buggy/glTF-Embedded/Buggy.gltf, 2.0/gltf_embed/Buggy 13 | Cameras_embed, 2.0/Cameras/glTF-Embedded/Cameras.gltf, 2.0/gltf_embed/Cameras 14 | CesiumMan_embed, 2.0/CesiumMan/glTF-Embedded/CesiumMan.gltf, 2.0/gltf_embed/CesiumMan 15 | CesiumMilkTruck_embed, 2.0/CesiumMilkTruck/glTF-Embedded/CesiumMilkTruck.gltf, 2.0/gltf_embed/CesiumMilkTruck 16 | DamagedHelmet_embed, 2.0/DamagedHelmet/glTF-Embedded/DamagedHelmet.gltf, 2.0/gltf_embed/DamagedHelmet 17 | Duck_embed, 2.0/Duck/glTF-Embedded/Duck.gltf, 2.0/gltf_embed/Duck 18 | GearboxAssy_embed, 2.0/GearboxAssy/glTF-Embedded/GearboxAssy.gltf, 2.0/gltf_embed/GearboxAssy 19 | MetalRoughSpheres_embed, 2.0/MetalRoughSpheres/glTF-Embedded/MetalRoughSpheres.gltf, 2.0/gltf_embed/MetalRoughSpheres 20 | Monster_embed, 2.0/Monster/glTF-Embedded/Monster.gltf, 2.0/gltf_embed/Monster 21 | MultiUVTest_embed, 2.0/MultiUVTest/glTF-Embedded/MultiUVTest.gltf, 2.0/gltf_embed/MultiUVTest 22 | NormalTangentMirrorTest_embed, 2.0/NormalTangentMirrorTest/glTF-Embedded/NormalTangentMirrorTest.gltf, 2.0/gltf_embed/NormalTangentMirrorTest 23 | NormalTangentTest_embed, 2.0/NormalTangentTest/glTF-Embedded/NormalTangentTest.gltf, 2.0/gltf_embed/NormalTangentTest 24 | OrientationTest_embed, 2.0/OrientationTest/glTF-Embedded/OrientationTest.gltf, 2.0/gltf_embed/OrientationTest 25 | ReciprocatingSaw_embed, 2.0/ReciprocatingSaw/glTF-Embedded/ReciprocatingSaw.gltf, 2.0/gltf_embed/ReciprocatingSaw 26 | RiggedFigure_embed, 2.0/RiggedFigure/glTF-Embedded/RiggedFigure.gltf, 2.0/gltf_embed/RiggedFigure 27 | RiggedSimple_embed, 2.0/RiggedSimple/glTF-Embedded/RiggedSimple.gltf, 2.0/gltf_embed/RiggedSimple 28 | SimpleMeshes_embed, 2.0/SimpleMeshes/glTF-Embedded/SimpleMeshes.gltf, 2.0/gltf_embed/SimpleMeshes 29 | SimpleMorph_embed, 2.0/SimpleMorph/glTF-Embedded/SimpleMorph.gltf, 2.0/gltf_embed/SimpleMorph 30 | SimpleSparseAccessor_embed, 2.0/SimpleSparseAccessor/glTF-Embedded/SimpleSparseAccessor.gltf, 2.0/gltf_embed/SimpleSparseAccessor 31 | TextureCoordinateTest_embed, 2.0/TextureCoordinateTest/glTF-Embedded/TextureCoordinateTest.gltf, 2.0/gltf_embed/TextureCoordinateTest 32 | TextureSettingsTest_embed, 2.0/TextureSettingsTest/glTF-Embedded/TextureSettingsTest.gltf, 2.0/gltf_embed/TextureSettingsTest 33 | Triangle_embed, 2.0/Triangle/glTF-Embedded/Triangle.gltf, 2.0/gltf_embed/Triangle 34 | TriangleWithoutIndices_embed, 2.0/TriangleWithoutIndices/glTF-Embedded/TriangleWithoutIndices.gltf, 2.0/gltf_embed/TriangleWithoutIndices 35 | VC_embed, 2.0/VC/glTF-Embedded/VC.gltf, 2.0/gltf_embed/VC 36 | VertexColorTest_embed, 2.0/VertexColorTest/glTF-Embedded/VertexColorTest.gltf, 2.0/gltf_embed/VertexColorTest 37 | -------------------------------------------------------------------------------- /testdata/samp_glb.csv: -------------------------------------------------------------------------------- 1 | @2.0 Samples - GLB 2 | 2CylinderEngine_glb, 2.0/2CylinderEngine/glTF-Binary/2CylinderEngine.glb, 2.0/glb/2CylinderEngine 3 | AlphaBlendModeTest_glb, 2.0/AlphaBlendModeTest/glTF-Binary/AlphaBlendModeTest.glb, 2.0/glb/AlphaBlendModeTest 4 | AnimatedMorphCube_glb, 2.0/AnimatedMorphCube/glTF-Binary/AnimatedMorphCube.glb, 2.0/glb/AnimatedMorphCube 5 | AnimatedMorphSphere_glb, 2.0/AnimatedMorphSphere/glTF-Binary/AnimatedMorphSphere.glb, 2.0/glb/AnimatedMorphSphere 6 | AntiqueCamera_glb, 2.0/AntiqueCamera/glTF-Binary/AntiqueCamera.glb, 2.0/glb/AntiqueCamera 7 | Avocado_glb, 2.0/Avocado/glTF-Binary/Avocado.glb, 2.0/glb/Avocado 8 | BarramundiFish_glb, 2.0/BarramundiFish/glTF-Binary/BarramundiFish.glb, 2.0/glb/BarramundiFish 9 | BoomBox_glb, 2.0/BoomBox/glTF-Binary/BoomBox.glb, 2.0/glb/BoomBox 10 | Box_glb, 2.0/Box/glTF-Binary/Box.glb, 2.0/glb/Box 11 | BoxAnimated_glb, 2.0/BoxAnimated/glTF-Binary/BoxAnimated.glb, 2.0/glb/BoxAnimated 12 | BoxInterleaved_glb, 2.0/BoxInterleaved/glTF-Binary/BoxInterleaved.glb, 2.0/glb/BoxInterleaved 13 | BoxTextured_glb, 2.0/BoxTextured/glTF-Binary/BoxTextured.glb, 2.0/glb/BoxTextured 14 | BoxTexturedNonPowerOfTwo_glb, 2.0/BoxTexturedNonPowerOfTwo/glTF-Binary/BoxTexturedNonPowerOfTwo.glb, 2.0/glb/BoxTexturedNonPowerOfTwo 15 | BoxVertexColors_glb, 2.0/BoxVertexColors/glTF-Binary/BoxVertexColors.glb, 2.0/glb/BoxVertexColors 16 | BrainStem_glb, 2.0/BrainStem/glTF-Binary/BrainStem.glb, 2.0/glb/BrainStem 17 | Buggy_glb, 2.0/Buggy/glTF-Binary/Buggy.glb, 2.0/glb/Buggy 18 | CesiumMan_glb, 2.0/CesiumMan/glTF-Binary/CesiumMan.glb, 2.0/glb/CesiumMan 19 | CesiumMilkTruck_glb, 2.0/CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb, 2.0/glb/CesiumMilkTruck 20 | Corset_glb, 2.0/Corset/glTF-Binary/Corset.glb, 2.0/glb/Corset 21 | DamagedHelmet_glb, 2.0/DamagedHelmet/glTF-Binary/DamagedHelmet.glb, 2.0/glb/DamagedHelmet 22 | Duck_glb, 2.0/Duck/glTF-Binary/Duck.glb, 2.0/glb/Duck 23 | GearboxAssy_glb, 2.0/GearboxAssy/glTF-Binary/GearboxAssy.glb, 2.0/glb/GearboxAssy 24 | InterpolationTest_glb, 2.0/InterpolationTest/glTF-Binary/InterpolationTest.glb, 2.0/glb/InterpolationTest 25 | Lantern_glb, 2.0/Lantern/glTF-Binary/Lantern.glb, 2.0/glb/Lantern 26 | MetalRoughSpheres_glb, 2.0/MetalRoughSpheres/glTF-Binary/MetalRoughSpheres.glb, 2.0/glb/MetalRoughSpheres 27 | Monster_glb, 2.0/Monster/glTF-Binary/Monster.glb, 2.0/glb/Monster 28 | MorphPrimitivesTest_glb, 2.0/MorphPrimitivesTest/glTF-Binary/MorphPrimitivesTest.glb, 2.0/glb/MorphPrimitivesTest 29 | MultiUVTest_glb, 2.0/MultiUVTest/glTF-Binary/MultiUVTest.glb, 2.0/glb/MultiUVTest 30 | NormalTangentMirrorTest_glb, 2.0/NormalTangentMirrorTest/glTF-Binary/NormalTangentMirrorTest.glb, 2.0/glb/NormalTangentMirrorTest 31 | NormalTangentTest_glb, 2.0/NormalTangentTest/glTF-Binary/NormalTangentTest.glb, 2.0/glb/NormalTangentTest 32 | OrientationTest_glb, 2.0/OrientationTest/glTF-Binary/OrientationTest.glb, 2.0/glb/OrientationTest 33 | ReciprocatingSaw_glb, 2.0/ReciprocatingSaw/glTF-Binary/ReciprocatingSaw.glb, 2.0/glb/ReciprocatingSaw 34 | RiggedFigure_glb, 2.0/RiggedFigure/glTF-Binary/RiggedFigure.glb, 2.0/glb/RiggedFigure 35 | RiggedSimple_glb, 2.0/RiggedSimple/glTF-Binary/RiggedSimple.glb, 2.0/glb/RiggedSimple 36 | SpecGlossVsMetalRough_glb, 2.0/SpecGlossVsMetalRough/glTF-Binary/SpecGlossVsMetalRough.glb, 2.0/glb/SpecGlossVsMetalRough 37 | TextureCoordinateTest_glb, 2.0/TextureCoordinateTest/glTF-Binary/TextureCoordinateTest.glb, 2.0/glb/TextureCoordinateTest 38 | TextureSettingsTest_glb, 2.0/TextureSettingsTest/glTF-Binary/TextureSettingsTest.glb, 2.0/glb/TextureSettingsTest 39 | UnlitTest_glb, 2.0/UnlitTest/glTF-Binary/UnlitTest.glb, 2.0/glb/UnlitTest 40 | VC_glb, 2.0/VC/glTF-Binary/VC.glb, 2.0/glb/VC 41 | VertexColorTest_glb, 2.0/VertexColorTest/glTF-Binary/VertexColorTest.glb, 2.0/glb/VertexColorTest 42 | WaterBottle_glb, 2.0/WaterBottle/glTF-Binary/WaterBottle.glb, 2.0/glb/WaterBottle 43 | -------------------------------------------------------------------------------- /testdata/samp_gltf.csv: -------------------------------------------------------------------------------- 1 | @2.0 Samples - GLTF 2 | 2CylinderEngine, 2.0/2CylinderEngine/glTF/2CylinderEngine.gltf, 2.0/gltf/2CylinderEngine 3 | AlphaBlendModeTest, 2.0/AlphaBlendModeTest/glTF/AlphaBlendModeTest.gltf, 2.0/gltf/AlphaBlendModeTest 4 | AnimatedCube, 2.0/AnimatedCube/glTF/AnimatedCube.gltf, 2.0/gltf/AnimatedCube 5 | AnimatedMorphCube, 2.0/AnimatedMorphCube/glTF/AnimatedMorphCube.gltf, 2.0/gltf/AnimatedMorphCube 6 | AnimatedMorphSphere, 2.0/AnimatedMorphSphere/glTF/AnimatedMorphSphere.gltf, 2.0/gltf/AnimatedMorphSphere 7 | AnimatedTriangle, 2.0/AnimatedTriangle/glTF/AnimatedTriangle.gltf, 2.0/gltf/AnimatedTriangle 8 | AntiqueCamera, 2.0/AntiqueCamera/glTF/AntiqueCamera.gltf, 2.0/gltf/AntiqueCamera 9 | Avocado, 2.0/Avocado/glTF/Avocado.gltf, 2.0/gltf/Avocado 10 | BarramundiFish, 2.0/BarramundiFish/glTF/BarramundiFish.gltf, 2.0/gltf/BarramundiFish 11 | BoomBox, 2.0/BoomBox/glTF/BoomBox.gltf, 2.0/gltf/BoomBox 12 | BoomBoxWithAxes, 2.0/BoomBoxWithAxes/glTF/BoomBoxWithAxes.gltf, 2.0/gltf/BoomBoxWithAxes 13 | Box, 2.0/Box/glTF/Box.gltf, 2.0/gltf/Box 14 | BoxAnimated, 2.0/BoxAnimated/glTF/BoxAnimated.gltf, 2.0/gltf/BoxAnimated 15 | BoxInterleaved, 2.0/BoxInterleaved/glTF/BoxInterleaved.gltf, 2.0/gltf/BoxInterleaved 16 | BoxTextured, 2.0/BoxTextured/glTF/BoxTextured.gltf, 2.0/gltf/BoxTextured 17 | BoxTexturedNonPowerOfTwo, 2.0/BoxTexturedNonPowerOfTwo/glTF/BoxTexturedNonPowerOfTwo.gltf, 2.0/gltf/BoxTexturedNonPowerOfTwo 18 | BoxVertexColors, 2.0/BoxVertexColors/glTF/BoxVertexColors.gltf, 2.0/gltf/BoxVertexColors 19 | BrainStem, 2.0/BrainStem/glTF/BrainStem.gltf, 2.0/gltf/BrainStem 20 | Buggy, 2.0/Buggy/glTF/Buggy.gltf, 2.0/gltf/Buggy 21 | Cameras, 2.0/Cameras/glTF/Cameras.gltf, 2.0/gltf/Cameras 22 | CesiumMan, 2.0/CesiumMan/glTF/CesiumMan.gltf, 2.0/gltf/CesiumMan 23 | CesiumMilkTruck, 2.0/CesiumMilkTruck/glTF/CesiumMilkTruck.gltf, 2.0/gltf/CesiumMilkTruck 24 | Corset, 2.0/Corset/glTF/Corset.gltf, 2.0/gltf/Corset 25 | Cube, 2.0/Cube/glTF/Cube.gltf, 2.0/gltf/Cube 26 | DamagedHelmet, 2.0/DamagedHelmet/glTF/DamagedHelmet.gltf, 2.0/gltf/DamagedHelmet 27 | Duck, 2.0/Duck/glTF/Duck.gltf, 2.0/gltf/Duck 28 | EnvironmentTest, 2.0/EnvironmentTest/glTF/EnvironmentTest.gltf, 2.0/gltf/EnvironmentTest 29 | FlightHelmet, 2.0/FlightHelmet/glTF/FlightHelmet.gltf, 2.0/gltf/FlightHelmet 30 | GearboxAssy, 2.0/GearboxAssy/glTF/GearboxAssy.gltf, 2.0/gltf/GearboxAssy 31 | InterpolationTest_anim0, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim0, --anim 0 32 | InterpolationTest_anim1, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim1, --anim 1 33 | InterpolationTest_anim2, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim2, --anim 2 34 | InterpolationTest_anim3, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim3, --anim 3 35 | InterpolationTest_anim4, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim4, --anim 4 36 | InterpolationTest_anim5, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim5, --anim 5 37 | InterpolationTest_anim6, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim6, --anim 6 38 | InterpolationTest_anim7, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim7, --anim 7 39 | InterpolationTest_anim8, 2.0/InterpolationTest/glTF/InterpolationTest.gltf, 2.0/gltf/InterpolationTest_anim8, --anim 8 40 | Lantern, 2.0/Lantern/glTF/Lantern.gltf, 2.0/gltf/Lantern 41 | MetalRoughSpheres, 2.0/MetalRoughSpheres/glTF/MetalRoughSpheres.gltf, 2.0/gltf/MetalRoughSpheres 42 | Monster, 2.0/Monster/glTF/Monster.gltf, 2.0/gltf/Monster 43 | MorphPrimitivesTest, 2.0/MorphPrimitivesTest/glTF/MorphPrimitivesTest.gltf, 2.0/gltf/MorphPrimitivesTest 44 | MultiUVTest, 2.0/MultiUVTest/glTF/MultiUVTest.gltf, 2.0/gltf/MultiUVTest 45 | NormalTangentMirrorTest, 2.0/NormalTangentMirrorTest/glTF/NormalTangentMirrorTest.gltf, 2.0/gltf/NormalTangentMirrorTest 46 | NormalTangentTest, 2.0/NormalTangentTest/glTF/NormalTangentTest.gltf, 2.0/gltf/NormalTangentTest 47 | OrientationTest, 2.0/OrientationTest/glTF/OrientationTest.gltf, 2.0/gltf/OrientationTest 48 | ReciprocatingSaw, 2.0/ReciprocatingSaw/glTF/ReciprocatingSaw.gltf, 2.0/gltf/ReciprocatingSaw 49 | RiggedFigure, 2.0/RiggedFigure/glTF/RiggedFigure.gltf, 2.0/gltf/RiggedFigure 50 | RiggedSimple, 2.0/RiggedSimple/glTF/RiggedSimple.gltf, 2.0/gltf/RiggedSimple 51 | SciFiHelmet, 2.0/SciFiHelmet/glTF/SciFiHelmet.gltf, 2.0/gltf/SciFiHelmet 52 | SimpleMeshes, 2.0/SimpleMeshes/glTF/SimpleMeshes.gltf, 2.0/gltf/SimpleMeshes 53 | SimpleMorph, 2.0/SimpleMorph/glTF/SimpleMorph.gltf, 2.0/gltf/SimpleMorph 54 | SimpleSparseAccessor, 2.0/SimpleSparseAccessor/glTF/SimpleSparseAccessor.gltf, 2.0/gltf/SimpleSparseAccessor 55 | SpecGlossVsMetalRough, 2.0/SpecGlossVsMetalRough/glTF/SpecGlossVsMetalRough.gltf, 2.0/gltf/SpecGlossVsMetalRough 56 | Sponza, 2.0/Sponza/glTF/Sponza.gltf, 2.0/gltf/Sponza 57 | Suzanne, 2.0/Suzanne/glTF/Suzanne.gltf, 2.0/gltf/Suzanne 58 | TextureCoordinateTest, 2.0/TextureCoordinateTest/glTF/TextureCoordinateTest.gltf, 2.0/gltf/TextureCoordinateTest 59 | TextureSettingsTest, 2.0/TextureSettingsTest/glTF/TextureSettingsTest.gltf, 2.0/gltf/TextureSettingsTest 60 | TextureTransformTest, 2.0/TextureTransformTest/glTF/TextureTransformTest.gltf, 2.0/gltf/TextureTransformTest 61 | Triangle, 2.0/Triangle/glTF/Triangle.gltf, 2.0/gltf/Triangle 62 | TriangleWithoutIndices, 2.0/TriangleWithoutIndices/glTF/TriangleWithoutIndices.gltf, 2.0/gltf/TriangleWithoutIndices 63 | TwoSidedPlane, 2.0/TwoSidedPlane/glTF/TwoSidedPlane.gltf, 2.0/gltf/TwoSidedPlane 64 | UnlitTest, 2.0/UnlitTest/glTF/UnlitTest.gltf, 2.0/gltf/UnlitTest 65 | VC, 2.0/VC/glTF/VC.gltf, 2.0/gltf/VC 66 | VertexColorTest, 2.0/VertexColorTest/glTF/VertexColorTest.gltf, 2.0/gltf/VertexColorTest 67 | WaterBottle, 2.0/WaterBottle/glTF/WaterBottle.gltf, 2.0/gltf/WaterBottle 68 | -------------------------------------------------------------------------------- /testdata/samp_specgloss.csv: -------------------------------------------------------------------------------- 1 | @2.0 Samples - Spec+Gloss 2 | 2CylinderEngine_specgloss, 2.0/2CylinderEngine/glTF-pbrSpecularGlossiness/2CylinderEngine.gltf, 2.0/gltf_specgloss/2CylinderEngine 3 | Avocado_specgloss, 2.0/Avocado/glTF-pbrSpecularGlossiness/Avocado.gltf, 2.0/gltf_specgloss/Avocado 4 | BarramundiFish_specgloss, 2.0/BarramundiFish/glTF-pbrSpecularGlossiness/BarramundiFish.gltf, 2.0/gltf_specgloss/BarramundiFish 5 | BoomBox_specgloss, 2.0/BoomBox/glTF-pbrSpecularGlossiness/BoomBox.gltf, 2.0/gltf_specgloss/BoomBox 6 | Box_specgloss, 2.0/Box/glTF-pbrSpecularGlossiness/Box.gltf, 2.0/gltf_specgloss/Box 7 | BoxAnimated_specgloss, 2.0/BoxAnimated/glTF-pbrSpecularGlossiness/BoxAnimated.gltf, 2.0/gltf_specgloss/BoxAnimated 8 | BoxInterleaved_specgloss, 2.0/BoxInterleaved/glTF-pbrSpecularGlossiness/BoxInterleaved.gltf, 2.0/gltf_specgloss/BoxInterleaved 9 | BoxTextured_specgloss, 2.0/BoxTextured/glTF-pbrSpecularGlossiness/BoxTextured.gltf, 2.0/gltf_specgloss/BoxTextured 10 | BoxTexturedNonPowerOfTwo_specgloss, 2.0/BoxTexturedNonPowerOfTwo/glTF-pbrSpecularGlossiness/BoxTexturedNonPowerOfTwo.gltf, 2.0/gltf_specgloss/BoxTexturedNonPowerOfTwo 11 | BrainStem_specgloss, 2.0/BrainStem/glTF-pbrSpecularGlossiness/BrainStem.gltf, 2.0/gltf_specgloss/BrainStem 12 | Buggy_specgloss, 2.0/Buggy/glTF-pbrSpecularGlossiness/Buggy.gltf, 2.0/gltf_specgloss/Buggy 13 | CesiumMan_specgloss, 2.0/CesiumMan/glTF-pbrSpecularGlossiness/CesiumMan.gltf, 2.0/gltf_specgloss/CesiumMan 14 | CesiumMilkTruck_specgloss, 2.0/CesiumMilkTruck/glTF-pbrSpecularGlossiness/CesiumMilkTruck.gltf, 2.0/gltf_specgloss/CesiumMilkTruck 15 | Corset_specgloss, 2.0/Corset/glTF-pbrSpecularGlossiness/Corset.gltf, 2.0/gltf_specgloss/Corset 16 | Duck_specgloss, 2.0/Duck/glTF-pbrSpecularGlossiness/Duck.gltf, 2.0/gltf_specgloss/Duck 17 | GearboxAssy_specgloss, 2.0/GearboxAssy/glTF-pbrSpecularGlossiness/GearboxAssy.gltf, 2.0/gltf_specgloss/GearboxAssy 18 | Lantern_specgloss, 2.0/Lantern/glTF-pbrSpecularGlossiness/Lantern.gltf, 2.0/gltf_specgloss/Lantern 19 | Monster_specgloss, 2.0/Monster/glTF-pbrSpecularGlossiness/Monster.gltf, 2.0/gltf_specgloss/Monster 20 | ReciprocatingSaw_specgloss, 2.0/ReciprocatingSaw/glTF-pbrSpecularGlossiness/ReciprocatingSaw.gltf, 2.0/gltf_specgloss/ReciprocatingSaw 21 | RiggedFigure_specgloss, 2.0/RiggedFigure/glTF-pbrSpecularGlossiness/RiggedFigure.gltf, 2.0/gltf_specgloss/RiggedFigure 22 | RiggedSimple_specgloss, 2.0/RiggedSimple/glTF-pbrSpecularGlossiness/RiggedSimple.gltf, 2.0/gltf_specgloss/RiggedSimple 23 | VC_specgloss, 2.0/VC/glTF-pbrSpecularGlossiness/VC.gltf, 2.0/gltf_specgloss/VC 24 | WaterBottle_specgloss, 2.0/WaterBottle/glTF-pbrSpecularGlossiness/WaterBottle.gltf, 2.0/gltf_specgloss/WaterBottle 25 | -------------------------------------------------------------------------------- /tools/ufgbatch/html_resources/usdz_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/usd_from_gltf/6d288cce8b68744494a226574ae1d7ba6a9c46eb/tools/ufgbatch/html_resources/usdz_icon.png -------------------------------------------------------------------------------- /tools/ufgbatch/ufgbatch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Run batch usd_from_gltf conversion. 18 | 19 | This generates USD files from glTF according to a CSV listing. 20 | 21 | Usage: ufgbatch.py 22 | * csv: Path to CSV file containing conversion tasks, of the form: 23 | name, my/source/path.gltf, my/destination/usd/directory 24 | 25 | Typical usages: 26 | ufgbatch.py all.csv 27 | ufgbatch.py all.csv -t usda 28 | ufgbatch.py all.csv -t usdz 29 | """ 30 | 31 | from __future__ import print_function 32 | 33 | import argparse 34 | import os 35 | import sys 36 | 37 | # Add script directory to path so the interpreter can locate ufgcommon. 38 | sys.path.append(os.path.dirname(__file__)) 39 | 40 | from ufgcommon import util # pylint: disable=g-import-not-at-top 41 | from ufgcommon.process import get_process_count 42 | from ufgcommon.process import run_conversion 43 | from ufgcommon.task import get_csv_tasks 44 | from ufgcommon.util import clean_output_directory 45 | from ufgcommon.util import status 46 | 47 | 48 | def main(): 49 | util.enable_ansi_colors() 50 | (args, unknown_args) = parse_args() 51 | out_path = util.norm_abspath(args.out_dir) 52 | if args.clean: 53 | clean_output_directory(out_path) 54 | return 0 55 | 56 | # Parse CSVs for tasks. 57 | (tasks, csv_names, csv_tasks) = get_csv_tasks(args.csv) 58 | if not tasks: 59 | return 1 60 | 61 | usd_type = args.type 62 | 63 | # Choose the number of concurrent conversion processes. 64 | process_count = get_process_count(args.processes, args.process_max, 65 | len(tasks)) 66 | 67 | type_text = usd_type if usd_type else 'usda+usdz' 68 | status('Converting %s models to %s with %s processes.' % 69 | (len(tasks), type_text, process_count)) 70 | 71 | failed_tasks = [] 72 | 73 | in_path = util.norm_abspath(args.in_dir) 74 | 75 | # Output .usda, .usdz, or .usd- for both. 76 | ext = ('.' + usd_type) if usd_type else '.usd-' 77 | 78 | exe_args = unknown_args + util.split_args(args.args) 79 | tag_tracker = util.TagTracker() 80 | (_, failed_tasks, _) = run_conversion(csv_tasks, tasks, args.exe, exe_args, 81 | ext, in_path, out_path, csv_names, 82 | process_count, '', '', tag_tracker) 83 | if failed_tasks: 84 | return 1 85 | else: 86 | return 0 87 | 88 | 89 | def parse_args(): 90 | """Parse command-line arguments.""" 91 | try: 92 | parser = argparse.ArgumentParser( 93 | description=__doc__, 94 | formatter_class=argparse.RawDescriptionHelpFormatter) 95 | parser.add_argument( 96 | 'csv', 97 | nargs='+', 98 | type=argparse.FileType('r'), 99 | help='Task CSV file path.') 100 | parser.add_argument( 101 | '-t', 102 | '--type', 103 | type=str, 104 | default=None, 105 | help='Output file type (usda or usdz). Defaults to both.') 106 | parser.add_argument( 107 | '-c', 108 | '--clean', 109 | default=False, 110 | action='store_true', 111 | help='Clean the output by moving it to a backup directory.') 112 | parser.add_argument( 113 | '--exe', 114 | type=str, 115 | default='usd_from_gltf', 116 | help='usd_from_gltf executable path.') 117 | parser.add_argument( 118 | '-a', 119 | '--args', 120 | type=str, 121 | default='', 122 | help='Additional args passed to usd_from_gltf.') 123 | parser.add_argument( 124 | '--in_dir', 125 | '-i', 126 | type=str, 127 | default='', 128 | help='Input glTF directory.') 129 | parser.add_argument( 130 | '--out_dir', 131 | '-o', 132 | type=str, 133 | default='', 134 | help='Output USD directory.') 135 | parser.add_argument( 136 | '--processes', 137 | type=int, 138 | default=0, 139 | help='Number of conversion processes. 0 uses all available cores.') 140 | parser.add_argument( 141 | '--process_max', 142 | type=int, 143 | default=64, 144 | help='Maximum number of processes to use. Set to 0 for unlimited.') 145 | return parser.parse_known_args() 146 | except argparse.ArgumentError: 147 | exit(1) 148 | 149 | 150 | if __name__ == '__main__': 151 | exit_code = main() 152 | sys.exit(exit_code) 153 | -------------------------------------------------------------------------------- /tools/ufgbatch/ufgcommon/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Common code for usd_from_gltf scripts.""" 18 | -------------------------------------------------------------------------------- /tools/ufgbatch/ufgcommon/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Task definitions for batch processing models from CSV lists.""" 18 | 19 | from __future__ import print_function 20 | 21 | import csv 22 | import os 23 | import shlex 24 | 25 | from . import util 26 | 27 | 28 | class Task(object): 29 | """Contains info for each conversion task.""" 30 | 31 | def __init__(self, name, src, dst, args, csv_index, section): 32 | self.name = name 33 | self.src = src 34 | self.dst = dst 35 | self.args = args 36 | self.csv_index = csv_index 37 | self.section = section 38 | # Task completion state. 39 | self.success = False 40 | self.command = None 41 | self.output = None 42 | 43 | def format_output(self, in_path, out_path): 44 | """Format task output for logging.""" 45 | if not self.output: 46 | return '' 47 | output = self.output 48 | 49 | # Replace full paths to prevent differences based on build directories. 50 | if in_path: 51 | output = output.replace(in_path, '${IN}') 52 | if out_path: 53 | output = output.replace(out_path, '${OUT}') 54 | 55 | # Indent. 56 | output = ''.join((' ' + line) for line in output.splitlines(True)) 57 | return '\n' + output 58 | 59 | def get_log(self): 60 | """Get task log text (command plus output).""" 61 | return self.command + self.format_output(None, None) 62 | 63 | def get_result(self, in_path, out_path): 64 | """Get result text (status plus output), suitable for diff'ing.""" 65 | prefix = 'Success' if self.success else 'FAILURE' 66 | result = prefix + ' [' + self.name + '] ' + self.src + ' --> ' + self.dst 67 | return result + self.format_output(in_path, out_path) 68 | 69 | 70 | def parse_tasks(fp, csv_index): 71 | """Parse tasks from a CSV file.""" 72 | tasks = [] 73 | section = None 74 | section_args = [] 75 | with fp as csv_file: 76 | csv_reader = csv.reader(csv_file, delimiter=',', skipinitialspace=True) 77 | for row in csv_reader: 78 | if not row: 79 | # Just skip empty rows - we use them for organization. 80 | continue 81 | if row[0].startswith('#'): 82 | # Skip leading line comments. 83 | continue 84 | if row[0].startswith('@'): 85 | # Record section header, with optional section-specific arguments. 86 | if len(row) != 1 and len(row) != 2: 87 | util.error( 88 | '{0}: Incorrect number of section columns ({1}, expected 1 or 2) on line {2}.' 89 | .format(fp.name, len(row), csv_reader.line_num)) 90 | exit(1) 91 | section = row[0][1:] 92 | section_args = [] 93 | if len(row) >= 2: 94 | section_args = shlex.split(row[1]) 95 | continue 96 | if len(row) != 3 and len(row) != 4: 97 | util.error( 98 | '{0}: Incorrect number of columns ({1}, expected 3 or 4) on line {2}.' 99 | .format(fp.name, len(row), csv_reader.line_num)) 100 | exit(1) 101 | task_args = section_args 102 | if len(row) >= 4: 103 | task_args = task_args + shlex.split(row[3]) 104 | tasks.append(Task(row[0], row[1], row[2], task_args, csv_index, section)) 105 | return tasks 106 | 107 | 108 | def check_unique_task_names(tasks): 109 | """Returns true if task names are unique.""" 110 | names = {} 111 | have_dupes = False 112 | for task in tasks: 113 | if task.name in names: 114 | names[task.name] += 1 115 | have_dupes = True 116 | else: 117 | names[task.name] = 1 118 | if have_dupes: 119 | dupes = '' 120 | for (name, count) in names.items(): 121 | if count > 1: 122 | if dupes: 123 | dupes += ', ' 124 | dupes += name 125 | util.error('ERROR: Duplicate task(s): ' + dupes) 126 | return not have_dupes 127 | 128 | 129 | def get_csv_tasks(csv_files): 130 | """Parse tasks from CSV files and ensure tasks are uniquely named.""" 131 | csv_count = len(csv_files) 132 | tasks = [] 133 | csv_names = [None] * csv_count 134 | csv_tasks = [[]] * csv_count 135 | for csv_index, csv_file in enumerate(csv_files): 136 | csv_tasks[csv_index] = parse_tasks(csv_file, csv_index) 137 | tasks += csv_tasks[csv_index] 138 | (_, csv_file_name) = os.path.split(csv_file.name) 139 | (csv_names[csv_index], _) = os.path.splitext(csv_file_name) 140 | if not check_unique_task_names(tasks): 141 | return (None, None, None) 142 | return (tasks, csv_names, csv_tasks) 143 | -------------------------------------------------------------------------------- /tools/ufgbatch/ufgtest.pyproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | {f7a828a7-5ae5-4bdd-b2cb-8a7699c3fef9} 7 | 8 | ufgtest.py 9 | 10 | C:\projects\ufg_tests\data\test 11 | . 12 | {888888a0-9f3d-457c-b088-3a5042f75d52} 13 | Standard Python launcher 14 | 15 | 16 | False 17 | misc.csv --exe "C:\projects\ufg_built\build\ufg\usd_from_gltf\Release\usd_from_gltf.exe" --deploy_all 18 | False 19 | 20 | 21 | 22 | 23 | 10.0 24 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets 25 | 26 | 27 | 28 | Code 29 | 30 | 31 | Code 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tools/ufgbatch/ufgvalidate.pyproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | 94f879b4-4055-4fea-85ed-4c7b2edd43f7 7 | 8 | ufgvalidate.py 9 | 10 | C:\projects\ufg_tests\data\test 11 | . 12 | {888888a0-9f3d-457c-b088-3a5042f75d52} 13 | Standard Python launcher 14 | 15 | 16 | False 17 | error.csv samp_draco.csv --exe "$(SolutionDir)x64\$(Configuration)\gltf_validator.exe" 18 | False 19 | 20 | 21 | 22 | 23 | 10.0 24 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/giflib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.0) 16 | project(giflib) 17 | 18 | include_directories(.) 19 | 20 | add_library(giflib 21 | dgif_lib.c 22 | egif_lib.c 23 | gif_err.c 24 | gif_font.c 25 | gif_hash.c 26 | gifalloc.c 27 | openbsd-reallocarray.c 28 | quantize.c 29 | ) 30 | 31 | install(TARGETS giflib EXPORT giflib DESTINATION lib) 32 | install(EXPORT giflib DESTINATION lib) 33 | install(FILES giflib-config.cmake DESTINATION .) 34 | install(FILES gif_lib.h DESTINATION include) 35 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/giflib/giflib-config.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 16 | include(${SELF_DIR}/${CMAKE_BUILD_TYPE}/lib/giflib.cmake) 17 | set_and_check(giflib_INCLUDE_DIR "${SELF_DIR}/include") 18 | set_and_check(giflib_LIBRARY_DIR "${SELF_DIR}/lib") 19 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/giflib/unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Intentionally blank. This file is included but unused on Windows. 18 | #ifndef UNISTD_H_ 19 | #define UNISTD_H_ 20 | #endif // UNISTD_H_ 21 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.0) 16 | project(json) 17 | install(FILES json-config.cmake DESTINATION .) 18 | install(FILES json.hpp DESTINATION include) 19 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/json/json-config.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 16 | set(json_INCLUDE_DIR "${SELF_DIR}/include") 17 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/stb_image/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.0) 16 | project(stb_image) 17 | 18 | add_library(stb_image 19 | stb_image.cc 20 | ) 21 | 22 | install(TARGETS stb_image EXPORT stb_image DESTINATION lib) 23 | install(EXPORT stb_image DESTINATION lib) 24 | install(FILES stb_image-config.cmake DESTINATION .) 25 | install(FILES stb_image.h DESTINATION include) 26 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/stb_image/stb_image-config.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 16 | include(${SELF_DIR}/${CMAKE_BUILD_TYPE}/lib/stb_image.cmake) 17 | set_and_check(stb_image_INCLUDE_DIR "${SELF_DIR}/include") 18 | set_and_check(stb_image_LIBRARY_DIR "${SELF_DIR}/lib") 19 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/stb_image/stb_image.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define STB_IMAGE_IMPLEMENTATION 18 | #include "stb_image.h" // NOLINT: Silence relative path warning. 19 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/tclap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.0) 16 | project(tclap) 17 | 18 | add_library(tclap INTERFACE) 19 | 20 | install(TARGETS tclap EXPORT tclap DESTINATION lib) 21 | install(EXPORT tclap DESTINATION lib) 22 | install(FILES tclap-config.cmake DESTINATION .) 23 | install(DIRECTORY include/tclap DESTINATION include) 24 | -------------------------------------------------------------------------------- /tools/ufginstall/patches/tclap/tclap-config.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 16 | set(tclap_INCLUDE_DIR "${SELF_DIR}/include") 17 | -------------------------------------------------------------------------------- /tools/usdviewer.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2019 Google LLC 2 | :: 3 | :: Licensed under the Apache License, Version 2.0 (the "License"); 4 | :: you may not use this file except in compliance with the License. 5 | :: You may obtain a copy of the License at 6 | :: 7 | :: http://www.apache.org/licenses/LICENSE-2.0 8 | :: 9 | :: Unless required by applicable law or agreed to in writing, software 10 | :: distributed under the License is distributed on an "AS IS" BASIS, 11 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | :: See the License for the specific language governing permissions and 13 | :: limitations under the License. 14 | 15 | :: Usdview wrapper to allow USD and GLTF files to be viewed in Windows Explorer. 16 | :: Make sure USD bin directory is in your path, then 'Open with' this batch file. 17 | start cmd.exe /K "usdview.cmd %1 & exit" 18 | -------------------------------------------------------------------------------- /ufg-config.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 16 | include(${SELF_DIR}/${CMAKE_BUILD_TYPE}/lib/ufg/ufglib.cmake) 17 | set_and_check(ufg_INCLUDE_DIR "${SELF_DIR}/include/ufg") 18 | set_and_check(ufg_LIBRARY_DIR "${SELF_DIR}/lib/ufg") 19 | -------------------------------------------------------------------------------- /ufg_plugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include_directories( 16 | .. 17 | ${USD_INCLUDE_DIRS} 18 | ) 19 | 20 | add_library(ufg_plugin SHARED 21 | ufg_plugin.cc 22 | ufg_plugin.h 23 | ) 24 | 25 | if (MSVC) 26 | target_link_libraries(ufg_plugin 27 | convert 28 | ${USD_LIBS} 29 | arch.lib 30 | ) 31 | elseif (APPLE) 32 | target_link_libraries(ufg_plugin 33 | convert 34 | ${USD_LIBS} 35 | libarch.dylib 36 | ) 37 | else () 38 | target_link_libraries(ufg_plugin 39 | convert 40 | ${USD_LIBS} 41 | libarch.so 42 | ) 43 | endif () 44 | 45 | # Name it .dll for all platforms to match the reference in plugInfo.json. 46 | # This is simpler than copying platform-specific plugInfo.json files. 47 | set_target_properties(ufg_plugin PROPERTIES PREFIX "" SUFFIX ".dll") 48 | 49 | set_target_properties(ufg_plugin PROPERTIES RESOURCE plugInfo.json) 50 | 51 | install(TARGETS ufg_plugin DESTINATION bin/ufg_plugin) 52 | -------------------------------------------------------------------------------- /ufg_plugin/plugInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "Plugins": [ 3 | { 4 | "Info": { 5 | "Types": { 6 | "UsdGltfFileFormat": { 7 | "bases": ["SdfFileFormat"], 8 | "displayName": "GLTF Importer", 9 | "extensions": ["gltf", "glb"], 10 | "formatId": "gltf", 11 | "primary": true, 12 | "target": "usd" 13 | } 14 | } 15 | }, 16 | "LibraryPath": "ufg_plugin.dll", 17 | "Name": "ufg_plugin", 18 | "Type": "library" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /ufg_plugin/ufg_plugin.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "ufg_plugin.h" // NOLINT: Silence relative path warning. 18 | 19 | #include "convert/converter.h" 20 | #include "gltf/validate.h" 21 | #include "pxr/usd/sdf/layer.h" 22 | #include "pxr/usd/usd/usdaFileFormat.h" 23 | 24 | PXR_NAMESPACE_OPEN_SCOPE 25 | 26 | TF_DEFINE_PUBLIC_TOKENS(UsdGltfFileFormatTokens, USDGLTF_FILE_FORMAT_TOKENS); 27 | 28 | TF_REGISTRY_FUNCTION(TfType) { 29 | SDF_DEFINE_FILE_FORMAT(UsdGltfFileFormat, SdfFileFormat); 30 | } 31 | 32 | class UsdGltfFileFormatLogger : public GltfLogger { 33 | public: 34 | UsdGltfFileFormatLogger() : error_count_(0) {} 35 | 36 | void Add(const GltfMessage& message) override { 37 | const std::string text = message.ToString(false); 38 | switch (message.GetSeverity()) { 39 | case kGltfSeverityWarning: 40 | TF_DIAGNOSTIC_WARNING("%s", text.c_str()); 41 | break; 42 | case kGltfSeverityError: 43 | TF_RUNTIME_ERROR("%s", text.c_str()); 44 | ++error_count_; 45 | break; 46 | default: 47 | break; 48 | } 49 | } 50 | 51 | size_t GetErrorCount() const override { 52 | return error_count_; 53 | } 54 | 55 | private: 56 | size_t error_count_; 57 | }; 58 | 59 | UsdGltfFileFormat::UsdGltfFileFormat() 60 | : SdfFileFormat( 61 | UsdGltfFileFormatTokens->Id, UsdGltfFileFormatTokens->Version, 62 | UsdGltfFileFormatTokens->Target, UsdGltfFileFormatTokens->Id) {} 63 | 64 | UsdGltfFileFormat::~UsdGltfFileFormat() {} 65 | 66 | bool UsdGltfFileFormat::CanRead(const std::string& path) const { 67 | std::string src_dir, src_name; 68 | Gltf::SplitPath(path, &src_dir, &src_name); 69 | GltfVectorLogger logger; 70 | std::unique_ptr gltf_stream = 71 | GltfStream::Open(&logger, path.c_str(), src_dir.c_str()); 72 | if (!gltf_stream) { 73 | return false; 74 | } 75 | const ufg::ConvertSettings& settings = ufg::ConvertSettings::kDefault; 76 | Gltf gltf; 77 | return GltfLoadAndValidate( 78 | gltf_stream.get(), path.c_str(), settings.gltf_load_settings, 79 | &gltf, &logger); 80 | } 81 | 82 | #if OLD_FORMAT_PLUGIN_API 83 | bool UsdGltfFileFormat::Read(const SdfLayerBasePtr& layer_base, 84 | const std::string& resolved_path, bool metadata_only) const { 85 | SdfLayerHandle layer = TfDynamic_cast(layer_base); 86 | if (!TF_VERIFY(layer)) { 87 | TF_RUNTIME_ERROR("Cannot create layer for GLTF file: %s", 88 | resolved_path.c_str()); 89 | return false; 90 | } 91 | #else // OLD_FORMAT_PLUGIN_API 92 | bool UsdGltfFileFormat::Read(SdfLayer* layer, 93 | const std::string& resolved_path, bool metadata_only) const { 94 | #endif // OLD_FORMAT_PLUGIN_API 95 | 96 | UsdGltfFileFormatLogger logger; 97 | 98 | std::string src_dir, src_name; 99 | Gltf::SplitPath(resolved_path, &src_dir, &src_name); 100 | std::unique_ptr gltf_stream = GltfStream::Open( 101 | &logger, resolved_path.c_str(), src_dir.c_str()); 102 | if (!gltf_stream) { 103 | TF_RUNTIME_ERROR("Cannot open GLTF stream at: %s", resolved_path.c_str()); 104 | return false; 105 | } 106 | 107 | const ufg::ConvertSettings& settings = ufg::ConvertSettings::kDefault; 108 | Gltf gltf; 109 | std::vector messages; 110 | const bool load_success = GltfLoadAndValidate( 111 | gltf_stream.get(), resolved_path.c_str(), settings.gltf_load_settings, 112 | &gltf, &logger); 113 | if (!load_success) { 114 | TF_RUNTIME_ERROR("Failed loading GLTF file: %s", resolved_path.c_str()); 115 | return false; 116 | } 117 | 118 | const SdfLayerRefPtr gltf_layer = SdfLayer::CreateAnonymous(".usda"); 119 | ufg::Converter converter; 120 | if (!converter.Convert(settings, gltf, gltf_stream.get(), src_dir, src_dir, 121 | resolved_path, gltf_layer, &logger)) { 122 | TF_RUNTIME_ERROR("Failed converting GLTF file: %s", resolved_path.c_str()); 123 | return false; 124 | } 125 | 126 | layer->TransferContent(gltf_layer); 127 | return true; 128 | } 129 | 130 | #if OLD_FORMAT_PLUGIN_API 131 | bool UsdGltfFileFormat::ReadFromString(const SdfLayerBasePtr& layer_base, 132 | const std::string& str) const { 133 | // GLTF can use multiple files and the reader assumes those files are on disk. 134 | TF_RUNTIME_ERROR("Cannot import GLTF from a string in memory."); 135 | return false; 136 | } 137 | #else // OLD_FORMAT_PLUGIN_API 138 | bool UsdGltfFileFormat::ReadFromString(SdfLayer* layer, 139 | const std::string& str) const { 140 | // GLTF can use multiple files and the reader assumes those files are on disk. 141 | TF_RUNTIME_ERROR("Cannot import GLTF from a string in memory."); 142 | return false; 143 | } 144 | #endif // OLD_FORMAT_PLUGIN_API 145 | 146 | #if OLD_FORMAT_PLUGIN_API 147 | bool UsdGltfFileFormat::WriteToString(const SdfLayerBase* layer_base, 148 | std::string* str, const std::string& comment) const { 149 | // Write as USDA because we don't implement GLTF export. 150 | return SdfFileFormat::FindById(UsdUsdaFileFormatTokens->Id) 151 | ->WriteToString(layer_base, str, comment); 152 | } 153 | #else // OLD_FORMAT_PLUGIN_API 154 | bool UsdGltfFileFormat::WriteToString(const SdfLayer& layer, 155 | std::string* str, const std::string& comment) const { 156 | // Write as USDA because we don't implement GLTF export. 157 | return SdfFileFormat::FindById(UsdUsdaFileFormatTokens->Id) 158 | ->WriteToString(layer, str, comment); 159 | } 160 | #endif // OLD_FORMAT_PLUGIN_API 161 | 162 | bool UsdGltfFileFormat::WriteToStream( 163 | const SdfSpecHandle &spec, std::ostream& out, size_t indent) const { 164 | // Write as USDA because we don't implement GLTF export. 165 | return SdfFileFormat::FindById(UsdUsdaFileFormatTokens->Id) 166 | ->WriteToStream(spec, out, indent); 167 | } 168 | 169 | PXR_NAMESPACE_CLOSE_SCOPE 170 | -------------------------------------------------------------------------------- /ufg_plugin/ufg_plugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef USDGLTF_FILE_FORMAT_H 18 | #define USDGLTF_FILE_FORMAT_H 19 | 20 | #ifdef _MSC_VER 21 | // Disable warnings in the pxr headers. 22 | // conversion from 'double' to 'float', possible loss of data 23 | #pragma warning(disable : 4244) 24 | // conversion from 'size_t' to 'int', possible loss of data 25 | #pragma warning(disable : 4267) 26 | // truncation from 'double' to 'float' 27 | #pragma warning(disable : 4305) 28 | #endif // _MSC_VER 29 | 30 | #include 31 | #include 32 | #include "pxr/usd/sdf/fileFormat.h" 33 | #include "pxr/base/tf/staticTokens.h" 34 | 35 | // There was a breaking change in the SdfFileFormat interface, somewhere between 36 | // patch versions 3 and 5. 37 | #if PXR_MAJOR_VERSION == 0 && PXR_MINOR_VERSION <= 19 && \ 38 | PXR_PATCH_VERSION < 5 // VERSION 39 | #define OLD_FORMAT_PLUGIN_API 1 40 | #define STREAMING_SUPPORTED 1 41 | #elif PXR_MAJOR_VERSION == 0 && PXR_MINOR_VERSION <= 19 && \ 42 | PXR_PATCH_VERSION < 7 // VERSION 43 | #define OLD_FORMAT_PLUGIN_API 0 44 | #define STREAMING_SUPPORTED 1 45 | #else // VERSION 46 | // _IsStreamingLayer was removed from SdfFileFormat in version 0.19.7. 47 | #define OLD_FORMAT_PLUGIN_API 0 48 | #define STREAMING_SUPPORTED 0 49 | #endif // VERSION 50 | 51 | PXR_NAMESPACE_OPEN_SCOPE 52 | 53 | #define USDGLTF_FILE_FORMAT_TOKENS \ 54 | ((Id, "gltf")) \ 55 | ((Version, "1.0")) \ 56 | ((Target, "usd")) 57 | 58 | TF_DECLARE_PUBLIC_TOKENS(UsdGltfFileFormatTokens, USDGLTF_FILE_FORMAT_TOKENS); 59 | 60 | TF_DECLARE_WEAK_AND_REF_PTRS(UsdGltfFileFormat); 61 | TF_DECLARE_WEAK_AND_REF_PTRS(SdfLayerBase); 62 | 63 | class UsdGltfFileFormat : public SdfFileFormat { 64 | public: 65 | bool CanRead(const std::string &file) const override; 66 | #if OLD_FORMAT_PLUGIN_API 67 | bool Read(const SdfLayerBasePtr& layer_base, 68 | const std::string& resolved_path, bool metadata_only) const override; 69 | bool ReadFromString(const SdfLayerBasePtr& layer_base, 70 | const std::string& str) const override; 71 | bool WriteToString(const SdfLayerBase* layer_base, 72 | std::string* str, 73 | const std::string& comment = std::string()) const override; 74 | #else // OLD_FORMAT_PLUGIN_API 75 | bool Read(SdfLayer* layer, 76 | const std::string& resolved_path, bool metadata_only) const override; 77 | bool ReadFromString(SdfLayer* layer, const std::string& str) const override; 78 | bool WriteToString(const SdfLayer& layer, 79 | std::string* str, 80 | const std::string& comment = std::string()) const override; 81 | #endif // OLD_FORMAT_PLUGIN_API 82 | bool WriteToStream(const SdfSpecHandle& spec, std::ostream& out, 83 | size_t indent) const override; 84 | 85 | protected: 86 | SDF_FILE_FORMAT_FACTORY_ACCESS; 87 | ~UsdGltfFileFormat() override; 88 | UsdGltfFileFormat(); 89 | 90 | private: 91 | #if STREAMING_SUPPORTED 92 | #if OLD_FORMAT_PLUGIN_API 93 | bool _IsStreamingLayer(const SdfLayerBase& layer) const override { 94 | return false; 95 | } 96 | #else // OLD_FORMAT_PLUGIN_API 97 | bool _IsStreamingLayer(const SdfLayer& layer) const override { 98 | return false; 99 | } 100 | #endif // OLD_FORMAT_PLUGIN_API 101 | #endif // STREAMING_SUPPORTED 102 | }; 103 | 104 | PXR_NAMESPACE_CLOSE_SCOPE 105 | 106 | #endif // USDGLTF_FILE_FORMAT_H 107 | -------------------------------------------------------------------------------- /usd_from_gltf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | find_package(tclap) 16 | if (NOT tclap_FOUND) 17 | message(FATAL_ERROR "TCLAP package not found.") 18 | endif (NOT tclap_FOUND) 19 | 20 | include_directories( 21 | .. 22 | ${USD_INCLUDE_DIRS} 23 | ${tclap_INCLUDE_DIR} 24 | ) 25 | 26 | add_executable(usd_from_gltf 27 | args.cc 28 | args.h 29 | usd_from_gltf.cc 30 | ) 31 | 32 | target_link_libraries(usd_from_gltf 33 | convert 34 | ${USD_LIBS} 35 | ) 36 | 37 | install(TARGETS usd_from_gltf DESTINATION bin) 38 | -------------------------------------------------------------------------------- /usd_from_gltf/args.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef USD_FROM_GLTF_ARGS_H_ 18 | #define USD_FROM_GLTF_ARGS_H_ 19 | 20 | #include "common/config.h" 21 | #include "common/logging.h" 22 | 23 | struct Args { 24 | struct Job { 25 | std::string src; 26 | std::string dst; 27 | }; 28 | ufg::ConvertSettings settings; 29 | std::vector jobs; 30 | }; 31 | 32 | bool ParseArgs( 33 | int argc, const char* const* argv, Args* out_args, ufg::Logger* logger); 34 | 35 | #endif // USD_FROM_GLTF_ARGS_H_ 36 | -------------------------------------------------------------------------------- /usd_from_gltf/usd_from_gltf.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "args.h" // NOLINT: Silence relative path warning. 19 | #include "common/logging.h" 20 | #include "convert/package.h" 21 | 22 | int main(int argc, char* argv[]) { 23 | GltfPrintLogger logger; 24 | 25 | Args args; 26 | if (!ParseArgs(argc, argv, &args, &logger)) { 27 | return -1; 28 | } 29 | if (args.jobs.empty()) { 30 | return 0; 31 | } 32 | 33 | if (!ufg::RegisterPlugins(args.settings.plugin_path, &logger)) { 34 | return -1; 35 | } 36 | 37 | bool success = true; 38 | { 39 | ufg::ProfileSentry profile_sentry("Convert", args.settings.print_timing); 40 | for (const Args::Job& job : args.jobs) { 41 | if (args.jobs.size() > 1) { 42 | printf("%s\n", job.src.c_str()); 43 | logger.SetLinePrefix(" "); 44 | } 45 | if (!ufg::ConvertGltfToUsd( 46 | job.src.c_str(), job.dst.c_str(), args.settings, &logger)) { 47 | success = false; 48 | } 49 | } 50 | } 51 | return success ? 0 : -1; 52 | } 53 | --------------------------------------------------------------------------------