mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 10:48:56 +00:00
Compare commits
14 Commits
write-asse
...
mesh-conv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb99999c1a | ||
|
|
be9ff66eeb | ||
|
|
0a4e8b761f | ||
|
|
4adeae9709 | ||
|
|
6224e021ce | ||
|
|
5dcf778b31 | ||
|
|
289cc448ed | ||
|
|
0ee2120965 | ||
|
|
cf30d42cbc | ||
|
|
cb0a8794c3 | ||
|
|
60e22f3281 | ||
|
|
4cfd2849fb | ||
|
|
a5416707c9 | ||
|
|
8ec9af7f2e |
1
.github/ISSUE_TEMPLATE/config.yml
vendored
1
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
30
.github/ISSUE_TEMPLATE/issue-report.md
vendored
30
.github/ISSUE_TEMPLATE/issue-report.md
vendored
@@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
name: Issue report
|
|
||||||
about: Create a report
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the issue**
|
|
||||||
|
|
||||||
A clear and concise description of what the issue is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
|
|
||||||
- OS
|
|
||||||
- Compiler, compiler version, compile options
|
|
||||||
- Please attach minimal and reproducible .glTF file if you got an issue related to .glTF data
|
|
||||||
|
|
||||||
**Expected behaviour**
|
|
||||||
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
165
.github/workflows/c-cpp.yml
vendored
165
.github/workflows/c-cpp.yml
vendored
@@ -1,165 +0,0 @@
|
|||||||
name: C/C++ CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
|
|
||||||
# compile with older gcc4.8
|
|
||||||
build-gcc48:
|
|
||||||
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
name: Build with gcc 4.8
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
sudo apt-get install -y gcc-4.8 g++-4.8
|
|
||||||
g++-4.8 -std=c++11 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
- name: NoexceptBuild
|
|
||||||
run: |
|
|
||||||
g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
- name: RapidjsonBuild
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/Tencent/rapidjson
|
|
||||||
g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
# compile with mingw gcc cross
|
|
||||||
build-mingw-cross:
|
|
||||||
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
name: Build with MinGW gcc cross
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
sudo apt-get install -y mingw-w64
|
|
||||||
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
# Windows(x64) + Visual Studio 2019 build
|
|
||||||
build-windows-msvc:
|
|
||||||
|
|
||||||
runs-on: windows-latest
|
|
||||||
name: Build for Windows(x64, MSVC)
|
|
||||||
|
|
||||||
# Use system installed cmake
|
|
||||||
# https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Configure
|
|
||||||
run: |
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake -G "Visual Studio 16 2019" -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
|
||||||
cd ..
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build --config Release
|
|
||||||
|
|
||||||
|
|
||||||
build-linux:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Buld with gcc
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: build
|
|
||||||
run: |
|
|
||||||
g++ -std=c++11 -o loader_example loader_example.cc
|
|
||||||
- name: test
|
|
||||||
run: |
|
|
||||||
./loader_example models/Cube/Cube.gltf
|
|
||||||
|
|
||||||
- name: tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
g++ -I../ -std=c++11 -g -O0 -o tester tester.cc
|
|
||||||
./tester
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- name: noexcept_tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
g++ -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
|
||||||
./tester_noexcept
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
|
|
||||||
build-rapidjson-linux:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Buld with gcc + rapidjson
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: build
|
|
||||||
run: |
|
|
||||||
git clone https://github.com/Tencent/rapidjson
|
|
||||||
g++ -v
|
|
||||||
g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
- name: loader_example_test
|
|
||||||
run: |
|
|
||||||
./loader_example models/Cube/Cube.gltf
|
|
||||||
|
|
||||||
- name: tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -I../ -std=c++11 -g -O0 -o tester tester.cc
|
|
||||||
./tester
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- name: noexcept_tests
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
|
||||||
./tester_noexcept
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# Cross-compile for aarch64 linux target
|
|
||||||
build-cross-aarch64:
|
|
||||||
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
name: Build on cross aarch64
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y build-essential
|
|
||||||
sudo apt-get install -y gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu
|
|
||||||
|
|
||||||
git clone https://github.com/Tencent/rapidjson
|
|
||||||
aarch64-linux-gnu-g++-8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
# macOS clang
|
|
||||||
build-macos:
|
|
||||||
|
|
||||||
runs-on: macos-latest
|
|
||||||
name: Build on macOS
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
clang++ -std=c++11 -g -O0 -o loader_example loader_example.cc
|
|
||||||
./loader_example models/Cube/Cube.gltf
|
|
||||||
|
|
||||||
git clone https://github.com/Tencent/rapidjson
|
|
||||||
clang++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
|
||||||
|
|
||||||
@@ -4,29 +4,17 @@ PROJECT (tinygltf)
|
|||||||
|
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example" ON)
|
option(TINYGLTF_BUILD_EXAMPLES "Build examples" ON)
|
||||||
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
|
||||||
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator example" OFF)
|
|
||||||
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
|
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
if (TINYGLTF_BUILD_EXAMPLES)
|
||||||
ADD_EXECUTABLE ( loader_example
|
ADD_EXECUTABLE ( loader_example
|
||||||
loader_example.cc
|
loader_example.cc
|
||||||
)
|
)
|
||||||
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_GL_EXAMPLES)
|
|
||||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
ADD_SUBDIRECTORY ( examples/gltfutil )
|
||||||
ADD_SUBDIRECTORY ( examples/glview )
|
ADD_SUBDIRECTORY ( examples/glview )
|
||||||
endif (TINYGLTF_BUILD_GL_EXAMPLES)
|
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
|
||||||
ADD_SUBDIRECTORY ( examples/validator )
|
ADD_SUBDIRECTORY ( examples/validator )
|
||||||
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
endif (TINYGLTF_BUILD_EXAMPLES)
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
|
||||||
ADD_SUBDIRECTORY ( examples/build-gltf )
|
|
||||||
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# TinuGLTF is a header-only library, so no library build. just install header files.
|
# TinuGLTF is a header-only library, so no library build. just install header files.
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -3,7 +3,7 @@
|
|||||||
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
|
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
|
||||||
|
|
||||||
`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler.
|
`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler.
|
||||||
If you are looking for old, C++03 version, please use `devel-picojson` branch(but not maintained anymore).
|
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -13,18 +13,12 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch(bu
|
|||||||
- v2.1.0 release(Draco support)
|
- v2.1.0 release(Draco support)
|
||||||
- v2.0.0 release(22 Aug, 2018)!
|
- v2.0.0 release(22 Aug, 2018)!
|
||||||
|
|
||||||
### Branches
|
|
||||||
|
|
||||||
* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson)
|
|
||||||
|
|
||||||
## Builds
|
## Builds
|
||||||
|
|
||||||
[](https://travis-ci.org/syoyo/tinygltf)
|
[](https://travis-ci.org/syoyo/tinygltf)
|
||||||
|
|
||||||
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Written in portable C++. C++-11 with STL dependency only.
|
* Written in portable C++. C++-11 with STL dependency only.
|
||||||
@@ -77,7 +71,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
|||||||
* [glview](examples/glview) : Simple glTF geometry viewer.
|
* [glview](examples/glview) : Simple glTF geometry viewer.
|
||||||
* [validator](examples/validator) : Simple glTF validator with JSON schema.
|
* [validator](examples/validator) : Simple glTF validator with JSON schema.
|
||||||
* [basic](examples/basic) : Basic glTF viewer with texturing support.
|
* [basic](examples/basic) : Basic glTF viewer with texturing support.
|
||||||
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
|
* [mesh-conv](examples/mesh-conv) : Convert glTF mesh to wavefront .obj, wavefront .obj to glTF mesh.
|
||||||
|
|
||||||
## Projects using TinyGLTF
|
## Projects using TinyGLTF
|
||||||
|
|
||||||
@@ -90,8 +84,6 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
|||||||
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
|
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
|
||||||
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
|
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
|
||||||
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
|
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
|
||||||
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
|
|
||||||
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and proessional development of its developer
|
|
||||||
* Your projects here! (Please send PR)
|
* Your projects here! (Please send PR)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
@@ -157,10 +149,6 @@ if (!ret) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Loader options
|
|
||||||
|
|
||||||
* `TinyGLTF::SetPreserveimageChannels(bool onoff)`. `true` to preserve image channels as stored in image file for loaded image. `false` by default for backward compatibility(image channels are widen to `RGBA` 4 channels). Effective only when using builtin image loader(STB image loader).
|
|
||||||
|
|
||||||
## Compile options
|
## Compile options
|
||||||
|
|
||||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||||
@@ -229,3 +217,7 @@ We may be better to introduce bounded memory size checking when parsing glTF dat
|
|||||||
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
||||||
* RapidJSON : Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. http://rapidjson.org/
|
* RapidJSON : Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. http://rapidjson.org/
|
||||||
* dlib(uridecode, uriencode) : Copyright (C) 2003 Davis E. King Boost Software License 1.0. http://dlib.net/dlib/server/server_http.cpp.html
|
* dlib(uridecode, uriencode) : Copyright (C) 2003 Davis E. King Boost Software License 1.0. http://dlib.net/dlib/server/server_http.cpp.html
|
||||||
|
|
||||||
|
### Used in examples
|
||||||
|
|
||||||
|
* clipp: MIT License. https://github.com/muellan/clipp
|
||||||
|
|||||||
1
examples/basic/.gitignore
vendored
1
examples/basic/.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
.vs
|
.vs
|
||||||
Debug
|
Debug
|
||||||
Release
|
|
||||||
x64
|
x64
|
||||||
packages
|
packages
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,3 @@ $ make
|
|||||||
Plese use solution file located at `basic` folder.
|
Plese use solution file located at `basic` folder.
|
||||||
|
|
||||||
|
|
||||||
## Limitation
|
|
||||||
|
|
||||||
There are so many limitations in this example(e.g. no PBR shader. the shader only shows texture of textures[0] if available).
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,32 +22,32 @@
|
|||||||
<VCProjectVersion>15.0</VCProjectVersion>
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
<ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid>
|
<ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid>
|
||||||
<RootNamespace>basic</RootNamespace>
|
<RootNamespace>basic</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -100,49 +100,42 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
|||||||
std::cout << "vaa missing: " << attrib.first << std::endl;
|
std::cout << "vaa missing: " << attrib.first << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.textures.size() > 0) {
|
GLuint texid;
|
||||||
// fixme: Use material's baseColor
|
glGenTextures(1, &texid);
|
||||||
tinygltf::Texture &tex = model.textures[0];
|
|
||||||
|
|
||||||
if (tex.source > -1) {
|
tinygltf::Texture &tex = model.textures[0];
|
||||||
|
tinygltf::Image &image = model.images[tex.source];
|
||||||
|
|
||||||
GLuint texid;
|
glBindTexture(GL_TEXTURE_2D, texid);
|
||||||
glGenTextures(1, &texid);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
|
||||||
tinygltf::Image &image = model.images[tex.source];
|
GLenum format = GL_RGBA;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texid);
|
if (image.component == 1) {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
format = GL_RED;
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
} else if (image.component == 2) {
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
format = GL_RG;
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
} else if (image.component == 3) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
format = GL_RGB;
|
||||||
|
} else {
|
||||||
GLenum format = GL_RGBA;
|
// ???
|
||||||
|
|
||||||
if (image.component == 1) {
|
|
||||||
format = GL_RED;
|
|
||||||
} else if (image.component == 2) {
|
|
||||||
format = GL_RG;
|
|
||||||
} else if (image.component == 3) {
|
|
||||||
format = GL_RGB;
|
|
||||||
} else {
|
|
||||||
// ???
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum type = GL_UNSIGNED_BYTE;
|
|
||||||
if (image.bits == 8) {
|
|
||||||
// ok
|
|
||||||
} else if (image.bits == 16) {
|
|
||||||
type = GL_UNSIGNED_SHORT;
|
|
||||||
} else {
|
|
||||||
// ???
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
|
||||||
format, type, &image.image.at(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLenum type = GL_UNSIGNED_BYTE;
|
||||||
|
if (image.bits == 8) {
|
||||||
|
// ok
|
||||||
|
} else if (image.bits == 16) {
|
||||||
|
type = GL_UNSIGNED_SHORT;
|
||||||
|
} else {
|
||||||
|
// ???
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||||
|
format, type, &image.image.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return vbos;
|
return vbos;
|
||||||
@@ -151,12 +144,8 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
|||||||
// bind models
|
// bind models
|
||||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
||||||
tinygltf::Node &node) {
|
tinygltf::Node &node) {
|
||||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size()));
|
|
||||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +157,6 @@ GLuint bindModel(tinygltf::Model &model) {
|
|||||||
|
|
||||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||||
assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
|
|
||||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +182,7 @@ void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
|||||||
|
|
||||||
// recursively draw node and children nodes of model
|
// recursively draw node and children nodes of model
|
||||||
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
||||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
drawMesh(model, model.meshes[node.mesh]);
|
||||||
drawMesh(model, model.meshes[node.mesh]);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
drawModelNodes(model, model.nodes[node.children[i]]);
|
drawModelNodes(model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
@@ -329,7 +315,7 @@ static void error_callback(int error, const char *description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
std::string filename = "../../../models/Cube/Cube.gltf";
|
std::string filename = "../../models/Cube/Cube.gltf";
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
filename = argv[1];
|
filename = argv[1];
|
||||||
@@ -341,12 +327,9 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Force create OpenGL 3.3
|
// Force create OpenGL 3.3
|
||||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||||
// Note (PE): On laptops with intel hd graphics card you can overcome the segfault by enabling experimental, see below (tested on lenovo thinkpad)
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
glewExperimental = GL_TRUE;
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
all:
|
|
||||||
$(CXX) -o create_triangle_gltf -I../../ create_triangle_gltf.cpp
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
// An example of how to generate a gltf file from scratch. This example
|
|
||||||
// was translated from the pygltlib documentation in the pypi project page,
|
|
||||||
// which in turn is based on the Khronos Sample Models at:
|
|
||||||
//
|
|
||||||
// https://github.com/KhronosGroup/glTF-Sample-Models
|
|
||||||
//
|
|
||||||
// This example is released under the MIT license.
|
|
||||||
//
|
|
||||||
// 2021-02-25 Thu
|
|
||||||
// Dov Grobgeld <dov.grobgeld@gmail.com>
|
|
||||||
|
|
||||||
|
|
||||||
// Define these only in *one* .cc file.
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
||||||
|
|
||||||
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
|
|
||||||
#include "tiny_gltf.h"
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
// Create a model with a single mesh and save it as a gltf file
|
|
||||||
tinygltf::Model m;
|
|
||||||
tinygltf::Scene scene;
|
|
||||||
tinygltf::Mesh mesh;
|
|
||||||
tinygltf::Primitive primitive;
|
|
||||||
tinygltf::Node node;
|
|
||||||
tinygltf::Buffer buffer;
|
|
||||||
tinygltf::BufferView bufferView1;
|
|
||||||
tinygltf::BufferView bufferView2;
|
|
||||||
tinygltf::Accessor accessor1;
|
|
||||||
tinygltf::Accessor accessor2;
|
|
||||||
tinygltf::Asset asset;
|
|
||||||
|
|
||||||
// This is the raw data buffer.
|
|
||||||
buffer.data = {
|
|
||||||
// 6 bytes of indices and two bytes of padding
|
|
||||||
0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,
|
|
||||||
// 36 bytes of floating point numbers
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
||||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
|
|
||||||
0x00,0x00,0x00,0x00};
|
|
||||||
|
|
||||||
// "The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
|
|
||||||
// start of the buffer.
|
|
||||||
bufferView1.buffer = 0;
|
|
||||||
bufferView1.byteOffset=0;
|
|
||||||
bufferView1.byteLength=6;
|
|
||||||
bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
|
|
||||||
|
|
||||||
// The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
|
|
||||||
// at position 8 in the buffer and are of type ARRAY_BUFFER
|
|
||||||
bufferView2.buffer = 0;
|
|
||||||
bufferView2.byteOffset=8;
|
|
||||||
bufferView2.byteLength=36;
|
|
||||||
bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
|
||||||
|
|
||||||
// Describe the layout of bufferView1, the indices of the vertices
|
|
||||||
accessor1.bufferView = 0;
|
|
||||||
accessor1.byteOffset = 0;
|
|
||||||
accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
|
|
||||||
accessor1.count = 3;
|
|
||||||
accessor1.type = TINYGLTF_TYPE_SCALAR;
|
|
||||||
accessor1.maxValues.push_back(2);
|
|
||||||
accessor1.minValues.push_back(0);
|
|
||||||
|
|
||||||
// Describe the layout of bufferView2, the vertices themself
|
|
||||||
accessor2.bufferView = 1;
|
|
||||||
accessor2.byteOffset = 0;
|
|
||||||
accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
|
|
||||||
accessor2.count = 3;
|
|
||||||
accessor2.type = TINYGLTF_TYPE_VEC3;
|
|
||||||
accessor2.maxValues = {1.0, 1.0, 0.0};
|
|
||||||
accessor2.minValues = {0.0, 0.0, 0.0};
|
|
||||||
|
|
||||||
// Build the mesh primitive and add it to the mesh
|
|
||||||
primitive.indices = 0; // The index of the accessor for the vertex indices
|
|
||||||
primitive.attributes["POSITION"] = 1; // The index of the accessor for positions
|
|
||||||
primitive.material = 0;
|
|
||||||
primitive.mode = TINYGLTF_MODE_TRIANGLES;
|
|
||||||
mesh.primitives.push_back(primitive);
|
|
||||||
|
|
||||||
// Other tie ups
|
|
||||||
node.mesh = 0;
|
|
||||||
scene.nodes.push_back(0); // Default scene
|
|
||||||
|
|
||||||
// Define the asset. The version is required
|
|
||||||
asset.version = "2.0";
|
|
||||||
asset.generator = "tinygltf";
|
|
||||||
|
|
||||||
// Now all that remains is to tie back all the loose objects into the
|
|
||||||
// our single model.
|
|
||||||
m.scenes.push_back(scene);
|
|
||||||
m.meshes.push_back(mesh);
|
|
||||||
m.nodes.push_back(node);
|
|
||||||
m.buffers.push_back(buffer);
|
|
||||||
m.bufferViews.push_back(bufferView1);
|
|
||||||
m.bufferViews.push_back(bufferView2);
|
|
||||||
m.accessors.push_back(accessor1);
|
|
||||||
m.accessors.push_back(accessor2);
|
|
||||||
m.asset = asset;
|
|
||||||
|
|
||||||
// Create a simple material
|
|
||||||
tinygltf::Material mat;
|
|
||||||
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
|
|
||||||
mat.doubleSided = true;
|
|
||||||
m.materials.push_back(mat);
|
|
||||||
|
|
||||||
// Save it to a file
|
|
||||||
tinygltf::TinyGLTF gltf;
|
|
||||||
gltf.WriteGltfSceneToFile(&m, "triangle.gltf",
|
|
||||||
true, // embedImages
|
|
||||||
true, // embedBuffers
|
|
||||||
true, // pretty print
|
|
||||||
false); // write binary
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
20
examples/common/clipp.LICENSE
Normal file
20
examples/common/clipp.LICENSE
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 André Müller; foss@andremueller-online.de
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
7024
examples/common/clipp.h
Normal file
7024
examples/common/clipp.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
project(dxview)
|
|
||||||
|
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
|
||||||
find_package(spdlog CONFIG REQUIRED)
|
|
||||||
|
|
||||||
add_executable(dxview
|
|
||||||
src/Viewer.h
|
|
||||||
src/Viewer.cc
|
|
||||||
src/dxview.cc
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(dxview
|
|
||||||
PRIVATE
|
|
||||||
../../
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(dxview
|
|
||||||
PRIVATE
|
|
||||||
DXVIEW_SWAP_CHAIN_BUFFER_COUNT=3
|
|
||||||
DXVIEW_RES_DIR=L"${PROJECT_SOURCE_DIR}/res"
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(dxview
|
|
||||||
PRIVATE
|
|
||||||
dxgi
|
|
||||||
d3dcompiler
|
|
||||||
d3d12
|
|
||||||
glfw
|
|
||||||
spdlog::spdlog
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(dxview
|
|
||||||
PROPERTIES
|
|
||||||
CXX_STANDARD 17
|
|
||||||
)
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# DirectX glTF Viewer
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This project was motivated by a lack of sample code demonstrating the graphics API agnostic nature of the glTF specification. The sample code is written using modern C++ and DirectX 12 for the client application.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
* [x] DirectX 12
|
|
||||||
* [ ] Loader
|
|
||||||
* [ ] Animation
|
|
||||||
* [ ] Morph Target
|
|
||||||
* [ ] Physical Base Rendering
|
|
||||||
* [ ] Environment Map
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
* [CMake](https://github.com/Kitware/CMake)
|
|
||||||
* [Vcpkg](https://github.com/Microsoft/vcpkg)
|
|
||||||
* [GLFW](https://github.com/glfw/glfw)
|
|
||||||
* [spdlog](https://github.com/gabime/spdlog)
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
### Install dependencies
|
|
||||||
|
|
||||||
```
|
|
||||||
vcpkg install glfw3:x64-windows
|
|
||||||
vcpkg install spdlog:x64-windows
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate Project Files
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir build
|
|
||||||
cmake . -B build -DCMAKE_TOOLCHAIN_FILE=${VCPKG_DIR}/script/buildsystem/vcpkg.cmake
|
|
||||||
```
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
float4 main() : SV_Target {
|
|
||||||
return float4(0.5, 0.5, 0.5, 1.0);
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
struct RS2PS {
|
|
||||||
float4 position : SV_POSITION;
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
float2 texcoord_0: TEXCOORD_0;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureInfo {
|
|
||||||
uint textureIndex;
|
|
||||||
uint samplerIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PBRMetallicRoughness {
|
|
||||||
float4 baseColorFactor;
|
|
||||||
TextureInfo baseColorTexture;
|
|
||||||
float metallicFactor;
|
|
||||||
float roughnessFactor;
|
|
||||||
TextureInfo metallicRoughnessTexture;
|
|
||||||
};
|
|
||||||
|
|
||||||
cbuffer Material : register(b2) {
|
|
||||||
PBRMetallicRoughness pbrMetallicRoughness;
|
|
||||||
};
|
|
||||||
|
|
||||||
Texture2D textures[5] : register(t0);
|
|
||||||
SamplerState samplerState[5] : register(s0);
|
|
||||||
|
|
||||||
float4 getBaseColor(float2 uv) {
|
|
||||||
float4 baseColor = pbrMetallicRoughness.baseColorFactor;
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
TextureInfo baseColorTexture = pbrMetallicRoughness.baseColorTexture;
|
|
||||||
if (baseColorTexture.textureIndex >= 0) {
|
|
||||||
baseColor *= textures[baseColorTexture.textureIndex].Sample(samplerState[baseColorTexture.samplerIndex], uv);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return baseColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 main(RS2PS input) : SV_Target {
|
|
||||||
float2 uv = float2(0.0, 0.0);
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
uv = input.texcoord_0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float4 color = getBaseColor(uv);
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
struct IA2VS {
|
|
||||||
float3 position : POSITION;
|
|
||||||
|
|
||||||
#ifdef HAS_NORMAL
|
|
||||||
float3 normal : NORMAL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_TANGENT
|
|
||||||
float4 tangent : TANGENT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
float2 texcoord_0: TEXCOORD_0;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VS2RS {
|
|
||||||
float4 position : SV_POSITION;
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
float2 texcoord_0: TEXCOORD_0;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
cbuffer Camera : register(b0) {
|
|
||||||
float4x4 V;
|
|
||||||
float4x4 P;
|
|
||||||
float4x4 VP;
|
|
||||||
};
|
|
||||||
|
|
||||||
cbuffer Node : register(b1) {
|
|
||||||
float4x4 M;
|
|
||||||
};
|
|
||||||
|
|
||||||
VS2RS main(IA2VS input) {
|
|
||||||
VS2RS output;
|
|
||||||
output.position = mul(float4(input.position, 1.0), M);
|
|
||||||
output.position = mul(output.position, V);
|
|
||||||
output.position = mul(output.position, P);
|
|
||||||
|
|
||||||
#ifdef HAS_TEXCOORD_0
|
|
||||||
output.texcoord_0 = input.texcoord_0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,130 +0,0 @@
|
|||||||
#ifndef DXVIEW_VIEWER_GUARD
|
|
||||||
#define DXVIEW_VIEWER_GUARD
|
|
||||||
|
|
||||||
#include <DirectXMath.h>
|
|
||||||
#include <d3d12.h>
|
|
||||||
#include <dxgi1_6.h>
|
|
||||||
#include <tiny_gltf.h>
|
|
||||||
#include <wrl.h>
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using Microsoft::WRL::ComPtr;
|
|
||||||
|
|
||||||
enum RenderPassType { RENDER_PASS_TYPE_PRESENT = 0, RENDER_PASS_TYPE_COUNT };
|
|
||||||
|
|
||||||
struct RenderTarget {
|
|
||||||
ComPtr<ID3D12Resource> pTexture;
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE viewDescriptor;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureInfo {
|
|
||||||
int32_t textureIndex;
|
|
||||||
int32_t samplerIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PBRMetallicRoughness {
|
|
||||||
DirectX::XMFLOAT4 baseColorFactor;
|
|
||||||
TextureInfo baseColorTexture;
|
|
||||||
float metallicFactor;
|
|
||||||
float roughnessFactor;
|
|
||||||
TextureInfo metallicRoughnessTexture;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Material {
|
|
||||||
std::string name;
|
|
||||||
D3D12_BLEND_DESC blendDesc;
|
|
||||||
D3D12_RASTERIZER_DESC rasterizerDesc;
|
|
||||||
ComPtr<ID3D12Resource> pBuffer;
|
|
||||||
void* pBufferData;
|
|
||||||
ComPtr<ID3D12DescriptorHeap> pSRVDescriptorHeap;
|
|
||||||
ComPtr<ID3D12DescriptorHeap> pSamplerDescriptorHeap;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Attribute {
|
|
||||||
std::string name;
|
|
||||||
DXGI_FORMAT format;
|
|
||||||
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Primitive {
|
|
||||||
std::vector<Attribute> attributes;
|
|
||||||
uint32_t vertexCount;
|
|
||||||
D3D12_PRIMITIVE_TOPOLOGY primitiveTopology;
|
|
||||||
D3D12_INDEX_BUFFER_VIEW indexBufferView;
|
|
||||||
uint32_t indexCount;
|
|
||||||
Material* pMaterial;
|
|
||||||
ComPtr<ID3D12RootSignature> pRootSignature;
|
|
||||||
ComPtr<ID3D12PipelineState> pPipelineState;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Mesh {
|
|
||||||
std::string name;
|
|
||||||
std::vector<Primitive> primitives;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Node {
|
|
||||||
DirectX::XMFLOAT4X4 M;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Camera {
|
|
||||||
DirectX::XMFLOAT4X4 V;
|
|
||||||
DirectX::XMFLOAT4X4 P;
|
|
||||||
DirectX::XMFLOAT4X4 VP;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Viewer {
|
|
||||||
public:
|
|
||||||
Viewer(HWND window, tinygltf::Model* pModel);
|
|
||||||
|
|
||||||
void update(double deltaTime);
|
|
||||||
void render(double deltaTime);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void initDirectX(HWND window);
|
|
||||||
void buildRenderTargets();
|
|
||||||
void buildResources();
|
|
||||||
void buildBuffers(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
|
|
||||||
void buildImages(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
|
|
||||||
void buildSamplerDescs();
|
|
||||||
void buildMaterials();
|
|
||||||
void buildMeshes();
|
|
||||||
void buildNodes();
|
|
||||||
|
|
||||||
void drawNode(uint64_t nodeIndex);
|
|
||||||
|
|
||||||
private:
|
|
||||||
tinygltf::Model* pModel_;
|
|
||||||
ComPtr<IDXGIFactory1> pFactory_;
|
|
||||||
ComPtr<IDXGIAdapter1> pAdapter_;
|
|
||||||
ComPtr<ID3D12Device> pDevice_;
|
|
||||||
ComPtr<ID3D12CommandQueue> pDirectCommandQueue_;
|
|
||||||
UINT64 directFenceValue_;
|
|
||||||
ComPtr<ID3D12Fence> pDirectFence_;
|
|
||||||
ComPtr<ID3D12CommandQueue> pCopyCommandQueue_;
|
|
||||||
UINT64 copyFenceValue_;
|
|
||||||
ComPtr<ID3D12Fence> pCopyFence_;
|
|
||||||
ComPtr<IDXGISwapChain3> pSwapChain_;
|
|
||||||
ComPtr<ID3D12Resource> pSwapChainBuffers_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
|
||||||
ComPtr<ID3D12CommandAllocator>
|
|
||||||
pDirectCommandAllocators_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
|
||||||
ComPtr<ID3D12GraphicsCommandList> pDirectCommandList_;
|
|
||||||
ComPtr<ID3D12CommandAllocator> pCopyCommandAllocator_;
|
|
||||||
ComPtr<ID3D12GraphicsCommandList> pCopyCommandList_;
|
|
||||||
UINT descriptorIncrementSize_[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
|
|
||||||
ComPtr<ID3D12DescriptorHeap>
|
|
||||||
pRTVDescriptorHeaps_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
|
||||||
std::vector<RenderTarget> renderTargets_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
|
||||||
std::vector<ComPtr<ID3D12Resource> > pBuffers_;
|
|
||||||
std::vector<ComPtr<ID3D12Resource> > pTextures_;
|
|
||||||
std::vector<D3D12_SAMPLER_DESC> samplerDescs_;
|
|
||||||
std::vector<Material> materials_;
|
|
||||||
std::vector<Mesh> meshes_;
|
|
||||||
std::vector<ComPtr<ID3D12Resource> > pNodeBuffers_;
|
|
||||||
ComPtr<ID3D12Resource> pCameraBuffer_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
|
||||||
#define STBI_MSC_SECURE_CRT
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <GLFW/glfw3native.h>
|
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
#include <tiny_gltf.h>
|
|
||||||
|
|
||||||
#undef GLFW_EXPOSE_NATIVE_WIN32
|
|
||||||
#undef TINYGLTF_IMPLEMENTATION
|
|
||||||
#undef STBI_MSC_SECURE_CRT
|
|
||||||
#undef STB_IMAGE_IMPLEMENTATION
|
|
||||||
#undef STB_IMAGE_WRITE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Viewer.h"
|
|
||||||
|
|
||||||
static void onError(int error, const char* message) {
|
|
||||||
spdlog::error("[{}] {}", error, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onRender(Viewer* pViewer, double deltaTime) {
|
|
||||||
pViewer->update(deltaTime);
|
|
||||||
pViewer->render(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
tinygltf::TinyGLTF context;
|
|
||||||
|
|
||||||
tinygltf::Model model;
|
|
||||||
std::string error;
|
|
||||||
std::string warning;
|
|
||||||
if (!context.LoadASCIIFromFile(&model, &error, &warning, argv[1])) {
|
|
||||||
if (!error.empty()) {
|
|
||||||
spdlog::error("{}", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!warning.empty()) {
|
|
||||||
spdlog::warn("{}", warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLFWwindow* pWindow;
|
|
||||||
|
|
||||||
glfwSetErrorCallback(onError);
|
|
||||||
|
|
||||||
if (!glfwInit()) {
|
|
||||||
spdlog::error("Fail to initialize GLFW!!!");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
||||||
|
|
||||||
pWindow = glfwCreateWindow(512, 512, "dxview", nullptr, nullptr);
|
|
||||||
if (!pWindow) {
|
|
||||||
spdlog::error("Fail to create GLFWwindow!!!");
|
|
||||||
glfwTerminate();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pViewer = std::make_unique<Viewer>(glfwGetWin32Window(pWindow), &model);
|
|
||||||
if (!pViewer) {
|
|
||||||
spdlog::error("Fail to create Viewer");
|
|
||||||
glfwDestroyWindow(pWindow);
|
|
||||||
glfwTerminate();
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto prevTimeStamp = glfwGetTime();
|
|
||||||
while (!glfwWindowShouldClose(pWindow)) {
|
|
||||||
auto currTimeStamp = glfwGetTime();
|
|
||||||
|
|
||||||
onRender(pViewer.get(), currTimeStamp - prevTimeStamp);
|
|
||||||
prevTimeStamp = currTimeStamp;
|
|
||||||
|
|
||||||
glfwPollEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwDestroyWindow(pWindow);
|
|
||||||
glfwTerminate();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
5
examples/mesh-conv/Makefile
Normal file
5
examples/mesh-conv/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#EXTRA_CXXFLAGS := -fsanitize=address -fno-omit-frame-pointer -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded
|
||||||
|
EXTRA_CXXFLAGS :=
|
||||||
|
|
||||||
|
all:
|
||||||
|
clang++ -std=c++11 -g -O1 -I../../ -I../common $(EXTRA_CXXFLAGS) -o mesh-conv mesh-conv.cc mesh-util.cc tinygltf_impl.cc
|
||||||
5
examples/mesh-conv/Makefile.meson
Normal file
5
examples/mesh-conv/Makefile.meson
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
all:
|
||||||
|
ninja
|
||||||
|
|
||||||
|
clean:
|
||||||
|
ninja -t clean
|
||||||
58
examples/mesh-conv/README.md
Normal file
58
examples/mesh-conv/README.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Mesh modify experiment
|
||||||
|
|
||||||
|
Sometimes we want to tweak mesh attributes(e.g. vertex position, uv coord, etc).
|
||||||
|
glTF itself does not allow ASCII representation of such data so we need to write a converter.
|
||||||
|
|
||||||
|
This example show how to
|
||||||
|
|
||||||
|
- Export mesh data from .bin to .obj
|
||||||
|
- Import mesh data to .bin(update corresponding buffer data) from .obj
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Support skin weights(`JOINTS_N`, `WEIGHTS_N`)
|
||||||
|
|
||||||
|
## Supported attributes
|
||||||
|
|
||||||
|
* [x] POSITION
|
||||||
|
* [x] NORMAL
|
||||||
|
* [x] TANGENT
|
||||||
|
* [ ] COLOR (vertex color)
|
||||||
|
* [x] TEXCOORD_N
|
||||||
|
* Only single texcoord(uv set) is supported
|
||||||
|
* Specify `--uvset 1` to specify which UV to use.
|
||||||
|
* [x] WEIGHTS_N, JOINTS_N
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Wavefront .obj to glTF
|
||||||
|
|
||||||
|
```
|
||||||
|
$ mesh-modify --op=obj2gltf input.obj
|
||||||
|
```
|
||||||
|
|
||||||
|
All shapes in .obj are concatenated and create single glTF mesh.
|
||||||
|
(tinyobjloader's skin weight extension `vw` supported)
|
||||||
|
|
||||||
|
#### Limitation
|
||||||
|
|
||||||
|
Buffer is stored as external file(`.bin`)
|
||||||
|
|
||||||
|
### glTF to Wavefront .obj
|
||||||
|
|
||||||
|
```
|
||||||
|
$ mesh-modify --op=gltf2obj input.gltf
|
||||||
|
```
|
||||||
|
|
||||||
|
.obj will be created for each glTF Mesh.
|
||||||
|
(Skin weight data is exported to .obj using tinyobjloader's skin weight extension `vw`)
|
||||||
|
|
||||||
|
#### Limitation
|
||||||
|
|
||||||
|
Buffer is stored as external file(`.bin`)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
* [ ] obj2gltf: Assign glTF material from .mtl
|
||||||
|
* [ ] modify/patch mesh geometry in glTF
|
||||||
|
* By using JSON Patch or JSON Merge feature
|
||||||
3
examples/mesh-conv/bootstrap-meson.sh
Executable file
3
examples/mesh-conv/bootstrap-meson.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
rm -rf build
|
||||||
|
CXX=clang++ CC=clang meson build -Db_sanitize=address -Db_lundef=false --buildtype=debug
|
||||||
|
cp Makefile.meson build/Makefile
|
||||||
798
examples/mesh-conv/mesh-conv.cc
Normal file
798
examples/mesh-conv/mesh-conv.cc
Normal file
@@ -0,0 +1,798 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#if !defined(__ANDROID__) && !defined(_WIN32)
|
||||||
|
#include <wordexp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Weverything"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../../json.hpp"
|
||||||
|
#include "../common/clipp.h"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "../../tiny_gltf.h"
|
||||||
|
#else
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mesh-util.hh"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-function"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static std::string PrintMode(int mode) {
|
||||||
|
if (mode == TINYGLTF_MODE_POINTS) {
|
||||||
|
return "POINTS";
|
||||||
|
} else if (mode == TINYGLTF_MODE_LINE) {
|
||||||
|
return "LINE";
|
||||||
|
} else if (mode == TINYGLTF_MODE_LINE_LOOP) {
|
||||||
|
return "LINE_LOOP";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLES) {
|
||||||
|
return "TRIANGLES";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
|
||||||
|
return "TRIANGLE_FAN";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
|
||||||
|
return "TRIANGLE_STRIP";
|
||||||
|
}
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintTarget(int target) {
|
||||||
|
if (target == 34962) {
|
||||||
|
return "GL_ARRAY_BUFFER";
|
||||||
|
} else if (target == 34963) {
|
||||||
|
return "GL_ELEMENT_ARRAY_BUFFER";
|
||||||
|
} else {
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintType(int ty) {
|
||||||
|
if (ty == TINYGLTF_TYPE_SCALAR) {
|
||||||
|
return "SCALAR";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VECTOR) {
|
||||||
|
return "VECTOR";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC2) {
|
||||||
|
return "VEC2";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC3) {
|
||||||
|
return "VEC3";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC4) {
|
||||||
|
return "VEC4";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MATRIX) {
|
||||||
|
return "MATRIX";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT2) {
|
||||||
|
return "MAT2";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT3) {
|
||||||
|
return "MAT3";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT4) {
|
||||||
|
return "MAT4";
|
||||||
|
}
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintComponentType(int ty) {
|
||||||
|
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
return "BYTE";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
return "UNSIGNED_BYTE";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
return "SHORT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
return "UNSIGNED_SHORT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
|
||||||
|
return "INT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
|
||||||
|
return "UNSIGNED_INT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||||
|
return "FLOAT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
||||||
|
return "DOUBLE";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||||
|
// TODO(syoyo): Support more data type
|
||||||
|
struct VertexAttrib {
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// Value are converted to float type.
|
||||||
|
std::vector<float> data;
|
||||||
|
|
||||||
|
// Corresponding info in binary data
|
||||||
|
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||||
|
int component_type; // storage type. e.g.
|
||||||
|
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||||
|
uint64_t buffer_offset{0};
|
||||||
|
size_t buffer_length{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshPrim {
|
||||||
|
std::string name;
|
||||||
|
int32_t id{-1};
|
||||||
|
|
||||||
|
int mode{TINYGLTF_MODE_TRIANGLES};
|
||||||
|
|
||||||
|
VertexAttrib position; // vec3
|
||||||
|
VertexAttrib normal; // vec3
|
||||||
|
VertexAttrib tangent; // vec4
|
||||||
|
VertexAttrib color; // vec3 or vec4
|
||||||
|
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||||
|
std::map<int, VertexAttrib> weights; // <slot, attrib>
|
||||||
|
std::map<int, VertexAttrib>
|
||||||
|
joints; // <slot, attrib> store data as float type
|
||||||
|
|
||||||
|
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||||
|
std::vector<uint32_t> indices; // vertex indices
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static std::string GetFilePathExtension(const std::string &FileName) {
|
||||||
|
if (FileName.find_last_of(".") != std::string::npos)
|
||||||
|
return FileName.substr(FileName.find_last_of(".") + 1);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ComponentTypeByteSize(int type) {
|
||||||
|
switch (type) {
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||||
|
return sizeof(char);
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||||
|
return sizeof(short);
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||||
|
return sizeof(int);
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||||
|
return sizeof(float);
|
||||||
|
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||||
|
return sizeof(double);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> LoadBin(const std::string &filename) {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||||
|
|
||||||
|
if (is.is_open()) {
|
||||||
|
size_t size = size_t(is.tellg());
|
||||||
|
is.seekg(0, std::ios::beg);
|
||||||
|
if (size < 4) {
|
||||||
|
std::cerr << "File size is zero or too short: " << size << "\n";
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.resize(size);
|
||||||
|
is.read(reinterpret_cast<char *>(data.data()), std::streamsize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(syoyo): Use C++17 like filesystem library
|
||||||
|
|
||||||
|
bool FileExists(const std::string &abs_filename) {
|
||||||
|
bool ret;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO(syoyo): Support utf8 filepath
|
||||||
|
FILE *fp = nullptr;
|
||||||
|
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
|
||||||
|
if (err != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||||
|
#endif
|
||||||
|
if (fp) {
|
||||||
|
ret = true;
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string JoinPath(const std::string &path0,
|
||||||
|
const std::string &path1) {
|
||||||
|
if (path0.empty()) {
|
||||||
|
return path1;
|
||||||
|
} else {
|
||||||
|
// check '/'
|
||||||
|
char lastChar = *path0.rbegin();
|
||||||
|
if (lastChar != '/') {
|
||||||
|
return path0 + std::string("/") + path1;
|
||||||
|
} else {
|
||||||
|
return path0 + path1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExpandFilePath(const std::string &filepath) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||||
|
char *str = new char[len];
|
||||||
|
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||||
|
|
||||||
|
std::string s(str);
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
|
defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
||||||
|
// no expansion
|
||||||
|
std::string s = filepath;
|
||||||
|
#else
|
||||||
|
std::string s;
|
||||||
|
wordexp_t p;
|
||||||
|
|
||||||
|
if (filepath.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote the string to keep any spaces in filepath intact.
|
||||||
|
std::string quoted_path = "\"" + filepath + "\"";
|
||||||
|
// char** w;
|
||||||
|
int ret = wordexp(quoted_path.c_str(), &p, 0);
|
||||||
|
if (ret) {
|
||||||
|
// err
|
||||||
|
s = filepath;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use first element only.
|
||||||
|
if (p.we_wordv) {
|
||||||
|
s = std::string(p.we_wordv[0]);
|
||||||
|
wordfree(&p);
|
||||||
|
} else {
|
||||||
|
s = filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string FindFile(const std::vector<std::string> &paths,
|
||||||
|
const std::string &filepath) {
|
||||||
|
for (size_t i = 0; i < paths.size(); i++) {
|
||||||
|
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
|
||||||
|
if (FileExists(absPath)) {
|
||||||
|
return absPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetBaseDir(const std::string &filepath) {
|
||||||
|
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||||
|
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetSlotId(const std::string &name) {
|
||||||
|
if (name.rfind("TEXCOORD_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "TEXCOORD_%d", &id);
|
||||||
|
return id;
|
||||||
|
} else if (name.rfind("WEIGHTS_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "WEIGHTS_%d", &id);
|
||||||
|
return id;
|
||||||
|
} else if (name.rfind("JOINTS_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "JOINTS_%d", &id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsAttributeSupported(const std::string &name) {
|
||||||
|
constexpr int max_slots = 8;
|
||||||
|
|
||||||
|
if (name.compare("POSITION") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.compare("NORMAL") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.compare("TANGENT") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "TEXCOORD_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "WEIGHTS_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "JOINTS_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float Unpack(const unsigned char *ptr, int type) {
|
||||||
|
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
unsigned char data = *ptr;
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
char data = static_cast<char>(*ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||||
|
float data = *reinterpret_cast<const float *>(ptr);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t UnpackIndex(const unsigned char *ptr, int type) {
|
||||||
|
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
unsigned char data = *ptr;
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
char data = static_cast<char>(*ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_INT) {
|
||||||
|
// TODO(syoyo): Check overflow(2G+ index)
|
||||||
|
int32_t data = *reinterpret_cast<const int32_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
|
||||||
|
uint32_t data = *reinterpret_cast<const uint32_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
uint32_t data = *reinterpret_cast<const uint32_t *>(ptr);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||||
|
return static_cast<uint32_t>(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DumpMesh(const tinygltf::Model &model, const tinygltf::Mesh &mesh,
|
||||||
|
bool verbose, example::MeshPrim *out) {
|
||||||
|
out->prims.clear();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
||||||
|
const tinygltf::Primitive &primitive = mesh.primitives[i];
|
||||||
|
|
||||||
|
if (primitive.indices < 0) {
|
||||||
|
std::cerr << "Primitive indices must be provided\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
example::PrimSet out_prim;
|
||||||
|
|
||||||
|
// indices.
|
||||||
|
{
|
||||||
|
const tinygltf::Accessor &indexAccessor =
|
||||||
|
model.accessors[size_t(primitive.indices)];
|
||||||
|
|
||||||
|
size_t num_elements = indexAccessor.count;
|
||||||
|
std::cout << "index.elements = " << num_elements << "\n";
|
||||||
|
|
||||||
|
size_t byte_stride = ComponentTypeByteSize(indexAccessor.componentType);
|
||||||
|
|
||||||
|
const tinygltf::BufferView &indexBufferView =
|
||||||
|
model.bufferViews[size_t(indexAccessor.bufferView)];
|
||||||
|
|
||||||
|
// should be 34963(ELEMENT_ARRAY_BUFFER)
|
||||||
|
std::cout << "index.target = " << PrintTarget(indexBufferView.target)
|
||||||
|
<< "\n";
|
||||||
|
if (indexBufferView.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) {
|
||||||
|
std::cerr << "indexBufferView.target must be ELEMENT_ARRAY_BUFFER\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Buffer &indexBuffer =
|
||||||
|
model.buffers[size_t(indexBufferView.buffer)];
|
||||||
|
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < num_elements; k++) {
|
||||||
|
// TODO(syoyo): out-of-bounds check.
|
||||||
|
const unsigned char *ptr = indexBuffer.data.data() +
|
||||||
|
indexBufferView.byteOffset +
|
||||||
|
(k * byte_stride) + indexAccessor.byteOffset;
|
||||||
|
|
||||||
|
uint32_t idx = UnpackIndex(ptr, indexAccessor.componentType);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "vertex_index[" << k << "] = " << idx << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.push_back(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_prim.indices = indices;
|
||||||
|
out_prim.indices_type = indexAccessor.componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
{
|
||||||
|
std::map<std::string, int>::const_iterator it(
|
||||||
|
primitive.attributes.begin());
|
||||||
|
std::map<std::string, int>::const_iterator itEnd(
|
||||||
|
primitive.attributes.end());
|
||||||
|
|
||||||
|
for (; it != itEnd; it++) {
|
||||||
|
// it->first would be "POSITION", "NORMAL", "TEXCOORD_0", ...
|
||||||
|
if (!IsAttributeSupported(it->first)) {
|
||||||
|
std::cout << "Unsupported attribute: " << it->first << "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_t(it->second) >= model.accessors.size()) {
|
||||||
|
std::cerr << "Invalid accessor id: " << it->second << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Accessor &accessor =
|
||||||
|
model.accessors[size_t(it->second)];
|
||||||
|
|
||||||
|
size_t elem_size = 1;
|
||||||
|
if (accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||||
|
elem_size = 1;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||||
|
elem_size = 2;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||||
|
elem_size = 3;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||||
|
elem_size = 4;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Invalid or unsupported accessor type: "
|
||||||
|
<< PrintType(accessor.type) << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << PrintComponentType(accessor.componentType) << "\n";
|
||||||
|
|
||||||
|
size_t byte_stride = ComponentTypeByteSize(accessor.componentType);
|
||||||
|
|
||||||
|
std::cout << "attribute: " << it->first << "\n";
|
||||||
|
// if (gGLProgramState.attribs[it->first] >= 0) {
|
||||||
|
// Compute byteStride from Accessor + BufferView combination.
|
||||||
|
int byteStride =
|
||||||
|
accessor.ByteStride(model.bufferViews[size_t(accessor.bufferView)]);
|
||||||
|
assert(byteStride != -1);
|
||||||
|
|
||||||
|
std::cout << "byteOffset: " << accessor.byteOffset << "\n";
|
||||||
|
|
||||||
|
const tinygltf::BufferView &bufferView =
|
||||||
|
model.bufferViews[size_t(accessor.bufferView)];
|
||||||
|
const tinygltf::Buffer &buffer =
|
||||||
|
model.buffers[size_t(bufferView.buffer)];
|
||||||
|
|
||||||
|
size_t num_elems = accessor.count * elem_size;
|
||||||
|
|
||||||
|
example::VertexAttrib attrib;
|
||||||
|
for (size_t k = 0; k < num_elems; k++) {
|
||||||
|
// TODO(syoyo): out-of-bounds check.
|
||||||
|
const unsigned char *ptr = buffer.data.data() +
|
||||||
|
bufferView.byteOffset + (k * byte_stride) +
|
||||||
|
accessor.byteOffset;
|
||||||
|
float value = Unpack(ptr, accessor.componentType);
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "[" << k << "] value = " << value << "\n";
|
||||||
|
}
|
||||||
|
attrib.data.push_back(value);
|
||||||
|
}
|
||||||
|
attrib.component_type = accessor.componentType;
|
||||||
|
attrib.data_type = accessor.type;
|
||||||
|
attrib.name = it->first;
|
||||||
|
|
||||||
|
if (attrib.name.compare("POSITION") == 0) {
|
||||||
|
out_prim.position = attrib;
|
||||||
|
} else if (attrib.name.compare("NORMAL") == 0) {
|
||||||
|
out_prim.normal = attrib;
|
||||||
|
} else if (attrib.name.compare("TANGENT") == 0) {
|
||||||
|
out_prim.tangent = attrib;
|
||||||
|
} else if (attrib.name.rfind("TEXCOORD_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "texcoord[" << id << "]\n";
|
||||||
|
out_prim.texcoords[id] = attrib;
|
||||||
|
} else if (attrib.name.rfind("JOINTS_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "joints[" << id << "]\n";
|
||||||
|
out_prim.joints[id] = attrib;
|
||||||
|
} else if (attrib.name.rfind("WEIGHTS_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "weights[" << id << "]\n";
|
||||||
|
out_prim.weights[id] = attrib;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: attrib.name = " << attrib.name << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Accessor &indexAccessor =
|
||||||
|
model.accessors[size_t(primitive.indices)];
|
||||||
|
(void)indexAccessor;
|
||||||
|
PrintMode(primitive.mode);
|
||||||
|
if (primitive.mode != TINYGLTF_MODE_TRIANGLES) {
|
||||||
|
std::cerr << "Supported Primitive mode is TRIANGLES only at the moment\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_prim.mode = primitive.mode;
|
||||||
|
|
||||||
|
out->prims.push_back(out_prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
out->name = mesh.name;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model,
|
||||||
|
bool verbose, std::vector<example::MeshPrim> *outs) {
|
||||||
|
// Get .bin data
|
||||||
|
{
|
||||||
|
if (model.buffers.size() != 1) {
|
||||||
|
std::cerr << "Single element of `buffers` is supported at the moment.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Buffer &buffer = model.buffers[0];
|
||||||
|
if (buffer.uri.empty()) {
|
||||||
|
std::cerr << "buffer.uri must be a filepath.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.data.size() < 4) {
|
||||||
|
std::cerr << "Invalid buffer.byteLength.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> search_paths;
|
||||||
|
search_paths.push_back(asset_path);
|
||||||
|
|
||||||
|
std::string abs_filepath = FindFile(search_paths, buffer.uri);
|
||||||
|
std::vector<uint8_t> bin = LoadBin(abs_filepath);
|
||||||
|
if (bin.size() != buffer.data.size()) {
|
||||||
|
std::cerr << "Byte size mismatch. Failed to load file: " << buffer.uri
|
||||||
|
<< "\n";
|
||||||
|
std::cerr << " Searched absolute file path: " << abs_filepath << "\n";
|
||||||
|
std::cerr << " .bin size = " << bin.size()
|
||||||
|
<< ", size in 'buffer.uri' = " << buffer.data.size() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &mesh : model.meshes) {
|
||||||
|
std::cout << "mesh.name: " << mesh.name << "\n";
|
||||||
|
|
||||||
|
example::MeshPrim output;
|
||||||
|
bool ret = DumpMesh(model, mesh, verbose, &output);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outs->push_back(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
std::string op;
|
||||||
|
std::string input_filename;
|
||||||
|
std::string output_filename = "output.gltf";
|
||||||
|
int uvset = 0;
|
||||||
|
bool verbose = false;
|
||||||
|
bool export_skinweight = true;
|
||||||
|
bool no_flip_texcoord_y = false;
|
||||||
|
|
||||||
|
auto cli =
|
||||||
|
(clipp::required("-i", "--input") &
|
||||||
|
clipp::value("input filename", input_filename),
|
||||||
|
clipp::option("-o", "--outout") &
|
||||||
|
clipp::value("Output filename(obj2fltf)", output_filename),
|
||||||
|
clipp::option("-v", "--verbose").set(verbose).doc("Verbose output"),
|
||||||
|
clipp::option("--export_skinweight") &
|
||||||
|
clipp::value("Export skin weights(gltf2obj). default true.",
|
||||||
|
export_skinweight),
|
||||||
|
clipp::option("--uvset").set(uvset).doc("UV set(TEXCOORD_N) to use"),
|
||||||
|
clipp::option("--op") &
|
||||||
|
clipp::value("operation mode(`gltf2obj`, `obj2gltf`", op),
|
||||||
|
clipp::option("--no-flip-texcoord-y")
|
||||||
|
.set(no_flip_texcoord_y)
|
||||||
|
.doc("Do not flip texcoord Y"));
|
||||||
|
|
||||||
|
if (!clipp::parse(argc, argv, cli)) {
|
||||||
|
std::cout << clipp::make_man_page(cli, argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == "gltf2obj") {
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF loader;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
std::string ext = GetFilePathExtension(input_filename);
|
||||||
|
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
if (ext.compare("glb") == 0) {
|
||||||
|
// assume binary glTF.
|
||||||
|
ret = loader.LoadBinaryFromFile(&model, &err, &warn,
|
||||||
|
input_filename.c_str());
|
||||||
|
} else {
|
||||||
|
// assume ascii glTF.
|
||||||
|
ret = loader.LoadASCIIFromFile(&model, &err, &warn,
|
||||||
|
input_filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!warn.empty()) {
|
||||||
|
printf("Warn: %s\n", warn.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
printf("ERR: %s\n", err.c_str());
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
printf("Failed to load .glTF : %s\n", argv[1]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
json j;
|
||||||
|
{
|
||||||
|
std::ifstream i(input_filename);
|
||||||
|
i >> j;
|
||||||
|
}
|
||||||
|
std::cout << "j = " << j << "\n";
|
||||||
|
|
||||||
|
json j_patch = R"([
|
||||||
|
{ "op": "add", "path": "/buffers/-", "value": {
|
||||||
|
"name": "plane/data",
|
||||||
|
"byteLength": 480,
|
||||||
|
"uri": "plane1.bin"
|
||||||
|
} }
|
||||||
|
])"_json;
|
||||||
|
|
||||||
|
// a JSON value
|
||||||
|
json j_original = R"({
|
||||||
|
"baz": ["one", "two", "three"],
|
||||||
|
"foo": "bar"
|
||||||
|
})"_json;
|
||||||
|
|
||||||
|
//json j_patch = R"([
|
||||||
|
// { "op": "remove", "path": "/buffers" }
|
||||||
|
//])"_json;
|
||||||
|
|
||||||
|
std::cout << "patch = " << j_patch.dump(2) << "\n";
|
||||||
|
|
||||||
|
json j_ret = j.patch(j_patch);
|
||||||
|
std::cout << "patched = " << j_ret.dump(2) << "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string basedir = GetBaseDir(input_filename);
|
||||||
|
std::vector<example::MeshPrim> meshes;
|
||||||
|
bool ret = ExtractMesh(basedir, model, verbose, &meshes);
|
||||||
|
|
||||||
|
size_t n = 0;
|
||||||
|
for (const auto &mesh : meshes) {
|
||||||
|
// Assume no duplicated name in .glTF data
|
||||||
|
std::string basename;
|
||||||
|
if (mesh.name.empty()) {
|
||||||
|
basename = "untitled-" + std::to_string(n);
|
||||||
|
} else {
|
||||||
|
basename = mesh.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t primid = 0; primid < mesh.prims.size(); primid++) {
|
||||||
|
example::ObjExportOption options;
|
||||||
|
options.primid = int(primid);
|
||||||
|
options.export_skinweights = export_skinweight;
|
||||||
|
options.uvset = uvset;
|
||||||
|
options.flip_texcoord_y = !no_flip_texcoord_y;
|
||||||
|
|
||||||
|
bool ok = example::SaveAsObjMesh(basename, mesh, options);
|
||||||
|
if (!ok) {
|
||||||
|
std::cout << "Failed to export mesh[" << mesh.name << "].primitives["
|
||||||
|
<< primid << "]\n";
|
||||||
|
// may ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
} else if (op == "obj2gltf") {
|
||||||
|
// Require facevarying layout?
|
||||||
|
// facevarying representation is required if a vertex can have multiple
|
||||||
|
// normal/uv value. drawback of facevarying is mesh data increases. false =
|
||||||
|
// try to keep shared vertex representation as much as possible. true =
|
||||||
|
// reorder vertex data and re-assign vertex indices for facevarying data
|
||||||
|
// layout.
|
||||||
|
bool facevarying = false;
|
||||||
|
|
||||||
|
example::MeshPrim mesh;
|
||||||
|
bool ok = example::LoadObjMesh(input_filename, facevarying, &mesh);
|
||||||
|
if (!ok) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
PrintMeshPrim(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = example::SaveAsGLTFMesh(output_filename, mesh);
|
||||||
|
if (!ok) {
|
||||||
|
std::cerr << "Failed to save mesh as glTF\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::cout << "Write glTF: " << output_filename << "\n";
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Unknown operation: " << op << "\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
1479
examples/mesh-conv/mesh-util.cc
Normal file
1479
examples/mesh-conv/mesh-util.cc
Normal file
File diff suppressed because it is too large
Load Diff
95
examples/mesh-conv/mesh-util.hh
Normal file
95
examples/mesh-conv/mesh-util.hh
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||||
|
// TODO(syoyo): Support more data type
|
||||||
|
struct VertexAttrib {
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// Value are converted to float type.
|
||||||
|
std::vector<float> data;
|
||||||
|
|
||||||
|
// Corresponding info in binary data
|
||||||
|
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||||
|
int component_type; // storage type. e.g.
|
||||||
|
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||||
|
uint64_t buffer_offset{0};
|
||||||
|
size_t buffer_length{0};
|
||||||
|
|
||||||
|
// Optional.
|
||||||
|
std::vector<double> minValues;
|
||||||
|
std::vector<double> maxValues;
|
||||||
|
|
||||||
|
size_t numElements() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PrimSet {
|
||||||
|
|
||||||
|
int mode; // e.g. TRIANGLES
|
||||||
|
|
||||||
|
VertexAttrib position; // vec3
|
||||||
|
VertexAttrib normal; // vec3
|
||||||
|
VertexAttrib tangent; // vec4
|
||||||
|
VertexAttrib color; // vec3 or vec4
|
||||||
|
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||||
|
std::map<int, VertexAttrib> weights; // <slot, attrib> vec4
|
||||||
|
std::map<int, VertexAttrib>
|
||||||
|
joints; // <slot, attrib> store data as float type
|
||||||
|
|
||||||
|
|
||||||
|
// min/max of index value. -1 = undef
|
||||||
|
int indices_min{-1};
|
||||||
|
int indices_max{-1};
|
||||||
|
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||||
|
std::vector<uint32_t> indices; // vertex indices
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshPrim {
|
||||||
|
std::string name;
|
||||||
|
int32_t id{-1};
|
||||||
|
|
||||||
|
std::vector<PrimSet> prims;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjExportOption
|
||||||
|
{
|
||||||
|
bool export_skinweights{true};
|
||||||
|
int primid{0}; /// Primitive id to export(default 0).
|
||||||
|
int uvset{0}; /// Tex coord ID to export(default 0).
|
||||||
|
bool flip_texcoord_y{true}; /// Flip texture coordinate V?(default true).
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Save MeshPrim as wavefront .obj
|
||||||
|
///
|
||||||
|
/// @param[in] basename Base filename. ".obj" will be appended.
|
||||||
|
/// @param[in] mesh MeshPrim.
|
||||||
|
/// @param[in] option Export options
|
||||||
|
///
|
||||||
|
bool SaveAsObjMesh(const std::string &basename, const MeshPrim &mesh, const ObjExportOption &option);
|
||||||
|
|
||||||
|
//
|
||||||
|
/// Save MeshPrim as glTF mesh
|
||||||
|
///
|
||||||
|
bool SaveAsGLTFMesh(const std::string &filename, const MeshPrim &mesh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Loads .obj and convert to MeshPrim
|
||||||
|
///
|
||||||
|
/// @param[in] facevarying Construct mesh with facevarying vertex layout(default false)
|
||||||
|
///
|
||||||
|
bool LoadObjMesh(const std::string &filename, bool facevarying, MeshPrim *mesh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Print MeshPrim datra
|
||||||
|
///
|
||||||
|
void PrintMeshPrim(const MeshPrim &mesh);
|
||||||
|
|
||||||
|
} // namespace example
|
||||||
7
examples/mesh-conv/meson.build
Normal file
7
examples/mesh-conv/meson.build
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
project('mesh-conv', 'cpp', default_options : ['cpp_std=c++11'])
|
||||||
|
|
||||||
|
thread_dep = dependency('threads')
|
||||||
|
|
||||||
|
incdir = include_directories(['../../', '../common'])
|
||||||
|
|
||||||
|
executable('mesh-conv', ['mesh-conv.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep)
|
||||||
27
examples/mesh-conv/sandbox/README.md
Normal file
27
examples/mesh-conv/sandbox/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# concat_mesh.py
|
||||||
|
|
||||||
|
Append(merge) mesh of glTF A to glTF B.
|
||||||
|
|
||||||
|
`meshes`, `accessors`, `bufferViews`, `materials` of glTF A is appended to glTF B(index to accessor, bufferViews, etc will be recomputed).
|
||||||
|
|
||||||
|
`skin`, `nodes`, etc are not appended(to be merged).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
concatenate sourceN.gltf to target.gltf and save it to merged.gltf
|
||||||
|
|
||||||
|
```
|
||||||
|
$ python concat_mesh.py source0.gltf <source1.gltf source2.gltf ...> target.gltf merged.gltf
|
||||||
|
```
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
* [x] Support multiple glTFs to merge(concat)
|
||||||
|
* [ ] Support merging skin
|
||||||
|
* [ ] Support merging different node hierarchies
|
||||||
|
* [x] Support `images`, `textures`, `materials`, `samplers`
|
||||||
|
* [ ] Support other glTF info
|
||||||
|
|
||||||
|
# replace_attrib.py
|
||||||
|
|
||||||
|
Replace the accessor id of specified attribute.
|
||||||
272
examples/mesh-conv/sandbox/concat_mesh.py
Normal file
272
examples/mesh-conv/sandbox/concat_mesh.py
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
# concat mesh to glTF
|
||||||
|
# support multiple source glTF to me concatenated to target.gltf
|
||||||
|
|
||||||
|
# TODO: skins, nodes, scenes
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
g_prefix = "added/"
|
||||||
|
|
||||||
|
def adjustMaterialTextureIndex(mat, texture_index_offset):
|
||||||
|
# Args: mat(dict)
|
||||||
|
# texture_index_offset(int) Index offset
|
||||||
|
|
||||||
|
if "normalTexture" in mat:
|
||||||
|
if "index" in mat["normalTexture"]:
|
||||||
|
mat["normalTexture"]["index"] += texture_index_offset
|
||||||
|
|
||||||
|
if "occlusionTexture" in mat:
|
||||||
|
if "index" in mat["occlusionTexture"]:
|
||||||
|
mat["occlusionTexture"]["index"] += texture_index_offset
|
||||||
|
|
||||||
|
if "emissiveTexture" in mat:
|
||||||
|
if "index" in mat["emissiveTexture"]:
|
||||||
|
mat["emissiveTexture"]["index"] += texture_index_offset
|
||||||
|
|
||||||
|
if "pbrMetallicRoughness" in mat:
|
||||||
|
if "baseColorTexture" in mat["pbrMetallicRoughness"]:
|
||||||
|
if "index" in mat["pbrMetallicRoughness"]["baseColorTexture"]:
|
||||||
|
mat["pbrMetallicRoughness"]["baseColorTexture"]["index"] += texture_index_offset
|
||||||
|
|
||||||
|
if "metallicRoughnessTexture" in mat["pbrMetallicRoughness"]:
|
||||||
|
if "index" in mat["pbrMetallicRoughness"]["metallicRoughnessTexture"]:
|
||||||
|
mat["pbrMetallicRoughness"]["metallicRoughnessTexture"]["index"] += texture_index_offset
|
||||||
|
|
||||||
|
return mat
|
||||||
|
|
||||||
|
|
||||||
|
def concat(source, target, offsets, prefix, extraInfo):
|
||||||
|
# Args:
|
||||||
|
# source: dict(modified), target: dict(modified),
|
||||||
|
# offsets: dict(modified). contains offset table.
|
||||||
|
# prefix: str
|
||||||
|
# extraInfo: dict(inout)
|
||||||
|
|
||||||
|
num_source_meshes = len(source["meshes"])
|
||||||
|
num_source_buffers = len(source["buffers"])
|
||||||
|
num_source_bufferViews = len(source["bufferViews"])
|
||||||
|
num_source_accessors = len(source["accessors"])
|
||||||
|
num_source_materials = len(source["materials"]) if "materials" in source else 0
|
||||||
|
num_source_samplers = len(source["samplers"]) if "samplers" in source else 0
|
||||||
|
num_source_images = len(source["images"]) if "images" in source else 0
|
||||||
|
num_source_textures = len(source["textures"]) if "textures" in source else 0
|
||||||
|
print("src =====")
|
||||||
|
print("num_src_meshes: ", num_source_meshes)
|
||||||
|
print("num_src_buffers: ", num_source_buffers)
|
||||||
|
print("num_src_bufferViews: ", num_source_bufferViews)
|
||||||
|
print("num_src_accessors: ", num_source_accessors)
|
||||||
|
print("num_src_materials: ", num_source_materials)
|
||||||
|
print("num_src_textures: ", num_source_textures)
|
||||||
|
print("num_src_images: ", num_source_images)
|
||||||
|
print("num_src_samplers: ", num_source_samplers)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Modify name and adjust index offset
|
||||||
|
#
|
||||||
|
for i in range(len(source["buffers"])):
|
||||||
|
if "name" in source["buffers"][i]:
|
||||||
|
source["buffers"][i]["name"] = prefix + source["buffers"][i]["name"]
|
||||||
|
|
||||||
|
for i in range(len(source["bufferViews"])):
|
||||||
|
if "name" in source["bufferViews"][i]:
|
||||||
|
source["bufferViews"][i]["name"] = prefix + source["bufferViews"][i]["name"]
|
||||||
|
|
||||||
|
source["bufferViews"][i]["buffer"] += offsets["buffers"]
|
||||||
|
|
||||||
|
for i in range(len(source["accessors"])):
|
||||||
|
if "name" in source["accessors"][i]:
|
||||||
|
source["accessors"][i]["name"] = prefix + source["accessors"][i]["name"]
|
||||||
|
|
||||||
|
source["accessors"][i]["bufferView"] += offsets["bufferViews"]
|
||||||
|
|
||||||
|
for i in range(len(source["meshes"])):
|
||||||
|
mesh = source["meshes"][i]
|
||||||
|
|
||||||
|
if "name" in mesh:
|
||||||
|
source["meshes"][i]["name"] = prefix + source["meshes"][i]["name"]
|
||||||
|
|
||||||
|
for primid in range(len(mesh["primitives"])):
|
||||||
|
for attrib in mesh["primitives"][primid]["attributes"]:
|
||||||
|
#print(source["meshes"][i]["primitives"][primid]["attributes"][attrib])
|
||||||
|
source["meshes"][i]["primitives"][primid]["attributes"][attrib] += offsets["accessors"]
|
||||||
|
|
||||||
|
|
||||||
|
source["meshes"][i]["primitives"][primid]["indices"] += offsets["accessors"]
|
||||||
|
if "material" in source["meshes"][i]["primitives"][primid]:
|
||||||
|
source["meshes"][i]["primitives"][primid]["material"] += offsets["materials"]
|
||||||
|
|
||||||
|
|
||||||
|
if "materials" in source:
|
||||||
|
for i in range(len(source["materials"])):
|
||||||
|
if "name" in source["materials"][i]:
|
||||||
|
source["materials"][i]["name"] = prefix + source["materials"][i]["name"]
|
||||||
|
source["materials"][i] = adjustMaterialTextureIndex(source["materials"][i], offsets["textures"])
|
||||||
|
|
||||||
|
if "images" in source:
|
||||||
|
for i in range(len(source["images"])):
|
||||||
|
if "name" in source["images"][i]:
|
||||||
|
source["images"][i]["name"] = prefix + source["images"][i]["name"]
|
||||||
|
|
||||||
|
if "samplers" in source:
|
||||||
|
for i in range(len(source["samplers"])):
|
||||||
|
if "name" in source["samplers"][i]:
|
||||||
|
source["samplers"][i]["name"] = prefix + source["samplers"][i]["name"]
|
||||||
|
|
||||||
|
if "textures" in source:
|
||||||
|
for i in range(len(source["textures"])):
|
||||||
|
if "name" in source["textures"][i]:
|
||||||
|
source["textures"][i]["name"] = prefix + source["textures"][i]["name"]
|
||||||
|
source["textures"][i]["sampler"] += offsets["samplers"]
|
||||||
|
source["textures"][i]["source"] += offsets["images"]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Append mesh info
|
||||||
|
#
|
||||||
|
target["buffers"] += source["buffers"]
|
||||||
|
target["bufferViews"] += source["bufferViews"]
|
||||||
|
target["meshes"] += source["meshes"]
|
||||||
|
target["accessors"] += source["accessors"]
|
||||||
|
if "materials" in source:
|
||||||
|
if "materials" in target:
|
||||||
|
target["materials"] += source["materials"]
|
||||||
|
else:
|
||||||
|
target["materials"] = source["materials"]
|
||||||
|
if "images" in source:
|
||||||
|
if "images" in target:
|
||||||
|
target["images"] += source["images"]
|
||||||
|
else:
|
||||||
|
target["images"] = source["images"]
|
||||||
|
if "textures" in source:
|
||||||
|
if "textures" in target:
|
||||||
|
target["textures"] += source["textures"]
|
||||||
|
else:
|
||||||
|
target["textures"] = source["textures"]
|
||||||
|
if "samplers" in source:
|
||||||
|
if "samplers" in target:
|
||||||
|
target["samplers"] += source["samplers"]
|
||||||
|
else:
|
||||||
|
target["samplers"] = source["samplers"]
|
||||||
|
|
||||||
|
# assume `prefix` is unique
|
||||||
|
extraInfo["num_{}_meshes".format(prefix)] = num_source_meshes
|
||||||
|
extraInfo["num_{}_buffers".format(prefix)] = num_source_buffers
|
||||||
|
extraInfo["num_{}_bufferViews".format(prefix)] = num_source_bufferViews
|
||||||
|
extraInfo["num_{}_accessors".format(prefix)] = num_source_accessors
|
||||||
|
extraInfo["num_{}_materials".format(prefix)] = num_source_materials
|
||||||
|
extraInfo["num_{}_images".format(prefix)] = num_source_images
|
||||||
|
extraInfo["num_{}_samplers".format(prefix)] = num_source_samplers
|
||||||
|
extraInfo["num_{}_textures".format(prefix)] = num_source_textures
|
||||||
|
|
||||||
|
# update offsets
|
||||||
|
offsets["meshes"] += num_source_meshes
|
||||||
|
offsets["buffers"] += num_source_buffers
|
||||||
|
offsets["bufferViews"] += num_source_bufferViews
|
||||||
|
offsets["accessors"] += num_source_accessors
|
||||||
|
offsets["materials"] += num_source_materials
|
||||||
|
offsets["textures"] += num_source_textures
|
||||||
|
offsets["images"] += num_source_images
|
||||||
|
offsets["samplers"] += num_source_samplers
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 4:
|
||||||
|
print("Needs source0.gltf <source1.gltf, ...> target.gltf output.gltf")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
num_args = len(sys.argv)
|
||||||
|
print("num_args = ", num_args)
|
||||||
|
|
||||||
|
source_filenames = []
|
||||||
|
|
||||||
|
num_srcs = num_args - 3
|
||||||
|
|
||||||
|
for i in range(num_srcs):
|
||||||
|
source_filenames.append(sys.argv[1+i])
|
||||||
|
print("source[{}] = {}".format(i, sys.argv[1+i]))
|
||||||
|
|
||||||
|
target_filename = sys.argv[num_args - 2]
|
||||||
|
output_filename = sys.argv[num_args - 1]
|
||||||
|
print("target = ", target_filename)
|
||||||
|
print("output = ", output_filename)
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
for i in range(num_srcs):
|
||||||
|
sources.append(json.loads(open(source_filenames[i]).read()))
|
||||||
|
target = json.loads(open(target_filename).read())
|
||||||
|
|
||||||
|
num_target_meshes = len(target["meshes"])
|
||||||
|
num_target_buffers = len(target["buffers"])
|
||||||
|
num_target_bufferViews = len(target["bufferViews"])
|
||||||
|
num_target_accessors = len(target["accessors"])
|
||||||
|
num_target_materials = 0
|
||||||
|
if "materials" in target:
|
||||||
|
num_target_materials = len(target["materials"])
|
||||||
|
|
||||||
|
num_target_images = 0
|
||||||
|
if "images" in target:
|
||||||
|
num_target_images = len(target["images"])
|
||||||
|
|
||||||
|
num_target_samplers = 0
|
||||||
|
if "samplers" in target:
|
||||||
|
num_target_samplers = len(target["samplers"])
|
||||||
|
|
||||||
|
num_target_textures = 0
|
||||||
|
if "textures" in target:
|
||||||
|
num_target_textures = len(target["textures"])
|
||||||
|
|
||||||
|
print("num_target_meshes: ", num_target_meshes)
|
||||||
|
print("num_target_buffers: ", num_target_buffers)
|
||||||
|
print("num_target_bufferViews: ", num_target_bufferViews)
|
||||||
|
print("num_target_accessors: ", num_target_accessors)
|
||||||
|
print("num_target_materials: ", num_target_materials)
|
||||||
|
print("num_target_textures: ", num_target_textures)
|
||||||
|
print("num_target_images: ", num_target_images)
|
||||||
|
print("num_target_samplers: ", num_target_samplers)
|
||||||
|
|
||||||
|
#
|
||||||
|
# add some info to asset.extras
|
||||||
|
#
|
||||||
|
extraInfo = {}
|
||||||
|
extraInfo["num_target_meshes"] = num_target_meshes
|
||||||
|
extraInfo["num_target_buffers"] = num_target_buffers
|
||||||
|
extraInfo["num_target_bufferViews"] = num_target_bufferViews
|
||||||
|
extraInfo["num_target_accessors"] = num_target_accessors
|
||||||
|
extraInfo["num_target_materials"] = num_target_materials
|
||||||
|
extraInfo["num_target_textures"] = num_target_textures
|
||||||
|
extraInfo["num_target_images"] = num_target_images
|
||||||
|
extraInfo["num_target_samplers"] = num_target_samplers
|
||||||
|
|
||||||
|
offsets = {}
|
||||||
|
offsets["meshes"] = num_target_meshes
|
||||||
|
offsets["buffers"] = num_target_buffers
|
||||||
|
offsets["bufferViews"] = num_target_bufferViews
|
||||||
|
offsets["accessors"] = num_target_accessors
|
||||||
|
offsets["materials"] = num_target_materials
|
||||||
|
offsets["textures"] = num_target_textures
|
||||||
|
offsets["samplers"] = num_target_samplers
|
||||||
|
offsets["images"] = num_target_images
|
||||||
|
|
||||||
|
for i in range(num_srcs):
|
||||||
|
source = sources[i]
|
||||||
|
|
||||||
|
prefix = g_prefix + "{}/".format(source_filenames[i])
|
||||||
|
concat(source, target, offsets, prefix, extraInfo)
|
||||||
|
|
||||||
|
extraInfo["num_total_meshes"] = offsets["meshes"]
|
||||||
|
extraInfo["num_total_buffers"] = offsets["buffers"]
|
||||||
|
extraInfo["num_total_bufferViews"] = offsets["bufferViews"]
|
||||||
|
extraInfo["num_total_accessors"] = offsets["accessors"]
|
||||||
|
extraInfo["num_total_materials"] = offsets["materials"]
|
||||||
|
extraInfo["num_total_textures"] = offsets["textures"]
|
||||||
|
extraInfo["num_total_images"] = offsets["images"]
|
||||||
|
extraInfo["num_total_samplers"] = offsets["samplers"]
|
||||||
|
|
||||||
|
target["asset"]["extras"] = extraInfo
|
||||||
|
|
||||||
|
with open(output_filename, "w") as f:
|
||||||
|
f.write(json.dumps(target, indent=2))
|
||||||
|
|
||||||
|
print("Merged glTF was exported to : ", output_filename)
|
||||||
|
main()
|
||||||
107
examples/mesh-conv/sandbox/replace_attrib.py
Normal file
107
examples/mesh-conv/sandbox/replace_attrib.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Replace accessor id of attributes for speicified mesh
|
||||||
|
# Usually called after concat_mesh.py
|
||||||
|
# Example usecase is to replace UV coordinate of a mesh.
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
replace_indices = False
|
||||||
|
attrib_names = ["TEXCOORD_0"]
|
||||||
|
|
||||||
|
def check_accessor(src, target):
|
||||||
|
if src["componentType"] != target["componentType"]:
|
||||||
|
print("componentType mismatch!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if src["count"] != target["count"]:
|
||||||
|
print("`count` mismatch!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if src["type"] != target["type"]:
|
||||||
|
print("`type` mismatch!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 5:
|
||||||
|
print("Needs input.gltf output.gltf source_mesh_name target_mesh_name <source_primid> <target_primid>")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
input_filename = sys.argv[1]
|
||||||
|
output_filename = sys.argv[2]
|
||||||
|
source_mesh_name = sys.argv[3]
|
||||||
|
target_mesh_name = sys.argv[4]
|
||||||
|
|
||||||
|
source_primid = 0
|
||||||
|
target_primid = 0
|
||||||
|
|
||||||
|
if len(sys.argv) > 5:
|
||||||
|
source_primid = int(sys.argv[5])
|
||||||
|
|
||||||
|
if len(sys.argv) > 6:
|
||||||
|
target_primid = int(sys.argv[6])
|
||||||
|
|
||||||
|
gltf = json.loads(open(input_filename).read())
|
||||||
|
|
||||||
|
source_mesh_id = -1
|
||||||
|
target_mesh_id = -1
|
||||||
|
|
||||||
|
for i in range(len(gltf["meshes"])):
|
||||||
|
mesh = gltf["meshes"][i]
|
||||||
|
print("mesh[{}].name = {}".format(i, mesh["name"]))
|
||||||
|
|
||||||
|
if target_mesh_name == mesh["name"]:
|
||||||
|
target_mesh_id = i
|
||||||
|
|
||||||
|
if source_mesh_name == mesh["name"]:
|
||||||
|
source_mesh_id = i
|
||||||
|
|
||||||
|
if source_mesh_id == -1:
|
||||||
|
print("source mesh with name [{}] not found.".format(source_mesh_name))
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if target_mesh_id == -1:
|
||||||
|
print("target mesh with name [{}] not found.".format(target_mesh_name))
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
print("target: name = {}, id = {}".format(target_mesh_name, target_mesh_id))
|
||||||
|
print("source: name = {}, id = {}".format(source_mesh_name, source_mesh_id))
|
||||||
|
|
||||||
|
source_mesh = gltf["meshes"][source_mesh_id]
|
||||||
|
target_mesh = gltf["meshes"][target_mesh_id]
|
||||||
|
|
||||||
|
|
||||||
|
source_prim = source_mesh["primitives"][source_primid]
|
||||||
|
target_prim = target_mesh["primitives"][target_primid]
|
||||||
|
|
||||||
|
if replace_indices:
|
||||||
|
target_indices_id = target_prim["indices"]
|
||||||
|
src_indices_id = source_prim["indices"]
|
||||||
|
|
||||||
|
print("Replace vertex indices from {} to {}".format(target_indices_id, src_indices_id))
|
||||||
|
gltf["meshes"][target_mesh_id]["primitives"][target_primid]["indices"] = gltf["meshes"][source_mesh_id]["primitives"][source_primid]["indices"]
|
||||||
|
|
||||||
|
|
||||||
|
for attrib in target_prim["attributes"]:
|
||||||
|
print("attrib ", attrib)
|
||||||
|
if attrib in attrib_names:
|
||||||
|
if attrib in source_prim["attributes"]:
|
||||||
|
target_accessor_id = target_prim["attributes"][attrib]
|
||||||
|
src_accessor_id = source_prim["attributes"][attrib]
|
||||||
|
|
||||||
|
if check_accessor(gltf["accessors"][src_accessor_id], gltf["accessors"][target_accessor_id]):
|
||||||
|
gltf["meshes"][target_mesh_id]["primitives"][target_primid]["attributes"][attrib] = src_accessor_id
|
||||||
|
print("Replaced accessor id for attrib {} from {} to {}".format(attrib, target_accessor_id, src_accessor_id))
|
||||||
|
else:
|
||||||
|
print("Accessor type/format is not identical. Skip replace")
|
||||||
|
print(" attrib {}".format(attrib))
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("attribute[{}] not found in source primitive: mesh[{}].primitives[{}]".format(attrib, source_mesh_name, source_primid))
|
||||||
|
|
||||||
|
with open(output_filename, "w") as f:
|
||||||
|
f.write(json.dumps(gltf, indent=2))
|
||||||
|
|
||||||
|
print("Merged glTF was exported to : ", output_filename)
|
||||||
|
main()
|
||||||
9
examples/mesh-conv/tinygltf_impl.cc
Normal file
9
examples/mesh-conv/tinygltf_impl.cc
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "../../tiny_gltf.h"
|
||||||
|
#else
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
#endif
|
||||||
@@ -150,6 +150,7 @@ bool LoadObj(const std::string &filename, float scale,
|
|||||||
tinyobj::attrib_t attrib;
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
std::vector<tinyobj::material_t> materials;
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
std::string warn;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
std::string basedir = GetBaseDir(filename) + "/";
|
std::string basedir = GetBaseDir(filename) + "/";
|
||||||
@@ -158,12 +159,16 @@ bool LoadObj(const std::string &filename, float scale,
|
|||||||
// auto t_start = std::chrono::system_clock::now();
|
// auto t_start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
bool ret =
|
bool ret =
|
||||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str(),
|
||||||
basepath, /* triangulate */ true);
|
basepath, /* triangulate */ true);
|
||||||
|
|
||||||
// auto t_end = std::chrono::system_clock::now();
|
// auto t_end = std::chrono::system_clock::now();
|
||||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||||
|
|
||||||
|
if (!warn.empty()) {
|
||||||
|
std::cout << warn << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -1,376 +0,0 @@
|
|||||||
{
|
|
||||||
"accessors": [
|
|
||||||
{
|
|
||||||
"bufferView": 0,
|
|
||||||
"componentType": 5126,
|
|
||||||
"count": 8,
|
|
||||||
"max": [
|
|
||||||
0.5,
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"min": [
|
|
||||||
-0.5,
|
|
||||||
-0.5,
|
|
||||||
-0.5
|
|
||||||
],
|
|
||||||
"type": "VEC3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bufferView": 1,
|
|
||||||
"componentType": 5125,
|
|
||||||
"count": 36,
|
|
||||||
"type": "SCALAR"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"asset": {
|
|
||||||
"copyright": "NVIDIA Corporation",
|
|
||||||
"generator": "Iray glTF plugin",
|
|
||||||
"version": "2.0"
|
|
||||||
},
|
|
||||||
"bufferViews": [
|
|
||||||
{
|
|
||||||
"buffer": 0,
|
|
||||||
"byteLength": 96,
|
|
||||||
"byteStride": 12
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"buffer": 0,
|
|
||||||
"byteLength": 144,
|
|
||||||
"byteOffset": 96
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buffers": [
|
|
||||||
{
|
|
||||||
"byteLength": 240,
|
|
||||||
"uri": "issue-261.bin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cameras": [
|
|
||||||
{
|
|
||||||
"extensions": {
|
|
||||||
"NV_Iray": {
|
|
||||||
"mip_burn_highlights": 0.699999988079071,
|
|
||||||
"mip_burn_highlights_per_component": false,
|
|
||||||
"mip_camera_shutter": 4.0,
|
|
||||||
"mip_cm2_factor": 1.0,
|
|
||||||
"mip_crush_blacks": 0.5,
|
|
||||||
"mip_f_number": 1.0,
|
|
||||||
"mip_film_iso": 100.0,
|
|
||||||
"mip_gamma": 2.200000047683716,
|
|
||||||
"mip_saturation": 1.0,
|
|
||||||
"mip_vignetting": 0.00019999999494757503,
|
|
||||||
"mip_whitepoint": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"tm_enable_tonemapper": true,
|
|
||||||
"tm_tonemapper": "mia_exposure_photographic"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extras": {
|
|
||||||
"resolution": [
|
|
||||||
640,
|
|
||||||
480
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"name": "default",
|
|
||||||
"perspective": {
|
|
||||||
"aspectRatio": 1.3333333730697632,
|
|
||||||
"yfov": 0.9272952079772949,
|
|
||||||
"zfar": 1000.0,
|
|
||||||
"znear": 0.1
|
|
||||||
},
|
|
||||||
"type": "perspective"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"extensions": {
|
|
||||||
"KHR_lights_punctual": {
|
|
||||||
"lights": [
|
|
||||||
{
|
|
||||||
"color": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"intensity": 1000.0,
|
|
||||||
"name": "light",
|
|
||||||
"type": "point"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"NV_MDL": {
|
|
||||||
"modules": [
|
|
||||||
"mdl::base",
|
|
||||||
"mdl::nvidia::core_definitions",
|
|
||||||
"mdl::state"
|
|
||||||
],
|
|
||||||
"shaders": [
|
|
||||||
{
|
|
||||||
"definition": "mdl::base::environment_spherical(texture_2d)",
|
|
||||||
"name": "env_shd"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": {
|
|
||||||
"base_color": [
|
|
||||||
0.0055217444896698,
|
|
||||||
0.36859095096588135,
|
|
||||||
0.0041161770932376385
|
|
||||||
],
|
|
||||||
"normal=": 2
|
|
||||||
},
|
|
||||||
"definition": "mdl::nvidia::core_definitions::flex_material",
|
|
||||||
"name": "cube_instance_material"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"definition": "mdl::state::normal()",
|
|
||||||
"name": "mdl::state::normal_341"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": {
|
|
||||||
"base_color": [
|
|
||||||
0.0055217444896698,
|
|
||||||
0.36859095096588135,
|
|
||||||
0.0041161770932376385
|
|
||||||
],
|
|
||||||
"normal=": 4
|
|
||||||
},
|
|
||||||
"definition": "mdl::nvidia::core_definitions::flex_material",
|
|
||||||
"name": "cube_instance_material"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"definition": "mdl::state::normal()",
|
|
||||||
"name": "mdl::state::normal_341"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extensionsUsed": [
|
|
||||||
"NV_MDL",
|
|
||||||
"NV_Iray",
|
|
||||||
"KHR_lights_punctual"
|
|
||||||
],
|
|
||||||
"materials": [
|
|
||||||
{
|
|
||||||
"doubleSided": true,
|
|
||||||
"extras": {
|
|
||||||
"mdl_shader": 1
|
|
||||||
},
|
|
||||||
"name": "cube_instance_material",
|
|
||||||
"pbrMetallicRoughness": {
|
|
||||||
"baseColorFactor": [
|
|
||||||
0.0055217444896698,
|
|
||||||
0.36859095096588135,
|
|
||||||
0.0041161770932376385,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meshes": [
|
|
||||||
{
|
|
||||||
"name": "cube",
|
|
||||||
"primitives": [
|
|
||||||
{
|
|
||||||
"attributes": {
|
|
||||||
"POSITION": 0
|
|
||||||
},
|
|
||||||
"indices": 1,
|
|
||||||
"material": 0,
|
|
||||||
"mode": 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"camera": 0,
|
|
||||||
"extensions": {
|
|
||||||
"NV_Iray": {
|
|
||||||
"iview:fkey": -1,
|
|
||||||
"iview:fov": 53.130104064941406,
|
|
||||||
"iview:interest": [
|
|
||||||
0.1342654824256897,
|
|
||||||
-0.14356137812137604,
|
|
||||||
0.037264324724674225
|
|
||||||
],
|
|
||||||
"iview:position": [
|
|
||||||
0.9729073643684387,
|
|
||||||
1.2592438459396362,
|
|
||||||
2.4199187755584717
|
|
||||||
],
|
|
||||||
"iview:roll": 0.0,
|
|
||||||
"iview:up": [
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"matrix": [
|
|
||||||
0.9432751389105357,
|
|
||||||
-1.1769874756875739e-16,
|
|
||||||
-0.3320120665176343,
|
|
||||||
0.0,
|
|
||||||
-0.16119596696756341,
|
|
||||||
0.8742297945345237,
|
|
||||||
-0.45797175303889276,
|
|
||||||
0.0,
|
|
||||||
0.290254840694694,
|
|
||||||
0.48551237507207207,
|
|
||||||
0.8246392308792816,
|
|
||||||
0.0,
|
|
||||||
0.9729073377709113,
|
|
||||||
1.2592438262175363,
|
|
||||||
2.419918748461627,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"name": "CamInst"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extensions": {
|
|
||||||
"NV_Iray": {
|
|
||||||
"caustic": true,
|
|
||||||
"caustic_cast": true,
|
|
||||||
"caustic_recv": true,
|
|
||||||
"face_back": true,
|
|
||||||
"face_front": true,
|
|
||||||
"finalgather": true,
|
|
||||||
"finalgather_cast": true,
|
|
||||||
"finalgather_recv": true,
|
|
||||||
"globillum": true,
|
|
||||||
"globillum_cast": true,
|
|
||||||
"globillum_recv": true,
|
|
||||||
"material=": 3,
|
|
||||||
"pickable": true,
|
|
||||||
"reflection_cast": true,
|
|
||||||
"reflection_recv": true,
|
|
||||||
"refraction_cast": true,
|
|
||||||
"refraction_recv": true,
|
|
||||||
"shadow_cast": true,
|
|
||||||
"shadow_recv": true,
|
|
||||||
"transparency_cast": true,
|
|
||||||
"transparency_recv": true,
|
|
||||||
"visible": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mesh": 0,
|
|
||||||
"name": "cube_instance"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extensions": {
|
|
||||||
"KHR_lights_punctual": {
|
|
||||||
"light": 0
|
|
||||||
},
|
|
||||||
"NV_Iray": {
|
|
||||||
"shadow_cast": true,
|
|
||||||
"visible": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"matrix": [
|
|
||||||
0.6988062355563571,
|
|
||||||
-7.76042172309776e-17,
|
|
||||||
-0.7153110128800992,
|
|
||||||
-0.0,
|
|
||||||
-0.4276881690736487,
|
|
||||||
0.8015668284138362,
|
|
||||||
-0.41781987700564616,
|
|
||||||
-0.0,
|
|
||||||
0.57336957992379,
|
|
||||||
0.5979051928078428,
|
|
||||||
0.5601398979107212,
|
|
||||||
0.0,
|
|
||||||
2.3640632834071384,
|
|
||||||
2.465226204472449,
|
|
||||||
2.309515908392224,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"name": "light_inst"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"scene": 0,
|
|
||||||
"scenes": [
|
|
||||||
{
|
|
||||||
"extensions": {
|
|
||||||
"NV_Iray": {
|
|
||||||
"CP_canny_threshold1": 40,
|
|
||||||
"CP_canny_threshold2": 120,
|
|
||||||
"CP_color_quantization": 8,
|
|
||||||
"IVP_color": [
|
|
||||||
1.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"TM_drago_bias": 0.8500000238418579,
|
|
||||||
"TM_drago_gamma2": 2.200000047683716,
|
|
||||||
"TM_drago_saturation": 1.0,
|
|
||||||
"TM_durand_contrast": 4.0,
|
|
||||||
"TM_durand_gamma": 2.200000047683716,
|
|
||||||
"TM_durand_saturation": 1.0,
|
|
||||||
"TM_durand_sigma_color": 2.0,
|
|
||||||
"TM_durand_sigma_space": 2.0,
|
|
||||||
"TM_linear_gamma": 2.200000047683716,
|
|
||||||
"TM_reinhard_color_adapt": 0.8999999761581421,
|
|
||||||
"TM_reinhard_gamma": 1.0,
|
|
||||||
"TM_reinhard_intensity": 0.0,
|
|
||||||
"TM_reinhard_light_adapt": 1.0,
|
|
||||||
"TM_reye_Ywhite": 1000000.0,
|
|
||||||
"TM_reye_bsize": 2,
|
|
||||||
"TM_reye_bthres": 3.0,
|
|
||||||
"TM_reye_gamma": 2.200000047683716,
|
|
||||||
"TM_reye_key": 0.5,
|
|
||||||
"TM_reye_saturation": 1.0,
|
|
||||||
"TM_reye_whitebalance": [
|
|
||||||
1.0,
|
|
||||||
0.9965101480484009,
|
|
||||||
0.9805564880371094,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"environment_dome_depth": 200.0,
|
|
||||||
"environment_dome_height": 200.0,
|
|
||||||
"environment_dome_mode": "infinite",
|
|
||||||
"environment_dome_position": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"environment_dome_radius": 100.0,
|
|
||||||
"environment_dome_rotation_angle": 0.0,
|
|
||||||
"environment_dome_width": 200.0,
|
|
||||||
"environment_function=": 0,
|
|
||||||
"environment_function_intensity": 1.9900000095367432,
|
|
||||||
"iray_instancing": "off",
|
|
||||||
"iview::inline_color": [
|
|
||||||
1.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"iview::inline_width": 1.0,
|
|
||||||
"iview::magnifier_size": 300,
|
|
||||||
"iview::offset": 10.0,
|
|
||||||
"iview::outline_color": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
],
|
|
||||||
"iview::outline_width": 2.0,
|
|
||||||
"iview::overview": true,
|
|
||||||
"iview::zoom_factor": 1.0,
|
|
||||||
"samples": 4.0,
|
|
||||||
"shadow_cast": true,
|
|
||||||
"shadow_recv": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nodes": [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -3,9 +3,6 @@
|
|||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
// Nlohmann json(include ../json.hpp)
|
|
||||||
#include "json.hpp"
|
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
@@ -96,59 +93,6 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("extension-overwrite", "[issue-261]") {
|
|
||||||
|
|
||||||
tinygltf::Model model;
|
|
||||||
tinygltf::TinyGLTF ctx;
|
|
||||||
std::string err;
|
|
||||||
std::string warn;
|
|
||||||
|
|
||||||
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Extensions-overwrite-issue261/issue-261.gltf");
|
|
||||||
if (!err.empty()) {
|
|
||||||
std::cerr << err << std::endl;
|
|
||||||
}
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
|
|
||||||
REQUIRE(model.extensionsUsed.size() == 3);
|
|
||||||
{
|
|
||||||
bool has_ext_lights = false;
|
|
||||||
has_ext_lights |= (model.extensionsUsed[0].compare("KHR_lights_punctual") == 0);
|
|
||||||
has_ext_lights |= (model.extensionsUsed[1].compare("KHR_lights_punctual") == 0);
|
|
||||||
has_ext_lights |= (model.extensionsUsed[2].compare("KHR_lights_punctual") == 0);
|
|
||||||
|
|
||||||
REQUIRE(true == has_ext_lights);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
REQUIRE(model.extensions.size() == 2);
|
|
||||||
REQUIRE(model.extensions.count("NV_MDL"));
|
|
||||||
REQUIRE(model.extensions.count("KHR_lights_punctual"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(syoyo): create temp directory.
|
|
||||||
{
|
|
||||||
ret = ctx.WriteGltfSceneToFile(&model, "issue-261.gltf", true, true);
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
|
|
||||||
tinygltf::Model m;
|
|
||||||
|
|
||||||
// read back serialized glTF
|
|
||||||
bool ret = ctx.LoadASCIIFromFile(&m, &err, &warn, "issue-261.gltf");
|
|
||||||
if (!err.empty()) {
|
|
||||||
std::cerr << err << std::endl;
|
|
||||||
}
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
|
|
||||||
REQUIRE(m.extensionsUsed.size() == 3);
|
|
||||||
|
|
||||||
REQUIRE(m.extensions.size() == 2);
|
|
||||||
REQUIRE(m.extensions.count("NV_MDL"));
|
|
||||||
REQUIRE(m.extensions.count("KHR_lights_punctual"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
|
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
|
||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
tinygltf::TinyGLTF ctx;
|
tinygltf::TinyGLTF ctx;
|
||||||
@@ -415,40 +359,3 @@ TEST_CASE("image-uri-spaces", "[issue-236]") {
|
|||||||
REQUIRE(true == ret);
|
REQUIRE(true == ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("serialize-empty-material", "[issue-294]") {
|
|
||||||
|
|
||||||
tinygltf::Model m;
|
|
||||||
|
|
||||||
tinygltf::Material mat;
|
|
||||||
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 1.0f, 1.0f, 1.0f}; // default baseColorFactor
|
|
||||||
m.materials.push_back(mat);
|
|
||||||
|
|
||||||
std::stringstream os;
|
|
||||||
|
|
||||||
tinygltf::TinyGLTF ctx;
|
|
||||||
ctx.WriteGltfSceneToStream(&m, os, false, false);
|
|
||||||
|
|
||||||
// use nlohmann json
|
|
||||||
nlohmann::json j = nlohmann::json::parse(os.str());
|
|
||||||
|
|
||||||
REQUIRE(1 == j["materials"].size());
|
|
||||||
REQUIRE(j["materials"][0].is_object());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_FS
|
|
||||||
TEST_CASE("expandpath-utf-8", "[pr-226]") {
|
|
||||||
|
|
||||||
std::string s1 = "\xe5\xaf\xb9"; // utf-8 string
|
|
||||||
|
|
||||||
std::string ret = tinygltf::ExpandFilePath(s1, /* userdata */nullptr);
|
|
||||||
|
|
||||||
// expected: E5 AF B9
|
|
||||||
REQUIRE(3 == ret.size());
|
|
||||||
|
|
||||||
REQUIRE(0xe5 == static_cast<uint8_t>(ret[0]));
|
|
||||||
REQUIRE(0xaf == static_cast<uint8_t>(ret[1]));
|
|
||||||
REQUIRE(0xb9 == static_cast<uint8_t>(ret[2]));
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
360
tiny_gltf.h
360
tiny_gltf.h
@@ -4,7 +4,7 @@
|
|||||||
//
|
//
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many
|
// Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many
|
||||||
// contributors.
|
// contributors.
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -26,9 +26,6 @@
|
|||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
// Version:
|
// Version:
|
||||||
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
|
||||||
// - v2.4.3 Fix null object output when when material has all default
|
|
||||||
// parameters.
|
|
||||||
// - v2.4.2 Decode percent-encoded URI.
|
// - v2.4.2 Decode percent-encoded URI.
|
||||||
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
||||||
// `extras` property.
|
// `extras` property.
|
||||||
@@ -55,7 +52,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath> // std::fabs
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -298,7 +294,7 @@ class Value {
|
|||||||
|
|
||||||
DEFAULT_METHODS(Value)
|
DEFAULT_METHODS(Value)
|
||||||
|
|
||||||
char Type() const { return static_cast<char>(type_); }
|
char Type() const { return static_cast<const char>(type_); }
|
||||||
|
|
||||||
bool IsBool() const { return (type_ == BOOL_TYPE); }
|
bool IsBool() const { return (type_ == BOOL_TYPE); }
|
||||||
|
|
||||||
@@ -326,8 +322,7 @@ class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use this function if you want to have number value as int.
|
// Use this function if you want to have number value as int.
|
||||||
// TODO(syoyo): Support int value larger than 32 bits
|
double GetNumberAsInt() const {
|
||||||
int GetNumberAsInt() const {
|
|
||||||
if (type_ == REAL_TYPE) {
|
if (type_ == REAL_TYPE) {
|
||||||
return int(real_value_);
|
return int(real_value_);
|
||||||
} else {
|
} else {
|
||||||
@@ -614,7 +609,7 @@ struct Sampler {
|
|||||||
int wrapT =
|
int wrapT =
|
||||||
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
|
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
|
||||||
// "REPEAT"], default "REPEAT"
|
// "REPEAT"], default "REPEAT"
|
||||||
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently not used.
|
int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension
|
||||||
|
|
||||||
Value extras;
|
Value extras;
|
||||||
ExtensionMap extensions;
|
ExtensionMap extensions;
|
||||||
@@ -627,7 +622,8 @@ struct Sampler {
|
|||||||
: minFilter(-1),
|
: minFilter(-1),
|
||||||
magFilter(-1),
|
magFilter(-1),
|
||||||
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||||
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
|
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
|
||||||
|
wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
|
||||||
DEFAULT_METHODS(Sampler)
|
DEFAULT_METHODS(Sampler)
|
||||||
bool operator==(const Sampler &) const;
|
bool operator==(const Sampler &) const;
|
||||||
};
|
};
|
||||||
@@ -666,8 +662,6 @@ struct Image {
|
|||||||
width = -1;
|
width = -1;
|
||||||
height = -1;
|
height = -1;
|
||||||
component = -1;
|
component = -1;
|
||||||
bits = -1;
|
|
||||||
pixel_type = -1;
|
|
||||||
}
|
}
|
||||||
DEFAULT_METHODS(Image)
|
DEFAULT_METHODS(Image)
|
||||||
|
|
||||||
@@ -850,10 +844,8 @@ struct Accessor {
|
|||||||
std::string extras_json_string;
|
std::string extras_json_string;
|
||||||
std::string extensions_json_string;
|
std::string extensions_json_string;
|
||||||
|
|
||||||
std::vector<double>
|
std::vector<double> minValues; // optional
|
||||||
minValues; // optional. integer value is promoted to double
|
std::vector<double> maxValues; // optional
|
||||||
std::vector<double>
|
|
||||||
maxValues; // optional. integer value is promoted to double
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int count;
|
int count;
|
||||||
@@ -1002,7 +994,6 @@ struct Primitive {
|
|||||||
Primitive() {
|
Primitive() {
|
||||||
material = -1;
|
material = -1;
|
||||||
indices = -1;
|
indices = -1;
|
||||||
mode = -1;
|
|
||||||
}
|
}
|
||||||
DEFAULT_METHODS(Primitive)
|
DEFAULT_METHODS(Primitive)
|
||||||
bool operator==(const Primitive &) const;
|
bool operator==(const Primitive &) const;
|
||||||
@@ -1071,7 +1062,7 @@ struct Buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Asset {
|
struct Asset {
|
||||||
std::string version = "2.0"; // required
|
std::string version; // required
|
||||||
std::string generator;
|
std::string generator;
|
||||||
std::string minVersion;
|
std::string minVersion;
|
||||||
std::string copyright;
|
std::string copyright;
|
||||||
@@ -1122,9 +1113,9 @@ struct SpotLight {
|
|||||||
struct Light {
|
struct Light {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<double> color;
|
std::vector<double> color;
|
||||||
double intensity{1.0};
|
double intensity;
|
||||||
std::string type;
|
std::string type;
|
||||||
double range{0.0}; // 0.0 = inifinite
|
double range;
|
||||||
SpotLight spot;
|
SpotLight spot;
|
||||||
|
|
||||||
Light() : intensity(1.0), range(0.0) {}
|
Light() : intensity(1.0), range(0.0) {}
|
||||||
@@ -1193,8 +1184,7 @@ enum SectionCheck {
|
|||||||
///
|
///
|
||||||
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
|
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
|
||||||
std::string *, int, int,
|
std::string *, int, int,
|
||||||
const unsigned char *, int,
|
const unsigned char *, int, void *);
|
||||||
void *user_pointer);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
|
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
|
||||||
@@ -1257,14 +1247,7 @@ struct FsCallbacks {
|
|||||||
|
|
||||||
bool FileExists(const std::string &abs_filename, void *);
|
bool FileExists(const std::string &abs_filename, void *);
|
||||||
|
|
||||||
///
|
std::string ExpandFilePath(const std::string &filepath, void *);
|
||||||
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to
|
|
||||||
/// `C:\\Users\\tinygltf\\AppData`)
|
|
||||||
///
|
|
||||||
/// @param[in] filepath File path string. Assume UTF-8
|
|
||||||
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
|
|
||||||
///
|
|
||||||
std::string ExpandFilePath(const std::string &filepath, void *userdata);
|
|
||||||
|
|
||||||
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
const std::string &filepath, void *);
|
const std::string &filepath, void *);
|
||||||
@@ -1350,11 +1333,6 @@ class TinyGLTF {
|
|||||||
///
|
///
|
||||||
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
|
||||||
|
|
||||||
///
|
|
||||||
/// Unset(remove) callback of loading image data
|
|
||||||
///
|
|
||||||
void RemoveImageLoader();
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set callback to use for writing image data
|
/// Set callback to use for writing image data
|
||||||
///
|
///
|
||||||
@@ -1393,16 +1371,6 @@ class TinyGLTF {
|
|||||||
return store_original_json_for_extras_and_extensions_;
|
return store_original_json_for_extras_and_extensions_;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
/// Specify whether preserve image channales when loading images or not.
|
|
||||||
/// (Not effective when the user suppy their own LoadImageData callbacks)
|
|
||||||
///
|
|
||||||
void SetPreserveImageChannels(bool onoff) {
|
|
||||||
preserve_image_channels_ = onoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetPreserveImageChannels() const { return preserve_image_channels_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
/// Loads glTF asset from string(memory).
|
/// Loads glTF asset from string(memory).
|
||||||
@@ -1422,9 +1390,6 @@ class TinyGLTF {
|
|||||||
|
|
||||||
bool store_original_json_for_extras_and_extensions_ = false;
|
bool store_original_json_for_extras_and_extensions_ = false;
|
||||||
|
|
||||||
bool preserve_image_channels_ = false; /// Default false(expand channels to
|
|
||||||
/// RGBA) for backward compatibility.
|
|
||||||
|
|
||||||
FsCallbacks fs = {
|
FsCallbacks fs = {
|
||||||
#ifndef TINYGLTF_NO_FS
|
#ifndef TINYGLTF_NO_FS
|
||||||
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
|
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
|
||||||
@@ -1444,8 +1409,7 @@ class TinyGLTF {
|
|||||||
#else
|
#else
|
||||||
nullptr;
|
nullptr;
|
||||||
#endif
|
#endif
|
||||||
void *load_image_user_data_{nullptr};
|
void *load_image_user_data_ = reinterpret_cast<void *>(&fs);
|
||||||
bool user_image_loader_{false};
|
|
||||||
|
|
||||||
WriteImageDataFunction WriteImageData =
|
WriteImageDataFunction WriteImageData =
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
@@ -1453,7 +1417,7 @@ class TinyGLTF {
|
|||||||
#else
|
#else
|
||||||
nullptr;
|
nullptr;
|
||||||
#endif
|
#endif
|
||||||
void *write_image_user_data_{nullptr};
|
void *write_image_user_data_ = reinterpret_cast<void *>(&fs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@@ -1707,19 +1671,6 @@ void JsonParse(JsonDocument &doc, const char *str, size_t length,
|
|||||||
|
|
||||||
namespace tinygltf {
|
namespace tinygltf {
|
||||||
|
|
||||||
///
|
|
||||||
/// Internal LoadImageDataOption struct.
|
|
||||||
/// This struct is passed through `user_pointer` in LoadImageData.
|
|
||||||
/// The struct is not passed when the user supply their own LoadImageData
|
|
||||||
/// callbacks.
|
|
||||||
///
|
|
||||||
struct LoadImageDataOption {
|
|
||||||
// true: preserve image channels(e.g. load as RGB image if the image has RGB
|
|
||||||
// channels) default `false`(channels are expanded to RGBA for backward
|
|
||||||
// compatiblity).
|
|
||||||
bool preserve_channels{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Equals function for Value, for recursivity
|
// Equals function for Value, for recursivity
|
||||||
static bool Equals(const tinygltf::Value &one, const tinygltf::Value &other) {
|
static bool Equals(const tinygltf::Value &one, const tinygltf::Value &other) {
|
||||||
if (one.Type() != other.Type()) return false;
|
if (one.Type() != other.Type()) return false;
|
||||||
@@ -1932,9 +1883,8 @@ bool Sampler::operator==(const Sampler &other) const {
|
|||||||
return this->extensions == other.extensions && this->extras == other.extras &&
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
||||||
this->magFilter == other.magFilter &&
|
this->magFilter == other.magFilter &&
|
||||||
this->minFilter == other.minFilter && this->name == other.name &&
|
this->minFilter == other.minFilter && this->name == other.name &&
|
||||||
|
this->wrapR == other.wrapR && this->wrapS == other.wrapS &&
|
||||||
this->wrapT == other.wrapT;
|
this->wrapT == other.wrapT;
|
||||||
|
|
||||||
//this->wrapR == other.wrapR && this->wrapS == other.wrapS &&
|
|
||||||
}
|
}
|
||||||
bool Scene::operator==(const Scene &other) const {
|
bool Scene::operator==(const Scene &other) const {
|
||||||
return this->extensions == other.extensions && this->extras == other.extras &&
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
||||||
@@ -2335,40 +2285,22 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
|
void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
|
||||||
LoadImageData = func;
|
LoadImageData = func;
|
||||||
load_image_user_data_ = user_data;
|
load_image_user_data_ = user_data;
|
||||||
user_image_loader_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TinyGLTF::RemoveImageLoader() {
|
|
||||||
LoadImageData =
|
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
|
||||||
&tinygltf::LoadImageData;
|
|
||||||
#else
|
|
||||||
nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
load_image_user_data_ = nullptr;
|
|
||||||
user_image_loader_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_STB_IMAGE
|
#ifndef TINYGLTF_NO_STB_IMAGE
|
||||||
bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
||||||
std::string *warn, int req_width, int req_height,
|
std::string *warn, int req_width, int req_height,
|
||||||
const unsigned char *bytes, int size, void *user_data) {
|
const unsigned char *bytes, int size, void *user_data) {
|
||||||
|
(void)user_data;
|
||||||
(void)warn;
|
(void)warn;
|
||||||
|
|
||||||
LoadImageDataOption option;
|
|
||||||
if (user_data) {
|
|
||||||
option = *reinterpret_cast<LoadImageDataOption *>(user_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int w = 0, h = 0, comp = 0, req_comp = 0;
|
int w = 0, h = 0, comp = 0, req_comp = 0;
|
||||||
|
|
||||||
unsigned char *data = nullptr;
|
unsigned char *data = nullptr;
|
||||||
|
|
||||||
// preserve_channels true: Use channels stored in the image file.
|
// force 32-bit textures for common Vulkan compatibility. It appears that
|
||||||
// false: force 32-bit textures for common Vulkan compatibility. It appears
|
// some GPU drivers do not support 24-bit images for Vulkan
|
||||||
// that some GPU drivers do not support 24-bit images for Vulkan
|
req_comp = 4;
|
||||||
req_comp = option.preserve_channels ? 0 : 4;
|
|
||||||
int bits = 8;
|
int bits = 8;
|
||||||
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
||||||
|
|
||||||
@@ -2440,18 +2372,13 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req_comp != 0) {
|
|
||||||
// loaded data has `req_comp` channels(components)
|
|
||||||
comp = req_comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
image->width = w;
|
image->width = w;
|
||||||
image->height = h;
|
image->height = h;
|
||||||
image->component = comp;
|
image->component = req_comp;
|
||||||
image->bits = bits;
|
image->bits = bits;
|
||||||
image->pixel_type = pixel_type;
|
image->pixel_type = pixel_type;
|
||||||
image->image.resize(static_cast<size_t>(w * h * comp) * size_t(bits / 8));
|
image->image.resize(static_cast<size_t>(w * h * req_comp) * size_t(bits / 8));
|
||||||
std::copy(data, data + w * h * comp * (bits / 8), image->image.begin());
|
std::copy(data, data + w * h * req_comp * (bits / 8), image->image.begin());
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2554,15 +2481,6 @@ static inline std::wstring UTF8ToWchar(const std::string &str) {
|
|||||||
(int)wstr.size());
|
(int)wstr.size());
|
||||||
return wstr;
|
return wstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::string WcharToUTF8(const std::wstring &wstr) {
|
|
||||||
int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(),
|
|
||||||
nullptr, 0, NULL, NULL);
|
|
||||||
std::string str(str_size, 0);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
|
|
||||||
(int)str.size(), NULL, NULL);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_FS
|
#ifndef TINYGLTF_NO_FS
|
||||||
@@ -2614,16 +2532,15 @@ bool FileExists(const std::string &abs_filename, void *) {
|
|||||||
|
|
||||||
std::string ExpandFilePath(const std::string &filepath, void *) {
|
std::string ExpandFilePath(const std::string &filepath, void *) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Assume input `filepath` is encoded in UTF-8
|
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||||
std::wstring wfilepath = UTF8ToWchar(filepath);
|
char *str = new char[len];
|
||||||
DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0);
|
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||||
wchar_t *wstr = new wchar_t[wlen];
|
|
||||||
ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen);
|
|
||||||
|
|
||||||
std::wstring ws(wstr);
|
std::string s(str);
|
||||||
delete[] wstr;
|
|
||||||
return WcharToUTF8(ws);
|
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
return s;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
@@ -2675,12 +2592,11 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t size = AAsset_getLength(asset);
|
size_t size = AAsset_getLength(asset);
|
||||||
if (size == 0) {
|
if (size <= 0) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Invalid file size : " + filepath +
|
(*err) += "Invalid file size : " + filepath +
|
||||||
" (does the path point to a directory?)";
|
" (does the path point to a directory?)";
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
out->resize(size);
|
out->resize(size);
|
||||||
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
||||||
@@ -2699,12 +2615,9 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
std::istream f(&wfile_buf);
|
std::istream f(&wfile_buf);
|
||||||
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
|
#elif defined(_MSC_VER)
|
||||||
// For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
|
|
||||||
// `wchar_t *`
|
|
||||||
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
||||||
#else
|
#else // clang?
|
||||||
// Unknown compiler/runtime
|
|
||||||
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
@@ -2746,10 +2659,9 @@ bool WriteWholeFile(std::string *err, const std::string &filepath,
|
|||||||
const std::vector<unsigned char> &contents, void *) {
|
const std::vector<unsigned char> &contents, void *) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if defined(__GLIBCXX__) // mingw
|
#if defined(__GLIBCXX__) // mingw
|
||||||
int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
|
int file_descriptor =
|
||||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
_wopen(UTF8ToWchar(filepath).c_str(), _O_WRONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
|
||||||
std::ostream f(&wfile_buf);
|
std::ostream f(&wfile_buf);
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
||||||
@@ -2800,13 +2712,12 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|||||||
void *user_data = nullptr) {
|
void *user_data = nullptr) {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string ext;
|
std::string ext;
|
||||||
// If image has uri, use it it as a filename
|
|
||||||
|
// If image have uri. Use it it as a filename
|
||||||
if (image.uri.size()) {
|
if (image.uri.size()) {
|
||||||
filename = GetBaseFilename(image.uri);
|
filename = GetBaseFilename(image.uri);
|
||||||
ext = GetFilePathExtension(filename);
|
ext = GetFilePathExtension(filename);
|
||||||
} else if (image.bufferView != -1) {
|
|
||||||
// If there's no URI and the data exists in a buffer,
|
|
||||||
// don't change properties or write images
|
|
||||||
} else if (image.name.size()) {
|
} else if (image.name.size()) {
|
||||||
ext = MimeToExt(image.mimeType);
|
ext = MimeToExt(image.mimeType);
|
||||||
// Otherwise use name as filename
|
// Otherwise use name as filename
|
||||||
@@ -2818,7 +2729,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If callback is set, modify image data object
|
// If callback is set, modify image data object
|
||||||
if (*WriteImageData != nullptr && !filename.empty()) {
|
if (*WriteImageData != nullptr) {
|
||||||
std::string uri;
|
std::string uri;
|
||||||
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
||||||
}
|
}
|
||||||
@@ -3063,9 +2974,7 @@ json_const_iterator ObjectEnd(const json &o) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Making this a const char* results in a pointer to a temporary when
|
const char *GetKey(json_const_iterator &it) {
|
||||||
// TINYGLTF_USE_RAPIDJSON is off.
|
|
||||||
std::string GetKey(json_const_iterator &it) {
|
|
||||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||||
return it->name.GetString();
|
return it->name.GetString();
|
||||||
#else
|
#else
|
||||||
@@ -4951,13 +4860,13 @@ static bool ParseAnimationChannel(
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
||||||
if (store_original_json_for_extras_and_extensions) {
|
if (store_original_json_for_extras_and_extensions) {
|
||||||
json_const_iterator it;
|
json_const_iterator it;
|
||||||
if (FindMember(target_object, "extensions", it)) {
|
if (FindMember(target_object, "extensions", it)) {
|
||||||
channel->target_extensions_json_string = JsonToString(GetValue(it));
|
channel->target_extensions_json_string = JsonToString(GetValue(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->sampler = samplerIndex;
|
channel->sampler = samplerIndex;
|
||||||
@@ -5089,12 +4998,12 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|||||||
int magFilter = -1;
|
int magFilter = -1;
|
||||||
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
||||||
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
||||||
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
||||||
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
||||||
//ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
|
ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
|
||||||
|
|
||||||
// TODO(syoyo): Check the value is alloed one.
|
// TODO(syoyo): Check the value is alloed one.
|
||||||
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
|
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
|
||||||
@@ -5103,7 +5012,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|||||||
sampler->magFilter = magFilter;
|
sampler->magFilter = magFilter;
|
||||||
sampler->wrapS = wrapS;
|
sampler->wrapS = wrapS;
|
||||||
sampler->wrapT = wrapT;
|
sampler->wrapT = wrapT;
|
||||||
//sampler->wrapR = wrapR;
|
sampler->wrapR = wrapR;
|
||||||
|
|
||||||
ParseExtensionsProperty(&(sampler->extensions), err, o);
|
ParseExtensionsProperty(&(sampler->extensions), err, o);
|
||||||
ParseExtrasProperty(&(sampler->extras), o);
|
ParseExtrasProperty(&(sampler->extras), o);
|
||||||
@@ -5768,15 +5677,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &target : primitive.targets) {
|
for(auto &target : primitive.targets) {
|
||||||
for (auto &attribute : target) {
|
for(auto &attribute : target) {
|
||||||
auto bufferView =
|
model->bufferViews[size_t(model->accessors[size_t(attribute.second)].bufferView)]
|
||||||
model->accessors[size_t(attribute.second)].bufferView;
|
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
// bufferView could be null(-1) for sparse morph target
|
|
||||||
if (bufferView >= 0) {
|
|
||||||
model->bufferViews[size_t(bufferView)].target =
|
|
||||||
TINYGLTF_TARGET_ARRAY_BUFFER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5886,18 +5790,6 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 11. Parse Image
|
// 11. Parse Image
|
||||||
void *load_image_user_data{nullptr};
|
|
||||||
|
|
||||||
LoadImageDataOption load_image_option;
|
|
||||||
|
|
||||||
if (user_image_loader_) {
|
|
||||||
// Use user supplied pointer
|
|
||||||
load_image_user_data = load_image_user_data_;
|
|
||||||
} else {
|
|
||||||
load_image_option.preserve_channels = preserve_image_channels_;
|
|
||||||
load_image_user_data = reinterpret_cast<void *>(&load_image_option);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
bool success = ForEachInArray(v, "images", [&](const json &o) {
|
bool success = ForEachInArray(v, "images", [&](const json &o) {
|
||||||
@@ -5910,7 +5802,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
Image image;
|
Image image;
|
||||||
if (!ParseImage(&image, idx, err, warn, o,
|
if (!ParseImage(&image, idx, err, warn, o,
|
||||||
store_original_json_for_extras_and_extensions_, base_dir,
|
store_original_json_for_extras_and_extensions_, base_dir,
|
||||||
&fs, &this->LoadImageData, load_image_user_data)) {
|
&fs, &this->LoadImageData, load_image_user_data_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5948,7 +5840,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
bool ret = LoadImageData(
|
bool ret = LoadImageData(
|
||||||
&image, idx, err, warn, image.width, image.height,
|
&image, idx, err, warn, image.width, image.height,
|
||||||
&buffer.data[bufferView.byteOffset],
|
&buffer.data[bufferView.byteOffset],
|
||||||
static_cast<int>(bufferView.byteLength), load_image_user_data);
|
static_cast<int>(bufferView.byteLength), load_image_user_data_);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -6373,13 +6265,6 @@ static void SerializeNumberProperty(const std::string &key, T number,
|
|||||||
JsonAddMember(obj, key.c_str(), json(number));
|
JsonAddMember(obj, key.c_str(), json(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
|
||||||
template <>
|
|
||||||
void SerializeNumberProperty(const std::string &key, size_t number, json &obj) {
|
|
||||||
JsonAddMember(obj, key.c_str(), json(static_cast<uint64_t>(number)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void SerializeNumberArrayProperty(const std::string &key,
|
static void SerializeNumberArrayProperty(const std::string &key,
|
||||||
const std::vector<T> &value,
|
const std::vector<T> &value,
|
||||||
@@ -6530,10 +6415,9 @@ static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
|||||||
const std::string &binFilename) {
|
const std::string &binFilename) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if defined(__GLIBCXX__) // mingw
|
#if defined(__GLIBCXX__) // mingw
|
||||||
int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(),
|
int file_descriptor =
|
||||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
_wopen(UTF8ToWchar(binFilename).c_str(), _O_WRONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
|
||||||
std::ostream output(&wfile_buf);
|
std::ostream output(&wfile_buf);
|
||||||
if (!wfile_buf.is_open()) return false;
|
if (!wfile_buf.is_open()) return false;
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
@@ -6616,41 +6500,15 @@ static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
||||||
if (accessor.bufferView >= 0)
|
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
||||||
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
|
||||||
|
|
||||||
if (accessor.byteOffset != 0)
|
if (accessor.byteOffset != 0.0)
|
||||||
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
||||||
|
|
||||||
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
||||||
SerializeNumberProperty<size_t>("count", accessor.count, o);
|
SerializeNumberProperty<size_t>("count", accessor.count, o);
|
||||||
|
SerializeNumberArrayProperty<double>("min", accessor.minValues, o);
|
||||||
if ((accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) ||
|
SerializeNumberArrayProperty<double>("max", accessor.maxValues, o);
|
||||||
(accessor.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)) {
|
|
||||||
SerializeNumberArrayProperty<double>("min", accessor.minValues, o);
|
|
||||||
SerializeNumberArrayProperty<double>("max", accessor.maxValues, o);
|
|
||||||
} else {
|
|
||||||
// Issue #301. Serialize as integer.
|
|
||||||
// Assume int value is within [-2**31-1, 2**31-1]
|
|
||||||
{
|
|
||||||
std::vector<int> values;
|
|
||||||
std::transform(accessor.minValues.begin(), accessor.minValues.end(),
|
|
||||||
std::back_inserter(values),
|
|
||||||
[](double v) { return static_cast<int>(v); });
|
|
||||||
|
|
||||||
SerializeNumberArrayProperty<int>("min", values, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
std::vector<int> values;
|
|
||||||
std::transform(accessor.maxValues.begin(), accessor.maxValues.end(),
|
|
||||||
std::back_inserter(values),
|
|
||||||
[](double v) { return static_cast<int>(v); });
|
|
||||||
|
|
||||||
SerializeNumberArrayProperty<int>("max", values, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessor.normalized)
|
if (accessor.normalized)
|
||||||
SerializeValue("normalized", Value(accessor.normalized), o);
|
SerializeValue("normalized", Value(accessor.normalized), o);
|
||||||
std::string type;
|
std::string type;
|
||||||
@@ -6693,7 +6551,7 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
|||||||
SerializeNumberProperty("node", channel.target_node, target);
|
SerializeNumberProperty("node", channel.target_node, target);
|
||||||
SerializeStringProperty("path", channel.target_path, target);
|
SerializeStringProperty("path", channel.target_path, target);
|
||||||
|
|
||||||
SerializeExtensionMap(channel.target_extensions, target);
|
SerializeExtensionMap(channel.target_extensions, target);
|
||||||
|
|
||||||
JsonAddMember(o, "target", std::move(target));
|
JsonAddMember(o, "target", std::move(target));
|
||||||
}
|
}
|
||||||
@@ -6760,15 +6618,10 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
|
|||||||
SerializeStringProperty("copyright", asset.copyright, o);
|
SerializeStringProperty("copyright", asset.copyright, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset.version.empty()) {
|
if (!asset.version.empty()) {
|
||||||
// Just in case
|
SerializeStringProperty("version", asset.version, o);
|
||||||
// `version` must be defined
|
|
||||||
asset.version = "2.0";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0?
|
|
||||||
SerializeStringProperty("version", asset.version, o);
|
|
||||||
|
|
||||||
if (asset.extras.Keys().size()) {
|
if (asset.extras.Keys().size()) {
|
||||||
SerializeValue("extras", asset.extras, o);
|
SerializeValue("extras", asset.extras, o);
|
||||||
}
|
}
|
||||||
@@ -7105,9 +6958,7 @@ static void SerializeSpotLight(SpotLight &spot, json &o) {
|
|||||||
static void SerializeGltfLight(Light &light, json &o) {
|
static void SerializeGltfLight(Light &light, json &o) {
|
||||||
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
||||||
SerializeNumberProperty("intensity", light.intensity, o);
|
SerializeNumberProperty("intensity", light.intensity, o);
|
||||||
if (light.range > 0.0) {
|
SerializeNumberProperty("range", light.range, o);
|
||||||
SerializeNumberProperty("range", light.range, o);
|
|
||||||
}
|
|
||||||
SerializeNumberArrayProperty("color", light.color, o);
|
SerializeNumberArrayProperty("color", light.color, o);
|
||||||
SerializeStringProperty("type", light.type, o);
|
SerializeStringProperty("type", light.type, o);
|
||||||
if (light.type == "spot") {
|
if (light.type == "spot") {
|
||||||
@@ -7166,7 +7017,7 @@ static void SerializeGltfSampler(Sampler &sampler, json &o) {
|
|||||||
if (sampler.minFilter != -1) {
|
if (sampler.minFilter != -1) {
|
||||||
SerializeNumberProperty("minFilter", sampler.minFilter, o);
|
SerializeNumberProperty("minFilter", sampler.minFilter, o);
|
||||||
}
|
}
|
||||||
//SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
||||||
SerializeNumberProperty("wrapS", sampler.wrapS, o);
|
SerializeNumberProperty("wrapS", sampler.wrapS, o);
|
||||||
SerializeNumberProperty("wrapT", sampler.wrapT, o);
|
SerializeNumberProperty("wrapT", sampler.wrapT, o);
|
||||||
|
|
||||||
@@ -7221,11 +7072,6 @@ static void SerializeGltfCamera(const Camera &camera, json &o) {
|
|||||||
} else {
|
} else {
|
||||||
// ???
|
// ???
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camera.extras.Type() != NULL_TYPE) {
|
|
||||||
SerializeValue("extras", camera.extras, o);
|
|
||||||
}
|
|
||||||
SerializeExtensionMap(camera.extensions, o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfScene(Scene &scene, json &o) {
|
static void SerializeGltfScene(Scene &scene, json &o) {
|
||||||
@@ -7304,7 +7150,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
JsonAddMember(o, "asset", std::move(asset));
|
JsonAddMember(o, "asset", std::move(asset));
|
||||||
|
|
||||||
// BUFFERVIEWS
|
// BUFFERVIEWS
|
||||||
if (model->bufferViews.size()) {
|
if(model->bufferViews.size()) {
|
||||||
json bufferViews;
|
json bufferViews;
|
||||||
JsonReserveArray(bufferViews, model->bufferViews.size());
|
JsonReserveArray(bufferViews, model->bufferViews.size());
|
||||||
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
||||||
@@ -7315,6 +7161,11 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extensions used
|
||||||
|
if (model->extensionsUsed.size()) {
|
||||||
|
SerializeStringArrayProperty("extensionsUsed", model->extensionsUsed, o);
|
||||||
|
}
|
||||||
|
|
||||||
// Extensions required
|
// Extensions required
|
||||||
if (model->extensionsRequired.size()) {
|
if (model->extensionsRequired.size()) {
|
||||||
SerializeStringArrayProperty("extensionsRequired",
|
SerializeStringArrayProperty("extensionsRequired",
|
||||||
@@ -7328,16 +7179,6 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
||||||
json material;
|
json material;
|
||||||
SerializeGltfMaterial(model->materials[i], material);
|
SerializeGltfMaterial(model->materials[i], material);
|
||||||
|
|
||||||
if (JsonIsNull(material)) {
|
|
||||||
// Issue 294.
|
|
||||||
// `material` does not have any required parameters
|
|
||||||
// so the result may be null(unmodified) when all material parameters
|
|
||||||
// have default value.
|
|
||||||
//
|
|
||||||
// null is not allowed thus we create an empty JSON object.
|
|
||||||
JsonSetObject(material);
|
|
||||||
}
|
|
||||||
JsonPushBack(materials, std::move(material));
|
JsonPushBack(materials, std::move(material));
|
||||||
}
|
}
|
||||||
JsonAddMember(o, "materials", std::move(materials));
|
JsonAddMember(o, "materials", std::move(materials));
|
||||||
@@ -7435,9 +7276,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
// EXTENSIONS
|
// EXTENSIONS
|
||||||
SerializeExtensionMap(model->extensions, o);
|
SerializeExtensionMap(model->extensions, o);
|
||||||
|
|
||||||
auto extensionsUsed = model->extensionsUsed;
|
// LIGHTS as KHR_lights_cmn
|
||||||
|
|
||||||
// LIGHTS as KHR_lights_punctual
|
|
||||||
if (model->lights.size()) {
|
if (model->lights.size()) {
|
||||||
json lights;
|
json lights;
|
||||||
JsonReserveArray(lights, model->lights.size());
|
JsonReserveArray(lights, model->lights.size());
|
||||||
@@ -7452,7 +7291,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
json_const_iterator it;
|
json_const_iterator it;
|
||||||
if (FindMember(o, "extensions", it)) {
|
if (!FindMember(o, "extensions", it)) {
|
||||||
JsonAssign(ext_j, GetValue(it));
|
JsonAssign(ext_j, GetValue(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7460,24 +7299,6 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
||||||
|
|
||||||
JsonAddMember(o, "extensions", std::move(ext_j));
|
JsonAddMember(o, "extensions", std::move(ext_j));
|
||||||
|
|
||||||
// Also add "KHR_lights_punctual" to `extensionsUsed`
|
|
||||||
{
|
|
||||||
auto has_khr_lights_punctual =
|
|
||||||
std::find_if(extensionsUsed.begin(), extensionsUsed.end(),
|
|
||||||
[](const std::string &s) {
|
|
||||||
return (s.compare("KHR_lights_punctual") == 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (has_khr_lights_punctual == extensionsUsed.end()) {
|
|
||||||
extensionsUsed.push_back("KHR_lights_punctual");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extensions used
|
|
||||||
if (extensionsUsed.size()) {
|
|
||||||
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRAS
|
// EXTRAS
|
||||||
@@ -7497,10 +7318,9 @@ static bool WriteGltfFile(const std::string &output,
|
|||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
||||||
#elif defined(__GLIBCXX__)
|
#elif defined(__GLIBCXX__)
|
||||||
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
int file_descriptor =
|
||||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
|
||||||
std::ostream gltfFile(&wfile_buf);
|
std::ostream gltfFile(&wfile_buf);
|
||||||
if (!wfile_buf.is_open()) return false;
|
if (!wfile_buf.is_open()) return false;
|
||||||
#else
|
#else
|
||||||
@@ -7586,10 +7406,9 @@ static void WriteBinaryGltfFile(const std::string &output,
|
|||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
||||||
#elif defined(__GLIBCXX__)
|
#elif defined(__GLIBCXX__)
|
||||||
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
int file_descriptor =
|
||||||
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
|
||||||
std::ostream gltfFile(&wfile_buf);
|
std::ostream gltfFile(&wfile_buf);
|
||||||
#else
|
#else
|
||||||
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
||||||
@@ -7610,13 +7429,13 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
|
|
||||||
// BUFFERS
|
// BUFFERS
|
||||||
std::vector<unsigned char> binBuffer;
|
std::vector<unsigned char> binBuffer;
|
||||||
if (model->buffers.size()) {
|
if(model->buffers.size()) {
|
||||||
json buffers;
|
json buffers;
|
||||||
JsonReserveArray(buffers, model->buffers.size());
|
JsonReserveArray(buffers, model->buffers.size());
|
||||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||||
json buffer;
|
json buffer;
|
||||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
if (writeBinary && i==0 && model->buffers[i].uri.empty()){
|
||||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
|
||||||
} else {
|
} else {
|
||||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||||
}
|
}
|
||||||
@@ -7633,9 +7452,9 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
json image;
|
json image;
|
||||||
|
|
||||||
std::string dummystring = "";
|
std::string dummystring = "";
|
||||||
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
// UpdateImageObject need baseDir but only uses it if embededImages is
|
||||||
// enabled, since we won't write separate images when writing to a stream
|
// enable, since we won't write separte images when writing to a stream we
|
||||||
// we
|
// use a dummystring
|
||||||
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
||||||
&this->WriteImageData, this->write_image_user_data_);
|
&this->WriteImageData, this->write_image_user_data_);
|
||||||
SerializeGltfImage(model->images[i], image);
|
SerializeGltfImage(model->images[i], image);
|
||||||
@@ -7682,15 +7501,14 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|||||||
JsonReserveArray(buffers, model->buffers.size());
|
JsonReserveArray(buffers, model->buffers.size());
|
||||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||||
json buffer;
|
json buffer;
|
||||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
if (writeBinary && i==0 && model->buffers[i].uri.empty()){
|
||||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
|
||||||
} else if (embedBuffers) {
|
} else if (embedBuffers) {
|
||||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||||
} else {
|
} else {
|
||||||
std::string binSavePath;
|
std::string binSavePath;
|
||||||
std::string binUri;
|
std::string binUri;
|
||||||
if (!model->buffers[i].uri.empty() &&
|
if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
|
||||||
!IsDataURI(model->buffers[i].uri)) {
|
|
||||||
binUri = model->buffers[i].uri;
|
binUri = model->buffers[i].uri;
|
||||||
} else {
|
} else {
|
||||||
binUri = defaultBinFilename + defaultBinFileExt;
|
binUri = defaultBinFilename + defaultBinFileExt;
|
||||||
@@ -7716,7 +7534,7 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|||||||
}
|
}
|
||||||
JsonPushBack(buffers, std::move(buffer));
|
JsonPushBack(buffers, std::move(buffer));
|
||||||
}
|
}
|
||||||
JsonAddMember(output, "buffers", std::move(buffers));
|
JsonAddMember(output, "buffers", std::move(buffers));
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMAGES
|
// IMAGES
|
||||||
|
|||||||
Reference in New Issue
Block a user