Compare commits
573 Commits
temp-inter
...
vr_scene_i
Author | SHA1 | Date | |
---|---|---|---|
46b91b2dda | |||
3a73aba822 | |||
f0ccb6ab46 | |||
2f2f587881 | |||
99eb95337f | |||
3f114cd229 | |||
5d30598e3b | |||
a7e3b04e7a | |||
1792bf1c0a | |||
cd083a67c2 | |||
1a7135b12f | |||
ae14649583 | |||
4586813de6 | |||
860adf13ed | |||
97c929a88f | |||
5c1ac85ba5 | |||
a75a79272e | |||
ddbbd9928e | |||
d2ef342b2a | |||
d16897eb2e | |||
e9ef555c97 | |||
5d8906fbe5 | |||
![]() |
fb8ff0c112 | ||
![]() |
1fab889a40 | ||
![]() |
03c9039e8b | ||
![]() |
7bdd12e20c | ||
![]() |
60bcfbef40 | ||
![]() |
8a87e48b18 | ||
![]() |
98e61078d3 | ||
![]() |
8093667d5a | ||
![]() |
3eef47a26b | ||
![]() |
4be3e48a80 | ||
![]() |
f7a03d97ce | ||
![]() |
3b693a9aac | ||
![]() |
8e841ed71e | ||
29addd4360 | |||
3bc41d2f50 | |||
5ea28551cb | |||
27774c3e0d | |||
67da109882 | |||
b86be9b214 | |||
cb6cec904f | |||
1a07728c99 | |||
f4b6ce38a4 | |||
d5af5dbcde | |||
97c33d3670 | |||
4ad5449c92 | |||
e07f2aec7e | |||
5bcb37c3b7 | |||
e2bf7b1564 | |||
daa98f8978 | |||
61a5fcc83a | |||
39107d3ed1 | |||
a79b731edc | |||
4deee5c00c | |||
5333441eb1 | |||
dd8ef89633 | |||
5cca2f041d | |||
00f83ec125 | |||
a2d04deda7 | |||
8f327fb070 | |||
f8c3ccf398 | |||
7c11e45f5f | |||
792335cfab | |||
b381eba6c7 | |||
066d755e47 | |||
f2018ba492 | |||
![]() |
f07cd66ca1 | ||
80b15a44b6 | |||
8126e4ac14 | |||
cfa4302570 | |||
e7ceb041cf | |||
32bdfa0e06 | |||
c18d503205 | |||
![]() |
c02ba3653a | ||
6472edb2c8 | |||
5aedfd12cd | |||
7d9731ef7d | |||
6ae0839879 | |||
1e2253a8da | |||
5419542260 | |||
cd35a7b7d5 | |||
9abf5ba1d5 | |||
1cc81d39c4 | |||
e38cd1741e | |||
27bc3388da | |||
8b8142c13a | |||
![]() |
0315159501 | ||
d60c71f33d | |||
916efac0c8 | |||
ef20e1d378 | |||
262b1efd15 | |||
27cdc66484 | |||
549a5fd661 | |||
814931d27d | |||
f73a6c517c | |||
6e13062ddb | |||
73791a755a | |||
![]() |
da10812f25 | ||
![]() |
8c31727298 | ||
![]() |
247c691d69 | ||
![]() |
1c49f0cc20 | ||
![]() |
28321b064a | ||
![]() |
10d563baf4 | ||
![]() |
812c4f45f5 | ||
![]() |
75163f2a7d | ||
![]() |
3c0c28afe1 | ||
![]() |
4ecea3dd3e | ||
![]() |
25b3287ce6 | ||
![]() |
ba254334f0 | ||
![]() |
463fe7c949 | ||
![]() |
68cec61dae | ||
![]() |
c822556e27 | ||
![]() |
e62a012f90 | ||
![]() |
be7b41df3f | ||
![]() |
6f977c5e6d | ||
![]() |
a74af5f6f0 | ||
![]() |
3e41ea03be | ||
![]() |
489da13b94 | ||
![]() |
f9a3a42412 | ||
![]() |
202623419e | ||
![]() |
49f7848589 | ||
![]() |
6fda295034 | ||
![]() |
2b7e94e35e | ||
![]() |
65ceb8ee5d | ||
![]() |
9b5a1edbc4 | ||
![]() |
6cceecb82f | ||
![]() |
166c1f9a92 | ||
![]() |
d65ce022b6 | ||
![]() |
3da9ecc6c1 | ||
![]() |
0f979f3388 | ||
![]() |
72ad66b101 | ||
![]() |
f25a348915 | ||
![]() |
af00df3469 | ||
![]() |
80c6f6eb4e | ||
![]() |
e583eee37c | ||
![]() |
62db972f0f | ||
![]() |
e9036242fa | ||
![]() |
83aebf759e | ||
![]() |
5169f9e975 | ||
![]() |
d9c05e6997 | ||
![]() |
d205f36906 | ||
![]() |
85e5bbe0a0 | ||
![]() |
d0d0cc998e | ||
![]() |
f1e51c14e8 | ||
![]() |
12b405cd55 | ||
580230f0c5 | |||
fedb339eb7 | |||
43ad16701f | |||
b1d7085641 | |||
2686bc8383 | |||
dff31a5548 | |||
![]() |
38e75093a8 | ||
![]() |
e70e26043a | ||
93bb8ef737 | |||
9124e2bfa3 | |||
7c6f2e5683 | |||
8a4671e5ed | |||
c7a90ea656 | |||
22afd42cc2 | |||
ee9815b8af | |||
dd1a89e156 | |||
5a60ac152d | |||
![]() |
4d31095fde | ||
![]() |
7864aa7e86 | ||
19638bf00e | |||
57d29dc196 | |||
1cf049fd4b | |||
e6a9ece316 | |||
a0dd1a679b | |||
60bf5dcdc5 | |||
6f3ddcf629 | |||
fc5eed7845 | |||
4e2c0b3d7b | |||
79f727bb07 | |||
bfbd1135df | |||
caad28d050 | |||
811991716a | |||
5ec8888620 | |||
368791c7f5 | |||
ae1a75b960 | |||
8f5ad8df7e | |||
f7ef613155 | |||
be645d4550 | |||
71ccb092d4 | |||
de9c1bafed | |||
d0664a101e | |||
b50e2af4fe | |||
adc190cdac | |||
25601df774 | |||
![]() |
7873807aae | ||
448ff0751a | |||
e76dd30c8a | |||
978d4306d2 | |||
![]() |
5710f8eaee | ||
![]() |
2047394fc2 | ||
51b494864c | |||
![]() |
b11abfde87 | ||
e1c14a013a | |||
29f409178d | |||
![]() |
e76bd9264a | ||
0e12ea49b5 | |||
da0c062ee4 | |||
27c54f774e | |||
2d707840b8 | |||
![]() |
a31bc357f0 | ||
e0b8abf19b | |||
a639b37b88 | |||
4f19513df4 | |||
3341dcf5eb | |||
749120c1f4 | |||
a275fd0089 | |||
adda126d95 | |||
0bfdff1da7 | |||
d6a9824d6a | |||
a247174348 | |||
3aff10511d | |||
ddc8bff463 | |||
5bc46ecdac | |||
320ea5f32a | |||
f30c15e7d3 | |||
a18418de46 | |||
de91170546 | |||
1acf3418cb | |||
![]() |
6e07e61fc4 | ||
06b956c682 | |||
c6a4ca114b | |||
bf1ad6f3ad | |||
668618bb25 | |||
7aaadc3adc | |||
d9a713d7b9 | |||
f451240d00 | |||
661291f684 | |||
e9a004ba70 | |||
f6e51546c3 | |||
2667168421 | |||
2ee40a8558 | |||
bb6a508895 | |||
a0e109acdf | |||
d2245fe017 | |||
b3abd2e102 | |||
6be2ad8367 | |||
6bd5c1b33a | |||
03defc0182 | |||
![]() |
f4ead52f1b | ||
c093ef6ca2 | |||
aafbbe34a2 | |||
56da28b684 | |||
c30b9327b9 | |||
5a0719794e | |||
8672e0df44 | |||
1e53606603 | |||
![]() |
20cdf4f99c | ||
129fed65e5 | |||
63f1c86bc4 | |||
b65e894852 | |||
![]() |
fdabd1446b | ||
de28611d8f | |||
c1f153833c | |||
9ab004a6ee | |||
e769ae2c00 | |||
7b51a10bca | |||
5c6f5509da | |||
326137d9b9 | |||
7650c1652f | |||
![]() |
404cc8d1fc | ||
![]() |
af928a2fb1 | ||
![]() |
b1c9434332 | ||
![]() |
4c2ec7c5ec | ||
![]() |
79069884b1 | ||
![]() |
7254d1ae49 | ||
![]() |
63d34abc0f | ||
![]() |
8dd6f89a5d | ||
![]() |
fe1f7c038d | ||
![]() |
a18c254c6d | ||
![]() |
27bbbc9c57 | ||
![]() |
6dbe2d781d | ||
![]() |
3b1e67754c | ||
![]() |
19f3fdad97 | ||
![]() |
8d5996595f | ||
![]() |
47baf42e2c | ||
![]() |
cdfe5449df | ||
![]() |
f0786dfc52 | ||
![]() |
de2d03ace9 | ||
![]() |
e6e81376b7 | ||
![]() |
78643f0767 | ||
![]() |
34372607de | ||
![]() |
763eb3d016 | ||
![]() |
8d2119c054 | ||
![]() |
fe8222cf00 | ||
![]() |
0a27ab2e93 | ||
![]() |
d930ff7f4f | ||
![]() |
f3e9351111 | ||
![]() |
2a259497ae | ||
![]() |
eecf3021d7 | ||
![]() |
5d4f8d31a5 | ||
![]() |
e3e370c5ea | ||
![]() |
e99e914352 | ||
![]() |
a02e03fa16 | ||
![]() |
0173800572 | ||
![]() |
bc38898cf4 | ||
![]() |
1a812145e0 | ||
![]() |
f430f6fa18 | ||
![]() |
2f6ebe1b99 | ||
![]() |
c706834749 | ||
![]() |
f640704654 | ||
![]() |
dbc1622010 | ||
![]() |
ccbfeb0e57 | ||
![]() |
9b1d318222 | ||
![]() |
ff62a827ce | ||
![]() |
11ee2f1d09 | ||
![]() |
fcc6e94897 | ||
![]() |
d6cce8bc8e | ||
![]() |
4332e2b5fb | ||
![]() |
3ff91e97d9 | ||
![]() |
fd95e3275a | ||
![]() |
6b496ca687 | ||
![]() |
e951f4becf | ||
![]() |
5409b0b0be | ||
![]() |
d330d0762b | ||
![]() |
5954cb807f | ||
![]() |
69bfe4b4c3 | ||
![]() |
270eb33645 | ||
![]() |
4b18015a1c | ||
![]() |
06138de13a | ||
![]() |
0c7ac28b8a | ||
![]() |
43cfa0b682 | ||
![]() |
f426d3a002 | ||
![]() |
a1499f7f7d | ||
![]() |
530a8d1ab1 | ||
![]() |
2232406394 | ||
![]() |
8f6b3d27d0 | ||
![]() |
ffa16f677a | ||
![]() |
85ccec8639 | ||
![]() |
fc83dfdba1 | ||
![]() |
2448eb6136 | ||
![]() |
90df65892f | ||
![]() |
f07e361829 | ||
![]() |
779b3f0cff | ||
![]() |
561f4665a6 | ||
![]() |
58f95e9e4d | ||
![]() |
17121b2afd | ||
![]() |
fc26797e72 | ||
![]() |
fa9707a712 | ||
![]() |
8d45b4f75c | ||
![]() |
03ac9de0a9 | ||
![]() |
4456dbcded | ||
![]() |
cc23a8c84d | ||
![]() |
120d9c91dc | ||
![]() |
e1db5cc2c7 | ||
![]() |
a347ec08bc | ||
![]() |
ee8e4b7db8 | ||
![]() |
8c7be58e72 | ||
![]() |
1b39eb1060 | ||
![]() |
0d98e665ea | ||
![]() |
7f1fadba67 | ||
![]() |
8537cdc71d | ||
![]() |
6ae2979d05 | ||
![]() |
b698a926af | ||
![]() |
fac53c7bc2 | ||
![]() |
88f234e27f | ||
![]() |
0615321ca0 | ||
![]() |
3bed8a7338 | ||
![]() |
ff03e3b7e0 | ||
![]() |
350b7b378d | ||
![]() |
51af7510fb | ||
![]() |
927c300c02 | ||
![]() |
fa9a841d43 | ||
![]() |
b057298021 | ||
![]() |
1ada9f5bf9 | ||
![]() |
52c9d33cc2 | ||
![]() |
db6657aa15 | ||
![]() |
941e1f5a98 | ||
![]() |
e9832f053b | ||
![]() |
cddf043cca | ||
![]() |
6af2f222ca | ||
![]() |
639dffa43a | ||
![]() |
9baa9e2bd3 | ||
![]() |
3c38e67765 | ||
![]() |
1849e4fe19 | ||
2ef7a1f24d | |||
![]() |
bc8186b5d1 | ||
![]() |
e0bb3f9286 | ||
![]() |
d0b4ec00f6 | ||
![]() |
7b6514c222 | ||
![]() |
c506acf2fc | ||
![]() |
31b8350b01 | ||
![]() |
d7a216704b | ||
![]() |
4b67477732 | ||
![]() |
4a039158e5 | ||
![]() |
61014e1dd9 | ||
![]() |
3441314e40 | ||
![]() |
f175dcc35f | ||
![]() |
756b676076 | ||
![]() |
7462fca737 | ||
![]() |
7c9e18c193 | ||
![]() |
6b69b5349b | ||
![]() |
daba8140c2 | ||
![]() |
599d0611b0 | ||
![]() |
e88970db82 | ||
![]() |
20b0b36479 | ||
![]() |
2c77f2deac | ||
![]() |
fec7ac7c51 | ||
![]() |
2a1ec8ec2a | ||
1548682cde | |||
![]() |
588dea6751 | ||
![]() |
ad4f9a4d98 | ||
![]() |
84466c7d71 | ||
![]() |
de037b031d | ||
![]() |
a21ae28f96 | ||
![]() |
b2424bd781 | ||
![]() |
d0177fc541 | ||
![]() |
4cf8740790 | ||
![]() |
a53b90329a | ||
![]() |
2c41ffa380 | ||
![]() |
cdc2768f65 | ||
![]() |
eb477c67a1 | ||
![]() |
0dd3f3925b | ||
![]() |
9e7c48575a | ||
![]() |
8138099fa9 | ||
![]() |
02de1b9860 | ||
![]() |
57712625f2 | ||
![]() |
96a34d7f50 | ||
![]() |
873223f38d | ||
![]() |
716c6b0c01 | ||
![]() |
62bbd2e37d | ||
![]() |
ba223dfac8 | ||
![]() |
8557997e81 | ||
![]() |
bcc8f7c6be | ||
![]() |
fe7b01a08f | ||
![]() |
5350015d51 | ||
![]() |
3483aa57b3 | ||
![]() |
44a220f721 | ||
![]() |
5274c5cce6 | ||
![]() |
0d70afed19 | ||
![]() |
03b09dbe32 | ||
![]() |
f04a5ad1e4 | ||
![]() |
ab1455e972 | ||
![]() |
b94af38c31 | ||
![]() |
40db778de3 | ||
![]() |
22966f4d35 | ||
![]() |
e8f66ff060 | ||
![]() |
9ac33e56a1 | ||
![]() |
091cc94379 | ||
![]() |
fc31be5ab0 | ||
![]() |
aff49f607a | ||
![]() |
57b77cd193 | ||
![]() |
d58eb8d29d | ||
![]() |
a4310ba85f | ||
![]() |
bd42740ef1 | ||
![]() |
679a4c34fc | ||
![]() |
55362436d9 | ||
![]() |
c1d164070b | ||
![]() |
3a4034a741 | ||
![]() |
a0be113d2e | ||
![]() |
151fb129e7 | ||
![]() |
165c5a5259 | ||
![]() |
74fc1db25b | ||
![]() |
03ff2a8dd5 | ||
d99d15f48d | |||
![]() |
6a998833cd | ||
![]() |
fca4826c7f | ||
![]() |
b0845fc133 | ||
![]() |
70cf8bd9c6 | ||
![]() |
3a2e459f58 | ||
![]() |
330f062099 | ||
![]() |
09872df1c7 | ||
![]() |
67d6399da6 | ||
![]() |
c29724912b | ||
![]() |
99560d9657 | ||
![]() |
b8a7b87873 | ||
![]() |
c9f6c1a054 | ||
![]() |
dd0fcb50b4 | ||
![]() |
c1e9cf00ac | ||
![]() |
84d609f67b | ||
![]() |
86178548d5 | ||
![]() |
d711540a85 | ||
![]() |
6e3158cb00 | ||
![]() |
b216690505 | ||
![]() |
b98896ddd9 | ||
![]() |
a05104d61f | ||
![]() |
7fe1cc8d24 | ||
![]() |
70e84a2c20 | ||
![]() |
084a33ca94 | ||
![]() |
37f619aea3 | ||
![]() |
6904ab10f4 | ||
![]() |
146ef0dd1e | ||
![]() |
5891e86420 | ||
![]() |
2cedad990a | ||
![]() |
109be29e42 | ||
![]() |
13442da69f | ||
![]() |
231dbd53bf | ||
![]() |
d3e48fb096 | ||
![]() |
d544a0b41c | ||
![]() |
cf4799e299 | ||
![]() |
57d9f004aa | ||
![]() |
62cde7a9ef | ||
![]() |
e4fcf25fc5 | ||
![]() |
215c919b33 | ||
![]() |
da44a02d00 | ||
![]() |
867007d9d7 | ||
![]() |
e9ea814233 | ||
![]() |
6b43c82cb5 | ||
![]() |
afbb62fecd | ||
![]() |
8a676e8fa9 | ||
![]() |
c52111e983 | ||
![]() |
d749e8a2c4 | ||
![]() |
8663aa80e6 | ||
![]() |
88b39444a0 | ||
![]() |
4cfc3caa09 | ||
![]() |
28428b3462 | ||
![]() |
24146563a0 | ||
![]() |
2ee9c60c20 | ||
![]() |
fb64675209 | ||
![]() |
76385139cf | ||
![]() |
b18f5a6a81 | ||
![]() |
9d29373b06 | ||
![]() |
f2f1e4dfed | ||
![]() |
0da0f29ade | ||
![]() |
a8519dbac2 | ||
![]() |
d15d07c4f6 | ||
![]() |
d356787a65 | ||
![]() |
a284fa3abb | ||
![]() |
4eeb7523e9 | ||
![]() |
f30fcd6c85 | ||
![]() |
47e8133520 | ||
![]() |
3fa7d59a04 | ||
![]() |
df8dc43946 | ||
![]() |
3b0a2fecfc | ||
![]() |
80af6d534d | ||
![]() |
71c7d61808 | ||
![]() |
637b803b97 | ||
![]() |
314eef0df8 | ||
![]() |
34fa0f8ac6 | ||
![]() |
16366724bd | ||
![]() |
fc8127d070 | ||
![]() |
3ac37fb552 | ||
![]() |
8e51a75772 | ||
![]() |
ba2dab402d | ||
![]() |
796994d222 | ||
![]() |
66e90e9179 | ||
![]() |
1404edbe3a | ||
![]() |
2f68a76409 | ||
![]() |
304d9a20fc | ||
![]() |
b169e327bf | ||
![]() |
7238bbecc4 | ||
![]() |
a49b4ca402 | ||
![]() |
eb0424c946 | ||
![]() |
5d6da57aa3 | ||
![]() |
e968bbc5d8 | ||
![]() |
b1b0e05c54 | ||
![]() |
e547026dfe | ||
![]() |
f816380af5 | ||
![]() |
5e642bfea1 | ||
![]() |
0d1a22f74f | ||
![]() |
20a1af936d | ||
![]() |
c9c1b90532 | ||
![]() |
4192281e14 | ||
![]() |
329deadc9e | ||
![]() |
53845c554d | ||
![]() |
35c9e3beed | ||
![]() |
60f66768cf | ||
![]() |
3e88974a80 | ||
![]() |
09e7d6cd26 | ||
![]() |
5d5ad5d6dd | ||
![]() |
e70894c360 | ||
![]() |
4c11886c4e | ||
![]() |
41e2f2e75f | ||
![]() |
864abbd425 | ||
![]() |
f333e7eb56 | ||
![]() |
a2ac2ec3c3 | ||
![]() |
06d52afcda | ||
![]() |
e65ba62c37 |
@@ -186,8 +186,7 @@ if(APPLE)
|
||||
option(WITH_XR_OPENXR "Enable VR features through the OpenXR specification" OFF)
|
||||
mark_as_advanced(WITH_XR_OPENXR)
|
||||
else()
|
||||
# Disabled until there's more than just the build system stuff. Should be enabled soon.
|
||||
option(WITH_XR_OPENXR "Enable VR features through the OpenXR specification" OFF)
|
||||
option(WITH_XR_OPENXR "Enable VR features through the OpenXR specification" ON)
|
||||
endif()
|
||||
|
||||
# Compositor
|
||||
|
@@ -158,7 +158,7 @@ def submodules_update(args, release_version, branch):
|
||||
branch = "master"
|
||||
|
||||
submodules = [
|
||||
("release/scripts/addons", branch),
|
||||
("release/scripts/addons", "master"),
|
||||
("release/scripts/addons_contrib", branch),
|
||||
("release/datafiles/locale", branch),
|
||||
("source/tools", branch),
|
||||
|
@@ -357,6 +357,53 @@ elseif(WIN32)
|
||||
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
list(APPEND SRC
|
||||
intern/GHOST_Xr.cpp
|
||||
intern/GHOST_XrContext.cpp
|
||||
intern/GHOST_XrEvent.cpp
|
||||
intern/GHOST_XrGraphicsBinding.cpp
|
||||
intern/GHOST_XrSession.cpp
|
||||
intern/GHOST_XrSwapchain.cpp
|
||||
|
||||
GHOST_IXrContext.h
|
||||
intern/GHOST_IXrGraphicsBinding.h
|
||||
intern/GHOST_Xr_intern.h
|
||||
intern/GHOST_Xr_openxr_includes.h
|
||||
intern/GHOST_XrContext.h
|
||||
intern/GHOST_XrSession.h
|
||||
intern/GHOST_XrSwapchain.h
|
||||
)
|
||||
list(APPEND INC_SYS
|
||||
${XR_OPENXR_SDK_INCLUDE_DIR}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${XR_OPENXR_SDK_LIBRARIES}
|
||||
)
|
||||
|
||||
set(XR_PLATFORM_DEFINES -DXR_USE_GRAPHICS_API_OPENGL)
|
||||
|
||||
# Add compiler defines as required by the OpenXR specification.
|
||||
if(WIN32)
|
||||
list(APPEND XR_PLATFORM_DEFINES
|
||||
-DXR_USE_PLATFORM_WIN32
|
||||
-DXR_USE_GRAPHICS_API_D3D11
|
||||
)
|
||||
list(APPEND LIB
|
||||
shlwapi
|
||||
)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
list(APPEND XR_PLATFORM_DEFINES
|
||||
-DXR_OS_LINUX
|
||||
-DXR_USE_PLATFORM_XLIB
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions(-DWITH_XR_OPENXR ${XR_PLATFORM_DEFINES})
|
||||
|
||||
unset(XR_PLATFORM_DEFINES)
|
||||
endif()
|
||||
|
||||
add_definitions(${GL_DEFINITIONS})
|
||||
|
||||
blender_add_lib(bf_intern_ghost "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -30,21 +30,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a "handle" for a C++ GHOST object.
|
||||
* A handle is just an opaque pointer to an empty struct.
|
||||
* In the API the pointer is cast to the actual C++ class.
|
||||
* The 'name' argument to the macro is the name of the handle to create.
|
||||
*/
|
||||
|
||||
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
|
||||
|
||||
/**
|
||||
* Definition of a callback routine that receives events.
|
||||
* \param event The event received.
|
||||
@@ -771,6 +756,18 @@ extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthan
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Returns whether a context is rendered upside down compared to OpenGL. This only needs to be
|
||||
* called if there's a non-OpenGL context, which is really the exception.
|
||||
* So generally, this does not need to be called.
|
||||
*/
|
||||
extern int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
|
||||
*/
|
||||
@@ -1006,6 +1003,91 @@ extern void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
|
||||
*/
|
||||
extern void GHOST_EndIME(GHOST_WindowHandle windowhandle);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
/* XR-context */
|
||||
|
||||
/**
|
||||
* Set a custom callback to be executed whenever an error occurs. Should be set before calling
|
||||
* #GHOST_XrContextCreate() to get error handling during context creation too.
|
||||
*
|
||||
* \param customdata: Handle to some data that will get passed to \a handler_fn should an error be
|
||||
* thrown.
|
||||
*/
|
||||
void GHOST_XrErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata);
|
||||
|
||||
/**
|
||||
* \brief Initialize the Ghost XR-context.
|
||||
*
|
||||
* Includes setting up the OpenXR runtime link, querying available extensions and API layers,
|
||||
* enabling extensions and API layers.
|
||||
*
|
||||
* \param create_info: Options for creating the XR-context, e.g. debug-flags and ordered array of
|
||||
* graphics bindings to try enabling.
|
||||
*/
|
||||
GHOST_XrContextHandle GHOST_XrContextCreate(const GHOST_XrContextCreateInfo *create_info);
|
||||
/**
|
||||
* Free a XR-context involving OpenXR runtime link destruction and freeing of all internal data.
|
||||
*/
|
||||
void GHOST_XrContextDestroy(GHOST_XrContextHandle xr_context);
|
||||
|
||||
/**
|
||||
* Set callbacks for binding and unbinding a graphics context for a session. The binding callback
|
||||
* may create a new graphics context thereby. In fact that's the sole reason for this callback
|
||||
* approach to binding. Just make sure to have an unbind function set that properly destructs.
|
||||
*
|
||||
* \param bind_fn: Function to retrieve (possibly create) a graphics context.
|
||||
* \param unbind_fn: Function to release (possibly free) a graphics context.
|
||||
*/
|
||||
void GHOST_XrGraphicsContextBindFuncs(GHOST_XrContextHandle xr_context,
|
||||
GHOST_XrGraphicsContextBindFn bind_fn,
|
||||
GHOST_XrGraphicsContextUnbindFn unbind_fn);
|
||||
|
||||
/**
|
||||
* Set the drawing callback for views. A view would typically be either the left or the right eye,
|
||||
* although other configurations are possible. When #GHOST_XrSessionDrawViews() is called to draw
|
||||
* an XR frame, \a draw_view_fn is executed for each view.
|
||||
*
|
||||
* \param draw_view_fn: The callback to draw a single view for an XR frame.
|
||||
*/
|
||||
void GHOST_XrDrawViewFunc(GHOST_XrContextHandle xr_context, GHOST_XrDrawViewFn draw_view_fn);
|
||||
|
||||
/* sessions */
|
||||
/**
|
||||
* Create internal session data for \a xr_context and ask the OpenXR runtime to invoke a session.
|
||||
*
|
||||
* \param begin_info: Options for the session creation.
|
||||
*/
|
||||
void GHOST_XrSessionStart(GHOST_XrContextHandle xr_context,
|
||||
const GHOST_XrSessionBeginInfo *begin_info);
|
||||
/**
|
||||
* Destruct internal session data for \a xr_context and ask the OpenXR runtime to stop a session.
|
||||
*/
|
||||
void GHOST_XrSessionEnd(GHOST_XrContextHandle xr_context);
|
||||
/**
|
||||
* Draw a single frame by calling the view drawing callback defined by #GHOST_XrDrawViewFunc() for
|
||||
* each view and submit it to the OpenXR runtime.
|
||||
*
|
||||
* \param customdata: Handle to some data that will get passed to the view drawing callback.
|
||||
*/
|
||||
void GHOST_XrSessionDrawViews(GHOST_XrContextHandle xr_context, void *customdata);
|
||||
/**
|
||||
* Check if a \a xr_context has a session that, according to the OpenXR definition would be
|
||||
* considered to be 'running'
|
||||
* (https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#session_running).
|
||||
*/
|
||||
int GHOST_XrSessionIsRunning(const GHOST_XrContextHandle xr_context);
|
||||
|
||||
/* events */
|
||||
/**
|
||||
* Invoke handling of all OpenXR events for \a xr_context. Should be called on every main-loop
|
||||
* iteration and will early-exit if \a xr_context is NULL (so caller doesn't have to check).
|
||||
*
|
||||
* \returns GHOST_kSuccess if any event was handled, otherwise GHOST_kFailure.
|
||||
*/
|
||||
GHOST_TSuccess GHOST_XrEventsHandle(GHOST_XrContextHandle xr_context);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -56,6 +56,15 @@ class GHOST_IContext {
|
||||
*/
|
||||
virtual GHOST_TSuccess releaseDrawingContext() = 0;
|
||||
|
||||
virtual unsigned int getDefaultFramebuffer() = 0;
|
||||
|
||||
virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
virtual bool isUpsideDown() const = 0;
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
|
||||
#endif
|
||||
|
42
intern/ghost/GHOST_IXrContext.h
Normal file
42
intern/ghost/GHOST_IXrContext.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_IXRCONTEXT_H__
|
||||
#define __GHOST_IXRCONTEXT_H__
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
class GHOST_IXrContext {
|
||||
public:
|
||||
virtual ~GHOST_IXrContext() = default;
|
||||
|
||||
virtual void startSession(const GHOST_XrSessionBeginInfo *begin_info) = 0;
|
||||
virtual void endSession() = 0;
|
||||
virtual bool isSessionRunning() const = 0;
|
||||
virtual void drawSessionViews(void *draw_customdata) = 0;
|
||||
|
||||
virtual void dispatchErrorMessage(const class GHOST_XrException *) const = 0;
|
||||
|
||||
virtual void setGraphicsContextBindFuncs(GHOST_XrGraphicsContextBindFn bind_fn,
|
||||
GHOST_XrGraphicsContextUnbindFn unbind_fn) = 0;
|
||||
virtual void setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn) = 0;
|
||||
};
|
||||
|
||||
#endif // __GHOST_IXRCONTEXT_H__
|
@@ -41,6 +41,22 @@
|
||||
} * name
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a "handle" for a C++ GHOST object.
|
||||
* A handle is just an opaque pointer to an empty struct.
|
||||
* In the API the pointer is cast to the actual C++ class.
|
||||
* The 'name' argument to the macro is the name of the handle to create.
|
||||
*/
|
||||
|
||||
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_XrContextHandle);
|
||||
|
||||
typedef char GHOST_TInt8;
|
||||
typedef unsigned char GHOST_TUns8;
|
||||
typedef short GHOST_TInt16;
|
||||
@@ -580,4 +596,87 @@ struct GHOST_TimerTaskHandle__;
|
||||
typedef void (*GHOST_TimerProcPtr)(struct GHOST_TimerTaskHandle__ *task, GHOST_TUns64 time);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
struct GHOST_XrError;
|
||||
struct GHOST_XrDrawViewInfo;
|
||||
/**
|
||||
* The XR view (i.e. the OpenXR runtime) may require a different graphics library than OpenGL. An
|
||||
* offscreen texture of the viewport will then be drawn into using OpenGL, but the final texture
|
||||
* draw call will happen through another lib (say DirectX).
|
||||
*
|
||||
* This enum defines the possible graphics bindings to attempt to enable.
|
||||
*/
|
||||
typedef enum GHOST_TXrGraphicsBinding {
|
||||
GHOST_kXrGraphicsUnknown = 0,
|
||||
GHOST_kXrGraphicsOpenGL,
|
||||
# ifdef WIN32
|
||||
GHOST_kXrGraphicsD3D11,
|
||||
# endif
|
||||
/* For later */
|
||||
// GHOST_kXrGraphicsVulkan,
|
||||
} GHOST_TXrGraphicsBinding;
|
||||
|
||||
typedef void (*GHOST_XrErrorHandlerFn)(const struct GHOST_XrError *);
|
||||
|
||||
typedef void (*GHOST_XrSessionExitFn)(void *customdata);
|
||||
|
||||
typedef void *(*GHOST_XrGraphicsContextBindFn)(enum GHOST_TXrGraphicsBinding graphics_lib);
|
||||
typedef void (*GHOST_XrGraphicsContextUnbindFn)(enum GHOST_TXrGraphicsBinding graphics_lib,
|
||||
GHOST_ContextHandle graphics_context);
|
||||
typedef void (*GHOST_XrDrawViewFn)(const struct GHOST_XrDrawViewInfo *draw_view, void *customdata);
|
||||
|
||||
/* An array of GHOST_TXrGraphicsBinding items defining the candidate bindings to use. The first
|
||||
* available candidate will be chosen, so order defines priority. */
|
||||
typedef const GHOST_TXrGraphicsBinding *GHOST_XrGraphicsBindingCandidates;
|
||||
|
||||
typedef struct {
|
||||
float position[3];
|
||||
/* Blender convention (w, x, y, z) */
|
||||
float orientation_quat[4];
|
||||
} GHOST_XrPose;
|
||||
|
||||
enum {
|
||||
GHOST_kXrContextDebug = (1 << 0),
|
||||
GHOST_kXrContextDebugTime = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const GHOST_XrGraphicsBindingCandidates gpu_binding_candidates;
|
||||
unsigned int gpu_binding_candidates_count;
|
||||
|
||||
unsigned int context_flag;
|
||||
} GHOST_XrContextCreateInfo;
|
||||
|
||||
typedef struct {
|
||||
GHOST_XrPose base_pose;
|
||||
|
||||
GHOST_XrSessionExitFn exit_fn;
|
||||
void *exit_customdata;
|
||||
} GHOST_XrSessionBeginInfo;
|
||||
|
||||
typedef struct GHOST_XrDrawViewInfo {
|
||||
int ofsx, ofsy;
|
||||
int width, height;
|
||||
|
||||
GHOST_XrPose eye_pose;
|
||||
GHOST_XrPose local_pose;
|
||||
|
||||
struct {
|
||||
float angle_left, angle_right;
|
||||
float angle_up, angle_down;
|
||||
} fov;
|
||||
|
||||
/** Set if the buffer should be submitted with a srgb transfer applied. */
|
||||
char expects_srgb_buffer;
|
||||
} GHOST_XrDrawViewInfo;
|
||||
|
||||
typedef struct GHOST_XrError {
|
||||
const char *user_message;
|
||||
|
||||
void *customdata;
|
||||
} GHOST_XrError;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __GHOST_TYPES_H__
|
||||
|
@@ -30,7 +30,11 @@
|
||||
#include "GHOST_ISystem.h"
|
||||
#include "GHOST_IEvent.h"
|
||||
#include "GHOST_IEventConsumer.h"
|
||||
#ifdef WITH_XR_OPENXR
|
||||
# include "GHOST_IXrContext.h"
|
||||
#endif
|
||||
#include "intern/GHOST_CallbackEventConsumer.h"
|
||||
#include "intern/GHOST_XrException.h"
|
||||
|
||||
GHOST_SystemHandle GHOST_CreateSystem(void)
|
||||
{
|
||||
@@ -705,6 +709,20 @@ GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
return context->releaseDrawingContext();
|
||||
}
|
||||
|
||||
unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->getDefaultFramebuffer();
|
||||
}
|
||||
|
||||
int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->isUpsideDown();
|
||||
}
|
||||
|
||||
unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
@@ -914,3 +932,63 @@ void GHOST_EndIME(GHOST_WindowHandle windowhandle)
|
||||
}
|
||||
|
||||
#endif /* WITH_INPUT_IME */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
# define GHOST_XR_CAPI_CALL(call, ctx) \
|
||||
try { \
|
||||
call; \
|
||||
} \
|
||||
catch (GHOST_XrException & e) { \
|
||||
(ctx)->dispatchErrorMessage(&e); \
|
||||
}
|
||||
|
||||
# define GHOST_XR_CAPI_CALL_RET(call, ctx) \
|
||||
try { \
|
||||
return call; \
|
||||
} \
|
||||
catch (GHOST_XrException & e) { \
|
||||
(ctx)->dispatchErrorMessage(&e); \
|
||||
}
|
||||
|
||||
void GHOST_XrSessionStart(GHOST_XrContextHandle xr_contexthandle,
|
||||
const GHOST_XrSessionBeginInfo *begin_info)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL(xr_context->startSession(begin_info), xr_context);
|
||||
}
|
||||
|
||||
void GHOST_XrSessionEnd(GHOST_XrContextHandle xr_contexthandle)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL(xr_context->endSession(), xr_context);
|
||||
}
|
||||
|
||||
void GHOST_XrSessionDrawViews(GHOST_XrContextHandle xr_contexthandle, void *draw_customdata)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL(xr_context->drawSessionViews(draw_customdata), xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrSessionIsRunning(const GHOST_XrContextHandle xr_contexthandle)
|
||||
{
|
||||
const GHOST_IXrContext *xr_context = (const GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL_RET(xr_context->isSessionRunning(), xr_context);
|
||||
return 0; /* Only reached if exception is thrown. */
|
||||
}
|
||||
|
||||
void GHOST_XrGraphicsContextBindFuncs(GHOST_XrContextHandle xr_contexthandle,
|
||||
GHOST_XrGraphicsContextBindFn bind_fn,
|
||||
GHOST_XrGraphicsContextUnbindFn unbind_fn)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL(xr_context->setGraphicsContextBindFuncs(bind_fn, unbind_fn), xr_context);
|
||||
}
|
||||
|
||||
void GHOST_XrDrawViewFunc(GHOST_XrContextHandle xr_contexthandle, GHOST_XrDrawViewFn draw_view_fn)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XR_CAPI_CALL(xr_context->setDrawViewFunc(draw_view_fn), xr_context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -119,6 +119,14 @@ class GHOST_Context : public GHOST_IContext {
|
||||
return m_stereoVisual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
inline bool isUpsideDown() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenGL framebuffer associated with the OpenGL context
|
||||
* \return The ID of an OpenGL framebuffer object.
|
||||
|
@@ -30,6 +30,9 @@
|
||||
#include "GHOST_Context.h"
|
||||
|
||||
class GHOST_ContextD3D : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingD3D;
|
||||
|
||||
public:
|
||||
GHOST_ContextD3D(bool stereoVisual, HWND hWnd);
|
||||
~GHOST_ContextD3D();
|
||||
|
@@ -273,6 +273,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
|
||||
m_window = (Window)glXCreatePbuffer(m_display, framebuffer_config[0], pbuffer_attribs);
|
||||
}
|
||||
|
||||
m_fbconfig = framebuffer_config[0];
|
||||
XFree(framebuffer_config);
|
||||
}
|
||||
}
|
||||
|
@@ -38,6 +38,9 @@
|
||||
#endif
|
||||
|
||||
class GHOST_ContextGLX : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingOpenGL;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
|
@@ -35,6 +35,9 @@
|
||||
#endif
|
||||
|
||||
class GHOST_ContextWGL : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingOpenGL;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
|
73
intern/ghost/intern/GHOST_IXrGraphicsBinding.h
Normal file
73
intern/ghost/intern/GHOST_IXrGraphicsBinding.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_IXRGRAPHICSBINDING_H__
|
||||
#define __GHOST_IXRGRAPHICSBINDING_H__
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GHOST_Xr_openxr_includes.h"
|
||||
|
||||
class GHOST_IXrGraphicsBinding {
|
||||
friend std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
|
||||
GHOST_TXrGraphicsBinding type);
|
||||
|
||||
public:
|
||||
union {
|
||||
#if defined(WITH_X11)
|
||||
XrGraphicsBindingOpenGLXlibKHR glx;
|
||||
#elif defined(WIN32)
|
||||
XrGraphicsBindingOpenGLWin32KHR wgl;
|
||||
XrGraphicsBindingD3D11KHR d3d11;
|
||||
#endif
|
||||
} oxr_binding;
|
||||
|
||||
virtual ~GHOST_IXrGraphicsBinding() = default;
|
||||
|
||||
/**
|
||||
* Does __not__ require this object is initialized (can be called prior to
|
||||
* #initFromGhostContext). It's actually meant to be called first.
|
||||
*
|
||||
* \param r_requirement_info Return argument to retrieve an informal string on the requirements
|
||||
* to be met. Useful for error/debug messages.
|
||||
*/
|
||||
virtual bool checkVersionRequirements(class GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const = 0;
|
||||
virtual void initFromGhostContext(class GHOST_Context *ghost_ctx) = 0;
|
||||
virtual bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const = 0;
|
||||
virtual std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(
|
||||
uint32_t image_count) = 0;
|
||||
virtual void submitToSwapchainImage(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const GHOST_XrDrawViewInfo *draw_info) = 0;
|
||||
|
||||
protected:
|
||||
/* Use GHOST_XrGraphicsBindingCreateFromType! */
|
||||
GHOST_IXrGraphicsBinding() = default;
|
||||
};
|
||||
|
||||
std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
|
||||
GHOST_TXrGraphicsBinding type);
|
||||
|
||||
#endif /* __GHOST_IXRGRAPHICSBINDING_H__ */
|
59
intern/ghost/intern/GHOST_Xr.cpp
Normal file
59
intern/ghost/intern/GHOST_Xr.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*
|
||||
* Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GHOST_Xr_intern.h"
|
||||
#include "GHOST_XrContext.h"
|
||||
#include "GHOST_XrException.h"
|
||||
|
||||
GHOST_XrContextHandle GHOST_XrContextCreate(const GHOST_XrContextCreateInfo *create_info)
|
||||
{
|
||||
GHOST_XrContext *xr_context = new GHOST_XrContext(create_info);
|
||||
|
||||
/* TODO GHOST_XrContext's should probably be owned by the GHOST_System, which will handle context
|
||||
* creation and destruction. Try-catch logic can be moved to C-API then. */
|
||||
try {
|
||||
xr_context->initialize(create_info);
|
||||
}
|
||||
catch (GHOST_XrException &e) {
|
||||
xr_context->dispatchErrorMessage(&e);
|
||||
delete xr_context;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (GHOST_XrContextHandle)xr_context;
|
||||
}
|
||||
|
||||
void GHOST_XrContextDestroy(GHOST_XrContextHandle xr_contexthandle)
|
||||
{
|
||||
delete (GHOST_XrContext *)xr_contexthandle;
|
||||
}
|
||||
|
||||
void GHOST_XrErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata)
|
||||
{
|
||||
GHOST_XrContext::setErrorHandler(handler_fn, customdata);
|
||||
}
|
552
intern/ghost/intern/GHOST_XrContext.cpp
Normal file
552
intern/ghost/intern/GHOST_XrContext.cpp
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*
|
||||
* Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_XrSession.h"
|
||||
|
||||
#include "GHOST_XrContext.h"
|
||||
|
||||
struct OpenXRInstanceData {
|
||||
XrInstance instance = XR_NULL_HANDLE;
|
||||
XrInstanceProperties instance_properties = {};
|
||||
|
||||
std::vector<XrExtensionProperties> extensions;
|
||||
std::vector<XrApiLayerProperties> layers;
|
||||
|
||||
static PFN_xrCreateDebugUtilsMessengerEXT s_xrCreateDebugUtilsMessengerEXT_fn;
|
||||
static PFN_xrDestroyDebugUtilsMessengerEXT s_xrDestroyDebugUtilsMessengerEXT_fn;
|
||||
|
||||
XrDebugUtilsMessengerEXT debug_messenger = XR_NULL_HANDLE;
|
||||
};
|
||||
|
||||
PFN_xrCreateDebugUtilsMessengerEXT OpenXRInstanceData::s_xrCreateDebugUtilsMessengerEXT_fn =
|
||||
nullptr;
|
||||
PFN_xrDestroyDebugUtilsMessengerEXT OpenXRInstanceData::s_xrDestroyDebugUtilsMessengerEXT_fn =
|
||||
nullptr;
|
||||
|
||||
GHOST_XrErrorHandlerFn GHOST_XrContext::s_error_handler = nullptr;
|
||||
void *GHOST_XrContext::s_error_handler_customdata = nullptr;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Create, Initialize and Destruct
|
||||
*
|
||||
* \{ */
|
||||
|
||||
GHOST_XrContext::GHOST_XrContext(const GHOST_XrContextCreateInfo *create_info)
|
||||
: m_oxr(new OpenXRInstanceData()),
|
||||
m_debug(create_info->context_flag & GHOST_kXrContextDebug),
|
||||
m_debug_time(create_info->context_flag & GHOST_kXrContextDebugTime)
|
||||
{
|
||||
}
|
||||
|
||||
GHOST_XrContext::~GHOST_XrContext()
|
||||
{
|
||||
/* Destroy session data first. Otherwise xrDestroyInstance will implicitly do it, before the
|
||||
* session had a chance to do so explicitly. */
|
||||
m_session = nullptr;
|
||||
|
||||
if (m_oxr->debug_messenger != XR_NULL_HANDLE) {
|
||||
assert(m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn != nullptr);
|
||||
m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn(m_oxr->debug_messenger);
|
||||
}
|
||||
if (m_oxr->instance != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroyInstance(m_oxr->instance));
|
||||
m_oxr->instance = XR_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrContext::initialize(const GHOST_XrContextCreateInfo *create_info)
|
||||
{
|
||||
initApiLayers();
|
||||
initExtensions();
|
||||
if (isDebugMode()) {
|
||||
printAvailableAPILayersAndExtensionsInfo();
|
||||
}
|
||||
|
||||
m_gpu_binding_type = determineGraphicsBindingTypeToEnable(create_info);
|
||||
|
||||
assert(m_oxr->instance == XR_NULL_HANDLE);
|
||||
createOpenXRInstance();
|
||||
storeInstanceProperties();
|
||||
printInstanceInfo();
|
||||
if (isDebugMode()) {
|
||||
initDebugMessenger();
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrContext::createOpenXRInstance()
|
||||
{
|
||||
XrInstanceCreateInfo create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
|
||||
|
||||
std::string("Blender").copy(create_info.applicationInfo.applicationName,
|
||||
XR_MAX_APPLICATION_NAME_SIZE);
|
||||
create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||
|
||||
getAPILayersToEnable(m_enabled_layers);
|
||||
getExtensionsToEnable(m_enabled_extensions);
|
||||
create_info.enabledApiLayerCount = m_enabled_layers.size();
|
||||
create_info.enabledApiLayerNames = m_enabled_layers.data();
|
||||
create_info.enabledExtensionCount = m_enabled_extensions.size();
|
||||
create_info.enabledExtensionNames = m_enabled_extensions.data();
|
||||
if (isDebugMode()) {
|
||||
printExtensionsAndAPILayersToEnable();
|
||||
}
|
||||
|
||||
CHECK_XR(xrCreateInstance(&create_info, &m_oxr->instance),
|
||||
"Failed to connect to an OpenXR runtime.");
|
||||
}
|
||||
|
||||
void GHOST_XrContext::storeInstanceProperties()
|
||||
{
|
||||
const std::map<std::string, GHOST_TXrOpenXRRuntimeID> runtime_map = {
|
||||
{"Monado(XRT) by Collabora et al", OPENXR_RUNTIME_MONADO},
|
||||
{"Oculus", OPENXR_RUNTIME_OCULUS},
|
||||
{"Windows Mixed Reality Runtime", OPENXR_RUNTIME_WMR}};
|
||||
decltype(runtime_map)::const_iterator runtime_map_iter;
|
||||
|
||||
m_oxr->instance_properties.type = XR_TYPE_INSTANCE_PROPERTIES;
|
||||
CHECK_XR(xrGetInstanceProperties(m_oxr->instance, &m_oxr->instance_properties),
|
||||
"Failed to get OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
runtime_map_iter = runtime_map.find(m_oxr->instance_properties.runtimeName);
|
||||
if (runtime_map_iter != runtime_map.end()) {
|
||||
m_runtime_id = runtime_map_iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Create, Initialize and Destruct */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug Printing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrContext::printInstanceInfo()
|
||||
{
|
||||
assert(m_oxr->instance != XR_NULL_HANDLE);
|
||||
|
||||
printf("Connected to OpenXR runtime: %s (Version %u.%u.%u)\n",
|
||||
m_oxr->instance_properties.runtimeName,
|
||||
XR_VERSION_MAJOR(m_oxr->instance_properties.runtimeVersion),
|
||||
XR_VERSION_MINOR(m_oxr->instance_properties.runtimeVersion),
|
||||
XR_VERSION_PATCH(m_oxr->instance_properties.runtimeVersion));
|
||||
}
|
||||
|
||||
void GHOST_XrContext::printAvailableAPILayersAndExtensionsInfo()
|
||||
{
|
||||
puts("Available OpenXR API-layers/extensions:");
|
||||
for (XrApiLayerProperties &layer_info : m_oxr->layers) {
|
||||
printf("Layer: %s\n", layer_info.layerName);
|
||||
}
|
||||
for (XrExtensionProperties &ext_info : m_oxr->extensions) {
|
||||
printf("Extension: %s\n", ext_info.extensionName);
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrContext::printExtensionsAndAPILayersToEnable()
|
||||
{
|
||||
for (const char *layer_name : m_enabled_layers) {
|
||||
printf("Enabling OpenXR API-Layer: %s\n", layer_name);
|
||||
}
|
||||
for (const char *ext_name : m_enabled_extensions) {
|
||||
printf("Enabling OpenXR Extension: %s\n", ext_name);
|
||||
}
|
||||
}
|
||||
|
||||
static XrBool32 debug_messenger_func(XrDebugUtilsMessageSeverityFlagsEXT /*messageSeverity*/,
|
||||
XrDebugUtilsMessageTypeFlagsEXT /*messageTypes*/,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT *callbackData,
|
||||
void * /*userData*/)
|
||||
{
|
||||
puts("OpenXR Debug Message:");
|
||||
puts(callbackData->message);
|
||||
return XR_FALSE; /* OpenXR spec suggests always returning false. */
|
||||
}
|
||||
|
||||
void GHOST_XrContext::initDebugMessenger()
|
||||
{
|
||||
XrDebugUtilsMessengerCreateInfoEXT create_info = {XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
|
||||
|
||||
/* Extension functions need to be obtained through xrGetInstanceProcAddr(). */
|
||||
if (XR_FAILED(xrGetInstanceProcAddr(
|
||||
m_oxr->instance,
|
||||
"xrCreateDebugUtilsMessengerEXT",
|
||||
(PFN_xrVoidFunction *)&m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn)) ||
|
||||
XR_FAILED(xrGetInstanceProcAddr(
|
||||
m_oxr->instance,
|
||||
"xrDestroyDebugUtilsMessengerEXT",
|
||||
(PFN_xrVoidFunction *)&m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn))) {
|
||||
m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn = nullptr;
|
||||
m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn = nullptr;
|
||||
|
||||
fprintf(stderr,
|
||||
"Could not use XR_EXT_debug_utils to enable debug prints. Not a fatal error, "
|
||||
"continuing without the messenger.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
create_info.messageSeverities = XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
create_info.messageTypes = XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
create_info.userCallback = debug_messenger_func;
|
||||
|
||||
if (XR_FAILED(m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn(
|
||||
m_oxr->instance, &create_info, &m_oxr->debug_messenger))) {
|
||||
fprintf(stderr,
|
||||
"Failed to create OpenXR debug messenger. Not a fatal error, continuing without the "
|
||||
"messenger.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Debug Printing */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Error handling
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrContext::dispatchErrorMessage(const GHOST_XrException *exception) const
|
||||
{
|
||||
GHOST_XrError error;
|
||||
|
||||
error.user_message = exception->m_msg;
|
||||
error.customdata = s_error_handler_customdata;
|
||||
|
||||
if (isDebugMode()) {
|
||||
fprintf(stderr,
|
||||
"Error: \t%s\n\tOpenXR error value: %i\n",
|
||||
error.user_message,
|
||||
exception->m_result);
|
||||
}
|
||||
|
||||
/* Potentially destroys GHOST_XrContext */
|
||||
s_error_handler(&error);
|
||||
}
|
||||
|
||||
void GHOST_XrContext::setErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata)
|
||||
{
|
||||
s_error_handler = handler_fn;
|
||||
s_error_handler_customdata = customdata;
|
||||
}
|
||||
|
||||
/** \} */ /* Error handling */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name OpenXR API-Layers and Extensions
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \param layer_name May be NULL for extensions not belonging to a specific layer.
|
||||
*/
|
||||
void GHOST_XrContext::initExtensionsEx(std::vector<XrExtensionProperties> &extensions,
|
||||
const char *layer_name)
|
||||
{
|
||||
uint32_t extension_count = 0;
|
||||
|
||||
/* Get count for array creation/init first. */
|
||||
CHECK_XR(xrEnumerateInstanceExtensionProperties(layer_name, 0, &extension_count, nullptr),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
if (extension_count == 0) {
|
||||
/* Extensions are optional, can successfully exit. */
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < extension_count; i++) {
|
||||
XrExtensionProperties ext = {XR_TYPE_EXTENSION_PROPERTIES};
|
||||
extensions.push_back(ext);
|
||||
}
|
||||
|
||||
/* Actually get the extensions. */
|
||||
CHECK_XR(xrEnumerateInstanceExtensionProperties(
|
||||
layer_name, extension_count, &extension_count, extensions.data()),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
}
|
||||
|
||||
void GHOST_XrContext::initExtensions()
|
||||
{
|
||||
initExtensionsEx(m_oxr->extensions, nullptr);
|
||||
}
|
||||
|
||||
void GHOST_XrContext::initApiLayers()
|
||||
{
|
||||
uint32_t layer_count = 0;
|
||||
|
||||
/* Get count for array creation/init first. */
|
||||
CHECK_XR(xrEnumerateApiLayerProperties(0, &layer_count, nullptr),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
if (layer_count == 0) {
|
||||
/* Layers are optional, can safely exit. */
|
||||
return;
|
||||
}
|
||||
|
||||
m_oxr->layers = std::vector<XrApiLayerProperties>(layer_count);
|
||||
for (XrApiLayerProperties &layer : m_oxr->layers) {
|
||||
layer.type = XR_TYPE_API_LAYER_PROPERTIES;
|
||||
}
|
||||
|
||||
/* Actually get the layers. */
|
||||
CHECK_XR(xrEnumerateApiLayerProperties(layer_count, &layer_count, m_oxr->layers.data()),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
for (XrApiLayerProperties &layer : m_oxr->layers) {
|
||||
/* Each layer may have own extensions. */
|
||||
initExtensionsEx(m_oxr->extensions, layer.layerName);
|
||||
}
|
||||
}
|
||||
|
||||
static bool openxr_layer_is_available(const std::vector<XrApiLayerProperties> layers_info,
|
||||
const std::string &layer_name)
|
||||
{
|
||||
for (const XrApiLayerProperties &layer_info : layers_info) {
|
||||
if (layer_info.layerName == layer_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool openxr_extension_is_available(const std::vector<XrExtensionProperties> extensions_info,
|
||||
const std::string &extension_name)
|
||||
{
|
||||
for (const XrExtensionProperties &ext_info : extensions_info) {
|
||||
if (ext_info.extensionName == extension_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather an array of names for the API-layers to enable.
|
||||
*/
|
||||
void GHOST_XrContext::getAPILayersToEnable(std::vector<const char *> &r_ext_names)
|
||||
{
|
||||
static std::vector<std::string> try_layers;
|
||||
|
||||
try_layers.clear();
|
||||
|
||||
if (isDebugMode()) {
|
||||
try_layers.push_back("XR_APILAYER_LUNARG_core_validation");
|
||||
}
|
||||
|
||||
r_ext_names.reserve(try_layers.size());
|
||||
|
||||
for (const std::string &layer : try_layers) {
|
||||
if (openxr_layer_is_available(m_oxr->layers, layer)) {
|
||||
r_ext_names.push_back(layer.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *openxr_ext_name_from_wm_gpu_binding(GHOST_TXrGraphicsBinding binding)
|
||||
{
|
||||
switch (binding) {
|
||||
case GHOST_kXrGraphicsOpenGL:
|
||||
return XR_KHR_OPENGL_ENABLE_EXTENSION_NAME;
|
||||
#ifdef WIN32
|
||||
case GHOST_kXrGraphicsD3D11:
|
||||
return XR_KHR_D3D11_ENABLE_EXTENSION_NAME;
|
||||
#endif
|
||||
case GHOST_kXrGraphicsUnknown:
|
||||
assert(!"Could not identify graphics binding to choose.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather an array of names for the extensions to enable.
|
||||
*/
|
||||
void GHOST_XrContext::getExtensionsToEnable(std::vector<const char *> &r_ext_names)
|
||||
{
|
||||
assert(m_gpu_binding_type != GHOST_kXrGraphicsUnknown);
|
||||
|
||||
const char *gpu_binding = openxr_ext_name_from_wm_gpu_binding(m_gpu_binding_type);
|
||||
static std::vector<std::string> try_ext;
|
||||
|
||||
try_ext.clear();
|
||||
|
||||
/* Try enabling debug extension. */
|
||||
#ifndef WIN32
|
||||
if (isDebugMode()) {
|
||||
try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
r_ext_names.reserve(try_ext.size() + 1); /* + 1 for graphics binding extension. */
|
||||
|
||||
/* Add graphics binding extension. */
|
||||
assert(gpu_binding);
|
||||
assert(openxr_extension_is_available(m_oxr->extensions, gpu_binding));
|
||||
r_ext_names.push_back(gpu_binding);
|
||||
|
||||
for (const std::string &ext : try_ext) {
|
||||
if (openxr_extension_is_available(m_oxr->extensions, ext)) {
|
||||
r_ext_names.push_back(ext.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide which graphics binding extension to use based on
|
||||
* #GHOST_XrContextCreateInfo.gpu_binding_candidates and available extensions.
|
||||
*/
|
||||
GHOST_TXrGraphicsBinding GHOST_XrContext::determineGraphicsBindingTypeToEnable(
|
||||
const GHOST_XrContextCreateInfo *create_info)
|
||||
{
|
||||
assert(create_info->gpu_binding_candidates != NULL);
|
||||
assert(create_info->gpu_binding_candidates_count > 0);
|
||||
|
||||
for (uint32_t i = 0; i < create_info->gpu_binding_candidates_count; i++) {
|
||||
assert(create_info->gpu_binding_candidates[i] != GHOST_kXrGraphicsUnknown);
|
||||
const char *ext_name = openxr_ext_name_from_wm_gpu_binding(
|
||||
create_info->gpu_binding_candidates[i]);
|
||||
if (openxr_extension_is_available(m_oxr->extensions, ext_name)) {
|
||||
return create_info->gpu_binding_candidates[i];
|
||||
}
|
||||
}
|
||||
|
||||
return GHOST_kXrGraphicsUnknown;
|
||||
}
|
||||
|
||||
/** \} */ /* OpenXR API-Layers and Extensions */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Session management
|
||||
*
|
||||
* Manage session lifetime and delegate public calls to #GHOST_XrSession.
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrContext::startSession(const GHOST_XrSessionBeginInfo *begin_info)
|
||||
{
|
||||
m_custom_funcs.session_exit_fn = begin_info->exit_fn;
|
||||
m_custom_funcs.session_exit_customdata = begin_info->exit_customdata;
|
||||
|
||||
if (m_session == nullptr) {
|
||||
m_session = std::unique_ptr<GHOST_XrSession>(new GHOST_XrSession(this));
|
||||
}
|
||||
m_session->start(begin_info);
|
||||
}
|
||||
|
||||
void GHOST_XrContext::endSession()
|
||||
{
|
||||
m_session->requestEnd();
|
||||
}
|
||||
|
||||
bool GHOST_XrContext::isSessionRunning() const
|
||||
{
|
||||
return m_session && m_session->isRunning();
|
||||
}
|
||||
|
||||
void GHOST_XrContext::drawSessionViews(void *draw_customdata)
|
||||
{
|
||||
m_session->draw(draw_customdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates event to session, allowing context to destruct the session if needed.
|
||||
*/
|
||||
void GHOST_XrContext::handleSessionStateChange(const XrEventDataSessionStateChanged *lifecycle)
|
||||
{
|
||||
if (m_session &&
|
||||
m_session->handleStateChangeEvent(lifecycle) == GHOST_XrSession::SESSION_DESTROY) {
|
||||
m_session = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Session Management */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Public Accessors and Mutators
|
||||
*
|
||||
* Public as in, exposed in the Ghost API.
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrContext::setGraphicsContextBindFuncs(GHOST_XrGraphicsContextBindFn bind_fn,
|
||||
GHOST_XrGraphicsContextUnbindFn unbind_fn)
|
||||
{
|
||||
if (m_session) {
|
||||
m_session->unbindGraphicsContext();
|
||||
}
|
||||
m_custom_funcs.gpu_ctx_bind_fn = bind_fn;
|
||||
m_custom_funcs.gpu_ctx_unbind_fn = unbind_fn;
|
||||
}
|
||||
|
||||
void GHOST_XrContext::setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn)
|
||||
{
|
||||
m_custom_funcs.draw_view_fn = draw_view_fn;
|
||||
}
|
||||
|
||||
/** \} */ /* Public Accessors and Mutators */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Ghost Internal Accessors and Mutators
|
||||
*
|
||||
* \{ */
|
||||
|
||||
GHOST_TXrOpenXRRuntimeID GHOST_XrContext::getOpenXRRuntimeID() const
|
||||
{
|
||||
return m_runtime_id;
|
||||
}
|
||||
|
||||
const GHOST_XrCustomFuncs &GHOST_XrContext::getCustomFuncs() const
|
||||
{
|
||||
return m_custom_funcs;
|
||||
}
|
||||
|
||||
GHOST_TXrGraphicsBinding GHOST_XrContext::getGraphicsBindingType() const
|
||||
{
|
||||
return m_gpu_binding_type;
|
||||
}
|
||||
|
||||
XrInstance GHOST_XrContext::getInstance() const
|
||||
{
|
||||
return m_oxr->instance;
|
||||
}
|
||||
|
||||
bool GHOST_XrContext::isDebugMode() const
|
||||
{
|
||||
return m_debug;
|
||||
}
|
||||
|
||||
bool GHOST_XrContext::isDebugTimeMode() const
|
||||
{
|
||||
return m_debug_time;
|
||||
}
|
||||
|
||||
/** \} */ /* Ghost Internal Accessors and Mutators */
|
130
intern/ghost/intern/GHOST_XrContext.h
Normal file
130
intern/ghost/intern/GHOST_XrContext.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XRCONTEXT_H__
|
||||
#define __GHOST_XRCONTEXT_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GHOST_IXrContext.h"
|
||||
|
||||
struct OpenXRInstanceData;
|
||||
|
||||
struct GHOST_XrCustomFuncs {
|
||||
/** Function to retrieve (possibly create) a graphics context. */
|
||||
GHOST_XrGraphicsContextBindFn gpu_ctx_bind_fn = nullptr;
|
||||
/** Function to release (possibly free) a graphics context. */
|
||||
GHOST_XrGraphicsContextUnbindFn gpu_ctx_unbind_fn = nullptr;
|
||||
|
||||
GHOST_XrSessionExitFn session_exit_fn = nullptr;
|
||||
void *session_exit_customdata = nullptr;
|
||||
|
||||
/** Custom per-view draw function for Blender side drawing. */
|
||||
GHOST_XrDrawViewFn draw_view_fn = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* In some occasions, runtime specific handling is needed, e.g. to work around runtime bugs.
|
||||
*/
|
||||
enum GHOST_TXrOpenXRRuntimeID {
|
||||
OPENXR_RUNTIME_MONADO,
|
||||
OPENXR_RUNTIME_OCULUS,
|
||||
OPENXR_RUNTIME_WMR, /* Windows Mixed Reality */
|
||||
|
||||
OPENXR_RUNTIME_UNKNOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Main GHOST container to manage OpenXR through.
|
||||
*
|
||||
* Creating a context using #GHOST_XrContextCreate involves dynamically connecting to the OpenXR
|
||||
* runtime, likely reading the OS OpenXR configuration (i.e. active_runtime.json). So this is
|
||||
* something that should better be done using lazy-initialization.
|
||||
*/
|
||||
class GHOST_XrContext : public GHOST_IXrContext {
|
||||
public:
|
||||
GHOST_XrContext(const GHOST_XrContextCreateInfo *create_info);
|
||||
~GHOST_XrContext();
|
||||
void initialize(const GHOST_XrContextCreateInfo *create_info);
|
||||
|
||||
void startSession(const GHOST_XrSessionBeginInfo *begin_info) override;
|
||||
void endSession() override;
|
||||
bool isSessionRunning() const override;
|
||||
void drawSessionViews(void *draw_customdata) override;
|
||||
|
||||
static void setErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata);
|
||||
void dispatchErrorMessage(const class GHOST_XrException *exception) const override;
|
||||
|
||||
void setGraphicsContextBindFuncs(GHOST_XrGraphicsContextBindFn bind_fn,
|
||||
GHOST_XrGraphicsContextUnbindFn unbind_fn) override;
|
||||
void setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn) override;
|
||||
|
||||
void handleSessionStateChange(const XrEventDataSessionStateChanged *lifecycle);
|
||||
|
||||
GHOST_TXrOpenXRRuntimeID getOpenXRRuntimeID() const;
|
||||
const GHOST_XrCustomFuncs &getCustomFuncs() const;
|
||||
GHOST_TXrGraphicsBinding getGraphicsBindingType() const;
|
||||
XrInstance getInstance() const;
|
||||
bool isDebugMode() const;
|
||||
bool isDebugTimeMode() const;
|
||||
|
||||
private:
|
||||
static GHOST_XrErrorHandlerFn s_error_handler;
|
||||
static void *s_error_handler_customdata;
|
||||
|
||||
std::unique_ptr<OpenXRInstanceData> m_oxr;
|
||||
|
||||
GHOST_TXrOpenXRRuntimeID m_runtime_id = OPENXR_RUNTIME_UNKNOWN;
|
||||
|
||||
/* The active GHOST XR Session. Null while no session runs. */
|
||||
std::unique_ptr<class GHOST_XrSession> m_session;
|
||||
|
||||
/** Active graphics binding type. */
|
||||
GHOST_TXrGraphicsBinding m_gpu_binding_type = GHOST_kXrGraphicsUnknown;
|
||||
|
||||
/** Names of enabled extensions. */
|
||||
std::vector<const char *> m_enabled_extensions;
|
||||
/** Names of enabled API-layers. */
|
||||
std::vector<const char *> m_enabled_layers;
|
||||
|
||||
GHOST_XrCustomFuncs m_custom_funcs;
|
||||
|
||||
/** Enable debug message prints and OpenXR API validation layers. */
|
||||
bool m_debug = false;
|
||||
bool m_debug_time = false;
|
||||
|
||||
void createOpenXRInstance();
|
||||
void storeInstanceProperties();
|
||||
void initDebugMessenger();
|
||||
|
||||
void printInstanceInfo();
|
||||
void printAvailableAPILayersAndExtensionsInfo();
|
||||
void printExtensionsAndAPILayersToEnable();
|
||||
|
||||
void initApiLayers();
|
||||
void initExtensions();
|
||||
void initExtensionsEx(std::vector<XrExtensionProperties> &extensions, const char *layer_name);
|
||||
void getAPILayersToEnable(std::vector<const char *> &r_ext_names);
|
||||
void getExtensionsToEnable(std::vector<const char *> &r_ext_names);
|
||||
GHOST_TXrGraphicsBinding determineGraphicsBindingTypeToEnable(
|
||||
const GHOST_XrContextCreateInfo *create_info);
|
||||
};
|
||||
|
||||
#endif // __GHOST_XRCONTEXT_H__
|
64
intern/ghost/intern/GHOST_XrEvent.cpp
Normal file
64
intern/ghost/intern/GHOST_XrEvent.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
#include "GHOST_XrContext.h"
|
||||
|
||||
static bool GHOST_XrEventPollNext(XrInstance instance, XrEventDataBuffer &r_event_data)
|
||||
{
|
||||
/* (Re-)initialize as required by specification. */
|
||||
r_event_data.type = XR_TYPE_EVENT_DATA_BUFFER;
|
||||
r_event_data.next = nullptr;
|
||||
|
||||
return (xrPollEvent(instance, &r_event_data) == XR_SUCCESS);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_XrEventsHandle(GHOST_XrContextHandle xr_contexthandle)
|
||||
{
|
||||
GHOST_XrContext *xr_context = (GHOST_XrContext *)xr_contexthandle;
|
||||
XrEventDataBuffer event_buffer; /* Structure big enough to hold all possible events. */
|
||||
|
||||
if (xr_context == NULL) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
while (GHOST_XrEventPollNext(xr_context->getInstance(), event_buffer)) {
|
||||
XrEventDataBaseHeader *event = (XrEventDataBaseHeader *)&event_buffer;
|
||||
|
||||
switch (event->type) {
|
||||
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
|
||||
xr_context->handleSessionStateChange((XrEventDataSessionStateChanged *)event);
|
||||
return GHOST_kSuccess;
|
||||
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
|
||||
GHOST_XrContextDestroy(xr_contexthandle);
|
||||
return GHOST_kSuccess;
|
||||
default:
|
||||
if (xr_context->isDebugMode()) {
|
||||
printf("Unhandled event: %i\n", event->type);
|
||||
}
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
return GHOST_kFailure;
|
||||
}
|
45
intern/ghost/intern/GHOST_XrException.h
Normal file
45
intern/ghost/intern/GHOST_XrException.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XREXCEPTION_H__
|
||||
#define __GHOST_XREXCEPTION_H__
|
||||
|
||||
#include <exception>
|
||||
|
||||
class GHOST_XrException : public std::exception {
|
||||
friend class GHOST_XrContext;
|
||||
|
||||
public:
|
||||
GHOST_XrException(const char *msg, int result = 0)
|
||||
: std::exception(), m_msg(msg), m_result(result)
|
||||
{
|
||||
}
|
||||
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_msg;
|
||||
int m_result;
|
||||
};
|
||||
|
||||
#endif // __GHOST_XREXCEPTION_H__
|
318
intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
Normal file
318
intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#if defined(WITH_X11)
|
||||
# include "GHOST_ContextGLX.h"
|
||||
#elif defined(WIN32)
|
||||
# include "GHOST_ContextWGL.h"
|
||||
# include "GHOST_ContextD3D.h"
|
||||
#endif
|
||||
#include "GHOST_C-api.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
|
||||
#include "GHOST_IXrGraphicsBinding.h"
|
||||
|
||||
static bool choose_swapchain_format_from_candidates(std::vector<int64_t> gpu_binding_formats,
|
||||
std::vector<int64_t> runtime_formats,
|
||||
int64_t *r_result)
|
||||
{
|
||||
if (gpu_binding_formats.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto res = std::find_first_of(gpu_binding_formats.begin(),
|
||||
gpu_binding_formats.end(),
|
||||
runtime_formats.begin(),
|
||||
runtime_formats.end());
|
||||
if (res == gpu_binding_formats.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_result = *res;
|
||||
return true;
|
||||
}
|
||||
|
||||
class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
|
||||
public:
|
||||
~GHOST_XrGraphicsBindingOpenGL()
|
||||
{
|
||||
if (m_fbo != 0) {
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkVersionRequirements(GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const override
|
||||
{
|
||||
#if defined(WITH_X11)
|
||||
GHOST_ContextGLX *ctx_gl = static_cast<GHOST_ContextGLX *>(ghost_ctx);
|
||||
#else
|
||||
GHOST_ContextWGL *ctx_gl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
|
||||
#endif
|
||||
static PFN_xrGetOpenGLGraphicsRequirementsKHR s_xrGetOpenGLGraphicsRequirementsKHR_fn =
|
||||
nullptr;
|
||||
XrGraphicsRequirementsOpenGLKHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR};
|
||||
const XrVersion gl_version = XR_MAKE_VERSION(
|
||||
ctx_gl->m_contextMajorVersion, ctx_gl->m_contextMinorVersion, 0);
|
||||
|
||||
if (!s_xrGetOpenGLGraphicsRequirementsKHR_fn &&
|
||||
XR_FAILED(xrGetInstanceProcAddr(
|
||||
instance,
|
||||
"xrGetOpenGLGraphicsRequirementsKHR",
|
||||
(PFN_xrVoidFunction *)&s_xrGetOpenGLGraphicsRequirementsKHR_fn))) {
|
||||
s_xrGetOpenGLGraphicsRequirementsKHR_fn = nullptr;
|
||||
}
|
||||
|
||||
s_xrGetOpenGLGraphicsRequirementsKHR_fn(instance, system_id, &gpu_requirements);
|
||||
|
||||
if (r_requirement_info) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Min OpenGL version "
|
||||
<< XR_VERSION_MAJOR(gpu_requirements.minApiVersionSupported) << "."
|
||||
<< XR_VERSION_MINOR(gpu_requirements.minApiVersionSupported) << std::endl;
|
||||
strstream << "Max OpenGL version "
|
||||
<< XR_VERSION_MAJOR(gpu_requirements.maxApiVersionSupported) << "."
|
||||
<< XR_VERSION_MINOR(gpu_requirements.maxApiVersionSupported) << std::endl;
|
||||
|
||||
*r_requirement_info = strstream.str();
|
||||
}
|
||||
|
||||
return (gl_version >= gpu_requirements.minApiVersionSupported) &&
|
||||
(gl_version <= gpu_requirements.maxApiVersionSupported);
|
||||
}
|
||||
|
||||
void initFromGhostContext(GHOST_Context *ghost_ctx) override
|
||||
{
|
||||
#if defined(WITH_X11)
|
||||
GHOST_ContextGLX *ctx_glx = static_cast<GHOST_ContextGLX *>(ghost_ctx);
|
||||
XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx->m_display, ctx_glx->m_fbconfig);
|
||||
|
||||
oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
|
||||
oxr_binding.glx.xDisplay = ctx_glx->m_display;
|
||||
oxr_binding.glx.glxFBConfig = ctx_glx->m_fbconfig;
|
||||
oxr_binding.glx.glxDrawable = ctx_glx->m_window;
|
||||
oxr_binding.glx.glxContext = ctx_glx->m_context;
|
||||
oxr_binding.glx.visualid = visual_info->visualid;
|
||||
|
||||
XFree(visual_info);
|
||||
#elif defined(WIN32)
|
||||
GHOST_ContextWGL *ctx_wgl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
|
||||
|
||||
oxr_binding.wgl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
||||
oxr_binding.wgl.hDC = ctx_wgl->m_hDC;
|
||||
oxr_binding.wgl.hGLRC = ctx_wgl->m_hGLRC;
|
||||
#endif
|
||||
|
||||
/* Generate a framebuffer to use for blitting into the texture. */
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
}
|
||||
|
||||
bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {GL_RGBA8};
|
||||
return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
|
||||
}
|
||||
|
||||
std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
|
||||
{
|
||||
std::vector<XrSwapchainImageOpenGLKHR> ogl_images(image_count);
|
||||
std::vector<XrSwapchainImageBaseHeader *> base_images;
|
||||
|
||||
/* Need to return vector of base header pointers, so of a different type. Need to build a new
|
||||
* list with this type, and keep the initial one alive. */
|
||||
for (XrSwapchainImageOpenGLKHR &image : ogl_images) {
|
||||
image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
|
||||
base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
|
||||
}
|
||||
|
||||
/* Keep alive. */
|
||||
m_image_cache.push_back(std::move(ogl_images));
|
||||
|
||||
return base_images;
|
||||
}
|
||||
|
||||
void submitToSwapchainImage(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const GHOST_XrDrawViewInfo *draw_info) override
|
||||
{
|
||||
XrSwapchainImageOpenGLKHR *ogl_swapchain_image = reinterpret_cast<XrSwapchainImageOpenGLKHR *>(
|
||||
swapchain_image);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
|
||||
|
||||
glFramebufferTexture2D(
|
||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_swapchain_image->image, 0);
|
||||
|
||||
glBlitFramebuffer(draw_info->ofsx,
|
||||
draw_info->ofsy,
|
||||
draw_info->ofsx + draw_info->width,
|
||||
draw_info->ofsy + draw_info->height,
|
||||
draw_info->ofsx,
|
||||
draw_info->ofsy,
|
||||
draw_info->ofsx + draw_info->width,
|
||||
draw_info->ofsy + draw_info->height,
|
||||
GL_COLOR_BUFFER_BIT,
|
||||
GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<std::vector<XrSwapchainImageOpenGLKHR>> m_image_cache;
|
||||
GLuint m_fbo = 0;
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
|
||||
public:
|
||||
~GHOST_XrGraphicsBindingD3D()
|
||||
{
|
||||
if (m_shared_resource) {
|
||||
m_ghost_ctx->disposeSharedOpenGLResource(m_shared_resource);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkVersionRequirements(GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const override
|
||||
{
|
||||
GHOST_ContextD3D *ctx_dx = static_cast<GHOST_ContextD3D *>(ghost_ctx);
|
||||
static PFN_xrGetD3D11GraphicsRequirementsKHR s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
|
||||
XrGraphicsRequirementsD3D11KHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR};
|
||||
|
||||
if (!s_xrGetD3D11GraphicsRequirementsKHR_fn &&
|
||||
XR_FAILED(xrGetInstanceProcAddr(
|
||||
instance,
|
||||
"xrGetD3D11GraphicsRequirementsKHR",
|
||||
(PFN_xrVoidFunction *)&s_xrGetD3D11GraphicsRequirementsKHR_fn))) {
|
||||
s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
|
||||
}
|
||||
|
||||
s_xrGetD3D11GraphicsRequirementsKHR_fn(instance, system_id, &gpu_requirements);
|
||||
|
||||
if (r_requirement_info) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Minimum DirectX 11 Feature Level " << gpu_requirements.minFeatureLevel
|
||||
<< std::endl;
|
||||
|
||||
*r_requirement_info = std::move(strstream.str());
|
||||
}
|
||||
|
||||
return ctx_dx->m_device->GetFeatureLevel() >= gpu_requirements.minFeatureLevel;
|
||||
}
|
||||
|
||||
void initFromGhostContext(GHOST_Context *ghost_ctx) override
|
||||
{
|
||||
GHOST_ContextD3D *ctx_d3d = static_cast<GHOST_ContextD3D *>(ghost_ctx);
|
||||
|
||||
oxr_binding.d3d11.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
|
||||
oxr_binding.d3d11.device = ctx_d3d->m_device;
|
||||
m_ghost_ctx = ctx_d3d;
|
||||
}
|
||||
|
||||
bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {DXGI_FORMAT_R8G8B8A8_UNORM};
|
||||
return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
|
||||
}
|
||||
|
||||
std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
|
||||
{
|
||||
std::vector<XrSwapchainImageD3D11KHR> d3d_images(image_count);
|
||||
std::vector<XrSwapchainImageBaseHeader *> base_images;
|
||||
|
||||
/* Need to return vector of base header pointers, so of a different type. Need to build a new
|
||||
* list with this type, and keep the initial one alive. */
|
||||
for (XrSwapchainImageD3D11KHR &image : d3d_images) {
|
||||
image.type = XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR;
|
||||
base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
|
||||
}
|
||||
|
||||
/* Keep alive. */
|
||||
m_image_cache.push_back(std::move(d3d_images));
|
||||
|
||||
return base_images;
|
||||
}
|
||||
|
||||
void submitToSwapchainImage(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const GHOST_XrDrawViewInfo *draw_info) override
|
||||
{
|
||||
XrSwapchainImageD3D11KHR *d3d_swapchain_image = reinterpret_cast<XrSwapchainImageD3D11KHR *>(
|
||||
swapchain_image);
|
||||
|
||||
# if 0
|
||||
/* Ideally we'd just create a render target view for the OpenXR swapchain image texture and
|
||||
* blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with
|
||||
* this though. At least not with Optimus hardware. See:
|
||||
* https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807.
|
||||
*/
|
||||
|
||||
ID3D11RenderTargetView *rtv;
|
||||
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
|
||||
m_ghost_ctx->m_device->CreateRenderTargetView(d3d_swapchain_image->texture, &rtv_desc, &rtv);
|
||||
if (!m_shared_resource) {
|
||||
m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(
|
||||
draw_info->width, draw_info->height, rtv);
|
||||
}
|
||||
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
|
||||
# else
|
||||
if (!m_shared_resource) {
|
||||
m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(draw_info->width,
|
||||
draw_info->height);
|
||||
}
|
||||
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
|
||||
|
||||
m_ghost_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
m_ghost_ctx->m_device_ctx->CopyResource(d3d_swapchain_image->texture,
|
||||
m_ghost_ctx->getSharedTexture2D(m_shared_resource));
|
||||
# endif
|
||||
}
|
||||
|
||||
private:
|
||||
GHOST_ContextD3D *m_ghost_ctx;
|
||||
GHOST_SharedOpenGLResource *m_shared_resource;
|
||||
std::list<std::vector<XrSwapchainImageD3D11KHR>> m_image_cache;
|
||||
};
|
||||
#endif // WIN32
|
||||
|
||||
std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
|
||||
GHOST_TXrGraphicsBinding type)
|
||||
{
|
||||
switch (type) {
|
||||
case GHOST_kXrGraphicsOpenGL:
|
||||
return std::unique_ptr<GHOST_XrGraphicsBindingOpenGL>(new GHOST_XrGraphicsBindingOpenGL());
|
||||
#ifdef WIN32
|
||||
case GHOST_kXrGraphicsD3D11:
|
||||
return std::unique_ptr<GHOST_XrGraphicsBindingD3D>(new GHOST_XrGraphicsBindingD3D());
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
510
intern/ghost/intern/GHOST_XrSession.cpp
Normal file
510
intern/ghost/intern/GHOST_XrSession.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GHOST_IXrGraphicsBinding.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
#include "GHOST_XrContext.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_XrSwapchain.h"
|
||||
|
||||
#include "GHOST_XrSession.h"
|
||||
|
||||
struct OpenXRSessionData {
|
||||
XrSystemId system_id = XR_NULL_SYSTEM_ID;
|
||||
XrSession session = XR_NULL_HANDLE;
|
||||
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
|
||||
|
||||
/* Only stereo rendering supported now. */
|
||||
const XrViewConfigurationType view_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||
XrSpace reference_space;
|
||||
XrSpace view_space;
|
||||
std::vector<XrView> views;
|
||||
std::vector<std::unique_ptr<GHOST_XrSwapchain>> swapchains;
|
||||
};
|
||||
|
||||
struct GHOST_XrDrawInfo {
|
||||
XrFrameState frame_state;
|
||||
|
||||
/** Time at frame start to benchmark frame render durations. */
|
||||
std::chrono::high_resolution_clock::time_point frame_begin_time;
|
||||
/* Time previous frames took for rendering (in ms). */
|
||||
std::list<double> last_frame_times;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Create, Initialize and Destruct
|
||||
*
|
||||
* \{ */
|
||||
|
||||
GHOST_XrSession::GHOST_XrSession(GHOST_XrContext *xr_context)
|
||||
: m_context(xr_context), m_oxr(new OpenXRSessionData())
|
||||
{
|
||||
}
|
||||
|
||||
GHOST_XrSession::~GHOST_XrSession()
|
||||
{
|
||||
unbindGraphicsContext();
|
||||
|
||||
m_oxr->swapchains.clear();
|
||||
|
||||
if (m_oxr->reference_space != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroySpace(m_oxr->reference_space));
|
||||
}
|
||||
if (m_oxr->session != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroySession(m_oxr->session));
|
||||
}
|
||||
|
||||
m_oxr->session = XR_NULL_HANDLE;
|
||||
m_oxr->session_state = XR_SESSION_STATE_UNKNOWN;
|
||||
|
||||
m_context->getCustomFuncs().session_exit_fn(m_context->getCustomFuncs().session_exit_customdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* A system in OpenXR the combination of some sort of HMD plus controllers and whatever other
|
||||
* devices are managed through OpenXR. So this attempts to init the HMD and the other devices.
|
||||
*/
|
||||
void GHOST_XrSession::initSystem()
|
||||
{
|
||||
assert(m_context->getInstance() != XR_NULL_HANDLE);
|
||||
assert(m_oxr->system_id == XR_NULL_SYSTEM_ID);
|
||||
|
||||
XrSystemGetInfo system_info = {};
|
||||
system_info.type = XR_TYPE_SYSTEM_GET_INFO;
|
||||
system_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
|
||||
CHECK_XR(xrGetSystem(m_context->getInstance(), &system_info, &m_oxr->system_id),
|
||||
"Failed to get device information. Is a device plugged in?");
|
||||
}
|
||||
|
||||
/** \} */ /* Create, Initialize and Destruct */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State Management
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void create_reference_spaces(OpenXRSessionData *oxr, const GHOST_XrPose *base_pose)
|
||||
{
|
||||
XrReferenceSpaceCreateInfo create_info = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
|
||||
create_info.poseInReferenceSpace.orientation.w = 1.0f;
|
||||
|
||||
create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
|
||||
#if 0
|
||||
/* TODO
|
||||
*
|
||||
* Proper reference space set up is not supported yet. We simply hand OpenXR
|
||||
* the global space as reference space and apply its pose onto the active
|
||||
* camera matrix to get a basic viewing experience going. If there's no active
|
||||
* camera with stick to the world origin.
|
||||
*
|
||||
* Once we have proper reference space set up (i.e. a way to define origin, up-
|
||||
* direction and an initial view rotation perpendicular to the up-direction),
|
||||
* we can hand OpenXR a proper reference pose/space.
|
||||
*/
|
||||
create_info.poseInReferenceSpace.position.x = base_pose->position[0];
|
||||
create_info.poseInReferenceSpace.position.y = base_pose->position[1];
|
||||
create_info.poseInReferenceSpace.position.z = base_pose->position[2];
|
||||
create_info.poseInReferenceSpace.orientation.x = base_pose->orientation_quat[1];
|
||||
create_info.poseInReferenceSpace.orientation.y = base_pose->orientation_quat[2];
|
||||
create_info.poseInReferenceSpace.orientation.z = base_pose->orientation_quat[3];
|
||||
create_info.poseInReferenceSpace.orientation.w = base_pose->orientation_quat[0];
|
||||
#else
|
||||
(void)base_pose;
|
||||
#endif
|
||||
|
||||
CHECK_XR(xrCreateReferenceSpace(oxr->session, &create_info, &oxr->reference_space),
|
||||
"Failed to create reference space.");
|
||||
|
||||
create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
|
||||
CHECK_XR(xrCreateReferenceSpace(oxr->session, &create_info, &oxr->view_space),
|
||||
"Failed to create view reference space.");
|
||||
}
|
||||
|
||||
void GHOST_XrSession::start(const GHOST_XrSessionBeginInfo *begin_info)
|
||||
{
|
||||
assert(m_context->getInstance() != XR_NULL_HANDLE);
|
||||
assert(m_oxr->session == XR_NULL_HANDLE);
|
||||
if (m_context->getCustomFuncs().gpu_ctx_bind_fn == nullptr) {
|
||||
throw GHOST_XrException(
|
||||
"Invalid API usage: No way to bind graphics context to the XR session. Call "
|
||||
"GHOST_XrGraphicsContextBindFuncs() with valid parameters before starting the "
|
||||
"session (through GHOST_XrSessionStart()).");
|
||||
}
|
||||
|
||||
initSystem();
|
||||
|
||||
bindGraphicsContext();
|
||||
if (m_gpu_ctx == nullptr) {
|
||||
throw GHOST_XrException(
|
||||
"Invalid API usage: No graphics context returned through the callback set with "
|
||||
"GHOST_XrGraphicsContextBindFuncs(). This is required for session starting (through "
|
||||
"GHOST_XrSessionStart()).");
|
||||
}
|
||||
|
||||
std::string requirement_str;
|
||||
m_gpu_binding = GHOST_XrGraphicsBindingCreateFromType(m_context->getGraphicsBindingType());
|
||||
if (!m_gpu_binding->checkVersionRequirements(
|
||||
m_gpu_ctx, m_context->getInstance(), m_oxr->system_id, &requirement_str)) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Available graphics context version does not meet the following requirements: "
|
||||
<< requirement_str;
|
||||
throw GHOST_XrException(strstream.str().c_str());
|
||||
}
|
||||
m_gpu_binding->initFromGhostContext(m_gpu_ctx);
|
||||
|
||||
XrSessionCreateInfo create_info = {};
|
||||
create_info.type = XR_TYPE_SESSION_CREATE_INFO;
|
||||
create_info.systemId = m_oxr->system_id;
|
||||
create_info.next = &m_gpu_binding->oxr_binding;
|
||||
|
||||
CHECK_XR(xrCreateSession(m_context->getInstance(), &create_info, &m_oxr->session),
|
||||
"Failed to create VR session. The OpenXR runtime may have additional requirements for "
|
||||
"the graphics driver that are not met. Other causes are possible too however.\nTip: "
|
||||
"The --debug-xr command line option for Blender might allow the runtime to output "
|
||||
"detailed error information to the command line.");
|
||||
|
||||
prepareDrawing();
|
||||
create_reference_spaces(m_oxr.get(), &begin_info->base_pose);
|
||||
}
|
||||
|
||||
void GHOST_XrSession::requestEnd()
|
||||
{
|
||||
xrRequestExitSession(m_oxr->session);
|
||||
}
|
||||
|
||||
void GHOST_XrSession::end()
|
||||
{
|
||||
assert(m_oxr->session != XR_NULL_HANDLE);
|
||||
|
||||
CHECK_XR(xrEndSession(m_oxr->session), "Failed to cleanly end the VR session.");
|
||||
unbindGraphicsContext();
|
||||
m_draw_info = nullptr;
|
||||
}
|
||||
|
||||
GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
|
||||
const XrEventDataSessionStateChanged *lifecycle)
|
||||
{
|
||||
m_oxr->session_state = lifecycle->state;
|
||||
|
||||
/* Runtime may send events for apparently destroyed session. Our handle should be NULL then. */
|
||||
assert((m_oxr->session == XR_NULL_HANDLE) || (m_oxr->session == lifecycle->session));
|
||||
|
||||
switch (lifecycle->state) {
|
||||
case XR_SESSION_STATE_READY: {
|
||||
XrSessionBeginInfo begin_info = {XR_TYPE_SESSION_BEGIN_INFO};
|
||||
|
||||
begin_info.primaryViewConfigurationType = m_oxr->view_type;
|
||||
CHECK_XR(xrBeginSession(m_oxr->session, &begin_info),
|
||||
"Failed to cleanly begin the VR session.");
|
||||
break;
|
||||
}
|
||||
case XR_SESSION_STATE_STOPPING:
|
||||
/* Runtime will change state to STATE_EXITING, don't destruct session yet. */
|
||||
end();
|
||||
break;
|
||||
case XR_SESSION_STATE_EXITING:
|
||||
case XR_SESSION_STATE_LOSS_PENDING:
|
||||
return SESSION_DESTROY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SESSION_KEEP_ALIVE;
|
||||
}
|
||||
/** \} */ /* State Management */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Drawing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrSession::prepareDrawing()
|
||||
{
|
||||
std::vector<XrViewConfigurationView> view_configs;
|
||||
uint32_t view_count;
|
||||
|
||||
CHECK_XR(
|
||||
xrEnumerateViewConfigurationViews(
|
||||
m_context->getInstance(), m_oxr->system_id, m_oxr->view_type, 0, &view_count, nullptr),
|
||||
"Failed to get count of view configurations.");
|
||||
view_configs.resize(view_count, {XR_TYPE_VIEW_CONFIGURATION_VIEW});
|
||||
CHECK_XR(xrEnumerateViewConfigurationViews(m_context->getInstance(),
|
||||
m_oxr->system_id,
|
||||
m_oxr->view_type,
|
||||
view_configs.size(),
|
||||
&view_count,
|
||||
view_configs.data()),
|
||||
"Failed to get count of view configurations.");
|
||||
|
||||
for (const XrViewConfigurationView &view_config : view_configs) {
|
||||
m_oxr->swapchains.push_back(std::unique_ptr<GHOST_XrSwapchain>(
|
||||
new GHOST_XrSwapchain(*m_gpu_binding, m_oxr->session, view_config)));
|
||||
}
|
||||
|
||||
m_oxr->views.resize(view_count, {XR_TYPE_VIEW});
|
||||
|
||||
m_draw_info = std::unique_ptr<GHOST_XrDrawInfo>(new GHOST_XrDrawInfo());
|
||||
}
|
||||
|
||||
void GHOST_XrSession::beginFrameDrawing()
|
||||
{
|
||||
XrFrameWaitInfo wait_info = {XR_TYPE_FRAME_WAIT_INFO};
|
||||
XrFrameBeginInfo begin_info = {XR_TYPE_FRAME_BEGIN_INFO};
|
||||
XrFrameState frame_state = {XR_TYPE_FRAME_STATE};
|
||||
|
||||
/* TODO Blocking call. Drawing should run on a separate thread to avoid interferences. */
|
||||
CHECK_XR(xrWaitFrame(m_oxr->session, &wait_info, &frame_state),
|
||||
"Failed to synchronize frame rates between Blender and the device.");
|
||||
|
||||
CHECK_XR(xrBeginFrame(m_oxr->session, &begin_info),
|
||||
"Failed to submit frame rendering start state.");
|
||||
|
||||
m_draw_info->frame_state = frame_state;
|
||||
|
||||
if (m_context->isDebugTimeMode()) {
|
||||
m_draw_info->frame_begin_time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
static void print_debug_timings(GHOST_XrDrawInfo *draw_info)
|
||||
{
|
||||
/** Render time of last 8 frames (in ms) to calculate an average. */
|
||||
std::chrono::duration<double, std::milli> duration = std::chrono::high_resolution_clock::now() -
|
||||
draw_info->frame_begin_time;
|
||||
const double duration_ms = duration.count();
|
||||
const int avg_frame_count = 8;
|
||||
double avg_ms_tot = 0.0;
|
||||
|
||||
if (draw_info->last_frame_times.size() >= avg_frame_count) {
|
||||
draw_info->last_frame_times.pop_front();
|
||||
assert(draw_info->last_frame_times.size() == avg_frame_count - 1);
|
||||
}
|
||||
draw_info->last_frame_times.push_back(duration_ms);
|
||||
for (double ms_iter : draw_info->last_frame_times) {
|
||||
avg_ms_tot += ms_iter;
|
||||
}
|
||||
|
||||
printf("VR frame render time: %.0fms - %.2f FPS (%.2f FPS 8 frames average)\n",
|
||||
duration_ms,
|
||||
1000.0 / duration_ms,
|
||||
1000.0 / (avg_ms_tot / draw_info->last_frame_times.size()));
|
||||
}
|
||||
|
||||
void GHOST_XrSession::endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> *layers)
|
||||
{
|
||||
XrFrameEndInfo end_info = {XR_TYPE_FRAME_END_INFO};
|
||||
|
||||
end_info.displayTime = m_draw_info->frame_state.predictedDisplayTime;
|
||||
end_info.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||
end_info.layerCount = layers->size();
|
||||
end_info.layers = layers->data();
|
||||
|
||||
CHECK_XR(xrEndFrame(m_oxr->session, &end_info), "Failed to submit rendered frame.");
|
||||
|
||||
if (m_context->isDebugTimeMode()) {
|
||||
print_debug_timings(m_draw_info.get());
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrSession::draw(void *draw_customdata)
|
||||
{
|
||||
std::vector<XrCompositionLayerProjectionView>
|
||||
projection_layer_views; /* Keep alive until xrEndFrame() call! */
|
||||
XrCompositionLayerProjection proj_layer;
|
||||
std::vector<XrCompositionLayerBaseHeader *> layers;
|
||||
|
||||
beginFrameDrawing();
|
||||
|
||||
if (m_draw_info->frame_state.shouldRender) {
|
||||
proj_layer = drawLayer(projection_layer_views, draw_customdata);
|
||||
layers.push_back(reinterpret_cast<XrCompositionLayerBaseHeader *>(&proj_layer));
|
||||
}
|
||||
|
||||
endFrameDrawing(&layers);
|
||||
}
|
||||
|
||||
static void copy_openxr_pose_to_ghost_pose(const XrPosef &oxr_pose, GHOST_XrPose &r_ghost_pose)
|
||||
{
|
||||
/* Set and convert to Blender coodinate space. */
|
||||
r_ghost_pose.position[0] = oxr_pose.position.x;
|
||||
r_ghost_pose.position[1] = oxr_pose.position.y;
|
||||
r_ghost_pose.position[2] = oxr_pose.position.z;
|
||||
r_ghost_pose.orientation_quat[0] = oxr_pose.orientation.w;
|
||||
r_ghost_pose.orientation_quat[1] = oxr_pose.orientation.x;
|
||||
r_ghost_pose.orientation_quat[2] = oxr_pose.orientation.y;
|
||||
r_ghost_pose.orientation_quat[3] = oxr_pose.orientation.z;
|
||||
}
|
||||
|
||||
static void ghost_xr_draw_view_info_from_view(const XrView &view, GHOST_XrDrawViewInfo &r_info)
|
||||
{
|
||||
/* Set and convert to Blender coodinate space. */
|
||||
copy_openxr_pose_to_ghost_pose(view.pose, r_info.eye_pose);
|
||||
|
||||
r_info.fov.angle_left = view.fov.angleLeft;
|
||||
r_info.fov.angle_right = view.fov.angleRight;
|
||||
r_info.fov.angle_up = view.fov.angleUp;
|
||||
r_info.fov.angle_down = view.fov.angleDown;
|
||||
}
|
||||
|
||||
static bool ghost_xr_draw_view_expects_srgb_buffer(const GHOST_XrContext *context)
|
||||
{
|
||||
/* Monado seems to be faulty and doesn't do OETF transform correctly. So expect a SRGB buffer to
|
||||
* compensate. You get way too dark rendering without this, it's pretty obvious (even in the
|
||||
* default startup scene). */
|
||||
return (context->getOpenXRRuntimeID() == OPENXR_RUNTIME_MONADO);
|
||||
}
|
||||
|
||||
void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
|
||||
XrCompositionLayerProjectionView &r_proj_layer_view,
|
||||
XrSpaceLocation &view_location,
|
||||
XrView &view,
|
||||
void *draw_customdata)
|
||||
{
|
||||
XrSwapchainImageBaseHeader *swapchain_image = swapchain.acquireDrawableSwapchainImage();
|
||||
GHOST_XrDrawViewInfo draw_view_info = {};
|
||||
|
||||
r_proj_layer_view.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
||||
r_proj_layer_view.pose = view.pose;
|
||||
r_proj_layer_view.fov = view.fov;
|
||||
swapchain.updateCompositionLayerProjectViewSubImage(r_proj_layer_view.subImage);
|
||||
|
||||
draw_view_info.expects_srgb_buffer = ghost_xr_draw_view_expects_srgb_buffer(m_context);
|
||||
draw_view_info.ofsx = r_proj_layer_view.subImage.imageRect.offset.x;
|
||||
draw_view_info.ofsy = r_proj_layer_view.subImage.imageRect.offset.y;
|
||||
draw_view_info.width = r_proj_layer_view.subImage.imageRect.extent.width;
|
||||
draw_view_info.height = r_proj_layer_view.subImage.imageRect.extent.height;
|
||||
copy_openxr_pose_to_ghost_pose(view_location.pose, draw_view_info.local_pose);
|
||||
ghost_xr_draw_view_info_from_view(view, draw_view_info);
|
||||
|
||||
/* Draw! */
|
||||
m_context->getCustomFuncs().draw_view_fn(&draw_view_info, draw_customdata);
|
||||
m_gpu_binding->submitToSwapchainImage(swapchain_image, &draw_view_info);
|
||||
|
||||
swapchain.releaseImage();
|
||||
}
|
||||
|
||||
XrCompositionLayerProjection GHOST_XrSession::drawLayer(
|
||||
std::vector<XrCompositionLayerProjectionView> &r_proj_layer_views, void *draw_customdata)
|
||||
{
|
||||
XrViewLocateInfo viewloc_info = {XR_TYPE_VIEW_LOCATE_INFO};
|
||||
XrViewState view_state = {XR_TYPE_VIEW_STATE};
|
||||
XrCompositionLayerProjection layer = {XR_TYPE_COMPOSITION_LAYER_PROJECTION};
|
||||
XrSpaceLocation view_location{XR_TYPE_SPACE_LOCATION};
|
||||
uint32_t view_count;
|
||||
|
||||
viewloc_info.viewConfigurationType = m_oxr->view_type;
|
||||
viewloc_info.displayTime = m_draw_info->frame_state.predictedDisplayTime;
|
||||
viewloc_info.space = m_oxr->reference_space;
|
||||
|
||||
CHECK_XR(xrLocateViews(m_oxr->session,
|
||||
&viewloc_info,
|
||||
&view_state,
|
||||
m_oxr->views.size(),
|
||||
&view_count,
|
||||
m_oxr->views.data()),
|
||||
"Failed to query frame view and projection state.");
|
||||
assert(m_oxr->swapchains.size() == view_count);
|
||||
|
||||
CHECK_XR(
|
||||
xrLocateSpace(
|
||||
m_oxr->view_space, m_oxr->reference_space, viewloc_info.displayTime, &view_location),
|
||||
"Failed to query frame view space");
|
||||
|
||||
r_proj_layer_views.resize(view_count);
|
||||
|
||||
for (uint32_t view_idx = 0; view_idx < view_count; view_idx++) {
|
||||
drawView(*m_oxr->swapchains[view_idx],
|
||||
r_proj_layer_views[view_idx],
|
||||
view_location,
|
||||
m_oxr->views[view_idx],
|
||||
draw_customdata);
|
||||
}
|
||||
|
||||
layer.space = m_oxr->reference_space;
|
||||
layer.viewCount = r_proj_layer_views.size();
|
||||
layer.views = r_proj_layer_views.data();
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
/** \} */ /* Drawing */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State Queries
|
||||
*
|
||||
* \{ */
|
||||
|
||||
bool GHOST_XrSession::isRunning() const
|
||||
{
|
||||
if (m_oxr->session == XR_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
switch (m_oxr->session_state) {
|
||||
case XR_SESSION_STATE_READY:
|
||||
case XR_SESSION_STATE_SYNCHRONIZED:
|
||||
case XR_SESSION_STATE_VISIBLE:
|
||||
case XR_SESSION_STATE_FOCUSED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* State Queries */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Graphics Context Injection
|
||||
*
|
||||
* Sessions need access to Ghost graphics context information. Additionally, this API allows
|
||||
* creating contexts on the fly (created on start, destructed on end). For this, callbacks to bind
|
||||
* (potentially create) and unbind (potentially destruct) a Ghost graphics context have to be set,
|
||||
* which will be called on session start and end respectively.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrSession::bindGraphicsContext()
|
||||
{
|
||||
const GHOST_XrCustomFuncs &custom_funcs = m_context->getCustomFuncs();
|
||||
assert(custom_funcs.gpu_ctx_bind_fn);
|
||||
m_gpu_ctx = static_cast<GHOST_Context *>(
|
||||
custom_funcs.gpu_ctx_bind_fn(m_context->getGraphicsBindingType()));
|
||||
}
|
||||
|
||||
void GHOST_XrSession::unbindGraphicsContext()
|
||||
{
|
||||
const GHOST_XrCustomFuncs &custom_funcs = m_context->getCustomFuncs();
|
||||
if (custom_funcs.gpu_ctx_unbind_fn) {
|
||||
custom_funcs.gpu_ctx_unbind_fn(m_context->getGraphicsBindingType(),
|
||||
(GHOST_ContextHandle)m_gpu_ctx);
|
||||
}
|
||||
m_gpu_ctx = nullptr;
|
||||
}
|
||||
|
||||
/** \} */ /* Graphics Context Injection */
|
84
intern/ghost/intern/GHOST_XrSession.h
Normal file
84
intern/ghost/intern/GHOST_XrSession.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XRSESSION_H__
|
||||
#define __GHOST_XRSESSION_H__
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class GHOST_XrContext;
|
||||
class GHOST_XrSwapchain;
|
||||
struct OpenXRSessionData;
|
||||
struct GHOST_XrDrawInfo;
|
||||
|
||||
class GHOST_XrSession {
|
||||
public:
|
||||
enum LifeExpectancy {
|
||||
SESSION_KEEP_ALIVE,
|
||||
SESSION_DESTROY,
|
||||
};
|
||||
|
||||
GHOST_XrSession(GHOST_XrContext *xr_context);
|
||||
~GHOST_XrSession();
|
||||
|
||||
void start(const GHOST_XrSessionBeginInfo *begin_info);
|
||||
void requestEnd();
|
||||
|
||||
LifeExpectancy handleStateChangeEvent(const XrEventDataSessionStateChanged *lifecycle);
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
void unbindGraphicsContext(); /* Public so context can ensure it's unbound as needed. */
|
||||
|
||||
void draw(void *draw_customdata);
|
||||
|
||||
private:
|
||||
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
|
||||
* custom callbacks set before session start. */
|
||||
class GHOST_XrContext *m_context;
|
||||
|
||||
std::unique_ptr<OpenXRSessionData> m_oxr; /* Could use stack, but PImpl is preferable. */
|
||||
|
||||
/** Active Ghost graphic context. Owned by Blender, not GHOST. */
|
||||
class GHOST_Context *m_gpu_ctx = nullptr;
|
||||
std::unique_ptr<class GHOST_IXrGraphicsBinding> m_gpu_binding;
|
||||
|
||||
/** Rendering information. Set when drawing starts. */
|
||||
std::unique_ptr<GHOST_XrDrawInfo> m_draw_info;
|
||||
|
||||
void initSystem();
|
||||
void end();
|
||||
|
||||
void bindGraphicsContext();
|
||||
|
||||
void prepareDrawing();
|
||||
XrCompositionLayerProjection drawLayer(
|
||||
std::vector<XrCompositionLayerProjectionView> &r_proj_layer_views, void *draw_customdata);
|
||||
void drawView(GHOST_XrSwapchain &swapchain,
|
||||
XrCompositionLayerProjectionView &r_proj_layer_view,
|
||||
XrSpaceLocation &view_location,
|
||||
XrView &view,
|
||||
void *draw_customdata);
|
||||
void beginFrameDrawing();
|
||||
void endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> *layers);
|
||||
};
|
||||
|
||||
#endif /* GHOST_XRSESSION_H__ */
|
131
intern/ghost/intern/GHOST_XrSwapchain.cpp
Normal file
131
intern/ghost/intern/GHOST_XrSwapchain.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GHOST_IXrGraphicsBinding.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_XrSession.h"
|
||||
|
||||
#include "GHOST_XrSwapchain.h"
|
||||
|
||||
struct OpenXRSwapchainData {
|
||||
using ImageVec = std::vector<XrSwapchainImageBaseHeader *>;
|
||||
|
||||
XrSwapchain swapchain = XR_NULL_HANDLE;
|
||||
ImageVec swapchain_images;
|
||||
};
|
||||
|
||||
static OpenXRSwapchainData::ImageVec swapchain_images_create(XrSwapchain swapchain,
|
||||
GHOST_IXrGraphicsBinding &gpu_binding)
|
||||
{
|
||||
std::vector<XrSwapchainImageBaseHeader *> images;
|
||||
uint32_t image_count;
|
||||
|
||||
CHECK_XR(xrEnumerateSwapchainImages(swapchain, 0, &image_count, nullptr),
|
||||
"Failed to get count of swapchain images to create for the VR session.");
|
||||
images = gpu_binding.createSwapchainImages(image_count);
|
||||
CHECK_XR(xrEnumerateSwapchainImages(swapchain, images.size(), &image_count, images[0]),
|
||||
"Failed to create swapchain images for the VR session.");
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
GHOST_XrSwapchain::GHOST_XrSwapchain(GHOST_IXrGraphicsBinding &gpu_binding,
|
||||
const XrSession &session,
|
||||
const XrViewConfigurationView &view_config)
|
||||
: m_oxr(new OpenXRSwapchainData())
|
||||
{
|
||||
XrSwapchainCreateInfo create_info = {XR_TYPE_SWAPCHAIN_CREATE_INFO};
|
||||
uint32_t format_count = 0;
|
||||
int64_t chosen_format;
|
||||
|
||||
CHECK_XR(xrEnumerateSwapchainFormats(session, 0, &format_count, nullptr),
|
||||
"Failed to get count of swapchain image formats.");
|
||||
std::vector<int64_t> swapchain_formats(format_count);
|
||||
CHECK_XR(xrEnumerateSwapchainFormats(
|
||||
session, swapchain_formats.size(), &format_count, swapchain_formats.data()),
|
||||
"Failed to get swapchain image formats.");
|
||||
assert(swapchain_formats.size() == format_count);
|
||||
|
||||
if (!gpu_binding.chooseSwapchainFormat(swapchain_formats, &chosen_format)) {
|
||||
throw GHOST_XrException(
|
||||
"Error: No format matching OpenXR runtime supported swapchain formats found.");
|
||||
}
|
||||
|
||||
create_info.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
|
||||
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
create_info.format = chosen_format;
|
||||
create_info.sampleCount = view_config.recommendedSwapchainSampleCount;
|
||||
create_info.width = view_config.recommendedImageRectWidth;
|
||||
create_info.height = view_config.recommendedImageRectHeight;
|
||||
create_info.faceCount = 1;
|
||||
create_info.arraySize = 1;
|
||||
create_info.mipCount = 1;
|
||||
|
||||
CHECK_XR(xrCreateSwapchain(session, &create_info, &m_oxr->swapchain),
|
||||
"Failed to create OpenXR swapchain.");
|
||||
|
||||
m_image_width = create_info.width;
|
||||
m_image_height = create_info.height;
|
||||
|
||||
m_oxr->swapchain_images = swapchain_images_create(m_oxr->swapchain, gpu_binding);
|
||||
}
|
||||
|
||||
GHOST_XrSwapchain::~GHOST_XrSwapchain()
|
||||
{
|
||||
if (m_oxr->swapchain != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroySwapchain(m_oxr->swapchain));
|
||||
}
|
||||
}
|
||||
|
||||
XrSwapchainImageBaseHeader *GHOST_XrSwapchain::acquireDrawableSwapchainImage()
|
||||
|
||||
{
|
||||
XrSwapchainImageAcquireInfo acquire_info = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO};
|
||||
XrSwapchainImageWaitInfo wait_info = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO};
|
||||
uint32_t image_idx;
|
||||
|
||||
CHECK_XR(xrAcquireSwapchainImage(m_oxr->swapchain, &acquire_info, &image_idx),
|
||||
"Failed to acquire swapchain image for the VR session.");
|
||||
wait_info.timeout = XR_INFINITE_DURATION;
|
||||
CHECK_XR(xrWaitSwapchainImage(m_oxr->swapchain, &wait_info),
|
||||
"Failed to acquire swapchain image for the VR session.");
|
||||
|
||||
return m_oxr->swapchain_images[image_idx];
|
||||
}
|
||||
|
||||
void GHOST_XrSwapchain::updateCompositionLayerProjectViewSubImage(XrSwapchainSubImage &r_sub_image)
|
||||
{
|
||||
r_sub_image.swapchain = m_oxr->swapchain;
|
||||
r_sub_image.imageRect.offset = {0, 0};
|
||||
r_sub_image.imageRect.extent = {m_image_width, m_image_height};
|
||||
}
|
||||
|
||||
void GHOST_XrSwapchain::releaseImage()
|
||||
{
|
||||
XrSwapchainImageReleaseInfo release_info = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO};
|
||||
|
||||
CHECK_XR(xrReleaseSwapchainImage(m_oxr->swapchain, &release_info),
|
||||
"Failed to release swapchain image used to submit VR session frame.");
|
||||
}
|
45
intern/ghost/intern/GHOST_XrSwapchain.h
Normal file
45
intern/ghost/intern/GHOST_XrSwapchain.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XRSWAPCHAIN_H__
|
||||
#define __GHOST_XRSWAPCHAIN_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct OpenXRSwapchainData;
|
||||
|
||||
class GHOST_XrSwapchain {
|
||||
public:
|
||||
GHOST_XrSwapchain(GHOST_IXrGraphicsBinding &gpu_binding,
|
||||
const XrSession &session,
|
||||
const XrViewConfigurationView &view_config);
|
||||
~GHOST_XrSwapchain();
|
||||
|
||||
XrSwapchainImageBaseHeader *acquireDrawableSwapchainImage();
|
||||
void releaseImage();
|
||||
|
||||
void updateCompositionLayerProjectViewSubImage(XrSwapchainSubImage &r_sub_image);
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenXRSwapchainData> m_oxr; /* Could use stack, but PImpl is preferable. */
|
||||
int32_t m_image_width, m_image_height;
|
||||
};
|
||||
|
||||
#endif // GHOST_XRSWAPCHAIN_H
|
50
intern/ghost/intern/GHOST_Xr_intern.h
Normal file
50
intern/ghost/intern/GHOST_Xr_intern.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XR_INTERN_H__
|
||||
#define __GHOST_XR_INTERN_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GHOST_Xr_openxr_includes.h"
|
||||
|
||||
#define CHECK_XR(call, error_msg) \
|
||||
{ \
|
||||
XrResult _res = call; \
|
||||
if (XR_FAILED(_res)) { \
|
||||
throw GHOST_XrException(error_msg, _res); \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
/**
|
||||
* Variation of CHECK_XR() that doesn't throw, but asserts for success. Especially useful for
|
||||
* destructors, which shouldn't throw.
|
||||
*/
|
||||
#define CHECK_XR_ASSERT(call) \
|
||||
{ \
|
||||
XrResult _res = call; \
|
||||
assert(_res == XR_SUCCESS); \
|
||||
(void)_res; \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
#endif /* __GHOST_XR_INTERN_H__ */
|
52
intern/ghost/intern/GHOST_Xr_openxr_includes.h
Normal file
52
intern/ghost/intern/GHOST_Xr_openxr_includes.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*
|
||||
* \note This is taken mostly from the OpenXR SDK, but with modified D3D versions (e.g. d3d11_4.h
|
||||
* -> d3d11.h). Take care for that when updating, we don't want to require newest Win SDKs to be
|
||||
* installed.
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_XR_SYSTEM_INCLUDES_H__
|
||||
#define __GHOST_XR_SYSTEM_INCLUDES_H__
|
||||
|
||||
/* Platform headers */
|
||||
#ifdef XR_USE_PLATFORM_WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Graphics headers */
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D10
|
||||
# include <d3d10_1.h>
|
||||
#endif
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||
# include <d3d11.h>
|
||||
#endif
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D12
|
||||
# include <d3d12.h>
|
||||
#endif
|
||||
#ifdef WITH_X11
|
||||
# include <GL/glxew.h>
|
||||
#endif
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#endif /* __GHOST_XR_SYSTEM_INCLUDES_H__ */
|
14
release/windows/batch/blender_oculus.cmd
Normal file
14
release/windows/batch/blender_oculus.cmd
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
|
||||
REM Helper setting hints to get the OpenXR preview support enabled for Oculus.
|
||||
REM Of course this is not meant as a permanent solution. Oculus will likely provide a better setup at some point.
|
||||
|
||||
echo Starting Blender with Oculus OpenXR support. This assumes the Oculus runtime
|
||||
echo is installed in the default location. If this is not the case, please adjust
|
||||
echo the path inside oculus.json.
|
||||
echo.
|
||||
echo Note that OpenXR support in Oculus is considered a preview. Use with care!
|
||||
echo.
|
||||
pause
|
||||
set XR_RUNTIME_JSON=%~dp0oculus.json
|
||||
blender
|
9
release/windows/batch/oculus.json
Normal file
9
release/windows/batch/oculus.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"file_format_version": "1.0.0",
|
||||
"runtime":
|
||||
{
|
||||
"api_version": "1.0",
|
||||
"name": "Oculus OpenXR",
|
||||
"library_path": "c:\\Program Files\\Oculus\\Support\\oculus-runtime\\LibOVRRT64_1.dll"
|
||||
}
|
||||
}
|
@@ -90,6 +90,7 @@ set(SRC_DNA_INC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_workspace_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_world_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_xr_types.h
|
||||
)
|
||||
|
||||
add_subdirectory(datatoc)
|
||||
|
@@ -153,6 +153,8 @@ enum {
|
||||
G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...)*/
|
||||
G_DEBUG_GPU_SHADERS = (1 << 18), /* GLSL shaders */
|
||||
G_DEBUG_GPU_FORCE_WORKAROUNDS = (1 << 19), /* force gpu workarounds bypassing detections. */
|
||||
G_DEBUG_XR = (1 << 20), /* XR/OpenXR messages */
|
||||
G_DEBUG_XR_TIME = (1 << 21), /* XR/OpenXR timing messages */
|
||||
|
||||
G_DEBUG_GHOST = (1 << 20), /* Debug GHOST module. */
|
||||
};
|
||||
|
@@ -667,6 +667,10 @@ if(WITH_TBB)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
# # Warnings as errors, this is too strict!
|
||||
# if(MSVC)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
|
||||
|
@@ -2680,7 +2680,8 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the global transformation \a mat to the \a ob using a relative parent space if supplied.
|
||||
* Applies the global transformation \a mat to the \a ob using a relative parent space if
|
||||
* supplied.
|
||||
*
|
||||
* \param mat: the global transformation mat that the object should be set object to.
|
||||
* \param parent: the parent space in which this object will be set relative to
|
||||
@@ -3183,7 +3184,8 @@ typedef struct ObTfmBack {
|
||||
float obmat[4][4];
|
||||
/** inverse result of parent, so that object doesn't 'stick' to parent. */
|
||||
float parentinv[4][4];
|
||||
/** inverse result of constraints. doesn't include effect of parent or object local transform. */
|
||||
/** inverse result of constraints. doesn't include effect of parent or object local transform.
|
||||
*/
|
||||
float constinv[4][4];
|
||||
/** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */
|
||||
float imat[4][4];
|
||||
|
@@ -636,6 +636,13 @@ void perspective_m4(float mat[4][4],
|
||||
const float top,
|
||||
const float nearClip,
|
||||
const float farClip);
|
||||
void perspective_m4_fov(float mat[4][4],
|
||||
const float angle_left,
|
||||
const float angle_right,
|
||||
const float angle_up,
|
||||
const float angle_down,
|
||||
const float nearClip,
|
||||
const float farClip);
|
||||
void orthographic_m4(float mat[4][4],
|
||||
const float left,
|
||||
const float right,
|
||||
|
@@ -4709,6 +4709,25 @@ void perspective_m4(float mat[4][4],
|
||||
mat[3][3] = 0.0f;
|
||||
}
|
||||
|
||||
void perspective_m4_fov(float mat[4][4],
|
||||
const float angle_left,
|
||||
const float angle_right,
|
||||
const float angle_up,
|
||||
const float angle_down,
|
||||
const float nearClip,
|
||||
const float farClip)
|
||||
{
|
||||
const float tan_angle_left = tanf(angle_left);
|
||||
const float tan_angle_right = tanf(angle_right);
|
||||
const float tan_angle_bottom = tanf(angle_up);
|
||||
const float tan_angle_top = tanf(angle_down);
|
||||
|
||||
perspective_m4(
|
||||
mat, tan_angle_left, tan_angle_right, tan_angle_top, tan_angle_bottom, nearClip, farClip);
|
||||
mat[0][0] /= nearClip;
|
||||
mat[1][1] /= nearClip;
|
||||
}
|
||||
|
||||
/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
|
||||
* (used to jitter the view) */
|
||||
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
|
||||
|
@@ -7109,6 +7109,7 @@ static void direct_link_region(FileData *fd, ARegion *region, int spacetype)
|
||||
rv3d->smooth_timer = NULL;
|
||||
|
||||
rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING);
|
||||
rv3d->runtime_viewlock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7199,7 +7200,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
|
||||
direct_link_gpencil(fd, v3d->gpd);
|
||||
}
|
||||
v3d->localvd = newdataadr(fd, v3d->localvd);
|
||||
|
||||
/* Runtime data */
|
||||
v3d->runtime.properties_storage = NULL;
|
||||
v3d->runtime.flag = 0;
|
||||
|
||||
/* render can be quite heavy, set to solid on load */
|
||||
if (v3d->shading.type == OB_RENDER) {
|
||||
@@ -7579,6 +7583,23 @@ static bool direct_link_area_map(FileData *fd, ScrAreaMap *area_map)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-data
|
||||
* \{ */
|
||||
|
||||
static void direct_link_wm_xr_data(FileData *fd, wmXrData *xr_data)
|
||||
{
|
||||
direct_link_view3dshading(fd, &xr_data->session_settings.shading);
|
||||
}
|
||||
|
||||
static void lib_link_wm_xr_data(FileData *fd, ID *parent_id, wmXrData *xr_data)
|
||||
{
|
||||
xr_data->session_settings.base_pose_object = newlibadr(
|
||||
fd, parent_id->lib, xr_data->session_settings.base_pose_object);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Read ID: Window Manager
|
||||
* \{ */
|
||||
@@ -7632,6 +7653,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
|
||||
}
|
||||
}
|
||||
|
||||
direct_link_wm_xr_data(fd, &wm->xr);
|
||||
|
||||
BLI_listbase_clear(&wm->timers);
|
||||
BLI_listbase_clear(&wm->operators);
|
||||
BLI_listbase_clear(&wm->paintcursors);
|
||||
@@ -7646,6 +7669,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
|
||||
|
||||
wm->message_bus = NULL;
|
||||
|
||||
wm->xr.runtime = NULL;
|
||||
|
||||
BLI_listbase_clear(&wm->jobs);
|
||||
BLI_listbase_clear(&wm->drags);
|
||||
|
||||
@@ -7669,6 +7694,8 @@ static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowMa
|
||||
for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
|
||||
lib_link_area(fd, &wm->id, area);
|
||||
}
|
||||
|
||||
lib_link_wm_xr_data(fd, &wm->id, &wm->xr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7833,6 +7860,12 @@ static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newma
|
||||
FOREACH_MAIN_ID_END;
|
||||
}
|
||||
|
||||
static void lib_link_wm_xr_data_restore(struct IDNameLib_Map *id_map, wmXrData *xr_data)
|
||||
{
|
||||
xr_data->session_settings.base_pose_object = restore_pointer_by_name(
|
||||
id_map, (ID *)xr_data->session_settings.base_pose_object, USER_REAL);
|
||||
}
|
||||
|
||||
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
|
||||
@@ -8163,6 +8196,8 @@ void blo_lib_link_restore(Main *oldmain,
|
||||
BLI_assert(win->screen == NULL);
|
||||
}
|
||||
|
||||
lib_link_wm_xr_data_restore(id_map, &curwm->xr);
|
||||
|
||||
/* Restore all ID pointers in Main database itself
|
||||
* (especially IDProperties might point to some word-space of other 'weirdly unchanged' ID
|
||||
* pointers, see T69146).
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_camera_types.h"
|
||||
@@ -4845,5 +4847,21 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DNA_struct_find(fd->filesdna, "XrSessionSettings")) {
|
||||
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
|
||||
const View3D *v3d_default = DNA_struct_default_get(View3D);
|
||||
|
||||
wm->xr.session_settings.shading = v3d_default->shading;
|
||||
/* Don't rotate light with the viewer by default, make it fixed. */
|
||||
wm->xr.session_settings.shading.flag |= V3D_SHADING_WORLD_ORIENTATION;
|
||||
wm->xr.session_settings.draw_flags = (V3D_OFSDRAW_SHOW_GRIDFLOOR |
|
||||
V3D_OFSDRAW_SHOW_ANNOTATION);
|
||||
wm->xr.session_settings.clip_start = v3d_default->clip_start;
|
||||
wm->xr.session_settings.clip_end = v3d_default->clip_end;
|
||||
|
||||
wm->xr.session_settings.flag = XR_SESSION_USE_POSITION_TRACKING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2805,6 +2805,11 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
|
||||
}
|
||||
}
|
||||
|
||||
static void write_wm_xr_data(WriteData *wd, wmXrData *xr_data)
|
||||
{
|
||||
write_view3dshading(wd, &xr_data->session_settings.shading);
|
||||
}
|
||||
|
||||
static void write_region(WriteData *wd, ARegion *region, int spacetype)
|
||||
{
|
||||
writestruct(wd, DATA, ARegion, 1, region);
|
||||
@@ -3051,6 +3056,7 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
|
||||
{
|
||||
writestruct(wd, ID_WM, wmWindowManager, 1, wm);
|
||||
write_iddata(wd, &wm->id);
|
||||
write_wm_xr_data(wd, &wm->xr);
|
||||
|
||||
for (wmWindow *win = wm->windows.first; win; win = win->next) {
|
||||
#ifndef WITH_GLOBAL_AREA_WRITING
|
||||
|
@@ -390,4 +390,8 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -93,6 +93,7 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
|
||||
struct RenderEngineType *engine_type,
|
||||
struct ARegion *region,
|
||||
struct View3D *v3d,
|
||||
const bool is_image_render,
|
||||
const bool draw_background,
|
||||
const bool do_color_management,
|
||||
struct GPUOffScreen *ofs,
|
||||
@@ -139,6 +140,14 @@ void DRW_opengl_context_destroy(void);
|
||||
void DRW_opengl_context_enable(void);
|
||||
void DRW_opengl_context_disable(void);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* XXX see comment on DRW_xr_opengl_context_get() */
|
||||
void *DRW_xr_opengl_context_get(void);
|
||||
void *DRW_xr_gpu_context_get(void);
|
||||
void DRW_xr_drawing_begin(void);
|
||||
void DRW_xr_drawing_end(void);
|
||||
#endif
|
||||
|
||||
/* For garbage collection */
|
||||
void DRW_cache_free_old_batches(struct Main *bmain);
|
||||
|
||||
|
@@ -562,7 +562,7 @@ static void drw_viewport_var_init(void)
|
||||
DRW_view_camtexco_set(DST.view_default, rv3d->viewcamtexcofac);
|
||||
|
||||
if (DST.draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) {
|
||||
int plane_len = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
|
||||
int plane_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6;
|
||||
DRW_view_clip_planes_set(DST.view_default, rv3d->clip, plane_len);
|
||||
}
|
||||
|
||||
@@ -1554,6 +1554,7 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
|
||||
RenderEngineType *engine_type,
|
||||
ARegion *region,
|
||||
View3D *v3d,
|
||||
const bool is_image_render,
|
||||
const bool draw_background,
|
||||
const bool do_color_management,
|
||||
GPUOffScreen *ofs,
|
||||
@@ -1569,7 +1570,7 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
|
||||
|
||||
/* Reset before using it. */
|
||||
drw_state_prepare_clean_for_draw(&DST);
|
||||
DST.options.is_image_render = true;
|
||||
DST.options.is_image_render = is_image_render;
|
||||
DST.options.do_color_management = do_color_management;
|
||||
DST.options.draw_background = draw_background;
|
||||
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, render_viewport, NULL);
|
||||
@@ -2829,4 +2830,39 @@ void DRW_gpu_render_context_disable(void *UNUSED(re_gpu_context))
|
||||
GPU_context_active_set(NULL);
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
/* XXX
|
||||
* There should really be no such getter, but for VR we currently can't easily avoid it. OpenXR
|
||||
* needs some low level info for the OpenGL context that will be used for submitting the
|
||||
* final framebuffer. VR could in theory create its own context, but that would mean we have to
|
||||
* switch to it just to submit the final frame, which has notable performance impact.
|
||||
*
|
||||
* We could "inject" a context through DRW_opengl_render_context_enable(), but that would have to
|
||||
* work from the main thread, which is tricky to get working too. The preferable solution would be
|
||||
* using a separate thread for VR drawing where a single context can stay active. */
|
||||
void *DRW_xr_opengl_context_get(void)
|
||||
{
|
||||
return DST.gl_context;
|
||||
}
|
||||
|
||||
/* XXX See comment on DRW_xr_opengl_context_get(). */
|
||||
void *DRW_xr_gpu_context_get(void)
|
||||
{
|
||||
return DST.gpu_context;
|
||||
}
|
||||
|
||||
/* XXX See comment on DRW_xr_opengl_context_get(). */
|
||||
void DRW_xr_drawing_begin(void)
|
||||
{
|
||||
BLI_ticket_mutex_lock(DST.gl_context_mutex);
|
||||
}
|
||||
|
||||
/* XXX See comment on DRW_xr_opengl_context_get(). */
|
||||
void DRW_xr_drawing_end(void)
|
||||
{
|
||||
BLI_ticket_mutex_unlock(DST.gl_context_mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
/** \} */
|
||||
|
@@ -561,6 +561,9 @@ struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
|
||||
bool ED_view3d_context_user_region(struct bContext *C,
|
||||
struct View3D **r_v3d,
|
||||
struct ARegion **r_ar);
|
||||
bool ED_view3d_area_user_region(const struct ScrArea *sa,
|
||||
const struct View3D *v3d,
|
||||
struct ARegion **r_ar);
|
||||
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
|
||||
|
||||
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d);
|
||||
@@ -584,7 +587,8 @@ void ED_draw_object_facemap(struct Depsgraph *depsgraph,
|
||||
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
|
||||
|
||||
bool ED_view3d_context_activate(struct bContext *C);
|
||||
void ED_view3d_draw_setup_view(struct wmWindow *win,
|
||||
void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
|
||||
struct wmWindow *win,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct ARegion *region,
|
||||
@@ -730,6 +734,16 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
|
||||
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
|
||||
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
void ED_view3d_xr_mirror_update(const struct ScrArea *area,
|
||||
const struct View3D *v3d,
|
||||
const bool enable);
|
||||
void ED_view3d_xr_shading_update(struct wmWindowManager *wm, const View3D *v3d);
|
||||
bool ED_view3d_is_region_xr_mirror_active(const struct wmWindowManager *wm,
|
||||
const struct View3D *v3d,
|
||||
const struct ARegion *region);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -51,12 +51,31 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
|
||||
int winy,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
bool is_image_render,
|
||||
bool do_sky,
|
||||
bool is_persp,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
struct GPUOffScreen *ofs,
|
||||
struct GPUViewport *viewport);
|
||||
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct View3DShading *shading_override,
|
||||
int drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
unsigned int draw_flags,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
bool is_image_render,
|
||||
bool do_sky,
|
||||
bool is_persp,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
struct GPUOffScreen *ofs,
|
||||
struct GPUViewport *viewport);
|
||||
|
||||
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
@@ -3818,6 +3818,7 @@ static void region_quadview_init_rv3d(
|
||||
}
|
||||
|
||||
rv3d->viewlock = viewlock;
|
||||
rv3d->runtime_viewlock = 0;
|
||||
rv3d->view = view;
|
||||
rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
|
||||
rv3d->persp = persp;
|
||||
@@ -3915,7 +3916,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
const char viewlock = (rv3d->viewlock_quad & RV3D_VIEWLOCK_INIT) ?
|
||||
(rv3d->viewlock_quad & ~RV3D_VIEWLOCK_INIT) :
|
||||
RV3D_LOCKED;
|
||||
RV3D_LOCK_ROTATION;
|
||||
|
||||
region_quadview_init_rv3d(
|
||||
sa, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
|
||||
|
@@ -1239,6 +1239,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
return;
|
||||
}
|
||||
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
@@ -1443,7 +1444,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
|
||||
/* Draw 3D brush cursor. */
|
||||
GPU_matrix_push_projection();
|
||||
ED_view3d_draw_setup_view(CTX_wm_window(C),
|
||||
ED_view3d_draw_setup_view(wm,
|
||||
CTX_wm_window(C),
|
||||
CTX_data_depsgraph_pointer(C),
|
||||
CTX_data_scene(C),
|
||||
region,
|
||||
@@ -1537,7 +1539,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
!is_multires) {
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
|
||||
GPU_matrix_push_projection();
|
||||
ED_view3d_draw_setup_view(CTX_wm_window(C),
|
||||
ED_view3d_draw_setup_view(wm,
|
||||
CTX_wm_window(C),
|
||||
CTX_data_depsgraph_pointer(C),
|
||||
CTX_data_scene(C),
|
||||
region,
|
||||
@@ -1556,7 +1559,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE &&
|
||||
brush->flag2 & BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW && !ss->cache->first_time) {
|
||||
GPU_matrix_push_projection();
|
||||
ED_view3d_draw_setup_view(CTX_wm_window(C),
|
||||
ED_view3d_draw_setup_view(wm,
|
||||
CTX_wm_window(C),
|
||||
CTX_data_depsgraph_pointer(C),
|
||||
CTX_data_scene(C),
|
||||
region,
|
||||
@@ -1573,7 +1577,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
||||
|
||||
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && !ss->cache->first_time) {
|
||||
GPU_matrix_push_projection();
|
||||
ED_view3d_draw_setup_view(CTX_wm_window(C),
|
||||
ED_view3d_draw_setup_view(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_depsgraph_pointer(C),
|
||||
CTX_data_scene(C),
|
||||
region,
|
||||
|
@@ -94,6 +94,10 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
# Needed so we can use dna_type_offsets.h for defaults initialization.
|
||||
|
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_icons.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_lattice.h"
|
||||
@@ -114,38 +115,14 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
|
||||
if (region) {
|
||||
RegionView3D *rv3d;
|
||||
if ((region->regiontype == RGN_TYPE_WINDOW) && (rv3d = region->regiondata) &&
|
||||
(rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
(rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
|
||||
*r_v3d = v3d;
|
||||
*r_ar = region;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
ARegion *ar_unlock_user = NULL;
|
||||
ARegion *ar_unlock = NULL;
|
||||
for (region = sa->regionbase.first; region; region = region->next) {
|
||||
/* find the first unlocked rv3d */
|
||||
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
|
||||
rv3d = region->regiondata;
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
ar_unlock = region;
|
||||
if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
|
||||
ar_unlock_user = region;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* camera/perspective view get priority when the active region is locked */
|
||||
if (ar_unlock_user) {
|
||||
if (ED_view3d_area_user_region(sa, v3d, r_ar)) {
|
||||
*r_v3d = v3d;
|
||||
*r_ar = ar_unlock_user;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ar_unlock) {
|
||||
*r_v3d = v3d;
|
||||
*r_ar = ar_unlock;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -155,6 +132,47 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
|
||||
* Also works if \a v3d is not the active space.
|
||||
*/
|
||||
bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **r_ar)
|
||||
{
|
||||
RegionView3D *rv3d = NULL;
|
||||
ARegion *ar_unlock_user = NULL;
|
||||
ARegion *ar_unlock = NULL;
|
||||
const ListBase *region_list = (v3d == sa->spacedata.first) ? &sa->regionbase : &v3d->regionbase;
|
||||
|
||||
BLI_assert(v3d->spacetype == SPACE_VIEW3D);
|
||||
|
||||
for (ARegion *region = region_list->first; region; region = region->next) {
|
||||
/* find the first unlocked rv3d */
|
||||
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
|
||||
rv3d = region->regiondata;
|
||||
if ((rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
|
||||
ar_unlock = region;
|
||||
if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
|
||||
ar_unlock_user = region;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* camera/perspective view get priority when the active region is locked */
|
||||
if (ar_unlock_user) {
|
||||
*r_ar = ar_unlock_user;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ar_unlock) {
|
||||
*r_ar = ar_unlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Most of the time this isn't needed since you could assume the view matrix was
|
||||
* set while drawing, however when functions like mesh_foreachScreenVert are
|
||||
* called by selection tools, we can't be sure this object was the last.
|
||||
@@ -333,9 +351,11 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
|
||||
v3dn->localvd = NULL;
|
||||
v3dn->runtime.properties_storage = NULL;
|
||||
}
|
||||
/* Only one View3D is allowed to have this flag! */
|
||||
v3dn->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
|
||||
|
||||
v3dn->local_collections_uuid = 0;
|
||||
v3dn->flag &= ~V3D_LOCAL_COLLECTIONS;
|
||||
v3dn->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_XR_SESSION_MIRROR);
|
||||
|
||||
if (v3dn->shading.type == OB_RENDER) {
|
||||
v3dn->shading.type = OB_SOLID;
|
||||
@@ -715,6 +735,13 @@ static void view3d_main_region_listener(
|
||||
if (ELEM(wmn->data, ND_UNDO)) {
|
||||
WM_gizmomap_tag_refresh(gzmap);
|
||||
}
|
||||
else if (ELEM(wmn->data, ND_XR_DATA_CHANGED)) {
|
||||
/* Only cause a redraw if this a VR session mirror. Should more features be added that
|
||||
* require redraws, we could pass something to wmn->reference, e.g. the flag value. */
|
||||
if (v3d->flag & V3D_XR_SESSION_MIRROR) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NC_ANIMATION:
|
||||
switch (wmn->data) {
|
||||
@@ -912,6 +939,11 @@ static void view3d_main_region_listener(
|
||||
if (wmn->subtype == NS_VIEW3D_GPU) {
|
||||
rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
|
||||
}
|
||||
#ifdef WITH_XR_OPENXR
|
||||
else if (wmn->subtype == NS_VIEW3D_SHADING) {
|
||||
ED_view3d_xr_shading_update(G_MAIN->wm.first, v3d);
|
||||
}
|
||||
#endif
|
||||
ED_region_tag_redraw(region);
|
||||
WM_gizmomap_tag_refresh(gzmap);
|
||||
}
|
||||
@@ -1374,6 +1406,11 @@ static void view3d_buttons_region_listener(wmWindow *UNUSED(win),
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
break;
|
||||
case NC_WM:
|
||||
if (wmn->data == ND_XR_DATA_CHANGED) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -317,10 +317,35 @@ static void view3d_stereo3d_setup(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
static void view3d_xr_mirror_setup(const wmWindowManager *wm,
|
||||
Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
View3D *v3d,
|
||||
ARegion *region,
|
||||
const rcti *rect)
|
||||
{
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
float viewmat[4][4];
|
||||
const float lens_old = v3d->lens;
|
||||
|
||||
if (!WM_xr_session_state_viewer_pose_matrix_info_get(&wm->xr, viewmat, &v3d->lens)) {
|
||||
/* Can't get info from XR session, use fallback values. */
|
||||
copy_m4_m4(viewmat, rv3d->viewmat);
|
||||
v3d->lens = lens_old;
|
||||
}
|
||||
view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
|
||||
|
||||
/* Reset overridden View3D data */
|
||||
v3d->lens = lens_old;
|
||||
}
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/**
|
||||
* Set the correct matrices
|
||||
*/
|
||||
void ED_view3d_draw_setup_view(wmWindow *win,
|
||||
void ED_view3d_draw_setup_view(const wmWindowManager *wm,
|
||||
wmWindow *win,
|
||||
Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
ARegion *region,
|
||||
@@ -331,13 +356,23 @@ void ED_view3d_draw_setup_view(wmWindow *win,
|
||||
{
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* Setup the view matrix. */
|
||||
if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
|
||||
if (ED_view3d_is_region_xr_mirror_active(wm, v3d, region)) {
|
||||
view3d_xr_mirror_setup(wm, depsgraph, scene, v3d, region, rect);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
|
||||
view3d_stereo3d_setup(depsgraph, scene, v3d, region, rect);
|
||||
}
|
||||
else {
|
||||
view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, winmat, rect);
|
||||
}
|
||||
|
||||
#ifndef WITH_XR_OPENXR
|
||||
UNUSED_VARS(wm);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -803,7 +838,8 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *region, View3D *v3d, bo
|
||||
UI_Theme_Store(&theme_state);
|
||||
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
|
||||
|
||||
ED_view3d_draw_setup_view(NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
|
||||
ED_view3d_draw_setup_view(
|
||||
G_MAIN->wm.first, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
|
||||
|
||||
GPU_clear(GPU_DEPTH_BIT);
|
||||
|
||||
@@ -1481,7 +1517,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) &&
|
||||
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) &&
|
||||
(rv3d->persp != RV3D_CAMOB)) {
|
||||
/* TODO: draw something else (but not this) during fly mode */
|
||||
draw_rotation_guide(rv3d);
|
||||
@@ -1552,7 +1588,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
|
||||
|
||||
static void view3d_draw_view(const bContext *C, ARegion *region)
|
||||
{
|
||||
ED_view3d_draw_setup_view(CTX_wm_window(C),
|
||||
ED_view3d_draw_setup_view(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_expect_evaluated_depsgraph(C),
|
||||
CTX_data_scene(C),
|
||||
region,
|
||||
@@ -1641,6 +1678,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
||||
int winy,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
bool is_image_render,
|
||||
bool do_sky,
|
||||
bool UNUSED(is_persp),
|
||||
const char *viewname,
|
||||
@@ -1690,8 +1728,15 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
||||
}
|
||||
|
||||
/* main drawing call */
|
||||
DRW_draw_render_loop_offscreen(
|
||||
depsgraph, engine_type, region, v3d, do_sky, do_color_management, ofs, viewport);
|
||||
DRW_draw_render_loop_offscreen(depsgraph,
|
||||
engine_type,
|
||||
region,
|
||||
v3d,
|
||||
is_image_render,
|
||||
do_sky,
|
||||
do_color_management,
|
||||
ofs,
|
||||
viewport);
|
||||
|
||||
/* restore size */
|
||||
region->winx = bwinx;
|
||||
@@ -1706,6 +1751,94 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
||||
G.f &= ~G_FLAG_RENDER_VIEWPORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
|
||||
* #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
|
||||
*/
|
||||
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
View3DShading *shading_override,
|
||||
int drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
uint draw_flags,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
bool is_image_render,
|
||||
bool do_sky,
|
||||
bool is_persp,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
GPUOffScreen *ofs,
|
||||
GPUViewport *viewport)
|
||||
{
|
||||
View3D v3d = {NULL};
|
||||
ARegion ar = {NULL};
|
||||
RegionView3D rv3d = {{{0}}};
|
||||
|
||||
v3d.regionbase.first = v3d.regionbase.last = &ar;
|
||||
ar.regiondata = &rv3d;
|
||||
ar.regiontype = RGN_TYPE_WINDOW;
|
||||
|
||||
View3DShading *source_shading_settings = &scene->display.shading;
|
||||
if (draw_flags & V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS && shading_override != NULL) {
|
||||
source_shading_settings = shading_override;
|
||||
}
|
||||
memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
|
||||
v3d.shading.type = drawtype;
|
||||
|
||||
if (shading_override) {
|
||||
/* Pass. */
|
||||
}
|
||||
else if (drawtype == OB_MATERIAL) {
|
||||
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
|
||||
}
|
||||
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
v3d.grid = 1.0f;
|
||||
v3d.gridlines = 16;
|
||||
v3d.gridsubdiv = 10;
|
||||
|
||||
/* Show grid, disable other overlays (set all available _HIDE_ flags). */
|
||||
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
|
||||
V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
|
||||
V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
|
||||
v3d.flag |= V3D_HIDE_HELPLINES;
|
||||
}
|
||||
else {
|
||||
v3d.flag2 = V3D_HIDE_OVERLAYS;
|
||||
}
|
||||
|
||||
rv3d.persp = RV3D_PERSP;
|
||||
v3d.clip_start = clip_start;
|
||||
v3d.clip_end = clip_end;
|
||||
/* Actually not used since we pass in the projection matrix. */
|
||||
v3d.lens = 0;
|
||||
|
||||
ED_view3d_draw_offscreen(depsgraph,
|
||||
scene,
|
||||
drawtype,
|
||||
&v3d,
|
||||
&ar,
|
||||
winx,
|
||||
winy,
|
||||
viewmat,
|
||||
winmat,
|
||||
is_image_render,
|
||||
do_sky,
|
||||
is_persp,
|
||||
viewname,
|
||||
do_color_management,
|
||||
ofs,
|
||||
viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility func for ED_view3d_draw_offscreen
|
||||
*
|
||||
@@ -1815,6 +1948,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
|
||||
sizey,
|
||||
NULL,
|
||||
winmat,
|
||||
true,
|
||||
draw_sky,
|
||||
!is_ortho,
|
||||
viewname,
|
||||
@@ -1902,6 +2036,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
}
|
||||
|
||||
v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
|
||||
|
||||
@@ -2212,7 +2349,7 @@ float view3d_depth_near(ViewDepths *d)
|
||||
void ED_view3d_draw_depth_gpencil(Depsgraph *depsgraph, Scene *scene, ARegion *region, View3D *v3d)
|
||||
{
|
||||
/* Setup view matrix. */
|
||||
ED_view3d_draw_setup_view(NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
|
||||
ED_view3d_draw_setup_view(NULL, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
|
||||
|
||||
GPU_clear(GPU_DEPTH_BIT);
|
||||
|
||||
|
@@ -85,6 +85,52 @@ enum {
|
||||
HAS_ROTATE = (1 << 0),
|
||||
};
|
||||
|
||||
/* test for unlocked camera view in quad view */
|
||||
static bool view3d_camera_user_poll(bContext *C)
|
||||
{
|
||||
View3D *v3d;
|
||||
ARegion *region;
|
||||
|
||||
if (ED_view3d_context_user_region(C, &v3d, ®ion)) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
if ((rv3d->persp == RV3D_CAMOB) && !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool view3d_lock_poll(bContext *C)
|
||||
{
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
if (v3d) {
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
if (rv3d) {
|
||||
return ED_view3d_offset_lock_check(v3d, rv3d);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool view3d_pan_poll(bContext *C)
|
||||
{
|
||||
if (ED_operator_region_view3d_active(C)) {
|
||||
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_LOCATION);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool view3d_zoom_or_dolly_poll(bContext *C)
|
||||
{
|
||||
if (ED_operator_region_view3d_active(C)) {
|
||||
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
return !(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ZOOM_AND_DOLLY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Generic View Operator Properties
|
||||
* \{ */
|
||||
@@ -935,7 +981,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
vod = op->customdata;
|
||||
|
||||
/* poll should check but in some cases fails, see poll func for details */
|
||||
if (vod->rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) {
|
||||
viewops_data_free(C, op);
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
@@ -983,34 +1029,6 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
/* test for unlocked camera view in quad view */
|
||||
static bool view3d_camera_user_poll(bContext *C)
|
||||
{
|
||||
View3D *v3d;
|
||||
ARegion *region;
|
||||
|
||||
if (ED_view3d_context_user_region(C, &v3d, ®ion)) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
if (rv3d->persp == RV3D_CAMOB) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool view3d_lock_poll(bContext *C)
|
||||
{
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
if (v3d) {
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
if (rv3d) {
|
||||
return ED_view3d_offset_lock_check(v3d, rv3d);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void viewrotate_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
viewops_data_free(C, op);
|
||||
@@ -1051,7 +1069,7 @@ static bool ndof_has_translate(const wmNDOFMotionData *ndof,
|
||||
|
||||
static bool ndof_has_rotate(const wmNDOFMotionData *ndof, const RegionView3D *rv3d)
|
||||
{
|
||||
return !is_zero_v3(ndof->rvec) && ((rv3d->viewlock & RV3D_LOCKED) == 0);
|
||||
return !is_zero_v3(ndof->rvec) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1159,7 +1177,7 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
|
||||
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
|
||||
sub_v3_v3(rv3d->ofs, pan_vec);
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(sa, region);
|
||||
}
|
||||
}
|
||||
@@ -1176,7 +1194,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
|
||||
|
||||
float view_inv[4];
|
||||
|
||||
BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
|
||||
BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0);
|
||||
|
||||
ED_view3d_persp_ensure(vod->depsgraph, v3d, region);
|
||||
|
||||
@@ -1400,7 +1418,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
const bool has_rotation = ndof_has_rotate(ndof, rv3d);
|
||||
/* if we can't rotate, fallback to translate (locked axis views) */
|
||||
const bool has_translate = ndof_has_translate(ndof, v3d, rv3d) &&
|
||||
(rv3d->viewlock & RV3D_LOCKED);
|
||||
(RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION);
|
||||
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
|
||||
|
||||
if (has_translate || has_zoom) {
|
||||
@@ -1732,7 +1750,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
|
||||
|
||||
add_v3_v3(vod->rv3d->ofs, dvec);
|
||||
|
||||
if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(vod->sa, vod->region);
|
||||
}
|
||||
}
|
||||
@@ -1807,12 +1825,17 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
|
||||
/* makes op->customdata */
|
||||
viewops_data_alloc(C, op);
|
||||
vod = op->customdata;
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_LOCATION) {
|
||||
viewops_data_free(C, op);
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
viewops_data_create(C,
|
||||
op,
|
||||
event,
|
||||
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
||||
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
||||
vod = op->customdata;
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
@@ -2165,7 +2188,7 @@ static void viewzoom_apply_3d(ViewOpsData *vod,
|
||||
/* these limits were in old code too */
|
||||
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
|
||||
|
||||
if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(vod->sa, vod->region);
|
||||
}
|
||||
|
||||
@@ -2318,7 +2341,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(sa, region);
|
||||
}
|
||||
|
||||
@@ -2416,7 +2439,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
|
||||
ot->invoke = viewzoom_invoke;
|
||||
ot->exec = viewzoom_exec;
|
||||
ot->modal = viewzoom_modal;
|
||||
ot->poll = ED_operator_region_view3d_active;
|
||||
ot->poll = view3d_zoom_or_dolly_poll;
|
||||
ot->cancel = viewzoom_cancel;
|
||||
|
||||
/* flags */
|
||||
@@ -2514,7 +2537,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_
|
||||
view_dolly_to_vector_3d(vod->region, vod->init.ofs, vod->init.mousevec, zfac);
|
||||
}
|
||||
|
||||
if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(vod->sa, vod->region);
|
||||
}
|
||||
|
||||
@@ -2612,7 +2635,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
|
||||
|
||||
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f);
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(sa, region);
|
||||
}
|
||||
|
||||
@@ -2641,7 +2664,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
vod = op->customdata;
|
||||
|
||||
/* poll should check but in some cases fails, see poll func for details */
|
||||
if (vod->rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_LOCK_ROTATION) {
|
||||
viewops_data_free(C, op);
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
@@ -3121,7 +3144,7 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = viewselected_exec;
|
||||
ot->poll = ED_operator_region_view3d_active;
|
||||
ot->poll = view3d_zoom_or_dolly_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
@@ -3265,7 +3288,7 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = viewcenter_cursor_exec;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
ot->poll = view3d_pan_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
@@ -3317,7 +3340,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewcenter_pick_invoke;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
ot->poll = view3d_pan_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
@@ -3701,7 +3724,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
|
||||
.dist = &new_dist,
|
||||
});
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(CTX_wm_area(C), region);
|
||||
}
|
||||
|
||||
@@ -3721,7 +3744,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
|
||||
ot->modal = WM_gesture_box_modal;
|
||||
ot->cancel = WM_gesture_box_cancel;
|
||||
|
||||
ot->poll = ED_operator_region_view3d_active;
|
||||
ot->poll = view3d_zoom_or_dolly_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
@@ -3834,7 +3857,7 @@ static void axis_set_view(bContext *C,
|
||||
rv3d->view_axis_roll = view_axis_roll;
|
||||
}
|
||||
|
||||
if (rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) {
|
||||
ED_region_tag_redraw(region);
|
||||
return;
|
||||
}
|
||||
@@ -4058,7 +4081,7 @@ static int view_camera_exec(bContext *C, wmOperator *op)
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) {
|
||||
/* lastview - */
|
||||
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
@@ -4207,7 +4230,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
|
||||
RV3D_VIEW_USER;
|
||||
orbitdir = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) && (view_opposite == RV3D_VIEW_USER)) {
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) && (view_opposite == RV3D_VIEW_USER)) {
|
||||
/* no NULL check is needed, poll checks */
|
||||
ED_view3d_context_user_region(C, &v3d, ®ion);
|
||||
rv3d = region->regiondata;
|
||||
@@ -4215,7 +4238,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, v3d, region);
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0 || (view_opposite != RV3D_VIEW_USER)) {
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0 || (view_opposite != RV3D_VIEW_USER)) {
|
||||
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
|
||||
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
|
||||
float quat_mul[4];
|
||||
@@ -4352,7 +4375,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
|
||||
vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs);
|
||||
}
|
||||
|
||||
if (vod->rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(vod->sa, vod->region);
|
||||
}
|
||||
|
||||
@@ -4621,7 +4644,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewpan_invoke;
|
||||
ot->poll = ED_operator_region_view3d_active;
|
||||
ot->poll = view3d_pan_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
@@ -4647,7 +4670,8 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
ED_view3d_context_user_region(C, &v3d_dummy, ®ion);
|
||||
rv3d = region->regiondata;
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
/* Could add a separate lock flag for locking persp. */
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) {
|
||||
if (rv3d->persp != RV3D_ORTHO) {
|
||||
rv3d->persp = RV3D_ORTHO;
|
||||
}
|
||||
|
@@ -1039,7 +1039,7 @@ static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
FlyInfo *fly;
|
||||
|
||||
if (rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@@ -252,14 +252,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
|
||||
(navgroup->state.rect_visible.ymax == rect_visible->ymax) &&
|
||||
(navgroup->state.rv3d.is_persp == rv3d->is_persp) &&
|
||||
(navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) &&
|
||||
(navgroup->state.rv3d.viewlock == rv3d->viewlock)) {
|
||||
(navgroup->state.rv3d.viewlock == RV3D_LOCK_FLAGS(rv3d))) {
|
||||
return;
|
||||
}
|
||||
|
||||
navgroup->state.rect_visible = *rect_visible;
|
||||
navgroup->state.rv3d.is_persp = rv3d->is_persp;
|
||||
navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB);
|
||||
navgroup->state.rv3d.viewlock = rv3d->viewlock;
|
||||
navgroup->state.rv3d.viewlock = RV3D_LOCK_FLAGS(rv3d);
|
||||
|
||||
const bool show_navigate = (U.uiflag & USER_SHOW_GIZMO_NAVIGATE) != 0;
|
||||
const bool show_rotate_gizmo = (U.mini_axis_type == USER_MINI_AXIS_TYPE_GIZMO);
|
||||
@@ -296,7 +296,6 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
|
||||
}
|
||||
|
||||
/* RV3D_LOCKED or Camera: only show supported buttons. */
|
||||
if (show_rotate_gizmo) {
|
||||
gz = navgroup->gz_array[GZ_INDEX_ROTATE];
|
||||
gz->matrix_basis[3][0] = co_rotate[0];
|
||||
@@ -306,26 +305,30 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
|
||||
|
||||
if (show_navigate) {
|
||||
int icon_mini_slot = 0;
|
||||
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
|
||||
gz->matrix_basis[3][0] = roundf(co[0]);
|
||||
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
|
||||
gz = navgroup->gz_array[GZ_INDEX_MOVE];
|
||||
gz->matrix_basis[3][0] = roundf(co[0]);
|
||||
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ZOOM_AND_DOLLY) == 0) {
|
||||
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
|
||||
gz->matrix_basis[3][0] = roundf(co[0]);
|
||||
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
}
|
||||
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_LOCATION) == 0) {
|
||||
gz = navgroup->gz_array[GZ_INDEX_MOVE];
|
||||
gz->matrix_basis[3][0] = roundf(co[0]);
|
||||
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
}
|
||||
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
|
||||
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
|
||||
gz->matrix_basis[3][0] = co[0];
|
||||
gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
|
||||
if (navgroup->state.rv3d.is_camera == false) {
|
||||
gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO];
|
||||
gz->matrix_basis[3][0] = roundf(co[0]);
|
||||
gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
|
||||
gz->matrix_basis[3][0] = co[0];
|
||||
gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
|
||||
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
|
||||
}
|
||||
}
|
||||
|
@@ -458,7 +458,7 @@ bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *re
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
|
||||
|
||||
BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
|
||||
BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0);
|
||||
|
||||
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
||||
return false;
|
||||
@@ -678,7 +678,7 @@ static void view3d_boxview_clip(ScrArea *sa)
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXCLIP) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
|
||||
if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
|
||||
if (region->winx > region->winy) {
|
||||
x1 = rv3d->dist;
|
||||
@@ -750,7 +750,7 @@ static void view3d_boxview_clip(ScrArea *sa)
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXCLIP) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
|
||||
rv3d->rflag |= RV3D_CLIPPING;
|
||||
memcpy(rv3d->clip, clip, sizeof(clip));
|
||||
if (rv3d->clipbb) {
|
||||
@@ -821,10 +821,10 @@ void view3d_boxview_sync(ScrArea *sa, ARegion *region)
|
||||
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3dtest = artest->regiondata;
|
||||
|
||||
if (rv3dtest->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(rv3dtest) & RV3D_LOCK_ROTATION) {
|
||||
rv3dtest->dist = rv3d->dist;
|
||||
view3d_boxview_sync_axis(rv3dtest, rv3d);
|
||||
clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
|
||||
clip |= RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP;
|
||||
|
||||
ED_region_tag_redraw(artest);
|
||||
}
|
||||
@@ -847,12 +847,12 @@ void view3d_boxview_copy(ScrArea *sa, ARegion *region)
|
||||
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
|
||||
RegionView3D *rv3dtest = artest->regiondata;
|
||||
|
||||
if (rv3dtest->viewlock) {
|
||||
if (RV3D_LOCK_FLAGS(rv3dtest)) {
|
||||
rv3dtest->dist = rv3d->dist;
|
||||
copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
|
||||
ED_region_tag_redraw(artest);
|
||||
|
||||
clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0);
|
||||
clip |= ((RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -873,7 +873,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
|
||||
* properties are always being edited, weak */
|
||||
viewlock = rv3d->viewlock;
|
||||
|
||||
if ((viewlock & RV3D_LOCKED) == 0) {
|
||||
if ((viewlock & RV3D_LOCK_ROTATION) == 0) {
|
||||
do_clip = (viewlock & RV3D_BOXCLIP) != 0;
|
||||
viewlock = 0;
|
||||
}
|
||||
@@ -898,12 +898,12 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
|
||||
}
|
||||
}
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
|
||||
}
|
||||
|
||||
/* ensure locked regions have an axis, locked user views don't make much sense */
|
||||
if (viewlock & RV3D_LOCKED) {
|
||||
if (viewlock & RV3D_LOCK_ROTATION) {
|
||||
int index_qsplit = 0;
|
||||
for (region = sa->regionbase.first; region; region = region->next) {
|
||||
if (region->alignment == RGN_ALIGN_QSPLIT) {
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_layer.h"
|
||||
@@ -228,7 +229,7 @@ void ED_view3d_smooth_view_ex(
|
||||
ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
|
||||
}
|
||||
/* grid draw as floor */
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
|
||||
/* use existing if exists, means multiple calls to smooth view
|
||||
* wont loose the original 'view' setting */
|
||||
rv3d->view = RV3D_VIEW_USER;
|
||||
@@ -291,7 +292,7 @@ void ED_view3d_smooth_view_ex(
|
||||
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
|
||||
}
|
||||
|
||||
if (rv3d->viewlock & RV3D_BOXVIEW) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
||||
view3d_boxview_copy(sa, region);
|
||||
}
|
||||
|
||||
@@ -344,7 +345,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
|
||||
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
|
||||
}
|
||||
|
||||
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
|
||||
rv3d->view = sms->org_view;
|
||||
}
|
||||
|
||||
@@ -384,7 +385,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
|
||||
WM_event_add_mousemove(CTX_wm_window(C));
|
||||
}
|
||||
|
||||
if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) {
|
||||
if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) {
|
||||
view3d_boxview_copy(CTX_wm_area(C), region);
|
||||
}
|
||||
|
||||
@@ -494,7 +495,7 @@ static bool view3d_camera_to_view_poll(bContext *C)
|
||||
if (ED_view3d_context_user_region(C, &v3d, ®ion)) {
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
if (v3d && v3d->camera && !ID_IS_LINKED(v3d->camera)) {
|
||||
if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) {
|
||||
if (rv3d && (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0) {
|
||||
if (rv3d->persp != RV3D_CAMOB) {
|
||||
return 1;
|
||||
}
|
||||
@@ -826,7 +827,7 @@ void view3d_viewmatrix_set(Depsgraph *depsgraph,
|
||||
bool use_lock_ofs = false;
|
||||
|
||||
/* should be moved to better initialize later on XXX */
|
||||
if (rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) {
|
||||
ED_view3d_lock(rv3d);
|
||||
}
|
||||
|
||||
@@ -991,6 +992,7 @@ int view3d_opengl_select(ViewContext *vc,
|
||||
eV3DSelectObjectFilter select_filter)
|
||||
{
|
||||
struct bThemeState theme_state;
|
||||
const wmWindowManager *wm = CTX_wm_manager(vc->C);
|
||||
Depsgraph *depsgraph = vc->depsgraph;
|
||||
Scene *scene = vc->scene;
|
||||
View3D *v3d = vc->v3d;
|
||||
@@ -1097,7 +1099,7 @@ int view3d_opengl_select(ViewContext *vc,
|
||||
/* Important we use the 'viewmat' and don't re-calculate since
|
||||
* the object & bone view locking takes 'rect' into account, see: T51629. */
|
||||
ED_view3d_draw_setup_view(
|
||||
vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, &rect);
|
||||
wm, vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, &rect);
|
||||
|
||||
if (!XRAY_ACTIVE(v3d)) {
|
||||
GPU_depth_test(true);
|
||||
@@ -1165,7 +1167,8 @@ int view3d_opengl_select(ViewContext *vc,
|
||||
}
|
||||
|
||||
G.f &= ~G_FLAG_PICKSEL;
|
||||
ED_view3d_draw_setup_view(vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, NULL);
|
||||
ED_view3d_draw_setup_view(
|
||||
wm, vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, NULL);
|
||||
|
||||
if (!XRAY_ACTIVE(v3d)) {
|
||||
GPU_depth_test(false);
|
||||
@@ -1684,3 +1687,71 @@ void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Functionality
|
||||
* \{ */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
static void view3d_xr_mirror_begin(RegionView3D *rv3d)
|
||||
{
|
||||
/* If there is no session yet, changes below should not be applied! */
|
||||
BLI_assert(WM_xr_session_exists(&((wmWindowManager *)G_MAIN->wm.first)->xr));
|
||||
|
||||
rv3d->runtime_viewlock |= RV3D_LOCK_ANY_TRANSFORM;
|
||||
/* Force perspective view. This isn't reset but that's not really an issue. */
|
||||
rv3d->persp = RV3D_PERSP;
|
||||
}
|
||||
|
||||
static void view3d_xr_mirror_end(RegionView3D *rv3d)
|
||||
{
|
||||
rv3d->runtime_viewlock &= ~RV3D_LOCK_ANY_TRANSFORM;
|
||||
}
|
||||
|
||||
void ED_view3d_xr_mirror_update(const ScrArea *area, const View3D *v3d, const bool enable)
|
||||
{
|
||||
ARegion *region_rv3d;
|
||||
|
||||
BLI_assert(v3d->spacetype == SPACE_VIEW3D);
|
||||
|
||||
if (ED_view3d_area_user_region(area, v3d, ®ion_rv3d)) {
|
||||
if (enable) {
|
||||
view3d_xr_mirror_begin(region_rv3d->regiondata);
|
||||
}
|
||||
else {
|
||||
view3d_xr_mirror_end(region_rv3d->regiondata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d)
|
||||
{
|
||||
if (v3d->runtime.flag & V3D_RUNTIME_XR_SESSION_ROOT) {
|
||||
View3DShading *xr_shading = &wm->xr.session_settings.shading;
|
||||
|
||||
BLI_assert(WM_xr_session_exists(&wm->xr));
|
||||
|
||||
/* Copy shading from View3D to VR view. */
|
||||
*xr_shading = v3d->shading;
|
||||
if (xr_shading->prop) {
|
||||
IDP_FreeProperty(xr_shading->prop);
|
||||
xr_shading->prop = IDP_CopyProperty(xr_shading->prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ED_view3d_is_region_xr_mirror_active(const wmWindowManager *wm,
|
||||
const View3D *v3d,
|
||||
const ARegion *region)
|
||||
{
|
||||
return (v3d->flag & V3D_XR_SESSION_MIRROR) &&
|
||||
/* The free region (e.g. the camera region in quad-view) is always the last in the list
|
||||
base. We don't want any other to be affected. */
|
||||
!region->next && //
|
||||
WM_xr_session_is_ready(&wm->xr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
@@ -1347,7 +1347,7 @@ static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
WalkInfo *walk;
|
||||
|
||||
if (rv3d->viewlock & RV3D_LOCKED) {
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@@ -104,6 +104,9 @@ GPUViewport *GPU_viewport_create(void);
|
||||
void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect);
|
||||
void GPU_viewport_unbind(GPUViewport *viewport);
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect);
|
||||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
||||
const rcti *rect,
|
||||
bool display_colorspace);
|
||||
void GPU_viewport_free(GPUViewport *viewport);
|
||||
|
||||
void GPU_viewport_colorspace_set(GPUViewport *viewport,
|
||||
|
@@ -532,7 +532,13 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
/**
|
||||
* Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace
|
||||
* transform should be performed.
|
||||
*/
|
||||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
|
||||
const rcti *rect,
|
||||
bool display_colorspace)
|
||||
{
|
||||
DefaultFramebufferList *dfbl = viewport->fbl;
|
||||
DefaultTextureList *dtxl = viewport->txl;
|
||||
@@ -545,18 +551,22 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
const float w = (float)GPU_texture_width(color);
|
||||
const float h = (float)GPU_texture_height(color);
|
||||
|
||||
BLI_assert(w == BLI_rcti_size_x(rect) + 1);
|
||||
BLI_assert(h == BLI_rcti_size_y(rect) + 1);
|
||||
/* We allow rects with min/max swapped, but we also need coorectly assigned coordinates. */
|
||||
rcti sanitized_rect = *rect;
|
||||
BLI_rcti_sanitize(&sanitized_rect);
|
||||
|
||||
BLI_assert(w == BLI_rcti_size_x(&sanitized_rect) + 1);
|
||||
BLI_assert(h == BLI_rcti_size_y(&sanitized_rect) + 1);
|
||||
|
||||
/* wmOrtho for the screen has this same offset */
|
||||
const float halfx = GLA_PIXEL_OFS / w;
|
||||
const float halfy = GLA_PIXEL_OFS / h;
|
||||
|
||||
rctf pos_rect = {
|
||||
.xmin = rect->xmin,
|
||||
.ymin = rect->ymin,
|
||||
.xmax = rect->xmin + w,
|
||||
.ymax = rect->ymin + h,
|
||||
.xmin = sanitized_rect.xmin,
|
||||
.ymin = sanitized_rect.ymin,
|
||||
.xmax = sanitized_rect.xmin + w,
|
||||
.ymax = sanitized_rect.ymin + h,
|
||||
};
|
||||
|
||||
rctf uv_rect = {
|
||||
@@ -565,8 +575,28 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
.xmax = halfx + 1.0f,
|
||||
.ymax = halfy + 1.0f,
|
||||
};
|
||||
/* Mirror the UV rect in case axis-swapped drawing is requested (by passing a rect with min and
|
||||
* max values swapped). */
|
||||
if (BLI_rcti_size_x(rect) < 0) {
|
||||
SWAP(float, uv_rect.xmin, uv_rect.xmax);
|
||||
}
|
||||
if (BLI_rcti_size_y(rect) < 0) {
|
||||
SWAP(float, uv_rect.ymin, uv_rect.ymax);
|
||||
}
|
||||
|
||||
gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, true);
|
||||
gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
|
||||
* color transform to display space.
|
||||
*
|
||||
* \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done with
|
||||
* inversed axis coordinates (upside down or sideways).
|
||||
*/
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
{
|
||||
GPU_viewport_draw_to_screen_ex(viewport, rect, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -26,6 +26,7 @@ typedef enum eV3DOffscreenDrawFlag {
|
||||
V3D_OFSDRAW_NONE = (0),
|
||||
V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0),
|
||||
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1),
|
||||
V3D_OFSDRAW_SHOW_GRIDFLOOR = (1 << 2),
|
||||
} eV3DOffscreenDrawFlag;
|
||||
|
||||
/** #View3DShading.light */
|
||||
|
@@ -106,10 +106,12 @@ typedef struct RegionView3D {
|
||||
char persp;
|
||||
char view;
|
||||
char view_axis_roll;
|
||||
char viewlock;
|
||||
char viewlock; /* Should usually be accessed with RV3D_LOCK_FLAGS()! */
|
||||
/** Options for runtime only locking (cleared on file read) */
|
||||
char runtime_viewlock; /* Should usually be accessed with RV3D_LOCK_FLAGS()! */
|
||||
/** Options for quadview (store while out of quad view). */
|
||||
char viewlock_quad;
|
||||
char _pad[2];
|
||||
char _pad[1];
|
||||
/** Normalized offset for locked view: (-1, -1) bottom left, (1, 1) upper right. */
|
||||
float ofs_lock[2];
|
||||
|
||||
@@ -232,6 +234,10 @@ typedef struct View3DOverlay {
|
||||
typedef struct View3D_Runtime {
|
||||
/** Nkey panel stores stuff here. */
|
||||
void *properties_storage;
|
||||
/** Runtime only flags. */
|
||||
int flag;
|
||||
|
||||
char _pad1[4];
|
||||
} View3D_Runtime;
|
||||
|
||||
/** 3D ViewPort Struct. */
|
||||
@@ -342,6 +348,7 @@ typedef struct View3D {
|
||||
#define V3D_FLAG_UNUSED_1 (1 << 1) /* cleared */
|
||||
#define V3D_HIDE_HELPLINES (1 << 2)
|
||||
#define V3D_INVALID_BACKBUF (1 << 3)
|
||||
#define V3D_XR_SESSION_MIRROR (1 << 4)
|
||||
|
||||
#define V3D_FLAG_UNUSED_10 (1 << 10) /* cleared */
|
||||
#define V3D_SELECT_OUTLINE (1 << 11)
|
||||
@@ -349,6 +356,12 @@ typedef struct View3D {
|
||||
#define V3D_GLOBAL_STATS (1 << 13)
|
||||
#define V3D_DRAW_CENTERS (1 << 15)
|
||||
|
||||
/** #View3D_Runtime.flag */
|
||||
enum {
|
||||
/** The 3D view which the XR session was created in is flagged with this. */
|
||||
V3D_RUNTIME_XR_SESSION_ROOT = (1 << 0),
|
||||
};
|
||||
|
||||
/** #RegionView3D.persp */
|
||||
#define RV3D_ORTHO 0
|
||||
#define RV3D_PERSP 1
|
||||
@@ -367,9 +380,19 @@ typedef struct View3D {
|
||||
#define RV3D_ZOFFSET_DISABLED 64
|
||||
|
||||
/** #RegionView3D.viewlock */
|
||||
#define RV3D_LOCKED (1 << 0)
|
||||
#define RV3D_BOXVIEW (1 << 1)
|
||||
#define RV3D_BOXCLIP (1 << 2)
|
||||
enum {
|
||||
RV3D_LOCK_ROTATION = (1 << 0),
|
||||
RV3D_BOXVIEW = (1 << 1),
|
||||
RV3D_BOXCLIP = (1 << 2),
|
||||
RV3D_LOCK_LOCATION = (1 << 3),
|
||||
RV3D_LOCK_ZOOM_AND_DOLLY = (1 << 4),
|
||||
|
||||
RV3D_LOCK_ANY_TRANSFORM = (RV3D_LOCK_LOCATION | RV3D_LOCK_ROTATION | RV3D_LOCK_ZOOM_AND_DOLLY),
|
||||
};
|
||||
|
||||
/* Bitwise OR of the regular lock-flags with runtime only lock-flags. */
|
||||
#define RV3D_LOCK_FLAGS(rv3d) ((rv3d)->viewlock | ((rv3d)->runtime_viewlock))
|
||||
|
||||
/** #RegionView3D.viewlock_quad */
|
||||
#define RV3D_VIEWLOCK_INIT (1 << 7)
|
||||
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_vec_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
@@ -119,6 +120,16 @@ typedef struct ReportTimerInfo {
|
||||
float widthfac;
|
||||
} ReportTimerInfo;
|
||||
|
||||
//#ifdef WITH_XR_OPENXR
|
||||
typedef struct wmXrData {
|
||||
/** Runtime information for managing Blender specific behaviors. */
|
||||
struct wmXrRuntimeData *runtime;
|
||||
/** Permanent session settings (draw mode, feature toggles, etc). Stored in files and accessible
|
||||
* even before the session runs. */
|
||||
XrSessionSettings session_settings;
|
||||
} wmXrData;
|
||||
//#endif
|
||||
|
||||
/* reports need to be before wmWindowManager */
|
||||
|
||||
/* windowmanager is saved, tag WMAN */
|
||||
@@ -180,6 +191,9 @@ typedef struct wmWindowManager {
|
||||
|
||||
struct wmMsgBus *message_bus;
|
||||
|
||||
//#ifdef WITH_XR_OPENXR
|
||||
wmXrData xr;
|
||||
//#endif
|
||||
} wmWindowManager;
|
||||
|
||||
/* wmWindowManager.initialized */
|
||||
|
58
source/blender/makesdna/DNA_xr_types.h
Normal file
58
source/blender/makesdna/DNA_xr_types.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup DNA
|
||||
*/
|
||||
|
||||
#ifndef __DNA_XR_TYPES_H__
|
||||
#define __DNA_XR_TYPES_H__
|
||||
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
typedef struct XrSessionSettings {
|
||||
/** Shading settings, struct shared with 3D-View so settings are the same. */
|
||||
struct View3DShading shading;
|
||||
|
||||
char _pad[7];
|
||||
|
||||
char base_pose_type; /* eXRSessionBasePoseType */
|
||||
/** Object to take the location and rotation as base position from. */
|
||||
Object *base_pose_object;
|
||||
float base_pose_location[3];
|
||||
float base_pose_angle;
|
||||
|
||||
/** View3D draw flags (V3D_OFSDRAW_NONE, V3D_OFSDRAW_SHOW_ANNOTATION, ...). */
|
||||
char draw_flags;
|
||||
char _pad2[3];
|
||||
|
||||
/** Clipping distance. */
|
||||
float clip_start, clip_end;
|
||||
|
||||
int flag;
|
||||
} XrSessionSettings;
|
||||
|
||||
typedef enum eXrSessionFlag {
|
||||
XR_SESSION_USE_POSITION_TRACKING = (1 << 0),
|
||||
} eXrSessionFlag;
|
||||
|
||||
typedef enum eXRSessionBasePoseType {
|
||||
XR_BASE_POSE_SCENE_CAMERA = 0,
|
||||
XR_BASE_POSE_OBJECT = 1,
|
||||
XR_BASE_POSE_CUSTOM = 2,
|
||||
} eXRSessionBasePoseType;
|
||||
|
||||
#endif /* __DNA_XR_TYPES_H__ */
|
@@ -132,6 +132,7 @@ static const char *includefiles[] = {
|
||||
"DNA_workspace_types.h",
|
||||
"DNA_lightprobe_types.h",
|
||||
"DNA_curveprofile_types.h",
|
||||
"DNA_xr_types.h",
|
||||
|
||||
/* see comment above before editing! */
|
||||
|
||||
@@ -1598,6 +1599,7 @@ int main(int argc, char **argv)
|
||||
#include "DNA_workspace_types.h"
|
||||
#include "DNA_lightprobe_types.h"
|
||||
#include "DNA_curveprofile_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
|
||||
/* end of list */
|
||||
|
||||
|
@@ -694,6 +694,8 @@ extern StructRNA RNA_WorkSpace;
|
||||
extern StructRNA RNA_World;
|
||||
extern StructRNA RNA_WorldLighting;
|
||||
extern StructRNA RNA_WorldMistSettings;
|
||||
extern StructRNA RNA_XrSessionSettings;
|
||||
extern StructRNA RNA_XrSessionState;
|
||||
extern StructRNA RNA_uiPopover;
|
||||
extern StructRNA RNA_wmOwnerIDs;
|
||||
|
||||
|
@@ -92,6 +92,7 @@ set(DEFSRC
|
||||
rna_wm_gizmo.c
|
||||
rna_workspace.c
|
||||
rna_world.c
|
||||
rna_xr.c
|
||||
)
|
||||
|
||||
set(APISRC
|
||||
@@ -325,6 +326,10 @@ if(WITH_INPUT_NDOF)
|
||||
add_definitions(-DWITH_INPUT_NDOF)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
# Build makesrna executable
|
||||
blender_include_dirs(
|
||||
.
|
||||
|
@@ -4306,6 +4306,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
|
||||
{"rna_movieclip.c", NULL, RNA_def_movieclip},
|
||||
{"rna_tracking.c", NULL, RNA_def_tracking},
|
||||
{"rna_mask.c", NULL, RNA_def_mask},
|
||||
{"rna_xr.c", NULL, RNA_def_xr},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
@@ -205,6 +205,7 @@ void RNA_def_world(struct BlenderRNA *brna);
|
||||
void RNA_def_movieclip(struct BlenderRNA *brna);
|
||||
void RNA_def_tracking(struct BlenderRNA *brna);
|
||||
void RNA_def_mask(struct BlenderRNA *brna);
|
||||
void RNA_def_xr(struct BlenderRNA *brna);
|
||||
|
||||
/* Common Define functions */
|
||||
|
||||
|
@@ -997,7 +997,7 @@ static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create)
|
||||
static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
ID *id = ptr->owner_id;
|
||||
if (GS(id->name) == ID_SCE) {
|
||||
if (GS(id->name) != ID_SCR) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1333,6 +1333,25 @@ static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *C
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_SpaceView3D_mirror_xr_session_update(Main *main,
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmWindowManager *wm = main->wm.first;
|
||||
|
||||
/* Handle mirror toggling while there is a session already. */
|
||||
if (WM_xr_session_exists(&wm->xr)) {
|
||||
const View3D *v3d = ptr->data;
|
||||
const ScrArea *area = rna_area_from_space(ptr);
|
||||
ED_view3d_xr_mirror_update(area, v3d, v3d->flag & V3D_XR_SESSION_MIRROR);
|
||||
}
|
||||
|
||||
# else
|
||||
UNUSED_VARS(main, ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_SpaceView3D_icon_from_show_object_viewport_get(PointerRNA *ptr)
|
||||
{
|
||||
const View3D *v3d = (View3D *)ptr->data;
|
||||
@@ -3166,19 +3185,20 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
"rna_3DViewShading_type_itemf");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_3DViewShading_type_update");
|
||||
RNA_def_property_update(
|
||||
prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, "rna_3DViewShading_type_update");
|
||||
|
||||
prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "light");
|
||||
RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items);
|
||||
RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_object_outline", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_OBJECT_OUTLINE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Outline", "Show Object Outline");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "studio_light", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, rna_enum_studio_light_items);
|
||||
@@ -3188,45 +3208,45 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
"rna_View3DShading_studio_light_set",
|
||||
"rna_View3DShading_studio_light_itemf");
|
||||
RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_world_space_lighting", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_WORLD_ORIENTATION);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "World Space Lighting", "Make the lighting fixed and not follow the camera");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_BACKFACE_CULLING);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Backface Culling", "Use back face culling to hide the back side of faces");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_CAVITY);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Cavity", "Show Cavity");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "cavity_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, cavity_type_items);
|
||||
RNA_def_property_ui_text(prop, "Cavity Type", "Way to draw the cavity shading");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "curvature_ridge_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "curvature_ridge_factor");
|
||||
RNA_def_property_ui_text(prop, "Curvature Ridge", "Factor for the curvature ridges");
|
||||
RNA_def_property_range(prop, 0.0f, 2.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "curvature_valley_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "curvature_valley_factor");
|
||||
RNA_def_property_ui_text(prop, "Curvature Valley", "Factor for the curvature valleys");
|
||||
RNA_def_property_range(prop, 0.0f, 2.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "cavity_ridge_factor");
|
||||
@@ -3234,7 +3254,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 250.0f);
|
||||
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "cavity_valley_factor");
|
||||
@@ -3242,7 +3262,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 250.0f);
|
||||
RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "selected_studio_light", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "StudioLight");
|
||||
@@ -3259,7 +3279,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
prop, "Studiolight Rotation", "Rotation of the studiolight around the Z-Axis");
|
||||
RNA_def_property_range(prop, -M_PI, M_PI);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "studiolight_intensity", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "studiolight_intensity");
|
||||
@@ -3267,7 +3287,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Strength", "Strength of the studiolight");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
|
||||
@@ -3275,7 +3295,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "studiolight_background_blur", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "studiolight_blur");
|
||||
@@ -3284,7 +3304,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "color_type");
|
||||
@@ -3292,64 +3312,65 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_View3DShading_color_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Color", "Color Type");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
|
||||
RNA_def_property_update(
|
||||
prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "wireframe_color_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "wire_color_type");
|
||||
RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_View3DShading_color_type_itemf");
|
||||
RNA_def_property_ui_text(prop, "Color", "Color Type");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "single_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "single_color");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Color", "Color for single color mode");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, background_type_items);
|
||||
RNA_def_property_ui_text(prop, "Background", "Way to draw the background");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SHADOW);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Shadow", "Show Shadow");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_xray", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_XRAY);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Show X-Ray", "Show whole scene transparent");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_xray_wireframe", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_XRAY_WIREFRAME);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Show X-Ray", "Show whole scene transparent");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "xray_alpha", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "xray_alpha");
|
||||
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "xray_alpha_wireframe", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "xray_alpha_wire");
|
||||
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_DEPTH_OF_FIELD);
|
||||
@@ -3358,46 +3379,46 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
prop,
|
||||
"Depth Of Field",
|
||||
"Use depth of field on viewport using the values from the active camera");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_scene_lights", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS);
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_scene_world", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD);
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_scene_lights_render", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS_RENDER);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_scene_world_render", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD_RENDER);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_specular_highlight", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SPECULAR_HIGHLIGHT);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Specular Highlights", "Render specular highlights");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "object_outline_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "object_outline_color");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Outline Color", "Color for object outline");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "shadow_intensity");
|
||||
@@ -3405,7 +3426,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "render_pass", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "render_pass");
|
||||
@@ -3413,7 +3434,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Render Pass", "Render Pass to show in the viewport");
|
||||
RNA_def_property_enum_funcs(
|
||||
prop, "rna_3DViewShading_render_pass_get", NULL, "rna_3DViewShading_render_pass_itemf");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d_overlay(BlenderRNA *brna)
|
||||
@@ -4189,6 +4210,15 @@ static void rna_def_space_view3d(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "mirror_xr_session", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_XR_SESSION_MIRROR);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Mirror VR Session",
|
||||
"Synchronize the viewer perspective of virtual reality sessions with this 3D viewport");
|
||||
RNA_def_property_update(
|
||||
prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_mirror_xr_session_update");
|
||||
|
||||
{
|
||||
struct {
|
||||
const char *name;
|
||||
@@ -4268,7 +4298,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
|
||||
RNA_def_struct_ui_text(srna, "3D View Region", "3D View region data");
|
||||
|
||||
prop = RNA_def_property(srna, "lock_rotation", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_LOCKED);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "viewlock", RV3D_LOCK_ROTATION);
|
||||
RNA_def_property_ui_text(prop, "Lock", "Lock view rotation in side views");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RegionView3D_quadview_update");
|
||||
|
||||
|
@@ -1266,6 +1266,20 @@ static void rna_wmClipboard_set(PointerRNA *UNUSED(ptr), const char *value)
|
||||
WM_clipboard_text_set((void *)value, false);
|
||||
}
|
||||
|
||||
static PointerRNA rna_WindowManager_xr_session_state_get(PointerRNA *ptr)
|
||||
{
|
||||
wmWindowManager *wm = ptr->data;
|
||||
struct wmXrSessionState *state =
|
||||
# ifdef WITH_XR_OPENXR
|
||||
WM_xr_session_state_handle_get(&wm->xr);
|
||||
# else
|
||||
NULL;
|
||||
UNUSED_VAR(wm);
|
||||
# endif
|
||||
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_XrSessionState, state);
|
||||
}
|
||||
|
||||
# ifdef WITH_PYTHON
|
||||
|
||||
static bool rna_operator_poll_cb(bContext *C, wmOperatorType *ot)
|
||||
@@ -2484,6 +2498,18 @@ static void rna_def_windowmanager(BlenderRNA *brna)
|
||||
prop, "rna_wmClipboard_get", "rna_wmClipboard_length", "rna_wmClipboard_set");
|
||||
RNA_def_property_ui_text(prop, "Text Clipboard", "");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_session_settings", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "xr.session_settings");
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_ui_text(prop, "XR Session Settings", "");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_session_state", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "XrSessionState");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_WindowManager_xr_session_state_get", NULL, NULL, NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "XR Session State", "Runtime state information about the VR session");
|
||||
|
||||
RNA_api_wm(srna);
|
||||
}
|
||||
|
||||
|
@@ -1376,6 +1376,12 @@ static void rna_def_gizmogroup(BlenderRNA *brna)
|
||||
0,
|
||||
"Tool Init",
|
||||
"Postpone running until tool operator run (when used with a tool)"},
|
||||
{WM_GIZMOGROUPTYPE_VR_REDRAWS,
|
||||
"VR_REDRAWS",
|
||||
0,
|
||||
"VR Redraws",
|
||||
"The gizmos are made for use with virtual reality sessions and require special redraw "
|
||||
"management"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
|
||||
|
229
source/blender/makesrna/intern/rna_xr.c
Normal file
229
source/blender/makesrna/intern/rna_xr.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup RNA
|
||||
*/
|
||||
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "BLI_math.h"
|
||||
|
||||
# include "WM_api.h"
|
||||
|
||||
static bool rna_XrSessionState_is_running(bContext *C)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
return WM_xr_session_is_ready(&wm->xr);
|
||||
# else
|
||||
UNUSED_VARS(C);
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef WITH_XR_OPENXR
|
||||
static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr)
|
||||
{
|
||||
/* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
|
||||
* consistently pass wmXrData pointers to the WM_xr_xxx() API. */
|
||||
|
||||
BLI_assert(ptr->type == &RNA_XrSessionState);
|
||||
|
||||
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
|
||||
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
|
||||
|
||||
return &wm->xr;
|
||||
}
|
||||
# endif
|
||||
|
||||
static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewer_pose_location_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
zero_v3(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSessionState_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewer_pose_rotation_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
unit_qt(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
#else /* RNA_RUNTIME */
|
||||
|
||||
static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem base_pose_types[] = {
|
||||
{XR_BASE_POSE_SCENE_CAMERA,
|
||||
"SCENE_CAMERA",
|
||||
0,
|
||||
"Scene Camera",
|
||||
"Follow the active scene camera to define the VR view's base pose"},
|
||||
{XR_BASE_POSE_OBJECT,
|
||||
"OBJECT",
|
||||
0,
|
||||
"Object",
|
||||
"Follow the transformation of an object to define the VR view's base pose"},
|
||||
{XR_BASE_POSE_CUSTOM,
|
||||
"CUSTOM",
|
||||
0,
|
||||
"Custom",
|
||||
"Follow a custom transformation to define the VR view's base pose"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "XrSessionSettings", NULL);
|
||||
RNA_def_struct_ui_text(srna, "XR Session Settings", "");
|
||||
|
||||
prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_ui_text(prop, "Shading Settings", "");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "base_pose_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_items(prop, base_pose_types);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Base Pose Type",
|
||||
"Define where the location and rotation for the VR view come from, to which "
|
||||
"translation and rotation deltas from the VR headset will be applied to");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "base_pose_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Base Pose Object",
|
||||
"Object to take the location and rotation to which translation and "
|
||||
"rotation deltas from the VR headset will be applied to");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "base_pose_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Base Pose Location",
|
||||
"Coordinates to apply translation deltas from the VR headset to");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "base_pose_angle", PROP_FLOAT, PROP_AXISANGLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Base Pose Angle",
|
||||
"Rotation angle around the Z-Axis to apply the rotation deltas from the VR headset to");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_GRIDFLOOR);
|
||||
RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_ANNOTATION);
|
||||
RNA_def_property_ui_text(prop, "Show Annotation", "Show annotations for this view");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Clip Start", "VR viewport near clipping distance");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
|
||||
RNA_def_property_ui_text(prop, "Clip End", "VR viewport far clipping distance");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_positional_tracking", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", XR_SESSION_USE_POSITION_TRACKING);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Positional Tracking",
|
||||
"Allow VR headsets to affect the location in virtual space, in addition to the rotation");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_xr_session_state(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm, *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "XrSessionState", NULL);
|
||||
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
|
||||
RNA_def_struct_ui_text(srna, "Session State", "Runtime state information about the VR session");
|
||||
|
||||
func = RNA_def_function(srna, "is_running", "rna_XrSessionState_is_running");
|
||||
RNA_def_function_ui_description(func, "Query if the VR session is currently running");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
parm = RNA_def_pointer(func, "context", "Context", "", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(func, "result", 0, "Result", "");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
prop = RNA_def_property(srna, "viewer_pose_location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_location_get", NULL, NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Viewer Pose Location",
|
||||
"Last known location of the viewer pose (center between the eyes) in world space");
|
||||
|
||||
prop = RNA_def_property(srna, "viewer_pose_rotation", PROP_FLOAT, PROP_QUATERNION);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_rotation_get", NULL, NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Viewer Pose Rotation",
|
||||
"Last known rotation of the viewer pose (center between the eyes) in world space");
|
||||
}
|
||||
|
||||
void RNA_def_xr(BlenderRNA *brna)
|
||||
{
|
||||
RNA_define_animate_sdna(false);
|
||||
|
||||
rna_def_xr_session_settings(brna);
|
||||
rna_def_xr_session_state(brna);
|
||||
|
||||
RNA_define_animate_sdna(true);
|
||||
}
|
||||
|
||||
#endif /* RNA_RUNTIME */
|
@@ -257,6 +257,7 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self,
|
||||
(float(*)[4])py_mat_projection->matrix,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
self->ofs,
|
||||
|
@@ -75,6 +75,7 @@ set(SRC
|
||||
intern/wm_splash_screen.c
|
||||
intern/wm_stereo.c
|
||||
intern/wm_subwindow.c
|
||||
intern/wm_surface.c
|
||||
intern/wm_toolsystem.c
|
||||
intern/wm_tooltip.c
|
||||
intern/wm_uilist_type.c
|
||||
@@ -101,6 +102,7 @@ set(SRC
|
||||
wm_event_system.h
|
||||
wm_event_types.h
|
||||
wm_files.h
|
||||
wm_surface.h
|
||||
wm_window.h
|
||||
intern/wm_platform_support.h
|
||||
intern/wm_window_private.h
|
||||
@@ -187,4 +189,11 @@ if(WITH_COMPOSITOR)
|
||||
add_definitions(-DWITH_COMPOSITOR)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
list(APPEND SRC
|
||||
intern/wm_xr.c
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib_nolist(bf_windowmanager "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -156,6 +156,10 @@ void *WM_opengl_context_create(void);
|
||||
void WM_opengl_context_dispose(void *context);
|
||||
void WM_opengl_context_activate(void *context);
|
||||
void WM_opengl_context_release(void *context);
|
||||
#ifdef WIN32
|
||||
void *WM_directx_context_create(void);
|
||||
void WM_directx_context_dispose(void *context);
|
||||
#endif
|
||||
|
||||
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
|
||||
struct wmWindow *WM_window_open_temp(struct bContext *C,
|
||||
@@ -867,6 +871,18 @@ void WM_generic_callback_free(struct wmGenericCallback *callback);
|
||||
|
||||
void WM_generic_user_data_free(struct wmGenericUserData *user_data);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* wm_xr.c */
|
||||
bool WM_xr_session_exists(const wmXrData *xr);
|
||||
bool WM_xr_session_is_ready(const wmXrData *xr);
|
||||
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
|
||||
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
|
||||
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
|
||||
float r_viewmat[4][4],
|
||||
float *r_focal_len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -310,6 +310,7 @@ typedef struct wmNotifier {
|
||||
#define ND_HISTORY (4 << 16)
|
||||
#define ND_JOB (5 << 16)
|
||||
#define ND_UNDO (6 << 16)
|
||||
#define ND_XR_DATA_CHANGED (7 << 17)
|
||||
|
||||
/* NC_SCREEN */
|
||||
#define ND_LAYOUTBROWSE (1 << 16)
|
||||
@@ -437,6 +438,7 @@ typedef struct wmNotifier {
|
||||
|
||||
/* subtype 3d view editing */
|
||||
#define NS_VIEW3D_GPU (16 << 8)
|
||||
#define NS_VIEW3D_SHADING (16 << 9)
|
||||
|
||||
/* action classification */
|
||||
#define NOTE_ACTION (0x000000FF)
|
||||
|
@@ -139,6 +139,13 @@ typedef enum eWM_GizmoFlagGroupTypeFlag {
|
||||
* with click drag events by popping up under the cursor and catching the tweak event.
|
||||
*/
|
||||
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK = (1 << 8),
|
||||
|
||||
/**
|
||||
* Cause continuous redraws, i.e. set the region redraw flag on every main loop itertion. This
|
||||
* should really be avoided by using proper region redraw tagging, notifiers and the message-bus,
|
||||
* however for VR it's sometimes needed.
|
||||
*/
|
||||
WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 9),
|
||||
} eWM_GizmoFlagGroupTypeFlag;
|
||||
|
||||
/**
|
||||
|
@@ -576,6 +576,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
||||
const int co[2],
|
||||
const int hotspot)
|
||||
{
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
View3D *v3d = sa->spacedata.first;
|
||||
@@ -588,7 +589,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
||||
BLI_rcti_init_pt_radius(&rect, co, hotspot);
|
||||
|
||||
ED_view3d_draw_setup_view(
|
||||
CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
|
||||
|
||||
bool use_select_bias = false;
|
||||
|
||||
@@ -608,7 +609,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
|
||||
}
|
||||
|
||||
ED_view3d_draw_setup_view(
|
||||
CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
|
||||
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
|
||||
|
||||
if (use_select_bias && (hits > 1)) {
|
||||
float co_direction[3];
|
||||
|
@@ -379,6 +379,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
|
||||
wm_autosave_timer_ended(wm);
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* May send notifier, so do before freeing notifier queue. */
|
||||
wm_xr_exit(wm);
|
||||
#endif
|
||||
|
||||
while ((win = BLI_pophead(&wm->windows))) {
|
||||
/* prevent draw clear to use screen */
|
||||
BKE_workspace_active_set(win->workspace_hook, NULL);
|
||||
|
@@ -67,6 +67,7 @@
|
||||
#include "wm_draw.h"
|
||||
#include "wm_window.h"
|
||||
#include "wm_event_system.h"
|
||||
#include "wm_surface.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "BKE_subsurf.h"
|
||||
@@ -186,7 +187,10 @@ static void wm_area_mark_invalid_backbuf(ScrArea *sa)
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_region_test_gizmo_do_draw(ARegion *region, bool tag_redraw)
|
||||
static void wm_region_test_gizmo_do_draw(bContext *C,
|
||||
ScrArea *sa,
|
||||
ARegion *region,
|
||||
bool tag_redraw)
|
||||
{
|
||||
if (region->gizmo_map == NULL) {
|
||||
return;
|
||||
@@ -195,10 +199,26 @@ static void wm_region_test_gizmo_do_draw(ARegion *region, bool tag_redraw)
|
||||
wmGizmoMap *gzmap = region->gizmo_map;
|
||||
for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first; gzgroup;
|
||||
gzgroup = gzgroup->next) {
|
||||
if (tag_redraw && (gzgroup->type->flag & WM_GIZMOGROUPTYPE_VR_REDRAWS)) {
|
||||
ScrArea *ctx_sa = CTX_wm_area(C);
|
||||
ARegion *ctx_ar = CTX_wm_region(C);
|
||||
|
||||
CTX_wm_area_set(C, sa);
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
|
||||
ED_region_tag_redraw_editor_overlays(region);
|
||||
}
|
||||
|
||||
/* Reset. */
|
||||
CTX_wm_area_set(C, ctx_sa);
|
||||
CTX_wm_region_set(C, ctx_ar);
|
||||
}
|
||||
|
||||
for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
|
||||
if (gz->do_draw) {
|
||||
if (tag_redraw) {
|
||||
ED_region_tag_redraw_no_rebuild(region);
|
||||
ED_region_tag_redraw_editor_overlays(region);
|
||||
}
|
||||
gz->do_draw = false;
|
||||
}
|
||||
@@ -237,6 +257,19 @@ static void wm_region_test_render_do_draw(const Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
static void wm_region_test_xr_do_draw(const wmWindowManager *wm,
|
||||
const ScrArea *area,
|
||||
ARegion *region)
|
||||
{
|
||||
if ((area->spacetype == SPACE_VIEW3D) && (region->regiontype == RGN_TYPE_WINDOW)) {
|
||||
if (ED_view3d_is_region_xr_mirror_active(wm, area->spacedata.first, region)) {
|
||||
ED_region_tag_redraw_no_rebuild(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool wm_region_use_viewport_by_type(short space_type, short region_type)
|
||||
{
|
||||
return (ELEM(space_type, SPACE_VIEW3D, SPACE_IMAGE) && region_type == RGN_TYPE_WINDOW);
|
||||
@@ -836,11 +869,26 @@ static void wm_draw_window(bContext *C, wmWindow *win)
|
||||
screen->do_draw = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw offscreen contexts not bound to a specific window.
|
||||
*/
|
||||
static void wm_draw_surface(bContext *C, wmSurface *surface)
|
||||
{
|
||||
wm_window_clear_drawable(CTX_wm_manager(C));
|
||||
wm_surface_make_drawable(surface);
|
||||
|
||||
surface->draw(C);
|
||||
|
||||
/* Avoid interference with window drawable */
|
||||
wm_surface_clear_drawable();
|
||||
}
|
||||
|
||||
/****************** main update call **********************/
|
||||
|
||||
/* quick test to prevent changing window drawable */
|
||||
static bool wm_draw_update_test_window(Main *bmain, wmWindow *win)
|
||||
static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
|
||||
{
|
||||
const wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Scene *scene = WM_window_get_active_scene(win);
|
||||
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
|
||||
struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
|
||||
@@ -861,8 +909,11 @@ static bool wm_draw_update_test_window(Main *bmain, wmWindow *win)
|
||||
ED_screen_areas_iter(win, screen, sa)
|
||||
{
|
||||
for (region = sa->regionbase.first; region; region = region->next) {
|
||||
wm_region_test_gizmo_do_draw(region, true);
|
||||
wm_region_test_gizmo_do_draw(C, sa, region, true);
|
||||
wm_region_test_render_do_draw(scene, depsgraph, sa, region);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
wm_region_test_xr_do_draw(wm, sa, region);
|
||||
#endif
|
||||
|
||||
if (region->visible && region->do_draw) {
|
||||
do_draw = true;
|
||||
@@ -890,19 +941,23 @@ static bool wm_draw_update_test_window(Main *bmain, wmWindow *win)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef WITH_XR_OPENXR
|
||||
UNUSED_VARS(wm);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear drawing flags, after drawing is complete so any draw flags set during
|
||||
* drawing don't cause any additional redraws. */
|
||||
static void wm_draw_update_clear_window(wmWindow *win)
|
||||
static void wm_draw_update_clear_window(bContext *C, wmWindow *win)
|
||||
{
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
|
||||
ED_screen_areas_iter(win, screen, sa)
|
||||
{
|
||||
for (ARegion *region = sa->regionbase.first; region; region = region->next) {
|
||||
wm_region_test_gizmo_do_draw(region, false);
|
||||
wm_region_test_gizmo_do_draw(C, sa, region, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,10 +999,10 @@ void wm_draw_update(bContext *C)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wm_draw_update_test_window(bmain, win)) {
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
CTX_wm_window_set(C, win);
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
if (wm_draw_update_test_window(bmain, C, win)) {
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
|
||||
/* sets context window+screen */
|
||||
wm_window_make_drawable(wm, win);
|
||||
@@ -956,13 +1011,16 @@ void wm_draw_update(bContext *C)
|
||||
ED_screen_ensure_updated(wm, win, screen);
|
||||
|
||||
wm_draw_window(C, win);
|
||||
wm_draw_update_clear_window(win);
|
||||
wm_draw_update_clear_window(C, win);
|
||||
|
||||
wm_window_swap_buffers(win);
|
||||
|
||||
CTX_wm_window_set(C, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CTX_wm_window_set(C, NULL);
|
||||
|
||||
/* Draw non-windows (surfaces) */
|
||||
wm_surfaces_iter(C, wm_draw_surface);
|
||||
}
|
||||
|
||||
void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(region))
|
||||
|
@@ -98,6 +98,7 @@
|
||||
#include "wm_event_system.h"
|
||||
#include "wm.h"
|
||||
#include "wm_files.h"
|
||||
#include "wm_surface.h"
|
||||
#include "wm_window.h"
|
||||
#include "wm_platform_support.h"
|
||||
|
||||
@@ -534,6 +535,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
|
||||
BKE_materials_exit();
|
||||
|
||||
wm_operatortype_free();
|
||||
wm_surfaces_free();
|
||||
wm_dropbox_free();
|
||||
WM_menutype_free();
|
||||
WM_uilisttype_free();
|
||||
|
@@ -3645,6 +3645,81 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
|
||||
{
|
||||
const bool session_exists = WM_xr_session_exists(xr_data);
|
||||
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
for (ScrArea *area = screen->areabase.first; area; area = area->next) {
|
||||
for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) {
|
||||
if (slink->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)slink;
|
||||
|
||||
if (v3d->flag & V3D_XR_SESSION_MIRROR) {
|
||||
ED_view3d_xr_mirror_update(area, v3d, session_exists);
|
||||
}
|
||||
|
||||
if (session_exists) {
|
||||
ED_view3d_xr_shading_update(bmain->wm.first, v3d);
|
||||
}
|
||||
/* Ensure no 3D View is tagged as session root. */
|
||||
else {
|
||||
v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
|
||||
{
|
||||
/* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
|
||||
wm_xr_session_update_screen(G_MAIN, xr_data);
|
||||
}
|
||||
|
||||
static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
|
||||
/* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
|
||||
if (wm_xr_init(wm) == false) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
|
||||
wm_xr_session_toggle(wm, wm_xr_session_update_screen_on_exit_cb);
|
||||
wm_xr_session_update_screen(bmain, &wm->xr);
|
||||
|
||||
WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void WM_OT_xr_session_toggle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Toggle VR Session";
|
||||
ot->idname = "WM_OT_xr_session_toggle";
|
||||
ot->description =
|
||||
"Open a view for use with virtual reality headsets, or close it if already "
|
||||
"opened";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = wm_xr_session_toggle_exec;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
|
||||
/* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
|
||||
* UI instead. Not meant as a permanent solution. */
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Registration & Keymaps
|
||||
* \{ */
|
||||
@@ -3686,6 +3761,9 @@ void wm_operatortypes_register(void)
|
||||
WM_operatortype_append(WM_OT_call_panel);
|
||||
WM_operatortype_append(WM_OT_radial_control);
|
||||
WM_operatortype_append(WM_OT_stereo3d_set);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_operatortype_append(WM_OT_xr_session_toggle);
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
WM_operatortype_append(WM_OT_console_toggle);
|
||||
#endif
|
||||
|
118
source/blender/windowmanager/intern/wm_surface.c
Normal file
118
source/blender/windowmanager/intern/wm_surface.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GPU_batch_presets.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_context.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
#include "WM_api.h"
|
||||
#include "wm.h"
|
||||
|
||||
#include "wm_surface.h"
|
||||
|
||||
static ListBase global_surface_list = {NULL, NULL};
|
||||
static wmSurface *g_drawable = NULL;
|
||||
|
||||
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
|
||||
{
|
||||
for (wmSurface *surf = global_surface_list.first; surf; surf = surf->next) {
|
||||
cb(C, surf);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_clear_drawable(void)
|
||||
{
|
||||
if (g_drawable) {
|
||||
BLF_batch_reset();
|
||||
gpu_batch_presets_reset();
|
||||
immDeactivate();
|
||||
|
||||
g_drawable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_set_drawable(wmSurface *surface, bool activate)
|
||||
{
|
||||
BLI_assert(ELEM(g_drawable, NULL, surface));
|
||||
|
||||
g_drawable = surface;
|
||||
if (activate) {
|
||||
GHOST_ActivateOpenGLContext(surface->ghost_ctx);
|
||||
}
|
||||
|
||||
GPU_context_active_set(surface->gpu_ctx);
|
||||
immActivate();
|
||||
}
|
||||
|
||||
void wm_surface_make_drawable(wmSurface *surface)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
|
||||
if (surface != g_drawable) {
|
||||
wm_surface_clear_drawable();
|
||||
wm_surface_set_drawable(surface, true);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_reset_drawable(void)
|
||||
{
|
||||
BLI_assert(BLI_thread_is_main());
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
|
||||
if (g_drawable) {
|
||||
wm_surface_clear_drawable();
|
||||
wm_surface_set_drawable(g_drawable, true);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_add(wmSurface *surface)
|
||||
{
|
||||
BLI_addtail(&global_surface_list, surface);
|
||||
}
|
||||
|
||||
void wm_surface_remove(wmSurface *surface)
|
||||
{
|
||||
BLI_remlink(&global_surface_list, surface);
|
||||
surface->free_data(surface);
|
||||
MEM_freeN(surface);
|
||||
}
|
||||
|
||||
void wm_surfaces_free(void)
|
||||
{
|
||||
for (wmSurface *surf = global_surface_list.first, *surf_next; surf; surf = surf_next) {
|
||||
surf_next = surf->next;
|
||||
wm_surface_remove(surf);
|
||||
}
|
||||
|
||||
BLI_assert(BLI_listbase_is_empty(&global_surface_list));
|
||||
}
|
@@ -1631,6 +1631,11 @@ void wm_window_process_events(const bContext *C)
|
||||
GHOST_DispatchEvents(g_system);
|
||||
}
|
||||
hasevent |= wm_window_timer(C);
|
||||
#ifdef WITH_XR_OPENXR
|
||||
/* XR events don't use the regular window queues. So here we don't only trigger
|
||||
* processing/dispatching but also handling. */
|
||||
hasevent |= wm_xr_events_handle(CTX_wm_manager(C));
|
||||
#endif
|
||||
|
||||
/* no event, we sleep 5 milliseconds */
|
||||
if (hasevent == 0) {
|
||||
@@ -1957,6 +1962,9 @@ void wm_window_raise(wmWindow *win)
|
||||
/** \name Window Buffers
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief Push rendered buffer to the screen.
|
||||
*/
|
||||
void wm_window_swap_buffers(wmWindow *win)
|
||||
{
|
||||
GHOST_SwapWindowBuffers(win->ghostwin);
|
||||
@@ -2446,3 +2454,24 @@ void WM_ghost_show_message_box(const char *title,
|
||||
GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
|
||||
}
|
||||
/** \} */
|
||||
|
||||
#ifdef WIN32
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Direct DirectX Context Management
|
||||
* \{ */
|
||||
|
||||
void *WM_directx_context_create(void)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
return GHOST_CreateDirectXContext(g_system);
|
||||
}
|
||||
|
||||
void WM_directx_context_dispose(void *context)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
GHOST_DisposeDirectXContext(g_system, context);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#endif
|
||||
|
759
source/blender/windowmanager/intern/wm_xr.c
Normal file
759
source/blender/windowmanager/intern/wm_xr.c
Normal file
@@ -0,0 +1,759 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Window-Manager XR API
|
||||
*
|
||||
* Implements Blender specific functionality for the GHOST_Xr API.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
|
||||
#include "DRW_engine.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_view3d_offscreen.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GPU_context.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_viewport.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "wm.h"
|
||||
#include "wm_surface.h"
|
||||
#include "wm_window.h"
|
||||
|
||||
struct wmXrRuntimeData *wm_xr_runtime_data_create(void);
|
||||
void wm_xr_runtime_data_free(struct wmXrRuntimeData **runtime);
|
||||
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *, void *);
|
||||
void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding);
|
||||
void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding, GHOST_ContextHandle);
|
||||
wmSurface *wm_xr_session_surface_create(wmWindowManager *, unsigned int);
|
||||
void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct wmXrSessionState {
|
||||
bool is_started;
|
||||
|
||||
/** Last known viewer pose (centroid of eyes, in world space) stored for queries. */
|
||||
GHOST_XrPose viewer_pose;
|
||||
/** The last known view matrix, calculated from above's viewer pose. */
|
||||
float viewer_viewmat[4][4];
|
||||
float focal_len;
|
||||
|
||||
/** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
|
||||
int prev_settings_flag;
|
||||
/** Copy of wmXrDrawData.eye_position_ofs. */
|
||||
float prev_eye_position_ofs[3];
|
||||
|
||||
bool is_view_data_set;
|
||||
} wmXrSessionState;
|
||||
|
||||
typedef struct wmXrRuntimeData {
|
||||
GHOST_XrContextHandle context;
|
||||
|
||||
/* Although this struct is internal, RNA gets a handle to this for state information queries. */
|
||||
wmXrSessionState session_state;
|
||||
wmXrSessionExitFn exit_fn;
|
||||
} wmXrRuntimeData;
|
||||
|
||||
typedef struct wmXrDrawData {
|
||||
/** The pose (location + rotation) to which eye deltas will be applied to when drawing (world
|
||||
* space). With positional tracking enabled, it should be the same as the base pose, when
|
||||
* disabled it also contains a location delta from the moment the option was toggled. */
|
||||
GHOST_XrPose base_pose;
|
||||
float eye_position_ofs[3]; /* Local/view space. */
|
||||
} wmXrDrawData;
|
||||
|
||||
typedef struct {
|
||||
GHOST_TXrGraphicsBinding gpu_binding_type;
|
||||
GPUOffScreen *offscreen;
|
||||
GPUViewport *viewport;
|
||||
|
||||
GHOST_ContextHandle secondary_ghost_ctx;
|
||||
} wmXrSurfaceData;
|
||||
|
||||
typedef struct {
|
||||
wmWindowManager *wm;
|
||||
} wmXrErrorHandlerData;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static wmSurface *g_xr_surface = NULL;
|
||||
static CLG_LogRef LOG = {"wm.xr"};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Context
|
||||
*
|
||||
* All XR functionality is accessed through a #GHOST_XrContext handle.
|
||||
* The lifetime of this context also determines the lifetime of the OpenXR instance, which is the
|
||||
* representation of the OpenXR runtime connection within the application.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_error_handler(const GHOST_XrError *error)
|
||||
{
|
||||
wmXrErrorHandlerData *handler_data = error->customdata;
|
||||
wmWindowManager *wm = handler_data->wm;
|
||||
|
||||
BKE_reports_clear(&wm->reports);
|
||||
WM_report(RPT_ERROR, error->user_message);
|
||||
WM_report_banner_show();
|
||||
|
||||
if (wm->xr.runtime->context) {
|
||||
/* Just play safe and destroy the entire runtime data, including context. */
|
||||
wm_xr_runtime_data_free(&wm->xr.runtime);
|
||||
}
|
||||
}
|
||||
|
||||
bool wm_xr_init(wmWindowManager *wm)
|
||||
{
|
||||
if (wm->xr.runtime && wm->xr.runtime->context) {
|
||||
return true;
|
||||
}
|
||||
static wmXrErrorHandlerData error_customdata;
|
||||
|
||||
/* Set up error handling */
|
||||
error_customdata.wm = wm;
|
||||
GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata);
|
||||
|
||||
{
|
||||
const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = {
|
||||
GHOST_kXrGraphicsOpenGL,
|
||||
#ifdef WIN32
|
||||
GHOST_kXrGraphicsD3D11,
|
||||
#endif
|
||||
};
|
||||
GHOST_XrContextCreateInfo create_info = {
|
||||
.gpu_binding_candidates = gpu_bindings_candidates,
|
||||
.gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates),
|
||||
};
|
||||
GHOST_XrContextHandle context;
|
||||
|
||||
if (G.debug & G_DEBUG_XR) {
|
||||
create_info.context_flag |= GHOST_kXrContextDebug;
|
||||
}
|
||||
if (G.debug & G_DEBUG_XR_TIME) {
|
||||
create_info.context_flag |= GHOST_kXrContextDebugTime;
|
||||
}
|
||||
|
||||
if (!(context = GHOST_XrContextCreate(&create_info))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set up context callbacks */
|
||||
GHOST_XrGraphicsContextBindFuncs(context,
|
||||
wm_xr_session_gpu_binding_context_create,
|
||||
wm_xr_session_gpu_binding_context_destroy);
|
||||
GHOST_XrDrawViewFunc(context, wm_xr_draw_view);
|
||||
|
||||
if (!wm->xr.runtime) {
|
||||
wm->xr.runtime = wm_xr_runtime_data_create();
|
||||
wm->xr.runtime->context = context;
|
||||
}
|
||||
}
|
||||
BLI_assert(wm->xr.runtime && wm->xr.runtime->context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wm_xr_exit(wmWindowManager *wm)
|
||||
{
|
||||
if (wm->xr.runtime != NULL) {
|
||||
wm_xr_runtime_data_free(&wm->xr.runtime);
|
||||
}
|
||||
if (wm->xr.session_settings.shading.prop) {
|
||||
IDP_FreeProperty(wm->xr.session_settings.shading.prop);
|
||||
wm->xr.session_settings.shading.prop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool wm_xr_events_handle(wmWindowManager *wm)
|
||||
{
|
||||
if (wm->xr.runtime && wm->xr.runtime->context) {
|
||||
return GHOST_XrEventsHandle(wm->xr.runtime->context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Context */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Runtime Data
|
||||
*
|
||||
* \{ */
|
||||
|
||||
wmXrRuntimeData *wm_xr_runtime_data_create(void)
|
||||
{
|
||||
wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__);
|
||||
return runtime;
|
||||
}
|
||||
|
||||
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
|
||||
{
|
||||
/* Note that this function may be called twice, because of an indirect recursion: If a session is
|
||||
* running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this
|
||||
* again, because it's also set as the session exit callback. So NULL-check and NULL everything
|
||||
* that is freed here. */
|
||||
|
||||
/* We free all runtime XR data here, so if the context is still alive, destroy it. */
|
||||
if ((*runtime)->context != NULL) {
|
||||
GHOST_XrContextHandle context = (*runtime)->context;
|
||||
/* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the
|
||||
* first call, see comment above. */
|
||||
(*runtime)->context = NULL;
|
||||
GHOST_XrContextDestroy(context);
|
||||
}
|
||||
MEM_SAFE_FREE(*runtime);
|
||||
}
|
||||
|
||||
static void wm_xr_base_pose_calc(const Scene *scene,
|
||||
const XrSessionSettings *settings,
|
||||
GHOST_XrPose *r_base_pose)
|
||||
{
|
||||
const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
|
||||
settings->base_pose_object) ?
|
||||
settings->base_pose_object :
|
||||
scene->camera;
|
||||
|
||||
if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
|
||||
float tmp_quatx[4], tmp_quatz[4];
|
||||
|
||||
copy_v3_v3(r_base_pose->position, settings->base_pose_location);
|
||||
axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
|
||||
axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
|
||||
mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
|
||||
}
|
||||
else if (base_pose_object) {
|
||||
float tmp_quat[4];
|
||||
float tmp_eul[3];
|
||||
|
||||
mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat);
|
||||
|
||||
/* Only use rotation around Z-axis to align view with floor. */
|
||||
quat_to_eul(tmp_eul, tmp_quat);
|
||||
tmp_eul[0] = M_PI_2;
|
||||
tmp_eul[1] = 0;
|
||||
eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(r_base_pose->position, 0.0f);
|
||||
axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_draw_data_populate(const wmXrSessionState *state,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
const XrSessionSettings *settings,
|
||||
const Scene *scene,
|
||||
wmXrDrawData *r_draw_data)
|
||||
{
|
||||
const bool position_tracking_toggled = ((state->prev_settings_flag &
|
||||
XR_SESSION_USE_POSITION_TRACKING) !=
|
||||
(settings->flag & XR_SESSION_USE_POSITION_TRACKING));
|
||||
const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
|
||||
|
||||
memset(r_draw_data, 0, sizeof(*r_draw_data));
|
||||
|
||||
wm_xr_base_pose_calc(scene, settings, &r_draw_data->base_pose);
|
||||
|
||||
if (position_tracking_toggled || !state->is_view_data_set) {
|
||||
if (use_position_tracking) {
|
||||
copy_v3_fl(r_draw_data->eye_position_ofs, 0.0f);
|
||||
}
|
||||
else {
|
||||
/* Store the current local offset (local pose) so that we can apply that to the eyes. This
|
||||
* way the eyes stay exactly where they are when disabling positional tracking. */
|
||||
copy_v3_v3(r_draw_data->eye_position_ofs, draw_view->local_pose.position);
|
||||
}
|
||||
}
|
||||
else if (!use_position_tracking) {
|
||||
/* Keep previous offset when positional tracking is disabled. */
|
||||
copy_v3_v3(r_draw_data->eye_position_ofs, state->prev_eye_position_ofs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update information that is only stored for external state queries. E.g. for Python API to
|
||||
* request the current (as in, last known) viewer pose.
|
||||
*/
|
||||
static void wm_xr_session_state_update(wmXrSessionState *state,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
const XrSessionSettings *settings,
|
||||
const wmXrDrawData *draw_data)
|
||||
{
|
||||
GHOST_XrPose viewer_pose;
|
||||
const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
|
||||
|
||||
mul_qt_qtqt(viewer_pose.orientation_quat,
|
||||
draw_data->base_pose.orientation_quat,
|
||||
draw_view->local_pose.orientation_quat);
|
||||
copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
|
||||
/* The local pose and the eye pose (which is copied from an earlier local pose) both are view
|
||||
* space, so Y-up. In this case we need them in regular Z-up. */
|
||||
viewer_pose.position[0] += draw_data->eye_position_ofs[0];
|
||||
viewer_pose.position[1] -= draw_data->eye_position_ofs[2];
|
||||
viewer_pose.position[2] += draw_data->eye_position_ofs[1];
|
||||
if (use_position_tracking) {
|
||||
viewer_pose.position[0] += draw_view->local_pose.position[0];
|
||||
viewer_pose.position[1] -= draw_view->local_pose.position[2];
|
||||
viewer_pose.position[2] += draw_view->local_pose.position[1];
|
||||
}
|
||||
|
||||
copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
|
||||
copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
|
||||
wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat);
|
||||
/* No idea why, but multiplying by two seems to make it match the VR view more. */
|
||||
state->focal_len = 2.0f *
|
||||
fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
|
||||
DEFAULT_SENSOR_WIDTH);
|
||||
|
||||
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
|
||||
state->prev_settings_flag = settings->flag;
|
||||
state->is_view_data_set = true;
|
||||
}
|
||||
|
||||
wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
|
||||
{
|
||||
return xr->runtime ? &xr->runtime->session_state : NULL;
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
zero_v3(r_location);
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
unit_qt(r_rotation);
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
|
||||
float r_viewmat[4][4],
|
||||
float *r_focal_len)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
unit_m4(r_viewmat);
|
||||
*r_focal_len = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_m4_m4(r_viewmat, xr->runtime->session_state.viewer_viewmat);
|
||||
*r_focal_len = xr->runtime->session_state.focal_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */ /* XR Runtime Data */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Session
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding graphics_binding)
|
||||
{
|
||||
wmSurface *surface = wm_xr_session_surface_create(G_MAIN->wm.first, graphics_binding);
|
||||
wmXrSurfaceData *data = surface->customdata;
|
||||
|
||||
wm_surface_add(surface);
|
||||
|
||||
/* Some regions may need to redraw with updated session state after the session is entirely up
|
||||
* and running. */
|
||||
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
|
||||
return data->secondary_ghost_ctx ? data->secondary_ghost_ctx : surface->ghost_ctx;
|
||||
}
|
||||
|
||||
void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding UNUSED(graphics_lib),
|
||||
GHOST_ContextHandle UNUSED(context))
|
||||
{
|
||||
if (g_xr_surface) { /* Might have been freed already */
|
||||
wm_surface_remove(g_xr_surface);
|
||||
}
|
||||
|
||||
wm_window_reset_drawable();
|
||||
|
||||
/* Some regions may need to redraw with updated session state after the session is entirely
|
||||
* stopped. */
|
||||
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
|
||||
}
|
||||
|
||||
static void wm_xr_session_exit_cb(void *customdata)
|
||||
{
|
||||
wmXrData *xr_data = customdata;
|
||||
|
||||
xr_data->runtime->session_state.is_started = false;
|
||||
if (xr_data->runtime->exit_fn) {
|
||||
xr_data->runtime->exit_fn(xr_data);
|
||||
}
|
||||
|
||||
/* Free the entire runtime data (including session state and context), to play safe. */
|
||||
wm_xr_runtime_data_free(&xr_data->runtime);
|
||||
}
|
||||
|
||||
static void wm_xr_session_begin_info_create(wmXrData *xr_data,
|
||||
GHOST_XrSessionBeginInfo *r_begin_info)
|
||||
{
|
||||
/* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(),
|
||||
* to allow external code to execute its own session-exit logic. */
|
||||
r_begin_info->exit_fn = wm_xr_session_exit_cb;
|
||||
r_begin_info->exit_customdata = xr_data;
|
||||
}
|
||||
|
||||
void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn)
|
||||
{
|
||||
wmXrData *xr_data = &wm->xr;
|
||||
|
||||
if (WM_xr_session_exists(xr_data)) {
|
||||
GHOST_XrSessionEnd(xr_data->runtime->context);
|
||||
}
|
||||
else {
|
||||
GHOST_XrSessionBeginInfo begin_info;
|
||||
|
||||
xr_data->runtime->session_state.is_started = true;
|
||||
xr_data->runtime->exit_fn = session_exit_fn;
|
||||
|
||||
wm_xr_session_begin_info_create(xr_data, &begin_info);
|
||||
GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the XR-Session was triggered.
|
||||
* If an error happened while trying to start a session, this returns false too.
|
||||
*/
|
||||
bool WM_xr_session_exists(const wmXrData *xr)
|
||||
{
|
||||
return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the session is running, according to the OpenXR definition.
|
||||
*/
|
||||
bool WM_xr_session_is_ready(const wmXrData *xr)
|
||||
{
|
||||
return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Session */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Session Surface
|
||||
*
|
||||
* A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the
|
||||
* session.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief Call Ghost-XR to draw a frame
|
||||
*
|
||||
* Draw callback for the XR-session surface. It's expected to be called on each main loop iteration
|
||||
* and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view,
|
||||
* #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()).
|
||||
*/
|
||||
static void wm_xr_session_surface_draw(bContext *C)
|
||||
{
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
|
||||
return;
|
||||
}
|
||||
DRW_xr_drawing_begin();
|
||||
GHOST_XrSessionDrawViews(wm->xr.runtime->context, C);
|
||||
GPU_offscreen_unbind(surface_data->offscreen, false);
|
||||
DRW_xr_drawing_end();
|
||||
}
|
||||
|
||||
static void wm_xr_session_free_data(wmSurface *surface)
|
||||
{
|
||||
wmXrSurfaceData *data = surface->customdata;
|
||||
|
||||
if (data->secondary_ghost_ctx) {
|
||||
#ifdef WIN32
|
||||
if (data->gpu_binding_type == GHOST_kXrGraphicsD3D11) {
|
||||
WM_directx_context_dispose(data->secondary_ghost_ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (data->viewport) {
|
||||
GPU_viewport_free(data->viewport);
|
||||
}
|
||||
if (data->offscreen) {
|
||||
GPU_offscreen_free(data->offscreen);
|
||||
}
|
||||
|
||||
MEM_freeN(surface->customdata);
|
||||
|
||||
g_xr_surface = NULL;
|
||||
}
|
||||
|
||||
static bool wm_xr_session_surface_offscreen_ensure(const GHOST_XrDrawViewInfo *draw_view)
|
||||
{
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
const bool size_changed = surface_data->offscreen &&
|
||||
(GPU_offscreen_width(surface_data->offscreen) != draw_view->width) &&
|
||||
(GPU_offscreen_height(surface_data->offscreen) != draw_view->height);
|
||||
char err_out[256] = "unknown";
|
||||
bool failure = false;
|
||||
|
||||
if (surface_data->offscreen) {
|
||||
BLI_assert(surface_data->viewport);
|
||||
|
||||
if (!size_changed) {
|
||||
return true;
|
||||
}
|
||||
GPU_viewport_free(surface_data->viewport);
|
||||
GPU_offscreen_free(surface_data->offscreen);
|
||||
}
|
||||
|
||||
if (!(surface_data->offscreen = GPU_offscreen_create(
|
||||
draw_view->width, draw_view->height, 0, true, false, err_out))) {
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
/* Pass. */
|
||||
}
|
||||
else if (!(surface_data->viewport = GPU_viewport_create())) {
|
||||
GPU_offscreen_free(surface_data->offscreen);
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wmSurface *wm_xr_session_surface_create(wmWindowManager *UNUSED(wm), unsigned int gpu_binding_type)
|
||||
{
|
||||
if (g_xr_surface) {
|
||||
BLI_assert(false);
|
||||
return g_xr_surface;
|
||||
}
|
||||
|
||||
wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
|
||||
wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
|
||||
|
||||
#ifndef WIN32
|
||||
BLI_assert(gpu_binding_type == GHOST_kXrGraphicsOpenGL);
|
||||
#endif
|
||||
|
||||
surface->draw = wm_xr_session_surface_draw;
|
||||
surface->free_data = wm_xr_session_free_data;
|
||||
|
||||
data->gpu_binding_type = gpu_binding_type;
|
||||
surface->customdata = data;
|
||||
|
||||
surface->ghost_ctx = DRW_xr_opengl_context_get();
|
||||
|
||||
switch (gpu_binding_type) {
|
||||
case GHOST_kXrGraphicsOpenGL:
|
||||
break;
|
||||
#ifdef WIN32
|
||||
case GHOST_kXrGraphicsD3D11:
|
||||
data->secondary_ghost_ctx = WM_directx_context_create();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
surface->gpu_ctx = DRW_xr_gpu_context_get();
|
||||
|
||||
g_xr_surface = surface;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Session Surface */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Drawing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4])
|
||||
{
|
||||
float iquat[4];
|
||||
invert_qt_qt_normalized(iquat, pose->orientation_quat);
|
||||
quat_to_mat4(r_viewmat, iquat);
|
||||
translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]);
|
||||
}
|
||||
|
||||
static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
|
||||
const GHOST_XrDrawViewInfo *draw_view,
|
||||
const XrSessionSettings *session_settings,
|
||||
float r_view_mat[4][4],
|
||||
float r_proj_mat[4][4])
|
||||
{
|
||||
GHOST_XrPose eye_pose;
|
||||
|
||||
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
|
||||
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
|
||||
add_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
|
||||
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
|
||||
sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
|
||||
}
|
||||
|
||||
perspective_m4_fov(r_proj_mat,
|
||||
draw_view->fov.angle_left,
|
||||
draw_view->fov.angle_right,
|
||||
draw_view->fov.angle_up,
|
||||
draw_view->fov.angle_down,
|
||||
session_settings->clip_start,
|
||||
session_settings->clip_end);
|
||||
|
||||
float eye_mat[4][4];
|
||||
float base_mat[4][4];
|
||||
|
||||
wm_xr_pose_to_viewmat(&eye_pose, eye_mat);
|
||||
/* Calculate the base pose matrix (in world space!). */
|
||||
wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat);
|
||||
|
||||
mul_m4_m4m4(r_view_mat, eye_mat, base_mat);
|
||||
}
|
||||
|
||||
static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
|
||||
const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
|
||||
{
|
||||
const bool is_upside_down = surface_data->secondary_ghost_ctx &&
|
||||
GHOST_isUpsideDownContext(surface_data->secondary_ghost_ctx);
|
||||
rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1};
|
||||
|
||||
wmViewport(&rect);
|
||||
|
||||
/* For upside down contexts, draw with inverted y-values. */
|
||||
if (is_upside_down) {
|
||||
SWAP(int, rect.ymin, rect.ymax);
|
||||
}
|
||||
GPU_viewport_draw_to_screen_ex(surface_data->viewport, &rect, draw_view->expects_srgb_buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draw a viewport for a single eye.
|
||||
*
|
||||
* This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
|
||||
* callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
|
||||
*/
|
||||
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
||||
{
|
||||
bContext *C = customdata;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
wmXrSessionState *session_state = &wm->xr.runtime->session_state;
|
||||
XrSessionSettings *settings = &wm->xr.session_settings;
|
||||
wmXrDrawData draw_data;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
|
||||
|
||||
float viewmat[4][4], winmat[4][4];
|
||||
|
||||
BLI_assert(WM_xr_session_is_ready(&wm->xr));
|
||||
|
||||
wm_xr_draw_data_populate(session_state, draw_view, settings, scene, &draw_data);
|
||||
wm_xr_draw_matrices_create(&draw_data, draw_view, settings, viewmat, winmat);
|
||||
wm_xr_session_state_update(session_state, draw_view, settings, &draw_data);
|
||||
|
||||
if (!wm_xr_session_surface_offscreen_ensure(draw_view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* In case a framebuffer is still bound from drawing the last eye. */
|
||||
GPU_framebuffer_restore();
|
||||
/* Some systems have drawing glitches without this. */
|
||||
GPU_clear(GPU_DEPTH_BIT);
|
||||
|
||||
/* Draws the view into the surface_data->viewport's framebuffers */
|
||||
ED_view3d_draw_offscreen_simple(CTX_data_ensure_evaluated_depsgraph(C),
|
||||
scene,
|
||||
&wm->xr.session_settings.shading,
|
||||
wm->xr.session_settings.shading.type,
|
||||
draw_view->width,
|
||||
draw_view->height,
|
||||
display_flags,
|
||||
viewmat,
|
||||
winmat,
|
||||
settings->clip_start,
|
||||
settings->clip_end,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
NULL,
|
||||
false,
|
||||
surface_data->offscreen,
|
||||
surface_data->viewport);
|
||||
|
||||
/* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
|
||||
* call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
|
||||
* viewport buffers composited together and potentially color managed for display on screen.
|
||||
* It needs a bound framebuffer to draw into, for which we simply reuse the GPUOffscreen one.
|
||||
*
|
||||
* In a next step, Ghost-XR will use the the currently bound framebuffer to retrieve the image to
|
||||
* be submitted to the OpenXR swapchain. So do not un-bind the offscreen yet! */
|
||||
|
||||
GPU_offscreen_bind(surface_data->offscreen, false);
|
||||
|
||||
wm_xr_draw_viewport_buffers_to_active_framebuffer(surface_data, draw_view);
|
||||
}
|
||||
|
||||
/** \} */ /* XR Drawing */
|
@@ -98,4 +98,14 @@ void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
|
||||
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
|
||||
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
|
||||
|
||||
/* wm_xr.c */
|
||||
bool wm_xr_init(wmWindowManager *wm);
|
||||
void wm_xr_exit(wmWindowManager *wm);
|
||||
void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn);
|
||||
bool wm_xr_events_handle(wmWindowManager *wm);
|
||||
#endif
|
||||
|
||||
#endif /* __WM_H__ */
|
||||
|
57
source/blender/windowmanager/wm_surface.h
Normal file
57
source/blender/windowmanager/wm_surface.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name WM-Surface
|
||||
*
|
||||
* Container to manage painting in an offscreen context.
|
||||
*/
|
||||
|
||||
#ifndef __WM_SURFACE_H__
|
||||
#define __WM_SURFACE_H__
|
||||
|
||||
struct bContext;
|
||||
|
||||
typedef struct wmSurface {
|
||||
struct wmSurface *next, *prev;
|
||||
|
||||
GHOST_ContextHandle ghost_ctx;
|
||||
struct GPUContext *gpu_ctx;
|
||||
|
||||
void *customdata;
|
||||
|
||||
void (*draw)(struct bContext *);
|
||||
/** Free customdata, not the surface itself (done by wm_surface API) */
|
||||
void (*free_data)(struct wmSurface *);
|
||||
} wmSurface;
|
||||
|
||||
/* Create/Free */
|
||||
void wm_surface_add(wmSurface *surface);
|
||||
void wm_surface_remove(wmSurface *surface);
|
||||
void wm_surfaces_free(void);
|
||||
|
||||
/* Utils */
|
||||
void wm_surfaces_iter(struct bContext *C, void (*cb)(bContext *, wmSurface *));
|
||||
|
||||
/* Drawing */
|
||||
void wm_surface_make_drawable(wmSurface *surface);
|
||||
void wm_surface_clear_drawable(void);
|
||||
void wm_surface_set_drawable(wmSurface *surface, bool activate);
|
||||
void wm_surface_reset_drawable(void);
|
||||
|
||||
#endif /* __WM_SURFACE_H__ */
|
@@ -111,6 +111,10 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
endif()
|
||||
|
||||
# Setup the exe sources and buildinfo
|
||||
set(SRC
|
||||
creator.c
|
||||
@@ -856,6 +860,8 @@ elseif(WIN32)
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_debug_gpu_glitchworkaround.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_debug_log.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_factory_startup.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_oculus.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/oculus.json
|
||||
DESTINATION "."
|
||||
)
|
||||
|
||||
|
@@ -603,6 +603,10 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
|
||||
BLI_argsPrintArgDoc(ba, "--debug-gpu-shaders");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-gpu-force-workarounds");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-wm");
|
||||
# ifdef WITH_XR_OPENXR
|
||||
BLI_argsPrintArgDoc(ba, "--debug-xr");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-xr-time");
|
||||
# endif
|
||||
BLI_argsPrintArgDoc(ba, "--debug-all");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-io");
|
||||
|
||||
@@ -940,6 +944,16 @@ static const char arg_handle_debug_mode_generic_set_doc_wm[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for the window manager, shows all operators in search, shows "
|
||||
"keymap errors.";
|
||||
# ifdef WITH_XR_OPENXR
|
||||
static const char arg_handle_debug_mode_generic_set_doc_xr[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for virtual reality contexts.\n"
|
||||
"\tEnables the OpenXR API validation layer, (OpenXR) debug messages and general information "
|
||||
"prints.";
|
||||
static const char arg_handle_debug_mode_generic_set_doc_xr_time[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for virtual reality frame rendering times.";
|
||||
# endif
|
||||
static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
|
||||
"\n\t"
|
||||
"Enable time profiling for background jobs.";
|
||||
@@ -2091,6 +2105,16 @@ void main_args_setup(bContext *C, bArgs *ba)
|
||||
(void *)G_DEBUG_HANDLERS);
|
||||
BLI_argsAdd(
|
||||
ba, 1, NULL, "--debug-wm", CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
|
||||
# ifdef WITH_XR_OPENXR
|
||||
BLI_argsAdd(
|
||||
ba, 1, NULL, "--debug-xr", CB_EX(arg_handle_debug_mode_generic_set, xr), (void *)G_DEBUG_XR);
|
||||
BLI_argsAdd(ba,
|
||||
1,
|
||||
NULL,
|
||||
"--debug-xr-time",
|
||||
CB_EX(arg_handle_debug_mode_generic_set, xr_time),
|
||||
(void *)G_DEBUG_XR_TIME);
|
||||
# endif
|
||||
BLI_argsAdd(ba,
|
||||
1,
|
||||
NULL,
|
||||
|
@@ -50,6 +50,9 @@ def _init_addon_blacklist():
|
||||
# netrender has known problems re-registering
|
||||
BLACKLIST_ADDONS.add("netrender")
|
||||
|
||||
if not bpy.app.build_options.xr_openxr:
|
||||
BLACKLIST_ADDONS.add("viewport_vr_preview")
|
||||
|
||||
for mod in addon_utils.modules():
|
||||
if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0):
|
||||
BLACKLIST_ADDONS.add(mod.__name__)
|
||||
|
@@ -56,6 +56,9 @@ MODULE_SYS_PATHS = {
|
||||
if not bpy.app.build_options.freestyle:
|
||||
BLACKLIST.add("render_freestyle_svg")
|
||||
|
||||
if not bpy.app.build_options.xr_openxr:
|
||||
BLACKLIST.add("viewport_vr_preview")
|
||||
|
||||
BLACKLIST_DIRS = (
|
||||
os.path.join(bpy.utils.resource_path('USER'), "scripts"),
|
||||
) + tuple(addon_utils.paths()[1:])
|
||||
|
Reference in New Issue
Block a user