Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
350c296802 | ||
|
|
cc93e1fd25 | ||
|
|
59cc44ad4f | ||
|
|
1a5046e06b | ||
|
|
877d856e71 | ||
|
|
b534b6b0d8 | ||
|
|
ecfd37dee2 | ||
|
|
5c06b7d03b | ||
|
|
a75355b018 | ||
|
|
a977f7a16f | ||
|
|
5a6c55870e | ||
|
|
49caa65177 | ||
|
|
d71c6f61f3 | ||
|
|
b5d27fd151 | ||
|
|
af4456ba68 | ||
|
|
344669ddf6 | ||
|
|
967c98dd90 | ||
|
|
7658624bb4 | ||
|
|
84a83d39f5 | ||
|
|
03ad33cc8d | ||
|
|
3831802717 | ||
|
|
1f9a4b97a3 | ||
|
|
6dba104c54 | ||
|
|
b5e1b35ef1 | ||
|
|
52b73c7f0b | ||
|
|
98adbb3fb3 | ||
|
|
283b552a4e | ||
|
|
c2ca97b38b | ||
|
|
f051892c55 | ||
|
|
137a7ca999 | ||
|
|
477d977fea | ||
|
|
8cd5e759d0 | ||
|
|
a6c3945ed3 | ||
|
|
6614bddef3 | ||
|
|
385946dfd8 | ||
|
|
03bbe0921c | ||
|
|
a9121550b9 | ||
|
|
d2b0af6915 | ||
|
|
695608dd11 | ||
|
|
584f1dfbe4 | ||
|
|
a40ca4c5ab | ||
|
|
de75d87cfd | ||
|
|
cf11842e64 | ||
|
|
38003032e3 | ||
|
|
186016bf11 | ||
|
|
5ee08f9274 | ||
|
|
aa613a1f57 | ||
|
|
222454cc6d | ||
|
|
16c2d3a8bf | ||
|
|
186093657a | ||
|
|
9bdd256625 | ||
|
|
264ae4c131 | ||
|
|
091a1fcc1a | ||
|
|
3a295887d6 | ||
|
|
d9ce9eb9d2 | ||
|
|
56e1098993 | ||
|
|
9bb5806df4 | ||
|
|
1668d1ecc5 | ||
|
|
6e8a858c45 | ||
|
|
e0b625561c | ||
|
|
18450eafe7 | ||
|
|
e9fbc03e2d | ||
|
|
612e57816f | ||
|
|
a778c089d1 | ||
|
|
387fd61b83 | ||
|
|
6514490090 | ||
|
|
6b7ec9f494 | ||
|
|
c670f08a3b | ||
|
|
eec4c98862 | ||
|
|
c7e911cf11 | ||
|
|
43172238f7 | ||
|
|
0cc23356dc | ||
|
|
e413216722 | ||
|
|
4581d37bec | ||
|
|
966a9d0df7 | ||
|
|
64452bb5fa | ||
|
|
69eeea145b | ||
|
|
24e539621d | ||
|
|
f4f5c3cf3a | ||
|
|
b12a54ed15 | ||
|
|
240d993f94 | ||
|
|
46ee8b4276 | ||
|
|
3bddc09af4 | ||
|
|
9117abb45d | ||
|
|
52ff00a384 | ||
|
|
0fa56e239c | ||
|
|
5c2dd83964 | ||
|
|
1a8814d687 | ||
|
|
666ab8661c | ||
|
|
0b31543098 | ||
|
|
81f7dbe53a | ||
|
|
544969b732 | ||
|
|
3d4150419e | ||
|
|
41e1102e57 | ||
|
|
b901dd62d8 | ||
|
|
bc03ceaac1 | ||
|
|
2c9b25642b | ||
|
|
a894904f11 | ||
|
|
912856823d | ||
|
|
1a7c7d2001 | ||
|
|
fae6543b7a | ||
|
|
6ed7c39d71 | ||
|
|
5a90ab76ee | ||
|
|
0ffdc4334a | ||
|
|
53338352f2 | ||
|
|
d642c80a86 | ||
|
|
a1952053ee | ||
|
|
cbd3885049 | ||
|
|
9471517c1e | ||
|
|
e59028d68f | ||
|
|
cfab524125 | ||
|
|
9229971bcb | ||
|
|
051149311c | ||
|
|
0c7789b1e5 | ||
|
|
51b12d2546 | ||
|
|
4749b0989d | ||
|
|
0bfcb4f49e | ||
|
|
17e6e310ce | ||
|
|
07ceb4c313 | ||
|
|
e7f1ff5c59 | ||
|
|
fd904063c9 | ||
|
|
38398cc2da | ||
|
|
ed1a294bc4 | ||
|
|
b86eb6c079 | ||
|
|
e4bc6c7bd4 | ||
|
|
13803659f8 | ||
|
|
a3d5d5d1c9 | ||
|
|
9e3d1f6db5 | ||
|
|
190382aecd | ||
|
|
c6501530e3 | ||
|
|
ed48224f4b | ||
|
|
19a41d20ec | ||
|
|
0598a20cce | ||
|
|
514167b475 | ||
|
|
0f76561ebf | ||
|
|
f3dc4acaa4 | ||
|
|
1588e75e26 | ||
|
|
d1453b5e5e | ||
|
|
7e83ef9fb4 | ||
|
|
425195bf9c | ||
|
|
ce3a30e612 | ||
|
|
8a35b8f6fe | ||
|
|
f66f3bfeb3 | ||
|
|
e29ba7c49a | ||
|
|
bc753d4ac5 | ||
|
|
688ba8a60e | ||
|
|
d07b976d59 | ||
|
|
08a7dd8dad | ||
|
|
87da1e775f | ||
|
|
151495558e | ||
|
|
84e15260ba | ||
|
|
03cdef430d | ||
|
|
fb4bd82e2c | ||
|
|
3ddf8301f6 | ||
|
|
298c37a954 | ||
|
|
b702de755f | ||
|
|
58ceed1d89 | ||
|
|
d1b6b3a5aa | ||
|
|
c56d069726 | ||
|
|
d1e32865f1 | ||
|
|
869a9d273c | ||
|
|
1208f057d6 | ||
|
|
f684dde9f1 | ||
|
|
7905a5b4dc | ||
|
|
f161782001 | ||
|
|
654bcf733c | ||
|
|
001c870051 | ||
|
|
2c521b3432 | ||
|
|
a159945db9 | ||
|
|
010ee9c67b | ||
|
|
a23971c603 | ||
|
|
1923067982 | ||
|
|
68adc4ba5e | ||
|
|
42a8cd50ff | ||
|
|
0543640a83 | ||
|
|
9c59a0b64c | ||
|
|
452541a231 | ||
|
|
78fe8d9b89 | ||
|
|
51e5508fa0 | ||
|
|
91da299729 | ||
|
|
50ae8a31a8 | ||
|
|
0af0435ef1 | ||
|
|
7c342533e9 | ||
|
|
7842c1276f | ||
|
|
125e4a2033 | ||
|
|
c9d6c5b9b4 | ||
|
|
96a8b2c69b | ||
|
|
01d54380ac | ||
|
|
6cd8fdb2c8 | ||
|
|
fe01af2f01 | ||
|
|
efdd2b04dc | ||
|
|
2e642b3322 | ||
|
|
1739d025a9 | ||
|
|
39418e5728 | ||
|
|
5622d2762d | ||
|
|
3d939fd3ee | ||
|
|
fbbeb4d6a9 | ||
|
|
cef1787ef8 | ||
|
|
2f5aa9f13b | ||
|
|
28bafe4b11 | ||
|
|
34894a6325 | ||
|
|
2e7006797b | ||
|
|
d9c03d041a | ||
|
|
50a3061ddf | ||
|
|
014dce27f4 | ||
|
|
c046769054 | ||
|
|
c43266fdc9 | ||
|
|
aca196e8d3 | ||
|
|
b48c027c9a | ||
|
|
db5c3bea45 | ||
|
|
ddfa1f2f0b | ||
|
|
7b69c778fe | ||
|
|
73e73bf3c1 | ||
|
|
35d664e417 | ||
|
|
272a9dfa5f | ||
|
|
f3bf6ee78e | ||
|
|
aba57bb907 | ||
|
|
6fad7adb9c | ||
|
|
3dad303bea | ||
|
|
ff0a2e9fb4 | ||
|
|
fe77cc5cdd | ||
|
|
18f0e20a11 | ||
|
|
978adee547 | ||
|
|
73c4cce303 | ||
|
|
925b83627a | ||
|
|
92c23725ae | ||
|
|
af750a5104 | ||
|
|
ff48fa0ff4 | ||
|
|
ec45334d3d | ||
|
|
5f603c56dc | ||
|
|
063b8586f1 | ||
|
|
db855c6794 | ||
|
|
e391f6b03e | ||
|
|
5ecede71f0 | ||
|
|
40982716f9 | ||
|
|
4bdc96fb9b | ||
|
|
96ecea080a | ||
|
|
22bfc843ee | ||
|
|
eaa25a307a | ||
|
|
ab600b8e72 | ||
|
|
eb9d29c06e | ||
|
|
57356933c5 | ||
|
|
c3d6716c56 | ||
|
|
ac5e09f8c3 | ||
|
|
e2c3fe1c0b | ||
|
|
973d9b3394 | ||
|
|
28ad4ab7b8 | ||
|
|
0227ae5d9b | ||
|
|
a0a62bde1c | ||
|
|
23d1ff2880 | ||
|
|
bcf2ce586e | ||
|
|
aa3c5a1cad | ||
|
|
db2fbeec9d | ||
|
|
c4166e4c60 | ||
|
|
1cf179d377 | ||
|
|
ddc14f8ba6 | ||
|
|
72f4a55edd | ||
|
|
379bb612f1 | ||
|
|
1da4e5d633 | ||
|
|
4e47bc7799 | ||
|
|
9cc3e91968 | ||
|
|
d09788d10f | ||
|
|
a11f6e1939 | ||
|
|
8ced108571 | ||
|
|
3eb65e269a | ||
|
|
1322c7bf09 | ||
|
|
49651fe3d9 | ||
|
|
db93a87c4a | ||
|
|
7b0d81bf12 | ||
|
|
2e8a115d7e | ||
|
|
ae9364902a | ||
|
|
06d2fbdae6 | ||
|
|
d5ff5cbfb1 | ||
|
|
1d20520680 | ||
|
|
4ab0386d09 | ||
|
|
a471770f38 | ||
|
|
125d8e50a9 | ||
|
|
45cac78709 | ||
|
|
a9d86c1af4 | ||
|
|
2f26eddac4 | ||
|
|
a0939550ca | ||
|
|
58ab95be2f | ||
|
|
bf0e4f8e45 | ||
|
|
30f333c607 | ||
|
|
419162716e | ||
|
|
9533c352a1 | ||
|
|
9ff3d93084 | ||
|
|
aea514a975 | ||
|
|
05a4456948 | ||
|
|
6e08b17ce3 | ||
|
|
fb256609f2 | ||
|
|
5cecef2b92 | ||
|
|
1100f0f1eb | ||
|
|
2b66c81f67 | ||
|
|
f29375f59b | ||
|
|
79e3df26a8 | ||
|
|
e3cf5edb94 | ||
|
|
b74fadef8e | ||
|
|
a11709a9ff | ||
|
|
cf668683f9 | ||
|
|
817bbcfb58 | ||
|
|
23467959ca | ||
|
|
6f08785e9f | ||
|
|
ff2b1f92dd | ||
|
|
e886247329 | ||
|
|
83bb1a48d7 | ||
|
|
c3353e1acd | ||
|
|
81b672bcc2 | ||
|
|
cece6ee6d2 | ||
|
|
31f875ddbc | ||
|
|
8dccf9bf4e | ||
|
|
508dcfa2e6 | ||
|
|
7e009041e3 | ||
|
|
14977937c2 | ||
|
|
8bb18fbd9c | ||
|
|
9eeaf20133 | ||
|
|
a34aa8ea77 | ||
|
|
59b2966f81 | ||
|
|
7481011fd9 | ||
|
|
0d2b6efa6f | ||
|
|
ce7fa7419b | ||
|
|
906f98fa74 | ||
|
|
d2a2703ec5 | ||
|
|
95f05757d6 | ||
|
|
ab63db6318 | ||
|
|
6ff95392b0 | ||
|
|
c29bd3d9ce | ||
|
|
63419a11e1 | ||
|
|
06c30c4d04 | ||
|
|
67e6160a9a | ||
|
|
a3b8b355ae | ||
|
|
5145394239 | ||
|
|
67aa2ca75e | ||
|
|
ce25385eab | ||
|
|
6143c6662b | ||
|
|
81d75df48a | ||
|
|
83ccb9f28d | ||
|
|
9b6f52e98a | ||
|
|
5cecc41db9 | ||
|
|
208c3058bf | ||
|
|
cba5d6caae | ||
|
|
d1e1472992 | ||
|
|
ff51570c26 | ||
|
|
a472a3fa0f | ||
|
|
1f160d5b8f | ||
|
|
5150a46072 | ||
|
|
cea69e37a5 | ||
|
|
8b56c016ab | ||
|
|
c7e205be87 | ||
|
|
6dba6c6aac | ||
|
|
6df800d2b6 | ||
|
|
2f044e77f1 | ||
|
|
af5a5ef026 | ||
|
|
6591ba4461 | ||
|
|
74c3c10121 | ||
|
|
ad63bf748b | ||
|
|
5d43cf8e64 | ||
|
|
4e2988eebd | ||
|
|
ee179b2cb6 | ||
|
|
4ebd6368fb | ||
|
|
67d3d2504d | ||
|
|
d9a468bbb4 | ||
|
|
c7bae71f7f | ||
|
|
f93642c196 | ||
|
|
f68d5e1f2a | ||
|
|
1c84fc22a5 | ||
|
|
150f243b1b | ||
|
|
0ee273fdfa | ||
|
|
046400b17f | ||
|
|
89fd93f815 | ||
|
|
e940337796 | ||
|
|
1b5f476d95 | ||
|
|
52936a00e0 | ||
|
|
f3ef880029 | ||
|
|
1af7c1d784 | ||
|
|
c0b79afecc | ||
|
|
c49461b7c2 | ||
|
|
051f4be2f1 | ||
|
|
4557b6aa22 | ||
|
|
b2d7d88dbc | ||
|
|
b7ca7c9381 | ||
|
|
0ffedcbe79 | ||
|
|
80faac5238 | ||
|
|
2a9d9deb67 | ||
|
|
8a98d98cd9 | ||
|
|
689edcbef6 | ||
|
|
820ede87db | ||
|
|
d6b0d0a61f | ||
|
|
5f180aaf74 | ||
|
|
dab0daaedf | ||
|
|
0ccc8dc262 | ||
|
|
811e1d3899 | ||
|
|
f65e06c5ca | ||
|
|
f29ae1a653 | ||
|
|
3bf16e4be5 | ||
|
|
fbc4295770 | ||
|
|
edf8d5cae1 | ||
|
|
b7f2473225 | ||
|
|
ed7bf66255 | ||
|
|
caa36dd050 | ||
|
|
389d5016ad | ||
|
|
d02ad0dede | ||
|
|
8f67121deb | ||
|
|
62be8d04cf | ||
|
|
d11a4c4d71 | ||
|
|
19b806e052 | ||
|
|
e0ab69cb31 | ||
|
|
8915252407 | ||
|
|
9446f65667 | ||
|
|
fb9f709166 | ||
|
|
a63cc6373d | ||
|
|
b3c1471317 | ||
|
|
9056aee823 | ||
|
|
29c431b2f2 | ||
|
|
d06b2c2022 | ||
|
|
339c9d578a | ||
|
|
7c315fa8a8 | ||
|
|
0f04ed018a | ||
|
|
ca56f726d6 | ||
|
|
e8a46c4e1d | ||
|
|
9cd14a461b | ||
|
|
1ef603ea2a | ||
|
|
14d259f361 | ||
|
|
9223d3133a | ||
|
|
9b321a8515 | ||
|
|
7e9f734d73 | ||
|
|
9d86405d3d | ||
|
|
1ccb4ff580 | ||
|
|
8fd91aea04 | ||
|
|
8f76d790b8 | ||
|
|
853f6df7b5 | ||
|
|
758a1240c9 | ||
|
|
7bdfed3bec | ||
|
|
bf9c2f4abd | ||
|
|
fc0116b323 | ||
|
|
962552c5c8 | ||
|
|
606e5dde31 | ||
|
|
6a0d4c57b1 | ||
|
|
f4b6d11abc | ||
|
|
5a4c898912 | ||
|
|
f2addc0e44 | ||
|
|
70d16a7b92 | ||
|
|
326d7ea310 | ||
|
|
eb011068c0 | ||
|
|
87be0ce34b | ||
|
|
7d9a0bda3a | ||
|
|
7ece5c8275 | ||
|
|
6bdffedcbe | ||
|
|
d2fb7dc2af | ||
|
|
c0d0251e2c | ||
|
|
62a72c4845 | ||
|
|
73584ba7b7 | ||
|
|
ead876fce9 | ||
|
|
6c4a006496 | ||
|
|
281af41b6c | ||
|
|
215e1fae61 | ||
|
|
cba75b9927 | ||
|
|
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 |
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: syoyo
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Issue report
|
||||
about: Create a report
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the issue**
|
||||
|
||||
A clear and concise description of what the issue is.
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
- OS
|
||||
- Compiler, compiler version, compile options
|
||||
- Please attach minimal and reproducible .glTF file if you got an issue related to .glTF data
|
||||
|
||||
**Expected behaviour**
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,169 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
# gcc4.8 is too old and ubuntu-18.04 image is not supported in GitHub Actions anymore,
|
||||
# so disable this build.
|
||||
## compile with older gcc4.8
|
||||
#build-gcc48:
|
||||
|
||||
# runs-on: ubuntu-18.04
|
||||
# name: Build with gcc 4.8
|
||||
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v1
|
||||
|
||||
# - name: Build
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y build-essential
|
||||
# sudo apt-get install -y gcc-4.8 g++-4.8
|
||||
# g++-4.8 -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# - name: NoexceptBuild
|
||||
# run: |
|
||||
# g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# - name: RapidjsonBuild
|
||||
# run: |
|
||||
# git clone https://github.com/Tencent/rapidjson
|
||||
# g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# compile with mingw gcc cross
|
||||
build-mingw-cross:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Build with MinGW gcc cross
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
sudo apt-get install -y mingw-w64
|
||||
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
# Windows(x64) + Visual Studio 2022 build
|
||||
# Assume windows-latest have VS2022 installed
|
||||
build-windows-msvc:
|
||||
|
||||
runs-on: windows-latest
|
||||
name: Build for Windows(x64, MSVC)
|
||||
|
||||
# Use system installed cmake
|
||||
# https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Configure
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake --help
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
||||
cd ..
|
||||
- name: Build
|
||||
run: cmake --build build --config Release
|
||||
|
||||
|
||||
build-linux:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Buld with gcc
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
g++ -std=c++11 -o loader_example loader_example.cc
|
||||
- name: test
|
||||
run: |
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
- name: tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -I../ -std=c++11 -g -O0 -o tester tester.cc
|
||||
./tester
|
||||
cd ..
|
||||
|
||||
- name: noexcept_tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
./tester_noexcept
|
||||
cd ..
|
||||
|
||||
|
||||
build-rapidjson-linux:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Buld with gcc + rapidjson
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build
|
||||
run: |
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
g++ -v
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
|
||||
|
||||
- name: loader_example_test
|
||||
run: |
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
- name: tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -I../ -std=c++11 -g -O0 -o tester tester.cc
|
||||
./tester
|
||||
cd ..
|
||||
|
||||
- name: noexcept_tests
|
||||
run: |
|
||||
cd tests
|
||||
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
|
||||
./tester_noexcept
|
||||
cd ..
|
||||
|
||||
# Cross-compile for aarch64 linux target
|
||||
build-cross-aarch64:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on cross aarch64
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
||||
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
aarch64-linux-gnu-g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
# macOS clang
|
||||
build-macos:
|
||||
|
||||
runs-on: macos-latest
|
||||
name: Build on macOS
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Build
|
||||
run: |
|
||||
clang++ -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
./loader_example models/Cube/Cube.gltf
|
||||
|
||||
git clone https://github.com/Tencent/rapidjson
|
||||
clang++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '21 20 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
# 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
|
||||
tests/issue-97.gltf
|
||||
tests/issue-261.gltf
|
||||
|
||||
# unignore
|
||||
!Makefile
|
||||
!examples/build-gltf/Makefile
|
||||
!examples/raytrace/cornellbox_suzanne.obj
|
||||
!tests/Makefile
|
||||
!tools/windows/premake5.exe
|
||||
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
|
||||
+25
-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,21 @@ 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"
|
||||
- addons: &3
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
compiler: gcc
|
||||
env: COMPILER_VERSION=4.8 BUILD_TYPE=Debug
|
||||
- addons: *3
|
||||
compiler: gcc
|
||||
env: COMPILER_VERSION=4.8 BUILD_TYPE=Release
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi
|
||||
- ./.travis-before-install.sh
|
||||
|
||||
|
||||
script:
|
||||
@@ -42,3 +53,11 @@ script:
|
||||
- ${CC} -v
|
||||
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
|
||||
- ./loader_example ./models/Cube/Cube.gltf
|
||||
- cd tests
|
||||
- clang++ -v
|
||||
- make
|
||||
- ./tester
|
||||
- ./tester_noexcept
|
||||
- cd ../examples/raytrace
|
||||
- ../../premake5 gmake
|
||||
- make
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
PROJECT (tinygltf)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
|
||||
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
||||
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
|
||||
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
|
||||
option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF)
|
||||
option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON)
|
||||
|
||||
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||
ADD_EXECUTABLE ( loader_example
|
||||
loader_example.cc
|
||||
)
|
||||
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||
|
||||
if (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
||||
ADD_SUBDIRECTORY ( examples/glview )
|
||||
endif (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||
|
||||
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||
ADD_SUBDIRECTORY ( examples/validator )
|
||||
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||
|
||||
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
||||
ADD_SUBDIRECTORY ( examples/build-gltf )
|
||||
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
||||
|
||||
#
|
||||
# for add_subdirectory and standalone build
|
||||
#
|
||||
if (TINYGLTF_HEADER_ONLY)
|
||||
add_library(tinygltf INTERFACE)
|
||||
|
||||
target_include_directories(tinygltf
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
else (TINYGLTF_HEADER_ONLY)
|
||||
add_library(tinygltf)
|
||||
target_sources(tinygltf PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tiny_gltf.cc)
|
||||
target_include_directories(tinygltf
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
endif (TINYGLTF_HEADER_ONLY)
|
||||
|
||||
if (TINYGLTF_INSTALL)
|
||||
install(TARGETS tinygltf EXPORT tinygltfTargets)
|
||||
install(EXPORT tinygltfTargets NAMESPACE tinygltf:: FILE TinyGLTFTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/TinyGLTFConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
# Do not install .lib even if !TINYGLTF_HEADER_ONLY
|
||||
|
||||
INSTALL ( FILES
|
||||
json.hpp
|
||||
stb_image.h
|
||||
stb_image_write.h
|
||||
tiny_gltf.h
|
||||
${TINYGLTF_EXTRA_SOUECES}
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
endif(TINYGLTF_INSTALL)
|
||||
@@ -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,13 @@
|
||||
|
||||
# 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
|
||||
|
||||
# With draco
|
||||
# EXTRA_CXXFLAGS := -I../draco/src/ -I../draco/build -DTINYGLTF_ENABLE_DRACO -L../draco/build
|
||||
# EXTRA_LINKFLAGS := -L../draco/build/ -ldracodec -ldraco
|
||||
|
||||
all:
|
||||
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc
|
||||
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc $(EXTRA_LINKFLAGS)
|
||||
|
||||
lint:
|
||||
./cpplint.py tiny_gltf_loader.h
|
||||
deps/cpplint.py tiny_gltf.h
|
||||
|
||||
@@ -2,9 +2,27 @@
|
||||
|
||||
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
|
||||
|
||||
`TinyGLTF` uses Niels Lohmann's json library (https://github.com/nlohmann/json), so now it requires C++11 compiler.
|
||||
(Also, you can use RadpidJSON as an JSON backend)
|
||||
If you are looking for old, C++03 version, please use `devel-picojson` branch (but not maintained anymore).
|
||||
|
||||
## Status
|
||||
|
||||
Work in process(`devel` branch). Very near to release, but need more tests and examples.
|
||||
Currently TinyGLTF is stable and maintenance mode. No drastic changes and feature additions planned.
|
||||
|
||||
- v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397
|
||||
- v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393
|
||||
- v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
|
||||
- v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
||||
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
|
||||
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
|
||||
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
|
||||
- v2.1.0 release(Draco decoding support)
|
||||
- v2.0.0 release(22 Aug, 2018)!
|
||||
|
||||
### Branches
|
||||
|
||||
* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson), but not well maintained.
|
||||
|
||||
## Builds
|
||||
|
||||
@@ -12,44 +30,103 @@ Work in process(`devel` branch). Very near to release, but need more tests and e
|
||||
|
||||
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
Probably mostly feature-complete. Last missing feature is Draco encoding: https://github.com/syoyo/tinygltf/issues/207
|
||||
|
||||
* Written in portable C++. C++-11 with STL dependency only.
|
||||
* [x] macOS + clang(LLVM)
|
||||
* [x] iOS + clang
|
||||
* [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.
|
||||
* glTF specification v2.0.0
|
||||
* [x] ASCII glTF
|
||||
* [x] Load
|
||||
* [x] Save
|
||||
* [x] Binary glTF(GLB)
|
||||
* [x] PBR material description
|
||||
* [x] Load
|
||||
* [x] Save(.bin embedded .glb)
|
||||
* 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] Load PNG(8bit and 16bit)
|
||||
* [x] Load JPEG(8bit only)
|
||||
* [x] Load BMP
|
||||
* [x] Load GIF
|
||||
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
|
||||
* Morph traget
|
||||
* [x] Sparse accessor
|
||||
* Load glTF from memory
|
||||
* Custom callback handler
|
||||
* [x] Image load
|
||||
* [x] Image save
|
||||
* Extensions
|
||||
* [x] Draco mesh decoding
|
||||
* [ ] Draco mesh encoding
|
||||
|
||||
## Note on extension property
|
||||
|
||||
In extension(`ExtensionMap`), JSON number value is parsed as int or float(number) and stored as `tinygltf::Value` object. If you want a floating point value from `tinygltf::Value`, use `GetNumberAsDouble()` method.
|
||||
|
||||
`IsNumber()` returns true if the underlying value is an int value or a floating point value.
|
||||
|
||||
## Examples
|
||||
|
||||
* [glview](examples/glview) : Simple glTF geometry viewer.
|
||||
* [validator](examples/validator) : Simple glTF validator with JSON schema.
|
||||
* [basic](examples/basic) : Basic glTF viewer with texturing support.
|
||||
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
|
||||
|
||||
### WASI/WASM build
|
||||
|
||||
Users who want to run TinyGLTF securely and safely(e.g. need to handle malcious glTF file to serve online glTF conver),
|
||||
I recommend to build TinyGLTF for WASM target.
|
||||
WASI build example is located in [wasm](wasm) .
|
||||
|
||||
## Projects using TinyGLTF
|
||||
|
||||
* 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.
|
||||
* [Diligent Engine](https://github.com/DiligentGraphics/DiligentEngine) - A modern cross-platform low-level graphics library and rendering framework
|
||||
* Lighthouse 2: a rendering framework for real-time ray tracing / path tracing experiments. https://github.com/jbikker/lighthouse2
|
||||
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
|
||||
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
|
||||
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
|
||||
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
|
||||
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and professional development of its developer
|
||||
* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing
|
||||
* [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design.
|
||||
* Your projects here! (Please send PR)
|
||||
|
||||
## TODOs
|
||||
|
||||
* [ ] Write C++ code generator from json schema for robust parsing.
|
||||
* [x] Serialization
|
||||
* [ ] Compression/decompression(Open3DGC, etc)
|
||||
* [ ] Support `extensions` and `extras` property
|
||||
* [ ] Robust URI decoding/encoding. https://github.com/syoyo/tinygltf/issues/369
|
||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||
* [x] Load Draco compressed mesh
|
||||
* [ ] Save Draco compressed mesh
|
||||
* [ ] Open3DGC?
|
||||
* [x] Support `extensions` and `extras` property
|
||||
* [ ] HDR image?
|
||||
* [ ] Write tests for `animation` and `skin`
|
||||
* [ ] OpenEXR extension through TinyEXR.
|
||||
* [ ] 16bit PNG support in Serialization
|
||||
* [ ] Write example and tests for `animation` and `skin`
|
||||
|
||||
### Optional
|
||||
|
||||
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing?
|
||||
|
||||
## Licenses
|
||||
|
||||
@@ -59,29 +136,38 @@ 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;
|
||||
|
||||
Model model;
|
||||
Model model;
|
||||
TinyGLTF loader;
|
||||
std::string err;
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, argv[1]); // for binary glTF(.glb)
|
||||
std::string warn;
|
||||
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
|
||||
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
|
||||
|
||||
if (!warn.empty()) {
|
||||
printf("Warn: %s\n", warn.c_str());
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
printf("Err: %s\n", err.c_str());
|
||||
}
|
||||
@@ -92,19 +178,90 @@ if (!ret) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Loader options
|
||||
|
||||
* `TinyGLTF::SetPreserveimageChannels(bool onoff)`. `true` to preserve image channels as stored in image file for loaded image. `false` by default for backward compatibility(image channels are widen to `RGBA` 4 channels). Effective only when using builtin image loader(STB image loader).
|
||||
|
||||
## Compile options
|
||||
|
||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
||||
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
|
||||
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option would be helpful if you do not want to load image files during glTF parsing.
|
||||
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
|
||||
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
|
||||
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_NO_INCLUDE_RAPIDJSON `: Disable including RapidJson's header files from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this feature.
|
||||
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
|
||||
|
||||
## CMake options
|
||||
|
||||
You can add tinygltf using `add_subdirectory` feature.
|
||||
If you add tinygltf to your project using `add_subdirectory`, it would be better to set `TINYGLTF_HEADER_ONLY` on(just add an include path to tinygltf) and `TINYGLTF_INSTALL` off(Which does not install tinygltf files).
|
||||
|
||||
```
|
||||
// Your project's CMakeLists.txt
|
||||
...
|
||||
|
||||
set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE)
|
||||
set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(/path/to/tinygltf)
|
||||
```
|
||||
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
|
||||
T.B.W.
|
||||
* Buffers.
|
||||
* [x] To file
|
||||
* [x] Embedded
|
||||
* [ ] Draco compressed?
|
||||
* [x] Images
|
||||
* [x] To file
|
||||
* [x] Embedded
|
||||
* Binary(.glb)
|
||||
* [x] .bin embedded single .glb
|
||||
* [ ] External .bin
|
||||
|
||||
## Running tests.
|
||||
|
||||
### Setup
|
||||
### glTF parsing test
|
||||
|
||||
Python 2.6 or 2.7 required.
|
||||
#### Setup
|
||||
|
||||
Python 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
|
||||
```
|
||||
|
||||
### Fuzzing tests
|
||||
|
||||
See `tests/fuzzer` for details.
|
||||
|
||||
After running fuzzer on Ryzen9 3950X a week, at least `LoadASCIIFromString` looks safe except for out-of-memory error in Fuzzer.
|
||||
We may be better to introduce bounded memory size checking when parsing glTF data.
|
||||
|
||||
## Third party licenses
|
||||
|
||||
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
|
||||
* stb_image : Public domain.
|
||||
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
||||
* RapidJSON : Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. http://rapidjson.org/
|
||||
* dlib(uridecode, uriencode) : Copyright (C) 2003 Davis E. King Boost Software License 1.0. http://dlib.net/dlib/server/server_http.cpp.html
|
||||
|
||||
@@ -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,3 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/TinyGLTFTargets.cmake)
|
||||
@@ -0,0 +1,3 @@
|
||||
cd examples\raytrace
|
||||
..\..\tools\windows\premake5.exe vs2015
|
||||
msbuild NanoSGSolution.sln /property:Configuration=Release
|
||||
@@ -0,0 +1,8 @@
|
||||
.vs
|
||||
Debug
|
||||
Release
|
||||
x64
|
||||
packages
|
||||
|
||||
!*.sln
|
||||
!*.vcxproj*
|
||||
@@ -0,0 +1,25 @@
|
||||
# Basic glTF viewer
|
||||
|
||||
## Requirements
|
||||
|
||||
* glew
|
||||
* glfw3
|
||||
* premake5(linux)
|
||||
* OpenGL 3.3+ GPU
|
||||
|
||||
## Build on Linux and macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
```
|
||||
|
||||
## Build on Visual Studio
|
||||
|
||||
Plese use solution file located at `basic` folder.
|
||||
|
||||
|
||||
## Limitation
|
||||
|
||||
There are so many limitations in this example(e.g. no PBR shader. the shader only shows texture of textures[0] if available).
|
||||
|
||||
@@ -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</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</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,394 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
void 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).
|
||||
*/
|
||||
}
|
||||
|
||||
const 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;
|
||||
}
|
||||
|
||||
if (model.textures.size() > 0) {
|
||||
// fixme: Use material's baseColor
|
||||
tinygltf::Texture &tex = model.textures[0];
|
||||
|
||||
if (tex.source > -1) {
|
||||
|
||||
GLuint texid;
|
||||
glGenTextures(1, &texid);
|
||||
|
||||
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);
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
|
||||
if (image.component == 1) {
|
||||
format = GL_RED;
|
||||
} else if (image.component == 2) {
|
||||
format = GL_RG;
|
||||
} else if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
GLenum type = GL_UNSIGNED_BYTE;
|
||||
if (image.bits == 8) {
|
||||
// ok
|
||||
} else if (image.bits == 16) {
|
||||
type = GL_UNSIGNED_SHORT;
|
||||
} else {
|
||||
// ???
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||
format, type, &image.image.at(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bind models
|
||||
void bindModelNodes(std::map<int, GLuint>& vbos, tinygltf::Model &model,
|
||||
tinygltf::Node &node) {
|
||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size()));
|
||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<GLuint, std::map<int, 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) {
|
||||
assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
|
||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
// cleanup vbos but do not delete index buffers yet
|
||||
for (auto it = vbos.cbegin(); it != vbos.cend();) {
|
||||
tinygltf::BufferView bufferView = model.bufferViews[it->first];
|
||||
if (bufferView.target != GL_ELEMENT_ARRAY_BUFFER) {
|
||||
glDeleteBuffers(1, &vbos[it->first]);
|
||||
vbos.erase(it++);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return {vao, vbos};
|
||||
}
|
||||
|
||||
void drawMesh(const std::map<int, GLuint>& vbos,
|
||||
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];
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.at(indexAccessor.bufferView));
|
||||
|
||||
glDrawElements(primitive.mode, indexAccessor.count,
|
||||
indexAccessor.componentType,
|
||||
BUFFER_OFFSET(indexAccessor.byteOffset));
|
||||
}
|
||||
}
|
||||
|
||||
// recursively draw node and children nodes of model
|
||||
void drawModelNodes(const std::pair<GLuint, std::map<int, GLuint>>& vaoAndEbos,
|
||||
tinygltf::Model &model, tinygltf::Node &node) {
|
||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||
drawMesh(vaoAndEbos.second, model, model.meshes[node.mesh]);
|
||||
}
|
||||
for (size_t i = 0; i < node.children.size(); i++) {
|
||||
drawModelNodes(vaoAndEbos, model, model.nodes[node.children[i]]);
|
||||
}
|
||||
}
|
||||
void drawModel(const std::pair<GLuint, std::map<int, GLuint>>& vaoAndEbos,
|
||||
tinygltf::Model &model) {
|
||||
glBindVertexArray(vaoAndEbos.first);
|
||||
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||
drawModelNodes(vaoAndEbos, 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;
|
||||
|
||||
std::pair<GLuint, std::map<int, GLuint>> vaoAndEbos = 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, 20), 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(vaoAndEbos, model);
|
||||
glfwSwapBuffers(window.window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glDeleteVertexArrays(1, &vaoAndEbos.first);
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char *description) {
|
||||
(void)error;
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string filename = "../../../models/Cube/Cube.gltf";
|
||||
|
||||
if (argc > 1) {
|
||||
filename = argv[1];
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit()) return -1;
|
||||
|
||||
// Force create OpenGL 3.3
|
||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||
// Note (PE): On laptops with intel hd graphics card you can overcome the segfault by enabling experimental, see below (tested on lenovo thinkpad)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glewExperimental = GL_TRUE;
|
||||
|
||||
#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();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
$(CXX) -o create_triangle_gltf -I../../ create_triangle_gltf.cpp
|
||||
@@ -0,0 +1,121 @@
|
||||
// An example of how to generate a gltf file from scratch. This example
|
||||
// was translated from the pygltlib documentation in the pypi project page,
|
||||
// which in turn is based on the Khronos Sample Models at:
|
||||
//
|
||||
// https://github.com/KhronosGroup/glTF-Sample-Models
|
||||
//
|
||||
// This example is released under the MIT license.
|
||||
//
|
||||
// 2021-02-25 Thu
|
||||
// Dov Grobgeld <dov.grobgeld@gmail.com>
|
||||
|
||||
|
||||
// Define these only in *one* .cc file.
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Create a model with a single mesh and save it as a gltf file
|
||||
tinygltf::Model m;
|
||||
tinygltf::Scene scene;
|
||||
tinygltf::Mesh mesh;
|
||||
tinygltf::Primitive primitive;
|
||||
tinygltf::Node node;
|
||||
tinygltf::Buffer buffer;
|
||||
tinygltf::BufferView bufferView1;
|
||||
tinygltf::BufferView bufferView2;
|
||||
tinygltf::Accessor accessor1;
|
||||
tinygltf::Accessor accessor2;
|
||||
tinygltf::Asset asset;
|
||||
|
||||
// This is the raw data buffer.
|
||||
buffer.data = {
|
||||
// 6 bytes of indices and two bytes of padding
|
||||
0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,
|
||||
// 36 bytes of floating point numbers
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
|
||||
0x00,0x00,0x00,0x00};
|
||||
|
||||
// "The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
|
||||
// start of the buffer.
|
||||
bufferView1.buffer = 0;
|
||||
bufferView1.byteOffset=0;
|
||||
bufferView1.byteLength=6;
|
||||
bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
|
||||
|
||||
// The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
|
||||
// at position 8 in the buffer and are of type ARRAY_BUFFER
|
||||
bufferView2.buffer = 0;
|
||||
bufferView2.byteOffset=8;
|
||||
bufferView2.byteLength=36;
|
||||
bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||
|
||||
// Describe the layout of bufferView1, the indices of the vertices
|
||||
accessor1.bufferView = 0;
|
||||
accessor1.byteOffset = 0;
|
||||
accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
|
||||
accessor1.count = 3;
|
||||
accessor1.type = TINYGLTF_TYPE_SCALAR;
|
||||
accessor1.maxValues.push_back(2);
|
||||
accessor1.minValues.push_back(0);
|
||||
|
||||
// Describe the layout of bufferView2, the vertices themself
|
||||
accessor2.bufferView = 1;
|
||||
accessor2.byteOffset = 0;
|
||||
accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
|
||||
accessor2.count = 3;
|
||||
accessor2.type = TINYGLTF_TYPE_VEC3;
|
||||
accessor2.maxValues = {1.0, 1.0, 0.0};
|
||||
accessor2.minValues = {0.0, 0.0, 0.0};
|
||||
|
||||
// Build the mesh primitive and add it to the mesh
|
||||
primitive.indices = 0; // The index of the accessor for the vertex indices
|
||||
primitive.attributes["POSITION"] = 1; // The index of the accessor for positions
|
||||
primitive.material = 0;
|
||||
primitive.mode = TINYGLTF_MODE_TRIANGLES;
|
||||
mesh.primitives.push_back(primitive);
|
||||
|
||||
// Other tie ups
|
||||
node.mesh = 0;
|
||||
scene.nodes.push_back(0); // Default scene
|
||||
|
||||
// Define the asset. The version is required
|
||||
asset.version = "2.0";
|
||||
asset.generator = "tinygltf";
|
||||
|
||||
// Now all that remains is to tie back all the loose objects into the
|
||||
// our single model.
|
||||
m.scenes.push_back(scene);
|
||||
m.meshes.push_back(mesh);
|
||||
m.nodes.push_back(node);
|
||||
m.buffers.push_back(buffer);
|
||||
m.bufferViews.push_back(bufferView1);
|
||||
m.bufferViews.push_back(bufferView2);
|
||||
m.accessors.push_back(accessor1);
|
||||
m.accessors.push_back(accessor2);
|
||||
m.asset = asset;
|
||||
|
||||
// Create a simple material
|
||||
tinygltf::Material mat;
|
||||
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
|
||||
mat.doubleSided = true;
|
||||
m.materials.push_back(mat);
|
||||
|
||||
// Save it to a file
|
||||
tinygltf::TinyGLTF gltf;
|
||||
gltf.WriteGltfSceneToFile(&m, "triangle.gltf",
|
||||
true, // embedImages
|
||||
true, // embedBuffers
|
||||
true, // pretty print
|
||||
false); // write binary
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
+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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1502
-602
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(dxview)
|
||||
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
|
||||
add_executable(dxview
|
||||
src/Viewer.h
|
||||
src/Viewer.cc
|
||||
src/dxview.cc
|
||||
)
|
||||
|
||||
target_include_directories(dxview
|
||||
PRIVATE
|
||||
../../
|
||||
)
|
||||
|
||||
target_compile_definitions(dxview
|
||||
PRIVATE
|
||||
DXVIEW_SWAP_CHAIN_BUFFER_COUNT=3
|
||||
DXVIEW_RES_DIR=L"${PROJECT_SOURCE_DIR}/res"
|
||||
)
|
||||
|
||||
target_link_libraries(dxview
|
||||
PRIVATE
|
||||
dxgi
|
||||
d3dcompiler
|
||||
d3d12
|
||||
glfw
|
||||
spdlog::spdlog
|
||||
)
|
||||
|
||||
set_target_properties(dxview
|
||||
PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
# DirectX glTF Viewer
|
||||
|
||||
## Overview
|
||||
|
||||
This project was motivated by a lack of sample code demonstrating the graphics API agnostic nature of the glTF specification. The sample code is written using modern C++ and DirectX 12 for the client application.
|
||||
|
||||
## Features
|
||||
|
||||
* [x] DirectX 12
|
||||
* [ ] Loader
|
||||
* [ ] Animation
|
||||
* [ ] Morph Target
|
||||
* [ ] Physical Base Rendering
|
||||
* [ ] Environment Map
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [CMake](https://github.com/Kitware/CMake)
|
||||
* [Vcpkg](https://github.com/Microsoft/vcpkg)
|
||||
* [GLFW](https://github.com/glfw/glfw)
|
||||
* [spdlog](https://github.com/gabime/spdlog)
|
||||
|
||||
## Building
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```
|
||||
vcpkg install glfw3:x64-windows
|
||||
vcpkg install spdlog:x64-windows
|
||||
```
|
||||
|
||||
### Generate Project Files
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cmake . -B build -DCMAKE_TOOLCHAIN_FILE=${VCPKG_DIR}/script/buildsystem/vcpkg.cmake
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
float4 main() : SV_Target {
|
||||
return float4(0.5, 0.5, 0.5, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
struct RS2PS {
|
||||
float4 position : SV_POSITION;
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
float2 texcoord_0: TEXCOORD_0;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct TextureInfo {
|
||||
uint textureIndex;
|
||||
uint samplerIndex;
|
||||
};
|
||||
|
||||
struct PBRMetallicRoughness {
|
||||
float4 baseColorFactor;
|
||||
TextureInfo baseColorTexture;
|
||||
float metallicFactor;
|
||||
float roughnessFactor;
|
||||
TextureInfo metallicRoughnessTexture;
|
||||
};
|
||||
|
||||
cbuffer Material : register(b2) {
|
||||
PBRMetallicRoughness pbrMetallicRoughness;
|
||||
};
|
||||
|
||||
Texture2D textures[5] : register(t0);
|
||||
SamplerState samplerState[5] : register(s0);
|
||||
|
||||
float4 getBaseColor(float2 uv) {
|
||||
float4 baseColor = pbrMetallicRoughness.baseColorFactor;
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
TextureInfo baseColorTexture = pbrMetallicRoughness.baseColorTexture;
|
||||
if (baseColorTexture.textureIndex >= 0) {
|
||||
baseColor *= textures[baseColorTexture.textureIndex].Sample(samplerState[baseColorTexture.samplerIndex], uv);
|
||||
}
|
||||
#endif
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
float4 main(RS2PS input) : SV_Target {
|
||||
float2 uv = float2(0.0, 0.0);
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
uv = input.texcoord_0;
|
||||
#endif
|
||||
|
||||
float4 color = getBaseColor(uv);
|
||||
|
||||
return color;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
struct IA2VS {
|
||||
float3 position : POSITION;
|
||||
|
||||
#ifdef HAS_NORMAL
|
||||
float3 normal : NORMAL;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_TANGENT
|
||||
float4 tangent : TANGENT;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
float2 texcoord_0: TEXCOORD_0;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct VS2RS {
|
||||
float4 position : SV_POSITION;
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
float2 texcoord_0: TEXCOORD_0;
|
||||
#endif
|
||||
};
|
||||
|
||||
cbuffer Camera : register(b0) {
|
||||
float4x4 V;
|
||||
float4x4 P;
|
||||
float4x4 VP;
|
||||
};
|
||||
|
||||
cbuffer Node : register(b1) {
|
||||
float4x4 M;
|
||||
};
|
||||
|
||||
VS2RS main(IA2VS input) {
|
||||
VS2RS output;
|
||||
output.position = mul(float4(input.position, 1.0), M);
|
||||
output.position = mul(output.position, V);
|
||||
output.position = mul(output.position, P);
|
||||
|
||||
#ifdef HAS_TEXCOORD_0
|
||||
output.texcoord_0 = input.texcoord_0;
|
||||
#endif
|
||||
|
||||
return output;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
#ifndef DXVIEW_VIEWER_GUARD
|
||||
#define DXVIEW_VIEWER_GUARD
|
||||
|
||||
#include <DirectXMath.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <tiny_gltf.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
enum RenderPassType { RENDER_PASS_TYPE_PRESENT = 0, RENDER_PASS_TYPE_COUNT };
|
||||
|
||||
struct RenderTarget {
|
||||
ComPtr<ID3D12Resource> pTexture;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE viewDescriptor;
|
||||
};
|
||||
|
||||
struct TextureInfo {
|
||||
int32_t textureIndex;
|
||||
int32_t samplerIndex;
|
||||
};
|
||||
|
||||
struct PBRMetallicRoughness {
|
||||
DirectX::XMFLOAT4 baseColorFactor;
|
||||
TextureInfo baseColorTexture;
|
||||
float metallicFactor;
|
||||
float roughnessFactor;
|
||||
TextureInfo metallicRoughnessTexture;
|
||||
};
|
||||
|
||||
struct Material {
|
||||
std::string name;
|
||||
D3D12_BLEND_DESC blendDesc;
|
||||
D3D12_RASTERIZER_DESC rasterizerDesc;
|
||||
ComPtr<ID3D12Resource> pBuffer;
|
||||
void* pBufferData;
|
||||
ComPtr<ID3D12DescriptorHeap> pSRVDescriptorHeap;
|
||||
ComPtr<ID3D12DescriptorHeap> pSamplerDescriptorHeap;
|
||||
};
|
||||
|
||||
struct Attribute {
|
||||
std::string name;
|
||||
DXGI_FORMAT format;
|
||||
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
|
||||
};
|
||||
|
||||
struct Primitive {
|
||||
std::vector<Attribute> attributes;
|
||||
uint32_t vertexCount;
|
||||
D3D12_PRIMITIVE_TOPOLOGY primitiveTopology;
|
||||
D3D12_INDEX_BUFFER_VIEW indexBufferView;
|
||||
uint32_t indexCount;
|
||||
Material* pMaterial;
|
||||
ComPtr<ID3D12RootSignature> pRootSignature;
|
||||
ComPtr<ID3D12PipelineState> pPipelineState;
|
||||
};
|
||||
|
||||
struct Mesh {
|
||||
std::string name;
|
||||
std::vector<Primitive> primitives;
|
||||
};
|
||||
|
||||
struct Node {
|
||||
DirectX::XMFLOAT4X4 M;
|
||||
};
|
||||
|
||||
struct Camera {
|
||||
DirectX::XMFLOAT4X4 V;
|
||||
DirectX::XMFLOAT4X4 P;
|
||||
DirectX::XMFLOAT4X4 VP;
|
||||
};
|
||||
|
||||
class Viewer {
|
||||
public:
|
||||
Viewer(HWND window, tinygltf::Model* pModel);
|
||||
|
||||
void update(double deltaTime);
|
||||
void render(double deltaTime);
|
||||
|
||||
private:
|
||||
void initDirectX(HWND window);
|
||||
void buildRenderTargets();
|
||||
void buildResources();
|
||||
void buildBuffers(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
|
||||
void buildImages(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
|
||||
void buildSamplerDescs();
|
||||
void buildMaterials();
|
||||
void buildMeshes();
|
||||
void buildNodes();
|
||||
|
||||
void drawNode(uint64_t nodeIndex);
|
||||
|
||||
private:
|
||||
tinygltf::Model* pModel_;
|
||||
ComPtr<IDXGIFactory1> pFactory_;
|
||||
ComPtr<IDXGIAdapter1> pAdapter_;
|
||||
ComPtr<ID3D12Device> pDevice_;
|
||||
ComPtr<ID3D12CommandQueue> pDirectCommandQueue_;
|
||||
UINT64 directFenceValue_;
|
||||
ComPtr<ID3D12Fence> pDirectFence_;
|
||||
ComPtr<ID3D12CommandQueue> pCopyCommandQueue_;
|
||||
UINT64 copyFenceValue_;
|
||||
ComPtr<ID3D12Fence> pCopyFence_;
|
||||
ComPtr<IDXGISwapChain3> pSwapChain_;
|
||||
ComPtr<ID3D12Resource> pSwapChainBuffers_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
||||
ComPtr<ID3D12CommandAllocator>
|
||||
pDirectCommandAllocators_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
||||
ComPtr<ID3D12GraphicsCommandList> pDirectCommandList_;
|
||||
ComPtr<ID3D12CommandAllocator> pCopyCommandAllocator_;
|
||||
ComPtr<ID3D12GraphicsCommandList> pCopyCommandList_;
|
||||
UINT descriptorIncrementSize_[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
|
||||
ComPtr<ID3D12DescriptorHeap>
|
||||
pRTVDescriptorHeaps_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
||||
std::vector<RenderTarget> renderTargets_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
|
||||
std::vector<ComPtr<ID3D12Resource> > pBuffers_;
|
||||
std::vector<ComPtr<ID3D12Resource> > pTextures_;
|
||||
std::vector<D3D12_SAMPLER_DESC> samplerDescs_;
|
||||
std::vector<Material> materials_;
|
||||
std::vector<Mesh> meshes_;
|
||||
std::vector<ComPtr<ID3D12Resource> > pNodeBuffers_;
|
||||
ComPtr<ID3D12Resource> pCameraBuffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STBI_MSC_SECURE_CRT
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
#undef GLFW_EXPOSE_NATIVE_WIN32
|
||||
#undef TINYGLTF_IMPLEMENTATION
|
||||
#undef STBI_MSC_SECURE_CRT
|
||||
#undef STB_IMAGE_IMPLEMENTATION
|
||||
#undef STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "Viewer.h"
|
||||
|
||||
static void onError(int error, const char* message) {
|
||||
spdlog::error("[{}] {}", error, message);
|
||||
}
|
||||
|
||||
static void onRender(Viewer* pViewer, double deltaTime) {
|
||||
pViewer->update(deltaTime);
|
||||
pViewer->render(deltaTime);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
tinygltf::TinyGLTF context;
|
||||
|
||||
tinygltf::Model model;
|
||||
std::string error;
|
||||
std::string warning;
|
||||
if (!context.LoadASCIIFromFile(&model, &error, &warning, argv[1])) {
|
||||
if (!error.empty()) {
|
||||
spdlog::error("{}", error);
|
||||
}
|
||||
|
||||
if (!warning.empty()) {
|
||||
spdlog::warn("{}", warning);
|
||||
}
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GLFWwindow* pWindow;
|
||||
|
||||
glfwSetErrorCallback(onError);
|
||||
|
||||
if (!glfwInit()) {
|
||||
spdlog::error("Fail to initialize GLFW!!!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
|
||||
pWindow = glfwCreateWindow(512, 512, "dxview", nullptr, nullptr);
|
||||
if (!pWindow) {
|
||||
spdlog::error("Fail to create GLFWwindow!!!");
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto pViewer = std::make_unique<Viewer>(glfwGetWin32Window(pWindow), &model);
|
||||
if (!pViewer) {
|
||||
spdlog::error("Fail to create Viewer");
|
||||
glfwDestroyWindow(pWindow);
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto prevTimeStamp = glfwGetTime();
|
||||
while (!glfwWindowShouldClose(pWindow)) {
|
||||
auto currTimeStamp = glfwGetTime();
|
||||
|
||||
onRender(pViewer.get(), currTimeStamp - prevTimeStamp);
|
||||
prevTimeStamp = currTimeStamp;
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glfwDestroyWindow(pWindow);
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(gltfutil)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include_directories(../../)
|
||||
include_directories(../common/)
|
||||
|
||||
file(GLOB gltfutil_sources *.cc *.h)
|
||||
add_executable(gltfutil ${gltfutil_sources} ../common/lodepng.cpp)
|
||||
|
||||
install ( TARGETS
|
||||
gltfutil
|
||||
DESTINATION
|
||||
bin
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
#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 use_exr = false;
|
||||
|
||||
bool has_output_dir;
|
||||
bool is_valid() {
|
||||
// TODO impl check
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gltfutil
|
||||
@@ -0,0 +1,136 @@
|
||||
#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"
|
||||
|
||||
#define TINYEXR_IMPLEMENTATION
|
||||
#include "tinyexr.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\n"
|
||||
<< "\t\t -o: ouptput directory path\n"
|
||||
<< "\t\t -e: Use OpenEXR format for 16bit image\n"
|
||||
<< "\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 'e':
|
||||
config.use_exr = true;
|
||||
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.use_exr) {
|
||||
dumper.set_use_exr(true);
|
||||
}
|
||||
|
||||
if (config.requested_format !=
|
||||
texture_dumper::texture_output_format::not_specified)
|
||||
dumper.set_output_format(config.requested_format);
|
||||
|
||||
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,169 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "stb_image_write.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#include "lodepng.h" // ../common
|
||||
|
||||
#include "tinyexr.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
using namespace gltfutil;
|
||||
using namespace tinygltf;
|
||||
using std::cout;
|
||||
|
||||
static LodePNGColorType GetLodePNGColorType(int channels) {
|
||||
if (channels == 1) {
|
||||
return LodePNGColorType::LCT_GREY;
|
||||
} else if (channels == 2) {
|
||||
return LodePNGColorType::LCT_GREY_ALPHA;
|
||||
} else if (channels == 3) {
|
||||
return LodePNGColorType::LCT_RGB;
|
||||
} else if (channels == 4) {
|
||||
return LodePNGColorType::LCT_RGBA;
|
||||
} else {
|
||||
std::cerr << "??? unsupported channels " << channels << "\n";
|
||||
return LodePNGColorType::LCT_RGB; // FIXME(syoyo): Raise error
|
||||
}
|
||||
}
|
||||
|
||||
static void ToBigEndian(std::vector<uint8_t>* image) {
|
||||
|
||||
assert(image->size() % 2 == 0);
|
||||
|
||||
union {
|
||||
unsigned int i;
|
||||
char c[4];
|
||||
} bint = {0x01020304};
|
||||
|
||||
bool is_big_endian = (bint.c[0] == 1);
|
||||
|
||||
if (is_big_endian) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t *>(image->data());
|
||||
size_t n = image->size() / 2;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
ptr[i] = ((0xFF00 & ptr[i]) >> 8) | ((0x00FF & ptr[i]) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Save16bitImageAsEXR(const std::string& filename,
|
||||
const tinygltf::Image& image) {
|
||||
assert(image.bits == 16);
|
||||
|
||||
std::vector<float> buf(image.width * image.height * image.component);
|
||||
|
||||
// widen to float image.
|
||||
// Store as is(i.e, pixel value range is [0.0, 65535.0])
|
||||
const unsigned short* ptr =
|
||||
reinterpret_cast<const unsigned short*>(image.image.data());
|
||||
for (size_t i = 0; i < image.width * image.height * image.component; i++) {
|
||||
buf[i] = float(ptr[i]);
|
||||
}
|
||||
|
||||
const char* err = nullptr;
|
||||
int ret = SaveEXR(buf.data(), image.width, image.height, image.component,
|
||||
/* save_as_fp16 */ 0, filename.c_str(), &err);
|
||||
|
||||
if (err) {
|
||||
std::cerr << "EXR err: " << err << std::endl;
|
||||
FreeEXRErrorMessage(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ret == TINYEXR_SUCCESS);
|
||||
}
|
||||
|
||||
texture_dumper::texture_dumper(const Model& input)
|
||||
: model(input), configured_format(texture_output_format::png) {
|
||||
cout << "Texture dumper\n";
|
||||
}
|
||||
|
||||
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';
|
||||
cout << "pixel bit depth :" << image.bits << '\n';
|
||||
std::string basename =
|
||||
image.name.empty() ? std::to_string(index) : image.name;
|
||||
|
||||
unsigned char* bytes_to_write =
|
||||
const_cast<unsigned char*>(image.image.data());
|
||||
|
||||
std::string filename;
|
||||
switch (configured_format) {
|
||||
case texture_output_format::png:
|
||||
filename = path + "/" + basename + ".png";
|
||||
|
||||
if (this->use_exr) {
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
filename = path + "/" + basename + ".exr";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
|
||||
if (image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||
if (this->use_exr) {
|
||||
bool ret = Save16bitImageAsEXR(filename, image);
|
||||
assert(ret);
|
||||
} else {
|
||||
// Use lodepng to save 16bit PNG.
|
||||
// NOTE(syoyo): `loadpng::encode` requires image data must be stored in big endian.
|
||||
std::vector<uint8_t> tmp = image.image; // copy
|
||||
ToBigEndian(&tmp);
|
||||
|
||||
unsigned ret = lodepng::encode(
|
||||
filename, tmp.data(), image.width, image.height,
|
||||
GetLodePNGColorType(image.component), /* bits */ 16);
|
||||
assert(ret == 0); // 0 = no err.
|
||||
}
|
||||
} else {
|
||||
// TODO(syoyo): check status
|
||||
stbi_write_png(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write, 0);
|
||||
}
|
||||
break;
|
||||
case texture_output_format::bmp:
|
||||
filename = path + "/" + basename + ".bmp";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_bmp(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
break;
|
||||
case texture_output_format::tga:
|
||||
filename = path + "/" + basename + ".tga";
|
||||
std::cout << "Image will be written to " << filename << '\n';
|
||||
stbi_write_tga(filename.c_str(), image.width, image.height,
|
||||
image.component, bytes_to_write);
|
||||
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,27 @@
|
||||
#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;
|
||||
bool use_exr = false; // Use EXR for 16bit image?
|
||||
|
||||
public:
|
||||
texture_dumper(const tinygltf::Model& inputModel);
|
||||
void dump_to_folder(const std::string& path = "./");
|
||||
void set_output_format(texture_output_format format);
|
||||
void set_use_exr(const bool value) {
|
||||
use_exr = value;
|
||||
}
|
||||
|
||||
static texture_output_format get_fromat_from_string(const std::string& str);
|
||||
};
|
||||
} // namespace gltfutil
|
||||
@@ -0,0 +1,7 @@
|
||||
.vs
|
||||
Debug
|
||||
x64
|
||||
packages
|
||||
|
||||
!*.sln
|
||||
!*.vcxproj*
|
||||
@@ -0,0 +1,69 @@
|
||||
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 (DEFINED DRACO_DIR)
|
||||
if (DRACO_DIR STREQUAL "")
|
||||
else ()
|
||||
# TODO(syoyo): better CMake script for draco
|
||||
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
||||
include_directories(${DRACO_DIR}/include)
|
||||
|
||||
link_directories(${DRACO_DIR}/lib)
|
||||
set(DRACO_LIBRARY draco)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
../../
|
||||
../common
|
||||
# ${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_LIBRARIES}
|
||||
${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 ()
|
||||
+435
-235
@@ -12,11 +12,21 @@
|
||||
#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))
|
||||
|
||||
@@ -44,7 +54,9 @@ float eye[3], lookat[3], up[3];
|
||||
|
||||
GLFWwindow *window;
|
||||
|
||||
typedef struct { GLuint vb; } GLBufferState;
|
||||
typedef struct {
|
||||
GLuint vb;
|
||||
} GLBufferState;
|
||||
|
||||
typedef struct {
|
||||
std::vector<GLuint> diffuseTex; // for each primitive in mesh
|
||||
@@ -243,6 +255,26 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
|
||||
prevMouseY = mouse_y;
|
||||
}
|
||||
|
||||
static size_t ComponentTypeByteSize(int type) {
|
||||
switch (type) {
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
return sizeof(char);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
return sizeof(short);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
return sizeof(int);
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
return sizeof(float);
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
|
||||
return sizeof(double);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
// Buffer
|
||||
{
|
||||
@@ -253,14 +285,117 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
continue; // Unsupported bufferView.
|
||||
}
|
||||
|
||||
int sparse_accessor = -1;
|
||||
for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
|
||||
const auto &accessor = model.accessors[a_i];
|
||||
if (accessor.bufferView == i) {
|
||||
std::cout << i << " is used by accessor " << a_i << std::endl;
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout
|
||||
<< "WARN: this bufferView has at least one sparse accessor to "
|
||||
"it. We are going to load the data as patched by this "
|
||||
"sparse accessor, not the original data"
|
||||
<< std::endl;
|
||||
sparse_accessor = a_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||
GLBufferState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(bufferView.target, state.vb);
|
||||
std::cout << "buffer.size= " << buffer.data.size()
|
||||
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||
|
||||
if (sparse_accessor < 0)
|
||||
glBufferData(bufferView.target, bufferView.byteLength,
|
||||
&buffer.data.at(0) + bufferView.byteOffset,
|
||||
GL_STATIC_DRAW);
|
||||
else {
|
||||
const auto accessor = model.accessors[sparse_accessor];
|
||||
// copy the buffer to a temporary one for sparse patching
|
||||
unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
|
||||
memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
|
||||
bufferView.byteLength);
|
||||
|
||||
const size_t size_of_object_in_buffer =
|
||||
ComponentTypeByteSize(accessor.componentType);
|
||||
const size_t size_of_sparse_indices =
|
||||
ComponentTypeByteSize(accessor.sparse.indices.componentType);
|
||||
|
||||
const auto &indices_buffer_view =
|
||||
model.bufferViews[accessor.sparse.indices.bufferView];
|
||||
const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
|
||||
|
||||
const auto &values_buffer_view =
|
||||
model.bufferViews[accessor.sparse.values.bufferView];
|
||||
const auto &values_buffer = model.buffers[values_buffer_view.buffer];
|
||||
|
||||
for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
|
||||
++sparse_index) {
|
||||
int index = 0;
|
||||
// std::cout << "accessor.sparse.indices.componentType = " <<
|
||||
// accessor.sparse.indices.componentType << std::endl;
|
||||
switch (accessor.sparse.indices.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
index = (int)*(
|
||||
unsigned char *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
index = (int)*(
|
||||
unsigned short *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
index = (int)*(
|
||||
unsigned int *)(indices_buffer.data.data() +
|
||||
indices_buffer_view.byteOffset +
|
||||
accessor.sparse.indices.byteOffset +
|
||||
(sparse_index * size_of_sparse_indices));
|
||||
break;
|
||||
}
|
||||
std::cout << "updating sparse data at index : " << index
|
||||
<< std::endl;
|
||||
// index is now the target of the sparse index to patch in
|
||||
const unsigned char *read_from =
|
||||
values_buffer.data.data() +
|
||||
(values_buffer_view.byteOffset +
|
||||
accessor.sparse.values.byteOffset) +
|
||||
(sparse_index * (size_of_object_in_buffer * accessor.type));
|
||||
|
||||
/*
|
||||
std::cout << ((float*)read_from)[0] << "\n";
|
||||
std::cout << ((float*)read_from)[1] << "\n";
|
||||
std::cout << ((float*)read_from)[2] << "\n";
|
||||
*/
|
||||
|
||||
unsigned char *write_to =
|
||||
tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
|
||||
|
||||
memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
|
||||
}
|
||||
|
||||
// debug:
|
||||
/*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
|
||||
{
|
||||
float* b = (float*)tmp_buffer;
|
||||
std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
|
||||
}*/
|
||||
|
||||
glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
|
||||
GL_STATIC_DRAW);
|
||||
delete[] tmp_buffer;
|
||||
}
|
||||
glBindBuffer(bufferView.target, 0);
|
||||
|
||||
gBufferState[i] = state;
|
||||
@@ -268,55 +403,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
}
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
// Texture
|
||||
{
|
||||
for (size_t i = 0; i < model.meshes.size(); i++) {
|
||||
const tinygltf::Mesh &mesh = model.meshes[i];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (primitive.material < 0) {
|
||||
continue;
|
||||
}
|
||||
tinygltf::Material &mat = model.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (model.textures.find(diffuseTexName) != model.textures.end()) {
|
||||
tinygltf::Texture &tex = model.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != model.images.end()) {
|
||||
tinygltf::Image &image = model.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glUseProgram(progId);
|
||||
@@ -337,164 +472,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
// Setup curves geometry extension
|
||||
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
// Find curves primitive.
|
||||
{
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(
|
||||
scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
|
||||
scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
for (; it != itEnd; it++) {
|
||||
const tinygltf::Mesh &mesh = it->second;
|
||||
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
// Currently we only support one primitive per mesh.
|
||||
if (mesh.primitives.size() > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
|
||||
const tinygltf::Primitive &primitive = mesh.primitives[primId];
|
||||
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
gMeshState[mesh.name].diffuseTex[primId] = 0;
|
||||
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (primitive.material.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
bool has_curves = false;
|
||||
if (primitive.extras.IsObject()) {
|
||||
if (primitive.extras.Has("ext_mode")) {
|
||||
const tinygltf::Value::Object &o =
|
||||
primitive.extras.Get<tinygltf::Value::Object>();
|
||||
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
|
||||
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ext_mode.IsString()) {
|
||||
const std::string &str = ext_mode.Get<std::string>();
|
||||
if (str.compare("curves") == 0) {
|
||||
has_curves = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
if (!has_curves) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
// Construct curves buffer
|
||||
const tinygltf::Accessor &vtx_accessor =
|
||||
scene.accessors[primitive.attributes.find("POSITION")->second];
|
||||
const tinygltf::Accessor &nverts_accessor =
|
||||
scene.accessors[primitive.attributes.find("NVERTS")->second];
|
||||
const tinygltf::BufferView &vtx_bufferView =
|
||||
scene.bufferViews[vtx_accessor.bufferView];
|
||||
const tinygltf::BufferView &nverts_bufferView =
|
||||
scene.bufferViews[nverts_accessor.bufferView];
|
||||
const tinygltf::Buffer &vtx_buffer =
|
||||
scene.buffers[vtx_bufferView.buffer];
|
||||
const tinygltf::Buffer &nverts_buffer =
|
||||
scene.buffers[nverts_bufferView.buffer];
|
||||
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
|
||||
// std::endl;
|
||||
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
|
||||
// std::endl;
|
||||
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
|
||||
// std::endl;
|
||||
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
const int *nverts =
|
||||
reinterpret_cast<const int *>(nverts_buffer.data.data());
|
||||
const float *vtx =
|
||||
reinterpret_cast<const float *>(vtx_buffer.data.data());
|
||||
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
// Convert to GL_LINES data.
|
||||
std::vector<float> line_pts;
|
||||
size_t vtx_offset = 0;
|
||||
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
|
||||
for (int n = 0; n < nverts[k] - 1; n++) {
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
|
||||
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
|
||||
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
|
||||
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
|
||||
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
|
||||
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
|
||||
}
|
||||
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
vtx_offset += nverts[k];
|
||||
}
|
||||
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
GLCurvesState state;
|
||||
glGenBuffers(1, &state.vb);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
|
||||
line_pts.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
state.count = line_pts.size() / 3;
|
||||
gCurvesMesh[mesh.name] = state;
|
||||
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// Material
|
||||
tinygltf::Material &mat = scene.materials[primitive.material];
|
||||
// printf("material.name = %s\n", mat.name.c_str());
|
||||
if (mat.values.find("diffuse") != mat.values.end()) {
|
||||
std::string diffuseTexName = mat.values["diffuse"].string_value;
|
||||
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
|
||||
tinygltf::Texture &tex = scene.textures[diffuseTexName];
|
||||
if (scene.images.find(tex.source) != scene.images.end()) {
|
||||
tinygltf::Image &image = scene.images[tex.source];
|
||||
GLuint texId;
|
||||
glGenTextures(1, &texId);
|
||||
glBindTexture(tex.target, texId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
// Ignore Texture.fomat.
|
||||
GLenum format = GL_RGBA;
|
||||
if (image.component == 3) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
|
||||
image.height, 0, format, tex.type,
|
||||
&image.image.at(0));
|
||||
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
CheckErrors("texImage2D");
|
||||
glBindTexture(tex.target, 0);
|
||||
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("TexId = %d\n", texId);
|
||||
gMeshState[mesh.name].diffuseTex[primId] = texId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
glUseProgram(progId);
|
||||
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
|
||||
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
|
||||
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
|
||||
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
|
||||
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
|
||||
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
gGLProgramState.attribs["POSITION"] = vtloc;
|
||||
gGLProgramState.attribs["NORMAL"] = nrmloc;
|
||||
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
|
||||
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
|
||||
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -546,10 +681,14 @@ 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,
|
||||
BUFFER_OFFSET(accessor.byteOffset));
|
||||
accessor.componentType,
|
||||
accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
||||
CheckErrors("vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
|
||||
CheckErrors("enable vertex attrib array");
|
||||
@@ -603,34 +742,58 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
|
||||
|
||||
#if 0 // TODO(syoyo): Implement
|
||||
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
||||
(void)scene;
|
||||
(void)scene;
|
||||
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void QuatToAngleAxis(const std::vector<double> quaternion,
|
||||
double &outAngleDegrees,
|
||||
double *axis) {
|
||||
double qx = quaternion[0];
|
||||
double qy = quaternion[1];
|
||||
double qz = quaternion[2];
|
||||
double qw = quaternion[3];
|
||||
|
||||
double angleRadians = 2 * acos(qw);
|
||||
if (angleRadians == 0.0) {
|
||||
outAngleDegrees = 0.0;
|
||||
axis[0] = 0.0;
|
||||
axis[1] = 0.0;
|
||||
axis[2] = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
|
||||
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
|
||||
}
|
||||
|
||||
GLCurvesState &state = gCurvesMesh[mesh.name];
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
|
||||
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
|
||||
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
|
||||
CheckErrors("curve: vertex attrib pointer");
|
||||
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
CheckErrors("curve: enable vertex attrib array");
|
||||
}
|
||||
|
||||
glDrawArrays(GL_LINES, 0, state.count);
|
||||
|
||||
if (gGLProgramState.attribs["POSITION"] >= 0) {
|
||||
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
|
||||
}
|
||||
double denom = sqrt(1-qw*qw);
|
||||
outAngleDegrees = angleRadians * 180.0 / M_PI;
|
||||
axis[0] = qx / denom;
|
||||
axis[1] = qy / denom;
|
||||
axis[2] = qz / denom;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Hierarchically draw nodes
|
||||
static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
@@ -642,18 +805,22 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
glMultMatrixd(node.matrix.data());
|
||||
} else {
|
||||
// Assume Trans x Rotate x Scale order
|
||||
if (node.scale.size() == 3) {
|
||||
glScaled(node.scale[0], node.scale[1], node.scale[2]);
|
||||
}
|
||||
|
||||
if (node.rotation.size() == 4) {
|
||||
glRotated(node.rotation[0], node.rotation[1], node.rotation[2],
|
||||
node.rotation[3]);
|
||||
}
|
||||
|
||||
if (node.translation.size() == 3) {
|
||||
glTranslated(node.translation[0], node.translation[1],
|
||||
node.translation[2]);
|
||||
}
|
||||
|
||||
if (node.rotation.size() == 4) {
|
||||
double angleDegrees;
|
||||
double axis[3];
|
||||
|
||||
QuatToAngleAxis(node.rotation, angleDegrees, axis);
|
||||
|
||||
glRotated(angleDegrees, axis[0], axis[1], axis[2]);
|
||||
}
|
||||
|
||||
if (node.scale.size() == 3) {
|
||||
glScaled(node.scale[0], node.scale[1], node.scale[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,10 +830,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]]);
|
||||
}
|
||||
|
||||
@@ -675,18 +846,19 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||
|
||||
static void DrawModel(tinygltf::Model &model) {
|
||||
#if 0
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
|
||||
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
|
||||
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
for (; it != itEnd; it++) {
|
||||
DrawMesh(scene, it->second);
|
||||
DrawCurves(scene, it->second);
|
||||
}
|
||||
#else
|
||||
|
||||
// TODO(syoyo): Support non-default scenes.
|
||||
assert(model.defaultScene >= 0);
|
||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||
// If the glTF asset has at least one scene, and doesn't define a default one
|
||||
// just show the first one we can find
|
||||
assert(model.scenes.size() > 0);
|
||||
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
|
||||
const tinygltf::Scene &scene = model.scenes[scene_to_display];
|
||||
for (size_t i = 0; i < scene.nodes.size(); i++) {
|
||||
DrawNode(model, model.nodes[scene.nodes[i]]);
|
||||
}
|
||||
@@ -717,8 +889,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 +901,31 @@ 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()) {
|
||||
@@ -752,17 +939,19 @@ int main(int argc, char **argv) {
|
||||
Init();
|
||||
|
||||
// DBG
|
||||
PrintNodes(model.scenes[model.defaultScene]);
|
||||
PrintNodes(model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]);
|
||||
|
||||
if (!glfwInit()) {
|
||||
std::cerr << "Failed to initialize GLFW." << std::endl;
|
||||
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 +977,23 @@ 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()
|
||||
+354
-18
@@ -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";
|
||||
@@ -171,7 +175,10 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
|
||||
ss << arr[i];
|
||||
if (i != arr.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << " ]";
|
||||
|
||||
@@ -186,7 +193,10 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
|
||||
ss << arr[i];
|
||||
if (i != arr.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
}
|
||||
ss << " ]";
|
||||
|
||||
@@ -210,8 +220,22 @@ 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 +243,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 << Indent(indent) << 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 << Indent(indent) << 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 << Indent(indent) << 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 << Indent(indent) << value.Get<int>() << " ";
|
||||
}
|
||||
} else if (value.IsArray()) {
|
||||
// TODO(syoyo): Better pretty printing of array item
|
||||
ss << Indent(indent) << name << " [ \n";
|
||||
for (size_t i = 0; i < value.Size(); i++) {
|
||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
||||
if (i != (value.ArrayLen() - 1)) {
|
||||
ss << ", \n";
|
||||
}
|
||||
}
|
||||
ss << "\n" << Indent(indent) << "] ";
|
||||
}
|
||||
// @todo { binary, array }
|
||||
|
||||
// @todo { binary }
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
@@ -272,6 +322,15 @@ static void DumpStringIntMap(const std::map<std::string, int> &m, int indent) {
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpExtensions(const tinygltf::ExtensionMap &extension,
|
||||
const int indent) {
|
||||
// TODO(syoyo): pritty print Value
|
||||
for (auto &e : extension) {
|
||||
std::cout << Indent(indent) << e.first << std::endl;
|
||||
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
std::cout << Indent(indent) << "material : " << primitive.material
|
||||
<< std::endl;
|
||||
@@ -283,8 +342,80 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||
<< std::endl;
|
||||
DumpStringIntMap(primitive.attributes, indent + 1);
|
||||
|
||||
DumpExtensions(primitive.extensions, indent);
|
||||
std::cout << Indent(indent) << "extras :" << std::endl
|
||||
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
|
||||
|
||||
if (!primitive.extensions_json_string.empty()) {
|
||||
std::cout << Indent(indent + 1) << "extensions(JSON string) = "
|
||||
<< primitive.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!primitive.extras_json_string.empty()) {
|
||||
std::cout << Indent(indent + 1)
|
||||
<< "extras(JSON string) = " << primitive.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
|
||||
if (!texinfo.extensions_json_string.empty()) {
|
||||
std::cout << Indent(indent)
|
||||
<< "extensions(JSON string) = " << texinfo.extensions_json_string
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
if (!texinfo.extras_json_string.empty()) {
|
||||
std::cout << Indent(indent)
|
||||
<< "extras(JSON string) = " << texinfo.extras_json_string << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void DumpOcclusionTextureInfo(
|
||||
const tinygltf::OcclusionTextureInfo &texinfo, const int indent) {
|
||||
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n";
|
||||
DumpExtensions(texinfo.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr,
|
||||
const int indent) {
|
||||
std::cout << Indent(indent)
|
||||
<< "baseColorFactor : " << PrintFloatArray(pbr.baseColorFactor)
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "baseColorTexture :\n";
|
||||
DumpTextureInfo(pbr.baseColorTexture, indent + 1);
|
||||
|
||||
std::cout << Indent(indent) << "metallicFactor : " << pbr.metallicFactor
|
||||
<< "\n";
|
||||
std::cout << Indent(indent) << "roughnessFactor : " << pbr.roughnessFactor
|
||||
<< "\n";
|
||||
|
||||
std::cout << Indent(indent) << "metallicRoughnessTexture :\n";
|
||||
DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1);
|
||||
DumpExtensions(pbr.extensions, indent + 1);
|
||||
std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n";
|
||||
}
|
||||
|
||||
static void Dump(const tinygltf::Model &model) {
|
||||
@@ -307,6 +438,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 +476,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,10 +484,34 @@ 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;
|
||||
}
|
||||
|
||||
if (accessor.sparse.isSparse) {
|
||||
std::cout << Indent(2) << "sparse:" << std::endl;
|
||||
std::cout << Indent(3) << "count : " << accessor.sparse.count
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "indices: " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.indices.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.indices.byteOffset
|
||||
<< std::endl;
|
||||
std::cout << Indent(4) << "componentType: "
|
||||
<< PrintComponentType(accessor.sparse.indices.componentType)
|
||||
<< "(" << accessor.sparse.indices.componentType << ")"
|
||||
<< std::endl;
|
||||
std::cout << Indent(3) << "values : " << std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "bufferView : " << accessor.sparse.values.bufferView
|
||||
<< std::endl;
|
||||
std::cout << Indent(4)
|
||||
<< "byteOffset : " << accessor.sparse.values.byteOffset
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +524,7 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
|
||||
std::cout << Indent(1) << "channels : [ " << std::endl;
|
||||
for (size_t j = 0; i < animation.channels.size(); i++) {
|
||||
for (size_t j = 0; j < animation.channels.size(); j++) {
|
||||
std::cout << Indent(2)
|
||||
<< "sampler : " << animation.channels[j].sampler
|
||||
<< std::endl;
|
||||
@@ -414,6 +570,21 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2)
|
||||
<< "target : " << PrintTarget(bufferView.target)
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(bufferView.extensions, 1);
|
||||
std::cout << PrintValue("extras", bufferView.extras, 2) << std::endl;
|
||||
|
||||
if (!bufferView.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< bufferView.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!bufferView.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << bufferView.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +595,21 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(1) << "name : " << buffer.name << std::endl;
|
||||
std::cout << Indent(2) << "byteLength : " << buffer.data.size()
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(buffer.extensions, 1);
|
||||
std::cout << PrintValue("extras", buffer.extras, 2) << std::endl;
|
||||
|
||||
if (!buffer.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< buffer.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!buffer.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << buffer.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,16 +618,55 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
for (size_t i = 0; i < model.materials.size(); i++) {
|
||||
const tinygltf::Material &material = model.materials[i];
|
||||
std::cout << Indent(1) << "name : " << material.name << std::endl;
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
||||
std::cout << Indent(1) << "name : " << material.name
|
||||
<< std::endl;
|
||||
|
||||
std::cout << Indent(1) << "alphaMode : " << material.alphaMode
|
||||
<< std::endl;
|
||||
std::cout << Indent(1)
|
||||
<< "alphaCutoff : " << material.alphaCutoff
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "doubleSided : "
|
||||
<< (material.doubleSided ? "true" : "false") << std::endl;
|
||||
std::cout << Indent(1) << "emissiveFactor : "
|
||||
<< PrintFloatArray(material.emissiveFactor) << std::endl;
|
||||
|
||||
std::cout << Indent(1) << "pbrMetallicRoughness :\n";
|
||||
DumpPbrMetallicRoughness(material.pbrMetallicRoughness, 2);
|
||||
|
||||
std::cout << Indent(1) << "normalTexture :\n";
|
||||
DumpNormalTextureInfo(material.normalTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "occlusionTexture :\n";
|
||||
DumpOcclusionTextureInfo(material.occlusionTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "emissiveTexture :\n";
|
||||
DumpTextureInfo(material.emissiveTexture, 2);
|
||||
|
||||
std::cout << Indent(1) << "---- legacy material parameter ----\n";
|
||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
||||
<< std::endl;
|
||||
tinygltf::ParameterMap::const_iterator p(material.values.begin());
|
||||
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
|
||||
for (; p != pEnd; p++) {
|
||||
std::cout << Indent(2) << p->first << ": "
|
||||
<< PrintParameterValue(p->second) << std::endl;
|
||||
}
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(material.extensions, 1);
|
||||
std::cout << PrintValue("extras", material.extras, 2) << std::endl;
|
||||
|
||||
if (!material.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< material.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!material.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << material.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,6 +689,19 @@ 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);
|
||||
std::cout << PrintValue("extras", image.extras, 2) << std::endl;
|
||||
|
||||
if (!image.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< image.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!image.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << image.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,6 +713,19 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "source : " << texture.source
|
||||
<< std::endl;
|
||||
DumpExtensions(texture.extensions, 1);
|
||||
std::cout << PrintValue("extras", texture.extras, 2) << std::endl;
|
||||
|
||||
if (!texture.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< texture.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!texture.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << texture.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,6 +747,20 @@ static void Dump(const tinygltf::Model &model) {
|
||||
std::cout << Indent(2)
|
||||
<< "wrapT : " << PrintWrapMode(sampler.wrapT)
|
||||
<< std::endl;
|
||||
|
||||
DumpExtensions(sampler.extensions, 1);
|
||||
std::cout << PrintValue("extras", sampler.extras, 2) << std::endl;
|
||||
|
||||
if (!sampler.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< sampler.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!sampler.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << sampler.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,8 +793,63 @@ static void Dump(const tinygltf::Model &model) {
|
||||
<< "znear : " << camera.orthographic.znear
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(camera.extensions, 1);
|
||||
std::cout << PrintValue("extras", camera.extras, 2) << std::endl;
|
||||
|
||||
if (!camera.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2) << "extensions(JSON string) = "
|
||||
<< camera.extensions_json_string << "\n";
|
||||
}
|
||||
|
||||
if (!camera.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << camera.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "skins(items=" << model.skins.size() << ")" << std::endl;
|
||||
for (size_t i = 0; i < model.skins.size(); i++) {
|
||||
const tinygltf::Skin &skin = model.skins[i];
|
||||
std::cout << Indent(1) << "name : " << skin.name << std::endl;
|
||||
std::cout << Indent(2)
|
||||
<< "inverseBindMatrices : " << skin.inverseBindMatrices
|
||||
<< std::endl;
|
||||
std::cout << Indent(2) << "skeleton : " << skin.skeleton
|
||||
<< std::endl;
|
||||
std::cout << Indent(2)
|
||||
<< "joints : " << PrintIntArray(skin.joints)
|
||||
<< std::endl;
|
||||
std::cout << Indent(1) << "-------------------------------------\n";
|
||||
|
||||
DumpExtensions(skin.extensions, 1);
|
||||
std::cout << PrintValue("extras", skin.extras, 2) << std::endl;
|
||||
|
||||
if (!skin.extensions_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extensions(JSON string) = " << skin.extensions_json_string
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
if (!skin.extras_json_string.empty()) {
|
||||
std::cout << Indent(2)
|
||||
<< "extras(JSON string) = " << skin.extras_json_string
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// toplevel extensions
|
||||
{
|
||||
std::cout << "extensions(items=" << model.extensions.size() << ")"
|
||||
<< std::endl;
|
||||
DumpExtensions(model.extensions, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -538,21 +858,37 @@ int main(int argc, char **argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Store original JSON string for `extras` and `extensions`
|
||||
bool store_original_json_for_extras_and_extensions = false;
|
||||
if (argc > 2) {
|
||||
store_original_json_for_extras_and_extensions = true;
|
||||
}
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF gltf_ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string ext = GetFilePathExtension(input_filename);
|
||||
|
||||
gltf_ctx.SetStoreOriginalJSONForExtrasAndExtensions(
|
||||
store_original_json_for_extras_and_extensions);
|
||||
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
std::cout << "Reading binary glTF" << std::endl;
|
||||
// assume binary glTF.
|
||||
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, 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()) {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [0]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"POSITION": 1
|
||||
},
|
||||
"indices": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"uri": "simpleTriangle.bin",
|
||||
"byteLength": 44
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 1e300,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 8,
|
||||
"byteLength": 36,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 3,
|
||||
"type": "VEC3",
|
||||
"max": [1, 1, 0],
|
||||
"min": [0, 0, 0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user