Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4de57db325 | ||
|
|
a32fa80102 | ||
|
|
5f34dab548 | ||
|
|
0d77a291f7 | ||
|
|
b926195ef8 | ||
|
|
c8ba17fcab | ||
|
|
df39e04e7b | ||
|
|
7319db7a50 | ||
|
|
7ae7110800 | ||
|
|
b864ea7349 | ||
|
|
d6b0b0b990 | ||
|
|
af3ebb2e76 | ||
|
|
105694b468 | ||
|
|
5f9cb24245 | ||
|
|
9fcd3f998e | ||
|
|
d96b45df06 | ||
|
|
dd7c9efbea | ||
|
|
80a85af661 | ||
|
|
7cf2c44ad7 | ||
|
|
f1b5bb12fd | ||
|
|
174334eaf4 | ||
|
|
1212a6ee51 | ||
|
|
8674c60781 | ||
|
|
9d89f02cf0 | ||
|
|
463408c4a0 | ||
|
|
a9d862aeee | ||
|
|
2123da775b | ||
|
|
20806b27d7 | ||
|
|
94fcfdeb9d | ||
|
|
d44b6e7bcc | ||
|
|
9df05806ad | ||
|
|
93db9e20c0 | ||
|
|
2c5597f591 | ||
|
|
2dcf79566f | ||
|
|
f20888ae8b | ||
|
|
5892d3e3ea | ||
|
|
27aab61d62 | ||
|
|
d80f0f9a6c | ||
|
|
5110820ebb | ||
|
|
c3e34c2ff7 | ||
|
|
0ddfaead8f | ||
|
|
ae2cf8e26f | ||
|
|
8b7cdde30c | ||
|
|
764bcb5a8a | ||
|
|
50ada7ff11 | ||
|
|
16fae080f9 | ||
|
|
90c0008b0e | ||
|
|
b572650d26 | ||
|
|
6af9e886cd | ||
|
|
60f97325b1 | ||
|
|
a3595488e3 | ||
|
|
cf60322e73 | ||
|
|
77decfaff8 | ||
|
|
e26117e026 | ||
|
|
33514af61a | ||
|
|
ba3c3c99ef | ||
|
|
8d96b4a14e | ||
|
|
1cef6dcf33 | ||
|
|
e46774940c | ||
|
|
dddaee695d | ||
|
|
a645cfc840 | ||
|
|
040310e0d3 | ||
|
|
d9eddbfeb9 | ||
|
|
10365a53ff | ||
|
|
d0e293fd7d | ||
|
|
3b25d9130a | ||
|
|
db7f4e4d04 | ||
|
|
30bbe0fe3c | ||
|
|
ee3d06646d | ||
|
|
924d86e362 | ||
|
|
68353f1b34 | ||
|
|
05a8d0bc52 | ||
|
|
39a263c2a8 | ||
|
|
61673a62ef | ||
|
|
fdf105645b | ||
|
|
440cb1e66b | ||
|
|
c884e5827e | ||
|
|
7cb31e4e23 | ||
|
|
2bda71c8fb | ||
|
|
13b6402388 | ||
|
|
8eb3904de2 | ||
|
|
b5a72a1ba2 | ||
|
|
0820d83a9d | ||
|
|
641b3ccf8c | ||
|
|
7518334044 | ||
|
|
efc919c022 | ||
|
|
fa0a998a8b | ||
|
|
31cb7f92d8 | ||
|
|
e59dd6a5c0 | ||
|
|
e66d8c992f | ||
|
|
3e53feb046 | ||
|
|
9ec7109089 | ||
|
|
da9eac2fbe | ||
|
|
5cf22e3abc | ||
|
|
a8f0b1c383 | ||
|
|
098dfee982 | ||
|
|
c0cfc1ed95 | ||
|
|
be718436c1 | ||
|
|
18ef338ff5 | ||
|
|
1d0bd6c64f | ||
|
|
e3b3fa9eb6 | ||
|
|
cda38e03ed | ||
|
|
fcdfc71ba6 | ||
|
|
0d0e97e8cd | ||
|
|
dfc3545d79 | ||
|
|
1898f10836 | ||
|
|
96d2f314cd | ||
|
|
fd84ceb791 | ||
|
|
6d38ca3894 | ||
|
|
a6802d10fb | ||
|
|
28dc902368 | ||
|
|
7c8d4ed748 | ||
|
|
a71be9cc98 | ||
|
|
8c29e35b42 | ||
|
|
9f04583280 | ||
|
|
239be2c09f | ||
|
|
39abfb5f91 | ||
|
|
81bbf86e2a | ||
|
|
b2a587af96 | ||
|
|
e6601bfb4b | ||
|
|
90e2c9cc74 | ||
|
|
c0d4d1c50c | ||
|
|
0f282f7e26 | ||
|
|
b3af2f1cf6 | ||
|
|
4769b1ca37 | ||
|
|
0067a9e43a | ||
|
|
57f8e7ca3b | ||
|
|
a48f12d2fc | ||
|
|
a9718668b4 | ||
|
|
b96f6966ab | ||
|
|
7c56f8eb9e | ||
|
|
f6af224135 | ||
|
|
3b735bb878 | ||
|
|
2d17a31d3b | ||
|
|
48f6db0994 | ||
|
|
c89fc5f06b | ||
|
|
1e629c8efe | ||
|
|
341fc31aee | ||
|
|
7b0bbc6570 | ||
|
|
9eae110946 | ||
|
|
fa7022f364 | ||
|
|
6c67da478f | ||
|
|
b97d34cfee | ||
|
|
142aed7499 | ||
|
|
ca80a591e0 | ||
|
|
dc4bb86bf1 | ||
|
|
ef151a4fed | ||
|
|
0894de77f9 | ||
|
|
642a343684 | ||
|
|
719d7e4a74 | ||
|
|
13fd7152ee | ||
|
|
30c5347afe | ||
|
|
841c858bfd | ||
|
|
faa2722f45 | ||
|
|
ae751c4882 | ||
|
|
6a04c87807 | ||
|
|
5210f1539e | ||
|
|
35c798ed28 | ||
|
|
5e379693cb | ||
|
|
a403cd8736 | ||
|
|
246654a15a | ||
|
|
ba28ddcc9e | ||
|
|
8e2c24fb92 | ||
|
|
ba809ff52f | ||
|
|
d1f8bae89c | ||
|
|
70d8b7a42b | ||
|
|
3f1c5a90d3 | ||
|
|
2960379eba | ||
|
|
4ba01f5968 | ||
|
|
cd366ddd1d | ||
|
|
68174a3fb3 | ||
|
|
34c8b60325 | ||
|
|
8d8840f809 | ||
|
|
85b3cbc44d | ||
|
|
ea2b1c5e5d | ||
|
|
d5b0244e2c | ||
|
|
f1cdd1c4cb | ||
|
|
2a15f387bc | ||
|
|
5b8eb9b429 | ||
|
|
67af3c98aa | ||
|
|
580d7c8b9f | ||
|
|
e69069d53c | ||
|
|
d42767e63f | ||
|
|
7d8cbba8e4 | ||
|
|
09d2ff12d8 | ||
|
|
20244e1e4e | ||
|
|
4f0b893d73 | ||
|
|
2d3594de22 | ||
|
|
ff644d82c9 | ||
|
|
f99f760b07 | ||
|
|
4337463c79 | ||
|
|
188965b11e | ||
|
|
179edbf054 | ||
|
|
1e94d05012 | ||
|
|
92000ddeed | ||
|
|
abf4bd1800 | ||
|
|
c14616d21c | ||
|
|
e832baf229 | ||
|
|
df9003ea08 | ||
|
|
ab156c7d18 | ||
|
|
dd45c56927 | ||
|
|
0b01361d15 | ||
|
|
493cad4e64 | ||
|
|
c227c5bddb | ||
|
|
de8e3a6e6b | ||
|
|
a5a03a2d44 | ||
|
|
6cf0228fa7 | ||
|
|
1cd3b0f756 | ||
|
|
0e0a884378 | ||
|
|
8eb0fbb3d4 | ||
|
|
0da2b35085 | ||
|
|
55bff342c2 | ||
|
|
37ba0ae481 | ||
|
|
27ae4ba9c1 | ||
|
|
07e6c5c109 | ||
|
|
0b4f54162b | ||
|
|
db1e8b3e8b | ||
|
|
2b211221c8 | ||
|
|
72f535e198 | ||
|
|
02fce26c6c | ||
|
|
7218e40bfd | ||
|
|
2b10d88e42 | ||
|
|
aad6f06208 | ||
|
|
b62e95f414 | ||
|
|
ffc79a719b | ||
|
|
ce75870894 | ||
|
|
49721f0fd4 | ||
|
|
62da4688af | ||
|
|
365e56b779 | ||
|
|
1baa211450 | ||
|
|
01bf27443e | ||
|
|
7e91e9bb9f | ||
|
|
67f5fbd79e | ||
|
|
a6cbf3d35b | ||
|
|
3903446bfc | ||
|
|
8066a54415 | ||
|
|
3d63a08ce2 | ||
|
|
d868aff1d1 | ||
|
|
6233b2e6bb | ||
|
|
b09d660c38 | ||
|
|
0dca478817 | ||
|
|
b7bf01c679 | ||
|
|
dc07a50ab7 | ||
|
|
6edd3a7f60 | ||
|
|
fac0ad9243 | ||
|
|
58baa51463 | ||
|
|
d095ef53c4 | ||
|
|
9993a71410 | ||
|
|
e64e6d2d2a | ||
|
|
db5b272a1b | ||
|
|
5682cb4542 | ||
|
|
7c54677acd | ||
|
|
b8040e2a19 | ||
|
|
e42ba4e404 | ||
|
|
cc4fd4be8e | ||
|
|
f4fbee1cdf | ||
|
|
088aa0210f | ||
|
|
1340e62848 | ||
|
|
d800c88d09 | ||
|
|
ca8cfee824 | ||
|
|
c9ec1ea7b6 | ||
|
|
adfe936dd3 | ||
|
|
e1e868a704 | ||
|
|
75af411fda | ||
|
|
90ff6f7ce9 | ||
|
|
c81be8f87d | ||
|
|
fb7ebb955e | ||
|
|
c7ae1a3e76 | ||
|
|
d492efc38a | ||
|
|
568f05fec9 | ||
|
|
f8a8d9caa0 | ||
|
|
0d9a495fd1 | ||
|
|
a62e955a52 | ||
|
|
89cd83e22f | ||
|
|
476a8b21b0 | ||
|
|
05e0bf1cdc | ||
|
|
f2aba36638 | ||
|
|
688236a3a8 | ||
|
|
d93364e63f | ||
|
|
e3a7aef197 | ||
|
|
85ed1ac824 | ||
|
|
760c1a5065 | ||
|
|
f0606e83d3 | ||
|
|
8ce4e54394 | ||
|
|
45c29dc54d | ||
|
|
1b482fe0be | ||
|
|
9585391311 | ||
|
|
41fe772058 | ||
|
|
5845319b1a | ||
|
|
1ebd29d84e | ||
|
|
f5318cc759 | ||
|
|
17cfbcc976 | ||
|
|
584f8c0ddf | ||
|
|
3ab8ee1f87 | ||
|
|
daa726ec7c | ||
|
|
5194b47a16 | ||
|
|
b66d68f3fb | ||
|
|
85591954ab | ||
|
|
dac2a89b63 | ||
|
|
660256062b | ||
|
|
87a76e1679 | ||
|
|
6bdd54f709 | ||
|
|
f889d2b0dc | ||
|
|
246d866961 | ||
|
|
06096520b8 | ||
|
|
5307850555 |
+70
@@ -0,0 +1,70 @@
|
||||
# CMake
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
|
||||
#Files created by the CI scripts (downloading and installing premake)
|
||||
premake5
|
||||
premake5.tar.gz
|
||||
|
||||
#built examples
|
||||
/examples/raytrace/bin/
|
||||
|
||||
#visual studio files
|
||||
*.sln
|
||||
*.vcxproj*
|
||||
.vs
|
||||
|
||||
#binary directories
|
||||
bin/
|
||||
obj/
|
||||
|
||||
#runtime gui config
|
||||
imgui.ini
|
||||
|
||||
#visual stuido code
|
||||
.vscode
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
loader_example
|
||||
tests/tester
|
||||
tests/tester_noexcept
|
||||
|
||||
Executable
+10
@@ -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
|
||||
+9
-6
@@ -7,15 +7,15 @@ matrix:
|
||||
sources:
|
||||
- george-edison55-precise-backports
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
- llvm-toolchain-trusty-3.9
|
||||
packages:
|
||||
- g++-4.9
|
||||
- clang-3.7
|
||||
- clang-3.9
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug
|
||||
- addons: *1
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Release
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Release
|
||||
- addons: &2
|
||||
apt:
|
||||
sources:
|
||||
@@ -30,10 +30,10 @@ matrix:
|
||||
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release EXTRA_CXXFLAGS="-fsanitize=address"
|
||||
- addons: *1
|
||||
compiler: clang
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi
|
||||
- ./.travis-before-install.sh
|
||||
|
||||
|
||||
script:
|
||||
@@ -42,3 +42,6 @@ script:
|
||||
- ${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
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
PROJECT (tinygltf)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
ADD_EXECUTABLE ( loader_example
|
||||
loader_example.cc
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
||||
ADD_SUBDIRECTORY ( examples/glview )
|
||||
ADD_SUBDIRECTORY ( examples/validator )
|
||||
|
||||
INSTALL ( FILES
|
||||
json.hpp
|
||||
stb_image.h
|
||||
stb_image_write.h
|
||||
tiny_gltf.h
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
INSTALL ( FILES
|
||||
cmake/TinyGLTFConfig.cmake
|
||||
DESTINATION
|
||||
cmake
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
# Use this for strict compilation check(will work on clang 3.8+)
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -DTINYGLTF_APPLY_CLANG_WEVERYTHING
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat
|
||||
|
||||
all:
|
||||
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
lint:
|
||||
./cpplint.py tiny_gltf_loader.h
|
||||
deps/cpplint.py tiny_gltf.h
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
`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.
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
||||
|
||||
## Status
|
||||
|
||||
Work in process(`devel` branch). Very near to release, but need more tests and examples.
|
||||
v2.0.0 release(22 Aug, 2018)!
|
||||
|
||||
## Builds
|
||||
|
||||
@@ -19,6 +22,9 @@ Work in process(`devel` branch). Very near to release, but need more tests and e
|
||||
* [x] iOS + clang
|
||||
* [x] Linux + gcc/clang
|
||||
* [x] Windows + MinGW
|
||||
* [x] Windows + Visual Studio 2015 Update 3 or later.
|
||||
* Visual Studio 2013 is not supported since they have limited C++11 support and failed to compile `json.hpp`.
|
||||
* [x] Android NDK
|
||||
* [x] Android + CrystaX(NDK drop-in replacement) GCC
|
||||
* [x] Web using Emscripten(LLVM)
|
||||
* Moderate parsing time and memory consumption.
|
||||
@@ -27,29 +33,48 @@ Work in process(`devel` branch). Very near to release, but need more tests and e
|
||||
* [x] Binary glTF(GLB)
|
||||
* [x] PBR material description
|
||||
* Buffers
|
||||
* [x] Parse BASE64 encoded embedded buffer fata(DataURI).
|
||||
* [x] Parse BASE64 encoded embedded buffer data(DataURI).
|
||||
* [x] Load `.bin` file.
|
||||
* Image(Using stb_image)
|
||||
* [x] Parse BASE64 encoded embedded image fata(DataURI).
|
||||
* [x] Parse BASE64 encoded embedded image data(DataURI).
|
||||
* [x] Load external image file.
|
||||
* [x] PNG(8bit only)
|
||||
* [x] JPEG(8bit only)
|
||||
* [x] BMP
|
||||
* [x] GIF
|
||||
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
|
||||
* Load from memory
|
||||
* Custom callback handler
|
||||
* [x] Image load
|
||||
* Extensions
|
||||
* [x] Draco mesh decoding
|
||||
|
||||
## 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.
|
||||
|
||||
## Projects using TinyGLTF
|
||||
|
||||
* px_render Single header C++ Libraries for Thread Scheduling, Rendering, and so on... https://github.com/pplux/px
|
||||
* 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.
|
||||
* Your projects here! (Please send PR)
|
||||
|
||||
## TODOs
|
||||
|
||||
* [ ] Write C++ code generator from json schema for robust parsing.
|
||||
* [x] Serialization
|
||||
* [ ] Compression/decompression(Open3DGC, etc)
|
||||
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
|
||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||
* [x] Load Draco compressed mesh
|
||||
* [x] Save Draco compressed mesh
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] Write tests for `animation` and `skin`
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
* [ ] Skinning
|
||||
* [ ] Morph targets
|
||||
|
||||
## Licenses
|
||||
|
||||
@@ -59,19 +84,22 @@ TinyGLTF uses the following third party libraries.
|
||||
|
||||
* json.hpp : Copyright (c) 2013-2017 Niels Lohmann. MIT license.
|
||||
* base64 : Copyright (C) 2004-2008 René Nyffenegger
|
||||
* stb_image.h : v2.08 - public domain image loader - http://nothings.org/stb_image.h
|
||||
* 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)
|
||||
|
||||
|
||||
## Build and example
|
||||
|
||||
Copy `stb_image.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
||||
Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project.
|
||||
|
||||
### Loading glTF 2.0 model
|
||||
|
||||
```
|
||||
```c++
|
||||
// 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"
|
||||
|
||||
using namespace tinygltf;
|
||||
@@ -79,9 +107,15 @@ using namespace tinygltf;
|
||||
Model model;
|
||||
TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, argv[1]); // for binary glTF(.glb)
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
@@ -92,19 +126,53 @@ if (!ret) {
|
||||
}
|
||||
```
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
## Compile options
|
||||
|
||||
T.B.W.
|
||||
* `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 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.
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
* [ ] Buffers.
|
||||
* [x] To file
|
||||
* [x] Embedded
|
||||
* [ ] Draco compressed?
|
||||
* [x] Images
|
||||
* [x] To file
|
||||
* [x] Embedded
|
||||
* [ ] Binary(.glb)
|
||||
|
||||
## Running tests.
|
||||
|
||||
### Setup
|
||||
### glTF parsing test
|
||||
|
||||
#### Setup
|
||||
|
||||
Python 2.6 or 2.7 required.
|
||||
Git clone https://github.com/KhronosGroup/glTF-Sample-Models to your local dir.
|
||||
|
||||
### Run test
|
||||
#### Run parsing test
|
||||
|
||||
After building `loader_example`, edit `test_runner.py`, then,
|
||||
|
||||
$ python test_runner.py
|
||||
```bash
|
||||
$ python test_runner.py
|
||||
```
|
||||
|
||||
### Unit tests
|
||||
|
||||
```bash
|
||||
$ cd tests
|
||||
$ make
|
||||
$ ./tester
|
||||
$ ./tester_noexcept
|
||||
```
|
||||
|
||||
## 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.
|
||||
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
version: 0.9.{build}
|
||||
|
||||
image:
|
||||
- Visual Studio 2015
|
||||
|
||||
# scripts that runs after repo cloning.
|
||||
install:
|
||||
- vcsetup.bat
|
||||
@@ -10,3 +13,6 @@ configuration: Release
|
||||
build:
|
||||
parallel: true
|
||||
project: TinyGLTFSolution.sln
|
||||
|
||||
after_build:
|
||||
- examples.bat
|
||||
|
||||
@@ -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 ()
|
||||
@@ -0,0 +1,3 @@
|
||||
cd examples\raytrace
|
||||
..\..\tools\windows\premake5.exe vs2015
|
||||
msbuild NanoSGSolution.sln /property:Configuration=Release
|
||||
@@ -0,0 +1,7 @@
|
||||
.vs
|
||||
Debug
|
||||
x64
|
||||
packages
|
||||
|
||||
!*.sln
|
||||
!*.vcxproj*
|
||||
@@ -0,0 +1,21 @@
|
||||
# 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.
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2050
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic", "basic.vcxproj", "{0589AC44-0CF3-40D8-8D89-68393CFD40F3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Debug|x64.Build.0 = Debug|x64
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Debug|x86.Build.0 = Debug|Win32
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Release|x64.ActiveCfg = Release|x64
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Release|x64.Build.0 = Release|x64
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{0589AC44-0CF3-40D8-8D89-68393CFD40F3}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {055E97C4-43DC-41B4-8D61-4FDDBC7B1EF7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid>
|
||||
<RootNamespace>basic</RootNamespace>
|
||||
<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>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<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>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\main.cpp" />
|
||||
<ClCompile Include="..\shaders.cpp" />
|
||||
<ClCompile Include="..\window.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\shaders.h" />
|
||||
<ClInclude Include="..\window.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets" Condition="Exists('packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets')" />
|
||||
<Import Project="packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets" Condition="Exists('packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets')" />
|
||||
<Import Project="packages\glm.0.9.9.200\build\native\glm.targets" Condition="Exists('packages\glm.0.9.9.200\build\native\glm.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets'))" />
|
||||
<Error Condition="!Exists('packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets'))" />
|
||||
<Error Condition="!Exists('packages\glm.0.9.9.200\build\native\glm.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\glm.0.9.9.200\build\native\glm.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\window.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\shaders.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\window.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\shaders.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="glm" version="0.9.9.200" targetFramework="native" />
|
||||
<package id="nupengl.core" version="0.1.0.1" targetFramework="native" />
|
||||
<package id="nupengl.core.redist" version="0.1.0.1" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -0,0 +1,334 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "shaders.h"
|
||||
#include "window.h"
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define TINYGLTF_NOEXCEPTION
|
||||
#define JSON_NOEXCEPTION
|
||||
#include "../../tiny_gltf.h"
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
bool loadModel(tinygltf::Model &model, const char *filename) {
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
|
||||
if (!warn.empty()) {
|
||||
std::cout << "WARN: " << warn << std::endl;
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cout << "ERR: " << err << std::endl;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
std::cout << "Failed to load glTF: " << filename << std::endl;
|
||||
else
|
||||
std::cout << "Loaded glTF: " << filename << std::endl;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
|
||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||
if (bufferView.target == 0) { // TODO impl drawarrays
|
||||
std::cout << "WARN: bufferView.target is zero" << std::endl;
|
||||
continue; // Unsupported bufferView.
|
||||
/*
|
||||
From spec2.0 readme:
|
||||
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
|
||||
... drawArrays function should be used with a count equal to
|
||||
the count property of any of the accessors referenced by the attributes
|
||||
property (they are all equal for a given primitive).
|
||||
*/
|
||||
}
|
||||
|
||||
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
|
||||
std::cout << "bufferview.target " << bufferView.target << std::endl;
|
||||
|
||||
GLuint vbo;
|
||||
glGenBuffers(1, &vbo);
|
||||
vbos[i] = vbo;
|
||||
glBindBuffer(bufferView.target, vbo);
|
||||
|
||||
std::cout << "buffer.data.size = " << buffer.data.size()
|
||||
<< ", bufferview.byteOffset = " << bufferView.byteOffset
|
||||
<< std::endl;
|
||||
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
||||
tinygltf::Primitive primitive = mesh.primitives[i];
|
||||
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
||||
|
||||
for (auto &attrib : primitive.attributes) {
|
||||
tinygltf::Accessor accessor = model.accessors[attrib.second];
|
||||
int byteStride =
|
||||
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
|
||||
|
||||
int size = 1;
|
||||
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
|
||||
size = accessor.type;
|
||||
}
|
||||
|
||||
int vaa = -1;
|
||||
if (attrib.first.compare("POSITION") == 0) vaa = 0;
|
||||
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
|
||||
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
|
||||
if (vaa > -1) {
|
||||
glEnableVertexAttribArray(vaa);
|
||||
glVertexAttribPointer(vaa, size, accessor.componentType,
|
||||
accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
||||
} else
|
||||
std::cout << "vaa missing: " << attrib.first << std::endl;
|
||||
}
|
||||
|
||||
GLuint texid;
|
||||
glGenTextures(1, &texid);
|
||||
|
||||
tinygltf::Texture &tex = model.textures[0];
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, &image.image.at(0));
|
||||
}
|
||||
|
||||
return vbos;
|
||||
}
|
||||
|
||||
// bind models
|
||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
||||
tinygltf::Node &node) {
|
||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||
}
|
||||
}
|
||||
GLuint bindModel(tinygltf::Model &model) {
|
||||
std::map<int, GLuint> vbos;
|
||||
GLuint vao;
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
// cleanup vbos
|
||||
for (size_t i = 0; i < vbos.size(); ++i) {
|
||||
glDeleteBuffers(1, &vbos[i]);
|
||||
}
|
||||
|
||||
return vao;
|
||||
}
|
||||
|
||||
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
||||
tinygltf::Primitive primitive = mesh.primitives[i];
|
||||
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
||||
|
||||
glDrawElements(primitive.mode, indexAccessor.count,
|
||||
indexAccessor.componentType,
|
||||
BUFFER_OFFSET(indexAccessor.byteOffset));
|
||||
}
|
||||
}
|
||||
|
||||
// recursively draw node and children nodes of model
|
||||
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
||||
drawMesh(model, model.meshes[node.mesh]);
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
drawModelNodes(model, model.nodes[node.children[i]]);
|
||||
}
|
||||
}
|
||||
void drawModel(GLuint vao, tinygltf::Model &model) {
|
||||
glBindVertexArray(vao);
|
||||
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||
drawModelNodes(model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void dbgModel(tinygltf::Model &model) {
|
||||
for (auto &mesh : model.meshes) {
|
||||
std::cout << "mesh : " << mesh.name << std::endl;
|
||||
for (auto &primitive : mesh.primitives) {
|
||||
const tinygltf::Accessor &indexAccessor =
|
||||
model.accessors[primitive.indices];
|
||||
|
||||
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
|
||||
<< indexAccessor.componentType << std::endl;
|
||||
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
for (auto &mats : mat.values) {
|
||||
std::cout << "mat : " << mats.first.c_str() << std::endl;
|
||||
}
|
||||
|
||||
for (auto &image : model.images) {
|
||||
std::cout << "image name : " << image.uri << std::endl;
|
||||
std::cout << " size : " << image.image.size() << std::endl;
|
||||
std::cout << " w/h : " << image.width << "/" << image.height
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << "indices : " << primitive.indices << std::endl;
|
||||
std::cout << "mode : "
|
||||
<< "(" << primitive.mode << ")" << std::endl;
|
||||
|
||||
for (auto &attrib : primitive.attributes) {
|
||||
std::cout << "attribute : " << attrib.first.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
|
||||
// Camera matrix
|
||||
glm::mat4 view = glm::lookAt(
|
||||
pos, // Camera in World Space
|
||||
lookat, // and looks at the origin
|
||||
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
|
||||
);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
|
||||
int h) {
|
||||
glm::mat4 Projection =
|
||||
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
|
||||
|
||||
// Or, for an ortho camera :
|
||||
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
|
||||
// // In world coordinates
|
||||
|
||||
glm::mat4 mvp = Projection * view_mat * model_mat;
|
||||
|
||||
return mvp;
|
||||
}
|
||||
|
||||
void displayLoop(Window &window, const std::string &filename) {
|
||||
Shaders shader = Shaders();
|
||||
glUseProgram(shader.pid);
|
||||
|
||||
// grab uniforms to modify
|
||||
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
|
||||
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
|
||||
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
|
||||
|
||||
tinygltf::Model model;
|
||||
if (!loadModel(model, filename.c_str())) return;
|
||||
|
||||
GLuint vao = bindModel(model);
|
||||
// dbgModel(model); return;
|
||||
|
||||
// Model matrix : an identity matrix (model will be at the origin)
|
||||
glm::mat4 model_mat = glm::mat4(1.0f);
|
||||
glm::mat4 model_rot = glm::mat4(1.0f);
|
||||
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
|
||||
|
||||
// generate a camera view, based on eye-position and lookAt world-position
|
||||
glm::mat4 view_mat = genView(glm::vec3(2, 2, 2), model_pos);
|
||||
|
||||
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
|
||||
glm::vec3 sun_color = glm::vec3(1.0);
|
||||
|
||||
while (!window.Close()) {
|
||||
window.Resize();
|
||||
|
||||
glClearColor(0.2, 0.2, 0.2, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glm::mat4 trans =
|
||||
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
|
||||
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
|
||||
glm::vec3(0, 1, 0)); // rotate model on y axis
|
||||
model_mat = trans * model_rot;
|
||||
|
||||
// build a model-view-projection
|
||||
GLint w, h;
|
||||
glfwGetWindowSize(window.window, &w, &h);
|
||||
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
|
||||
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
|
||||
|
||||
glUniform3fv(sun_position_u, 1, &sun_position[0]);
|
||||
glUniform3fv(sun_color_u, 1, &sun_color[0]);
|
||||
|
||||
drawModel(vao, model);
|
||||
glfwSwapBuffers(window.window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string filename = "../../models/Cube/Cube.gltf";
|
||||
|
||||
if (argc > 1) {
|
||||
filename = argv[1];
|
||||
}
|
||||
|
||||
if (!glfwInit()) return -1;
|
||||
|
||||
// Force create 3.3 profile.
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
|
||||
Window window = Window(800, 600, "TinyGLTF basic example");
|
||||
glfwMakeContextCurrent(window.window);
|
||||
|
||||
#ifdef __APPLE__
|
||||
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
|
||||
glewExperimental = GL_TRUE;
|
||||
#endif
|
||||
|
||||
glewInit();
|
||||
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
|
||||
<< std::endl;
|
||||
|
||||
if (!GLEW_VERSION_3_3) {
|
||||
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
displayLoop(window, filename);
|
||||
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
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"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,114 @@
|
||||
#include "shaders.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
std::string FragmentShaderCode =
|
||||
"#version 330 core\n\
|
||||
in vec3 normal;\n\
|
||||
in vec3 position;\n\
|
||||
in vec2 texcoord;\n\
|
||||
\n\
|
||||
uniform sampler2D tex;\n\
|
||||
uniform vec3 sun_position; \n\
|
||||
uniform vec3 sun_color; \n\
|
||||
\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\
|
||||
}\n\
|
||||
";
|
||||
|
||||
std::string VertexShaderCode =
|
||||
"#version 330 core\n\
|
||||
layout(location = 0) in vec3 in_vertex;\n\
|
||||
layout(location = 1) in vec3 in_normal;\n\
|
||||
layout(location = 2) in vec2 in_texcoord;\n\
|
||||
\n\
|
||||
uniform mat4 MVP;\n\
|
||||
\n\
|
||||
out vec3 normal;\n\
|
||||
out vec3 position;\n\
|
||||
out vec2 texcoord;\n\
|
||||
\n\
|
||||
void main(){\n\
|
||||
gl_Position = MVP * vec4(in_vertex, 1);\n\
|
||||
position = gl_Position.xyz;\n\
|
||||
normal = normalize(mat3(MVP) * in_normal);\n\
|
||||
position = in_vertex;\n\
|
||||
texcoord = in_texcoord;\n\
|
||||
}";
|
||||
|
||||
|
||||
Shaders::Shaders()
|
||||
{
|
||||
|
||||
// Create the shaders
|
||||
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
|
||||
GLint Result = GL_FALSE;
|
||||
int InfoLogLength;
|
||||
|
||||
// Compile Vertex Shader
|
||||
char const * VertexSourcePointer = VertexShaderCode.c_str();
|
||||
glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
|
||||
glCompileShader(VertexShaderID);
|
||||
|
||||
// Check Vertex Shader
|
||||
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
||||
if (InfoLogLength > 0) {
|
||||
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
|
||||
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
|
||||
printf("%s\n", &VertexShaderErrorMessage[0]);
|
||||
}
|
||||
|
||||
// Compile Fragment Shader
|
||||
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
|
||||
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
|
||||
glCompileShader(FragmentShaderID);
|
||||
|
||||
// Check Fragment Shader
|
||||
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
||||
if (InfoLogLength > 0) {
|
||||
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
|
||||
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
|
||||
printf("%s\n", &FragmentShaderErrorMessage[0]);
|
||||
}
|
||||
|
||||
// Link the program
|
||||
printf("Linking program\n");
|
||||
GLuint ProgramID = glCreateProgram();
|
||||
glAttachShader(ProgramID, VertexShaderID);
|
||||
glAttachShader(ProgramID, FragmentShaderID);
|
||||
glLinkProgram(ProgramID);
|
||||
|
||||
// Check the program
|
||||
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
|
||||
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
|
||||
if (InfoLogLength > 0) {
|
||||
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
|
||||
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
|
||||
printf("%s\n", &ProgramErrorMessage[0]);
|
||||
}
|
||||
|
||||
glDetachShader(ProgramID, VertexShaderID);
|
||||
glDetachShader(ProgramID, FragmentShaderID);
|
||||
|
||||
glDeleteShader(VertexShaderID);
|
||||
glDeleteShader(FragmentShaderID);
|
||||
|
||||
this->pid = ProgramID;
|
||||
}
|
||||
|
||||
|
||||
Shaders::~Shaders()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
class Shaders
|
||||
{
|
||||
public:
|
||||
GLuint pid;
|
||||
Shaders();
|
||||
~Shaders();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "window.h"
|
||||
|
||||
|
||||
|
||||
Window::Window(int x, int y, const char* title)
|
||||
{
|
||||
GLFWwindow* window = glfwCreateWindow(x, y, title, NULL, NULL);
|
||||
this->window = window;
|
||||
}
|
||||
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
glfwDestroyWindow(this->window);
|
||||
}
|
||||
|
||||
void Window::Resize()
|
||||
{
|
||||
GLint w, h;
|
||||
glfwGetWindowSize(this->window, &w, &h);
|
||||
glViewport(0, 0, w, h);
|
||||
}
|
||||
|
||||
int Window::Close()
|
||||
{
|
||||
return glfwWindowShouldClose(this->window);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
GLFWwindow* window;
|
||||
|
||||
Window(int x, int y, const char* title);
|
||||
~Window();
|
||||
void Resize();
|
||||
int Close();
|
||||
};
|
||||
|
||||
+358
-253
@@ -21,7 +21,9 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include "imgui_internal.h"
|
||||
#include "ImGuizmo.h"
|
||||
|
||||
@@ -65,6 +67,8 @@ namespace ImGuizmo
|
||||
//template <typename T> T LERP(T x, T y, float z) { return (x + (y - x)*z); }
|
||||
template <typename T> T Clamp(T x, T y, T z) { return ((x<y) ? y : ((x>z) ? z : x)); }
|
||||
template <typename T> T max(T x, T y) { return (x > y) ? x : y; }
|
||||
template <typename T> T min(T x, T y) { return (x < y) ? x : y; }
|
||||
template <typename T> bool IsWithin(T x, T y, T z) { return (x>=y) && (x<=z); }
|
||||
|
||||
struct matrix_t;
|
||||
struct vec_t
|
||||
@@ -86,7 +90,7 @@ namespace ImGuizmo
|
||||
vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
|
||||
vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
|
||||
vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }
|
||||
vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
|
||||
vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
|
||||
|
||||
vec_t operator * (float f) const;
|
||||
vec_t operator - () const;
|
||||
@@ -99,7 +103,7 @@ namespace ImGuizmo
|
||||
float LengthSq() const { return (x*x + y*y + z*z); };
|
||||
vec_t Normalize() { (*this) *= (1.f / Length()); return (*this); }
|
||||
vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
|
||||
vec_t Abs() const;
|
||||
vec_t Abs() const;
|
||||
void Cross(const vec_t& v)
|
||||
{
|
||||
vec_t res;
|
||||
@@ -147,7 +151,6 @@ namespace ImGuizmo
|
||||
vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||
vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
|
||||
vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }
|
||||
ImVec2 operator+ (const ImVec2& a, const ImVec2& b) { return ImVec2(a.x + b.x, a.y + b.y); }
|
||||
|
||||
vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }
|
||||
vec_t Cross(const vec_t& v1, const vec_t& v2)
|
||||
@@ -188,7 +191,7 @@ namespace ImGuizmo
|
||||
{
|
||||
vec_t right, up, dir, position;
|
||||
} v;
|
||||
vec_t component[4];
|
||||
vec_t component[4];
|
||||
};
|
||||
|
||||
matrix_t(const matrix_t& other) { memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); }
|
||||
@@ -491,7 +494,7 @@ namespace ImGuizmo
|
||||
SCALE_Y,
|
||||
SCALE_Z,
|
||||
SCALE_XYZ,
|
||||
BOUNDS
|
||||
BOUNDS
|
||||
};
|
||||
|
||||
struct Context
|
||||
@@ -520,6 +523,7 @@ namespace ImGuizmo
|
||||
vec_t mRayOrigin;
|
||||
vec_t mRayVector;
|
||||
|
||||
float mRadiusSquareCenter;
|
||||
ImVec2 mScreenSquareCenter;
|
||||
ImVec2 mScreenSquareMin;
|
||||
ImVec2 mScreenSquareMax;
|
||||
@@ -551,23 +555,25 @@ namespace ImGuizmo
|
||||
bool mBelowPlaneLimit[3];
|
||||
float mAxisFactor[3];
|
||||
|
||||
// bounds stretching
|
||||
vec_t mBoundsPivot;
|
||||
vec_t mBoundsAnchor;
|
||||
vec_t mBoundsPlan;
|
||||
vec_t mBoundsLocalPivot;
|
||||
int mBoundsBestAxis;
|
||||
int mBoundsAxis[2];
|
||||
bool mbUsingBounds;
|
||||
matrix_t mBoundsMatrix;
|
||||
// bounds stretching
|
||||
vec_t mBoundsPivot;
|
||||
vec_t mBoundsAnchor;
|
||||
vec_t mBoundsPlan;
|
||||
vec_t mBoundsLocalPivot;
|
||||
int mBoundsBestAxis;
|
||||
int mBoundsAxis[2];
|
||||
bool mbUsingBounds;
|
||||
matrix_t mBoundsMatrix;
|
||||
|
||||
//
|
||||
int mCurrentOperation;
|
||||
|
||||
float mX = 0.f;
|
||||
float mY = 0.f;
|
||||
float mWidth = 0.f;
|
||||
float mHeight = 0.f;
|
||||
float mX = 0.f;
|
||||
float mY = 0.f;
|
||||
float mWidth = 0.f;
|
||||
float mHeight = 0.f;
|
||||
float mXMax = 0.f;
|
||||
float mYMax = 0.f;
|
||||
};
|
||||
|
||||
static Context gContext;
|
||||
@@ -577,7 +583,11 @@ namespace ImGuizmo
|
||||
|
||||
static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };
|
||||
static const ImU32 directionColor[3] = { 0xFF0000AA, 0xFF00AA00, 0xFFAA0000 };
|
||||
static const ImU32 selectionColor = 0xFF1080FF;
|
||||
|
||||
// Alpha: 100%: FF, 87%: DE, 70%: B3, 54%: 8A, 50%: 80, 38%: 61, 12%: 1F
|
||||
static const ImU32 planeBorderColor[3] = { 0xFFAA0000, 0xFF0000AA, 0xFF00AA00 };
|
||||
static const ImU32 planeColor[3] = { 0x610000AA, 0x6100AA00, 0x61AA0000 };
|
||||
static const ImU32 selectionColor = 0x8A1080FF;
|
||||
static const ImU32 inactiveColor = 0x99999999;
|
||||
static const ImU32 translationLineColor = 0xAAAAAAAA;
|
||||
static const char *translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", "X : %5.3f Y : %5.3f", "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f Z : %5.3f" };
|
||||
@@ -598,18 +608,16 @@ namespace ImGuizmo
|
||||
|
||||
static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat)
|
||||
{
|
||||
//ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
vec_t trans;
|
||||
trans.TransformPoint(worldPos, mat);
|
||||
trans *= 0.5f / trans.w;
|
||||
trans += makeVect(0.5f, 0.5f);
|
||||
trans.y = 1.f - trans.y;
|
||||
trans.x *= gContext.mWidth;
|
||||
trans.y *= gContext.mHeight;
|
||||
trans.x += gContext.mX;
|
||||
trans.y += gContext.mY;
|
||||
return ImVec2(trans.x, trans.y);
|
||||
trans.x *= gContext.mWidth;
|
||||
trans.y *= gContext.mHeight;
|
||||
trans.x += gContext.mX;
|
||||
trans.y += gContext.mY;
|
||||
return ImVec2(trans.x, trans.y);
|
||||
}
|
||||
|
||||
static void ComputeCameraRay(vec_t &rayOrigin, vec_t &rayDir)
|
||||
@@ -619,9 +627,9 @@ namespace ImGuizmo
|
||||
matrix_t mViewProjInverse;
|
||||
mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat);
|
||||
|
||||
float mox = ((io.MousePos.x - gContext.mX) / gContext.mWidth) * 2.f - 1.f;
|
||||
float moy = (1.f - ((io.MousePos.y - gContext.mY) / gContext.mHeight)) * 2.f - 1.f;
|
||||
|
||||
float mox = ((io.MousePos.x - gContext.mX) / gContext.mWidth) * 2.f - 1.f;
|
||||
float moy = (1.f - ((io.MousePos.y - gContext.mY) / gContext.mHeight)) * 2.f - 1.f;
|
||||
|
||||
rayOrigin.Transform(makeVect(mox, moy, 0.f, 1.f), mViewProjInverse);
|
||||
rayOrigin *= 1.f / rayOrigin.w;
|
||||
vec_t rayEnd;
|
||||
@@ -641,23 +649,38 @@ namespace ImGuizmo
|
||||
return -(numer / denom);
|
||||
}
|
||||
|
||||
static bool IsInContextRect( ImVec2 p )
|
||||
{
|
||||
return IsWithin( p.x, gContext.mX, gContext.mXMax ) && IsWithin(p.y, gContext.mY, gContext.mYMax );
|
||||
}
|
||||
|
||||
void SetRect(float x, float y, float width, float height)
|
||||
{
|
||||
gContext.mX = x;
|
||||
gContext.mY = y;
|
||||
gContext.mWidth = width;
|
||||
gContext.mHeight = height;
|
||||
gContext.mX = x;
|
||||
gContext.mY = y;
|
||||
gContext.mWidth = width;
|
||||
gContext.mHeight = height;
|
||||
gContext.mXMax = gContext.mX + gContext.mWidth;
|
||||
gContext.mYMax = gContext.mY + gContext.mXMax;
|
||||
}
|
||||
|
||||
void SetDrawlist()
|
||||
{
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
}
|
||||
|
||||
void BeginFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::Begin("gizmo", NULL, io.DisplaySize, 0, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus);
|
||||
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);
|
||||
ImGui::Begin("gizmo", NULL, flags);
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
bool IsUsing()
|
||||
@@ -673,11 +696,11 @@ namespace ImGuizmo
|
||||
void Enable(bool enable)
|
||||
{
|
||||
gContext.mbEnable = enable;
|
||||
if (!enable)
|
||||
{
|
||||
gContext.mbUsing = false;
|
||||
gContext.mbUsingBounds = false;
|
||||
}
|
||||
if (!enable)
|
||||
{
|
||||
gContext.mbUsing = false;
|
||||
gContext.mbUsingBounds = false;
|
||||
}
|
||||
}
|
||||
|
||||
static float GetUniform(const vec_t& position, const matrix_t& mat)
|
||||
@@ -738,7 +761,8 @@ namespace ImGuizmo
|
||||
{
|
||||
int colorPlaneIndex = (i + 2) % 3;
|
||||
colors[i + 1] = (type == (int)(MOVE_X + i)) ? selectionColor : directionColor[i];
|
||||
colors[i + 4] = (type == (int)(MOVE_XY + i)) ? selectionColor : directionColor[colorPlaneIndex];
|
||||
colors[i + 4] = (type == (int)(MOVE_XY + i)) ? selectionColor : planeColor[colorPlaneIndex];
|
||||
colors[i + 4] = (type == MOVE_SCREEN) ? selectionColor : colors[i + 4];
|
||||
}
|
||||
break;
|
||||
case ROTATE:
|
||||
@@ -751,8 +775,6 @@ namespace ImGuizmo
|
||||
for (int i = 0; i < 3; i++)
|
||||
colors[i + 1] = (type == (int)(SCALE_X + i)) ? selectionColor : directionColor[i];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -848,7 +870,6 @@ namespace ImGuizmo
|
||||
static void DrawRotationGizmo(int type)
|
||||
{
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
//ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// colors
|
||||
ImU32 colors[7];
|
||||
@@ -857,6 +878,7 @@ namespace ImGuizmo
|
||||
vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
|
||||
cameraToModelNormalized.TransformVector(gContext.mModelInverse);
|
||||
|
||||
gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;
|
||||
for (int axis = 0; axis < 3; axis++)
|
||||
{
|
||||
ImVec2 circlePos[halfCircleSegmentCount];
|
||||
@@ -870,9 +892,14 @@ namespace ImGuizmo
|
||||
vec_t pos = makeVect(axisPos[axis], axisPos[(axis+1)%3], axisPos[(axis+2)%3]) * gContext.mScreenFactor;
|
||||
circlePos[i] = worldToPos(pos, gContext.mMVP);
|
||||
}
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2, true);
|
||||
|
||||
float radiusAxis = sqrtf( (ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0]) ));
|
||||
if(radiusAxis > gContext.mRadiusSquareCenter)
|
||||
gContext.mRadiusSquareCenter = radiusAxis;
|
||||
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2);
|
||||
}
|
||||
drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), screenRotateSize * gContext.mHeight, colors[0], 64);
|
||||
drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, 3.f);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
@@ -889,8 +916,8 @@ namespace ImGuizmo
|
||||
pos *= gContext.mScreenFactor;
|
||||
circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
|
||||
}
|
||||
drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF, true);
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2, true);
|
||||
drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF);
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2);
|
||||
|
||||
ImVec2 destinationPosOnScreen = circlePos[1];
|
||||
char tmps[512];
|
||||
@@ -918,9 +945,6 @@ namespace ImGuizmo
|
||||
ImU32 colors[7];
|
||||
ComputeColors(colors, type, SCALE);
|
||||
|
||||
// draw screen cirle
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 12.f, colors[0], 32);
|
||||
|
||||
// draw
|
||||
vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
|
||||
|
||||
@@ -942,17 +966,20 @@ namespace ImGuizmo
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 6.f);
|
||||
drawList->AddCircleFilled(worldDirSSpaceNoScale, 10.f, 0xFF404040);
|
||||
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 3.f);
|
||||
drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, 0xFF404040);
|
||||
}
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
|
||||
drawList->AddCircleFilled(worldDirSSpace, 10.f, colors[i + 1]);
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
|
||||
drawList->AddCircleFilled(worldDirSSpace, 6.f, colors[i + 1]);
|
||||
|
||||
if (gContext.mAxisFactor[i] < 0.f)
|
||||
DrawHatchedAxis(dirPlaneX * scaleDisplay[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// draw screen cirle
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
@@ -978,21 +1005,21 @@ namespace ImGuizmo
|
||||
static void DrawTranslationGizmo(int type)
|
||||
{
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
if (!drawList)
|
||||
return;
|
||||
if (!drawList)
|
||||
return;
|
||||
|
||||
// colors
|
||||
ImU32 colors[7];
|
||||
ComputeColors(colors, type, TRANSLATE);
|
||||
|
||||
// draw screen quad
|
||||
drawList->AddRectFilled(gContext.mScreenSquareMin, gContext.mScreenSquareMax, colors[0], 2.f);
|
||||
|
||||
const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
|
||||
// draw
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
bool belowAxisLimit = false;
|
||||
bool belowPlaneLimit = false;
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
{
|
||||
vec_t dirPlaneX, dirPlaneY;
|
||||
bool belowAxisLimit, belowPlaneLimit;
|
||||
ComputeTripodAxisAndVisibility(i, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
|
||||
|
||||
// draw axis
|
||||
@@ -1001,8 +1028,20 @@ namespace ImGuizmo
|
||||
ImVec2 baseSSpace = worldToPos(dirPlaneX * 0.1f * gContext.mScreenFactor, gContext.mMVP);
|
||||
ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
|
||||
|
||||
// Arrow head begin
|
||||
ImVec2 dir(origin - worldDirSSpace);
|
||||
|
||||
float d = sqrtf(ImLengthSqr(dir));
|
||||
dir /= d; // Normalize
|
||||
dir *= 6.0f;
|
||||
|
||||
ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector
|
||||
ImVec2 a(worldDirSSpace + dir);
|
||||
drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]);
|
||||
// Arrow head end
|
||||
|
||||
if (gContext.mAxisFactor[i] < 0.f)
|
||||
DrawHatchedAxis(dirPlaneX);
|
||||
}
|
||||
@@ -1011,15 +1050,18 @@ namespace ImGuizmo
|
||||
if (belowPlaneLimit)
|
||||
{
|
||||
ImVec2 screenQuadPts[4];
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
|
||||
screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
|
||||
}
|
||||
drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4], true);
|
||||
drawList->AddPolyline(screenQuadPts, 4, planeBorderColor[i], true, 1.0f);
|
||||
drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);
|
||||
}
|
||||
}
|
||||
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
|
||||
@@ -1040,176 +1082,233 @@ namespace ImGuizmo
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanActivate()
|
||||
{
|
||||
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleAndDrawLocalBounds(float *bounds, matrix_t *matrix, float *snapValues)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
|
||||
// compute best projection axis
|
||||
vec_t bestAxisWorldDirection;
|
||||
int bestAxis = gContext.mBoundsBestAxis;
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
|
||||
float bestDot = 0.f;
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
vec_t dirPlaneNormalWorld;
|
||||
dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
|
||||
dirPlaneNormalWorld.Normalize();
|
||||
// compute best projection axis
|
||||
vec_t axesWorldDirections[3];
|
||||
vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
int axes[3];
|
||||
unsigned int numAxes = 1;
|
||||
axes[0] = gContext.mBoundsBestAxis;
|
||||
int bestAxis = axes[0];
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
numAxes = 0;
|
||||
float bestDot = 0.f;
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
vec_t dirPlaneNormalWorld;
|
||||
dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
|
||||
dirPlaneNormalWorld.Normalize();
|
||||
|
||||
float dt = Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld);
|
||||
if (fabsf(dt) >= bestDot)
|
||||
{
|
||||
bestDot = fabsf(dt);
|
||||
bestAxis = i;
|
||||
bestAxisWorldDirection = dirPlaneNormalWorld;
|
||||
}
|
||||
}
|
||||
}
|
||||
float dt = fabsf( Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld) );
|
||||
if ( dt >= bestDot )
|
||||
{
|
||||
bestDot = dt;
|
||||
bestAxis = i;
|
||||
bestAxisWorldDirection = dirPlaneNormalWorld;
|
||||
}
|
||||
|
||||
// corners
|
||||
vec_t aabb[4];
|
||||
if( dt >= 0.1f )
|
||||
{
|
||||
axes[numAxes] = i;
|
||||
axesWorldDirections[numAxes] = dirPlaneNormalWorld;
|
||||
++numAxes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int secondAxis = (bestAxis + 1) % 3;
|
||||
int thirdAxis = (bestAxis + 2) % 3;
|
||||
if( numAxes == 0 )
|
||||
{
|
||||
axes[0] = bestAxis;
|
||||
axesWorldDirections[0] = bestAxisWorldDirection;
|
||||
numAxes = 1;
|
||||
}
|
||||
else if( bestAxis != axes[0] )
|
||||
{
|
||||
unsigned int bestIndex = 0;
|
||||
for (unsigned int i = 0; i < numAxes; i++)
|
||||
{
|
||||
if( axes[i] == bestAxis )
|
||||
{
|
||||
bestIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int tempAxis = axes[0];
|
||||
axes[0] = axes[bestIndex];
|
||||
axes[bestIndex] = tempAxis;
|
||||
vec_t tempDirection = axesWorldDirections[0];
|
||||
axesWorldDirections[0] = axesWorldDirections[bestIndex];
|
||||
axesWorldDirections[bestIndex] = tempDirection;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
aabb[i][3] = aabb[i][bestAxis] = 0.f;
|
||||
aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
|
||||
aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
|
||||
}
|
||||
for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex)
|
||||
{
|
||||
bestAxis = axes[axisIndex];
|
||||
bestAxisWorldDirection = axesWorldDirections[axisIndex];
|
||||
|
||||
// draw bounds
|
||||
unsigned int anchorAlpha = gContext.mbEnable ? 0xFF000000 : 0x80000000;
|
||||
// corners
|
||||
vec_t aabb[4];
|
||||
|
||||
matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
|
||||
for (int i = 0; i < 4;i++)
|
||||
{
|
||||
ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
|
||||
ImVec2 worldBound2 = worldToPos(aabb[(i+1)%4], boundsMVP);
|
||||
float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
|
||||
int stepCount = (int)(boundDistance / 10.f);
|
||||
float stepLength = 1.f / (float)stepCount;
|
||||
for (int j = 0; j < stepCount; j++)
|
||||
{
|
||||
float t1 = (float)j * stepLength;
|
||||
float t2 = (float)j * stepLength + stepLength * 0.5f;
|
||||
ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
|
||||
ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
|
||||
drawList->AddLine(worldBoundSS1, worldBoundSS2, 0xAAAAAA + anchorAlpha, 3.f);
|
||||
}
|
||||
vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4] ) * 0.5f;
|
||||
ImVec2 midBound = worldToPos(midPoint, boundsMVP);
|
||||
static const float AnchorBigRadius = 8.f;
|
||||
static const float AnchorSmallRadius = 6.f;
|
||||
bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
int secondAxis = (bestAxis + 1) % 3;
|
||||
int thirdAxis = (bestAxis + 2) % 3;
|
||||
|
||||
|
||||
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
|
||||
drawList->AddCircleFilled(worldBound1, AnchorBigRadius, bigAnchorColor);
|
||||
drawList->AddCircleFilled(midBound, AnchorSmallRadius, smallAnchorColor);
|
||||
int oppositeIndex = (i + 2) % 4;
|
||||
// big anchor on corners
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && io.MouseDown[0])
|
||||
{
|
||||
gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
gContext.mBoundsAxis[0] = secondAxis;
|
||||
gContext.mBoundsAxis[1] = thirdAxis;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
aabb[i][3] = aabb[i][bestAxis] = 0.f;
|
||||
aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
|
||||
aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
|
||||
}
|
||||
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
|
||||
gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
|
||||
// draw bounds
|
||||
unsigned int anchorAlpha = gContext.mbEnable ? 0xFF000000 : 0x80000000;
|
||||
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
// small anchor on middle of segment
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && io.MouseDown[0])
|
||||
{
|
||||
vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
|
||||
gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
int indices[] = { secondAxis , thirdAxis };
|
||||
gContext.mBoundsAxis[0] = indices[i%2];
|
||||
gContext.mBoundsAxis[1] = -1;
|
||||
matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
|
||||
for (int i = 0; i < 4;i++)
|
||||
{
|
||||
ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
|
||||
ImVec2 worldBound2 = worldToPos(aabb[(i+1)%4], boundsMVP);
|
||||
if( !IsInContextRect( worldBound1 ) || !IsInContextRect( worldBound2 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
|
||||
int stepCount = (int)(boundDistance / 10.f);
|
||||
stepCount = min( stepCount, 1000 );
|
||||
float stepLength = 1.f / (float)stepCount;
|
||||
for (int j = 0; j < stepCount; j++)
|
||||
{
|
||||
float t1 = (float)j * stepLength;
|
||||
float t2 = (float)j * stepLength + stepLength * 0.5f;
|
||||
ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
|
||||
ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
|
||||
drawList->AddLine(worldBoundSS1, worldBoundSS2, 0xAAAAAA + anchorAlpha, 3.f);
|
||||
}
|
||||
vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4] ) * 0.5f;
|
||||
ImVec2 midBound = worldToPos(midPoint, boundsMVP);
|
||||
static const float AnchorBigRadius = 8.f;
|
||||
static const float AnchorSmallRadius = 6.f;
|
||||
bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
|
||||
|
||||
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
|
||||
drawList->AddCircleFilled(worldBound1, AnchorBigRadius, bigAnchorColor);
|
||||
drawList->AddCircleFilled(midBound, AnchorSmallRadius, smallAnchorColor);
|
||||
int oppositeIndex = (i + 2) % 4;
|
||||
// big anchor on corners
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate())
|
||||
{
|
||||
gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
gContext.mBoundsAxis[0] = secondAxis;
|
||||
gContext.mBoundsAxis[1] = thirdAxis;
|
||||
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
}
|
||||
|
||||
if (gContext.mbUsingBounds)
|
||||
{
|
||||
matrix_t scale;
|
||||
scale.SetToIdentity();
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
|
||||
gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
|
||||
|
||||
// compute projected mouse position on plan
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
// small anchor on middle of segment
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate())
|
||||
{
|
||||
vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
|
||||
gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
int indices[] = { secondAxis , thirdAxis };
|
||||
gContext.mBoundsAxis[0] = indices[i%2];
|
||||
gContext.mBoundsAxis[1] = -1;
|
||||
|
||||
// compute a reference and delta vectors base on mouse move
|
||||
vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
|
||||
vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
|
||||
|
||||
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int axisIndex = gContext.mBoundsAxis[i];
|
||||
if (axisIndex == -1)
|
||||
continue;
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
}
|
||||
|
||||
if (gContext.mbUsingBounds)
|
||||
{
|
||||
matrix_t scale;
|
||||
scale.SetToIdentity();
|
||||
|
||||
float ratioAxis = 1.f;
|
||||
vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex].Abs();
|
||||
// compute projected mouse position on plan
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
|
||||
float dtAxis = axisDir.Dot(referenceVector);
|
||||
float boundSize = bounds[axisIndex + 3] - bounds[axisIndex];
|
||||
if (dtAxis > FLT_EPSILON)
|
||||
ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
|
||||
// compute a reference and delta vectors base on mouse move
|
||||
vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
|
||||
vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
|
||||
|
||||
if (snapValues)
|
||||
{
|
||||
float length = boundSize * ratioAxis;
|
||||
ComputeSnap(&length, snapValues[axisIndex]);
|
||||
if (boundSize > FLT_EPSILON)
|
||||
ratioAxis = length / boundSize;
|
||||
}
|
||||
scale.component[axisIndex] *= ratioAxis;
|
||||
}
|
||||
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int axisIndex1 = gContext.mBoundsAxis[i];
|
||||
if (axisIndex1 == -1)
|
||||
continue;
|
||||
|
||||
// transform matrix
|
||||
matrix_t preScale, postScale;
|
||||
preScale.Translation(-gContext.mBoundsLocalPivot);
|
||||
postScale.Translation(gContext.mBoundsLocalPivot);
|
||||
matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
|
||||
*matrix = res;
|
||||
float ratioAxis = 1.f;
|
||||
vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs();
|
||||
|
||||
// info text
|
||||
char tmps[512];
|
||||
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f"
|
||||
, (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
|
||||
, (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
|
||||
, (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
|
||||
);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
|
||||
}
|
||||
float dtAxis = axisDir.Dot(referenceVector);
|
||||
float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1];
|
||||
if (dtAxis > FLT_EPSILON)
|
||||
ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
|
||||
|
||||
if (!io.MouseDown[0])
|
||||
gContext.mbUsingBounds = false;
|
||||
if (snapValues)
|
||||
{
|
||||
float length = boundSize * ratioAxis;
|
||||
ComputeSnap(&length, snapValues[axisIndex1]);
|
||||
if (boundSize > FLT_EPSILON)
|
||||
ratioAxis = length / boundSize;
|
||||
}
|
||||
scale.component[axisIndex1] *= ratioAxis;
|
||||
}
|
||||
|
||||
// transform matrix
|
||||
matrix_t preScale, postScale;
|
||||
preScale.Translation(-gContext.mBoundsLocalPivot);
|
||||
postScale.Translation(gContext.mBoundsLocalPivot);
|
||||
matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
|
||||
*matrix = res;
|
||||
|
||||
// info text
|
||||
char tmps[512];
|
||||
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f"
|
||||
, (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
|
||||
, (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
|
||||
, (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
|
||||
);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
|
||||
}
|
||||
|
||||
if (!io.MouseDown[0])
|
||||
gContext.mbUsingBounds = false;
|
||||
|
||||
if( gContext.mbUsingBounds )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1255,7 +1354,7 @@ namespace ImGuizmo
|
||||
|
||||
vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
|
||||
float dist = deltaScreen.Length();
|
||||
if (dist >= (screenRotateSize - 0.002f) * gContext.mHeight && dist < (screenRotateSize + 0.002f) * gContext.mHeight)
|
||||
if (dist >= (gContext.mRadiusSquareCenter - 1.0f) && dist < (gContext.mRadiusSquareCenter + 1.0f))
|
||||
type = ROTATE_SCREEN;
|
||||
|
||||
const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir};
|
||||
@@ -1327,6 +1426,7 @@ namespace ImGuizmo
|
||||
// move
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
|
||||
@@ -1385,8 +1485,9 @@ namespace ImGuizmo
|
||||
// find new possible way to move
|
||||
vec_t gizmoHitProportion;
|
||||
type = GetMoveType(&gizmoHitProportion);
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.up, -gContext.mCameraDir };
|
||||
@@ -1409,8 +1510,9 @@ namespace ImGuizmo
|
||||
{
|
||||
// find new possible way to scale
|
||||
type = GetScaleType();
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir };
|
||||
@@ -1429,6 +1531,7 @@ namespace ImGuizmo
|
||||
// scale
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
|
||||
@@ -1448,7 +1551,7 @@ namespace ImGuizmo
|
||||
gContext.mScale[axisIndex] = max(ratio, 0.001f);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
|
||||
gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
|
||||
}
|
||||
@@ -1492,14 +1595,15 @@ namespace ImGuizmo
|
||||
if (!gContext.mbUsing)
|
||||
{
|
||||
type = GetRotateType();
|
||||
|
||||
|
||||
if (type == ROTATE_SCREEN)
|
||||
{
|
||||
applyRotationLocaly = true;
|
||||
}
|
||||
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
|
||||
@@ -1523,6 +1627,7 @@ namespace ImGuizmo
|
||||
// rotation
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mRotationAngle = ComputeAngleOnPlan();
|
||||
if (snap)
|
||||
{
|
||||
@@ -1627,41 +1732,41 @@ namespace ImGuizmo
|
||||
int type = NONE;
|
||||
if (gContext.mbEnable)
|
||||
{
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
HandleRotation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
HandleTranslation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case SCALE:
|
||||
HandleScale(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
HandleRotation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
HandleTranslation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case SCALE:
|
||||
HandleScale(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (localBounds && !gContext.mbUsing)
|
||||
HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap);
|
||||
if (localBounds && !gContext.mbUsing)
|
||||
HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap);
|
||||
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
DrawRotationGizmo(type);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
DrawTranslationGizmo(type);
|
||||
break;
|
||||
case SCALE:
|
||||
DrawScaleGizmo(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
DrawRotationGizmo(type);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
DrawTranslationGizmo(type);
|
||||
break;
|
||||
case SCALE:
|
||||
DrawScaleGizmo(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCube(const float *view, const float *projection, float *matrix)
|
||||
@@ -1713,7 +1818,7 @@ namespace ImGuizmo
|
||||
continue;
|
||||
|
||||
// draw face with lighter color
|
||||
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080, true);
|
||||
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,6 +112,9 @@ void EditTransform(const Camera& camera, matrix_t& matrix)
|
||||
|
||||
namespace ImGuizmo
|
||||
{
|
||||
// call inside your own window and before Manipulate() in order to draw gizmo to that window.
|
||||
IMGUI_API void SetDrawlist();
|
||||
|
||||
// call BeginFrame right after ImGui_XXXX_NewFrame();
|
||||
IMGUI_API void BeginFrame();
|
||||
|
||||
|
||||
+6489
-2931
File diff suppressed because it is too large
Load Diff
+854
-458
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
#include "OpenGLWindow/X11OpenGLWindow.h"
|
||||
#endif
|
||||
|
||||
#include <imgui_internal.h>
|
||||
#include <cstdio>
|
||||
|
||||
#define IMGUI_B3G_CONTROL (300)
|
||||
@@ -122,12 +123,12 @@ void ImGui_ImplBtGui_RenderDrawLists(ImDrawData* draw_data) {
|
||||
(GLsizei)last_viewport[3]);
|
||||
}
|
||||
|
||||
static const char* ImGui_ImplBtGui_GetClipboardText() {
|
||||
static const char* ImGui_ImplBtGui_GetClipboardText(void* user_ctx) {
|
||||
// @todo
|
||||
return NULL; // glfwGetClipboardString(g_Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplBtGui_SetClipboardText(const char* text) {
|
||||
static void ImGui_ImplBtGui_SetClipboardText(void* user_ctx, const char* text) {
|
||||
// @todo
|
||||
return;
|
||||
// glfwSetClipboardString(g_Window, text);
|
||||
@@ -259,7 +260,7 @@ bool ImGui_ImplBtGui_Init(b3gDefaultOpenGLWindow* window) {
|
||||
io.SetClipboardTextFn = ImGui_ImplBtGui_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplBtGui_GetClipboardText;
|
||||
#ifdef _WIN32
|
||||
//io.ImeWindowHandle = glfwGetWin32Window(g_Window);
|
||||
// io.ImeWindowHandle = glfwGetWin32Window(g_Window);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@@ -277,7 +278,7 @@ bool ImGui_ImplBtGui_Init(b3gDefaultOpenGLWindow* window) {
|
||||
|
||||
void ImGui_ImplBtGui_Shutdown() {
|
||||
ImGui_ImplBtGui_InvalidateDeviceObjects();
|
||||
ImGui::Shutdown();
|
||||
ImGui::Shutdown(ImGui::GetCurrentContext());
|
||||
}
|
||||
|
||||
void ImGui_ImplBtGui_NewFrame(int mouse_x, int mouse_y) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(gltfutil)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include_directories(../../)
|
||||
|
||||
file(GLOB gltfutil_sources *.cc *.h)
|
||||
add_executable(gltfutil ${gltfutil_sources})
|
||||
|
||||
install ( TARGETS
|
||||
gltfutil
|
||||
DESTINATION
|
||||
bin
|
||||
)
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "texture_dumper.h"
|
||||
|
||||
namespace gltfutil {
|
||||
|
||||
enum class ui_mode { cli, interactive };
|
||||
enum class cli_action { not_set, help, dump };
|
||||
enum class FileType { Ascii, Binary, Unknown };
|
||||
|
||||
/// Probe inside the file, or check the extension to determine if we have to
|
||||
/// load a text file, or a binary file
|
||||
FileType detectType(const std::string& path) {
|
||||
// Quickly open the file as binary and chekc if there's the gltf binary magic
|
||||
// number
|
||||
{
|
||||
auto probe = std::ifstream(path, std::ios_base::binary);
|
||||
if (!probe) throw std::runtime_error("Could not open " + path);
|
||||
|
||||
std::array<char, 5> buffer;
|
||||
for (size_t i{0}; i < 4; ++i) probe >> buffer[i];
|
||||
buffer[4] = 0;
|
||||
|
||||
if (std::string("glTF") == std::string(buffer.data())) {
|
||||
std::cout
|
||||
<< "Detected binary file thanks to the magic number at the start!\n";
|
||||
return FileType::Binary;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have any better, check the file extension.
|
||||
auto extension = path.substr(path.find_last_of('.') + 1);
|
||||
std::transform(std::begin(extension), std::end(extension),
|
||||
std::begin(extension),
|
||||
[](char c) { return char(::tolower(int(c))); });
|
||||
if (extension == "gltf") return FileType::Ascii;
|
||||
if (extension == "glb") return FileType::Binary;
|
||||
|
||||
return FileType::Unknown;
|
||||
}
|
||||
|
||||
struct configuration {
|
||||
std::string input_path, output_dir;
|
||||
ui_mode mode;
|
||||
cli_action action = cli_action::not_set;
|
||||
texture_dumper::texture_output_format requested_format =
|
||||
texture_dumper::texture_output_format::not_specified;
|
||||
|
||||
bool has_output_dir;
|
||||
bool is_valid() {
|
||||
// TODO impl check
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gltfutil
|
||||
@@ -0,0 +1,124 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gltfuilconfig.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
namespace gltfutil {
|
||||
int usage(int ret = 0) {
|
||||
using std::cout;
|
||||
cout << "gltfutil: tool for manipulating gltf files\n"
|
||||
<< " usage information:\n\n"
|
||||
<< "\t gltfutil (-d|-h|) (-f [png|bmp|tga]) [path to .gltf/glb] (-o "
|
||||
"[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"
|
||||
<< "\t\t -o: ouptput directory path"
|
||||
<< "\t\t -h: print this help\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
int arg_error() {
|
||||
(void)usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int parse_args(int argc, char** argv) {
|
||||
gltfutil::configuration config;
|
||||
|
||||
for (size_t i = 1; i < size_t(argc); ++i) {
|
||||
char* arg = argv[i];
|
||||
if (arg[0] == '-') switch (arg[1]) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
break;
|
||||
case 'd':
|
||||
config.mode = ui_mode::cli;
|
||||
config.action = cli_action::dump;
|
||||
break;
|
||||
case 'i':
|
||||
config.mode = ui_mode::interactive;
|
||||
break;
|
||||
case 'o':
|
||||
i++;
|
||||
config.output_dir = argv[i];
|
||||
break;
|
||||
case 'f':
|
||||
i++;
|
||||
config.requested_format =
|
||||
texture_dumper::get_fromat_from_string(argv[i]);
|
||||
break;
|
||||
default:
|
||||
return arg_error();
|
||||
}
|
||||
else {
|
||||
// set the input path
|
||||
config.input_path = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (config.is_valid()) {
|
||||
tinygltf::TinyGLTF loader;
|
||||
tinygltf::Model model;
|
||||
std::string error;
|
||||
std::string warning;
|
||||
bool state;
|
||||
switch (detectType(config.input_path)) {
|
||||
case FileType::Ascii:
|
||||
state = loader.LoadASCIIFromFile(&model, &error, &warning, config.input_path);
|
||||
break;
|
||||
case FileType::Binary:
|
||||
state = loader.LoadBinaryFromFile(&model, &error, &warning, config.input_path);
|
||||
break;
|
||||
case FileType::Unknown:
|
||||
default:
|
||||
return arg_error();
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "state is " << state << '\n';
|
||||
|
||||
if (config.mode == ui_mode::interactive) {
|
||||
// interactive usage now;
|
||||
// TODO impl
|
||||
} else {
|
||||
switch (config.action) {
|
||||
case cli_action::help:
|
||||
return usage();
|
||||
break;
|
||||
|
||||
case cli_action::dump: {
|
||||
texture_dumper dumper(model);
|
||||
if (config.requested_format !=
|
||||
texture_dumper::texture_output_format::not_specified)
|
||||
dumper.set_output_format(config.requested_format);
|
||||
|
||||
if (config.output_dir.empty())
|
||||
dumper.dump_to_folder();
|
||||
else
|
||||
dumper.dump_to_folder(config.output_dir);
|
||||
|
||||
} break;
|
||||
default:
|
||||
return arg_error();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return arg_error();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace gltfutil
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 1) return gltfutil::usage();
|
||||
if (argc > 1) return gltfutil::parse_args(argc, argv);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "stb_image_write.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
using namespace gltfutil;
|
||||
using namespace tinygltf;
|
||||
using std::cout;
|
||||
|
||||
texture_dumper::texture_dumper(const Model& input)
|
||||
: model(input), configured_format(texture_output_format::png) {
|
||||
cout << "Texture dumper\n";
|
||||
}
|
||||
|
||||
void texture_dumper::dump_to_folder(const std::string& path) {
|
||||
cout << "dumping to folder " << path << '\n';
|
||||
cout << "model file has " << model.textures.size() << " textures.\n";
|
||||
size_t index = 0;
|
||||
|
||||
for (const auto& texture : model.textures) {
|
||||
index++;
|
||||
const auto& image = model.images[texture.source];
|
||||
cout << "image name is: \"" << image.name << "\"\n";
|
||||
cout << "image size is: " << image.width << 'x' << image.height << '\n';
|
||||
cout << "pixel channel count :" << image.component << '\n';
|
||||
std::string name = image.name.empty() ? std::to_string(index) : image.name;
|
||||
|
||||
switch (configured_format) {
|
||||
case texture_output_format::png:
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void texture_dumper::set_output_format(texture_output_format format) {
|
||||
configured_format = format;
|
||||
}
|
||||
|
||||
texture_dumper::texture_output_format texture_dumper::get_fromat_from_string(
|
||||
const std::string& str) {
|
||||
std::string type = str;
|
||||
std::transform(str.begin(), str.end(), type.begin(), ::tolower);
|
||||
|
||||
if (type == "png") return texture_output_format::png;
|
||||
if (type == "bmp") return texture_output_format::bmp;
|
||||
if (type == "tga") return texture_output_format::tga;
|
||||
|
||||
return texture_output_format::not_specified;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
namespace gltfutil {
|
||||
class texture_dumper {
|
||||
public:
|
||||
enum class texture_output_format { png, bmp, tga, not_specified };
|
||||
|
||||
private:
|
||||
const tinygltf::Model& model;
|
||||
texture_output_format configured_format;
|
||||
|
||||
public:
|
||||
texture_dumper(const tinygltf::Model& inputModel);
|
||||
void dump_to_folder(const std::string& path = "./");
|
||||
void set_output_format(texture_output_format format);
|
||||
|
||||
static texture_output_format get_fromat_from_string(const std::string& str);
|
||||
};
|
||||
} // namespace gltfutil
|
||||
@@ -0,0 +1,7 @@
|
||||
.vs
|
||||
Debug
|
||||
x64
|
||||
packages
|
||||
|
||||
!*.sln
|
||||
!*.vcxproj*
|
||||
@@ -0,0 +1,67 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
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 )
|
||||
|
||||
if (APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
find_library(COREVIDEO_LIBRARY CoreVideo)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
else ()
|
||||
if (NOT WIN32)
|
||||
# This means it is Unices
|
||||
set ( GLFW3_UNIX_LINK_LIBRARIES X11 Xxf86vm Xrandr Xi Xinerama Xcursor )
|
||||
find_package (Threads)
|
||||
endif()
|
||||
endif (APPLE)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
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 ()
|
||||
|
||||
include_directories(
|
||||
../../
|
||||
../common
|
||||
# ${OPENGL_INCLUDE_DIR}
|
||||
${GLEW_INCLUDE_DIR}
|
||||
${GLFW3_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_executable(glview
|
||||
glview.cc
|
||||
../common/trackball.cc
|
||||
)
|
||||
|
||||
target_link_libraries ( glview
|
||||
${DRACO_LIBRARY}
|
||||
${GLFW3_UNIX_LINK_LIBRARIES}
|
||||
${GLEW_LIBRARY}
|
||||
${GLFW3_glfw_LIBRARY}
|
||||
${OPENGL_gl_LIBRARY}
|
||||
${OPENGL_glu_LIBRARY}
|
||||
${COCOA_LIBRARY}
|
||||
${COREVIDEO_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${CMAKE_DL_LIBS}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
install ( TARGETS
|
||||
glview
|
||||
DESTINATION
|
||||
bin
|
||||
)
|
||||
@@ -2,9 +2,11 @@ Simple OpenGL viewer for glTF geometry.
|
||||
|
||||
## Requirements
|
||||
|
||||
* premake4 : Requires recent `premake4` for macosx and linux, `premake5` for windows.
|
||||
* premake5 : Requires recent `premake5`(alpha12 or later) for macosx and linux. `premake5` for windows is included in `$tinygltf/tools/window` directory.
|
||||
* GLEW
|
||||
* Ubuntu 16.04: sudo apt install libglew-dev
|
||||
* glfw3
|
||||
* Ubuntu 16.04: sudo apt install libglfw3-dev
|
||||
|
||||
### MacOSX and Linux
|
||||
|
||||
@@ -17,7 +19,7 @@ Simple OpenGL viewer for glTF geometry.
|
||||
|
||||
### Windows(not tested well)
|
||||
|
||||
Edit glew and glfw path in `premake4.lua`, then
|
||||
Edit glew and glfw path in `premake5.lua`, then
|
||||
|
||||
> premake5.exe vs2013
|
||||
|
||||
@@ -25,6 +27,17 @@ 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
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#-*-cmake-*-
|
||||
#
|
||||
# yue.nicholas@gmail.com
|
||||
#
|
||||
# This auxiliary CMake file helps in find the glfw3 headers and libraries
|
||||
#
|
||||
# GLFW3_FOUND set if glfw3 is found.
|
||||
# GLFW3_INCLUDE_DIR glfw3's include directory
|
||||
# GLFW3_LIBRARY_DIR glfw3's library directory
|
||||
# GLFW3_LIBRARIES all glfw3 libraries
|
||||
|
||||
FIND_PACKAGE (Threads)
|
||||
|
||||
FIND_PACKAGE ( PackageHandleStandardArgs )
|
||||
|
||||
FIND_PATH( GLFW3_LOCATION include/GLFW/glfw3.h
|
||||
"$ENV{GLFW3_HOME}"
|
||||
)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS ( GLFW3
|
||||
REQUIRED_VARS GLFW3_LOCATION
|
||||
)
|
||||
|
||||
IF (GLFW3_FOUND)
|
||||
SET( GLFW3_INCLUDE_DIR "${GLFW3_LOCATION}/include" CACHE STRING "GLFW3 include path")
|
||||
IF (GLFW3_USE_STATIC_LIBS)
|
||||
FIND_LIBRARY ( GLFW3_glfw_LIBRARY libglfw3.a ${GLFW3_LOCATION}/lib
|
||||
)
|
||||
ELSE (GLFW3_USE_STATIC_LIBS)
|
||||
# On windows build, we need to look for glfw3
|
||||
IF (WIN32)
|
||||
SET ( GLFW3_LIBRARY_NAME glfw3 )
|
||||
ELSE ()
|
||||
SET ( GLFW3_LIBRARY_NAME glfw )
|
||||
ENDIF()
|
||||
FIND_LIBRARY ( GLFW3_glfw_LIBRARY ${GLFW3_LIBRARY_NAME} ${GLFW3_LOCATION}/lib
|
||||
)
|
||||
ENDIF (GLFW3_USE_STATIC_LIBS)
|
||||
|
||||
IF (APPLE)
|
||||
FIND_LIBRARY ( COCOA_LIBRARY Cocoa )
|
||||
FIND_LIBRARY ( IOKIT_LIBRARY IOKit )
|
||||
FIND_LIBRARY ( COREVIDEO_LIBRARY CoreVideo )
|
||||
ELSEIF (UNIX AND NOT APPLE)
|
||||
SET ( GLFW3_REQUIRED_X11_LIBRARIES
|
||||
X11
|
||||
Xi
|
||||
Xrandr
|
||||
Xinerama
|
||||
Xcursor
|
||||
Xxf86vm
|
||||
m
|
||||
${CMAKE_DL_LIBS}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
ENDIF ()
|
||||
|
||||
SET ( GLFW3_LIBRARIES
|
||||
${OPENGL_gl_LIBRARY}
|
||||
${OPENGL_glu_LIBRARY}
|
||||
${GLFW3_glfw_LIBRARY}
|
||||
# UNIX
|
||||
${GLFW3_REQUIRED_X11_LIBRARIES}
|
||||
# APPLE
|
||||
${COCOA_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${COREVIDEO_LIBRARY}
|
||||
CACHE STRING "GLFW3 required libraries"
|
||||
)
|
||||
|
||||
ENDIF ()
|
||||
+57
-12
@@ -12,11 +12,22 @@
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../common/trackball.h"
|
||||
#else
|
||||
#include "trackball.h"
|
||||
#endif
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "../../tiny_gltf.h"
|
||||
#else
|
||||
#include "tiny_gltf.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
@@ -546,9 +557,12 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
(it->first.compare("NORMAL") == 0) ||
|
||||
(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]);
|
||||
assert(byteStride != -1);
|
||||
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
|
||||
accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
model.bufferViews[accessor.bufferView].byteStride,
|
||||
byteStride,
|
||||
BUFFER_OFFSET(accessor.byteOffset));
|
||||
CheckErrors("vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
|
||||
@@ -663,10 +677,14 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
// std::cout << it->first << std::endl;
|
||||
// FIXME(syoyo): Refactor.
|
||||
// DrawCurves(scene, it->second);
|
||||
DrawMesh(model, model.meshes[node.mesh]);
|
||||
if (node.mesh > -1) {
|
||||
assert(node.mesh < model.meshes.size());
|
||||
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]]);
|
||||
}
|
||||
|
||||
@@ -717,8 +735,8 @@ static void PrintNodes(const tinygltf::Scene &scene) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cout << "glview input.gltf <scale>\n" << std::endl;
|
||||
return 0;
|
||||
std::cout << "glview input.gltf <scale>" << std::endl;
|
||||
std::cout << "defaulting to example cube model" << std::endl;
|
||||
}
|
||||
|
||||
float scale = 1.0f;
|
||||
@@ -729,16 +747,29 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string warn;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
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");
|
||||
#endif
|
||||
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, input_filename.c_str());
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str());
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
}
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
@@ -759,10 +790,12 @@ int main(int argc, char **argv) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char title[1024];
|
||||
sprintf(title, "Simple glTF viewer: %s", input_filename.c_str());
|
||||
std::stringstream ss;
|
||||
ss << "Simple glTF viewer: " << input_filename;
|
||||
|
||||
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
std::string title = ss.str();
|
||||
|
||||
window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
|
||||
if (window == NULL) {
|
||||
std::cerr << "Failed to open GLFW window. " << std::endl;
|
||||
glfwTerminate();
|
||||
@@ -788,12 +821,24 @@ int main(int argc, char **argv) {
|
||||
reshapeFunc(window, width, height);
|
||||
|
||||
GLuint vertId = 0, fragId = 0, progId = 0;
|
||||
if (false == LoadShader(GL_VERTEX_SHADER, vertId, "shader.vert")) {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _DEBUG
|
||||
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;
|
||||
}
|
||||
CheckErrors("load vert shader");
|
||||
|
||||
if (false == LoadShader(GL_FRAGMENT_SHADER, fragId, "shader.frag")) {
|
||||
if (false == LoadShader(GL_FRAGMENT_SHADER, fragId, shader_frag_filename)) {
|
||||
return -1;
|
||||
}
|
||||
CheckErrors("load frag shader");
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2050
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glview", "glview\glview.vcxproj", "{D078BB24-377E-497B-8045-03AF2A0547ED}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Debug|x64.Build.0 = Debug|x64
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Debug|x86.Build.0 = Debug|Win32
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Release|x64.ActiveCfg = Release|x64
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Release|x64.Build.0 = Release|x64
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Release|x86.ActiveCfg = Release|Win32
|
||||
{D078BB24-377E-497B-8045-03AF2A0547ED}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DB7C2F91-06C9-4BD8-95BF-04814E0C62DA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{D078BB24-377E-497B-8045-03AF2A0547ED}</ProjectGuid>
|
||||
<RootNamespace>glview</RootNamespace>
|
||||
<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>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<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>v141</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib;glu32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib;glu32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib;glu32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);opengl32.lib;glu32.lib</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\trackball.cc" />
|
||||
<ClCompile Include="..\glview.cc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets" Condition="Exists('..\packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets')" />
|
||||
<Import Project="..\packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets" Condition="Exists('..\packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\nupengl.core.redist.0.1.0.1\build\native\nupengl.core.redist.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\nupengl.core.0.1.0.1\build\native\nupengl.core.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\glview.cc">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\trackball.cc">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="nupengl.core" version="0.1.0.1" targetFramework="native" />
|
||||
<package id="nupengl.core.redist" version="0.1.0.1" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -7,10 +7,11 @@ solution "glview"
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
files { "glview.cc", "trackball.cc" }
|
||||
cppdialect "C++11"
|
||||
files { "glview.cc", "../common/trackball.cc" }
|
||||
includedirs { "./" }
|
||||
includedirs { "../../" }
|
||||
flags "c++11"
|
||||
includedirs { "../common/" }
|
||||
|
||||
configuration { "linux" }
|
||||
linkoptions { "`pkg-config --libs glfw3`" }
|
||||
@@ -34,9 +35,10 @@ solution "glview"
|
||||
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols", "ExtraWarnings"}
|
||||
symbols "On"
|
||||
warnings "Extra"
|
||||
|
||||
configuration "Release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize", "ExtraWarnings"}
|
||||
|
||||
optimize "On"
|
||||
warnings "Extra"
|
||||
@@ -1,292 +0,0 @@
|
||||
/*
|
||||
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
|
||||
* ALL RIGHTS RESERVED
|
||||
* Permission to use, copy, modify, and distribute this software for
|
||||
* any purpose and without fee is hereby granted, provided that the above
|
||||
* copyright notice appear in all copies and that both the copyright notice
|
||||
* and this permission notice appear in supporting documentation, and that
|
||||
* the name of Silicon Graphics, Inc. not be used in advertising
|
||||
* or publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission.
|
||||
*
|
||||
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
|
||||
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
|
||||
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
|
||||
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
|
||||
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
|
||||
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
|
||||
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* US Government Users Restricted Rights
|
||||
* Use, duplication, or disclosure by the Government is subject to
|
||||
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
|
||||
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
|
||||
* clause at DFARS 252.227-7013 and/or in similar or successor
|
||||
* clauses in the FAR or the DOD or NASA FAR Supplement.
|
||||
* Unpublished-- rights reserved under the copyright laws of the
|
||||
* United States. Contractor/manufacturer is Silicon Graphics,
|
||||
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
|
||||
*
|
||||
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
* Trackball code:
|
||||
*
|
||||
* Implementation of a virtual trackball.
|
||||
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
|
||||
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
|
||||
*
|
||||
* Vector manip code:
|
||||
*
|
||||
* Original code from:
|
||||
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
|
||||
*
|
||||
* Much mucking with by:
|
||||
* Gavin Bell
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "trackball.h"
|
||||
|
||||
/*
|
||||
* This size should really be based on the distance from the center of
|
||||
* rotation to the point on the object underneath the mouse. That
|
||||
* point would then track the mouse as closely as possible. This is a
|
||||
* simple example, though, so that is left as an Exercise for the
|
||||
* Programmer.
|
||||
*/
|
||||
#define TRACKBALLSIZE (0.8)
|
||||
|
||||
/*
|
||||
* Local function prototypes (not defined in trackball.h)
|
||||
*/
|
||||
static float tb_project_to_sphere(float, float, float);
|
||||
static void normalize_quat(float[4]);
|
||||
|
||||
static void vzero(float *v) {
|
||||
v[0] = 0.0;
|
||||
v[1] = 0.0;
|
||||
v[2] = 0.0;
|
||||
}
|
||||
|
||||
static void vset(float *v, float x, float y, float z) {
|
||||
v[0] = x;
|
||||
v[1] = y;
|
||||
v[2] = z;
|
||||
}
|
||||
|
||||
static void vsub(const float *src1, const float *src2, float *dst) {
|
||||
dst[0] = src1[0] - src2[0];
|
||||
dst[1] = src1[1] - src2[1];
|
||||
dst[2] = src1[2] - src2[2];
|
||||
}
|
||||
|
||||
static void vcopy(const float *v1, float *v2) {
|
||||
register int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
v2[i] = v1[i];
|
||||
}
|
||||
|
||||
static void vcross(const float *v1, const float *v2, float *cross) {
|
||||
float temp[3];
|
||||
|
||||
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
|
||||
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
|
||||
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
|
||||
vcopy(temp, cross);
|
||||
}
|
||||
|
||||
static float vlength(const float *v) {
|
||||
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
}
|
||||
|
||||
static void vscale(float *v, float div) {
|
||||
v[0] *= div;
|
||||
v[1] *= div;
|
||||
v[2] *= div;
|
||||
}
|
||||
|
||||
static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); }
|
||||
|
||||
static float vdot(const float *v1, const float *v2) {
|
||||
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
|
||||
}
|
||||
|
||||
static void vadd(const float *src1, const float *src2, float *dst) {
|
||||
dst[0] = src1[0] + src2[0];
|
||||
dst[1] = src1[1] + src2[1];
|
||||
dst[2] = src1[2] + src2[2];
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, simulate a track-ball. Project the points onto the virtual
|
||||
* trackball, then figure out the axis of rotation, which is the cross
|
||||
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
|
||||
* Note: This is a deformed trackball-- is a trackball in the center,
|
||||
* but is deformed into a hyperbolic sheet of rotation away from the
|
||||
* center. This particular function was chosen after trying out
|
||||
* several variations.
|
||||
*
|
||||
* It is assumed that the arguments to this routine are in the range
|
||||
* (-1.0 ... 1.0)
|
||||
*/
|
||||
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
|
||||
float a[3]; /* Axis of rotation */
|
||||
float phi; /* how much to rotate about axis */
|
||||
float p1[3], p2[3], d[3];
|
||||
float t;
|
||||
|
||||
if (p1x == p2x && p1y == p2y) {
|
||||
/* Zero rotation */
|
||||
vzero(q);
|
||||
q[3] = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, figure out z-coordinates for projection of P1 and P2 to
|
||||
* deformed sphere
|
||||
*/
|
||||
vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
|
||||
vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
|
||||
|
||||
/*
|
||||
* Now, we want the cross product of P1 and P2
|
||||
*/
|
||||
vcross(p2, p1, a);
|
||||
|
||||
/*
|
||||
* Figure out how much to rotate around that axis.
|
||||
*/
|
||||
vsub(p1, p2, d);
|
||||
t = vlength(d) / (2.0 * TRACKBALLSIZE);
|
||||
|
||||
/*
|
||||
* Avoid problems with out-of-control values...
|
||||
*/
|
||||
if (t > 1.0)
|
||||
t = 1.0;
|
||||
if (t < -1.0)
|
||||
t = -1.0;
|
||||
phi = 2.0 * asin(t);
|
||||
|
||||
axis_to_quat(a, phi, q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given an axis and angle, compute quaternion.
|
||||
*/
|
||||
void axis_to_quat(float a[3], float phi, float q[4]) {
|
||||
vnormal(a);
|
||||
vcopy(a, q);
|
||||
vscale(q, sin(phi / 2.0));
|
||||
q[3] = cos(phi / 2.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
|
||||
* if we are away from the center of the sphere.
|
||||
*/
|
||||
static float tb_project_to_sphere(float r, float x, float y) {
|
||||
float d, t, z;
|
||||
|
||||
d = sqrt(x * x + y * y);
|
||||
if (d < r * 0.70710678118654752440) { /* Inside sphere */
|
||||
z = sqrt(r * r - d * d);
|
||||
} else { /* On hyperbola */
|
||||
t = r / 1.41421356237309504880;
|
||||
z = t * t / d;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given two rotations, e1 and e2, expressed as quaternion rotations,
|
||||
* figure out the equivalent single rotation and stuff it into dest.
|
||||
*
|
||||
* This routine also normalizes the result every RENORMCOUNT times it is
|
||||
* called, to keep error from creeping in.
|
||||
*
|
||||
* NOTE: This routine is written so that q1 or q2 may be the same
|
||||
* as dest (or each other).
|
||||
*/
|
||||
|
||||
#define RENORMCOUNT 97
|
||||
|
||||
void add_quats(float q1[4], float q2[4], float dest[4]) {
|
||||
static int count = 0;
|
||||
float t1[4], t2[4], t3[4];
|
||||
float tf[4];
|
||||
|
||||
vcopy(q1, t1);
|
||||
vscale(t1, q2[3]);
|
||||
|
||||
vcopy(q2, t2);
|
||||
vscale(t2, q1[3]);
|
||||
|
||||
vcross(q2, q1, t3);
|
||||
vadd(t1, t2, tf);
|
||||
vadd(t3, tf, tf);
|
||||
tf[3] = q1[3] * q2[3] - vdot(q1, q2);
|
||||
|
||||
dest[0] = tf[0];
|
||||
dest[1] = tf[1];
|
||||
dest[2] = tf[2];
|
||||
dest[3] = tf[3];
|
||||
|
||||
if (++count > RENORMCOUNT) {
|
||||
count = 0;
|
||||
normalize_quat(dest);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
|
||||
* If they don't add up to 1.0, dividing by their magnitued will
|
||||
* renormalize them.
|
||||
*
|
||||
* Note: See the following for more information on quaternions:
|
||||
*
|
||||
* - Shoemake, K., Animating rotation with quaternion curves, Computer
|
||||
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
|
||||
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
|
||||
* graphics, The Visual Computer 5, 2-13, 1989.
|
||||
*/
|
||||
static void normalize_quat(float q[4]) {
|
||||
int i;
|
||||
float mag;
|
||||
|
||||
mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
|
||||
for (i = 0; i < 4; i++)
|
||||
q[i] /= mag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a rotation matrix, given a quaternion rotation.
|
||||
*
|
||||
*/
|
||||
void build_rotmatrix(float m[4][4], const float q[4]) {
|
||||
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
|
||||
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
|
||||
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
|
||||
m[0][3] = 0.0;
|
||||
|
||||
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
|
||||
m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
|
||||
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
|
||||
m[1][3] = 0.0;
|
||||
|
||||
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
|
||||
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
|
||||
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
|
||||
m[2][3] = 0.0;
|
||||
|
||||
m[3][0] = 0.0;
|
||||
m[3][1] = 0.0;
|
||||
m[3][2] = 0.0;
|
||||
m[3][3] = 1.0;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
|
||||
* ALL RIGHTS RESERVED
|
||||
* Permission to use, copy, modify, and distribute this software for
|
||||
* any purpose and without fee is hereby granted, provided that the above
|
||||
* copyright notice appear in all copies and that both the copyright notice
|
||||
* and this permission notice appear in supporting documentation, and that
|
||||
* the name of Silicon Graphics, Inc. not be used in advertising
|
||||
* or publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission.
|
||||
*
|
||||
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
|
||||
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
||||
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
|
||||
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
|
||||
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
|
||||
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
|
||||
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
|
||||
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* US Government Users Restricted Rights
|
||||
* Use, duplication, or disclosure by the Government is subject to
|
||||
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
|
||||
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
|
||||
* clause at DFARS 252.227-7013 and/or in similar or successor
|
||||
* clauses in the FAR or the DOD or NASA FAR Supplement.
|
||||
* Unpublished-- rights reserved under the copyright laws of the
|
||||
* United States. Contractor/manufacturer is Silicon Graphics,
|
||||
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
|
||||
*
|
||||
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
* trackball.h
|
||||
* A virtual trackball implementation
|
||||
* Written by Gavin Bell for Silicon Graphics, November 1988.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pass the x and y coordinates of the last and current positions of
|
||||
* the mouse, scaled so they are from (-1.0 ... 1.0).
|
||||
*
|
||||
* The resulting rotation is returned as a quaternion rotation in the
|
||||
* first paramater.
|
||||
*/
|
||||
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
|
||||
|
||||
void negate_quat(float *q, float *qn);
|
||||
|
||||
/*
|
||||
* Given two quaternions, add them together to get a third quaternion.
|
||||
* Adding quaternions to get a compound rotation is analagous to adding
|
||||
* translations to get a compound translation. When incrementally
|
||||
* adding rotations, the first argument here should be the new
|
||||
* rotation, the second and third the total rotation (which will be
|
||||
* over-written with the resulting new total rotation).
|
||||
*/
|
||||
void add_quats(float *q1, float *q2, float *dest);
|
||||
|
||||
/*
|
||||
* A useful function, builds a rotation matrix in Matrix based on
|
||||
* given quaternion.
|
||||
*/
|
||||
void build_rotmatrix(float m[4][4], const float q[4]);
|
||||
|
||||
/*
|
||||
* This function computes a quaternion based on an axis (defined by
|
||||
* the given vector) and an angle about which to rotate. The angle is
|
||||
* expressed in radians. The result is put into the third argument.
|
||||
*/
|
||||
void axis_to_quat(float a[3], float phi, float q[4]);
|
||||
+109
-9
@@ -1,28 +1,128 @@
|
||||
# Raytrace example
|
||||
# NanoSG
|
||||
|
||||
Simple raytracing example with OpenGL preview
|
||||
Simple, minimal and header-only scene graph library for NanoRT.
|
||||
|
||||
NanoSG itself shoud be compiled with C++-03 compiler, but demo code uses C++11 features.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Build
|
||||
|
||||
### Linux or macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
```bash
|
||||
premake5 gmake
|
||||
make
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
$ premake5 vs2015
|
||||
```bash
|
||||
premake5 vs2015
|
||||
```
|
||||
|
||||
## Data structure
|
||||
|
||||
## Third party libraries and its icenses.
|
||||
### Node
|
||||
|
||||
Node represents scene graph node. Tansformation node or Mesh(shape) node.
|
||||
Node is interpreted as transformation node when passing `nullptr` to Node class constructure.
|
||||
|
||||
Node can contain multiple children.
|
||||
|
||||
### Scene
|
||||
|
||||
Scene contains root nodes and provides the method to find an intersection of nodes.
|
||||
|
||||
## User defined data structure
|
||||
|
||||
Following are required in user application.
|
||||
|
||||
### Mesh class
|
||||
|
||||
Current example code assumes mesh is all composed of triangle meshes.
|
||||
|
||||
Following method must be implemented for `Scene::Traversal`.
|
||||
|
||||
```cpp
|
||||
///
|
||||
/// Get the geometric normal and the shading normal at `face_idx' th face.
|
||||
///
|
||||
template<typename T>
|
||||
void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const;
|
||||
```
|
||||
|
||||
### Intersection class
|
||||
|
||||
Represents intersection(hit) information.
|
||||
|
||||
### Transform
|
||||
|
||||
Transformation is done in the following procedure.
|
||||
|
||||
`M' = parent_xform x local_xform x local_pivot`
|
||||
|
||||
## Memory management
|
||||
|
||||
`Scene` and `Node` does not create a copy of asset data(e.g. vertices, indices). Thus user must care about memory management of scene assets in user side.
|
||||
|
||||
## API
|
||||
|
||||
API is still subject to change.
|
||||
|
||||
### Node
|
||||
|
||||
```cpp
|
||||
void Node::SetName(const std::string &name);
|
||||
```
|
||||
|
||||
Set (unique) name for the node.
|
||||
|
||||
```cpp
|
||||
void Node::AddChild(const type &child);
|
||||
```
|
||||
|
||||
Add node as child node.
|
||||
|
||||
```cpp
|
||||
void Node::SetLocalXform(const T xform[4][4]) {
|
||||
```
|
||||
|
||||
Set local transformation matrix. Default is identity matrix.
|
||||
|
||||
### Scene
|
||||
|
||||
```cpp
|
||||
bool Scene::AddNode(const Node<T, M> &node);
|
||||
```
|
||||
|
||||
Add a node to the scene.
|
||||
|
||||
```cpp
|
||||
bool Scene::Commit() {
|
||||
```
|
||||
|
||||
Commit the scene. After adding nodes to the scene or changed transformation matrix, call this `Commit` before tracing rays.
|
||||
`Commit` triggers BVH build in each nodes and updates node's transformation matrix.
|
||||
|
||||
```cpp
|
||||
template<class H>
|
||||
bool Scene::Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const;
|
||||
```
|
||||
|
||||
Trace ray into the scene and find an intersection.
|
||||
Returns `true` when there is an intersection and hit information is stored in `isect`.
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Compute pivot point of each node(mesh).
|
||||
|
||||
## Third party libraries and its icenses
|
||||
|
||||
* picojson : BSD license.
|
||||
* bt3gui : zlib license.
|
||||
* bt3gui : zlib license.
|
||||
* glew : BSD/MIT license.
|
||||
* tinyobjloader : MIT license.
|
||||
* glm : The Happy Bunny License (Modified MIT License). Copyright (c) 2005 - 2017 G-Truc Creation
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
{ "gltf_filename" : "../../models/Cube/Cube.gltf",
|
||||
"scene_scale" : 1.0,
|
||||
"width" : 512,
|
||||
"height" : 512,
|
||||
"eye" : [0, 2.5, 15],
|
||||
"up" : [0, 1, 0],
|
||||
"look_at" : [0, 0, 0],
|
||||
"dummy" : 0
|
||||
{
|
||||
"commented_out_obj_filename": "cornellbox_suzanne.obj",
|
||||
"gltf_filename": "../../models/Cube/Cube.gltf",
|
||||
"scene_scale": 1.0,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"eye": [
|
||||
0,
|
||||
2.5,
|
||||
15
|
||||
],
|
||||
"up": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"look_at": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"dummy": 0
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
#include "gltf-loader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <memory> // c++11
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
namespace example {
|
||||
|
||||
static std::string GetFilePathExtension(const std::string &FileName) {
|
||||
if (FileName.find_last_of(".") != std::string::npos)
|
||||
return FileName.substr(FileName.find_last_of(".") + 1);
|
||||
@@ -17,24 +16,30 @@ static std::string GetFilePathExtension(const std::string &FileName) {
|
||||
///
|
||||
/// Loads glTF 2.0 mesh
|
||||
///
|
||||
bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures)
|
||||
{
|
||||
|
||||
bool LoadGLTF(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *materials,
|
||||
std::vector<Texture> *textures) {
|
||||
// TODO(syoyo): Texture
|
||||
// TODO(syoyo): Material
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string ext = GetFilePathExtension(filename);
|
||||
std::string warn;
|
||||
const std::string ext = GetFilePathExtension(filename);
|
||||
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
// assume binary glTF.
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, filename.c_str());
|
||||
ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename.c_str());
|
||||
} else {
|
||||
// assume ascii glTF.
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, filename.c_str());
|
||||
ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename.c_str());
|
||||
}
|
||||
|
||||
if (!warn.empty()) {
|
||||
std::cout << "glTF parse warning: " << warn << std::endl;
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
@@ -45,7 +50,448 @@ bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float>
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
std::cout << "loaded glTF file has:\n"
|
||||
<< model.accessors.size() << " accessors\n"
|
||||
<< model.animations.size() << " animations\n"
|
||||
<< model.buffers.size() << " buffers\n"
|
||||
<< model.bufferViews.size() << " bufferViews\n"
|
||||
<< model.materials.size() << " materials\n"
|
||||
<< model.meshes.size() << " meshes\n"
|
||||
<< model.nodes.size() << " nodes\n"
|
||||
<< model.textures.size() << " textures\n"
|
||||
<< model.images.size() << " images\n"
|
||||
<< model.skins.size() << " skins\n"
|
||||
<< model.samplers.size() << " samplers\n"
|
||||
<< model.cameras.size() << " cameras\n"
|
||||
<< model.scenes.size() << " scenes\n"
|
||||
<< model.lights.size() << " lights\n";
|
||||
|
||||
} // namespace example
|
||||
// Iterate through all the meshes in the glTF file
|
||||
for (const auto &gltfMesh : model.meshes) {
|
||||
std::cout << "Current mesh has " << gltfMesh.primitives.size()
|
||||
<< " primitives:\n";
|
||||
|
||||
// Create a mesh object
|
||||
Mesh<float> loadedMesh(sizeof(float) * 3);
|
||||
|
||||
// To store the min and max of the buffer (as 3D vector of floats)
|
||||
v3f pMin = {}, pMax = {};
|
||||
|
||||
// Store the name of the glTF mesh (if defined)
|
||||
loadedMesh.name = gltfMesh.name;
|
||||
|
||||
// For each primitive
|
||||
for (const auto &meshPrimitive : gltfMesh.primitives) {
|
||||
// Boolean used to check if we have converted the vertex buffer format
|
||||
bool convertedToTriangleList = false;
|
||||
// This permit to get a type agnostic way of reading the index buffer
|
||||
std::unique_ptr<intArrayBase> indicesArrayPtr = nullptr;
|
||||
{
|
||||
const auto &indicesAccessor = model.accessors[meshPrimitive.indices];
|
||||
const auto &bufferView = model.bufferViews[indicesAccessor.bufferView];
|
||||
const auto &buffer = model.buffers[bufferView.buffer];
|
||||
const auto dataAddress = buffer.data.data() + bufferView.byteOffset +
|
||||
indicesAccessor.byteOffset;
|
||||
const auto byteStride = indicesAccessor.ByteStride(bufferView);
|
||||
const auto count = indicesAccessor.count;
|
||||
|
||||
// Allocate the index array in the pointer-to-base declared in the
|
||||
// parent scope
|
||||
switch (indicesAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
indicesArrayPtr =
|
||||
std::unique_ptr<intArray<char> >(new intArray<char>(
|
||||
arrayAdapter<char>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned char> >(
|
||||
new intArray<unsigned char>(arrayAdapter<unsigned char>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
indicesArrayPtr =
|
||||
std::unique_ptr<intArray<short> >(new intArray<short>(
|
||||
arrayAdapter<short>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned short> >(
|
||||
new intArray<unsigned short>(arrayAdapter<unsigned short>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<int> >(new intArray<int>(
|
||||
arrayAdapter<int>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned int> >(
|
||||
new intArray<unsigned int>(arrayAdapter<unsigned int>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto &indices = *indicesArrayPtr;
|
||||
|
||||
if (indicesArrayPtr) {
|
||||
std::cout << "indices: ";
|
||||
for (size_t i(0); i < indicesArrayPtr->size(); ++i) {
|
||||
std::cout << indices[i] << " ";
|
||||
loadedMesh.faces.push_back(indices[i]);
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
switch (meshPrimitive.mode) {
|
||||
// We re-arrange the indices so that it describe a simple list of
|
||||
// triangles
|
||||
case TINYGLTF_MODE_TRIANGLE_FAN:
|
||||
if (!convertedToTriangleList) {
|
||||
std::cout << "TRIANGLE_FAN\n";
|
||||
// This only has to be done once per primitive
|
||||
convertedToTriangleList = true;
|
||||
|
||||
// We steal the guts of the vector
|
||||
auto triangleFan = std::move(loadedMesh.faces);
|
||||
loadedMesh.faces.clear();
|
||||
|
||||
// Push back the indices that describe just one triangle one by one
|
||||
for (size_t i{2}; i < triangleFan.size(); ++i) {
|
||||
loadedMesh.faces.push_back(triangleFan[0]);
|
||||
loadedMesh.faces.push_back(triangleFan[i - 1]);
|
||||
loadedMesh.faces.push_back(triangleFan[i]);
|
||||
}
|
||||
}
|
||||
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
||||
if (!convertedToTriangleList) {
|
||||
std::cout << "TRIANGLE_STRIP\n";
|
||||
// This only has to be done once per primitive
|
||||
convertedToTriangleList = true;
|
||||
|
||||
auto triangleStrip = std::move(loadedMesh.faces);
|
||||
loadedMesh.faces.clear();
|
||||
|
||||
for (size_t i{2}; i < triangleStrip.size(); ++i) {
|
||||
loadedMesh.faces.push_back(triangleStrip[i - 2]);
|
||||
loadedMesh.faces.push_back(triangleStrip[i - 1]);
|
||||
loadedMesh.faces.push_back(triangleStrip[i]);
|
||||
}
|
||||
}
|
||||
case TINYGLTF_MODE_TRIANGLES: // this is the simpliest case to handle
|
||||
|
||||
{
|
||||
std::cout << "TRIANGLES\n";
|
||||
|
||||
for (const auto &attribute : meshPrimitive.attributes) {
|
||||
const auto attribAccessor = model.accessors[attribute.second];
|
||||
const auto &bufferView =
|
||||
model.bufferViews[attribAccessor.bufferView];
|
||||
const auto &buffer = model.buffers[bufferView.buffer];
|
||||
const auto dataPtr = buffer.data.data() + bufferView.byteOffset +
|
||||
attribAccessor.byteOffset;
|
||||
const auto byte_stride = attribAccessor.ByteStride(bufferView);
|
||||
const auto count = attribAccessor.count;
|
||||
|
||||
std::cout << "current attribute has count " << count
|
||||
<< " and stride " << byte_stride << " bytes\n";
|
||||
|
||||
std::cout << "attribute string is : " << attribute.first << '\n';
|
||||
if (attribute.first == "POSITION") {
|
||||
std::cout << "found position attribute\n";
|
||||
|
||||
// get the position min/max for computing the boundingbox
|
||||
pMin.x = attribAccessor.minValues[0];
|
||||
pMin.y = attribAccessor.minValues[1];
|
||||
pMin.z = attribAccessor.minValues[2];
|
||||
pMax.x = attribAccessor.maxValues[0];
|
||||
pMax.y = attribAccessor.maxValues[1];
|
||||
pMax.z = attribAccessor.maxValues[2];
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
std::cout << "Type is FLOAT\n";
|
||||
// 3D vector of float
|
||||
v3fArray positions(
|
||||
arrayAdapter<v3f>(dataPtr, count, byte_stride));
|
||||
|
||||
std::cout << "positions's size : " << positions.size()
|
||||
<< '\n';
|
||||
|
||||
for (size_t i{0}; i < positions.size(); ++i) {
|
||||
const auto v = positions[i];
|
||||
std::cout << "positions[" << i << "]: (" << v.x << ", "
|
||||
<< v.y << ", " << v.z << ")\n";
|
||||
|
||||
loadedMesh.vertices.push_back(v.x * scale);
|
||||
loadedMesh.vertices.push_back(v.y * scale);
|
||||
loadedMesh.vertices.push_back(v.z * scale);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "Type is DOUBLE\n";
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
v3dArray positions(
|
||||
arrayAdapter<v3d>(dataPtr, count, byte_stride));
|
||||
for (size_t i{0}; i < positions.size(); ++i) {
|
||||
const auto v = positions[i];
|
||||
std::cout << "positions[" << i << "]: (" << v.x
|
||||
<< ", " << v.y << ", " << v.z << ")\n";
|
||||
|
||||
loadedMesh.vertices.push_back(v.x * scale);
|
||||
loadedMesh.vertices.push_back(v.y * scale);
|
||||
loadedMesh.vertices.push_back(v.z * scale);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
// TODO Handle error
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
if (attribute.first == "NORMAL") {
|
||||
std::cout << "found normal attribute\n";
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
std::cout << "Normal is VEC3\n";
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT: {
|
||||
std::cout << "Normal is FLOAT\n";
|
||||
v3fArray normals(
|
||||
arrayAdapter<v3f>(dataPtr, count, byte_stride));
|
||||
|
||||
// IMPORTANT: We need to reorder normals (and texture
|
||||
// coordinates into "facevarying" order) for each face
|
||||
|
||||
// For each triangle :
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the 3 normal vectors for that face
|
||||
v3f n0, n1, n2;
|
||||
n0 = normals[f0];
|
||||
n1 = normals[f1];
|
||||
n2 = normals[f2];
|
||||
|
||||
// Put them in the array in the correct order
|
||||
loadedMesh.facevarying_normals.push_back(n0.x);
|
||||
loadedMesh.facevarying_normals.push_back(n0.y);
|
||||
loadedMesh.facevarying_normals.push_back(n0.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n1.x);
|
||||
loadedMesh.facevarying_normals.push_back(n1.y);
|
||||
loadedMesh.facevarying_normals.push_back(n1.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n2.x);
|
||||
loadedMesh.facevarying_normals.push_back(n2.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
}
|
||||
} break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "Normal is DOUBLE\n";
|
||||
v3dArray normals(
|
||||
arrayAdapter<v3d>(dataPtr, count, byte_stride));
|
||||
|
||||
// IMPORTANT: We need to reorder normals (and texture
|
||||
// coordinates into "facevarying" order) for each face
|
||||
|
||||
// For each triangle :
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the 3 normal vectors for that face
|
||||
v3d n0, n1, n2;
|
||||
n0 = normals[f0];
|
||||
n1 = normals[f1];
|
||||
n2 = normals[f2];
|
||||
|
||||
// Put them in the array in the correct order
|
||||
loadedMesh.facevarying_normals.push_back(n0.x);
|
||||
loadedMesh.facevarying_normals.push_back(n0.y);
|
||||
loadedMesh.facevarying_normals.push_back(n0.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n1.x);
|
||||
loadedMesh.facevarying_normals.push_back(n1.y);
|
||||
loadedMesh.facevarying_normals.push_back(n1.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n2.x);
|
||||
loadedMesh.facevarying_normals.push_back(n2.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "Unhandeled componant type for normal\n";
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "Unhandeled vector type for normal\n";
|
||||
}
|
||||
|
||||
// Face varying comment on the normals is also true for the UVs
|
||||
if (attribute.first == "TEXCOORD_0") {
|
||||
std::cout << "Found texture coordinates\n";
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC2: {
|
||||
std::cout << "TEXTCOORD is VEC2\n";
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT: {
|
||||
std::cout << "TEXTCOORD is FLOAT\n";
|
||||
v2fArray uvs(
|
||||
arrayAdapter<v2f>(dataPtr, count, byte_stride));
|
||||
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the texture coordinates for each triangle's
|
||||
// vertices
|
||||
v2f uv0, uv1, uv2;
|
||||
uv0 = uvs[f0];
|
||||
uv1 = uvs[f1];
|
||||
uv2 = uvs[f2];
|
||||
|
||||
// push them in order into the mesh data
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.y);
|
||||
}
|
||||
|
||||
} break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "TEXTCOORD is DOUBLE\n";
|
||||
v2dArray uvs(
|
||||
arrayAdapter<v2d>(dataPtr, count, byte_stride));
|
||||
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
v2d uv0, uv1, uv2;
|
||||
uv0 = uvs[f0];
|
||||
uv1 = uvs[f1];
|
||||
uv2 = uvs[f2];
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.y);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "unrecognized vector type for UV";
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "unreconized componant type for UV";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "primitive mode not implemented";
|
||||
break;
|
||||
|
||||
// These aren't triangles:
|
||||
case TINYGLTF_MODE_POINTS:
|
||||
case TINYGLTF_MODE_LINE:
|
||||
case TINYGLTF_MODE_LINE_LOOP:
|
||||
std::cerr << "primitive is not triangle based, ignoring";
|
||||
}
|
||||
}
|
||||
|
||||
// bbox :
|
||||
v3f bCenter;
|
||||
bCenter.x = 0.5f * (pMax.x - pMin.x) + pMin.x;
|
||||
bCenter.y = 0.5f * (pMax.y - pMin.y) + pMin.y;
|
||||
bCenter.z = 0.5f * (pMax.z - pMin.z) + pMin.z;
|
||||
|
||||
for (size_t v = 0; v < loadedMesh.vertices.size() / 3; v++) {
|
||||
loadedMesh.vertices[3 * v + 0] -= bCenter.x;
|
||||
loadedMesh.vertices[3 * v + 1] -= bCenter.y;
|
||||
loadedMesh.vertices[3 * v + 2] -= bCenter.z;
|
||||
}
|
||||
|
||||
loadedMesh.pivot_xform[0][0] = 1.0f;
|
||||
loadedMesh.pivot_xform[0][1] = 0.0f;
|
||||
loadedMesh.pivot_xform[0][2] = 0.0f;
|
||||
loadedMesh.pivot_xform[0][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[1][0] = 0.0f;
|
||||
loadedMesh.pivot_xform[1][1] = 1.0f;
|
||||
loadedMesh.pivot_xform[1][2] = 0.0f;
|
||||
loadedMesh.pivot_xform[1][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[2][0] = 0.0f;
|
||||
loadedMesh.pivot_xform[2][1] = 0.0f;
|
||||
loadedMesh.pivot_xform[2][2] = 1.0f;
|
||||
loadedMesh.pivot_xform[2][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[3][0] = bCenter.x;
|
||||
loadedMesh.pivot_xform[3][1] = bCenter.y;
|
||||
loadedMesh.pivot_xform[3][2] = bCenter.z;
|
||||
loadedMesh.pivot_xform[3][3] = 1.0f;
|
||||
|
||||
// TODO handle materials
|
||||
for (size_t i{0}; i < loadedMesh.faces.size(); ++i)
|
||||
loadedMesh.material_ids.push_back(materials->at(0).id);
|
||||
|
||||
meshes->push_back(loadedMesh);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through all texture declaration in glTF file
|
||||
for (const auto &gltfTexture : model.textures) {
|
||||
std::cout << "Found texture!";
|
||||
Texture loadedTexture;
|
||||
const auto &image = model.images[gltfTexture.source];
|
||||
loadedTexture.components = image.component;
|
||||
loadedTexture.width = image.width;
|
||||
loadedTexture.height = image.height;
|
||||
|
||||
const auto size =
|
||||
image.component * image.width * image.height * sizeof(unsigned char);
|
||||
loadedTexture.image = new unsigned char[size];
|
||||
memcpy(loadedTexture.image, image.image.data(), size);
|
||||
textures->push_back(loadedTexture);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace example
|
||||
|
||||
@@ -1,19 +1,166 @@
|
||||
#ifndef EXAMPLE_GLTF_LOADER_H_
|
||||
#define EXAMPLE_GLTF_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "material.h"
|
||||
#include "mesh.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
/// Adapts an array of bytes to an array of T. Will advace of byte_stride each
|
||||
/// elements.
|
||||
template <typename T>
|
||||
struct arrayAdapter {
|
||||
/// Pointer to the bytes
|
||||
const unsigned char *dataPtr;
|
||||
/// Number of elements in the array
|
||||
const size_t elemCount;
|
||||
/// Stride in bytes between two elements
|
||||
const size_t stride;
|
||||
|
||||
/// Construct an array adapter.
|
||||
/// \param ptr Pointer to the start of the data, with offset applied
|
||||
/// \param count Number of elements in the array
|
||||
/// \param byte_stride Stride betweens elements in the array
|
||||
arrayAdapter(const unsigned char *ptr, size_t count, size_t byte_stride)
|
||||
: dataPtr(ptr), elemCount(count), stride(byte_stride) {}
|
||||
|
||||
/// Returns a *copy* of a single element. Can't be used to modify it.
|
||||
T operator[](size_t pos) const {
|
||||
if (pos >= elemCount)
|
||||
throw std::out_of_range(
|
||||
"Tried to access beyond the last element of an array adapter with "
|
||||
"count " +
|
||||
std::to_string(elemCount) + " while getting elemnet number " +
|
||||
std::to_string(pos));
|
||||
return *(reinterpret_cast<const T *>(dataPtr + pos * stride));
|
||||
}
|
||||
};
|
||||
|
||||
/// Interface of any adapted array that returns ingeger data
|
||||
struct intArrayBase {
|
||||
virtual ~intArrayBase() = default;
|
||||
virtual unsigned int operator[](size_t) const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
};
|
||||
|
||||
/// Interface of any adapted array that returns float data
|
||||
struct floatArrayBase {
|
||||
virtual ~floatArrayBase() = default;
|
||||
virtual float operator[](size_t) const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
};
|
||||
|
||||
/// An array that loads interger types, returns them as int
|
||||
template <class T>
|
||||
struct intArray : public intArrayBase {
|
||||
arrayAdapter<T> adapter;
|
||||
|
||||
intArray(const arrayAdapter<T> &a) : adapter(a) {}
|
||||
unsigned int operator[](size_t position) const override {
|
||||
return static_cast<unsigned int>(adapter[position]);
|
||||
}
|
||||
|
||||
size_t size() const override { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct floatArray : public floatArrayBase {
|
||||
arrayAdapter<T> adapter;
|
||||
|
||||
floatArray(const arrayAdapter<T> &a) : adapter(a) {}
|
||||
float operator[](size_t position) const override {
|
||||
return static_cast<float>(adapter[position]);
|
||||
}
|
||||
|
||||
size_t size() const override { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
template <typename T>
|
||||
struct v2 {
|
||||
T x, y;
|
||||
};
|
||||
/// 3D vector of floats without padding
|
||||
template <typename T>
|
||||
struct v3 {
|
||||
T x, y, z;
|
||||
};
|
||||
|
||||
/// 4D vector of floats without padding
|
||||
template <typename T>
|
||||
struct v4 {
|
||||
T x, y, z, w;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
using v2f = v2<float>;
|
||||
using v3f = v3<float>;
|
||||
using v4f = v4<float>;
|
||||
using v2d = v2<double>;
|
||||
using v3d = v3<double>;
|
||||
using v4d = v4<double>;
|
||||
|
||||
struct v2fArray {
|
||||
arrayAdapter<v2f> adapter;
|
||||
v2fArray(const arrayAdapter<v2f> &a) : adapter(a) {}
|
||||
|
||||
v2f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v3fArray {
|
||||
arrayAdapter<v3f> adapter;
|
||||
v3fArray(const arrayAdapter<v3f> &a) : adapter(a) {}
|
||||
|
||||
v3f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v4fArray {
|
||||
arrayAdapter<v4f> adapter;
|
||||
v4fArray(const arrayAdapter<v4f> &a) : adapter(a) {}
|
||||
|
||||
v4f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v2dArray {
|
||||
arrayAdapter<v2d> adapter;
|
||||
v2dArray(const arrayAdapter<v2d> &a) : adapter(a) {}
|
||||
|
||||
v2d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v3dArray {
|
||||
arrayAdapter<v3d> adapter;
|
||||
v3dArray(const arrayAdapter<v3d> &a) : adapter(a) {}
|
||||
|
||||
v3d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v4dArray {
|
||||
arrayAdapter<v4d> adapter;
|
||||
v4dArray(const arrayAdapter<v4d> &a) : adapter(a) {}
|
||||
|
||||
v4d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
///
|
||||
/// Loads glTF 2.0 mesh
|
||||
///
|
||||
bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
bool LoadGLTF(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
|
||||
}
|
||||
} // namespace example
|
||||
|
||||
#endif // EXAMPLE_GLTF_LOADER_H_
|
||||
#endif // EXAMPLE_GLTF_LOADER_H_
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
+226
-165
@@ -53,12 +53,13 @@ THE SOFTWARE.
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <atomic> // C++11
|
||||
#include <chrono> // C++11
|
||||
@@ -72,22 +73,23 @@ THE SOFTWARE.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
#include "glm/mat4x4.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "glm/gtc/type_ptr.hpp"
|
||||
#include "glm/mat4x4.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "gltf-loader.h"
|
||||
#include "nanosg.h"
|
||||
#include "obj-loader.h"
|
||||
#include "render-config.h"
|
||||
#include "render.h"
|
||||
#include "gltf-loader.h"
|
||||
#include "trackball.h"
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -96,19 +98,17 @@ THE SOFTWARE.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SHOW_BUFFER_COLOR (0)
|
||||
#define SHOW_BUFFER_NORMAL (1)
|
||||
#define SHOW_BUFFER_POSITION (2)
|
||||
#define SHOW_BUFFER_DEPTH (3)
|
||||
#define SHOW_BUFFER_TEXCOORD (4)
|
||||
#define SHOW_BUFFER_VARYCOORD (5)
|
||||
|
||||
b3gDefaultOpenGLWindow* window = 0;
|
||||
b3gDefaultOpenGLWindow *window = 0;
|
||||
int gWidth = 512;
|
||||
int gHeight = 512;
|
||||
int gMousePosX = -1, gMousePosY = -1;
|
||||
bool gMouseLeftDown = false;
|
||||
|
||||
// FIX issue when max passes is done - no modes is switched. pass must be set to
|
||||
// 0 when mode is changed
|
||||
int gShowBufferMode_prv = SHOW_BUFFER_COLOR;
|
||||
int gShowBufferMode = SHOW_BUFFER_COLOR;
|
||||
|
||||
bool gTabPressed = false;
|
||||
bool gShiftPressed = false;
|
||||
float gShowPositionScale = 1.0f;
|
||||
@@ -128,8 +128,7 @@ std::atomic<bool> gSceneDirty;
|
||||
example::RenderConfig gRenderConfig;
|
||||
std::mutex gMutex;
|
||||
|
||||
struct RenderLayer
|
||||
{
|
||||
struct RenderLayer {
|
||||
std::vector<float> displayRGBA; // Accumurated image.
|
||||
std::vector<float> rgba;
|
||||
std::vector<float> auxRGBA; // Auxiliary buffer
|
||||
@@ -143,14 +142,12 @@ struct RenderLayer
|
||||
|
||||
RenderLayer gRenderLayer;
|
||||
|
||||
struct Camera
|
||||
{
|
||||
struct Camera {
|
||||
glm::mat4 view;
|
||||
glm::mat4 projection;
|
||||
};
|
||||
|
||||
struct ManipConfig
|
||||
{
|
||||
struct ManipConfig {
|
||||
glm::vec3 snapTranslation;
|
||||
glm::vec3 snapRotation;
|
||||
glm::vec3 snapScale;
|
||||
@@ -201,9 +198,12 @@ void RenderThread() {
|
||||
// gRenderCancel may be set to true in main loop.
|
||||
// Render() will repeatedly check this flag inside the rendering loop.
|
||||
|
||||
bool ret =
|
||||
example::Renderer::Render(&gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0), &gRenderLayer.sampleCounts.at(0),
|
||||
gCurrQuat, gScene, gAsset, gRenderConfig, gRenderCancel);
|
||||
bool ret = example::Renderer::Render(
|
||||
&gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0),
|
||||
&gRenderLayer.sampleCounts.at(0), gCurrQuat, gScene, gAsset,
|
||||
gRenderConfig, gRenderCancel,
|
||||
gShowBufferMode // added mode passing
|
||||
);
|
||||
|
||||
if (ret) {
|
||||
std::lock_guard<std::mutex> guard(gMutex);
|
||||
@@ -219,16 +219,18 @@ void RenderThread() {
|
||||
}
|
||||
}
|
||||
|
||||
void InitRender(example::RenderConfig* rc) {
|
||||
void InitRender(example::RenderConfig *rc) {
|
||||
rc->pass = 0;
|
||||
|
||||
rc->max_passes = 128;
|
||||
|
||||
gRenderLayer.sampleCounts.resize(rc->width * rc->height);
|
||||
std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(), 0.0);
|
||||
std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.displayRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.rgba.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.rgba.begin(), gRenderLayer.rgba.end(), 0.0);
|
||||
@@ -237,19 +239,23 @@ void InitRender(example::RenderConfig* rc) {
|
||||
std::fill(gRenderLayer.auxRGBA.begin(), gRenderLayer.auxRGBA.end(), 0.0);
|
||||
|
||||
gRenderLayer.normalRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.positionRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.depthRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.depthRGBA.begin(), gRenderLayer.depthRGBA.end(), 0.0);
|
||||
|
||||
gRenderLayer.texCoordRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.varyCoordRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.varyCoordRGBA.begin(), gRenderLayer.varyCoordRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.varyCoordRGBA.begin(),
|
||||
gRenderLayer.varyCoordRGBA.end(), 0.0);
|
||||
|
||||
rc->normalImage = &gRenderLayer.normalRGBA.at(0);
|
||||
rc->positionImage = &gRenderLayer.positionRGBA.at(0);
|
||||
@@ -268,19 +274,18 @@ void checkErrors(std::string desc) {
|
||||
}
|
||||
}
|
||||
|
||||
static int CreateDisplayTextureGL(const float *data, int width, int height,
|
||||
int components) {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
static int CreateDisplayTextureGL(const float *data, int width,
|
||||
int height, int components) {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
if (components == 1) {
|
||||
format = GL_LUMINANCE;
|
||||
@@ -290,15 +295,15 @@ static int CreateDisplayTextureGL(const float *data, int width,
|
||||
format = GL_RGB;
|
||||
} else if (components == 4) {
|
||||
format = GL_RGBA;
|
||||
} else {
|
||||
assert(0); // "Invalid components"
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format,
|
||||
GL_FLOAT, data);
|
||||
|
||||
} else {
|
||||
assert(0); // "Invalid components"
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_FLOAT,
|
||||
data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
|
||||
return static_cast<int>(id);
|
||||
}
|
||||
|
||||
@@ -312,8 +317,10 @@ void keyboardCallback(int keycode, int state) {
|
||||
// reset.
|
||||
trackball(gCurrQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// clear buffer.
|
||||
memset(gRenderLayer.rgba.data(), 0, sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4);
|
||||
memset(gRenderLayer.sampleCounts.data(), 0, sizeof(int) * gRenderConfig.width * gRenderConfig.height);
|
||||
memset(gRenderLayer.rgba.data(), 0,
|
||||
sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4);
|
||||
memset(gRenderLayer.sampleCounts.data(), 0,
|
||||
sizeof(int) * gRenderConfig.width * gRenderConfig.height);
|
||||
} else if (keycode == 9) {
|
||||
gTabPressed = (state == 1);
|
||||
} else if (keycode == B3G_SHIFT) {
|
||||
@@ -330,9 +337,10 @@ void keyboardCallback(int keycode, int state) {
|
||||
}
|
||||
|
||||
void mouseMoveCallback(float x, float y) {
|
||||
|
||||
if (gMouseLeftDown) {
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
gSceneDirty = true;
|
||||
// RequestRender();
|
||||
} else {
|
||||
float w = static_cast<float>(gRenderConfig.width);
|
||||
float h = static_cast<float>(gRenderConfig.height);
|
||||
@@ -371,31 +379,34 @@ void mouseButtonCallback(int button, int state, float x, float y) {
|
||||
(void)y;
|
||||
ImGui_ImplBtGui_SetMouseButtonState(button, (state == 1));
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.WantCaptureMouse || io.WantCaptureKeyboard) {
|
||||
return;
|
||||
}
|
||||
if (button == 0 && !state)
|
||||
gMouseLeftDown = false; // prevent sticky trackball after using gizmo
|
||||
|
||||
// left button
|
||||
if (button == 0) {
|
||||
if (state) {
|
||||
gMouseLeftDown = true;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
} else {
|
||||
trackball(gPrevQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
} else {
|
||||
gMouseLeftDown = false;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
if (io.WantCaptureMouse || io.WantCaptureKeyboard) {
|
||||
if (button == 0 && !state) {
|
||||
if (ImGuizmo::IsUsing()) {
|
||||
gSceneDirty = true;
|
||||
RequestRender();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// left button
|
||||
if (button == 0) {
|
||||
if (state) {
|
||||
gMouseLeftDown = true;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
} else {
|
||||
trackball(gPrevQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resizeCallback(float width, float height) {
|
||||
//GLfloat h = (GLfloat)height / (GLfloat)width;
|
||||
// GLfloat h = (GLfloat)height / (GLfloat)width;
|
||||
GLfloat xmax, znear, zfar;
|
||||
|
||||
znear = 1.0f;
|
||||
@@ -406,7 +417,7 @@ void resizeCallback(float width, float height) {
|
||||
gHeight = static_cast<int>(height);
|
||||
}
|
||||
|
||||
inline float pesudoColor(float v, int ch) {
|
||||
inline float pseudoColor(float v, int ch) {
|
||||
if (ch == 0) { // red
|
||||
if (v <= 0.5f)
|
||||
return 0.f;
|
||||
@@ -471,7 +482,7 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) {
|
||||
for (size_t i = 0; i < buf.size(); i++) {
|
||||
float v = (gRenderLayer.depthRGBA[i] - d_min) / d_diff;
|
||||
if (gShowDepthPeseudoColor) {
|
||||
buf[i] = pesudoColor(v, i % 4);
|
||||
buf[i] = pseudoColor(v, i % 4);
|
||||
} else {
|
||||
buf[i] = v;
|
||||
}
|
||||
@@ -491,31 +502,31 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) {
|
||||
disp.resize(width * height * 4);
|
||||
{
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)], sizeof(float) * 4 * width);
|
||||
memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)],
|
||||
sizeof(float) * 4 * width);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, disp.data());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT,
|
||||
disp.data());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
//glRasterPos2i(-1, -1);
|
||||
//glDrawPixels(width, height, GL_RGBA, GL_FLOAT,
|
||||
// glRasterPos2i(-1, -1);
|
||||
// glDrawPixels(width, height, GL_RGBA, GL_FLOAT,
|
||||
// static_cast<const GLvoid*>(&buf.at(0)));
|
||||
}
|
||||
|
||||
void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& matrix)
|
||||
{
|
||||
void EditTransform(const ManipConfig &config, const Camera &camera,
|
||||
glm::mat4 &matrix) {
|
||||
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
|
||||
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
|
||||
if (ImGui::IsKeyPressed(90))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(69))
|
||||
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
if (ImGui::IsKeyPressed(82)) // r Key
|
||||
if (ImGui::IsKeyPressed(90)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(69)) mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
if (ImGui::IsKeyPressed(82)) // r Key
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||
if (ImGui::RadioButton("Translate",
|
||||
mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
|
||||
@@ -524,14 +535,15 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m
|
||||
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||
ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation, matrixRotation, matrixScale);
|
||||
ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation,
|
||||
matrixRotation, matrixScale);
|
||||
ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||
ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||
ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, &matrix[0][0]);
|
||||
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation,
|
||||
matrixScale, &matrix[0][0]);
|
||||
|
||||
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
|
||||
{
|
||||
if (mCurrentGizmoOperation != ImGuizmo::SCALE) {
|
||||
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
|
||||
mCurrentGizmoMode = ImGuizmo::LOCAL;
|
||||
ImGui::SameLine();
|
||||
@@ -539,33 +551,32 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m
|
||||
mCurrentGizmoMode = ImGuizmo::WORLD;
|
||||
}
|
||||
static bool useSnap(false);
|
||||
if (ImGui::IsKeyPressed(83))
|
||||
useSnap = !useSnap;
|
||||
if (ImGui::IsKeyPressed(83)) useSnap = !useSnap;
|
||||
ImGui::Checkbox("", &useSnap);
|
||||
ImGui::SameLine();
|
||||
glm::vec3 snap;
|
||||
switch (mCurrentGizmoOperation)
|
||||
{
|
||||
case ImGuizmo::TRANSLATE:
|
||||
snap = config.snapTranslation;
|
||||
ImGui::InputFloat3("Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::ROTATE:
|
||||
snap = config.snapRotation;
|
||||
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::SCALE:
|
||||
snap = config.snapScale;
|
||||
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||
break;
|
||||
switch (mCurrentGizmoOperation) {
|
||||
case ImGuizmo::TRANSLATE:
|
||||
snap = config.snapTranslation;
|
||||
ImGui::InputFloat3("Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::ROTATE:
|
||||
snap = config.snapRotation;
|
||||
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::SCALE:
|
||||
snap = config.snapScale;
|
||||
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||
break;
|
||||
}
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0], mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0], NULL, useSnap ? &snap.x : NULL);
|
||||
ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0],
|
||||
mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0],
|
||||
NULL, useSnap ? &snap.x : NULL);
|
||||
}
|
||||
|
||||
void DrawMesh(const example::Mesh<float> *mesh)
|
||||
{
|
||||
void DrawMesh(const example::Mesh<float> *mesh) {
|
||||
// TODO(LTE): Use vertex array or use display list.
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
@@ -579,20 +590,17 @@ void DrawMesh(const example::Mesh<float> *mesh)
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 0],
|
||||
mesh->facevarying_normals[9 * i + 1],
|
||||
mesh->facevarying_normals[9 * i + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0],
|
||||
mesh->vertices[3 * f0 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1],
|
||||
mesh->vertices[3 * f0 + 2]);
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 3],
|
||||
mesh->facevarying_normals[9 * i + 4],
|
||||
mesh->facevarying_normals[9 * i + 5]);
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0],
|
||||
mesh->vertices[3 * f1 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1],
|
||||
mesh->vertices[3 * f1 + 2]);
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 6],
|
||||
mesh->facevarying_normals[9 * i + 7],
|
||||
mesh->facevarying_normals[9 * i + 8]);
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0],
|
||||
mesh->vertices[3 * f2 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1],
|
||||
mesh->vertices[3 * f2 + 2]);
|
||||
}
|
||||
|
||||
@@ -602,23 +610,19 @@ void DrawMesh(const example::Mesh<float> *mesh)
|
||||
unsigned int f1 = mesh->faces[3 * i + 1];
|
||||
unsigned int f2 = mesh->faces[3 * i + 2];
|
||||
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0],
|
||||
mesh->vertices[3 * f0 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1],
|
||||
mesh->vertices[3 * f0 + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0],
|
||||
mesh->vertices[3 * f1 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1],
|
||||
mesh->vertices[3 * f1 + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0],
|
||||
mesh->vertices[3 * f2 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1],
|
||||
mesh->vertices[3 * f2 + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node)
|
||||
{
|
||||
void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node) {
|
||||
glPushMatrix();
|
||||
glMultMatrixf(node.GetLocalXformPtr());
|
||||
|
||||
@@ -634,8 +638,8 @@ void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node)
|
||||
}
|
||||
|
||||
// Draw scene with OpenGL
|
||||
void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const Camera &camera)
|
||||
{
|
||||
void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene,
|
||||
const Camera &camera) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
@@ -649,11 +653,12 @@ void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const C
|
||||
const float light_diffuse[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, &light0_pos[0]);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, &light1_pos[0]);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]);
|
||||
|
||||
const std::vector<nanosg::Node<float, example::Mesh<float> > > &root_nodes = scene.GetNodes();
|
||||
const std::vector<nanosg::Node<float, example::Mesh<float> > > &root_nodes =
|
||||
scene.GetNodes();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
@@ -675,15 +680,12 @@ void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const C
|
||||
glDisable(GL_LIGHT1);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
}
|
||||
|
||||
void BuildSceneItems(
|
||||
std::vector<std::string> *display_names,
|
||||
std::vector<std::string> *names,
|
||||
const nanosg::Node<float, example::Mesh<float> > &node,
|
||||
int indent)
|
||||
{
|
||||
void BuildSceneItems(std::vector<std::string> *display_names,
|
||||
std::vector<std::string> *names,
|
||||
const nanosg::Node<float, example::Mesh<float> > &node,
|
||||
int indent) {
|
||||
if (node.GetName().empty()) {
|
||||
// Skip a node with empty name.
|
||||
return;
|
||||
@@ -699,14 +701,16 @@ void BuildSceneItems(
|
||||
|
||||
display_names->push_back(display_name);
|
||||
names->push_back(node.GetName());
|
||||
|
||||
|
||||
for (size_t i = 0; i < node.GetChildren().size(); i++) {
|
||||
BuildSceneItems(display_names, names, node.GetChildren()[i], indent + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// tigra: add default material
|
||||
example::Material default_material;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string config_filename = "config.json";
|
||||
|
||||
if (argc > 1) {
|
||||
@@ -729,13 +733,47 @@ int main(int argc, char** argv) {
|
||||
std::vector<example::Material> materials;
|
||||
std::vector<example::Texture> textures;
|
||||
|
||||
bool ret = LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale, &meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load glTF [ " << gRenderConfig.gltf_filename << " ]" << std::endl;
|
||||
return -1;
|
||||
// tigra: set default material to 95% white diffuse
|
||||
default_material.diffuse[0] = 0.95f;
|
||||
default_material.diffuse[1] = 0.95f;
|
||||
default_material.diffuse[2] = 0.95f;
|
||||
|
||||
default_material.specular[0] = 0;
|
||||
default_material.specular[1] = 0;
|
||||
default_material.specular[2] = 0;
|
||||
|
||||
// Material pushed as first material on the list
|
||||
materials.push_back(default_material);
|
||||
|
||||
if (!gRenderConfig.obj_filename.empty()) {
|
||||
bool ret = LoadObj(gRenderConfig.obj_filename, gRenderConfig.scene_scale,
|
||||
&meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load .obj [ " << gRenderConfig.obj_filename
|
||||
<< " ]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gRenderConfig.gltf_filename.empty()) {
|
||||
std::cout << "Found gltf file : " << gRenderConfig.gltf_filename << "\n";
|
||||
|
||||
bool ret =
|
||||
LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale,
|
||||
&meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load glTF file [ "
|
||||
<< gRenderConfig.gltf_filename << " ]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (textures.size() > 0) {
|
||||
materials[0].diffuse_texid = 0;
|
||||
}
|
||||
|
||||
gAsset.materials = materials;
|
||||
gAsset.default_material = default_material;
|
||||
gAsset.textures = textures;
|
||||
|
||||
for (size_t n = 0; n < meshes.size(); n++) {
|
||||
@@ -744,12 +782,20 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < gAsset.meshes.size(); n++) {
|
||||
|
||||
nanosg::Node<float, example::Mesh<float> > node(&gAsset.meshes[n]);
|
||||
|
||||
// case where the name of a mesh isn't defined in the loaded file
|
||||
if (gAsset.meshes[n].name.empty()) {
|
||||
std::string generatedName = "unnamed_" + std::to_string(n);
|
||||
gAsset.meshes[n].name = generatedName;
|
||||
meshes[n].name = generatedName;
|
||||
}
|
||||
|
||||
node.SetName(meshes[n].name);
|
||||
node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform as node's local transform.
|
||||
node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform
|
||||
// as node's local transform.
|
||||
gNodes.push_back(node);
|
||||
|
||||
|
||||
gScene.AddNode(node);
|
||||
}
|
||||
|
||||
@@ -761,11 +807,12 @@ int main(int argc, char** argv) {
|
||||
float bmin[3], bmax[3];
|
||||
gScene.GetBoundingBox(bmin, bmax);
|
||||
printf(" # of nodes : %d\n", int(gNodes.size()));
|
||||
printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
|
||||
printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
|
||||
|
||||
printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1],
|
||||
bmin[2]);
|
||||
printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1],
|
||||
bmax[2]);
|
||||
}
|
||||
|
||||
|
||||
std::vector<const char *> imgui_node_names;
|
||||
std::vector<std::string> display_node_names;
|
||||
std::vector<std::string> node_names;
|
||||
@@ -773,13 +820,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < gScene.GetNodes().size(); i++) {
|
||||
BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i], /* indent */0);
|
||||
BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i],
|
||||
/* indent */ 0);
|
||||
}
|
||||
|
||||
// List of strings for imgui.
|
||||
// Assume nodes in the scene does not change.
|
||||
for (size_t i = 0; i < display_node_names.size(); i++) {
|
||||
//std::cout << "name : " << display_node_names[i] << std::endl;
|
||||
// std::cout << "name : " << display_node_names[i] << std::endl;
|
||||
imgui_node_names.push_back(display_node_names[i].c_str());
|
||||
}
|
||||
|
||||
@@ -788,13 +836,13 @@ int main(int argc, char** argv) {
|
||||
nanosg::Node<float, example::Mesh<float> > *node;
|
||||
|
||||
if (gScene.FindNode(node_names[i], &node)) {
|
||||
//std::cout << "id : " << i << ", name : " << node_names[i] << std::endl;
|
||||
// std::cout << "id : " << i << ", name : " << node_names[i] <<
|
||||
// std::endl;
|
||||
node_map[i] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window = new b3gDefaultOpenGLWindow;
|
||||
b3gWindowConstructionInfo ci;
|
||||
#ifdef USE_OPENGL2
|
||||
@@ -834,11 +882,12 @@ int main(int argc, char** argv) {
|
||||
window->setResizeCallback(resizeCallback);
|
||||
checkErrors("resize");
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui_ImplBtGui_Init(window);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.Fonts->AddFontDefault();
|
||||
//io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f);
|
||||
// io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f);
|
||||
|
||||
glm::mat4 projection(1.0f);
|
||||
glm::mat4 view(1.0f);
|
||||
@@ -861,7 +910,7 @@ int main(int argc, char** argv) {
|
||||
ImGuizmo::BeginFrame();
|
||||
ImGuizmo::Enable(true);
|
||||
|
||||
//ImGuiIO &io = ImGui::GetIO();
|
||||
// ImGuiIO &io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
|
||||
ImGui::Begin("UI");
|
||||
@@ -897,7 +946,7 @@ int main(int argc, char** argv) {
|
||||
ImGui::InputFloat("show pos scale", &gShowPositionScale);
|
||||
|
||||
ImGui::InputFloat2("show depth range", gShowDepthRange);
|
||||
ImGui::Checkbox("show depth pesudo color", &gShowDepthPeseudoColor);
|
||||
ImGui::Checkbox("show depth pseudo color", &gShowDepthPeseudoColor);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
@@ -908,38 +957,47 @@ int main(int argc, char** argv) {
|
||||
|
||||
checkErrors("clear");
|
||||
|
||||
// fix max passes issue
|
||||
if (gShowBufferMode_prv != gShowBufferMode) {
|
||||
gRenderConfig.pass = 0;
|
||||
gShowBufferMode_prv = gShowBufferMode;
|
||||
}
|
||||
|
||||
// Render display window
|
||||
{
|
||||
static GLint gl_texid = -1;
|
||||
if (gl_texid < 0) {
|
||||
gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width, gRenderConfig.height, 4);
|
||||
gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width,
|
||||
gRenderConfig.height, 4);
|
||||
}
|
||||
|
||||
// Refresh texture until rendering finishes.
|
||||
if (gRenderConfig.pass < gRenderConfig.max_passes) {
|
||||
// FIXME(LTE): Do not update GL texture frequently.
|
||||
UpdateDisplayTextureGL(gl_texid, gRenderConfig.width, gRenderConfig.height);
|
||||
UpdateDisplayTextureGL(gl_texid, gRenderConfig.width,
|
||||
gRenderConfig.height);
|
||||
}
|
||||
|
||||
ImGui::Begin("Render");
|
||||
ImTextureID tex_id = reinterpret_cast<void *>(
|
||||
static_cast<intptr_t>(gl_texid));
|
||||
ImTextureID tex_id =
|
||||
reinterpret_cast<void *>(static_cast<intptr_t>(gl_texid));
|
||||
ImGui::Image(tex_id, ImVec2(256, 256), ImVec2(0, 0),
|
||||
ImVec2(1, 1));// Setup camera and draw imguizomo
|
||||
ImVec2(1, 1)); // Setup camera and draw imguizomo
|
||||
|
||||
ImGui::End();
|
||||
|
||||
}
|
||||
|
||||
// scene graph tree
|
||||
glm::mat4 node_matrix;
|
||||
static int node_selected = 0;
|
||||
static int node_selected_index = 0;
|
||||
{
|
||||
ImGui::Begin("Scene");
|
||||
|
||||
ImGui::ListBox("Node list", &node_selected, imgui_node_names.data(), imgui_node_names.size(), 16);
|
||||
node_matrix = glm::make_mat4(node_map[node_selected]->GetLocalXformPtr());
|
||||
ImGui::ListBox("Node list", &node_selected_index, imgui_node_names.data(),
|
||||
imgui_node_names.size(), 16);
|
||||
|
||||
auto node_selected = node_map.at(node_selected_index);
|
||||
node_matrix = glm::make_mat4(node_selected->GetLocalXformPtr());
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -964,11 +1022,14 @@ int main(int argc, char** argv) {
|
||||
up[2] = gRenderConfig.up[2];
|
||||
|
||||
// NOTE(LTE): w, then (x,y,z) for glm::quat.
|
||||
glm::quat rot = glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]);
|
||||
glm::quat rot =
|
||||
glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]);
|
||||
glm::mat4 rm = glm::mat4_cast(rot);
|
||||
|
||||
view = glm::lookAt(eye, lookat, up) * glm::inverse(glm::mat4_cast(rot));
|
||||
projection = glm::perspective (45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f, 1000.0f);
|
||||
projection = glm::perspective(
|
||||
45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f,
|
||||
1000.0f);
|
||||
|
||||
camera.view = view;
|
||||
camera.projection = projection;
|
||||
@@ -978,10 +1039,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
float mat[4][4];
|
||||
memcpy(mat, &node_matrix[0][0], sizeof(float) * 16);
|
||||
node_map[node_selected]->SetLocalXform(mat);
|
||||
node_map[node_selected_index]->SetLocalXform(mat);
|
||||
|
||||
checkErrors("edit_transform");
|
||||
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace example {
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO(syoyo): Support PBR material.
|
||||
namespace example {
|
||||
|
||||
struct Material {
|
||||
// float ambient[3];
|
||||
@@ -53,6 +58,7 @@ struct Texture {
|
||||
int width;
|
||||
int height;
|
||||
int components;
|
||||
int _pad_;
|
||||
unsigned char* image;
|
||||
|
||||
Texture() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace example {
|
||||
|
||||
@@ -69,9 +70,13 @@ inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3], const T v2[3
|
||||
template<typename T>
|
||||
class Mesh {
|
||||
public:
|
||||
explicit Mesh(const size_t vertex_stride) :
|
||||
stride(vertex_stride) {
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
std::vector<T> vertices; /// [xyz] * num_vertices
|
||||
std::vector<T> vertices; /// stride * num_vertices
|
||||
std::vector<T> facevarying_normals; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_tangents; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_binormals; /// [xyz] * 3(triangle) * num_faces
|
||||
@@ -82,6 +87,7 @@ class Mesh {
|
||||
std::vector<unsigned int> material_ids; /// index x num_faces
|
||||
|
||||
T pivot_xform[4][4];
|
||||
size_t stride; /// stride for vertex data.
|
||||
|
||||
// --- Required methods in Scene::Traversal. ---
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "nanort.h"
|
||||
+208
-125
@@ -44,6 +44,13 @@ THE SOFTWARE.
|
||||
|
||||
namespace nanort {
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Parallelized BVH build is not yet fully tested,
|
||||
// thus turn off if you face a problem when building BVH.
|
||||
#define NANORT_ENABLE_PARALLEL_BUILD (1)
|
||||
@@ -301,9 +308,7 @@ class real3 {
|
||||
real3 operator/(const real3 &f2) const {
|
||||
return real3(x() / f2.x(), y() / f2.y(), z() / f2.z());
|
||||
}
|
||||
real3 operator-() const {
|
||||
return real3(-x(), -y(), -z());
|
||||
}
|
||||
real3 operator-() const { return real3(-x(), -y(), -z()); }
|
||||
T operator[](int i) const { return v[i]; }
|
||||
T &operator[](int i) { return v[i]; }
|
||||
|
||||
@@ -330,8 +335,8 @@ template <typename T>
|
||||
inline real3<T> vnormalize(const real3<T> &rhs) {
|
||||
real3<T> v = rhs;
|
||||
T len = vlength(rhs);
|
||||
if (fabs(len) > 1.0e-6f) {
|
||||
float inv_len = 1.0f / len;
|
||||
if (std::fabs(len) > static_cast<T>(1.0e-6)) {
|
||||
T inv_len = static_cast<T>(1.0) / len;
|
||||
v.v[0] *= inv_len;
|
||||
v.v[1] *= inv_len;
|
||||
v.v[2] *= inv_len;
|
||||
@@ -363,9 +368,7 @@ inline const real *get_vertex_addr(const real *p, const size_t idx,
|
||||
template <typename T = float>
|
||||
class Ray {
|
||||
public:
|
||||
Ray()
|
||||
: min_t(static_cast<T>(0.0))
|
||||
, max_t(std::numeric_limits<T>::max()) {
|
||||
Ray() : min_t(static_cast<T>(0.0)), max_t(std::numeric_limits<T>::max()) {
|
||||
org[0] = static_cast<T>(0.0);
|
||||
org[1] = static_cast<T>(0.0);
|
||||
org[2] = static_cast<T>(0.0);
|
||||
@@ -374,11 +377,11 @@ class Ray {
|
||||
dir[2] = static_cast<T>(-1.0);
|
||||
}
|
||||
|
||||
T org[3]; // must set
|
||||
T dir[3]; // must set
|
||||
T min_t; // minium ray hit distance.
|
||||
T max_t; // maximum ray hit distance.
|
||||
T inv_dir[3]; // filled internally
|
||||
T org[3]; // must set
|
||||
T dir[3]; // must set
|
||||
T min_t; // minimum ray hit distance.
|
||||
T max_t; // maximum ray hit distance.
|
||||
T inv_dir[3]; // filled internally
|
||||
int dir_sign[3]; // filled internally
|
||||
};
|
||||
|
||||
@@ -386,6 +389,38 @@ template <typename T = float>
|
||||
class BVHNode {
|
||||
public:
|
||||
BVHNode() {}
|
||||
BVHNode(const BVHNode &rhs) {
|
||||
bmin[0] = rhs.bmin[0];
|
||||
bmin[1] = rhs.bmin[1];
|
||||
bmin[2] = rhs.bmin[2];
|
||||
flag = rhs.flag;
|
||||
|
||||
bmax[0] = rhs.bmax[0];
|
||||
bmax[1] = rhs.bmax[1];
|
||||
bmax[2] = rhs.bmax[2];
|
||||
axis = rhs.axis;
|
||||
|
||||
data[0] = rhs.data[0];
|
||||
data[1] = rhs.data[1];
|
||||
}
|
||||
|
||||
BVHNode &operator=(const BVHNode &rhs) {
|
||||
bmin[0] = rhs.bmin[0];
|
||||
bmin[1] = rhs.bmin[1];
|
||||
bmin[2] = rhs.bmin[2];
|
||||
flag = rhs.flag;
|
||||
|
||||
bmax[0] = rhs.bmax[0];
|
||||
bmax[1] = rhs.bmax[1];
|
||||
bmax[2] = rhs.bmax[2];
|
||||
axis = rhs.axis;
|
||||
|
||||
data[0] = rhs.data[0];
|
||||
data[1] = rhs.data[1];
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~BVHNode() {}
|
||||
|
||||
T bmin[3];
|
||||
@@ -480,14 +515,26 @@ class BBox {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class NodeHit
|
||||
{
|
||||
template <typename T>
|
||||
class NodeHit {
|
||||
public:
|
||||
NodeHit()
|
||||
: t_min(std::numeric_limits<T>::max())
|
||||
, t_max(-std::numeric_limits<T>::max())
|
||||
, node_id(static_cast<unsigned int>(-1)) {
|
||||
: t_min(std::numeric_limits<T>::max()),
|
||||
t_max(-std::numeric_limits<T>::max()),
|
||||
node_id(static_cast<unsigned int>(-1)) {}
|
||||
|
||||
NodeHit(const NodeHit<T> &rhs) {
|
||||
t_min = rhs.t_min;
|
||||
t_max = rhs.t_max;
|
||||
node_id = rhs.node_id;
|
||||
}
|
||||
|
||||
NodeHit &operator=(const NodeHit<T> &rhs) {
|
||||
t_min = rhs.t_min;
|
||||
t_max = rhs.t_max;
|
||||
node_id = rhs.node_id;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~NodeHit() {}
|
||||
@@ -497,9 +544,8 @@ class NodeHit
|
||||
unsigned int node_id;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class NodeHitComparator
|
||||
{
|
||||
template <typename T>
|
||||
class NodeHitComparator {
|
||||
public:
|
||||
inline bool operator()(const NodeHit<T> &a, const NodeHit<T> &b) {
|
||||
return a.t_min < b.t_min;
|
||||
@@ -512,29 +558,37 @@ class BVHAccel {
|
||||
BVHAccel() : pad0_(0) { (void)pad0_; }
|
||||
~BVHAccel() {}
|
||||
|
||||
///
|
||||
/// Build BVH for input primitives.
|
||||
template<class P, class Pred>
|
||||
bool Build(const unsigned int num_primitives,
|
||||
const P &p, const Pred &pred, const BVHBuildOptions<T> &options = BVHBuildOptions<T>());
|
||||
///
|
||||
template <class P, class Pred>
|
||||
bool Build(const unsigned int num_primitives, const P &p, const Pred &pred,
|
||||
const BVHBuildOptions<T> &options = BVHBuildOptions<T>());
|
||||
|
||||
///
|
||||
/// Get statistics of built BVH tree. Valid after Build()
|
||||
///
|
||||
BVHBuildStatistics GetStatistics() const { return stats_; }
|
||||
|
||||
///
|
||||
/// Dump built BVH to the file.
|
||||
///
|
||||
bool Dump(const char *filename);
|
||||
|
||||
///
|
||||
/// Load BVH binary
|
||||
///
|
||||
bool Load(const char *filename);
|
||||
|
||||
void Debug();
|
||||
|
||||
///
|
||||
/// Traverse into BVH along ray and find closest hit point & primitive if
|
||||
/// found
|
||||
template<class I, class H>
|
||||
bool Traverse(const Ray<T> &ray,
|
||||
const I &intersector,
|
||||
H *isect,
|
||||
const BVHTraceOptions& options = BVHTraceOptions()) const;
|
||||
///
|
||||
template <class I, class H>
|
||||
bool Traverse(const Ray<T> &ray, const I &intersector, H *isect,
|
||||
const BVHTraceOptions &options = BVHTraceOptions()) const;
|
||||
|
||||
#if 0
|
||||
/// Multi-hit ray traversal
|
||||
@@ -551,16 +605,17 @@ class BVHAccel {
|
||||
/// List up nodes which intersects along the ray.
|
||||
/// This function is useful for two-level BVH traversal.
|
||||
///
|
||||
template<class I>
|
||||
bool ListNodeIntersections(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
template <class I>
|
||||
bool ListNodeIntersections(const Ray<T> &ray, int max_intersections,
|
||||
const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const;
|
||||
|
||||
const std::vector<BVHNode<T> > &GetNodes() const { return nodes_; }
|
||||
const std::vector<unsigned int> &GetIndices() const { return indices_; }
|
||||
|
||||
///
|
||||
/// Returns bounding box of built BVH.
|
||||
///
|
||||
void BoundingBox(T bmin[3], T bmax[3]) const {
|
||||
if (nodes_.empty()) {
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<T>::max();
|
||||
@@ -589,7 +644,7 @@ class BVHAccel {
|
||||
std::vector<ShallowNodeInfo> shallow_node_infos_;
|
||||
|
||||
/// Builds shallow BVH tree recursively.
|
||||
template<class P, class Pred>
|
||||
template <class P, class Pred>
|
||||
unsigned int BuildShallowTree(std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx,
|
||||
unsigned int depth,
|
||||
@@ -598,22 +653,22 @@ class BVHAccel {
|
||||
#endif
|
||||
|
||||
/// Builds BVH tree recursively.
|
||||
template<class P, class Pred>
|
||||
template <class P, class Pred>
|
||||
unsigned int BuildTree(BVHBuildStatistics *out_stat,
|
||||
std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx,
|
||||
unsigned int depth, const P &p, const Pred &pred);
|
||||
|
||||
template<class I>
|
||||
template <class I>
|
||||
bool TestLeafNode(const BVHNode<T> &node, const Ray<T> &ray,
|
||||
const I &intersector) const;
|
||||
|
||||
template<class I>
|
||||
bool TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > *isect_pq) const;
|
||||
template <class I>
|
||||
bool TestLeafNodeIntersections(
|
||||
const BVHNode<T> &node, const Ray<T> &ray, const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> > *isect_pq) const;
|
||||
|
||||
#if 0
|
||||
template<class I, class H, class Comp>
|
||||
@@ -663,7 +718,7 @@ class TriangleSAHPred {
|
||||
|
||||
T center = p0[axis] + p1[axis] + p2[axis];
|
||||
|
||||
return (center < pos * 3.0);
|
||||
return (center < pos * static_cast<T>(3.0));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -762,7 +817,7 @@ class TriangleIntersector {
|
||||
/// distance `t`,
|
||||
/// varycentric coordinate `u` and `v`.
|
||||
/// Returns true if there's intersection.
|
||||
bool Intersect(T *t_inout, unsigned int prim_index) const {
|
||||
bool Intersect(T *t_inout, const unsigned int prim_index) const {
|
||||
if ((prim_index < trace_options_.prim_ids_range[0]) ||
|
||||
(prim_index >= trace_options_.prim_ids_range[1])) {
|
||||
return false;
|
||||
@@ -791,8 +846,13 @@ class TriangleIntersector {
|
||||
T V = Ax * Cy - Ay * Cx;
|
||||
T W = Bx * Ay - By * Ax;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
// Fall back to test against edges using double precision.
|
||||
if (U == 0.0 || V == 0.0 || W == 0.0) {
|
||||
if (U == static_cast<T>(0.0) || V == static_cast<T>(0.0) || W == static_cast<T>(0.0)) {
|
||||
double CxBy = static_cast<double>(Cx) * static_cast<double>(By);
|
||||
double CyBx = static_cast<double>(Cy) * static_cast<double>(Bx);
|
||||
U = static_cast<T>(CxBy - CyBx);
|
||||
@@ -807,15 +867,19 @@ class TriangleIntersector {
|
||||
}
|
||||
|
||||
if (trace_options_.cull_back_face) {
|
||||
if (U < 0.0 || V < 0.0 || W < 0.0) return false;
|
||||
if (U < static_cast<T>(0.0) || V < static_cast<T>(0.0) || W < static_cast<T>(0.0)) return false;
|
||||
} else {
|
||||
if ((U < 0.0 || V < 0.0 || W < 0.0) && (U > 0.0 || V > 0.0 || W > 0.0)) {
|
||||
if ((U < static_cast<T>(0.0) || V < static_cast<T>(0.0) || W < static_cast<T>(0.0)) && (U > static_cast<T>(0.0) || V > static_cast<T>(0.0) || W > static_cast<T>(0.0))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
T det = U + V + W;
|
||||
if (det == 0.0) return false;
|
||||
if (det == static_cast<T>(0.0)) return false;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
const T Az = ray_coeff_.Sz * A[ray_coeff_.kz];
|
||||
const T Bz = ray_coeff_.Sz * B[ray_coeff_.kz];
|
||||
@@ -829,6 +893,10 @@ class TriangleIntersector {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tt < t_min_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*t_inout) = tt;
|
||||
// Use Thomas-Mueller style barycentric coord.
|
||||
// U + V + W = 1.0 and interp(p) = U * p0 + V * p1 + W * p2
|
||||
@@ -884,6 +952,8 @@ class TriangleIntersector {
|
||||
|
||||
trace_options_ = trace_options;
|
||||
|
||||
t_min_ = ray.min_t;
|
||||
|
||||
u_ = 0.0f;
|
||||
v_ = 0.0f;
|
||||
}
|
||||
@@ -901,19 +971,20 @@ class TriangleIntersector {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const T *vertices_;
|
||||
const unsigned int *faces_;
|
||||
const size_t vertex_stride_bytes_;
|
||||
|
||||
|
||||
mutable real3<T> ray_org_;
|
||||
mutable RayCoeff ray_coeff_;
|
||||
mutable BVHTraceOptions trace_options_;
|
||||
mutable T t_min_;
|
||||
|
||||
mutable T t_;
|
||||
mutable T u_;
|
||||
mutable T v_;
|
||||
mutable T t_;
|
||||
mutable T u_;
|
||||
mutable T v_;
|
||||
mutable unsigned int prim_id_;
|
||||
int _pad_;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -950,7 +1021,8 @@ struct BinBuffer {
|
||||
template <typename T>
|
||||
inline T CalculateSurfaceArea(const real3<T> &min, const real3<T> &max) {
|
||||
real3<T> box = max - min;
|
||||
return static_cast<T>(2.0) * (box[0] * box[1] + box[1] * box[2] + box[2] * box[0]);
|
||||
return static_cast<T>(2.0) *
|
||||
(box[0] * box[1] + box[1] * box[2] + box[2] * box[0]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -994,12 +1066,12 @@ inline void ContributeBinBuffer(BinBuffer *bins, // [out]
|
||||
real3<T> scene_size, scene_inv_size;
|
||||
scene_size = scene_max - scene_min;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
assert(scene_size[i] >= 0.0);
|
||||
assert(scene_size[i] >= static_cast<T>(0.0));
|
||||
|
||||
if (scene_size[i] > 0.0) {
|
||||
if (scene_size[i] > static_cast<T>(0.0)) {
|
||||
scene_inv_size[i] = bin_size / scene_size[i];
|
||||
} else {
|
||||
scene_inv_size[i] = 0.0;
|
||||
scene_inv_size[i] = static_cast<T>(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,7 +1129,8 @@ inline T SAH(size_t ns1, T leftArea, size_t ns2, T rightArea, T invS, T Taabb,
|
||||
T Ttri) {
|
||||
T sah;
|
||||
|
||||
sah = static_cast<T>(2.0) * Taabb + (leftArea * invS) * static_cast<T>(ns1) * Ttri +
|
||||
sah = static_cast<T>(2.0) * Taabb +
|
||||
(leftArea * invS) * static_cast<T>(ns1) * Ttri +
|
||||
(rightArea * invS) * static_cast<T>(ns2) * Ttri;
|
||||
|
||||
return sah;
|
||||
@@ -1079,22 +1152,22 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
T pos;
|
||||
T minCost[3];
|
||||
|
||||
T costTtri = 1.0f - costTaabb;
|
||||
T costTtri = static_cast<T>(1.0) - costTaabb;
|
||||
|
||||
(*minCostAxis) = 0;
|
||||
|
||||
bsize = bmax - bmin;
|
||||
bstep = bsize * (1.0f / bins->bin_size);
|
||||
bstep = bsize * (static_cast<T>(1.0) / bins->bin_size);
|
||||
saTotal = CalculateSurfaceArea(bmin, bmax);
|
||||
|
||||
T invSaTotal = 0.0f;
|
||||
T invSaTotal = static_cast<T>(0.0);
|
||||
if (saTotal > kEPS) {
|
||||
invSaTotal = 1.0f / saTotal;
|
||||
invSaTotal = static_cast<T>(1.0) / saTotal;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
//
|
||||
// Compute SAH cost for right side of each cell of the bbox.
|
||||
// Compute SAH cost for the right side of each cell of the bbox.
|
||||
// Exclude both extreme side of the bbox.
|
||||
//
|
||||
// i: 0 1 2 3
|
||||
@@ -1103,7 +1176,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
// +----+----+----+----+----+
|
||||
//
|
||||
|
||||
T minCostPos = bmin[j] + 0.5f * bstep[j];
|
||||
T minCostPos = bmin[j] + static_cast<T>(1.0) * bstep[j];
|
||||
minCost[j] = std::numeric_limits<T>::max();
|
||||
|
||||
left = 0;
|
||||
@@ -1127,7 +1200,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
// +1 for i since we want a position on right side of the cell.
|
||||
//
|
||||
|
||||
pos = bmin[j] + (i + 0.5f) * bstep[j];
|
||||
pos = bmin[j] + (i + static_cast<T>(1.0)) * bstep[j];
|
||||
bmaxLeft[j] = pos;
|
||||
bminRight[j] = pos;
|
||||
|
||||
@@ -1280,11 +1353,14 @@ inline void GetBoundingBox(real3<T> *bmin, real3<T> *bmax,
|
||||
//
|
||||
|
||||
#if NANORT_ENABLE_PARALLEL_BUILD
|
||||
template <typename T> template<class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildShallowTree(
|
||||
std::vector<BVHNode<T> > *out_nodes, unsigned int left_idx,
|
||||
unsigned int right_idx, unsigned int depth, unsigned int max_shallow_depth,
|
||||
const P &p, const Pred &pred) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildShallowTree(std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx,
|
||||
unsigned int right_idx,
|
||||
unsigned int depth,
|
||||
unsigned int max_shallow_depth,
|
||||
const P &p, const Pred &pred) {
|
||||
assert(left_idx <= right_idx);
|
||||
|
||||
unsigned int offset = static_cast<unsigned int>(out_nodes->size());
|
||||
@@ -1424,11 +1500,13 @@ unsigned int BVHAccel<T>::BuildShallowTree(
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> template<class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildTree(
|
||||
BVHBuildStatistics *out_stat, std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx, unsigned int depth,
|
||||
const P &p, const Pred &pred) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildTree(BVHBuildStatistics *out_stat,
|
||||
std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx,
|
||||
unsigned int right_idx, unsigned int depth,
|
||||
const P &p, const Pred &pred) {
|
||||
assert(left_idx <= right_idx);
|
||||
|
||||
unsigned int offset = static_cast<unsigned int>(out_nodes->size());
|
||||
@@ -1554,10 +1632,10 @@ unsigned int BVHAccel<T>::BuildTree(
|
||||
return offset;
|
||||
}
|
||||
|
||||
template <typename T> template<class P, class Pred>
|
||||
bool BVHAccel<T>::Build(unsigned int num_primitives,
|
||||
const P &p, const Pred &pred,
|
||||
const BVHBuildOptions<T> &options) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
bool BVHAccel<T>::Build(unsigned int num_primitives, const P &p,
|
||||
const Pred &pred, const BVHBuildOptions<T> &options) {
|
||||
options_ = options;
|
||||
stats_ = BVHBuildStatistics();
|
||||
|
||||
@@ -1566,6 +1644,10 @@ bool BVHAccel<T>::Build(unsigned int num_primitives,
|
||||
|
||||
assert(options_.bin_size > 1);
|
||||
|
||||
if (num_primitives == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int n = num_primitives;
|
||||
|
||||
//
|
||||
@@ -1697,15 +1779,9 @@ void BVHAccel<T>::Debug() {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n",
|
||||
int(i),
|
||||
nodes_[i].bmin[0],
|
||||
nodes_[i].bmin[1],
|
||||
nodes_[i].bmin[1],
|
||||
nodes_[i].bmax[0],
|
||||
nodes_[i].bmax[1],
|
||||
nodes_[i].bmax[1]);
|
||||
|
||||
printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n", int(i),
|
||||
nodes_[i].bmin[0], nodes_[i].bmin[1], nodes_[i].bmin[1],
|
||||
nodes_[i].bmax[0], nodes_[i].bmax[1], nodes_[i].bmax[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1713,7 +1789,7 @@ template <typename T>
|
||||
bool BVHAccel<T>::Dump(const char *filename) {
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
//fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename);
|
||||
// fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1744,7 +1820,7 @@ template <typename T>
|
||||
bool BVHAccel<T>::Load(const char *filename) {
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
//fprintf(stderr, "Cannot open file: %s\n", filename);
|
||||
// fprintf(stderr, "Cannot open file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1815,10 +1891,10 @@ inline bool IntersectRayAABB(T *tminOut, // [out]
|
||||
return false; // no hit
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const I &intersector) const {
|
||||
template <typename T>
|
||||
template <class I>
|
||||
inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node, const Ray<T> &ray,
|
||||
const I &intersector) const {
|
||||
bool hit = false;
|
||||
|
||||
unsigned int num_primitives = node.data[0];
|
||||
@@ -1841,20 +1917,18 @@ inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node,
|
||||
|
||||
T local_t = t;
|
||||
if (intersector.Intersect(&local_t, prim_idx)) {
|
||||
if (local_t > ray.min_t) {
|
||||
// Update isect state
|
||||
t = local_t;
|
||||
// Update isect state
|
||||
t = local_t;
|
||||
|
||||
intersector.Update(t, prim_idx);
|
||||
hit = true;
|
||||
}
|
||||
intersector.Update(t, prim_idx);
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Implement
|
||||
#if 0 // TODO(LTE): Implement
|
||||
template <typename T> template<class I, class H, class Comp>
|
||||
bool BVHAccel<T>::MultiHitTestLeafNode(
|
||||
std::priority_queue<H, std::vector<H>, Comp> *isect_pq,
|
||||
@@ -1928,11 +2002,10 @@ bool BVHAccel<T>::MultiHitTestLeafNode(
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> template<class I, class H>
|
||||
bool BVHAccel<T>::Traverse(const Ray<T> &ray,
|
||||
const I &intersector,
|
||||
H *isect,
|
||||
const BVHTraceOptions &options) const {
|
||||
template <typename T>
|
||||
template <class I, class H>
|
||||
bool BVHAccel<T>::Traverse(const Ray<T> &ray, const I &intersector, H *isect,
|
||||
const BVHTraceOptions &options) const {
|
||||
const int kMaxStackDepth = 512;
|
||||
|
||||
T hit_t = ray.max_t;
|
||||
@@ -1999,13 +2072,14 @@ bool BVHAccel<T>::Traverse(const Ray<T> &ray,
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > *isect_pq) const {
|
||||
|
||||
template <typename T>
|
||||
template <class I>
|
||||
inline bool BVHAccel<T>::TestLeafNodeIntersections(
|
||||
const BVHNode<T> &node, const Ray<T> &ray, const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> > *isect_pq) const {
|
||||
bool hit = false;
|
||||
|
||||
unsigned int num_primitives = node.data[0];
|
||||
@@ -2043,7 +2117,6 @@ inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
isect_pq->pop();
|
||||
|
||||
isect_pq->push(isect);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2052,11 +2125,11 @@ inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
return hit;
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const {
|
||||
template <typename T>
|
||||
template <class I>
|
||||
bool BVHAccel<T>::ListNodeIntersections(
|
||||
const Ray<T> &ray, int max_intersections, const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const {
|
||||
const int kMaxStackDepth = 512;
|
||||
|
||||
T hit_t = ray.max_t;
|
||||
@@ -2066,14 +2139,19 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
node_stack[0] = 0;
|
||||
|
||||
// Stores furthest intersection at top
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > isect_pq;
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> >
|
||||
isect_pq;
|
||||
|
||||
(*hits)->clear();
|
||||
|
||||
int dir_sign[3];
|
||||
dir_sign[0] = ray.dir[0] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[1] = ray.dir[1] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[2] = ray.dir[2] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[0] =
|
||||
ray.dir[0] < static_cast<T>(0.0) ? 1 : 0;
|
||||
dir_sign[1] =
|
||||
ray.dir[1] < static_cast<T>(0.0) ? 1 : 0;
|
||||
dir_sign[2] =
|
||||
ray.dir[2] < static_cast<T>(0.0) ? 1 : 0;
|
||||
|
||||
// @fixme { Check edge case; i.e., 1/0 }
|
||||
real3<T> ray_inv_dir;
|
||||
@@ -2108,7 +2186,8 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
|
||||
} else { // leaf node
|
||||
if (hit) {
|
||||
TestLeafNodeIntersections(node, ray, max_intersections, intersector, &isect_pq);
|
||||
TestLeafNodeIntersections(node, ray, max_intersections, intersector,
|
||||
&isect_pq);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2132,7 +2211,7 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Implement
|
||||
#if 0 // TODO(LTE): Implement
|
||||
template <typename T> template<class I, class H, class Comp>
|
||||
bool BVHAccel<T>::MultiHitTraverse(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
@@ -2225,6 +2304,10 @@ bool BVHAccel<T>::MultiHitTraverse(const Ray<T> &ray,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace nanort
|
||||
|
||||
#endif // NANORT_H_
|
||||
|
||||
+185
-203
@@ -31,35 +31,36 @@ THE SOFTWARE.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "nanort.h"
|
||||
|
||||
namespace nanosg {
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
class PrimitiveInterface;
|
||||
|
||||
template<class T>
|
||||
class PrimitiveInterface{
|
||||
public:
|
||||
void print(){ static_cast<T &>(this)->print(); }
|
||||
template <class T>
|
||||
class PrimitiveInterface {
|
||||
public:
|
||||
void print() { static_cast<T &>(this)->print(); }
|
||||
};
|
||||
|
||||
class SpherePrimitive : PrimitiveInterface<SpherePrimitive> {
|
||||
public:
|
||||
void print(){ std::cout << "Sphere" << std::endl; }
|
||||
public:
|
||||
void print() { std::cout << "Sphere" << std::endl; }
|
||||
};
|
||||
|
||||
// 4x4 matrix
|
||||
template <typename T> class Matrix {
|
||||
public:
|
||||
template <typename T>
|
||||
class Matrix {
|
||||
public:
|
||||
Matrix();
|
||||
~Matrix();
|
||||
|
||||
static void Print(T m[4][4]) {
|
||||
static void Print(const T m[4][4]) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
printf("m[%d] = %f, %f, %f, %f\n", i, m[i][0], m[i][1], m[i][2], m[i][3]);
|
||||
}
|
||||
@@ -232,18 +233,15 @@ public:
|
||||
dst[1] = tmp[1];
|
||||
dst[2] = tmp[2];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//typedef Matrix<float> Matrixf;
|
||||
//typedef Matrix<double> Matrixd;
|
||||
|
||||
template<typename T>
|
||||
static void XformBoundingBox(T xbmin[3], // out
|
||||
T xbmax[3], // out
|
||||
T bmin[3], T bmax[3],
|
||||
T m[4][4]) {
|
||||
// typedef Matrix<float> Matrixf;
|
||||
// typedef Matrix<double> Matrixd;
|
||||
|
||||
template <typename T>
|
||||
static void XformBoundingBox(T xbmin[3], // out
|
||||
T xbmax[3], // out
|
||||
T bmin[3], T bmax[3], T m[4][4]) {
|
||||
// create bounding vertex from (bmin, bmax)
|
||||
T b[8][3];
|
||||
|
||||
@@ -286,7 +284,6 @@ static void XformBoundingBox(T xbmin[3], // out
|
||||
xbmax[2] = xb[0][2];
|
||||
|
||||
for (int i = 1; i < 8; i++) {
|
||||
|
||||
xbmin[0] = std::min(xb[i][0], xbmin[0]);
|
||||
xbmin[1] = std::min(xb[i][1], xbmin[1]);
|
||||
xbmin[2] = std::min(xb[i][2], xbmin[2]);
|
||||
@@ -297,48 +294,45 @@ static void XformBoundingBox(T xbmin[3], // out
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Intersection
|
||||
{
|
||||
template <typename T>
|
||||
struct Intersection {
|
||||
// required fields.
|
||||
T t; // hit distance
|
||||
unsigned int prim_id; // primitive ID of the hit
|
||||
float u;
|
||||
float v;
|
||||
T t; // hit distance
|
||||
unsigned int prim_id; // primitive ID of the hit
|
||||
float u;
|
||||
float v;
|
||||
|
||||
unsigned int node_id; // node ID of the hit.
|
||||
nanort::real3<T> P; // intersection point
|
||||
nanort::real3<T> Ns; // shading normal
|
||||
nanort::real3<T> Ng; // geometric normal
|
||||
unsigned int node_id; // node ID of the hit.
|
||||
nanort::real3<T> P; // intersection point
|
||||
nanort::real3<T> Ns; // shading normal
|
||||
nanort::real3<T> Ng; // geometric normal
|
||||
};
|
||||
|
||||
///
|
||||
/// Renderable node
|
||||
///
|
||||
template<typename T, class M>
|
||||
class Node
|
||||
{
|
||||
template <typename T, class M>
|
||||
class Node {
|
||||
public:
|
||||
typedef Node<T, M> type;
|
||||
|
||||
explicit Node(const M *mesh)
|
||||
: mesh_(mesh)
|
||||
{
|
||||
xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits<T>::max();
|
||||
xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits<T>::max();
|
||||
explicit Node(const M *mesh) : mesh_(mesh) {
|
||||
xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits<T>::max();
|
||||
xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits<T>::max();
|
||||
|
||||
lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits<T>::max();
|
||||
lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits<T>::max();
|
||||
lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits<T>::max();
|
||||
lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits<T>::max();
|
||||
|
||||
Matrix<T>::Identity(local_xform_);
|
||||
Matrix<T>::Identity(xform_);
|
||||
Matrix<T>::Identity(inv_xform_);
|
||||
Matrix<T>::Identity(inv_xform33_); inv_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_transpose_xform33_); inv_transpose_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_xform33_);
|
||||
inv_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_transpose_xform33_);
|
||||
inv_transpose_xform33_[3][3] = static_cast<T>(0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~Node() {}
|
||||
~Node() {}
|
||||
|
||||
void Copy(const type &rhs) {
|
||||
Matrix<T>::Copy(local_xform_, rhs.local_xform_);
|
||||
@@ -369,53 +363,44 @@ class Node
|
||||
children_ = rhs.children_;
|
||||
}
|
||||
|
||||
Node(const type &rhs) {
|
||||
Copy(rhs);
|
||||
}
|
||||
Node(const type &rhs) { Copy(rhs); }
|
||||
|
||||
const type &operator=(const type &rhs) {
|
||||
Copy(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void SetName(const std::string &name) {
|
||||
name_ = name;
|
||||
}
|
||||
void SetName(const std::string &name) { name_ = name; }
|
||||
|
||||
const std::string &GetName() const {
|
||||
return name_;
|
||||
}
|
||||
const std::string &GetName() const { return name_; }
|
||||
|
||||
///
|
||||
/// Add child node.
|
||||
///
|
||||
void AddChild(const type &child) {
|
||||
children_.push_back(child);
|
||||
}
|
||||
void AddChild(const type &child) { children_.push_back(child); }
|
||||
|
||||
///
|
||||
/// Get chidren
|
||||
///
|
||||
const std::vector<type> &GetChildren() const {
|
||||
return children_;
|
||||
}
|
||||
const std::vector<type> &GetChildren() const { return children_; }
|
||||
|
||||
std::vector<type> &GetChildren() {
|
||||
return children_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Update internal state.
|
||||
///
|
||||
void Update(const T parent_xform[4][4]) {
|
||||
|
||||
if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) && (mesh_->faces.size() >= 3)) {
|
||||
std::vector<type> &GetChildren() { return children_; }
|
||||
|
||||
///
|
||||
/// Update internal state.
|
||||
///
|
||||
void Update(const T parent_xform[4][4]) {
|
||||
if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) &&
|
||||
(mesh_->faces.size() >= 3)) {
|
||||
// Assume mesh is composed of triangle faces only.
|
||||
nanort::TriangleMesh<float> triangle_mesh(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
||||
nanort::TriangleSAHPred<float> triangle_pred(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
||||
nanort::TriangleMesh<float> triangle_mesh(
|
||||
mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride);
|
||||
nanort::TriangleSAHPred<float> triangle_pred(
|
||||
mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride);
|
||||
|
||||
bool ret = accel_.Build(int(mesh_->faces.size()) / 3, triangle_mesh, triangle_pred);
|
||||
bool ret =
|
||||
accel_.Build(static_cast<unsigned int>(mesh_->faces.size()) / 3,
|
||||
triangle_mesh, triangle_pred);
|
||||
|
||||
// Update local bbox.
|
||||
if (ret) {
|
||||
@@ -433,7 +418,7 @@ class Node
|
||||
Matrix<T>::Copy(inv_xform_, xform_);
|
||||
Matrix<T>::Inverse(inv_xform_);
|
||||
|
||||
// Clear translation, then inverse(xform)
|
||||
// Clear translation, then inverse(xform)
|
||||
Matrix<T>::Copy(inv_xform33_, xform_);
|
||||
inv_xform33_[3][0] = static_cast<T>(0.0);
|
||||
inv_xform33_[3][1] = static_cast<T>(0.0);
|
||||
@@ -448,67 +433,61 @@ class Node
|
||||
for (size_t i = 0; i < children_.size(); i++) {
|
||||
children_[i].Update(xform_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Set local transformation.
|
||||
///
|
||||
///
|
||||
/// Set local transformation.
|
||||
///
|
||||
void SetLocalXform(const T xform[4][4]) {
|
||||
memcpy(local_xform_, xform, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
const T *GetLocalXformPtr() const {
|
||||
return &local_xform_[0][0];
|
||||
const T *GetLocalXformPtr() const { return &local_xform_[0][0]; }
|
||||
|
||||
const T *GetXformPtr() const { return &xform_[0][0]; }
|
||||
|
||||
const M *GetMesh() const { return mesh_; }
|
||||
|
||||
const nanort::BVHAccel<T> &GetAccel() const { return accel_; }
|
||||
|
||||
inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = xbmin_[0];
|
||||
bmin[1] = xbmin_[1];
|
||||
bmin[2] = xbmin_[2];
|
||||
|
||||
bmax[0] = xbmax_[0];
|
||||
bmax[1] = xbmax_[1];
|
||||
bmax[2] = xbmax_[2];
|
||||
}
|
||||
|
||||
const T *GetXformPtr() const {
|
||||
return &xform_[0][0];
|
||||
inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = lbmin_[0];
|
||||
bmin[1] = lbmin_[1];
|
||||
bmin[2] = lbmin_[2];
|
||||
|
||||
bmax[0] = lbmax_[0];
|
||||
bmax[1] = lbmax_[1];
|
||||
bmax[2] = lbmax_[2];
|
||||
}
|
||||
|
||||
const M *GetMesh() const {
|
||||
return mesh_;
|
||||
}
|
||||
|
||||
const nanort::BVHAccel<T> &GetAccel() const {
|
||||
return accel_;
|
||||
}
|
||||
|
||||
inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = xbmin_[0];
|
||||
bmin[1] = xbmin_[1];
|
||||
bmin[2] = xbmin_[2];
|
||||
|
||||
bmax[0] = xbmax_[0];
|
||||
bmax[1] = xbmax_[1];
|
||||
bmax[2] = xbmax_[2];
|
||||
}
|
||||
|
||||
inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = lbmin_[0];
|
||||
bmin[1] = lbmin_[1];
|
||||
bmin[2] = lbmin_[2];
|
||||
|
||||
bmax[0] = lbmax_[0];
|
||||
bmax[1] = lbmax_[1];
|
||||
bmax[2] = lbmax_[2];
|
||||
}
|
||||
|
||||
T local_xform_[4][4]; // Node's local transformation matrix.
|
||||
T xform_[4][4]; // Parent xform x local_xform.
|
||||
T inv_xform_[4][4]; // inverse(xform). world -> local
|
||||
T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for transforming direction vector)
|
||||
T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left 3x3 elements only(for transforming normal vector)
|
||||
T local_xform_[4][4]; // Node's local transformation matrix.
|
||||
T xform_[4][4]; // Parent xform x local_xform.
|
||||
T inv_xform_[4][4]; // inverse(xform). world -> local
|
||||
T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for
|
||||
// transforming direction vector)
|
||||
T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left
|
||||
// 3x3 elements only(for transforming normal
|
||||
// vector)
|
||||
|
||||
private:
|
||||
// bounding box(local space)
|
||||
T lbmin_[3];
|
||||
T lbmax_[3];
|
||||
|
||||
// bounding box(local space)
|
||||
T lbmin_[3];
|
||||
T lbmax_[3];
|
||||
// bounding box after xform(world space)
|
||||
T xbmin_[3];
|
||||
T xbmax_[3];
|
||||
|
||||
// bounding box after xform(world space)
|
||||
T xbmin_[3];
|
||||
T xbmax_[3];
|
||||
|
||||
nanort::BVHAccel<T> accel_;
|
||||
|
||||
std::string name_;
|
||||
@@ -516,16 +495,16 @@ class Node
|
||||
const M *mesh_;
|
||||
|
||||
std::vector<type> children_;
|
||||
|
||||
};
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
// Predefined SAH predicator for cube.
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxPred {
|
||||
public:
|
||||
NodeBBoxPred(const std::vector<Node<T, M> >* nodes) : axis_(0), pos_(0.0f), nodes_(nodes) {}
|
||||
NodeBBoxPred(const std::vector<Node<T, M> > *nodes)
|
||||
: axis_(0), pos_(0.0f), nodes_(nodes) {}
|
||||
|
||||
void Set(int axis, float pos) const {
|
||||
axis_ = axis;
|
||||
@@ -538,8 +517,8 @@ class NodeBBoxPred {
|
||||
|
||||
T bmin[3], bmax[3];
|
||||
|
||||
(*nodes_)[i].GetWorldBoundingBox(bmin, bmax);
|
||||
|
||||
(*nodes_)[i].GetWorldBoundingBox(bmin, bmax);
|
||||
|
||||
T center = bmax[axis] - bmin[axis];
|
||||
|
||||
return (center < pos);
|
||||
@@ -551,15 +530,15 @@ class NodeBBoxPred {
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxGeometry {
|
||||
public:
|
||||
NodeBBoxGeometry(const std::vector<Node<T, M> >* nodes)
|
||||
: nodes_(nodes) {}
|
||||
NodeBBoxGeometry(const std::vector<Node<T, M> > *nodes) : nodes_(nodes) {}
|
||||
|
||||
/// Compute bounding box for `prim_index`th cube.
|
||||
/// This function is called for each primitive in BVH build.
|
||||
void BoundingBox(nanort::real3<T>* bmin, nanort::real3<T>* bmax, unsigned int prim_index) const {
|
||||
void BoundingBox(nanort::real3<T> *bmin, nanort::real3<T> *bmax,
|
||||
unsigned int prim_index) const {
|
||||
T a[3], b[3];
|
||||
(*nodes_)[prim_index].GetWorldBoundingBox(a, b);
|
||||
(*bmin)[0] = a[0];
|
||||
@@ -570,10 +549,11 @@ class NodeBBoxGeometry {
|
||||
(*bmax)[2] = b[2];
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> >* nodes_;
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
mutable nanort::real3<T> ray_org_;
|
||||
mutable nanort::real3<T> ray_dir_;
|
||||
mutable nanort::BVHTraceOptions trace_options_;
|
||||
int _pad_;
|
||||
};
|
||||
|
||||
class NodeBBoxIntersection {
|
||||
@@ -587,14 +567,13 @@ class NodeBBoxIntersection {
|
||||
unsigned int prim_id;
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxIntersector {
|
||||
public:
|
||||
NodeBBoxIntersector(const std::vector<Node<T, M> >* nodes)
|
||||
: nodes_(nodes) {}
|
||||
|
||||
bool Intersect(float* out_t_min, float *out_t_max, unsigned int prim_index) const {
|
||||
NodeBBoxIntersector(const std::vector<Node<T, M> > *nodes) : nodes_(nodes) {}
|
||||
|
||||
bool Intersect(float *out_t_min, float *out_t_max,
|
||||
unsigned int prim_index) const {
|
||||
T bmin[3], bmax[3];
|
||||
|
||||
(*nodes_)[prim_index].GetWorldBoundingBox(bmin, bmax);
|
||||
@@ -634,7 +613,7 @@ class NodeBBoxIntersector {
|
||||
|
||||
/// Prepare BVH traversal(e.g. compute inverse ray direction)
|
||||
/// This function is called only once in BVH traversal.
|
||||
void PrepareTraversal(const nanort::Ray<float>& ray) const {
|
||||
void PrepareTraversal(const nanort::Ray<float> &ray) const {
|
||||
ray_org_[0] = ray.org[0];
|
||||
ray_org_[1] = ray.org[1];
|
||||
ray_org_[2] = ray.org[2];
|
||||
@@ -648,40 +627,37 @@ class NodeBBoxIntersector {
|
||||
ray_inv_dir_[1] = static_cast<T>(1.0) / ray.dir[1];
|
||||
ray_inv_dir_[2] = static_cast<T>(1.0) / ray.dir[2];
|
||||
|
||||
ray_dir_sign_[0] = ray.dir[0] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[0] = ray.dir[0] < static_cast<T>(0.0) ? 1 : 0;
|
||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? 1 : 0;
|
||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? 1 : 0;
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> >* nodes_;
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
mutable nanort::real3<T> ray_org_;
|
||||
mutable nanort::real3<T> ray_dir_;
|
||||
mutable nanort::real3<T> ray_inv_dir_;
|
||||
mutable int ray_dir_sign_[3];
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
class Scene
|
||||
{
|
||||
template <typename T, class M>
|
||||
class Scene {
|
||||
public:
|
||||
Scene() {
|
||||
Scene() {
|
||||
bmin_[0] = bmin_[1] = bmin_[2] = std::numeric_limits<T>::max();
|
||||
bmax_[0] = bmax_[1] = bmax_[2] = -std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
~Scene() {};
|
||||
~Scene() {}
|
||||
|
||||
///
|
||||
/// Add intersectable node to the scene.
|
||||
///
|
||||
bool AddNode(const Node<T, M> &node) {
|
||||
bool AddNode(const Node<T, M> &node) {
|
||||
nodes_.push_back(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> > &GetNodes() const {
|
||||
return nodes_;
|
||||
}
|
||||
const std::vector<Node<T, M> > &GetNodes() const { return nodes_; }
|
||||
|
||||
bool FindNode(const std::string &name, Node<T, M> **found_node) {
|
||||
if (!found_node) {
|
||||
@@ -702,11 +678,15 @@ class Scene
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Commit the scene. Must be called before tracing rays into the scene.
|
||||
///
|
||||
bool Commit() {
|
||||
// the scene should contains something
|
||||
if (nodes_.size() == 0) {
|
||||
std::cerr << "You are attempting to commit an empty scene!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update nodes.
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
@@ -719,21 +699,26 @@ class Scene
|
||||
// Build toplevel BVH.
|
||||
NodeBBoxGeometry<T, M> geom(&nodes_);
|
||||
NodeBBoxPred<T, M> pred(&nodes_);
|
||||
|
||||
// FIXME(LTE): Limit one leaf contains one node bbox primitive. This would work, but would be inefficient.
|
||||
// e.g. will miss some node when constructed BVH depth is larger than the value of BVHBuildOptions.
|
||||
// Implement more better and efficient BVH build and traverse for Toplevel BVH.
|
||||
|
||||
// FIXME(LTE): Limit one leaf contains one node bbox primitive. This would
|
||||
// work, but would be inefficient.
|
||||
// e.g. will miss some node when constructed BVH depth is larger than the
|
||||
// value of BVHBuildOptions.
|
||||
// Implement more better and efficient BVH build and traverse for Toplevel
|
||||
// BVH.
|
||||
nanort::BVHBuildOptions<T> build_options;
|
||||
build_options.min_leaf_primitives = 1;
|
||||
|
||||
bool ret = toplevel_accel_.Build(static_cast<unsigned int>(nodes_.size()), geom, pred, build_options);
|
||||
|
||||
bool ret = toplevel_accel_.Build(static_cast<unsigned int>(nodes_.size()),
|
||||
geom, pred, build_options);
|
||||
|
||||
nanort::BVHBuildStatistics stats = toplevel_accel_.GetStatistics();
|
||||
(void)stats;
|
||||
|
||||
//toplevel_accel_.Debug();
|
||||
// toplevel_accel_.Debug();
|
||||
|
||||
if (ret) {
|
||||
toplevel_accel_.BoundingBox(bmin_, bmax_);
|
||||
toplevel_accel_.BoundingBox(bmin_, bmax_);
|
||||
} else {
|
||||
// Set invalid bbox value.
|
||||
bmin_[0] = std::numeric_limits<T>::max();
|
||||
@@ -766,51 +751,54 @@ class Scene
|
||||
/// First find the intersection of nodes' bounding box using toplevel BVH.
|
||||
/// Then, trace into the hit node to find the intersection of the primitive.
|
||||
///
|
||||
template<class H>
|
||||
bool Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const {
|
||||
|
||||
template <class H>
|
||||
bool Traverse(nanort::Ray<T> &ray, H *isect,
|
||||
const bool cull_back_face = false) const {
|
||||
if (!toplevel_accel_.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int kMaxIntersections = 64;
|
||||
const int kMaxIntersections = 64;
|
||||
|
||||
bool has_hit = false;
|
||||
|
||||
|
||||
NodeBBoxIntersector<T, M> isector(&nodes_);
|
||||
nanort::StackVector<nanort::NodeHit<T>, 128> node_hits;
|
||||
bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections, isector, &node_hits);
|
||||
bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections,
|
||||
isector, &node_hits);
|
||||
|
||||
if (may_hit) {
|
||||
|
||||
T t_max = std::numeric_limits<T>::max();
|
||||
T t_nearest = t_max;
|
||||
if (may_hit) {
|
||||
T t_max = std::numeric_limits<T>::max();
|
||||
T t_nearest = t_max;
|
||||
|
||||
nanort::BVHTraceOptions trace_options;
|
||||
trace_options.cull_back_face = cull_back_face;
|
||||
|
||||
// Find actual intersection point.
|
||||
for (size_t i = 0; i < node_hits->size(); i++) {
|
||||
|
||||
// Early cull test.
|
||||
// Find actual intersection point.
|
||||
for (size_t i = 0; i < node_hits->size(); i++) {
|
||||
// Early cull test.
|
||||
if (t_nearest < node_hits[i].t_min) {
|
||||
//printf("near: %f, t_min: %f, t_max: %f\n", t_nearest, node_hits[i].t_min, node_hits[i].t_max);
|
||||
// printf("near: %f, t_min: %f, t_max: %f\n", t_nearest,
|
||||
// node_hits[i].t_min, node_hits[i].t_max);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(node_hits[i].node_id < nodes_.size());
|
||||
const Node<T, M> &node = nodes_[node_hits[i].node_id];
|
||||
|
||||
// Transform ray into node's local space
|
||||
// Transform ray into node's local space
|
||||
// TODO(LTE): Set ray tmin and tmax
|
||||
nanort::Ray<T> local_ray;
|
||||
Matrix<T>::MultV(local_ray.org, node.inv_xform_, ray.org);
|
||||
Matrix<T>::MultV(local_ray.dir, node.inv_xform33_, ray.dir);
|
||||
|
||||
nanort::TriangleIntersector<T, H> triangle_intersector(node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(), sizeof(T) * 3);
|
||||
nanort::TriangleIntersector<T, H> triangle_intersector(
|
||||
node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(),
|
||||
node.GetMesh()->stride);
|
||||
H local_isect;
|
||||
|
||||
bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector, &local_isect);
|
||||
bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector,
|
||||
&local_isect);
|
||||
|
||||
if (hit) {
|
||||
// Calulcate hit distance in world coordiante.
|
||||
@@ -828,6 +816,7 @@ class Scene
|
||||
po[2] = world_P[2] - ray.org[2];
|
||||
|
||||
float t_world = vlength(po);
|
||||
// printf("tworld %f, tnear %f\n", t_world, t_nearest);
|
||||
|
||||
if (t_world < t_nearest) {
|
||||
t_nearest = t_world;
|
||||
@@ -839,36 +828,30 @@ class Scene
|
||||
isect->v = local_isect.v;
|
||||
|
||||
// TODO(LTE): Implement
|
||||
T Ng[3], Ns[3]; // geometric normal, shading normal.
|
||||
T Ng[3], Ns[3]; // geometric normal, shading normal.
|
||||
|
||||
node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u,
|
||||
isect->v);
|
||||
|
||||
node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u, isect->v);
|
||||
|
||||
// Convert position and normal into world coordinate.
|
||||
isect->t = t_world;
|
||||
Matrix<T>::MultV(isect->P, node.xform_, local_P);
|
||||
Matrix<T>::MultV(isect->Ng, node.inv_transpose_xform33_,
|
||||
Ng);
|
||||
Matrix<T>::MultV(isect->Ns, node.inv_transpose_xform33_,
|
||||
Ns);
|
||||
}
|
||||
|
||||
Matrix<T>::MultV(isect->Ng, node.inv_transpose_xform33_, Ng);
|
||||
Matrix<T>::MultV(isect->Ns, node.inv_transpose_xform33_, Ns);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return has_hit;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Find a node by name.
|
||||
///
|
||||
bool FindNodeRecursive(const std::string &name, Node<T, M> *root, Node<T, M> **found_node) {
|
||||
|
||||
///
|
||||
bool FindNodeRecursive(const std::string &name, Node<T, M> *root,
|
||||
Node<T, M> **found_node) {
|
||||
if (root->GetName().compare(name) == 0) {
|
||||
(*found_node) = root;
|
||||
return true;
|
||||
@@ -882,19 +865,18 @@ class Scene
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Scene bounding box.
|
||||
// Valid after calling `Commit()`.
|
||||
T bmin_[3];
|
||||
T bmax_[3];
|
||||
|
||||
|
||||
// Toplevel BVH accel.
|
||||
nanort::BVHAccel<T> toplevel_accel_;
|
||||
std::vector<Node<T, M> > nodes_;
|
||||
std::vector<Node<T, M> > nodes_;
|
||||
};
|
||||
|
||||
} // namespace nanosg
|
||||
} // namespace nanosg
|
||||
|
||||
#endif // NANOSG_H_
|
||||
#endif // NANOSG_H_
|
||||
|
||||
@@ -0,0 +1,458 @@
|
||||
#include "obj-loader.h"
|
||||
#include "nanort.h" // for float3
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||
#pragma clang diagnostic ignored "-Wcast-align"
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#pragma clang diagnostic ignored "-Wvariadic-macros"
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#if __has_warning("-Wdouble-promotion")
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
#if __has_warning("-Wcomma")
|
||||
#pragma clang diagnostic ignored "-Wcomma"
|
||||
#endif
|
||||
#if __has_warning("-Wcast-qual")
|
||||
#pragma clang diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "stb_image.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
#include <unordered_map>
|
||||
#else
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#define USE_TEX_CACHE 1
|
||||
|
||||
namespace example {
|
||||
|
||||
typedef nanort::real3<float> float3;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
// TODO(LTE): Remove global static definition.
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
static std::unordered_map<std::string, int> hashed_tex;
|
||||
#else
|
||||
static std::map<std::string, int> hashed_tex;
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
inline void CalcNormal(float3 &N, float3 v0, float3 v1, float3 v2) {
|
||||
float3 v10 = v1 - v0;
|
||||
float3 v20 = v2 - v0;
|
||||
|
||||
N = vcross(v20, v10);
|
||||
N = vnormalize(N);
|
||||
}
|
||||
|
||||
static std::string GetBaseDir(const std::string &filepath) {
|
||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||
return "";
|
||||
}
|
||||
|
||||
static int LoadTexture(const std::string &filename,
|
||||
std::vector<Texture> *textures) {
|
||||
int idx;
|
||||
|
||||
if (filename.empty()) return -1;
|
||||
|
||||
std::cout << " Loading texture : " << filename << std::endl;
|
||||
Texture texture;
|
||||
|
||||
// tigra: find in cache. get index
|
||||
if (USE_TEX_CACHE) {
|
||||
if (hashed_tex.find(filename) != hashed_tex.end()) {
|
||||
puts("from cache");
|
||||
return hashed_tex[filename];
|
||||
}
|
||||
}
|
||||
|
||||
int w, h, n;
|
||||
unsigned char *data = stbi_load(filename.c_str(), &w, &h, &n, 0);
|
||||
if (data) {
|
||||
texture.width = w;
|
||||
texture.height = h;
|
||||
texture.components = n;
|
||||
|
||||
size_t n_elem = size_t(w * h * n);
|
||||
texture.image = new unsigned char[n_elem];
|
||||
for (size_t i = 0; i < n_elem; i++) {
|
||||
texture.image[i] = data[i];
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
textures->push_back(texture);
|
||||
|
||||
idx = int(textures->size()) - 1;
|
||||
|
||||
// tigra: store index to cache
|
||||
if (USE_TEX_CACHE) {
|
||||
hashed_tex[filename] = idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::cout << " Failed to load : " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ComputeBoundingBoxOfMesh(float bmin[3], float bmax[3],
|
||||
const example::Mesh<float> &mesh) {
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||
|
||||
for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
|
||||
bmin[0] = std::min(bmin[0], mesh.vertices[3 * i + 0]);
|
||||
bmin[1] = std::min(bmin[1], mesh.vertices[3 * i + 1]);
|
||||
bmin[2] = std::min(bmin[1], mesh.vertices[3 * i + 2]);
|
||||
|
||||
bmax[0] = std::max(bmax[0], mesh.vertices[3 * i + 0]);
|
||||
bmax[1] = std::max(bmax[1], mesh.vertices[3 * i + 1]);
|
||||
bmax[2] = std::max(bmax[2], mesh.vertices[3 * i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadObj(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *out_materials,
|
||||
std::vector<Texture> *out_textures) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
|
||||
std::string basedir = GetBaseDir(filename) + "/";
|
||||
const char *basepath = (basedir.compare("/") == 0) ? NULL : basedir.c_str();
|
||||
|
||||
// auto t_start = std::chrono::system_clock::now();
|
||||
|
||||
bool ret =
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
||||
basepath, /* triangulate */ true);
|
||||
|
||||
// auto t_end = std::chrono::system_clock::now();
|
||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// std::cout << "[LoadOBJ] Parse time : " << ms.count() << " [msecs]"
|
||||
// << std::endl;
|
||||
|
||||
std::cout << "[LoadOBJ] # of shapes in .obj : " << shapes.size() << std::endl;
|
||||
std::cout << "[LoadOBJ] # of materials in .obj : " << materials.size()
|
||||
<< std::endl;
|
||||
|
||||
{
|
||||
size_t total_num_vertices = 0;
|
||||
size_t total_num_faces = 0;
|
||||
|
||||
total_num_vertices = attrib.vertices.size() / 3;
|
||||
std::cout << " vertices : " << attrib.vertices.size() / 3 << std::endl;
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
std::cout << " shape[" << i << "].name : " << shapes[i].name
|
||||
<< std::endl;
|
||||
std::cout << " shape[" << i
|
||||
<< "].indices : " << shapes[i].mesh.indices.size() << std::endl;
|
||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||
|
||||
total_num_faces += shapes[i].mesh.indices.size() / 3;
|
||||
|
||||
// tigra: empty name convert to _id
|
||||
if (shapes[i].name.length() == 0) {
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
shapes[i].name = "_" + std::to_string(i);
|
||||
#else
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
shapes[i].name = "_" + ss.str();
|
||||
#endif
|
||||
std::cout << " EMPTY shape[" << i << "].name, new : " << shapes[i].name
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "[LoadOBJ] # of faces: " << total_num_faces << std::endl;
|
||||
std::cout << "[LoadOBJ] # of vertices: " << total_num_vertices << std::endl;
|
||||
}
|
||||
|
||||
// TODO(LTE): Implement tangents and binormals
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
Mesh<float> mesh(/* stride */ sizeof(float) * 3);
|
||||
|
||||
mesh.name = shapes[i].name;
|
||||
|
||||
const size_t num_faces = shapes[i].mesh.indices.size() / 3;
|
||||
mesh.faces.resize(num_faces * 3);
|
||||
mesh.material_ids.resize(num_faces);
|
||||
mesh.facevarying_normals.resize(num_faces * 3 * 3);
|
||||
mesh.facevarying_uvs.resize(num_faces * 3 * 2);
|
||||
mesh.vertices.resize(num_faces * 3 * 3);
|
||||
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
// reorder vertices. may create duplicated vertices.
|
||||
size_t f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
size_t f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
size_t f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
mesh.vertices[9 * f + 0] = scale * attrib.vertices[3 * f0 + 0];
|
||||
mesh.vertices[9 * f + 1] = scale * attrib.vertices[3 * f0 + 1];
|
||||
mesh.vertices[9 * f + 2] = scale * attrib.vertices[3 * f0 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 3] = scale * attrib.vertices[3 * f1 + 0];
|
||||
mesh.vertices[9 * f + 4] = scale * attrib.vertices[3 * f1 + 1];
|
||||
mesh.vertices[9 * f + 5] = scale * attrib.vertices[3 * f1 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 6] = scale * attrib.vertices[3 * f2 + 0];
|
||||
mesh.vertices[9 * f + 7] = scale * attrib.vertices[3 * f2 + 1];
|
||||
mesh.vertices[9 * f + 8] = scale * attrib.vertices[3 * f2 + 2];
|
||||
|
||||
mesh.faces[3 * f + 0] = static_cast<unsigned int>(3 * f + 0);
|
||||
mesh.faces[3 * f + 1] = static_cast<unsigned int>(3 * f + 1);
|
||||
mesh.faces[3 * f + 2] = static_cast<unsigned int>(3 * f + 2);
|
||||
|
||||
mesh.material_ids[f] =
|
||||
static_cast<unsigned int>(shapes[i].mesh.material_ids[f]);
|
||||
}
|
||||
|
||||
if (attrib.normals.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].normal_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].normal_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].normal_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float n0[3], n1[3], n2[3];
|
||||
|
||||
n0[0] = attrib.normals[3 * f0 + 0];
|
||||
n0[1] = attrib.normals[3 * f0 + 1];
|
||||
n0[2] = attrib.normals[3 * f0 + 2];
|
||||
|
||||
n1[0] = attrib.normals[3 * f1 + 0];
|
||||
n1[1] = attrib.normals[3 * f1 + 1];
|
||||
n1[2] = attrib.normals[3 * f1 + 2];
|
||||
|
||||
n2[0] = attrib.normals[3 * f2 + 0];
|
||||
n2[1] = attrib.normals[3 * f2 + 1];
|
||||
n2[2] = attrib.normals[3 * f2 + 2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = n0[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = n0[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = n1[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = n1[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = n2[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = n2[2];
|
||||
} else { // face contains invalid normal index. calc geometric normal.
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// calc geometric normal
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
|
||||
if (attrib.texcoords.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].texcoord_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].texcoord_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].texcoord_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float3 n0, n1, n2;
|
||||
|
||||
n0[0] = attrib.texcoords[2 * f0 + 0];
|
||||
n0[1] = attrib.texcoords[2 * f0 + 1];
|
||||
|
||||
n1[0] = attrib.texcoords[2 * f1 + 0];
|
||||
n1[1] = attrib.texcoords[2 * f1 + 1];
|
||||
|
||||
n2[0] = attrib.texcoords[2 * f2 + 0];
|
||||
n2[1] = attrib.texcoords[2 * f2 + 1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 1] = n0[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 1] = n1[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 1] = n2[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute pivot translation and add offset to the vertices.
|
||||
float bmin[3], bmax[3];
|
||||
ComputeBoundingBoxOfMesh(bmin, bmax, mesh);
|
||||
|
||||
float bcenter[3];
|
||||
bcenter[0] = 0.5f * (bmax[0] - bmin[0]) + bmin[0];
|
||||
bcenter[1] = 0.5f * (bmax[1] - bmin[1]) + bmin[1];
|
||||
bcenter[2] = 0.5f * (bmax[2] - bmin[2]) + bmin[2];
|
||||
|
||||
for (size_t v = 0; v < mesh.vertices.size() / 3; v++) {
|
||||
mesh.vertices[3 * v + 0] -= bcenter[0];
|
||||
mesh.vertices[3 * v + 1] -= bcenter[1];
|
||||
mesh.vertices[3 * v + 2] -= bcenter[2];
|
||||
}
|
||||
|
||||
mesh.pivot_xform[0][0] = 1.0f;
|
||||
mesh.pivot_xform[0][1] = 0.0f;
|
||||
mesh.pivot_xform[0][2] = 0.0f;
|
||||
mesh.pivot_xform[0][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[1][0] = 0.0f;
|
||||
mesh.pivot_xform[1][1] = 1.0f;
|
||||
mesh.pivot_xform[1][2] = 0.0f;
|
||||
mesh.pivot_xform[1][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[2][0] = 0.0f;
|
||||
mesh.pivot_xform[2][1] = 0.0f;
|
||||
mesh.pivot_xform[2][2] = 1.0f;
|
||||
mesh.pivot_xform[2][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[3][0] = bcenter[0];
|
||||
mesh.pivot_xform[3][1] = bcenter[1];
|
||||
mesh.pivot_xform[3][2] = bcenter[2];
|
||||
mesh.pivot_xform[3][3] = 1.0f;
|
||||
|
||||
meshes->push_back(mesh);
|
||||
}
|
||||
|
||||
// material_t -> Material and Texture
|
||||
out_materials->resize(materials.size());
|
||||
out_textures->resize(0);
|
||||
for (size_t i = 0; i < materials.size(); i++) {
|
||||
(*out_materials)[i].diffuse[0] = materials[i].diffuse[0];
|
||||
(*out_materials)[i].diffuse[1] = materials[i].diffuse[1];
|
||||
(*out_materials)[i].diffuse[2] = materials[i].diffuse[2];
|
||||
(*out_materials)[i].specular[0] = materials[i].specular[0];
|
||||
(*out_materials)[i].specular[1] = materials[i].specular[1];
|
||||
(*out_materials)[i].specular[2] = materials[i].specular[2];
|
||||
|
||||
(*out_materials)[i].id = int(i);
|
||||
|
||||
// map_Kd
|
||||
(*out_materials)[i].diffuse_texid =
|
||||
LoadTexture(materials[i].diffuse_texname, out_textures);
|
||||
// map_Ks
|
||||
(*out_materials)[i].specular_texid =
|
||||
LoadTexture(materials[i].specular_texname, out_textures);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace example
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef EXAMPLE_OBJ_LOADER_H_
|
||||
#define EXAMPLE_OBJ_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "material.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
///
|
||||
/// Loads wavefront .obj mesh
|
||||
///
|
||||
bool LoadObj(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
|
||||
}
|
||||
|
||||
#endif // EXAMPLE_OBJ_LOADER_H_
|
||||
@@ -1,12 +1,19 @@
|
||||
newoption {
|
||||
trigger = "with-gtk3nfd",
|
||||
description = "Build with native file dialog support(GTK3 required. Linux only)"
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "asan",
|
||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
||||
}
|
||||
|
||||
sources = {
|
||||
"stbi-impl.cc",
|
||||
"main.cc",
|
||||
"render.cc",
|
||||
"render-config.cc",
|
||||
"obj-loader.cc",
|
||||
"gltf-loader.cc",
|
||||
"matrix.cc",
|
||||
"../common/trackball.cc",
|
||||
@@ -16,7 +23,7 @@ sources = {
|
||||
"../common/imgui/ImGuizmo.cpp",
|
||||
}
|
||||
|
||||
solution "RaytraceSolution"
|
||||
solution "NanoSGSolution"
|
||||
configurations { "Release", "Debug" }
|
||||
|
||||
if os.is("Windows") then
|
||||
@@ -53,7 +60,6 @@ solution "RaytraceSolution"
|
||||
end
|
||||
|
||||
if os.is("Windows") then
|
||||
flags { "FatalCompileWarnings" }
|
||||
warnings "Extra" -- /W4
|
||||
|
||||
defines { "NOMINMAX" }
|
||||
|
||||
@@ -29,12 +29,24 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) {
|
||||
|
||||
picojson::object o = v.get<picojson::object>();
|
||||
|
||||
if (o.find("obj_filename") != o.end()) {
|
||||
if (o["obj_filename"].is<std::string>()) {
|
||||
config->obj_filename = o["obj_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (o.find("gltf_filename") != o.end()) {
|
||||
if (o["gltf_filename"].is<std::string>()) {
|
||||
config->gltf_filename = o["gltf_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (o.find("eson_filename") != o.end()) {
|
||||
if (o["eson_filename"].is<std::string>()) {
|
||||
config->eson_filename = o["eson_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
config->scene_scale = 1.0f;
|
||||
if (o.find("scene_scale") != o.end()) {
|
||||
if (o["scene_scale"].is<double>()) {
|
||||
@@ -107,4 +119,4 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace example
|
||||
|
||||
@@ -28,7 +28,9 @@ typedef struct {
|
||||
float *varycoordImage;
|
||||
|
||||
// Scene input info
|
||||
std::string obj_filename;
|
||||
std::string gltf_filename;
|
||||
std::string eson_filename;
|
||||
float scene_scale;
|
||||
|
||||
} RenderConfig;
|
||||
|
||||
+65
-17
@@ -200,6 +200,7 @@ void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v,
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Not used method. Delete.
|
||||
nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
|
||||
const float3& du, const float3& dv, float u,
|
||||
float v) {
|
||||
@@ -217,9 +218,12 @@ nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
|
||||
ray.org[1] = origin[1];
|
||||
ray.org[2] = origin[2];
|
||||
ray.dir[0] = dir[0];
|
||||
ray.dir[1] = dir[1];
|
||||
ray.dir[2] = dir[2];
|
||||
|
||||
return ray;
|
||||
}
|
||||
#endif
|
||||
|
||||
void FetchTexture(const Texture &texture, float u, float v, float* col) {
|
||||
int tx = u * texture.width;
|
||||
@@ -235,10 +239,15 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
const nanosg::Scene<float, example::Mesh<float>> &scene,
|
||||
const example::Asset &asset,
|
||||
const RenderConfig& config,
|
||||
std::atomic<bool>& cancelFlag) {
|
||||
std::atomic<bool>& cancelFlag,
|
||||
int &_showBufferMode
|
||||
) {
|
||||
//if (!gAccel.IsValid()) {
|
||||
// return false;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
int width = config.width;
|
||||
int height = config.height;
|
||||
@@ -300,6 +309,19 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
float u1 = pcg32_random(&rng);
|
||||
|
||||
float3 dir;
|
||||
|
||||
//for modes not a "color"
|
||||
if(_showBufferMode != SHOW_BUFFER_COLOR)
|
||||
{
|
||||
//only one pass
|
||||
if(config.pass > 0)
|
||||
continue;
|
||||
|
||||
//to the center of pixel
|
||||
u0 = 0.5f;
|
||||
u1 = 0.5f;
|
||||
}
|
||||
|
||||
dir = corner + (float(x) + u0) * u +
|
||||
(float(config.height - y - 1) + u1) * v;
|
||||
dir = vnormalize(dir);
|
||||
@@ -320,6 +342,9 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
const std::vector<Material> &materials = asset.materials;
|
||||
const std::vector<Texture> &textures = asset.textures;
|
||||
const Mesh<float> &mesh = asset.meshes[isect.node_id];
|
||||
|
||||
//tigra: add default material
|
||||
const Material &default_material = asset.default_material;
|
||||
|
||||
float3 p;
|
||||
p[0] =
|
||||
@@ -410,26 +435,49 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
// Fetch texture
|
||||
unsigned int material_id =
|
||||
mesh.material_ids[isect.prim_id];
|
||||
|
||||
//printf("material_id=%d materials=%lld\n", material_id, materials.size());
|
||||
|
||||
float diffuse_col[3];
|
||||
int diffuse_texid = materials[material_id].diffuse_texid;
|
||||
if (diffuse_texid >= 0) {
|
||||
FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col);
|
||||
} else {
|
||||
diffuse_col[0] = materials[material_id].diffuse[0];
|
||||
diffuse_col[1] = materials[material_id].diffuse[1];
|
||||
diffuse_col[2] = materials[material_id].diffuse[2];
|
||||
}
|
||||
|
||||
float specular_col[3];
|
||||
int specular_texid = materials[material_id].specular_texid;
|
||||
if (specular_texid >= 0) {
|
||||
FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col);
|
||||
} else {
|
||||
specular_col[0] = materials[material_id].specular[0];
|
||||
specular_col[1] = materials[material_id].specular[1];
|
||||
specular_col[2] = materials[material_id].specular[2];
|
||||
}
|
||||
|
||||
//tigra: material_id is ok
|
||||
if(material_id<materials.size())
|
||||
{
|
||||
//printf("ok mat\n");
|
||||
|
||||
int diffuse_texid = materials[material_id].diffuse_texid;
|
||||
if (diffuse_texid >= 0) {
|
||||
FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col);
|
||||
} else {
|
||||
diffuse_col[0] = materials[material_id].diffuse[0];
|
||||
diffuse_col[1] = materials[material_id].diffuse[1];
|
||||
diffuse_col[2] = materials[material_id].diffuse[2];
|
||||
}
|
||||
|
||||
int specular_texid = materials[material_id].specular_texid;
|
||||
if (specular_texid >= 0) {
|
||||
FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col);
|
||||
} else {
|
||||
specular_col[0] = materials[material_id].specular[0];
|
||||
specular_col[1] = materials[material_id].specular[1];
|
||||
specular_col[2] = materials[material_id].specular[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
//tigra: wrong material_id, use default_material
|
||||
{
|
||||
|
||||
//printf("default_material\n");
|
||||
|
||||
diffuse_col[0] = default_material.diffuse[0];
|
||||
diffuse_col[1] = default_material.diffuse[1];
|
||||
diffuse_col[2] = default_material.diffuse[2];
|
||||
specular_col[0] = default_material.specular[0];
|
||||
specular_col[1] = default_material.specular[1];
|
||||
specular_col[2] = default_material.specular[2];
|
||||
}
|
||||
|
||||
// Simple shading
|
||||
float NdotV = fabsf(vdot(N, dir));
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
|
||||
#include <atomic> // C++11
|
||||
|
||||
//mode definitions now here
|
||||
|
||||
#define SHOW_BUFFER_COLOR (0)
|
||||
#define SHOW_BUFFER_NORMAL (1)
|
||||
#define SHOW_BUFFER_POSITION (2)
|
||||
#define SHOW_BUFFER_DEPTH (3)
|
||||
#define SHOW_BUFFER_TEXCOORD (4)
|
||||
#define SHOW_BUFFER_VARYCOORD (5)
|
||||
|
||||
#include "render-config.h"
|
||||
#include "nanosg.h"
|
||||
#include "mesh.h"
|
||||
@@ -13,6 +22,9 @@ namespace example {
|
||||
struct Asset {
|
||||
std::vector<Mesh<float> > meshes;
|
||||
std::vector<Material> materials;
|
||||
|
||||
//tigra: add default material
|
||||
Material default_material;
|
||||
std::vector<Texture> textures;
|
||||
};
|
||||
|
||||
@@ -23,7 +35,10 @@ class Renderer {
|
||||
|
||||
/// Returns false when the rendering was canceled.
|
||||
static bool Render(float* rgba, float* aux_rgba, int *sample_counts, float quat[4],
|
||||
const nanosg::Scene<float, Mesh<float>> &scene, const Asset &asset, const RenderConfig& config, std::atomic<bool>& cancel_flag);
|
||||
const nanosg::Scene<float, Mesh<float>> &scene, const Asset &asset, const RenderConfig& config,
|
||||
std::atomic<bool>& cancel_flag,
|
||||
int& _showBufferMode
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
@@ -0,0 +1,357 @@
|
||||
# GNU Make project makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release_native
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
.PHONY: clean prebuild prelink
|
||||
|
||||
ifeq ($(config),release_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/native/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x64/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x32/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/native/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x64/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x32/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
OBJECTS := \
|
||||
$(OBJDIR)/X11OpenGLWindow.o \
|
||||
$(OBJDIR)/glew.o \
|
||||
$(OBJDIR)/ImGuizmo.o \
|
||||
$(OBJDIR)/imgui.o \
|
||||
$(OBJDIR)/imgui_draw.o \
|
||||
$(OBJDIR)/imgui_impl_btgui.o \
|
||||
$(OBJDIR)/trackball.o \
|
||||
$(OBJDIR)/gltf-loader.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/matrix.o \
|
||||
$(OBJDIR)/obj-loader.o \
|
||||
$(OBJDIR)/render-config.o \
|
||||
$(OBJDIR)/render.o \
|
||||
$(OBJDIR)/stbi-impl.o \
|
||||
|
||||
RESOURCES := \
|
||||
|
||||
CUSTOMFILES := \
|
||||
|
||||
SHELLTYPE := msdos
|
||||
ifeq (,$(ComSpec)$(COMSPEC))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
ifeq (/bin,$(findstring /bin,$(SHELL)))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
|
||||
$(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES)
|
||||
@echo Linking viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(TARGETDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
|
||||
endif
|
||||
$(SILENT) $(LINKCMD)
|
||||
$(POSTBUILDCMDS)
|
||||
|
||||
clean:
|
||||
@echo Cleaning viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) rm -f $(TARGET)
|
||||
$(SILENT) rm -rf $(OBJDIR)
|
||||
else
|
||||
$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
|
||||
$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
prebuild:
|
||||
$(PREBUILDCMDS)
|
||||
|
||||
prelink:
|
||||
$(PRELINKCMDS)
|
||||
|
||||
ifneq (,$(PCH))
|
||||
$(OBJECTS): $(GCH) $(PCH)
|
||||
$(GCH): $(PCH)
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
|
||||
endif
|
||||
|
||||
$(OBJDIR)/X11OpenGLWindow.o: ../common/OpenGLWindow/X11OpenGLWindow.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/glew.o: ../common/ThirdPartyLibs/Glew/glew.c
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/ImGuizmo.o: ../common/imgui/ImGuizmo.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui.o: ../common/imgui/imgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_draw.o: ../common/imgui/imgui_draw.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_impl_btgui.o: ../common/imgui/imgui_impl_btgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/trackball.o: ../common/trackball.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/gltf-loader.o: gltf-loader.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/main.o: main.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/matrix.o: matrix.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/obj-loader.o: obj-loader.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render-config.o: render-config.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render.o: render.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/stbi-impl.o: stbi-impl.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
|
||||
-include $(OBJECTS:%.o=%.d)
|
||||
ifneq (,$(PCH))
|
||||
-include $(OBJDIR)/$(notdir $(PCH)).d
|
||||
endif
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
clang++ -std=c++11 -I../../ -g -O1 -o saver main.cc
|
||||
@@ -0,0 +1 @@
|
||||
# Simple serialization API sample.
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
|
||||
//#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
// If using a modern Microsoft Compiler, this define supress compilation
|
||||
// warnings in stb_image_write
|
||||
//#define STBI_MSC_SECURE_CRT
|
||||
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cout << "Needs input.gltf output.gltf" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string output_filename(argv[2]);
|
||||
std::string embedded_filename =
|
||||
output_filename.substr(0, output_filename.size() - 5) + "-Embedded.gltf";
|
||||
|
||||
// assume ascii glTF.
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
|
||||
if (!warn.empty()) {
|
||||
std::cout << "warn : " << warn << std::endl;
|
||||
}
|
||||
if (!ret) {
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
loader.WriteGltfSceneToFile(&model, output_filename);
|
||||
|
||||
// Embedd buffers and images
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
loader.WriteGltfSceneToFile(&model, embedded_filename, true, true);
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -45,3 +45,9 @@ endif()
|
||||
|
||||
# test-zone
|
||||
# enable_testing()
|
||||
|
||||
install ( TARGETS
|
||||
tinygltf-validator
|
||||
DESTINATION
|
||||
bin
|
||||
)
|
||||
|
||||
@@ -9,6 +9,22 @@ Experimental. W.I.P.
|
||||
## Requirements
|
||||
|
||||
* C++11 compiler
|
||||
* CMake
|
||||
|
||||
## How to build
|
||||
|
||||
```
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
```
|
||||
$ gltf-validator /path/to/file.gltf /path/to/gltf-schema
|
||||
```
|
||||
|
||||
## Third party licenses
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Python script which generates C++11 code from JSON schema.
|
||||
|
||||
## Requirements
|
||||
|
||||
* python3
|
||||
* jsonref
|
||||
|
||||
## Generate
|
||||
|
||||
Run `gen.py` by specifing the path to glTF schema directory(from https://github.com/KhronosGroup/glTF.git)
|
||||
|
||||
```
|
||||
$ python gen.py /path/to/glTF/specification/2.0/schema
|
||||
```
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os
|
||||
import subprocess
|
||||
import json
|
||||
from pprint import pprint
|
||||
import jsonref
|
||||
|
||||
# glTF 2.0
|
||||
schema_files = [
|
||||
"glTF.schema.json"
|
||||
]
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Requires path to glTF scheme directory.")
|
||||
sys.exit(-1)
|
||||
|
||||
gltf_schema_dir = sys.argv[1]
|
||||
|
||||
gltf_schema_filepath = os.path.join(gltf_schema_dir, schema_files[0])
|
||||
if not os.path.exists(gltf_schema_filepath):
|
||||
print("File not found: {}".format(gltf_schema_filepath))
|
||||
sys.exit(-1)
|
||||
|
||||
gltf_schema_uri = 'file://{}/'.format(gltf_schema_dir)
|
||||
with open(gltf_schema_filepath) as schema_file:
|
||||
j = jsonref.loads(schema_file.read(), base_uri=gltf_schema_uri, jsonschema=True)
|
||||
pprint(j)
|
||||
|
||||
|
||||
|
||||
main()
|
||||
+80
-13
@@ -1,5 +1,9 @@
|
||||
//
|
||||
// TODO(syoyo): Print extensions and extras for each glTF object.
|
||||
//
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
#include <cstdio>
|
||||
@@ -135,7 +139,7 @@ static std::string PrintParameterType(int ty) {
|
||||
#endif
|
||||
|
||||
static std::string PrintWrapMode(int mode) {
|
||||
if (mode == TINYGLTF_TEXTURE_WRAP_RPEAT) {
|
||||
if (mode == TINYGLTF_TEXTURE_WRAP_REPEAT) {
|
||||
return "REPEAT";
|
||||
} else if (mode == TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE) {
|
||||
return "CLAMP_TO_EDGE";
|
||||
@@ -210,8 +214,21 @@ static std::string PrintParameterValue(const tinygltf::Parameter ¶m) {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << pmap.size() << std::endl;
|
||||
for (auto &kv : pmap) {
|
||||
ss << kv.first << " : " << PrintParameterValue(kv.second) << std::endl;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string PrintValue(const std::string &name,
|
||||
const tinygltf::Value &value, const int indent) {
|
||||
const tinygltf::Value &value, const int indent, const bool tag = true) {
|
||||
std::stringstream ss;
|
||||
|
||||
if (value.IsObject()) {
|
||||
@@ -219,19 +236,45 @@ static std::string PrintValue(const std::string &name,
|
||||
tinygltf::Value::Object::const_iterator it(o.begin());
|
||||
tinygltf::Value::Object::const_iterator itEnd(o.end());
|
||||
for (; it != itEnd; it++) {
|
||||
ss << PrintValue(name, it->second, indent + 1);
|
||||
ss << PrintValue(it->first, it->second, indent + 1) << std::endl;
|
||||
}
|
||||
} else if (value.IsString()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<std::string>()
|
||||
<< std::endl;
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<std::string>();
|
||||
} else {
|
||||
ss << " " << value.Get<std::string>() << " ";
|
||||
}
|
||||
} else if (value.IsBool()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<bool>() << std::endl;
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<bool>();
|
||||
} else {
|
||||
ss << " " << value.Get<bool>() << " ";
|
||||
}
|
||||
} else if (value.IsNumber()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<double>() << std::endl;
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<double>();
|
||||
} else {
|
||||
ss << " " << value.Get<double>() << " ";
|
||||
}
|
||||
} else if (value.IsInt()) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<int>() << std::endl;
|
||||
if (tag) {
|
||||
ss << Indent(indent) << name << " : " << value.Get<int>();
|
||||
} else {
|
||||
ss << " " << value.Get<int>() << " ";
|
||||
}
|
||||
} else if (value.IsArray()) {
|
||||
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 << ", ";
|
||||
}
|
||||
|
||||
}
|
||||
ss << Indent(indent) << "] ";
|
||||
}
|
||||
// @todo { binary, array }
|
||||
|
||||
// @todo { binary }
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@@ -287,6 +330,15 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
|
||||
}
|
||||
|
||||
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) {
|
||||
std::cout << "=== Dump glTF ===" << std::endl;
|
||||
std::cout << "asset.copyright : " << model.asset.copyright
|
||||
@@ -307,6 +359,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
for (size_t i = 0; i < model.scenes.size(); i++) {
|
||||
std::cout << Indent(1) << "scene[" << i
|
||||
<< "] name : " << model.scenes[i].name << std::endl;
|
||||
DumpExtensions(model.scenes[i].extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +397,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2) << "min : [";
|
||||
for (size_t k = 0; k < accessor.minValues.size(); k++) {
|
||||
std::cout << accessor.minValues[k]
|
||||
<< ((i != accessor.minValues.size() - 1) ? ", " : "");
|
||||
<< ((k != accessor.minValues.size() - 1) ? ", " : "");
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
@@ -352,7 +405,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2) << "max : [";
|
||||
for (size_t k = 0; k < accessor.maxValues.size(); k++) {
|
||||
std::cout << accessor.maxValues[k]
|
||||
<< ((i != accessor.maxValues.size() - 1) ? ", " : "");
|
||||
<< ((k != accessor.maxValues.size() - 1) ? ", " : "");
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
@@ -464,6 +517,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2) << "width : " << image.width << std::endl;
|
||||
std::cout << Indent(2) << "height : " << image.height << std::endl;
|
||||
std::cout << Indent(2) << "component : " << image.component << std::endl;
|
||||
DumpExtensions(image.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,6 +529,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "source : " << texture.source
|
||||
<< std::endl;
|
||||
DumpExtensions(texture.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,6 +585,12 @@ static void Dump(const tinygltf::Model &model) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// toplevel extensions
|
||||
{
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
|
||||
DumpExtensions(model.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -541,6 +602,7 @@ int main(int argc, char **argv) {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF gltf_ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
@@ -548,13 +610,18 @@ int main(int argc, char **argv) {
|
||||
if (ext.compare("glb") == 0) {
|
||||
std::cout << "Reading binary glTF" << std::endl;
|
||||
// assume binary glTF.
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, 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, 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());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
{
|
||||
"scenes" : [
|
||||
{
|
||||
"nodes" : [ 0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"nodes" : [
|
||||
{
|
||||
"mesh" : 0
|
||||
}
|
||||
],
|
||||
|
||||
"meshes" : [
|
||||
{
|
||||
"primitives" : [ {
|
||||
"attributes" : {
|
||||
"POSITION" : 0
|
||||
}
|
||||
} ]
|
||||
}
|
||||
],
|
||||
|
||||
"buffers" : [
|
||||
{
|
||||
"uri" : "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAA",
|
||||
"byteLength" : 36
|
||||
}
|
||||
],
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 36,
|
||||
"target" : 34962
|
||||
}
|
||||
],
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 3,
|
||||
"type" : "VEC3",
|
||||
"max" : [ 1.0, 1.0, 0.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"asset" : {
|
||||
"version" : "2.0"
|
||||
},
|
||||
|
||||
"materials" : [
|
||||
{ "name" : "WHITE",
|
||||
"extensions": {
|
||||
"VENDOR_material_some_ext" : { }
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"extensionsUsed" : [
|
||||
"VENDOR_material_some_ext"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -17,7 +17,7 @@ solution "TinyGLTFSolution"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
files { sources }
|
||||
flags { "c++11" }
|
||||
flags { "C++11" }
|
||||
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" } -- -DDEBUG
|
||||
+1831
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -28,7 +28,7 @@ def run(filename):
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(stdout, stderr) = p.communicate()
|
||||
except:
|
||||
print "Failed to execute: ", cmd
|
||||
print("Failed to execute: ", cmd)
|
||||
raise
|
||||
|
||||
if p.returncode != 0:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Use this for strict compilation check(will work on clang 3.8+)
|
||||
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -DTINYGLTF_APPLY_CLANG_WEVERYTHING
|
||||
|
||||
all: ../tiny_gltf.h
|
||||
clang++ -I../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o tester tester.cc
|
||||
clang++ -DTINYGLTF_NOEXCEPTION -I../ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
+10445
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
TEST_CASE("parse-error", "[parse]") {
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", strlen("bora"), /* basedir*/ "");
|
||||
|
||||
REQUIRE(false == ret);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("datauri-in-glb", "[issue-79]") {
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/box01.glb");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
REQUIRE(true == ret);
|
||||
}
|
||||
|
||||
TEST_CASE("extension-with-empty-object", "[issue-97]") {
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Extensions-issue97/test.gltf");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
|
||||
REQUIRE(model.extensionsUsed.size() == 1);
|
||||
REQUIRE(model.extensionsUsed[0].compare("VENDOR_material_some_ext") == 0);
|
||||
|
||||
REQUIRE(model.materials.size() == 1);
|
||||
REQUIRE(model.materials[0].extensions.size() == 1);
|
||||
REQUIRE(model.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
|
||||
|
||||
// TODO(syoyo): create temp directory.
|
||||
{
|
||||
ret = ctx.WriteGltfSceneToFile(&model, "issue-97.gltf", true, true);
|
||||
REQUIRE(true == ret);
|
||||
|
||||
tinygltf::Model m;
|
||||
|
||||
// read back serialized glTF
|
||||
bool ret = ctx.LoadASCIIFromFile(&m, &err, &warn, "issue-97.gltf");
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
REQUIRE(true == ret);
|
||||
|
||||
REQUIRE(m.extensionsUsed.size() == 1);
|
||||
REQUIRE(m.extensionsUsed[0].compare("VENDOR_material_some_ext") == 0);
|
||||
|
||||
REQUIRE(m.materials.size() == 1);
|
||||
REQUIRE(m.materials[0].extensions.size() == 1);
|
||||
REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2247
-753
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
.\\tools\\windows\\premake5.exe vs2013
|
||||
.\\tools\\windows\\premake5.exe vs2015
|
||||
|
||||
Reference in New Issue
Block a user