Compare commits

..

6 Commits

Author SHA1 Message Date
Syoyo Fujita
1b7994a4f4 Make lodepng optional. 2019-01-14 21:33:56 +09:00
Syoyo Fujita
c91b6468e8 Merge pull request #133 from Ybalrid/lodepng
fix ci build of example
2019-01-11 02:29:29 +09:00
Arthur Brainville (Ybalrid)
d4f8fcea10 fix ci build of example 2019-01-10 18:19:20 +00:00
Syoyo Fujita
ab069ffb40 Initial support of loading 16bit PNG using lodepng. 2019-01-07 02:27:28 +09:00
Syoyo Fujita
cbf13fef62 Merge branch 'master' into lodepng 2019-01-07 01:05:12 +09:00
Syoyo Fujita
57074aee04 Add single file version of lodepng. 2019-01-07 01:04:37 +09:00
79 changed files with 12159 additions and 35559 deletions

13
.github/FUNDING.yml vendored
View File

@@ -1,13 +0,0 @@
# These are supported funding model platforms
github: syoyo
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -1 +0,0 @@
blank_issues_enabled: false

View File

@@ -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.

View File

@@ -1,169 +0,0 @@
name: C/C++ CI
on: [push, pull_request]
jobs:
# gcc4.8 is too old and ubuntu-18.04 image is not supported in GitHub Actions anymore,
# so disable this build.
## 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-latest
name: Build with MinGW gcc cross
steps:
- name: Checkout
uses: actions/checkout@v2
- 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 2022 build
# Assume windows-latest have VS2022 installed
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 --help
cmake -G "Visual Studio 17 2022" -A x64 -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-latest
name: Build on cross aarch64
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
git clone https://github.com/Tencent/rapidjson
aarch64-linux-gnu-g++ -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

View File

@@ -1,72 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '21 20 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@@ -1,45 +0,0 @@
name: MSYS2 MinGW-w64 Windows 64bit Build
on:
push:
branches:
- release
- devel
paths:
- 'tiny_gltf.*'
- 'CMakeLists.txt'
- '.github/workflows/mingw-w64-msys2.yml'
pull_request:
workflow_dispatch:
jobs:
mingw-w64-msys2-build:
name: MSYS2 MinGW-w64 Windows Build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
- name: Install core & build dependencies
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
install: base-devel
pacboy: >-
cc:p cmake:p ninja:p
update: true
release: false
- name: Configure
run: |
cmake \
-G"Ninja" \
-S . \
-B build
- name: Build
run: |
cmake --build build

9
.gitignore vendored
View File

@@ -24,7 +24,6 @@ premake5.tar.gz
#binary directories
bin/
obj/
out/
#runtime gui config
imgui.ini
@@ -68,12 +67,4 @@ imgui.ini
loader_example
tests/tester
tests/tester_noexcept
tests/issue-97.gltf
tests/issue-261.gltf
# unignore
!Makefile
!examples/build-gltf/Makefile
!examples/raytrace/cornellbox_suzanne.obj
!tests/Makefile
!tools/windows/premake5.exe

10
.travis-before-install.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
if [[ "$TRAVIS_OS_NAME" == "osx" ]]
then
brew upgrade
curl -o premake5.tar.gz https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-macosx.tar.gz
else
wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake5.tar.gz
fi
tar xzf premake5.tar.gz

47
.travis.yml Normal file
View File

@@ -0,0 +1,47 @@
language: cpp
sudo: false
matrix:
include:
- addons: &1
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-3.9
packages:
- g++-4.9
- clang-3.9
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Release
- addons: &2
apt:
sources:
- george-edison55-precise-backports
- ubuntu-toolchain-r-test
packages:
- g++-4.9
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Debug EXTRA_CXXFLAGS="-fsanitize=address"
- addons: *2
compiler: gcc
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release EXTRA_CXXFLAGS="-fsanitize=address"
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
before_install:
- ./.travis-before-install.sh
script:
- export CC="${CC}-${COMPILER_VERSION}"
- export CXX="${CXX}-${COMPILER_VERSION}"
- ${CC} -v
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
- ./loader_example ./models/Cube/Cube.gltf
- cd examples/raytrace
- ../../premake5 gmake
- make

View File

@@ -1,79 +1,28 @@
cmake_minimum_required(VERSION 3.6)
project(tinygltf)
PROJECT (tinygltf)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
SET(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS Off)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF)
option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON)
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
add_executable(loader_example
loader_example.cc
)
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
if (TINYGLTF_BUILD_GL_EXAMPLES)
add_subdirectory( examples/gltfutil )
add_subdirectory( examples/glview )
endif (TINYGLTF_BUILD_GL_EXAMPLES)
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
add_subdirectory( examples/validator )
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
add_subdirectory ( examples/build-gltf )
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
#
# for add_subdirectory and standalone build
#
if (TINYGLTF_HEADER_ONLY)
add_library(tinygltf INTERFACE)
target_include_directories(tinygltf
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
ADD_EXECUTABLE ( loader_example
loader_example.cc
)
else (TINYGLTF_HEADER_ONLY)
add_library(tinygltf)
target_sources(tinygltf PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/tiny_gltf.cc)
target_include_directories(tinygltf
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
endif (TINYGLTF_HEADER_ONLY)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
ADD_SUBDIRECTORY ( examples/validator )
if (TINYGLTF_INSTALL)
install(TARGETS tinygltf EXPORT tinygltfTargets)
install(EXPORT tinygltfTargets NAMESPACE tinygltf:: FILE TinyGLTFTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/TinyGLTFConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
# Do not install .lib even if !TINYGLTF_HEADER_ONLY
INSTALL ( FILES
json.hpp
stb_image.h
stb_image_write.h
tiny_gltf.h
DESTINATION
include
)
INSTALL ( FILES
json.hpp
stb_image.h
stb_image_write.h
tiny_gltf.h
${TINYGLTF_EXTRA_SOUECES}
DESTINATION
include
)
endif(TINYGLTF_INSTALL)
INSTALL ( FILES
cmake/TinyGLTFConfig.cmake
DESTINATION
cmake
)

View File

@@ -2,12 +2,8 @@
# Use this for strict compilation check(will work on clang 3.8+)
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat
# With draco
# EXTRA_CXXFLAGS := -I../draco/src/ -I../draco/build -DTINYGLTF_ENABLE_DRACO -L../draco/build
# EXTRA_LINKFLAGS := -L../draco/build/ -ldracodec -ldraco
all:
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc $(EXTRA_LINKFLAGS)
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc
lint:
deps/cpplint.py tiny_gltf.h

145
README.md
View File

@@ -2,38 +2,21 @@
`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.
(Also, you can use RadpidJSON as an JSON backend)
If you are looking for old, C++03 version, please use `devel-picojson` branch (but not maintained anymore).
`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.
## Status
Currently TinyGLTF is stable and maintenance mode. No drastic changes and feature additions planned.
- v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397
- v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393
- v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
- v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
- v2.1.0 release(Draco decoding support)
- 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), but not well maintained.
v2.0.0 release(22 Aug, 2018)!
## Builds
[![Build Status](https://travis-ci.org/syoyo/tinygltf.svg?branch=devel)](https://travis-ci.org/syoyo/tinygltf)
[![Build status](https://ci.appveyor.com/api/projects/status/warngenu9wjjhlm8?svg=true)](https://ci.appveyor.com/project/syoyo/tinygltf)
![C/C++ CI](https://github.com/syoyo/tinygltf/workflows/C/C++%20CI/badge.svg)
## Features
Probably mostly feature-complete. Last missing feature is Draco encoding: https://github.com/syoyo/tinygltf/issues/207
* Written in portable C++. C++-11 with STL dependency only.
* [x] macOS + clang(LLVM)
* [x] iOS + clang
@@ -47,50 +30,27 @@ Probably mostly feature-complete. Last missing feature is Draco encoding: https:
* Moderate parsing time and memory consumption.
* glTF specification v2.0.0
* [x] ASCII glTF
* [x] Load
* [x] Save
* [x] Binary glTF(GLB)
* [x] Load
* [x] Save(.bin embedded .glb)
* [x] PBR material description
* Buffers
* [x] Parse BASE64 encoded embedded buffer data(DataURI).
* [x] Load `.bin` file.
* Image(Using stb_image)
* [x] Parse BASE64 encoded embedded image data(DataURI).
* [x] Load external image file.
* [x] Load PNG(8bit and 16bit)
* [x] Load JPEG(8bit only)
* [x] Load BMP
* [x] Load GIF
* [x] PNG(8bit only)
* [x] JPEG(8bit only)
* [x] BMP
* [x] GIF
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
* Morph traget
* [x] Sparse accessor
* Load glTF from memory
* Load from memory
* Custom callback handler
* [x] Image load
* [x] Image save
* Extensions
* [x] Draco mesh decoding
* [ ] Draco mesh encoding
## Note on extension property
In extension(`ExtensionMap`), JSON number value is parsed as int or float(number) and stored as `tinygltf::Value` object. If you want a floating point value from `tinygltf::Value`, use `GetNumberAsDouble()` method.
`IsNumber()` returns true if the underlying value is an int value or a floating point value.
## Examples
* [glview](examples/glview) : Simple glTF geometry viewer.
* [validator](examples/validator) : Simple glTF validator with JSON schema.
* [basic](examples/basic) : Basic glTF viewer with texturing support.
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
### WASI/WASM build
Users who want to run TinyGLTF securely and safely(e.g. need to handle malcious glTF file to serve online glTF conver),
I recommend to build TinyGLTF for WASM target.
WASI build example is located in [wasm](wasm) .
## Projects using TinyGLTF
@@ -98,34 +58,19 @@ WASI build example is located in [wasm](wasm) .
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
* [TinyGltfImporter](http://doc.magnum.graphics/magnum/classMagnum_1_1Trade_1_1TinyGltfImporter.html) plugin for [Magnum](https://github.com/mosra/magnum), a lightweight and modular C++11/C++14 graphics middleware for games and data visualization.
* [Diligent Engine](https://github.com/DiligentGraphics/DiligentEngine) - A modern cross-platform low-level graphics library and rendering framework
* Lighthouse 2: a rendering framework for real-time ray tracing / path tracing experiments. https://github.com/jbikker/lighthouse2
* [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
* [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 professional development of its developer
* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing
* [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design.
* [Wicked Engine<img src="https://github.com/turanszkij/WickedEngine/blob/master/Content/logo_small.png" width="28px" align="center"/>](https://github.com/turanszkij/WickedEngine) - 3D engine with modern graphics
* Your projects here! (Please send PR)
## TODOs
* [ ] Robust URI decoding/encoding. https://github.com/syoyo/tinygltf/issues/369
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
* [ ] Mesh Compression/decompression(Open3DGC, etc)
* [x] Load Draco compressed mesh
* [ ] Save Draco compressed mesh
* [ ] Open3DGC?
* [x] Support `extensions` and `extras` property
* [ ] Load Draco compressed mesh
* [ ] Support `extensions` and `extras` property
* [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR.
* [ ] 16bit PNG support in Serialization
* [ ] Write example and tests for `animation` and `skin`
### Optional
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing?
* [ ] Write example and tests for `animation` and `skin`
* [ ] Skinning
* [ ] Morph targets
## Licenses
@@ -137,6 +82,7 @@ TinyGLTF uses the following third party libraries.
* base64 : Copyright (C) 2004-2008 René Nyffenegger
* stb_image.h : v2.08 - public domain image loader - [Github link](https://github.com/nothings/stb/blob/master/stb_image.h)
* stb_image_write.h : v1.09 - public domain image writer - [Github link](https://github.com/nothings/stb/blob/master/stb_image_write.h)
* lodepng : Copyright (c) 2005-2018 Lode Vandevenne. zlib license. https://lodev.org/lodepng/
## Build and example
@@ -155,13 +101,13 @@ Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your pr
using namespace tinygltf;
Model model;
Model model;
TinyGLTF loader;
std::string err;
std::string warn;
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str());
@@ -177,53 +123,24 @@ 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
* `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_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option would be helpful if you do not want to load image files during glTF parsing.
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_RAPIDJSON `: Disable including RapidJson's header files from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this feature.
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
## CMake options
You can add tinygltf using `add_subdirectory` feature.
If you add tinygltf to your project using `add_subdirectory`, it would be better to set `TINYGLTF_HEADER_ONLY` on(just add an include path to tinygltf) and `TINYGLTF_INSTALL` off(Which does not install tinygltf files).
```
// Your project's CMakeLists.txt
...
set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE)
set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory(/path/to/tinygltf)
```
* `TINYGLTF_USE_LODEPNG` : Load 16bit PNG image with lodepng(Valid when `TINYGLTF_NO_STB_IMAGE` was **not** defined). Must defined `LODEPNG_IMPLEMENTATION` in one .cc.
### Saving gltTF 2.0 model
* Buffers.
* [ ] Buffers.
* [x] To file
* [x] Embedded
* [ ] Draco compressed?
* [x] Images
* [x] To file
* [x] Embedded
* Binary(.glb)
* [x] .bin embedded single .glb
* [ ] External .bin
* [ ] Binary(.glb)
## Running tests.
@@ -231,7 +148,7 @@ add_subdirectory(/path/to/tinygltf)
#### Setup
Python required.
Python 2.6 or 2.7 required.
Git clone https://github.com/KhronosGroup/glTF-Sample-Models to your local dir.
#### Run parsing test
@@ -251,17 +168,9 @@ $ ./tester
$ ./tester_noexcept
```
### Fuzzing tests
See `tests/fuzzer` for details.
After running fuzzer on Ryzen9 3950X a week, at least `LoadASCIIFromString` looks safe except for out-of-memory error in Fuzzer.
We may be better to introduce bounded memory size checking when parsing glTF data.
## Third party licenses
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
* stb_image : Public domain.
* lodepng : zlib license
* 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/
* dlib(uridecode, uriencode) : Copyright (C) 2003 Davis E. King Boost Software License 1.0. http://dlib.net/dlib/server/server_http.cpp.html

View File

@@ -0,0 +1,15 @@
# -*- cmake -*-
# - Find TinyGLTF
# TinyGLTF_INCLUDE_DIR TinyGLTF's include directory
FIND_PACKAGE ( PackageHandleStandardArgs )
SET ( TinyGLTF_INCLUDE_DIR "${TinyGLTF_DIR}/../include" CACHE STRING "TinyGLTF include directory")
FIND_FILE ( TinyGLTF_HEADER tiny_gltf.h PATHS ${TinyGLTF_INCLUDE_DIR} )
IF (NOT TinyGLTF_HEADER)
MESSAGE ( FATAL_ERROR "Unable to find tiny_gltf.h, TinyGLTF_INCLUDE_DIR = ${TinyGLTF_INCLUDE_DIR}")
ENDIF ()

View File

@@ -1,3 +0,0 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/TinyGLTFTargets.cmake)

View File

@@ -1,6 +1,5 @@
.vs
Debug
Release
x64
packages

View File

@@ -1,25 +0,0 @@
# Basic glTF viewer
## Requirements
* glew
* glfw3
* premake5(linux)
* OpenGL 3.3+ GPU
## Build on Linux and macOS
```
$ premake5 gmake
$ make
```
## Build on Visual Studio
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).

View File

@@ -22,32 +22,32 @@
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid>
<RootNamespace>basic</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>

Binary file not shown.

View File

@@ -1,44 +0,0 @@
solution "basic_viewer"
-- location ( "build" )
configurations { "Debug", "Release" }
platforms {"native", "x64", "x32"}
project "basic_viewer"
kind "ConsoleApp"
language "C++"
cppdialect "C++11"
files { "main.cpp", "shaders.cpp", "window.cpp" }
includedirs { "./" }
includedirs { "../../" }
includedirs { "../common/glm" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
configuration { "windows" }
-- Edit path to glew and GLFW3 fit to your environment.
includedirs { "../../../../local/glew-1.13.0/include/" }
includedirs { "../../../../local/glfw-3.2.bin.WIN32/include/" }
libdirs { "../../../../local/glew-1.13.0/lib/Release/Win32/" }
libdirs { "../../../../local/glfw-3.2.bin.WIN32/lib-vc2013/" }
links { "glfw3", "gdi32", "winmm", "user32", "glew32", "glu32","opengl32", "kernel32" }
defines { "_CRT_SECURE_NO_WARNINGS" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
symbols "On"
warnings "Extra"
configuration "Release"
defines { "NDEBUG" }
optimize "On"
warnings "Extra"

View File

@@ -19,7 +19,7 @@ uniform vec3 sun_color; \n\
out vec4 color;\n\
void main() {\n\
float lum = max(dot(normal, normalize(sun_position)), 0.0);\n\
color = texture(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
color = texture2D(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
}\n\
";

View File

@@ -1,5 +0,0 @@
include_directories(${CMAKE_SOURCE_DIR})
add_executable(create_triangle_gltf create_triangle_gltf.cpp)
target_compile_options(create_triangle_gltf PUBLIC -Wall)
target_link_libraries(create_triangle_gltf )

View File

@@ -1,2 +0,0 @@
all:
$(CXX) -o create_triangle_gltf -I../../ create_triangle_gltf.cpp

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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
)

View File

@@ -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
```

View File

@@ -1,3 +0,0 @@
float4 main() : SV_Target {
return float4(0.5, 0.5, 0.5, 1.0);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -4,10 +4,9 @@ project(gltfutil)
set(CMAKE_CXX_STANDARD 11)
include_directories(../../)
include_directories(../common/)
file(GLOB gltfutil_sources *.cc *.h)
add_executable(gltfutil ${gltfutil_sources} ../common/lodepng.cpp)
add_executable(gltfutil ${gltfutil_sources})
install ( TARGETS
gltfutil

View File

@@ -49,7 +49,6 @@ struct configuration {
cli_action action = cli_action::not_set;
texture_dumper::texture_output_format requested_format =
texture_dumper::texture_output_format::not_specified;
bool use_exr = false;
bool has_output_dir;
bool is_valid() {

View File

@@ -11,9 +11,6 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define TINYEXR_IMPLEMENTATION
#include "tinyexr.h"
namespace gltfutil {
int usage(int ret = 0) {
using std::cout;
@@ -23,9 +20,8 @@ int usage(int ret = 0) {
"[path to output directory])\n\n"
//<< "\t\t -i: start in interactive mode\n"
<< "\t\t -d: dump enclosed content (image assets)\n"
<< "\t\t -f: file format for image output\n"
<< "\t\t -o: ouptput directory path\n"
<< "\t\t -e: Use OpenEXR format for 16bit image\n"
<< "\t\t -f: file format for image output"
<< "\t\t -o: ouptput directory path"
<< "\t\t -h: print this help\n";
return ret;
}
@@ -48,9 +44,6 @@ int parse_args(int argc, char** argv) {
config.mode = ui_mode::cli;
config.action = cli_action::dump;
break;
case 'e':
config.use_exr = true;
break;
case 'i':
config.mode = ui_mode::interactive;
break;
@@ -104,11 +97,6 @@ int parse_args(int argc, char** argv) {
case cli_action::dump: {
texture_dumper dumper(model);
if (config.use_exr) {
dumper.set_use_exr(true);
}
if (config.requested_format !=
texture_dumper::texture_output_format::not_specified)
dumper.set_output_format(config.requested_format);

View File

@@ -1,84 +1,15 @@
#include <algorithm>
#include <iostream>
#include <algorithm>
#include "stb_image_write.h"
#include "texture_dumper.h"
#include "lodepng.h" // ../common
#include "tinyexr.h"
#include <tiny_gltf.h>
using namespace gltfutil;
using namespace tinygltf;
using std::cout;
static LodePNGColorType GetLodePNGColorType(int channels) {
if (channels == 1) {
return LodePNGColorType::LCT_GREY;
} else if (channels == 2) {
return LodePNGColorType::LCT_GREY_ALPHA;
} else if (channels == 3) {
return LodePNGColorType::LCT_RGB;
} else if (channels == 4) {
return LodePNGColorType::LCT_RGBA;
} else {
std::cerr << "??? unsupported channels " << channels << "\n";
return LodePNGColorType::LCT_RGB; // FIXME(syoyo): Raise error
}
}
static void ToBigEndian(std::vector<uint8_t>* image) {
assert(image->size() % 2 == 0);
union {
unsigned int i;
char c[4];
} bint = {0x01020304};
bool is_big_endian = (bint.c[0] == 1);
if (is_big_endian) {
return;
}
uint16_t *ptr = reinterpret_cast<uint16_t *>(image->data());
size_t n = image->size() / 2;
for (size_t i = 0; i < n; i++) {
ptr[i] = ((0xFF00 & ptr[i]) >> 8) | ((0x00FF & ptr[i]) << 8);
}
}
static bool Save16bitImageAsEXR(const std::string& filename,
const tinygltf::Image& image) {
assert(image.bits == 16);
std::vector<float> buf(image.width * image.height * image.component);
// widen to float image.
// Store as is(i.e, pixel value range is [0.0, 65535.0])
const unsigned short* ptr =
reinterpret_cast<const unsigned short*>(image.image.data());
for (size_t i = 0; i < image.width * image.height * image.component; i++) {
buf[i] = float(ptr[i]);
}
const char* err = nullptr;
int ret = SaveEXR(buf.data(), image.width, image.height, image.component,
/* save_as_fp16 */ 0, filename.c_str(), &err);
if (err) {
std::cerr << "EXR err: " << err << std::endl;
FreeEXRErrorMessage(err);
return false;
}
return (ret == TINYEXR_SUCCESS);
}
texture_dumper::texture_dumper(const Model& input)
: model(input), configured_format(texture_output_format::png) {
cout << "Texture dumper\n";
@@ -95,58 +26,26 @@ void texture_dumper::dump_to_folder(const std::string& path) {
cout << "image name is: \"" << image.name << "\"\n";
cout << "image size is: " << image.width << 'x' << image.height << '\n';
cout << "pixel channel count :" << image.component << '\n';
cout << "pixel bit depth :" << image.bits << '\n';
std::string basename =
image.name.empty() ? std::to_string(index) : image.name;
std::string name = image.name.empty() ? std::to_string(index) : image.name;
unsigned char* bytes_to_write =
const_cast<unsigned char*>(image.image.data());
std::string filename;
switch (configured_format) {
case texture_output_format::png:
filename = path + "/" + basename + ".png";
if (this->use_exr) {
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
filename = path + "/" + basename + ".exr";
}
}
std::cout << "Image will be written to " << filename << '\n';
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
if (this->use_exr) {
bool ret = Save16bitImageAsEXR(filename, image);
assert(ret);
} else {
// Use lodepng to save 16bit PNG.
// NOTE(syoyo): `loadpng::encode` requires image data must be stored in big endian.
std::vector<uint8_t> tmp = image.image; // copy
ToBigEndian(&tmp);
unsigned ret = lodepng::encode(
filename, tmp.data(), image.width, image.height,
GetLodePNGColorType(image.component), /* bits */ 16);
assert(ret == 0); // 0 = no err.
}
} else {
// TODO(syoyo): check status
stbi_write_png(filename.c_str(), image.width, image.height,
image.component, bytes_to_write, 0);
}
name = path + "/" + name + ".png";
std::cout << "Image will be written to " << name << '\n';
stbi_write_png(name.c_str(), image.width, image.height, image.component,
image.image.data(), 0);
break;
case texture_output_format::bmp:
filename = path + "/" + basename + ".bmp";
std::cout << "Image will be written to " << filename << '\n';
stbi_write_bmp(filename.c_str(), image.width, image.height,
image.component, bytes_to_write);
std::cout << "Image will be written to " << name << '\n';
name = path + "/" + name + ".bmp";
stbi_write_bmp(name.c_str(), image.width, image.height, image.component,
image.image.data());
break;
case texture_output_format::tga:
filename = path + "/" + basename + ".tga";
std::cout << "Image will be written to " << filename << '\n';
stbi_write_tga(filename.c_str(), image.width, image.height,
image.component, bytes_to_write);
std::cout << "Image will be written to " << name << '\n';
name = path + "/" + name + ".tga";
stbi_write_tga(name.c_str(), image.width, image.height, image.component,
image.image.data());
break;
}
}

View File

@@ -12,15 +12,11 @@ class texture_dumper {
private:
const tinygltf::Model& model;
texture_output_format configured_format;
bool use_exr = false; // Use EXR for 16bit image?
public:
texture_dumper(const tinygltf::Model& inputModel);
void dump_to_folder(const std::string& path = "./");
void set_output_format(texture_output_format format);
void set_use_exr(const bool value) {
use_exr = value;
}
static texture_output_format get_fromat_from_string(const std::string& str);
};

View File

@@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.6)
project(glview)
set ( CMAKE_PREFIX_PATH cmake )
set ( DRACO_DIR "" CACHE STRING "Path to draco" )
find_package ( GLEW REQUIRED )
find_package ( GLFW3 REQUIRED )
find_package ( OpenGL REQUIRED )
@@ -23,18 +21,6 @@ endif (APPLE)
set(CMAKE_CXX_STANDARD 11)
if (DEFINED DRACO_DIR)
if (DRACO_DIR STREQUAL "")
else ()
# TODO(syoyo): better CMake script for draco
add_definitions(-DTINYGLTF_ENABLE_DRACO)
include_directories(${DRACO_DIR}/include)
link_directories(${DRACO_DIR}/lib)
set(DRACO_LIBRARY draco)
endif ()
endif()
include_directories(
../../
../common
@@ -49,9 +35,8 @@ add_executable(glview
)
target_link_libraries ( glview
${DRACO_LIBRARY}
${GLFW3_UNIX_LINK_LIBRARIES}
${GLEW_LIBRARIES}
${GLEW_LIBRARY}
${GLFW3_glfw_LIBRARY}
${OPENGL_gl_LIBRARY}
${OPENGL_glu_LIBRARY}

View File

@@ -27,17 +27,6 @@ Open .sln in Visual Studio 2013
When running .exe, glew and glfw dll must exist in the working directory.
#### Build with Draco(optional)
Assume CMake build.
```
$ mkdir build
$ cd build
$ cmake -DDRACO_DIR=/path/to/draco ../
$ make
```
## TODO
* [ ] PBR Material

View File

@@ -28,6 +28,7 @@
#include "tiny_gltf.h"
#endif
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#define CheckGLErrors(desc) \
@@ -54,9 +55,7 @@ float eye[3], lookat[3], up[3];
GLFWwindow *window;
typedef struct {
GLuint vb;
} GLBufferState;
typedef struct { GLuint vb; } GLBufferState;
typedef struct {
std::vector<GLuint> diffuseTex; // for each primitive in mesh
@@ -255,26 +254,6 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
prevMouseY = mouse_y;
}
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;
}
}
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
// Buffer
{
@@ -285,117 +264,14 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
continue; // Unsupported bufferView.
}
int sparse_accessor = -1;
for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
const auto &accessor = model.accessors[a_i];
if (accessor.bufferView == i) {
std::cout << i << " is used by accessor " << a_i << std::endl;
if (accessor.sparse.isSparse) {
std::cout
<< "WARN: this bufferView has at least one sparse accessor to "
"it. We are going to load the data as patched by this "
"sparse accessor, not the original data"
<< std::endl;
sparse_accessor = a_i;
break;
}
}
}
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
GLBufferState state;
glGenBuffers(1, &state.vb);
glBindBuffer(bufferView.target, state.vb);
std::cout << "buffer.size= " << buffer.data.size()
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
if (sparse_accessor < 0)
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset,
GL_STATIC_DRAW);
else {
const auto accessor = model.accessors[sparse_accessor];
// copy the buffer to a temporary one for sparse patching
unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
bufferView.byteLength);
const size_t size_of_object_in_buffer =
ComponentTypeByteSize(accessor.componentType);
const size_t size_of_sparse_indices =
ComponentTypeByteSize(accessor.sparse.indices.componentType);
const auto &indices_buffer_view =
model.bufferViews[accessor.sparse.indices.bufferView];
const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
const auto &values_buffer_view =
model.bufferViews[accessor.sparse.values.bufferView];
const auto &values_buffer = model.buffers[values_buffer_view.buffer];
for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
++sparse_index) {
int index = 0;
// std::cout << "accessor.sparse.indices.componentType = " <<
// accessor.sparse.indices.componentType << std::endl;
switch (accessor.sparse.indices.componentType) {
case TINYGLTF_COMPONENT_TYPE_BYTE:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
index = (int)*(
unsigned char *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
case TINYGLTF_COMPONENT_TYPE_SHORT:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
index = (int)*(
unsigned short *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
case TINYGLTF_COMPONENT_TYPE_INT:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
index = (int)*(
unsigned int *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
}
std::cout << "updating sparse data at index : " << index
<< std::endl;
// index is now the target of the sparse index to patch in
const unsigned char *read_from =
values_buffer.data.data() +
(values_buffer_view.byteOffset +
accessor.sparse.values.byteOffset) +
(sparse_index * (size_of_object_in_buffer * accessor.type));
/*
std::cout << ((float*)read_from)[0] << "\n";
std::cout << ((float*)read_from)[1] << "\n";
std::cout << ((float*)read_from)[2] << "\n";
*/
unsigned char *write_to =
tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
}
// debug:
/*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
{
float* b = (float*)tmp_buffer;
std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
}*/
glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
GL_STATIC_DRAW);
delete[] tmp_buffer;
}
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
glBindBuffer(bufferView.target, 0);
gBufferState[i] = state;
@@ -403,55 +279,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
}
#if 0 // TODO(syoyo): Implement
// Texture
{
for (size_t i = 0; i < model.meshes.size(); i++) {
const tinygltf::Mesh &mesh = model.meshes[i];
// Texture
{
for (size_t i = 0; i < model.meshes.size(); i++) {
const tinygltf::Mesh &mesh = model.meshes[i];
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex[primId] = 0;
gMeshState[mesh.name].diffuseTex[primId] = 0;
if (primitive.material < 0) {
continue;
}
tinygltf::Material &mat = model.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (model.textures.find(diffuseTexName) != model.textures.end()) {
tinygltf::Texture &tex = model.textures[diffuseTexName];
if (scene.images.find(tex.source) != model.images.end()) {
tinygltf::Image &image = model.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (primitive.material < 0) {
continue;
}
tinygltf::Material &mat = model.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (model.textures.find(diffuseTexName) != model.textures.end()) {
tinygltf::Texture &tex = model.textures[diffuseTexName];
if (scene.images.find(tex.source) != model.images.end()) {
tinygltf::Image &image = model.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
#endif
glUseProgram(progId);
@@ -472,164 +348,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
#if 0 // TODO(syoyo): Implement
// Setup curves geometry extension
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
// Find curves primitive.
{
std::map<std::string, tinygltf::Mesh>::const_iterator it(
scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
scene.meshes.end());
// Find curves primitive.
{
std::map<std::string, tinygltf::Mesh>::const_iterator it(
scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
scene.meshes.end());
for (; it != itEnd; it++) {
const tinygltf::Mesh &mesh = it->second;
for (; it != itEnd; it++) {
const tinygltf::Mesh &mesh = it->second;
// Currently we only support one primitive per mesh.
if (mesh.primitives.size() > 1) {
continue;
}
// Currently we only support one primitive per mesh.
if (mesh.primitives.size() > 1) {
continue;
}
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex[primId] = 0;
gMeshState[mesh.name].diffuseTex[primId] = 0;
if (primitive.material.empty()) {
continue;
}
if (primitive.material.empty()) {
continue;
}
bool has_curves = false;
if (primitive.extras.IsObject()) {
if (primitive.extras.Has("ext_mode")) {
const tinygltf::Value::Object &o =
primitive.extras.Get<tinygltf::Value::Object>();
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
bool has_curves = false;
if (primitive.extras.IsObject()) {
if (primitive.extras.Has("ext_mode")) {
const tinygltf::Value::Object &o =
primitive.extras.Get<tinygltf::Value::Object>();
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
if (ext_mode.IsString()) {
const std::string &str = ext_mode.Get<std::string>();
if (str.compare("curves") == 0) {
has_curves = true;
}
}
}
}
if (ext_mode.IsString()) {
const std::string &str = ext_mode.Get<std::string>();
if (str.compare("curves") == 0) {
has_curves = true;
}
}
}
}
if (!has_curves) {
continue;
}
if (!has_curves) {
continue;
}
// Construct curves buffer
const tinygltf::Accessor &vtx_accessor =
scene.accessors[primitive.attributes.find("POSITION")->second];
const tinygltf::Accessor &nverts_accessor =
scene.accessors[primitive.attributes.find("NVERTS")->second];
const tinygltf::BufferView &vtx_bufferView =
scene.bufferViews[vtx_accessor.bufferView];
const tinygltf::BufferView &nverts_bufferView =
scene.bufferViews[nverts_accessor.bufferView];
const tinygltf::Buffer &vtx_buffer =
scene.buffers[vtx_bufferView.buffer];
const tinygltf::Buffer &nverts_buffer =
scene.buffers[nverts_bufferView.buffer];
// Construct curves buffer
const tinygltf::Accessor &vtx_accessor =
scene.accessors[primitive.attributes.find("POSITION")->second];
const tinygltf::Accessor &nverts_accessor =
scene.accessors[primitive.attributes.find("NVERTS")->second];
const tinygltf::BufferView &vtx_bufferView =
scene.bufferViews[vtx_accessor.bufferView];
const tinygltf::BufferView &nverts_bufferView =
scene.bufferViews[nverts_accessor.bufferView];
const tinygltf::Buffer &vtx_buffer =
scene.buffers[vtx_bufferView.buffer];
const tinygltf::Buffer &nverts_buffer =
scene.buffers[nverts_bufferView.buffer];
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
// std::endl;
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
// std::endl;
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
// std::endl;
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
// std::endl;
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
// std::endl;
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
// std::endl;
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
// std::endl;
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
// std::endl;
const int *nverts =
reinterpret_cast<const int *>(nverts_buffer.data.data());
const float *vtx =
reinterpret_cast<const float *>(vtx_buffer.data.data());
const int *nverts =
reinterpret_cast<const int *>(nverts_buffer.data.data());
const float *vtx =
reinterpret_cast<const float *>(vtx_buffer.data.data());
// Convert to GL_LINES data.
std::vector<float> line_pts;
size_t vtx_offset = 0;
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
for (int n = 0; n < nverts[k] - 1; n++) {
// Convert to GL_LINES data.
std::vector<float> line_pts;
size_t vtx_offset = 0;
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
for (int n = 0; n < nverts[k] - 1; n++) {
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
// << vtx[3 * (vtx_offset + n) + 1] << ", "
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
// << vtx[3 * (vtx_offset + n) + 1] << ", "
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
}
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
}
vtx_offset += nverts[k];
}
vtx_offset += nverts[k];
}
GLCurvesState state;
glGenBuffers(1, &state.vb);
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
line_pts.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLCurvesState state;
glGenBuffers(1, &state.vb);
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
line_pts.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
state.count = line_pts.size() / 3;
gCurvesMesh[mesh.name] = state;
state.count = line_pts.size() / 3;
gCurvesMesh[mesh.name] = state;
// Material
tinygltf::Material &mat = scene.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
tinygltf::Texture &tex = scene.textures[diffuseTexName];
if (scene.images.find(tex.source) != scene.images.end()) {
tinygltf::Image &image = scene.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Material
tinygltf::Material &mat = scene.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
tinygltf::Texture &tex = scene.textures[diffuseTexName];
if (scene.images.find(tex.source) != scene.images.end()) {
tinygltf::Image &image = scene.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
glUseProgram(progId);
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
glUseProgram(progId);
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
gGLProgramState.attribs["POSITION"] = vtloc;
gGLProgramState.attribs["NORMAL"] = nrmloc;
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
gGLProgramState.attribs["POSITION"] = vtloc;
gGLProgramState.attribs["NORMAL"] = nrmloc;
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
};
#endif
@@ -682,13 +558,12 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
(it->first.compare("TEXCOORD_0") == 0)) {
if (gGLProgramState.attribs[it->first] >= 0) {
// Compute byteStride from Accessor + BufferView combination.
int byteStride =
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]);
assert(byteStride != -1);
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, BUFFER_OFFSET(accessor.byteOffset));
accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride,
BUFFER_OFFSET(accessor.byteOffset));
CheckErrors("vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
CheckErrors("enable vertex attrib array");
@@ -742,58 +617,34 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
#if 0 // TODO(syoyo): Implement
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
(void)scene;
(void)scene;
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
return;
}
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
}
GLCurvesState &state = gCurvesMesh[mesh.name];
if (gGLProgramState.attribs["POSITION"] >= 0) {
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
CheckErrors("curve: vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
CheckErrors("curve: enable vertex attrib array");
}
glDrawArrays(GL_LINES, 0, state.count);
if (gGLProgramState.attribs["POSITION"] >= 0) {
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
}
}
#endif
static void QuatToAngleAxis(const std::vector<double> quaternion,
double &outAngleDegrees,
double *axis) {
double qx = quaternion[0];
double qy = quaternion[1];
double qz = quaternion[2];
double qw = quaternion[3];
double angleRadians = 2 * acos(qw);
if (angleRadians == 0.0) {
outAngleDegrees = 0.0;
axis[0] = 0.0;
axis[1] = 0.0;
axis[2] = 1.0;
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
return;
}
double denom = sqrt(1-qw*qw);
outAngleDegrees = angleRadians * 180.0 / M_PI;
axis[0] = qx / denom;
axis[1] = qy / denom;
axis[2] = qz / denom;
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
}
GLCurvesState &state = gCurvesMesh[mesh.name];
if (gGLProgramState.attribs["POSITION"] >= 0) {
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
CheckErrors("curve: vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
CheckErrors("curve: enable vertex attrib array");
}
glDrawArrays(GL_LINES, 0, state.count);
if (gGLProgramState.attribs["POSITION"] >= 0) {
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
}
}
#endif
// Hierarchically draw nodes
static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
@@ -805,22 +656,18 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
glMultMatrixd(node.matrix.data());
} else {
// Assume Trans x Rotate x Scale order
if (node.scale.size() == 3) {
glScaled(node.scale[0], node.scale[1], node.scale[2]);
}
if (node.rotation.size() == 4) {
glRotated(node.rotation[0], node.rotation[1], node.rotation[2],
node.rotation[3]);
}
if (node.translation.size() == 3) {
glTranslated(node.translation[0], node.translation[1],
node.translation[2]);
}
if (node.rotation.size() == 4) {
double angleDegrees;
double axis[3];
QuatToAngleAxis(node.rotation, angleDegrees, axis);
glRotated(angleDegrees, axis[0], axis[1], axis[2]);
}
if (node.scale.size() == 3) {
glScaled(node.scale[0], node.scale[1], node.scale[2]);
}
}
@@ -830,14 +677,10 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
// std::cout << it->first << std::endl;
// FIXME(syoyo): Refactor.
// DrawCurves(scene, it->second);
if (node.mesh > -1) {
assert(node.mesh < model.meshes.size());
DrawMesh(model, model.meshes[node.mesh]);
}
DrawMesh(model, model.meshes[node.mesh]);
// Draw child nodes.
for (size_t i = 0; i < node.children.size(); i++) {
assert(node.children[i] < model.nodes.size());
DrawNode(model, model.nodes[node.children[i]]);
}
@@ -846,19 +689,18 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
static void DrawModel(tinygltf::Model &model) {
#if 0
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
for (; it != itEnd; it++) {
DrawMesh(scene, it->second);
DrawCurves(scene, it->second);
}
for (; it != itEnd; it++) {
DrawMesh(scene, it->second);
DrawCurves(scene, it->second);
}
#else
// If the glTF asset has at least one scene, and doesn't define a default one
// just show the first one we can find
assert(model.scenes.size() > 0);
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
const tinygltf::Scene &scene = model.scenes[scene_to_display];
// TODO(syoyo): Support non-default scenes.
assert(model.defaultScene >= 0);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); i++) {
DrawNode(model, model.nodes[scene.nodes[i]]);
}
@@ -905,8 +747,7 @@ int main(int argc, char **argv) {
#ifdef _WIN32
#ifdef _DEBUG
std::string input_filename(argv[1] ? argv[1]
: "../../../models/Cube/Cube.gltf");
std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf");
#endif
#else
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
@@ -917,8 +758,7 @@ int main(int argc, char **argv) {
bool ret = false;
if (ext.compare("glb") == 0) {
// assume binary glTF.
ret =
loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
} else {
// assume ascii glTF.
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
@@ -939,19 +779,17 @@ int main(int argc, char **argv) {
Init();
// DBG
PrintNodes(model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]);
PrintNodes(model.scenes[model.defaultScene]);
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW." << std::endl;
return -1;
}
std::stringstream ss;
ss << "Simple glTF viewer: " << input_filename;
char title[1024];
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
std::string title = ss.str();
window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
window = glfwCreateWindow(width, height, title, NULL, NULL);
if (window == NULL) {
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();
@@ -980,14 +818,15 @@ int main(int argc, char **argv) {
#ifdef _WIN32
#ifdef _DEBUG
const char *shader_frag_filename = "../shader.frag";
const char *shader_vert_filename = "../shader.vert";
const char *shader_frag_filename = "../shader.frag";
const char *shader_vert_filename = "../shader.vert";
#endif
#else
const char *shader_frag_filename = "shader.frag";
const char *shader_vert_filename = "shader.vert";
#endif
if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) {
return -1;
}

View File

@@ -0,0 +1,6 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define LODEPNG_IMPLEMENTATION
#include "lodepng.h"

View File

@@ -1,3 +1,5 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define LODEPNG_IMPLEMENTATION
#include "lodepng.h"

View File

@@ -9,7 +9,7 @@ newoption {
}
sources = {
"stbi-impl.cc",
"img-loaders.cc",
"main.cc",
"render.cc",
"render-config.cc",

22751
json.hpp

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define LODEPNG_IMPLEMENTATION
#include "tiny_gltf.h"
#include <cstdio>
@@ -175,10 +176,7 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
std::stringstream ss;
ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
}
ss << " ]";
@@ -193,10 +191,7 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
std::stringstream ss;
ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
}
ss << " ]";
@@ -234,8 +229,7 @@ static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
#endif
static std::string PrintValue(const std::string &name,
const tinygltf::Value &value, const int indent,
const bool tag = true) {
const tinygltf::Value &value, const int indent, const bool tag = true) {
std::stringstream ss;
if (value.IsObject()) {
@@ -249,36 +243,36 @@ static std::string PrintValue(const std::string &name,
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<std::string>();
} else {
ss << Indent(indent) << value.Get<std::string>() << " ";
ss << " " << value.Get<std::string>() << " ";
}
} else if (value.IsBool()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<bool>();
} else {
ss << Indent(indent) << value.Get<bool>() << " ";
ss << " " << value.Get<bool>() << " ";
}
} else if (value.IsNumber()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<double>();
} else {
ss << Indent(indent) << value.Get<double>() << " ";
ss << " " << value.Get<double>() << " ";
}
} else if (value.IsInt()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<int>();
} else {
ss << Indent(indent) << value.Get<int>() << " ";
ss << " " << value.Get<int>() << " ";
}
} else if (value.IsArray()) {
// TODO(syoyo): Better pretty printing of array item
ss << Indent(indent) << name << " [ \n";
ss << Indent(indent) << name << " [ ";
for (size_t i = 0; i < value.Size(); i++) {
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
if (i != (value.ArrayLen() - 1)) {
ss << ", \n";
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
if (i != (value.ArrayLen()-1)) {
ss << ", ";
}
}
ss << "\n" << Indent(indent) << "] ";
ss << Indent(indent) << "] ";
}
// @todo { binary }
@@ -322,15 +316,6 @@ static void DumpStringIntMap(const std::map<std::string, int> &m, int indent) {
}
}
static void DumpExtensions(const tinygltf::ExtensionMap &extension,
const int indent) {
// TODO(syoyo): pritty print Value
for (auto &e : extension) {
std::cout << Indent(indent) << e.first << std::endl;
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
}
}
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
std::cout << Indent(indent) << "material : " << primitive.material
<< std::endl;
@@ -342,80 +327,17 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
<< std::endl;
DumpStringIntMap(primitive.attributes, indent + 1);
DumpExtensions(primitive.extensions, indent);
std::cout << Indent(indent) << "extras :" << std::endl
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
if (!primitive.extensions_json_string.empty()) {
std::cout << Indent(indent + 1) << "extensions(JSON string) = "
<< primitive.extensions_json_string << "\n";
}
if (!primitive.extras_json_string.empty()) {
std::cout << Indent(indent + 1)
<< "extras(JSON string) = " << primitive.extras_json_string
<< "\n";
}
}
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
if (!texinfo.extensions_json_string.empty()) {
std::cout << Indent(indent)
<< "extensions(JSON string) = " << texinfo.extensions_json_string
<< "\n";
}
if (!texinfo.extras_json_string.empty()) {
std::cout << Indent(indent)
<< "extras(JSON string) = " << texinfo.extras_json_string << "\n";
}
}
static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpOcclusionTextureInfo(
const tinygltf::OcclusionTextureInfo &texinfo, const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr,
const int indent) {
std::cout << Indent(indent)
<< "baseColorFactor : " << PrintFloatArray(pbr.baseColorFactor)
<< "\n";
std::cout << Indent(indent) << "baseColorTexture :\n";
DumpTextureInfo(pbr.baseColorTexture, indent + 1);
std::cout << Indent(indent) << "metallicFactor : " << pbr.metallicFactor
<< "\n";
std::cout << Indent(indent) << "roughnessFactor : " << pbr.roughnessFactor
<< "\n";
std::cout << Indent(indent) << "metallicRoughnessTexture :\n";
DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1);
DumpExtensions(pbr.extensions, indent + 1);
std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n";
static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
{
// TODO(syoyo): pritty print Value
for (auto &e : extension) {
std::cout << Indent(indent) << e.first << std::endl;
std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
}
}
static void Dump(const tinygltf::Model &model) {
@@ -488,30 +410,6 @@ static void Dump(const tinygltf::Model &model) {
}
std::cout << "]" << std::endl;
}
if (accessor.sparse.isSparse) {
std::cout << Indent(2) << "sparse:" << std::endl;
std::cout << Indent(3) << "count : " << accessor.sparse.count
<< std::endl;
std::cout << Indent(3) << "indices: " << std::endl;
std::cout << Indent(4)
<< "bufferView : " << accessor.sparse.indices.bufferView
<< std::endl;
std::cout << Indent(4)
<< "byteOffset : " << accessor.sparse.indices.byteOffset
<< std::endl;
std::cout << Indent(4) << "componentType: "
<< PrintComponentType(accessor.sparse.indices.componentType)
<< "(" << accessor.sparse.indices.componentType << ")"
<< std::endl;
std::cout << Indent(3) << "values : " << std::endl;
std::cout << Indent(4)
<< "bufferView : " << accessor.sparse.values.bufferView
<< std::endl;
std::cout << Indent(4)
<< "byteOffset : " << accessor.sparse.values.byteOffset
<< std::endl;
}
}
}
@@ -524,7 +422,7 @@ static void Dump(const tinygltf::Model &model) {
<< std::endl;
std::cout << Indent(1) << "channels : [ " << std::endl;
for (size_t j = 0; j < animation.channels.size(); j++) {
for (size_t j = 0; i < animation.channels.size(); i++) {
std::cout << Indent(2)
<< "sampler : " << animation.channels[j].sampler
<< std::endl;
@@ -570,21 +468,6 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2)
<< "target : " << PrintTarget(bufferView.target)
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(bufferView.extensions, 1);
std::cout << PrintValue("extras", bufferView.extras, 2) << std::endl;
if (!bufferView.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< bufferView.extensions_json_string << "\n";
}
if (!bufferView.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << bufferView.extras_json_string
<< "\n";
}
}
}
@@ -595,21 +478,6 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(1) << "name : " << buffer.name << std::endl;
std::cout << Indent(2) << "byteLength : " << buffer.data.size()
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(buffer.extensions, 1);
std::cout << PrintValue("extras", buffer.extras, 2) << std::endl;
if (!buffer.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< buffer.extensions_json_string << "\n";
}
if (!buffer.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << buffer.extras_json_string
<< "\n";
}
}
}
@@ -618,55 +486,16 @@ static void Dump(const tinygltf::Model &model) {
<< std::endl;
for (size_t i = 0; i < model.materials.size(); i++) {
const tinygltf::Material &material = model.materials[i];
std::cout << Indent(1) << "name : " << material.name
<< std::endl;
std::cout << Indent(1) << "alphaMode : " << material.alphaMode
<< std::endl;
std::cout << Indent(1)
<< "alphaCutoff : " << material.alphaCutoff
<< std::endl;
std::cout << Indent(1) << "doubleSided : "
<< (material.doubleSided ? "true" : "false") << std::endl;
std::cout << Indent(1) << "emissiveFactor : "
<< PrintFloatArray(material.emissiveFactor) << std::endl;
std::cout << Indent(1) << "pbrMetallicRoughness :\n";
DumpPbrMetallicRoughness(material.pbrMetallicRoughness, 2);
std::cout << Indent(1) << "normalTexture :\n";
DumpNormalTextureInfo(material.normalTexture, 2);
std::cout << Indent(1) << "occlusionTexture :\n";
DumpOcclusionTextureInfo(material.occlusionTexture, 2);
std::cout << Indent(1) << "emissiveTexture :\n";
DumpTextureInfo(material.emissiveTexture, 2);
std::cout << Indent(1) << "---- legacy material parameter ----\n";
std::cout << Indent(1) << "name : " << material.name << std::endl;
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl;
tinygltf::ParameterMap::const_iterator p(material.values.begin());
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
for (; p != pEnd; p++) {
std::cout << Indent(2) << p->first << ": "
<< PrintParameterValue(p->second) << std::endl;
}
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(material.extensions, 1);
std::cout << PrintValue("extras", material.extras, 2) << std::endl;
if (!material.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< material.extensions_json_string << "\n";
}
if (!material.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << material.extras_json_string
<< "\n";
}
}
}
@@ -690,18 +519,6 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2) << "height : " << image.height << std::endl;
std::cout << Indent(2) << "component : " << image.component << std::endl;
DumpExtensions(image.extensions, 1);
std::cout << PrintValue("extras", image.extras, 2) << std::endl;
if (!image.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< image.extensions_json_string << "\n";
}
if (!image.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << image.extras_json_string
<< "\n";
}
}
}
@@ -714,18 +531,6 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(1) << "source : " << texture.source
<< std::endl;
DumpExtensions(texture.extensions, 1);
std::cout << PrintValue("extras", texture.extras, 2) << std::endl;
if (!texture.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< texture.extensions_json_string << "\n";
}
if (!texture.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << texture.extras_json_string
<< "\n";
}
}
}
@@ -747,20 +552,6 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2)
<< "wrapT : " << PrintWrapMode(sampler.wrapT)
<< std::endl;
DumpExtensions(sampler.extensions, 1);
std::cout << PrintValue("extras", sampler.extras, 2) << std::endl;
if (!sampler.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< sampler.extensions_json_string << "\n";
}
if (!sampler.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << sampler.extras_json_string
<< "\n";
}
}
}
@@ -793,61 +584,12 @@ static void Dump(const tinygltf::Model &model) {
<< "znear : " << camera.orthographic.znear
<< std::endl;
}
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(camera.extensions, 1);
std::cout << PrintValue("extras", camera.extras, 2) << std::endl;
if (!camera.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< camera.extensions_json_string << "\n";
}
if (!camera.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << camera.extras_json_string
<< "\n";
}
}
}
{
std::cout << "skins(items=" << model.skins.size() << ")" << std::endl;
for (size_t i = 0; i < model.skins.size(); i++) {
const tinygltf::Skin &skin = model.skins[i];
std::cout << Indent(1) << "name : " << skin.name << std::endl;
std::cout << Indent(2)
<< "inverseBindMatrices : " << skin.inverseBindMatrices
<< std::endl;
std::cout << Indent(2) << "skeleton : " << skin.skeleton
<< std::endl;
std::cout << Indent(2)
<< "joints : " << PrintIntArray(skin.joints)
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(skin.extensions, 1);
std::cout << PrintValue("extras", skin.extras, 2) << std::endl;
if (!skin.extensions_json_string.empty()) {
std::cout << Indent(2)
<< "extensions(JSON string) = " << skin.extensions_json_string
<< "\n";
}
if (!skin.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << skin.extras_json_string
<< "\n";
}
}
}
// toplevel extensions
{
std::cout << "extensions(items=" << model.extensions.size() << ")"
<< std::endl;
std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
DumpExtensions(model.extensions, 1);
}
}
@@ -858,39 +600,29 @@ int main(int argc, char **argv) {
exit(1);
}
// Store original JSON string for `extras` and `extensions`
bool store_original_json_for_extras_and_extensions = false;
if (argc > 2) {
store_original_json_for_extras_and_extensions = true;
}
tinygltf::Model model;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
std::string warn;
std::string warn;
std::string input_filename(argv[1]);
std::string ext = GetFilePathExtension(input_filename);
gltf_ctx.SetStoreOriginalJSONForExtrasAndExtensions(
store_original_json_for_extras_and_extensions);
bool ret = false;
if (ext.compare("glb") == 0) {
std::cout << "Reading binary glTF" << std::endl;
// assume binary glTF.
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn,
input_filename.c_str());
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
ret =
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
ret = gltf_ctx.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());
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,67 +0,0 @@
{
"scenes": [
{
"nodes": [0]
}
],
"nodes": [
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 1
},
"indices": 0
}
]
}
],
"buffers": [
{
"uri": "simpleTriangle.bin",
"byteLength": 44
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 1e300,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 8,
"byteLength": 36,
"target": 34962
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 3,
"type": "VEC3",
"max": [1, 1, 0],
"min": [0, 0, 0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -1,53 +0,0 @@
{
"scenes": [],
"nodes": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 0
}
]
}
],
"buffers": [
{
"uri": "simpleTriangle.bin",
"byteLength": 44
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
},
{
"buffer": 1,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"images": [
{
"bufferView": 1,
"mimeType": "image/png"
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -1,36 +0,0 @@
{
"scenes": [],
"nodes": [],
"buffers": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 0
}
]
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"accessors": [
{
"bufferView": 1,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -1,36 +0,0 @@
{
"scenes": [],
"nodes": [],
"buffers": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 1
}
]
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"accessors": [
{
"bufferView": 1,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 B

View File

@@ -1,224 +0,0 @@
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
35
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1.000001
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
-0,
-0,
1
],
"min": [
0,
-0,
-1,
-1
],
"type": "VEC4"
},
{
"bufferView": 4,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1
],
"min": [
-1,
-1
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"byteOffset": 0,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"0comment": "Use Cube_MetallicRoughness.png to reduce scene filesize",
"uri": "Cube_MetallicRoughness.png"
},
{
"uri": "Cube_MetallicRoughness.png"
}
],
"materials": [
{
"emissiveTexture": {
"index": 0,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"scale": [
1,
-1
]
}
}
}
},
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"rotation": 1.57079632679,
"scale": [
0.5,
0.5
]
}
}
}
}
}
],
"meshes": [
{
"name": "Cube",
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"samplers": [
{}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

View File

@@ -1,6 +0,0 @@
Added KHR_texture_transform property to Cube scene.
License: Donated by Norbert Nopper for glTF testing.
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

View File

@@ -1,171 +0,0 @@
{
"asset": {
"version": "2.0"
},
"scenes": [
{
"nodes": [
0
]
}
],
"scene": 0,
"nodes": [
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
]
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0,
"texCoord": 0
},
"baseColorFactor": [
1,
1,
1,
1
],
"metallicFactor": 1,
"roughnessFactor": 1
},
"emissiveFactor": [
0,
0,
0
],
"alphaMode": "OPAQUE"
}
],
"textures": [
{
"source": 0,
"sampler": 0
}
],
"samplers": [
{
"wrapS": 33071,
"wrapT": 33071
}
],
"images": [
{
"uri": " 2x2 image has multiple spaces.png"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5121,
"count": 36,
"normalized": false,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
1,
1
],
"min": [
0,
0
],
"type": "VEC2"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 36
},
{
"buffer": 0,
"byteOffset": 36,
"byteLength": 288
},
{
"buffer": 0,
"byteOffset": 324,
"byteLength": 288
},
{
"buffer": 0,
"byteOffset": 612,
"byteLength": 192
}
],
"buffers": [
{
"byteLength": 804,
"uri": "CubeImageUriSpaces.bin"
}
]
}

View File

@@ -1,171 +0,0 @@
{
"asset": {
"version": "2.0"
},
"scenes": [
{
"nodes": [
0
]
}
],
"scene": 0,
"nodes": [
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
]
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0,
"texCoord": 0
},
"baseColorFactor": [
1,
1,
1,
1
],
"metallicFactor": 1,
"roughnessFactor": 1
},
"emissiveFactor": [
0,
0,
0
],
"alphaMode": "OPAQUE"
}
],
"textures": [
{
"source": 0,
"sampler": 0
}
],
"samplers": [
{
"wrapS": 33071,
"wrapT": 33071
}
],
"images": [
{
"uri": "2x2 image has spaces.png"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5121,
"count": 36,
"normalized": false,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"normalized": false,
"max": [
1,
1
],
"min": [
0,
0
],
"type": "VEC2"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 36
},
{
"buffer": 0,
"byteOffset": 36,
"byteLength": 288
},
{
"buffer": 0,
"byteOffset": 324,
"byteLength": 288
},
{
"buffer": 0,
"byteOffset": 612,
"byteLength": 192
}
],
"buffers": [
{
"byteLength": 804,
"uri": "CubeImageUriSpaces.bin"
}
]
}

View File

@@ -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
]
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python
# Assume python 2.6 or 2.7
import glob
import os
import subprocess
@@ -12,7 +14,6 @@ import subprocess
sample_model_dir = "/home/syoyo/work/glTF-Sample-Models"
base_model_dir = os.path.join(sample_model_dir, "2.0")
# Include `glTF-Draco` when you build `loader_example` with draco support.
kinds = [ "glTF", "glTF-Binary", "glTF-Embedded", "glTF-MaterialsCommon"]
# ---------------------------------

View File

@@ -1,46 +0,0 @@
# Fuzzing test
Do fuzzing test for TinyGLTF API.
## Supported API
* [x] LoadASCIIFromMemory
* [ ] LoadBinaryFromMemory
## Requirements
* meson
* clang with fuzzer support(`-fsanitize=fuzzer`. at least clang 8.0 should work)
## Setup
### Ubuntu 18.04
```
$ sudo apt install clang++-8
$ sudo apt install libfuzzer-8-dev
```
Optionally, if you didn't set `update-alternatives` you can set `clang++` to point to `clang++8`
```
$ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 10
$ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 10
```
## How to compile
```
$ CXX=clang++ CC=clang meson build
$ cd build
$ ninja
```
## How to run
Increase memory limit. e.g. `-rss_limit_mb=50000`
```
$ ./fuzz_gltf -rss_limit_mb=20000 -jobs 4
```

View File

@@ -1,33 +0,0 @@
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_IMPLEMENTATION
#include "tiny_gltf.h"
static void parse_intCoding4(const uint8_t *data, size_t size)
{
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
const char *str = reinterpret_cast<const char *>(data);
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, str, size, /* base_dir */"" );
(void)ret;
}
extern "C"
int LLVMFuzzerTestOneInput(std::uint8_t const* data, std::size_t size)
{
parse_intCoding4(data, size);
return 0;
}

View File

@@ -1,9 +0,0 @@
project('fuzz_tinygltf', 'cpp', default_options : ['cpp_std=c++11'])
incdirs = include_directories('../../')
executable('fuzz_gltf',
'fuzz_gltf.cc',
include_directories : incdirs,
cpp_args : '-fsanitize=address,fuzzer',
link_args : '-fsanitize=address,fuzzer' )

View File

@@ -1 +0,0 @@
{"images":[{"uri":"%!QAAAQAAA5"}],"asset":{"version":""}}

View File

@@ -3,9 +3,6 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#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
#include "catch.hpp"
@@ -16,14 +13,6 @@
#include <sstream>
#include <fstream>
static tinygltf::detail::JsonDocument JsonConstruct(const char* str)
{
tinygltf::detail::JsonDocument doc;
tinygltf::detail::JsonParse(doc, str, strlen(str));
return doc;
}
TEST_CASE("parse-error", "[parse]") {
tinygltf::Model model;
@@ -31,7 +20,7 @@ TEST_CASE("parse-error", "[parse]") {
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", static_cast<int>(strlen("bora")), /* basedir*/ "");
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", strlen("bora"), /* basedir*/ "");
REQUIRE(false == ret);
@@ -48,7 +37,7 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
}
@@ -93,941 +82,7 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
REQUIRE(m.materials[0].extensions.size() == 1);
REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
}
}
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]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-primitive-indices.gltf");
REQUIRE_THAT(err,
Catch::Contains("primitive indices accessor out of bounds"));
REQUIRE_FALSE(ret);
}
TEST_CASE("invalid-buffer-view-index", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-buffer-view-index.gltf");
REQUIRE_THAT(err, Catch::Contains("accessor[0] invalid bufferView"));
REQUIRE_FALSE(ret);
}
TEST_CASE("invalid-buffer-index", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-buffer-index.gltf");
REQUIRE_THAT(
err, Catch::Contains("image[0] buffer \"1\" not found in the scene."));
REQUIRE_FALSE(ret);
}
TEST_CASE("glb-invalid-length", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// This glb has a much longer length than the provided data and should fail
// initial range checks.
const unsigned char glb_invalid_length[] = "glTF"
"\x20\x00\x00\x00" "\x6c\x66\x00\x00" //
// | version | length |
"\x02\x00\x00\x00" "\x4a\x53\x4f\x4e{}"; //
// | model length | model format |
bool ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, glb_invalid_length,
sizeof(glb_invalid_length));
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
REQUIRE_FALSE(ret);
}
TEST_CASE("integer-out-of-bounds", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/integer-out-of-bounds.gltf");
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
REQUIRE_FALSE(ret);
}
TEST_CASE("parse-integer", "[bounds-checking]") {
SECTION("parses valid numbers") {
std::string err;
int result = 123;
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"zero\" : 0}"), "zero",
true));
REQUIRE(err == "");
REQUIRE(result == 0);
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": -1234}"), "int",
true));
REQUIRE(err == "");
REQUIRE(result == -1234);
}
SECTION("detects missing properties") {
std::string err;
int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", true));
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
REQUIRE(result == -1);
}
SECTION("handled missing but not required properties") {
std::string err;
int result = -1;
CHECK_FALSE(
tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", false));
REQUIRE(err == "");
REQUIRE(result == -1);
}
SECTION("invalid integers") {
std::string err;
int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
// Excessively large values and NaN aren't allowed either.
err.clear();
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
err.clear();
{
tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::detail::JsonAddMember(o, "int", tinygltf::detail::json(nan));
CHECK_FALSE(tinygltf::ParseIntegerProperty(
&result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
}
}
}
TEST_CASE("parse-unsigned", "[bounds-checking]") {
SECTION("parses valid unsigned integers") {
// Use string-based parsing here, using the initializer list syntax doesn't
// parse 0 as unsigned.
auto zero_obj = JsonConstruct("{\"zero\": 0}");
std::string err;
size_t result = 123;
CHECK(
tinygltf::ParseUnsignedProperty(&result, &err, zero_obj, "zero", true));
REQUIRE(err == "");
REQUIRE(result == 0);
}
SECTION("invalid integers") {
std::string err;
size_t result = -1;
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": -1234}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
// Excessively large values and NaN aren't allowed either.
err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear();
{
tinygltf::detail::JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::detail::JsonAddMember(o, "int", tinygltf::detail::json(nan));
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
&result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
}
}
}
TEST_CASE("parse-integer-array", "[bounds-checking]") {
SECTION("parses valid integers") {
std::string err;
std::vector<int> result;
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
JsonConstruct("{\"x\": [-1, 2, 3]}"), "x", true));
REQUIRE(err == "");
REQUIRE(result.size() == 3);
REQUIRE(result[0] == -1);
REQUIRE(result[1] == 2);
REQUIRE(result[2] == 3);
}
SECTION("invalid integers") {
std::string err;
std::vector<int> result;
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
&result, &err, JsonConstruct("{\"x\": [-1, 1e300, 3]}"), "x", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
}
}
TEST_CASE("pbr-khr-texture-transform", "[material]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/Cube-texture-ext/Cube-textransform.gltf");
REQUIRE(ret == true);
REQUIRE(model.materials.size() == 2);
REQUIRE(model.materials[0].emissiveTexture.extensions.count("KHR_texture_transform") == 1);
REQUIRE(model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].IsObject());
tinygltf::Value::Object &texform = model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].Get<tinygltf::Value::Object>();
REQUIRE(texform.count("scale"));
REQUIRE(texform["scale"].IsArray());
// Note: It looks json.hpp parse integer JSON number as integer, not floating point.
// IsNumber return true either value is int or floating point.
REQUIRE(texform["scale"].Get(0).IsNumber());
REQUIRE(texform["scale"].Get(1).IsNumber());
double scale[2];
scale[0] = texform["scale"].Get(0).GetNumberAsDouble();
scale[1] = texform["scale"].Get(1).GetNumberAsDouble();
REQUIRE(scale[0] == Approx(1.0));
REQUIRE(scale[1] == Approx(-1.0));
}
TEST_CASE("image-uri-spaces", "[issue-236]") {
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Test image file with single spaces.
{
tinygltf::Model model;
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf");
if (!warn.empty()) {
std::cerr << warn << std::endl;
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(warn.empty());
REQUIRE(err.empty());
REQUIRE(model.images.size() == 1);
REQUIRE(model.images[0].uri.find(' ') != std::string::npos);
}
// Test image file with a beginning space, trailing space, and greater than
// one consecutive spaces.
tinygltf::Model model;
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf");
if (!warn.empty()) {
std::cerr << warn << std::endl;
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(warn.empty());
REQUIRE(err.empty());
REQUIRE(model.images.size() == 1);
REQUIRE(model.images[0].uri.size() > 1);
REQUIRE(model.images[0].uri[0] == ' ');
// Test the URI encoding API by saving and re-load the file, without embedding
// the image.
// TODO(syoyo): create temp directory.
{
// Encoder that only replaces spaces with "%20".
auto uriencode = [](const std::string &in_uri,
const std::string &object_type, std::string *out_uri,
void *user_data) -> bool {
(void)user_data;
bool imageOrBuffer = object_type == "image" || object_type == "buffer";
REQUIRE(true == imageOrBuffer);
*out_uri = {};
for (char c : in_uri) {
if (c == ' ')
*out_uri += "%20";
else
*out_uri += c;
}
return true;
};
// Remove the buffer URI, so a new one is generated based on the gltf
// filename and then encoded with the above callback.
model.buffers[0].uri.clear();
tinygltf::URICallbacks uri_cb{uriencode, tinygltf::URIDecode, nullptr};
ctx.SetURICallbacks(uri_cb);
ret = ctx.WriteGltfSceneToFile(&model, " issue-236.gltf", false, false);
REQUIRE(true == ret);
// read back serialized glTF
tinygltf::Model saved;
bool ret = ctx.LoadASCIIFromFile(&saved, &err, &warn, " issue-236.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(err.empty());
REQUIRE(!warn.empty()); // relative image path won't exist in tests/
REQUIRE(saved.images.size() == model.images.size());
// The image uri in CubeImageUriMultipleSpaces.gltf is not encoded and
// should be different after encoding spaces with %20.
REQUIRE(model.images[0].uri != saved.images[0].uri);
// Verify the image path remains the same after uri decoding
std::string image_uri, image_uri_saved;
(void)tinygltf::URIDecode(model.images[0].uri, &image_uri, nullptr);
(void)tinygltf::URIDecode(saved.images[0].uri, &image_uri_saved, nullptr);
REQUIRE(image_uri == image_uri_saved);
// Verify the buffer's generated and encoded URI
REQUIRE(saved.buffers.size() == model.buffers.size());
REQUIRE(saved.buffers[0].uri == "%20issue-236.bin");
}
}
TEST_CASE("serialize-empty-material", "[issue-294]") {
tinygltf::Model m;
// Add default constructed material to model
m.materials.push_back({});
// Serialize model to output stream
std::stringstream os;
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
// Parse serialized model
nlohmann::json j = nlohmann::json::parse(os.str());
// Serialized materials shall hold an empty object that
// represents the default constructed material
REQUIRE(j.find("materials") != j.end());
REQUIRE(j["materials"].is_array());
REQUIRE(1 == j["materials"].size());
CHECK(j["materials"][0].is_object());
CHECK(j["materials"][0].empty());
}
TEST_CASE("empty-skeleton-id", "[issue-321]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/regression/unassigned-skeleton.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(model.skins.size() == 1);
REQUIRE(model.skins[0].skeleton == -1); // unassigned
std::stringstream os;
ret = ctx.WriteGltfSceneToStream(&model, os, false, false);
REQUIRE(true == ret);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
// Ensure `skeleton` property is not written to .gltf(was serialized as -1)
REQUIRE(1 == j["skins"].size());
REQUIRE(j["skins"][0].is_object());
REQUIRE(j["skins"][0].count("skeleton") == 0);
}
#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
TEST_CASE("empty-bin-buffer", "[issue-382]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
tinygltf::Model model_empty;
std::stringstream stream;
bool ret = ctx.WriteGltfSceneToStream(&model_empty, stream, false, true);
REQUIRE(ret == true);
std::string str = stream.str();
const unsigned char* bytes = (unsigned char*)str.data();
ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, bytes, str.size());
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
err.clear();
warn.clear();
tinygltf::Model model_empty_buffer;
model_empty_buffer.buffers.push_back(tinygltf::Buffer());
stream = std::stringstream();
ret = ctx.WriteGltfSceneToStream(&model_empty_buffer, stream, false, true);
REQUIRE(ret == true);
str = stream.str();
bytes = (unsigned char*)str.data();
ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, bytes, str.size());
if (err.empty()) {
std::cerr << "there should have been an error reported" << std::endl;
}
REQUIRE(false == ret);
err.clear();
warn.clear();
tinygltf::Model model_single_byte_buffer;
tinygltf::Buffer buffer;
buffer.data.push_back(0);
model_single_byte_buffer.buffers.push_back(buffer);
stream = std::stringstream();
ret = ctx.WriteGltfSceneToStream(&model_single_byte_buffer, stream, false, true);
REQUIRE(ret == true);
str = stream.str();
{
std::ofstream ofs("tmp.glb");
ofs.write(str.data(), str.size());
}
bytes = (unsigned char*)str.data();
ret = ctx.LoadBinaryFromMemory(&model_single_byte_buffer, &err, &warn, bytes, str.size());
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
}
TEST_CASE("serialize-const-image", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
i.width = 1;
i.height = 1;
i.component = 4;
i.bits = 8;
i.pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
i.image = {255, 255, 255, 255};
i.uri = "image.png";
m.images.push_back(i);
std::stringstream os;
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
REQUIRE(true == ret);
REQUIRE(m.images[0].uri == i.uri);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() != i.uri);
REQUIRE(j["images"][0]["uri"].get<std::string>().rfind("data:", 0) == 0);
}
TEST_CASE("serialize-image-callback", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
i.width = 1;
i.height = 1;
i.bits = 32;
i.image = {255, 255, 255, 255};
i.uri = "foo";
m.images.push_back(i);
std::stringstream os;
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
void *user_pointer) -> bool {
(void)basepath;
(void)image;
(void)uri_cb;
REQUIRE(*filename == "foo");
REQUIRE(embedImages == true);
REQUIRE(user_pointer == (void *)0xba5e1e55);
*out_uri = "bar";
return true;
};
tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55);
bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(true == result);
REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() == "bar");
}
TEST_CASE("serialize-image-failure", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
// Set some data so the ImageWriter callback will be called
i.image = {255, 255, 255, 255};
m.images.push_back(i);
std::stringstream os;
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
void *user_pointer) -> bool {
(void)basepath;
(void)filename;
(void)image;
(void)embedImages;
(void)uri_cb;
(void)out_uri;
(void)user_pointer;
return false;
};
tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55);
bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
REQUIRE(false == result);
REQUIRE(os.str().size() == 0);
}
TEST_CASE("filesize-check", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
ctx.SetMaxExternalFileSize(10); // 10 bytes. will fail to load texture image.
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(false == ret);
}
TEST_CASE("load-issue-416-model", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "issue-416.gltf");
if (!warn.empty()) {
std::cout << "WARN:" << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "ERR:" << err << std::endl;
}
// external file load fails, but reading glTF itself is ok.
REQUIRE(true == ret);
}
TEST_CASE("serialize-empty-node", "[issue-457]") {
tinygltf::Model m;
// Add default constructed node to model
m.nodes.push_back({});
// Add scene to model
m.scenes.push_back({});
// The scene's only node is the empty node
m.scenes.front().nodes.push_back(0);
// Serialize model to output stream
std::stringstream os;
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
// Parse serialized model
nlohmann::json j = nlohmann::json::parse(os.str());
// Serialized nodes shall hold an empty object that
// represents the default constructed node
REQUIRE(j.find("nodes") != j.end());
REQUIRE(j["nodes"].is_array());
REQUIRE(1 == j["nodes"].size());
CHECK(j["nodes"][0].is_object());
CHECK(j["nodes"][0].empty());
// We also want to make sure that the serialized scene
// is referencing the empty node.
// There shall be a single serialized scene
auto scenes = j.find("scenes");
REQUIRE(scenes != j.end());
REQUIRE(scenes->is_array());
REQUIRE(1 == scenes->size());
auto scene = scenes->at(0);
REQUIRE(scene.is_object());
// The scene's nodes array shall hold a reference
// to the single node
auto nodes = scene.find("nodes");
REQUIRE(nodes != scene.end());
REQUIRE(nodes->is_array());
REQUIRE(1 == nodes->size());
auto node = nodes->at(0);
CHECK(node.is_number_integer());
int idx = -1;
node.get_to(idx);
CHECK(0 == idx);
}
TEST_CASE("serialize-light-index", "[issue-458]") {
// Create the light
tinygltf::Light light;
light.type = "point";
light.intensity = 0.75;
light.color = std::vector<double>{1.0, 0.8, 0.95};
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
tinygltf::Scene scene;
// Add the light to the model
m.lights.push_back(light);
// Create a node that uses the light
tinygltf::Node node;
node.light = 0;
// Add the node to the model
m.nodes.push_back(node);
// Add the node to the scene
scene.nodes.push_back(0);
// Add the scene to the model
m.scenes.push_back(scene);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Check if the light was correctly serialized
REQUIRE(1 == m.lights.size());
CHECK(m.lights[0] == light);
// Check that the node properly references the light
REQUIRE(1 == m.nodes.size());
CHECK(m.nodes[0].light == 0);
}
}
TEST_CASE("default-material", "[issue-459]") {
const std::vector<double> default_emissive_factor{ 0.0, 0.0, 0.0 };
const std::vector<double> default_base_color_factor{ 1.0, 1.0, 1.0, 1.0 };
const std::string default_alpha_mode = "OPAQUE";
const double default_alpha_cutoff = 0.5;
const bool default_double_sided = false;
const double default_metallic_factor = 1.0;
const double default_roughness_factor = 1.0;
// Check that default constructed material
// holds actual default GLTF material properties
tinygltf::Material mat;
CHECK(mat.alphaMode == default_alpha_mode);
CHECK(mat.alphaCutoff == default_alpha_cutoff);
CHECK(mat.doubleSided == default_double_sided);
CHECK(mat.emissiveFactor == default_emissive_factor);
CHECK(mat.pbrMetallicRoughness.baseColorFactor == default_base_color_factor);
CHECK(mat.pbrMetallicRoughness.metallicFactor == default_metallic_factor);
CHECK(mat.pbrMetallicRoughness.roughnessFactor == default_roughness_factor);
// None of the textures should be set
CHECK(mat.normalTexture.index == -1);
CHECK(mat.occlusionTexture.index == -1);
CHECK(mat.emissiveTexture.index == -1);
}
TEST_CASE("serialize-empty-scene", "[issue-464]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
// Add empty scene to the model
m.scenes.push_back({});
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure the empty scene is there
REQUIRE(1 == m.scenes.size());
tinygltf::Scene scene{};
// Check that the scene is empty
CHECK(m.scenes[0] == scene);
}
}
TEST_CASE("zero-sized-bin-chunk-glb", "[issue-440]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Input glb has zero-sized data in bin chunk(8 bytes for BIN chunk, and chunksize == 0)
// The spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-buffer says
//
// When the binary buffer is empty or when it is stored by other means, this chunk SHOULD be omitted.
//
// 'SHOULD' mean 'RECOMMENDED', so we'll need to allow such zero-sized bin chunk is NOT omitted.
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/regression/zero-sized-bin-chunk-issue-440.glb");
if (!warn.empty()) {
std::cout << "WARN: " << warn << "\n";
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
}
TEST_CASE("serialize-node-emitter", "[KHR_audio]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
// Create a default audio emitter
m.audioEmitters.resize(1);
// Create a single node
m.nodes.resize(1);
// The node references the single emitter
m.nodes[0].emitter = 0;
// Create a single scene
m.scenes.resize(1);
// Make the scene reference the single node
m.scenes[0].nodes.push_back(0);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure the single scene is there
REQUIRE(1 == m.scenes.size());
// Make sure all three nodes are there
REQUIRE(1 == m.nodes.size());
// Make sure the single root node of the scene is there
REQUIRE(1 == m.scenes[0].nodes.size());
REQUIRE(0 == m.scenes[0].nodes[0]);
// Retrieve the scene root node
const tinygltf::Node& node = m.nodes[m.scenes[0].nodes[0]];
// Make sure the single root node has both lod nodes
REQUIRE(0 == node.emitter);
}
}
TEST_CASE("serialize-lods", "[lods]") {
// Stream to serialize to
std::stringstream os;
{
tinygltf::Model m;
m.nodes.resize(3);
// Add Node 1 and Node 2 as lods to Node 0
m.nodes[0].lods.push_back(1);
m.nodes[0].lods.push_back(2);
// Add Material 1 and Material 2 as lods to Material 0
m.materials.resize(3);
m.materials[0].lods.push_back(1);
m.materials[0].lods.push_back(2);
tinygltf::Scene scene;
// Scene uses Node 0 as root node
scene.nodes.push_back(0);
// Add scene to the model
m.scenes.push_back(scene);
// Serialize model to output stream
tinygltf::TinyGLTF ctx;
bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false);
REQUIRE(true == ret);
}
{
tinygltf::Model m;
tinygltf::TinyGLTF ctx;
// Parse the serialized model
bool ok = ctx.LoadASCIIFromString(&m, nullptr, nullptr, os.str().c_str(), os.str().size(), "");
REQUIRE(true == ok);
// Make sure all three materials are there
REQUIRE(3 == m.materials.size());
// Make sure the first material has both lod materials
REQUIRE(2 == m.materials[0].lods.size());
// Make sure the order is still the same after serialization and deserialization
CHECK(1 == m.materials[0].lods[0]);
CHECK(2 == m.materials[0].lods[1]);
// Make sure the single scene is there
REQUIRE(1 == m.scenes.size());
// Make sure all three nodes are there
REQUIRE(3 == m.nodes.size());
// Make sure the single root node of the scene is there
REQUIRE(1 == m.scenes[0].nodes.size());
REQUIRE(0 == m.scenes[0].nodes[0]);
// Retrieve the scene root node
const tinygltf::Node& node = m.nodes[m.scenes[0].nodes[0]];
// Make sure the single root node has both lod nodes
REQUIRE(2 == node.lods.size());
// Make sure the order is still the same after serialization and deserialization
CHECK(1 == node.lods[0]);
CHECK(2 == node.lods[1]);
}
}

View File

@@ -1,4 +0,0 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
WASI_VERSION=16
WASI_VERSION_FULL=${WASI_VERSION}.0
WASI_SDK_PATH=$(HOME)/local/wasi-sdk-${WASI_VERSION_FULL}
CC=${WASI_SDK_PATH}/bin/clang
CXX=${WASI_SDK_PATH}/bin/clang++
CXXFLAGS=-fno-rtti -fno-exceptions -g -Os
all:
$(CXX) ../loader_example.cc $(CXXFLAGS) -I../

View File

@@ -1,31 +0,0 @@
Experimental WASI/WASM build
## Build
Download wasi-sdk https://github.com/WebAssembly/wasi-sdk
Compile tinygltf without C++ exceptions and threads. See `Makefile` for details
(NOTE: TinyGLTF itself does not use RTTI and threading feature(C++ threads, posix, win32 thread))
## Build examples and Run
Build `loader_example.cc`
```
$ /path/to/wasi-sdk-16.0/bin/clang++ ../loader_example.cc -fno-rtti -fno-exceptions -g -Os -I../ -o loader_example.wasi
```
Tested with wasmtime. https://github.com/bytecodealliance/wasmtime
Set a folder containing .gltf file to `--dir`
```
$ wasmtime --dir=../models loader_example.wasi ../models/Cube/Cube.gltf
```
## Emscripen
T.B.W. ...
EoL.