Compare commits

...

573 Commits

Author SHA1 Message Date
46b91b2dda Fix warning when compiling without WITH_XR_OPENXR 2020-03-17 20:09:35 +01:00
3a73aba822 Change 'make update' back to use the master add-ons branch 2020-03-17 18:52:20 +01:00
f0ccb6ab46 Fix crash when rendering Eevee/Workbench while VR session runs
We have to set the main draw-manager mutex.

Also some related cleanup.
2020-03-17 16:54:53 +01:00
2f2f587881 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-17 16:40:16 +01:00
99eb95337f Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-17 16:40:07 +01:00
3f114cd229 Revert changes to generalize 3D View Shading options button layout 2020-03-17 16:36:34 +01:00
5d30598e3b Make it obvious that the DRW context getters are not for general use 2020-03-17 16:28:29 +01:00
a7e3b04e7a Fix compile error when compiling with WITH_XR_OPENXR disabled (tm) 2020-03-17 15:50:40 +01:00
1792bf1c0a Always sync VR view shading with the 3D View the session was started in
Added a notifier subtype so that we can avoid unnecesarry updates of the
VR shading settings.
The VR session now needs to be invoked from a 3D View.
2020-03-17 15:44:41 +01:00
cd083a67c2 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-16 22:07:23 +01:00
1a7135b12f Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-16 22:07:02 +01:00
ae14649583 Fix comment being printed to console in Windows batch file 2020-03-16 22:00:36 +01:00
4586813de6 Cleanup: Use "Viewer Pose" not just "Viewer" 2020-03-16 21:44:25 +01:00
860adf13ed Cleanup: Rename gizmo-group-type flag for continuous redraws 2020-03-16 21:23:27 +01:00
97c929a88f Always read/write XR data, even with WITH_XR_OPENXR disabled 2020-03-16 18:18:54 +01:00
5c1ac85ba5 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-16 18:15:33 +01:00
a75a79272e Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-16 18:15:10 +01:00
ddbbd9928e Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-16 18:14:24 +01:00
d2ef342b2a Merge branch 'master' into temp-openxr-ghostxr 2020-03-16 18:13:37 +01:00
d16897eb2e Fix use-after-free when opening file with VR session running 2020-03-16 18:10:34 +01:00
e9ef555c97 Fix build error with WITH_XR_OPENXR disabled 2020-03-16 17:49:42 +01:00
5d8906fbe5 Fix compile errors and wrong pointer use 2020-03-16 17:26:32 +01:00
Julian Eisel
fb8ff0c112 Enable fixed world space lighting by default
Also make the button for it optional in the UI (the VR Add-on will hide
it for now).
2020-03-16 14:09:37 +01:00
Julian Eisel
1fab889a40 Fix crash when closing Blender with active VR session
On Windows I still get a crash in some Windows library inside the exit()
call, even though Blender shuts just fine. Not sure where that's coming
from.
2020-03-16 11:12:35 +01:00
Julian Eisel
03c9039e8b Cleanup: Improve naming of session state queries 2020-03-15 03:41:08 +01:00
Julian Eisel
7bdd12e20c Fix multiple issues when closing session from OpenXR runtime
We only managed Ghost-XR data then, not Blender side data. E.g. if there
was a VR mirror, its 3D View would remain locked then (disallowing
navigation).
2020-03-15 02:54:59 +01:00
Julian Eisel
60bcfbef40 Cleanup: Change misleading name 2020-03-15 02:08:53 +01:00
Julian Eisel
8a87e48b18 Refactor runtime data storage, for OpenXR side session ending
Right now, ending the session via the OpenXR runtime (e.g. closing the
WinMR Portal while the Blender VR session runs) causes multiple issues.
We need a way to properly react to session end events. Changes here
prepare us for that.
2020-03-15 02:02:42 +01:00
Julian Eisel
98e61078d3 Fix crash with some 3D View operators (e.g. Zoom to Border)
Would do a NULL-ptr dereference if the VR mirror option is enabled.
2020-03-14 23:09:34 +01:00
Julian Eisel
8093667d5a Fix VR mirror not redrawing continuously on some systems
Void pointers....

Mistake in 3bc41d2f50.
2020-03-14 22:50:48 +01:00
Julian Eisel
3eef47a26b Fix broken Positional Tracking toggle behavior
Probably broken since c18d503205.
2020-03-14 22:37:44 +01:00
Julian Eisel
4be3e48a80 Fix mistake in earlier commit
Misstake in 3b693a9aac.
2020-03-14 22:20:55 +01:00
Julian Eisel
f7a03d97ce Fix compile error and warning with WITH_XR_OPENXR disabled 2020-03-14 20:07:02 +01:00
Julian Eisel
3b693a9aac Fix memory errors and drawing glitches on some systems 2020-03-14 19:53:40 +01:00
Julian Eisel
8e841ed71e Fix warning on MSVC 2020-03-14 18:52:20 +01:00
29addd4360 Use preview quality settings for Eevee in VR, not high-quality ones
The high-quality settings are designed for actual renderings. We use the
same offscreen routines as these, but want the preview quality for
performance.

Brings performance from < 1FPS to ~40FPS in the classroom scene here.
2020-03-13 18:07:58 +01:00
3bc41d2f50 Force continuous redraws of mirrored 3D Views 2020-03-13 13:03:37 +01:00
5ea28551cb Refactor sharing of 3D View Shading layout 2020-03-13 12:28:39 +01:00
27774c3e0d Fix division-by-zero on session start with VR mirror enabled 2020-03-12 18:48:50 +01:00
67da109882 Remove unnecessary code, forgot to remove earlier 2020-03-12 17:44:58 +01:00
b86be9b214 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-12 15:58:03 +01:00
cb6cec904f Merge branch 'master' into temp-openxr-ghostxr 2020-03-12 15:55:48 +01:00
1a07728c99 Refactor XR mirror toggling some more 2020-03-12 14:45:18 +01:00
f4b6ce38a4 Fix XR toggle possibly starting already started session 2020-03-12 13:12:38 +01:00
d5af5dbcde Refactor how the user region is obtained in quad view 2020-03-12 13:12:38 +01:00
97c33d3670 Refactor XR mirror toggling 2020-03-12 13:12:38 +01:00
4ad5449c92 Refactor XR mirror toggling 2020-03-12 12:23:28 +01:00
e07f2aec7e Refactor RegionView3D runtime lock flag handling 2020-03-11 22:17:19 +01:00
5bcb37c3b7 Cleanup: Rename zoom/dolly lock flag 2020-03-11 20:59:27 +01:00
e2bf7b1564 Don't return uninitialized values when early-exiting 2020-03-11 20:54:16 +01:00
daa98f8978 Keep VR view grid aligned, even if there's no camera 2020-03-11 20:48:35 +01:00
61a5fcc83a Fix uninitialized variables when WITH_XR_OPENXR is disabled 2020-03-11 20:40:42 +01:00
39107d3ed1 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-11 20:36:19 +01:00
a79b731edc Fix possible error with base pose object on undo or Load UI disabled 2020-03-11 20:25:20 +01:00
4deee5c00c Fix missing IDProperty freeing for View3DShading settings 2020-03-11 20:14:48 +01:00
5333441eb1 Cleanup, naming, comments, etc 2020-03-11 19:32:40 +01:00
dd8ef89633 Remove leftover from merge conflict 2020-03-11 16:31:50 +01:00
5cca2f041d Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-11 16:28:43 +01:00
00f83ec125 Cleanup and correct wrong bpy.app.build_options usage 2020-03-11 16:27:48 +01:00
a2d04deda7 Remove in-place call to create reports-popup
To be replaced by D7113.
2020-03-11 15:34:49 +01:00
8f327fb070 Cleanup: Add comments on GPU data and Ghost context usage 2020-03-11 14:14:27 +01:00
f8c3ccf398 Add more info to blender_oculus batch file 2020-03-11 12:35:18 +01:00
7c11e45f5f Cleanup: Address various review comments 2020-03-11 12:34:23 +01:00
792335cfab Cleanup: Run clang-format on all affected files 2020-03-11 11:26:42 +01:00
b381eba6c7 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-11 11:26:05 +01:00
066d755e47 Cleanup: Clang-format 2020-03-11 11:25:49 +01:00
f2018ba492 Cleanup: Remove unused Ghost window function 2020-03-11 11:23:59 +01:00
Julian Eisel
f07cd66ca1 Fix incorrect versioning code after merge conflicts 2020-03-11 01:25:16 +01:00
80b15a44b6 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-10 18:25:20 +01:00
8126e4ac14 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-10 18:23:46 +01:00
cfa4302570 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-10 18:23:32 +01:00
e7ceb041cf Merge branch 'master' into temp-openxr-ghostxr 2020-03-10 18:22:40 +01:00
32bdfa0e06 Remove temporary hack to allow forcing gizmo redraws through anim play 2020-03-10 17:26:39 +01:00
c18d503205 Cleanup: Reorganize state structs, naming, unused functions, etc 2020-03-10 17:17:29 +01:00
Julian Eisel
c02ba3653a Color transforms were fixed in Windows MR -> disable our workaround 2020-03-10 16:48:18 +01:00
6472edb2c8 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-10 16:43:20 +01:00
5aedfd12cd Remove old files/changes, git keeps bringing them back... 2020-03-10 16:41:09 +01:00
7d9731ef7d Minor cleanup: Avoid forward declaration 2020-03-10 16:39:29 +01:00
6ae0839879 Remove obscure unique_oxr_ptr, implement alternative RAII for swapchain
Add an own class for the swapchain, through which we can ensure correct
RAII resource management.
2020-03-10 16:39:28 +01:00
1e2253a8da Cleanup: Avoid macros, don't print source location for errors 2020-03-10 16:37:53 +01:00
5419542260 Cleanup: Address various review comments 2020-03-10 16:37:53 +01:00
cd35a7b7d5 Add comments to C-API function declarations 2020-03-10 16:37:18 +01:00
9abf5ba1d5 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-10 16:34:26 +01:00
1cc81d39c4 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-10 16:21:15 +01:00
e38cd1741e Remove old files/changes, git keeps bringing them back... 2020-03-10 16:11:44 +01:00
27bc3388da Minor cleanup: Avoid forward declaration 2020-03-10 16:05:06 +01:00
8b8142c13a Remove obscure unique_oxr_ptr, implement alternative RAII for swapchain
Add an own class for the swapchain, through which we can ensure correct
RAII resource management.
2020-03-10 16:00:06 +01:00
Julian Eisel
0315159501 Minor cleanup: Use r_ prefix for return arguments 2020-03-10 01:40:43 +01:00
d60c71f33d Cleanup: Avoid macros, don't print source location for errors 2020-03-09 18:58:20 +01:00
916efac0c8 Cleanup: Address various review comments 2020-03-09 18:47:31 +01:00
ef20e1d378 Add comments to C-API function declarations 2020-03-09 18:37:16 +01:00
262b1efd15 Avoid queries on inaccessible session state
On the Blender side we now use a more narrow definition of when a
session is considered running than the OpenXR specification does.

Also does related cleanup.
2020-03-09 14:57:43 +01:00
27cdc66484 Fix shading options missing in 3D View popover
Wasn't actually returning the poll() result during regular usage (i.e.
not re-used for scene or VR view shading options).
2020-03-09 12:48:06 +01:00
549a5fd661 Fix use-after-free when closing Blender with running VR session
Somehow two wm_xr_data_destroy() calls ended up there, probably a merge
conflict.
2020-03-09 12:41:02 +01:00
814931d27d Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-09 12:20:36 +01:00
f73a6c517c Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-09 11:56:13 +01:00
6e13062ddb Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-09 11:55:47 +01:00
73791a755a Merge branch 'master' into temp-openxr-ghostxr 2020-03-09 11:31:48 +01:00
Julian Eisel
da10812f25 Enable WITH_XR_OPENXR by default 2020-03-05 13:03:25 +01:00
Julian Eisel
8c31727298 Fix build error and warnings when WITH_XR_OPENXR is disabled 2020-03-05 13:00:55 +01:00
Julian Eisel
247c691d69 Add XR_ prefix like now in master 2020-03-05 12:46:21 +01:00
Julian Eisel
1c49f0cc20 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-05 12:41:41 +01:00
Julian Eisel
28321b064a Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-05 12:40:18 +01:00
Julian Eisel
10d563baf4 Add XR_ prefix like now in master 2020-03-05 12:36:40 +01:00
Julian Eisel
812c4f45f5 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-05 12:32:54 +01:00
Julian Eisel
75163f2a7d Add XR_ prefix like now in master 2020-03-05 12:20:27 +01:00
Julian Eisel
3c0c28afe1 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-03-05 12:11:16 +01:00
Julian Eisel
4ecea3dd3e Merge branch 'master' into temp-openxr-directx 2020-03-05 12:10:58 +01:00
Julian Eisel
25b3287ce6 Support mirroring the VR view in regular 3D Views
Adds a per 3D View option to mirror the 3D session view. When enabled,
the viewport (continuously) renders using the same location and rotation
as the 3D view. While navigation is disabled then, other interactions
are working, so you can select and edit data as usual.
To be precise, we use the pose of the centroid, not the ones used by the
eyes.

Extra attention was put into forbidding viewport navigation while the VR
mirror runs (it overrides the current viewpoint anyway). Tried to make
this a generic feature. There may still be some navigation operators
that are not covered. So using them while the mirror runs will have an
affect on what you see once you end the session or mirroring.

Quadview is preserved, only the un-locked view shows the mirror then.
All of this is runtime data, no state changes should end up being read
from saved files.
2020-03-03 18:38:44 +01:00
Julian Eisel
ba254334f0 Fix build error after changes from last merge 2020-03-02 15:50:27 +01:00
Julian Eisel
463fe7c949 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-03-02 15:49:36 +01:00
Julian Eisel
68cec61dae Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-03-02 15:30:09 +01:00
Julian Eisel
c822556e27 Update oculus.json file for the Oculus runtime on Windows 2020-03-02 15:12:53 +01:00
Julian Eisel
e62a012f90 Fix compiler warning on Linux, swapping with wrong type 2020-03-02 14:51:20 +01:00
Julian Eisel
be7b41df3f Bring back vertically mirrored drawing for DirectX compatibility 2020-03-02 14:51:12 +01:00
Julian Eisel
6f977c5e6d Always do versioning code, even with WITH_OPENXR disabled 2020-03-02 14:41:56 +01:00
Julian Eisel
a74af5f6f0 Always generate XR-RNA, even with WITH_OPENXR disabled 2020-03-02 14:39:12 +01:00
Julian Eisel
3e41ea03be Cleanup: Move struct forward declaration to top of header 2020-03-02 14:31:01 +01:00
Julian Eisel
489da13b94 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-03-02 12:59:24 +01:00
Julian Eisel
f9a3a42412 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-03-02 12:52:41 +01:00
Julian Eisel
202623419e Use GL_NEAREST as interpolation mode for framebuffer blitting 2020-03-02 12:41:01 +01:00
Julian Eisel
49f7848589 Avoid clearing render-target on each redraw in release builds 2020-03-02 12:40:14 +01:00
Julian Eisel
6fda295034 Add comment on DirectX device debugging 2020-03-02 12:39:38 +01:00
Julian Eisel
2b7e94e35e Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-03-02 12:07:58 +01:00
Julian Eisel
65ceb8ee5d Don't attempt to force enable WITH_OPENXR on macOS 2020-03-02 11:01:26 +01:00
Julian Eisel
9b5a1edbc4 Remove unnecessary CMake search hints 2020-03-02 11:00:41 +01:00
Julian Eisel
6cceecb82f Mark WITH_OPENXR as advanced on macOS 2020-03-02 11:00:01 +01:00
Julian Eisel
166c1f9a92 Merge branch 'master' into temp-openxr-buildstuff 2020-03-02 10:46:59 +01:00
Julian Eisel
d65ce022b6 Fix stereo rendering broken without positional tracking
This required me to rework reference pose handling once more. The result
seems to work very well though, much more stable and glitch-free than it
used to.
2020-02-28 17:22:04 +01:00
Julian Eisel
3da9ecc6c1 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-26 21:19:59 +01:00
Julian Eisel
0f979f3388 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-02-26 21:19:35 +01:00
Julian Eisel
72ad66b101 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-02-26 21:19:23 +01:00
Julian Eisel
f25a348915 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-02-26 21:19:09 +01:00
Julian Eisel
af00df3469 Update OpenXR SDK dependency to version 1.0.6
Also fix a merge error in install_deps.sh
2020-02-26 21:18:10 +01:00
Julian Eisel
80c6f6eb4e Merge branch 'master' into temp-openxr-buildstuff 2020-02-26 21:17:04 +01:00
Julian Eisel
e583eee37c Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-02-25 14:46:52 +01:00
Julian Eisel
62db972f0f Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-25 14:43:41 +01:00
Julian Eisel
e9036242fa Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-02-25 14:42:29 +01:00
Julian Eisel
83aebf759e Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-02-25 14:38:08 +01:00
Julian Eisel
5169f9e975 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-02-25 14:37:52 +01:00
Julian Eisel
d9c05e6997 Merge branch 'master' into temp-openxr-buildstuff 2020-02-25 14:36:28 +01:00
Julian Eisel
d205f36906 Tag for gizmo-redraws only for continuous gizmo redraws
Note that this still doesn't make any difference in what we actually
redraw, hopefully soon it will.
2020-02-24 17:15:08 +01:00
Julian Eisel
85e5bbe0a0 Fix continuous viewport redrawing (even without VR session running)
With the VR add-on enabled, the viewport would constantly redraw.
Thought we'd only create gizmo-group instances for groups where the poll
function was successfully executed, but that's not the case. So we still
need to execute the poll and prepare context for that.
2020-02-24 17:08:31 +01:00
Julian Eisel
d0d0cc998e Fix compiler warning on Linux, swapping with wrong type 2020-02-24 15:09:39 +01:00
Julian Eisel
f1e51c14e8 Fix scene lighting and shadow options having no effect 2020-02-20 13:13:32 +01:00
Julian Eisel
12b405cd55 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-02-20 13:00:58 +01:00
580230f0c5 Fix some issues with versionning of older files.
Consequences of own refactor of usercount handling in readfile.c
(rB367ecff15d74).

Not super happy to have to call that function twice, but that should be
OK (not a real overhead here anyway).
2020-02-20 13:00:36 +01:00
fedb339eb7 CMake: Suppress strict warnings for extern on macOS
Silences a lot of noise from Mantaflow.
2020-02-20 13:00:36 +01:00
43ad16701f Fix ushort compiler errors in Windows
ushort is not supported
2020-02-20 13:00:36 +01:00
b1d7085641 Modifiers: Refactor Mask modifier
The functionality of the mask modifier remains unchanged.

This patch updates the mask modifier so that it uses C++.
The manual memory management has been replaced with proper containers.
The large `applyModifier` function has been splitup into multiple smaller functions.
A large speedup is achieved by using simple arrays instead of hash tables in multiple places.

In my performance test file the playback speed increased from 1.1 to 5.1 fps on my laptop.

Reviewers: campbellbarton, brecht

Differential Revision: https://developer.blender.org/D6779
2020-02-20 13:00:36 +01:00
2686bc8383 Cleanup: use named unsigned types in the Python API 2020-02-20 13:00:36 +01:00
dff31a5548 mathutils: support for to_2x2 as well as non-square matrices 2020-02-20 13:00:36 +01:00
Tiago Chaves
38e75093a8 mathutils: support Vector.rotate for 2D vectors 2020-02-20 13:00:36 +01:00
Tiago Chaves
e70e26043a BLI_math: add 2x2 matrix utilities 2020-02-20 13:00:36 +01:00
93bb8ef737 Cleanup: rename mul_m2v2 to mul_m2_v2
Matches mul_m3_v3
2020-02-20 13:00:36 +01:00
9124e2bfa3 Fix missing error message on convex hull failure
Also remove unused errors.
2020-02-20 13:00:36 +01:00
7c6f2e5683 Cleanup: remove use of 'register'
This isn't needed with modern compilers.
2020-02-20 13:00:36 +01:00
8a4671e5ed Cleanup: unused structs 2020-02-20 13:00:36 +01:00
c7a90ea656 Cleanup: unused enums 2020-02-20 13:00:18 +01:00
22afd42cc2 Cleanup: declatatuons for functions that don't exist 2020-02-20 13:00:18 +01:00
ee9815b8af Fix T65640: Axis of Custom Shape Bones are drawn in a wrong position.
The problem is that Custom Shape Bones can also have a custom size.
So the pchan->disp_mat doesn't always consider the actual length of the bone.
The proposed solution is to calculate the axes matrix at the drawing pass.

Ref T65640

Reviewed By: fclem

Differential Revision: http://developer.blender.org/D5049
2020-02-20 13:00:18 +01:00
dd1a89e156 Fix T74019 Eevee High Quality Normals causing pitch black faces
Was due to a mistake when removing previous code...
2020-02-20 13:00:18 +01:00
5a60ac152d DRW: Fix facing reset when drawing with inverted camera 2020-02-20 13:00:18 +01:00
Julian Eisel
4d31095fde RNA: Fail makesrna if enum identifiers contain spaces
We could of course always add checks for more invalid characters, but
I'd say they are more unlikely to happen.
2020-02-20 13:00:18 +01:00
Julian Eisel
7864aa7e86 Fix compile error when building with Cycles 2020-02-20 13:00:18 +01:00
19638bf00e DRW: Support inverted view matrix
We detect the case where we need to invert the facing directly inside the
DRWView update and do the appropriate GL calls at draw time.

Fix T63047 Camera with negative scale works only in Cycles Rendered view
Fix T71352 Negative scale camera causes BLI_assert
2020-02-20 13:00:18 +01:00
57d29dc196 Fluid: Temporary fix for gzopen on windows
Needs more consideration. This fixes compilation for now.
2020-02-20 13:00:18 +01:00
1cf049fd4b Theme: Radial gradient background and enum for gradient type
This commit replaces the "Use Gradient" checkbox theme option with an
enum and implements a radial background.

Whith this change, it should be easier to implemet other types of more
complex background types, like a world space oriented gradient.

Reviewed By: billreynish, fclem, brecht

Differential Revision: https://developer.blender.org/D6825
2020-02-20 13:00:18 +01:00
e6a9ece316 Fix T54270: Reset last_hit and last_location when reading the file
It does not make sense to read those values when loading a file and they can crash the cursor if they contain invalid coordinates.

Reviewed By: brecht

Maniphest Tasks: T54270

Differential Revision: https://developer.blender.org/D6754
2020-02-20 13:00:18 +01:00
a0dd1a679b Fluid: Updated manta pp files
Updates in the files include:
- New manta files now use an platform independent gzopen function
- Adjusted argument name for vorticity
2020-02-20 13:00:18 +01:00
60bf5dcdc5 Fluid: Updated Manta updater script
Minor adjustments for the build directory location.
2020-02-20 13:00:18 +01:00
6f3ddcf629 Cleanup: make format 2020-02-20 13:00:18 +01:00
fc5eed7845 Fluid: More cleanup in fluid rna code
Removed scientific variable names from UI.
2020-02-20 13:00:18 +01:00
4e2c0b3d7b Fix T73932: modifying keyframes in nodes fails when there is an image sequence
Image animation should not be an depsgraph node of type ANIMATION, there is
no need for it to be affected by the special casing for that.
2020-02-20 13:00:18 +01:00
79f727bb07 Sculpt: Pinch only in the direction perpendicular to the stroke
By pinching this way, we can fix some artifacts when sculpting following
the topology direction. It does not make much difference with dyntopo/
remesher, but I think this should improve the quality of the brush when
working with Multires.

Reviewed By: JulienKaspar, jbakker

Differential Revision: https://developer.blender.org/D6587
2020-02-20 13:00:18 +01:00
bfbd1135df Fluid: Cleanup in fluid rna code
More descriptive names for secondary particle options.
2020-02-20 13:00:18 +01:00
caad28d050 Fix T74009: bpy.ops.outliner.orphans_purge() poll being too restrictive.
There is no reason to even require an editor at all here, for now just
kept the 'orphan view needed' condition for the outliner case only.
2020-02-20 13:00:18 +01:00
811991716a Fix for Fix (c) : Normals Edit modifier using unititialized array of normals...
Own mistake in recent rBcfdb5b9a8b07.
2020-02-20 13:00:18 +01:00
5ec8888620 Fix T72751: Timeline crash from overridden scene.
Depsgraph RNA pointer would generate infinite loop in override comparisons.

Depsgraph pointer should never be considered here anyway, this is purely
runtime data.
2020-02-20 13:00:18 +01:00
368791c7f5 Fluid: Fix typo that was made in 4453509d83 2020-02-20 13:00:18 +01:00
ae1a75b960 Fix T73770: Mantaflow is unable to bake fluid simulations on non-ASCII file paths
Some fluid cache functions were not using Blender's more secure BLI_gzopen() function. On Windows there are some special cases which this function can handle compared to the plain gzopen().
2020-02-20 13:00:18 +01:00
8f5ad8df7e readfile: Move ID refcounting to libquery.
Having that extra ID users handling at readfile level, besides generic
one ensured by libquery, has been something bothering me for a long time
(had to fix my share of bugs due to mismatches between those two areas).

Further more, work on undo speedup will require even more complex ID
refcount management if we want to keep it in readfile.c area.

So idea is instead to generalize what we did for linked data already
when undoing: recompute properly usercount numbers after liblink step,
for all IDs.

Note that extra time required here is neglectable in a whole .blend file
reading (few extra milliseconds when loading a full production scene
e.g.).

Notes:
* Some deprecated data (IPOs) are not refcounted at all anymore, this
should not be an issue in pratice since the are supposed to get deleted
after doversion anyway.
* Refcounting happens after `do_versions_after_linking`, i.e those
functions won't get valid ID usercounts currently. Again, this is not a
problem in current code, if needed we could recompute refcount before,
and then ensure `do_versions_after_linoiing()` actually handles properly
usercount, which it does not currently.

Differential Revision: https://developer.blender.org/D6881
2020-02-20 13:00:18 +01:00
f7ef613155 Fix T68878: Update shapekeys during transformation
Only use the hack in `key_block_get_data` for the bmesh shapekey.
The remaining shapekeys can use the original offset values.

Differential Revision: https://developer.blender.org/D6516
2020-02-20 13:00:18 +01:00
be645d4550 Fix T73941: Custom normals from normal edit modifier ignored by further modifiers.
This commit actually fixes several issues in this modifier, but main one
from the report was caused by adding a `CD_NORMAL` layer to loops to
store temp real clnors. Unless we plan on modifying the topology itself,
this is useless, and would require some additional 'dirty normals'
tagging to work properly, so just switched to simpler, cleaner solution
of having a local array of computed clnors.
2020-02-20 13:00:18 +01:00
71ccb092d4 Fix T73938: Cycles Vertex Color wrong if no layer is specified
The node would render black in this case (but should use the
'active_render' layer choosen in the object data properties -- this is
now in line to how this is handled for e.g. UVs)

This introduces ATTR_STD_VERTEX_COLOR and uses this thoughout, if no
particular layer is specified in the node.

Maniphest Tasks: T73938

Differential Revision: https://developer.blender.org/D6887
2020-02-20 13:00:18 +01:00
de9c1bafed Subdiv: Clarify Subdiv settings
The actual naming might also be a subject to change, especially the one
around `level`. Tricky part here is that at some point in the API there
will be change from Blender modifier's Quality to OpenSubdiv's Level,
but which API level is most suitable for this?

At least now meaning of settings is better documented ans should be
clear what's going on.
2020-02-20 13:00:18 +01:00
d0664a101e Fix make deps OSL build on some systems with Qt libraries 2020-02-20 13:00:18 +01:00
b50e2af4fe Fix T73859: Support executing sculpt.set_pivot_position without invoke
Reviewers: brecht
2020-02-20 13:00:18 +01:00
adc190cdac Cleanup: assign Main, use existing assignments
Avoid accessing inline since it's often used multiple times.

In some cases it was already defined.
2020-02-20 13:00:18 +01:00
25601df774 BLI_math: unify zero area checks for barycentric weight calculation
This applies the change from T73348 fix to related functions.

Instead of checking against an epsilon to avoid divide by zero,
perform the division and check the result is finite.

This is needed since small faces can have an area under 'FLT_EPSILON',
and dividing by values close to zero can result in 'inf'.
2020-02-20 13:00:18 +01:00
Charlie Jolly
7873807aae EEVEE: Color Ramp Ease Optimisation
This patch provides an optimisation for Ease (Smoothstep) setting in the color ramp node.
This optimisation exists already for Constant and Linear modes.

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D6880
2020-02-20 13:00:18 +01:00
448ff0751a DRW: New High Quality Normal & Tangent extract
This patch adds a dedicated path to extract 16bit normals instead of packing them into 10bits/comp.
The tangents are also packed to 10bits/comp if not using the new High Quality Normal option.

Fix T61024 Degraded texture shading on dense meshes

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6614
2020-02-20 13:00:18 +01:00
e76dd30c8a GPU: Fix huge performance regression regarding instancing
Under some circumstances, MultiDrawIndirect was disabled to improve perf.
of average scene. But this conflicted with the normal instancing buffer
filling if only 1 or 2 instances were needed to fill the buffer. All
consecutive drawcalls could not be batched together and performance would
degrade rapidly.

This patch make my instance test scene go from 11fps back to 40fps where
it should have been.
2020-02-20 13:00:18 +01:00
978d4306d2 GPU: Limit Mesa workaround to older version 2020-02-20 13:00:18 +01:00
Cody Winchester
5710f8eaee Modifiers: UVWarp modifier add invert vgroup option
Adds the invert vgroup option to the UVWarp modifier. Adds a flag and char padding to the DNA.

Differential Revision: https://developer.blender.org/D6841
2020-02-20 13:00:18 +01:00
Cody Winchester
2047394fc2 Modifiers: Bevel modifier add invert vgroup option
Adds the invert vgroup option to the Bevel modifier.

Reviewed By: mont29

Differential Revision: https://developer.blender.org/D6845
2020-02-20 13:00:18 +01:00
51b494864c Fix crash loading .blend file saved with Blender 2.25
pathJumper.blend from 2.25 release demo files in demos225.zip
2020-02-20 13:00:18 +01:00
Cody Winchester
b11abfde87 Modifiers: Explode modifier add invert vgroup option
Adds the invert vgroup option to the Explode modifier.

Reviewed By: mont29

Differential Revision: https://developer.blender.org/D6844
2020-02-20 13:00:18 +01:00
e1c14a013a Fix Cycles fluid motion blur not working after recent refactor
This also re-enables the fluid motion blur test.
2020-02-20 13:00:18 +01:00
29f409178d Sculpt: Update red cursor color
Some users reported that the previous red color of the cursor was too
saturated and that can be distracting.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6828
2020-02-20 13:00:18 +01:00
Cody Winchester
e76bd9264a Modifiers: Laplacian Deform modifier add invert vgroup option
Adds the invert vgroup option to the Laplacian Deform modifier.

Differential Revision: https://developer.blender.org/D6843
2020-02-20 13:00:18 +01:00
0e12ea49b5 EEVEE: Fix default material disappearing when SSRefraction is enabled 2020-02-20 13:00:18 +01:00
da0c062ee4 Sculpt: Fix slide relax cursor color
Slide/Relax is a deform tool, so the color should be yellow.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6827
2020-02-20 13:00:18 +01:00
27c54f774e Fix T73105: Use Magnify instead of Pinch in the brush context menu
This matches the name in the properties panel for the Blob and Snake
Hook brushes

Reviewed By: brecht

Maniphest Tasks: T73105

Differential Revision: https://developer.blender.org/D6805
2020-02-20 13:00:18 +01:00
2d707840b8 Cleanup: clang-format. 2020-02-20 13:00:18 +01:00
Cody Winchester
a31bc357f0 Modifiers: Laplacian Smooth modifier add invert vgroup option
Adds the invert vgroup option to the Laplacian Smooth modifier.

Differential Revision: https://developer.blender.org/D6842
2020-02-20 13:00:18 +01:00
e0b8abf19b Fix Embree failing on objects with a very high number of motion steps
Set the limit to 129 to match Embree. This applies to all devices for
consistent render results.

Ref T73778
2020-02-20 13:00:18 +01:00
a639b37b88 Cycles: Fix failing avxf cross test on AVX2
cycles_util_avxf_avx2_test failed on the cross test, since
it wasn't immediately clear why, the test was disabled.

After looking into it, this test when build for AVX2 is
generating FMA instructions where the intermediate results
have "infinite" precision [1] leading to slightly different
results.

This diff re-enables the cross test and allows for a small error
in the results.

[1] https://www.felixcloutier.com/x86/vfmadd132ps:vfmadd213ps:vfmadd231ps

Differential Revision: https://developer.blender.org/D6873

Reviewers: brecht
2020-02-20 13:00:18 +01:00
4f19513df4 Cleanup: protect parameters of FOREACH_MAIN_ID & co macros. 2020-02-20 13:00:18 +01:00
3341dcf5eb Fix (unreported) wrong handling of usercount in BKE_workspace_add().
This does not seem to be an actual issue in current master code (as
creating a new ID will assign 1 user to it by default), but is breaking
generic usercount handling in future changes.
2020-02-20 13:00:18 +01:00
749120c1f4 Code cleanup EEVEE Render Passes
The render passes didn't follow the DrawManager way of doing things. It added new geometry and shading groups during drawing. This would make it harder to migrate to Vulkan later on.

This change will re-implement this part by using uniform references.

Reviewed By: Clément Foucault

Differential Revision: https://developer.blender.org/D6875
2020-02-20 13:00:18 +01:00
a275fd0089 Fix T62612: Saving with "Remap Relative" makes ALL paths relative 2020-02-20 13:00:18 +01:00
adda126d95 libquery: add optional handling of 'UI' ID pointers.
Handling those through different ways /might/ be needed sometimes, but
in most case this is just a nest of issues, since you can easily forget
to take them into account.

Note that this should be a 'non-functional' change, as this new behavior
is not used anywhere yet.
2020-02-20 13:00:18 +01:00
0bfdff1da7 Fix T73960: GPencil can't convert while it is a separate from old strokes
The problem was the new object hadn't any layer active.
2020-02-20 13:00:18 +01:00
d6a9824d6a Fix making paths relative on windows
Comparing the drive letter was case sensitive,
causing 'BLI_path_rel' to fail in common cases
(manually entering a lower case drive letter for example).

Surprisingly this issue dates back to 2005 and wasn't reported.
2020-02-20 13:00:18 +01:00
a247174348 Remove debug prints from blendfile_liblink.
rBf35f7bd97a4151 was the proper fix it seems.
2020-02-20 13:00:18 +01:00
3aff10511d Fix T73954: Cycles viewport render from camera not respecting aspect ratio 2020-02-20 13:00:18 +01:00
ddc8bff463 Fix missing output dir for blendfile_liblink test. 2020-02-20 13:00:17 +01:00
5bc46ecdac Cleanup: use doxy sections for BLI_bpath API 2020-02-20 13:00:17 +01:00
320ea5f32a build_deps: include venv on windows 2020-02-20 13:00:17 +01:00
f30c15e7d3 Fix Cycles Embree crash with AO shader local only option
Ref T73778
2020-02-20 13:00:17 +01:00
a18418de46 Fix Cycles Embree test failures with shadow catcher
Ref T73778
2020-02-20 13:00:17 +01:00
de91170546 Cleanup: compiler warnings 2020-02-20 13:00:17 +01:00
1acf3418cb Fix T70898: Area.type access fails for topbar & statusbar
Revert change from 5f6c45498c

Excluding enum items meant Python scripts couldn't access them.

This is no longer needed now Area.ui_type is used for the menu.
2020-02-20 13:00:17 +01:00
Stefan Werner
6e07e61fc4 Cycles: Enabled quaternion motion blur with Embree.
Bringing Embree's motion blur closer to Cycles' native blur.
This requries Embree 3.8.0 or newer.

Differential Revision: https://developer.blender.org/D6575
2020-02-20 13:00:17 +01:00
06b956c682 IC keymap: Use B for Sequencer Blade tool, Ctrl/Cmd-B for Split operator
Also add Q for select tool, as in other editors
2020-02-20 13:00:17 +01:00
c6a4ca114b DRW: Fix wrong view transform used in solid mode if using workbench engine 2020-02-20 13:00:17 +01:00
bf1ad6f3ad IC keymap: Fix warnings after recent Cut -> Split name change 2020-02-20 13:00:17 +01:00
668618bb25 Fix T73793 Walk navigation crosshair gets hidden behind objects
This is a bug that the recent refactor exposed. Some widgets were drawing
with alpha set to 0.
2020-02-20 13:00:17 +01:00
7aaadc3adc Fix T73914 Overlay: Unable to select bone in pose mode
It was caused by the bone selection overlay that was delaying the
xray pass. But OVERLAY_pose_draw were never called when doing selection.
2020-02-20 13:00:17 +01:00
d9a713d7b9 Temp debug prints for liblink tests to check what happens on windows. 2020-02-20 13:00:17 +01:00
f451240d00 Fix: Alphabeticalize Object Modifiers
Reported by Dalai on the live stream
2020-02-20 13:00:17 +01:00
661291f684 Fix T73748 Overlay: Infront disappearing/glitched while in Xray mode 2020-02-20 13:00:17 +01:00
e9a004ba70 Overlays: Fixed blending issue when not using smooth wire 2020-02-20 13:00:17 +01:00
f6e51546c3 Fix T73876 Overlay: Armature: Pose bones display randomly
Caused by unitialized value.
2020-02-20 13:00:17 +01:00
2667168421 MSVC: Fix obscure RNA related build error
When you switch between debug/release mode a lot, you could end up
in a situation where the generated RNA code was out of sync between
the two configurations.

There was one function optionally defined with an `#ifndef NDEBUG`
guard, this patch adds a stub implementation for the other configurations
to prevent build errors.

Differential Revision: https://developer.blender.org/D6855

Reviewers: brecht
2020-02-20 13:00:17 +01:00
2ee40a8558 Codesign: Harden check for archive being ready for sign
Seems like sometimes files are being only partially ready, which makes it so there
are unsigned files, failing to deliver fully signed bundle.

Now expected archive file size is stored into stamp file and is checked against
size of the archive file on another side.

There are some bare prints used for debugging, would need to switch it to a proper
logger (or to be removed).
2020-02-20 13:00:17 +01:00
bb6a508895 Embree: avoid potential clashing symbols with external renderer add-ons 2020-02-20 13:00:17 +01:00
a0e109acdf Fix: T73830 OSL not finding stdosl.h on linux
This extends FindOpenShadingLanguage.cmake to also look for the location of
stdosl.h and adds the path to the invocation of oslc to deal with the headers
being in different locations a little better.

Differential Revision: https://developer.blender.org/D6865

Reviewers: brecht
2020-02-20 13:00:17 +01:00
d2245fe017 Fix T71455, T73852, T73860: Transform, Redo doesn't work properly in time editors
The redo panel does not consider the position of the mouse.
So it is not possible to know the direction to redo the operator.

The solution is to add a new `direction` parameter that can be
saved and used for redo.

Differential Revision: https://developer.blender.org/D6852
2020-02-20 13:00:17 +01:00
b3abd2e102 Fix T73853: Redo does't work properly with NLA "Move" transform mode
The orientation matrix when re-doing some transform operations was negated.
Thanks @lichtwerk for pointing out the problem.
2020-02-20 13:00:17 +01:00
6be2ad8367 VSE: Fix missed renaming of cut operator
Fix errors introduced by commit rB819af2094b21.

Reviewed By: ISS

Differential Revision: https://developer.blender.org/D6870y
2020-02-20 13:00:17 +01:00
6bd5c1b33a VSE: Remove atomized image duplication for preprocessing stage
Each image that goes through preprocessing is already duplicated in `input_preprocess()`

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6790
2020-02-20 13:00:17 +01:00
03defc0182 Fix T70229: Show Cache On will cause a lower fps
Use gpu batch drawing for cache content in VSE.
Immediate drawing caused significant dorp in framerate.

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D6835
2020-02-20 13:00:17 +01:00
Charlie Jolly
f4ead52f1b Cycles: Vector Rotate Node using Axis and Angle method
This node provides the ability to rotate a vector around a `center` point using either `Axis Angle` , `Single Axis` or `Euler` methods.

Reviewed By: #cycles, brecht

Differential Revision: https://developer.blender.org/D3789
2020-02-20 13:00:17 +01:00
c093ef6ca2 Fix artifacts with Cycles viewport denoising when rendering with multiple CUDA devices
Rendering with multiple CUDA devices but denoising with OptiX caused parts of the image to go
missing at the start while the resolution was scaled. This is because the copy operation in
`MultiDevice::map_neighbor_tiles` which slices the copy across all devices would slice based on the
full resolution and not the scaled one and therefore copy incorrect data between devices.
Since this is not the recommended way of using viewport denoising anyway, simply avoid those
incorrect copies for now by disabling denoising while the resolution is scaled. Doing both rendering
and denoising with OptiX is not affected by this, since it avoids those copies altogether anyway.
2020-02-20 13:00:17 +01:00
aafbbe34a2 Fix T73817: Shape key users not properly mapped when duplicating their obdata.
Once again those crappy weirdos IDs with their crappy weirdos 'loopback'
pointers...

This is a quick hack for now, think id_copy needs to be reworked a bit
to supported re-entrant sub-ID copying (also an issue with nodes I bet).
2020-02-20 13:00:17 +01:00
56da28b684 ColorManagement: Dithering Improvement
- Unlock property range.
- Use triangular noise to keep perceptual noise error more uniform.
  Remap range to preserve perceptual intensity.
- Center noise distribution around 0 for GPU implementation because of
  rounding.
- Do dithering after merging overlays.

Effect of using triangular noise is not really noticeable if you don't use
really low bitdepth. But doing a test in the shader were we artificially
reduce the bitdepth (`col = (col * 16) / 16;`) reveals the real difference.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6850
2020-02-20 13:00:17 +01:00
c30b9327b9 Cleanup: Remove period from RNA description. 2020-02-20 13:00:17 +01:00
5a0719794e Cleanup: add extern "C" to UI_interface.h 2020-02-20 13:00:17 +01:00
8672e0df44 Fix T68749: BPY: Deprecate height of popup
`invoke_props_dialog` and `invoke_popup` had a width and a height field. The height field was ignored as the height is determined based on the content. This change removes the field from the BPY + WM_api

Reviewed By: Campbell Barton, Jacques Lucke

Differential Revision: https://developer.blender.org/D6694
2020-02-20 13:00:17 +01:00
1e53606603 Fix T73518: Normal Overlay
This change will not render the normals for faces that are hidden.
Before we had instance drawing the hidden faces were registered in the
index buffer. During the overlay refactoring the rendering was migrated
to instance rendering. Instance rendering does not use the index buffer
so the data was ignored.

This patch stored the normal visibility in the .w part of the normal or
for face normals it will set the normal to zero. The shader looks at
this and renders the normals fully transparent when detected.

Reviewed By: Clément Foucault

Differential Revision: https://developer.blender.org/D6798
2020-02-20 13:00:17 +01:00
Dalai Felinto
20cdf4f99c UI: Create quads > Create Quads 2020-02-20 13:00:17 +01:00
129fed65e5 Cycles: Add support for adaptive kernel compilation to OptiX device
This modifies the common CUDA implementation for adaptive kernel compilation slightly to support both CUBIN and PTX output (the latter which is then used in the OptiX device). It also fixes adaptive kernel compilation on Windows.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D6851
2020-02-20 13:00:17 +01:00
63f1c86bc4 Fix OpenCL issue after recent code cleanup
Thanks Patrick Mours for finding it.
2020-02-20 13:00:17 +01:00
b65e894852 Cleanup: compiler warning 2020-02-20 13:00:17 +01:00
Bartosz Moniewski
fdabd1446b Shading: add direction modes and phase offset to wave texture node
* Direction mode X, Y and Z to align with axes rather than diagonal or
  spherical as previously. X is the new default, existing files will
  use diagonal or spherical for compatibility.
* Phase offset to offset the wave along its direction, for purposes like
  animation and distortion.

https://developer.blender.org/D6382
2020-02-20 13:00:17 +01:00
de28611d8f Python: Expose WM is_interface_locked to python.
This patch exposes the Window Manager `is_interface_locked` as a read
only property to python.

This property is needed to allow script writers to detect if a job is
running with locked interface like the Alembic exporter.

Reviewed By: Brecht

Differential Revision: https://developer.blender.org/D6749
2020-02-20 13:00:17 +01:00
c1f153833c Fix many typos and other issues in UI messages. 2020-02-20 13:00:17 +01:00
9ab004a6ee Cleanup: Alembic, split source files into reader and writer
This separation between reader and writer code is part of Milesone 2 of
T73363.

In this commit the reader and writer classes are separated into their
own files, any `#include` and `using` statements are cleaned up, and
some separator comments have been removed.

No functional changes.
2020-02-20 13:00:17 +01:00
e769ae2c00 Fix macOS LLVM precompiled link error with older Xcode versions 2020-02-20 13:00:17 +01:00
7b51a10bca Alembic: fix unit test on Windows
There are two issues solved in this commit:

- Our Windows buildbot has slightly different floating point errors than
  the Linux one, which meant a larger delta was required for float
  comparisons.
- The test performs an export to a temporary Alembic file and
  subsequently imports it. Deleting the temporary file was impossible on
  Windows because it was still in use. This is now resolved by first
  loading the default blend file before deleting the Alembic file.
2020-02-20 13:00:17 +01:00
5c6f5509da UI: Use crosshair cursor for Extrude to Cursor tools
Since this tool doesn't perform selections when you click, it's important that the cursor helps communicate that something else will happen.

Also fix missing 'to' in Curve Edit Mode.
2020-02-20 13:00:17 +01:00
326137d9b9 Keymap: minor tweaks so box-select shortcuts show in the menu 2020-02-20 13:00:17 +01:00
7650c1652f GPencil: Fix unreported move to layer with lock material
The strokes with the material locked could be moved. Now the lock is respected.
2020-02-20 13:00:17 +01:00
Julian Eisel
404cc8d1fc Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-20 12:56:11 +01:00
Julian Eisel
af928a2fb1 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-02-20 12:53:03 +01:00
Julian Eisel
b1c9434332 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-02-20 12:51:46 +01:00
Julian Eisel
4c2ec7c5ec Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-02-20 12:51:35 +01:00
Julian Eisel
79069884b1 Merge branch 'master' into temp-openxr-buildstuff 2020-02-20 12:51:09 +01:00
Julian Eisel
7254d1ae49 Merge branch 'master' into temp-openxr-buildstuff 2020-02-20 11:16:17 +01:00
Julian Eisel
63d34abc0f Fix too bright rendering on some runtimes
Transform to display space on our end is only needed for the Monado
runtime.
2020-02-19 21:15:18 +01:00
Julian Eisel
8dd6f89a5d Bring back vertically mirrored drawing for DirectX compatibility 2020-02-19 14:48:23 +01:00
Julian Eisel
fe1f7c038d Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-02-17 17:06:26 +01:00
Julian Eisel
a18c254c6d Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-17 16:57:21 +01:00
Julian Eisel
27bbbc9c57 Remove own GPUViewport and GPUContext binding
Draw-manager handles these as needed now, so we can remove this.
2020-02-17 16:53:56 +01:00
Julian Eisel
6dbe2d781d Don't create framebuffer for VR view, re-use GPUViewport one 2020-02-17 16:21:28 +01:00
Julian Eisel
3b1e67754c Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-02-17 12:33:56 +01:00
Julian Eisel
19f3fdad97 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-17 12:21:00 +01:00
Julian Eisel
8d5996595f Fix compile errors and broken drawing after changes in master
There are still some issues left after the changes in master:
* Some optimizations need to be redone differently
* Color-space handling needs to be redone differently
* Upside-down drawing is broken
2020-02-17 12:15:42 +01:00
Julian Eisel
47baf42e2c Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
This will currently fail to compile. Fixes upcoming.
2020-02-17 11:29:17 +01:00
Julian Eisel
cdfe5449df Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-02-17 11:04:02 +01:00
Julian Eisel
f0786dfc52 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-02-17 11:03:39 +01:00
Julian Eisel
de2d03ace9 Merge branch 'master' into temp-openxr-buildstuff 2020-02-17 11:01:47 +01:00
Julian Eisel
e6e81376b7 Support forcing continuous gizmo redraws 2020-02-16 19:26:04 +01:00
Julian Eisel
78643f0767 Support inputting custom base pose location and Z-Axis rotation 2020-02-15 03:24:10 +01:00
Julian Eisel
34372607de Refactor reference pose setup, always sync with actual camera pose 2020-02-15 00:57:06 +01:00
Julian Eisel
763eb3d016 Only use Z-axis rotation for base pose (grid aligned) 2020-02-14 23:24:13 +01:00
Julian Eisel
8d2119c054 Cleanup: Rename anchor_object -> base_pose_object
The term "anchor" is already used differently in the context of XR, so
rather avoid the ambiguity.
2020-02-14 17:22:52 +01:00
Julian Eisel
fe8222cf00 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-02-05 14:39:18 +01:00
Julian Eisel
0a27ab2e93 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-02-05 14:38:19 +01:00
Julian Eisel
d930ff7f4f Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-02-05 14:37:59 +01:00
Julian Eisel
f3e9351111 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-02-05 14:37:45 +01:00
Julian Eisel
2a259497ae Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-02-05 14:37:30 +01:00
Julian Eisel
eecf3021d7 Merge branch 'master' into temp-openxr-buildstuff 2020-02-05 14:37:09 +01:00
Julian Eisel
5d4f8d31a5 Allow setting any object as "anchor" (to set base location/rotation)
Not sure how much of this will actually stay in, but it should allow us
experimenting with different ways to set the base position.
Also, when an anchor is set, the location/rotation of it and the VR base
position are synched.
2020-02-03 19:47:41 +01:00
Julian Eisel
e3e370c5ea Fix render settings not showing up for workbench engine 2020-01-28 11:48:56 +01:00
Julian Eisel
e99e914352 Support all 3D-view shading options for the VR session 2020-01-27 20:33:05 +01:00
Julian Eisel
a02e03fa16 Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-01-24 11:26:16 +01:00
Julian Eisel
0173800572 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-01-24 11:25:54 +01:00
Julian Eisel
bc38898cf4 Fix linking after recent build system changes in master 2020-01-24 11:24:34 +01:00
Julian Eisel
1a812145e0 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-01-24 11:22:04 +01:00
Julian Eisel
f430f6fa18 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-01-24 11:17:59 +01:00
Julian Eisel
2f6ebe1b99 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-01-24 11:17:43 +01:00
Julian Eisel
c706834749 Merge branch 'master' into temp-openxr-buildstuff 2020-01-24 11:17:23 +01:00
Julian Eisel
f640704654 Fix view stuck at center on session start without positional tracking 2020-01-16 19:53:31 +01:00
Julian Eisel
dbc1622010 Use correct add-on branch for 'make update' 2020-01-13 16:45:55 +01:00
Julian Eisel
ccbfeb0e57 Hack: Let gizmos draw during playback to force VR gizmo redraws that way
We have to somehow force VR gizmos (i.e. the virtual camera) to
continuously redraw. Until there's a proper way to do that (e.g.
continuously redrawing certain gizmos without redrawing the rest of the
3D View), just allow playing animation to force these redraws.
2020-01-10 17:33:54 +01:00
Julian Eisel
9b1d318222 Expose VR view rotation in the RNA/BPY 2020-01-10 16:59:26 +01:00
Julian Eisel
ff62a827ce Merge branch 'soc-2019-openxr' into vr_scene_inspection 2020-01-06 16:53:35 +01:00
Julian Eisel
11ee2f1d09 Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2020-01-06 16:52:35 +01:00
Julian Eisel
fcc6e94897 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2020-01-06 14:59:25 +01:00
Julian Eisel
d6cce8bc8e Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2020-01-06 14:52:28 +01:00
Julian Eisel
4332e2b5fb Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2020-01-06 14:52:06 +01:00
Julian Eisel
3ff91e97d9 Merge branch 'master' into temp-openxr-buildstuff 2020-01-06 14:41:20 +01:00
Julian Eisel
fd95e3275a Fix memory leak when closing Blender while VR session runs 2019-12-13 17:48:54 +01:00
Julian Eisel
6b496ca687 Fix crash on undo or file load with running VR session 2019-12-13 17:40:05 +01:00
Julian Eisel
e951f4becf Allow querying VR session viewer location from Python
Not 100% sure if the output coordinates are correct, only did quick
testing of that. I'm just slowly working towards the virtual camera
feature for a regular viewport.

Also fix compile in Windows error with previous commit.
2019-12-13 14:13:08 +01:00
Julian Eisel
5409b0b0be Fix two memory leaks in OpenGL Linux (X11) graphics binding 2019-12-13 11:31:45 +01:00
Julian Eisel
d330d0762b Add Py API for querying VR session state
This should be a rather important step to get the Python defined VR UIs
to work.

Also:
* Adds a bpy.types.XrSessionState.is_running() class method for
  the UI to use.
* Adds a XR-data-changed notifier type for the window manager category
  to ensure proper redraws on state changes.
2019-12-12 18:27:02 +01:00
Julian Eisel
5954cb807f Fix crash when ending VR session through "Toggle VR Session" 2019-12-12 16:18:17 +01:00
Julian Eisel
69bfe4b4c3 Fix memory leak when closing Blender with running VR session 2019-12-11 19:06:24 +01:00
Julian Eisel
270eb33645 Fix various space transform issues 2019-12-11 18:54:35 +01:00
Julian Eisel
4b18015a1c Add positional tracking option (3DoF vs. 6DoF)
For passing around the HMD or preparing scenes for 3DoF interaction
(e.g. cardboards) this option is quite handy.

After feedback from @sebastian_k and @noemis, decision was that
disabling the positional tracking should not reset the position to the
starting one. It should just keep whatever is the current position.
So we have to get the local pose (which is different from the per eye
pose) out of OpenXR so we can have more dynamic base position that
changes depending on the positional tracking option.

Not that this isn't working 100% as wanted: There's a slight offset when
disabling the positional tracking. I don't want to spend too much time
on something minor-ish while there are more major features to get done.
2019-12-11 15:10:43 +01:00
Julian Eisel
06138de13a Color transforms were fixed in Windows MR -> disable our workaround 2019-11-29 12:40:55 +01:00
Julian Eisel
0c7ac28b8a SDK changed loader lib name on Windows, update for that 2019-11-28 19:05:07 +01:00
Julian Eisel
43cfa0b682 Merge branch 'master' into soc-2019-openxr 2019-11-27 15:25:47 +01:00
Julian Eisel
f426d3a002 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2019-11-27 15:25:12 +01:00
Julian Eisel
a1499f7f7d Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2019-11-27 12:26:56 +01:00
Julian Eisel
530a8d1ab1 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2019-11-27 12:24:12 +01:00
Julian Eisel
2232406394 Merge branch 'master' into temp-openxr-buildstuff 2019-11-27 12:21:32 +01:00
Julian Eisel
8f6b3d27d0 Remove files to sync with latest changes in patches 2019-11-19 15:33:30 +01:00
Julian Eisel
ffa16f677a Merge branch 'temp-openxr-blenderside' into soc-2019-openxr 2019-11-19 15:31:07 +01:00
Julian Eisel
85ccec8639 Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2019-11-19 15:30:42 +01:00
Julian Eisel
fc83dfdba1 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2019-11-19 15:29:29 +01:00
Julian Eisel
2448eb6136 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2019-11-19 15:29:11 +01:00
Julian Eisel
90df65892f Merge branch 'master' into temp-openxr-buildstuff 2019-11-19 15:28:53 +01:00
Julian Eisel
f07e361829 Update branch to include changes from split off patches 2019-11-15 11:27:46 +01:00
Julian Eisel
779b3f0cff Bring back utility batch and config file for Oculus support 2019-11-14 12:49:18 +01:00
Julian Eisel
561f4665a6 Merge branch 'master' into soc-2019-openxr 2019-11-14 12:40:20 +01:00
Julian Eisel
58f95e9e4d Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2019-11-14 12:37:10 +01:00
Julian Eisel
17121b2afd Add required OpenXR defines to Ghost CMakeLists (used to be in root one) 2019-11-14 12:35:30 +01:00
Julian Eisel
fc26797e72 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2019-11-14 12:21:47 +01:00
Julian Eisel
fa9707a712 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2019-11-14 12:17:05 +01:00
Julian Eisel
8d45b4f75c Disable XR features (and the OpenXR SDK dependency) by default on Apple 2019-11-14 12:04:02 +01:00
Julian Eisel
03ac9de0a9 Remove XR defines from top-level CMakeLists file, can be done locally 2019-11-14 12:01:06 +01:00
Julian Eisel
4456dbcded Remove now unnecessary OpenXR SDK patch for Win CRT linkage 2019-11-14 11:51:39 +01:00
Julian Eisel
cc23a8c84d Merge branch 'master' into temp-openxr-buildstuff 2019-11-14 11:43:19 +01:00
Julian Eisel
120d9c91dc Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2019-11-13 17:03:05 +01:00
Julian Eisel
e1db5cc2c7 Remove CMake include unneeded after recent build system changes 2019-11-13 17:01:42 +01:00
Julian Eisel
a347ec08bc Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside 2019-11-13 13:02:32 +01:00
Julian Eisel
ee8e4b7db8 Merge branch 'temp-openxr-directx' into temp-openxr-ghostxr 2019-11-13 13:02:11 +01:00
Julian Eisel
8c7be58e72 Merge branch 'temp-openxr-buildstuff' into temp-openxr-directx 2019-11-13 13:01:39 +01:00
Julian Eisel
1b39eb1060 Merge branch 'master' into temp-openxr-buildstuff 2019-11-13 13:01:21 +01:00
Julian Eisel
0d98e665ea Core XR Support [part 1]: Add OpenXR-SDK dependency and WITH_OPENXR build option
Some points on the OpenXR-SDK dependency:
* The repository is located at https://github.com/KhronosGroup/OpenXR-SDK (Apache 2).
* We use the OpenXR loader lib from it, the headers, and some CMake utilities.
* It contains a bunch of generated files, for which the sources are in a separate repository.
* To use the injected OpenXR API-layers from the SDK (e.g. API validation layers), the SDK needs to be compiled from this other repository.
* We could use that other repo by default, but I'd rather go with the simpler solution and allow people to opt in if they want advanced dev features.
* For Windows a patch is needed to link the CRT in a compatible way.

All this is entirely untested on macOS.

Maniphest Tasks: T71365

Differential Revision: https://developer.blender.org/D6188
2019-11-13 12:57:35 +01:00
Julian Eisel
7f1fadba67 Core XR Support [part 4]: Blender-side changes (+ the remaining bits)
Changes for the higher level, more Blender specific side of the implementation.

Main additions:
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU context)
* DNA/RNA for initial management of VR session settings
* Utility batch & config file for using the Oculus runtime (Windows only)

Differential Revision: https://developer.blender.org/D6193
2019-11-05 15:33:48 +01:00
Julian Eisel
8537cdc71d Core XR Support [part 3]: Ghost-XR API based on OpenXR
## Design Overview
* For code using this API, the most important object is a GHOST_XrContext handle. Through it, all API functions and internal state can be accessed/modified.
* Main responsibilities of the Ghost XR-context are to manage lifetimes of the OpenXR runtime connection (represented by XrInstance), the session and to delegate operations/data to the session.
* The OpenXR related graphics code, which is OS dependent, is managed through a `GHOST_IXrGraphicsBinding` interface, that can be implemented for the different graphics libraries supported (currently OpenGL and DirectX).
* Much of this code here has to follow the OpenXR specification and is based on the OpenXR [[https://github.com/KhronosGroup/OpenXR-SDK-Source/tree/master/src/tests/hello_xr | `hello_xr`]] implentation.
* In future we may want to take some code out of the context, e.g. extension and API layer management.
* There are runtime debugging and benchmarking options (exposed through --debug-xr and --debug-xr-time, but not as part of this patch).
* Error handling is described in a section below.

## Why have this in Ghost?

Early on, I decided to do the OpenXR level access through GHOST. Main reasons:
* OpenXR requires access to low level, OS dependent graphics lib data (e.g. see [[https://www.khronos.org/registry/OpenXR/specs/0.90/man/html/openxr.html#XrGraphicsBindingOpenGLXlibKHR| XrGraphicsBindingOpenGLXlibKHR]])
* Some C++ features appeared handy (`std::vector`, RAII + exception handling, cleaner code through object methods, etc.)
* General low level nature of the OpenXR API

After all I think much of the functionality is too high level to live in GHOST however. I would like to address this by having a separate `VAMR` (virtual + augmented + mixed reality) module, placed in `intern/`.  The main issue is getting this to work well with Ghost data, especially how to get the mentioned low level data out of Ghost.
This is something I'd like to look into again before too long, but for now I think having this in Ghost is reasonable.

## Error Handling Strategy

The error handling strategy I chose uses C++ exceptions, a controversial feature. Let me explain why I think this is reasonable here.

The strategy requirements were:
* If an error occurs, cleanly exit the VR session (or destroy the entire context), causing no resource leaks or side effects to the rest of Blender.
* Show a *useful* error message to the user.
* Don't impair readability of code too much with error handling.

Here's why I chose an exception based strategy:
* Most alternatives require early exiting functions. This early exiting has to be 'bubbled up' the call stack to the point that performs error handling. For safe code, early exit checks have to be performed everywhere and code gets really impaired by error checking. Tried this first and wasn't happy at all. Even if error handling is wrapped into macros.
* All `GHOST_Xr` resources are managed via RAII. So stack unwinding will cause them to be released cleanly whenever an exception is thrown.
* `GHOST_Xr` has a clear boundary (the Ghost C-API) with only a handful of public functions. That is the only place we need to have try-catch blocks at. (Generally, try-catch blocks at kinda random places are a bad code smell IMHO. Module boundaries are a valid place to put them.)
* Exceptions allow us to pass multiple bits of error information through mulitple layers of the call stack. This information can also be made specific with a useful error message. As of now, they conain a user error message, the OpenXR error code (if any), as well as the exact source code location the error was caught at.

So the strategy I went with works as follows:
* If a VR related error occurs within `GHOST_Xr`, throw an exception (`GHOST_XrException` currently).
* OpenXR calls are wrapped into a macro throwing an exception if the return value indicates an error.
* Useful debugging information and user messages are stored in the exceptions.
* All resources must be managed through RAII, so throwing an exception will release 'dangling' ones cleanly.
* In the GHOST C-API wrappers, the exceptions are caught and contained error information is forwarded to a custom error handling callback.
* The error handling callback is set in `wm_xr.c`, prior to creating the XR-Context, and implements clean destruction of the context.

Differential Revision: https://developer.blender.org/D6192
2019-11-05 15:00:55 +01:00
Julian Eisel
6ae2979d05 Ghost DirectX compatibility from GSoC OpenXR branch
Needed for DirectX-only OpenXR runtimes (e.g. Windows Mixed Reality).

Adds a minimal DirectX 11 Ghost context, plus some shared DirectX-OpenGL resource interface using the NV_DX_interop2 WGL extension.
I know that the current implementation fails on some systems, which is something I'll have to fix at some point. Don't know if this is a showstopper though, I can fix that in master too. For now this isn't going to be used by many people anyway. Recently I also learned that OSVR uses the same extension, see https://github.com/sensics/OSVR-RenderManager/blob/master/osvr/RenderKit/RenderManagerD3DOpenGL.cpp. Their implementation may be useful to fix the issue, according to a OSVR dev, it works quite reliably for them.

Note: Didn't actually test just this patch on Windows yet.

Differential Revision: https://developer.blender.org/D6190
2019-11-05 13:39:44 +01:00
Julian Eisel
b698a926af Add back accidentally removed CMake files
No clue how those ended up tagged as removed.
2019-11-05 12:35:44 +01:00
Julian Eisel
fac53c7bc2 Core XR Support [part 1]: Add OpenXR-SDK dependency and WITH_XR build option
Some points on the OpenXR-SDK dependency:
* The repository is located at https://github.com/KhronosGroup/OpenXR-SDK (Apache 2).
* We use the OpenXR loader lib from it, the headers, and some CMake utilities.
* It contains a bunch of generated files, for which the sources are in a separate repository.
* To use the injected OpenXR API-layers from the SDK (e.g. API validation layers), the SDK needs to be compiled from this other repository.
* We could use that other repo by default, but I'd rather go with the simpler solution and allow people to opt in if they want advanced dev features.
* I copied `presentation.cmake` and `xr_platform_defines.cmake` from the SDK. They contain logic that is not needed for us and prints at CMake generation. We could change that but figured it would also be helpful to keep the files equal to the SDK ones.
* For Windows a patch is needed to link the CRT in a compatible way.
* @LazyDodo already pushed the precompiled binaries for Windows.

All this is entirely untested on macOS.

Differential Revision: https://developer.blender.org/D6188
2019-11-05 12:32:33 +01:00
Julian Eisel
88f234e27f Merge branch 'master' into soc-2019-openxr 2019-11-05 10:30:22 +01:00
Julian Eisel
0615321ca0 Fix too dark rendering on the Monado runtime
Just like the Windows Mixed Reality runtime, we have to apply a sRGB
OETF to get visually correct-ish looking colors.
We plan to further investigate if it's really WMR and Monado being wrong
here, or if it's Oculus (which doesn't need this additional transform),
but there are some details to check.
2019-10-16 14:36:13 +02:00
Julian Eisel
3bed8a7338 Refactor GPU viewport onscreen drawing for "upside down" drawing
Reduces code duplication for the DirectX specific upside down drawing.
Didn't actually test the upside down drawing, since I need to do that on
Windows.
2019-10-15 22:33:46 +02:00
Julian Eisel
ff03e3b7e0 Merge branch 'master' into soc-2019-openxr 2019-10-15 22:13:16 +02:00
Julian Eisel
350b7b378d Correct/remove disabled code for space conversion
Turns out we don't actually have to convert between spaces.
2019-10-15 22:10:08 +02:00
Julian Eisel
51af7510fb Cleanup: Avoid duplication of projection matrix calculation 2019-10-15 22:09:27 +02:00
Julian Eisel
927c300c02 Improve error messages & cleanup 2019-10-15 22:04:22 +02:00
Julian Eisel
fa9a841d43 Wrap WM XR data into own struct 2019-10-15 17:33:46 +02:00
Julian Eisel
b057298021 Revert accidental change in previour commit
Played around with the color management/transforms but forgot to undo.
2019-10-15 17:12:56 +02:00
Julian Eisel
1ada9f5bf9 Support VR Session settings & add some basic ones
* Adds the needed bits to support VR session settings and access them in
  the VR view drawing code.
* Added settings for: shading mode, grid floor, annotations, clipping.
  More can easily be added.
* The Add-on adds a "VR" tab in the side bar, containing buttons for the
  added settings
2019-10-15 16:01:06 +02:00
Julian Eisel
52c9d33cc2 Merge branch 'master' into soc-2019-openxr 2019-10-14 16:05:46 +02:00
Julian Eisel
db6657aa15 Fix compile error on Windows after last commit 2019-10-11 15:40:03 +02:00
Julian Eisel
941e1f5a98 Strictly follow specification to get OpenXR extension functions
This fixes linking errors with the Monado runtime. The specification
says that extension functions have to be gotten through
`xrGetInstanceProcAddr()` which we did for some extensions, but not for
the graphics extensions. Worked fine earlier, but broke meanwhile.
2019-10-10 14:47:00 +02:00
Julian Eisel
e9832f053b Merge branch 'master' into soc-2019-openxr 2019-10-10 11:30:14 +02:00
Julian Eisel
cddf043cca Cleanup: Don't pass unused lens value 2019-09-17 19:16:14 +02:00
Julian Eisel
6af2f222ca Cleanup: Comment style 2019-09-17 19:02:01 +02:00
Julian Eisel
639dffa43a CMake: Slight adjustment to warning message 2019-09-17 18:17:58 +02:00
Julian Eisel
9baa9e2bd3 Fix Linux linker config name for the OpenXR-SDK 2019-09-17 16:55:24 +02:00
Julian Eisel
3c38e67765 Fix mistakes in openxr build options
I remember merge conflicts here.
2019-09-17 16:54:28 +02:00
Julian Eisel
1849e4fe19 Merge branch 'master' into soc-2019-openxr 2019-09-17 13:48:54 +02:00
2ef7a1f24d Merge branch 'master' into soc-2019-openxr 2019-09-15 19:01:30 +02:00
Julian Eisel
bc8186b5d1 Merge branch 'master' into soc-2019-openxr 2019-08-30 14:22:04 +02:00
Julian Eisel
e0bb3f9286 Merge branch 'master' into soc-2019-openxr 2019-08-24 23:21:33 +02:00
Julian Eisel
d0b4ec00f6 Don't drwa relationship lines in the VR view 2019-08-24 22:06:23 +02:00
Julian Eisel
7b6514c222 Merge branch 'master' into soc-2019-openxr 2019-08-24 14:45:41 +02:00
Julian Eisel
c506acf2fc Add Oculus to the list of known runtimes
With this, all currently available runtimes are in the runtime map. So
removing the TODO comment.
2019-08-24 03:35:32 +02:00
Julian Eisel
31b8350b01 Cleanup: Refactor (hacky) swapchain image submission
Code now assumes that the view-draw callback left the OpenGL state for
ongoing use by Ghost-XR. So the state doesn't have to be set by the
swapchain image submission and thus it we don't need to pass the Ghost
OpenGL context to it in a hacky way.
Also, rename drawViewEnd (to submitToSwapchain) and remove
drawViewBegin.
2019-08-24 03:32:11 +02:00
Julian Eisel
d7a216704b Fix warning in release builds 2019-08-24 03:17:14 +02:00
Julian Eisel
4b67477732 Own FBO for VR viewport to get previous changes to work 2019-08-24 03:15:25 +02:00
Julian Eisel
4a039158e5 Avoid OpenGL context deactivation, just to reactivate it immediately 2019-08-24 00:13:36 +02:00
Julian Eisel
61014e1dd9 Remove hack to resize the usable default framebuffer region 2019-08-23 23:46:09 +02:00
Julian Eisel
3441314e40 Remove blitting from default framebuffer 2019-08-23 23:36:04 +02:00
Julian Eisel
f175dcc35f Add Monado to the list of known runtimes 2019-08-23 23:08:21 +02:00
Julian Eisel
756b676076 Merge branch 'master' into soc-2019-openxr 2019-08-23 17:51:28 +02:00
Julian Eisel
7462fca737 Avoid redundant framebuffer resize and offscreen texture drawing 2019-08-23 17:46:43 +02:00
Julian Eisel
7c9e18c193 Cleanup: Add comments 2019-08-23 17:00:30 +02:00
Julian Eisel
6b69b5349b Address and remove some TODOs marked in code 2019-08-22 23:24:05 +02:00
Julian Eisel
daba8140c2 Cleanup: Unused functions, add comments, sync to master 2019-08-22 23:02:01 +02:00
Julian Eisel
599d0611b0 Improve batch file text for starting Blender with Oculus support 2019-08-22 13:33:06 +02:00
Julian Eisel
e88970db82 Don't create a DirectX swap-chain
We only render offscreen anyway. There's no point in creating a
swap-chain. This simplifies things quite a bit.
2019-08-21 20:58:59 +02:00
Julian Eisel
20b0b36479 DirectX: Create an own render-target, don't use swapchain for blitting 2019-08-21 20:40:13 +02:00
Julian Eisel
2c77f2deac Remove GHOST API functions for OpenGL offscreen blitting
These were previously used to blit from a offscreen (non-OpenGL)
context, into an onscreen one. We do this differently, and only within
GHOST_XrGraphicsBinding now, so this can be removed.
2019-08-21 20:36:40 +02:00
Julian Eisel
fec7ac7c51 Refactor OpenGL/DirectX resource sharing for multiple shared resources
Rather than max. one shared resource per DirectX context, code can now
request a handle for a shared resource and ask the DirectX context to do
operations on that.
2019-08-21 19:44:08 +02:00
Julian Eisel
2a1ec8ec2a Fix missing CMake hint for OpenXR SDK path on linux 2019-08-21 13:24:16 +02:00
1548682cde Windows/deps: Add/fix openxr_sdk dependency
There were a few typos here and there, and the openxr_sdk does not respect the cflags we give it hence a patch was added to work around this undesirable behaviour.
2019-08-20 08:30:29 -06:00
Julian Eisel
588dea6751 Merge branch 'master' into soc-2019-openxr 2019-08-20 12:36:51 +02:00
Julian Eisel
ad4f9a4d98 Fix compiling with WITH_OPENXR disabled 2019-08-20 09:17:56 +02:00
Julian Eisel
84466c7d71 Blacklist VR add-on in Python tests if WITH_OPENXR is disabled 2019-08-20 00:55:21 +02:00
Julian Eisel
de037b031d Expose WITH_OPENXR build option to Python API 2019-08-20 00:12:59 +02:00
Julian Eisel
a21ae28f96 Prepare Toggle VR Session operator to be enabled by an add-on 2019-08-19 23:44:59 +02:00
Julian Eisel
b2424bd781 Windows: Print warning and disable WITH_OPENXR if SDK is not found 2019-08-19 15:41:27 +02:00
Julian Eisel
d0177fc541 Integrate the OpenXR SDK better into dependency management
Adds the SDK so that `make deps` works, on all platforms. On Windows,
the SDK headers and libraries are now assumed to be in the usual lib\
directory.
Also fixes a mistake in install_deps.sh

Note that none of this is tested as it requires an older Visual Studio
version than I have.
2019-08-18 13:06:48 +02:00
Julian Eisel
4cf8740790 Fix compile error on Linux 2019-08-17 23:59:39 +02:00
Julian Eisel
a53b90329a Merge branch 'master' into soc-2019-openxr 2019-08-17 23:58:09 +02:00
Julian Eisel
2c41ffa380 Fix compiling with external OpenXR SDK on Windows 2019-08-15 21:49:10 +02:00
Julian Eisel
cdc2768f65 Cleanup: Don't cast away const in GHOST C-API 2019-08-15 15:52:45 +02:00
Julian Eisel
eb477c67a1 Fix crash when no OpenXR runtime is found (or setup failed) 2019-08-15 15:50:01 +02:00
Julian Eisel
0dd3f3925b Remove bundled OpenXR-SDK sources from extern/
Removes the OPENXR_USE_BUNDLED_SRC option which allowed using the
OpenXR-SDK sources bundled in extern/. It would be too much hassle to
keept these updated.
Now these have to be provided on the system Blender is compiled on. I've
already added necessary bits to install_deps.sh and our Windows
maintainer is ready to provide builds with OpenXR-SDK linked.
Once this gets into master, platform maintainers will have to be
notified about the added dependency.

This also removes the JsonCpp dependency, it was only needed for the
OpenXR-SDK sources.
2019-08-15 15:42:23 +02:00
Julian Eisel
9e7c48575a Linux: Add OpenXR-SDK to install_deps.sh 2019-08-14 22:59:33 +02:00
Julian Eisel
8138099fa9 Silence warnings in OpenXR SDK API layer files 2019-08-14 17:44:02 +02:00
Julian Eisel
02de1b9860 Quiet warning 2019-08-14 16:11:14 +02:00
Julian Eisel
57712625f2 Merge branch 'master' into soc-2019-openxr 2019-08-14 16:01:30 +02:00
Julian Eisel
96a34d7f50 Cleanup: Unused includes, better structuring for wm_xr.c 2019-08-09 16:35:28 +02:00
Julian Eisel
873223f38d Cleanup: Remove unused support for non-OpenGL Windows
This was very useful for testing, but there's no current need for it.
Neither for VR code, nor for anything else in master.
2019-08-09 16:08:34 +02:00
Julian Eisel
716c6b0c01 Cleanup: Move secondary GHOST-context handle to XR surface data
This is used to refer to the DirectX context. For other (currently
non-existant) surfaces, this may not make much sense.
2019-08-09 13:29:08 +02:00
Julian Eisel
62bbd2e37d Don't swap buffers of offscreen surface OpenGL contexts
This does frame syncing to the regular screen, so hurts performance in
some cases.
2019-08-08 22:00:21 +02:00
Julian Eisel
ba223dfac8 Exit OpenXR context/session gracefully if the runtime reports loss pending
Handle XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING and
XR_SESSION_STATE_LOSS_PENDING according to the specification.
2019-08-07 23:58:28 +02:00
Julian Eisel
8557997e81 Disable specular highlights in the VR viewport 2019-08-07 23:05:24 +02:00
Julian Eisel
bcc8f7c6be Fix xrDestroy calls to data already implicitly destroyed by OpenXR
Would effectifely result in null-ops, since the loader does good sanity
checks. The failing functions would still lead to error prints though.
2019-08-07 22:17:55 +02:00
Julian Eisel
fe7b01a08f Correctly request session end according to OpenXR 1.0 specification 2019-08-07 22:13:35 +02:00
Julian Eisel
5350015d51 Fix dark VR rendering on Windows Mixed Reality by appyling SRGB OETF
Discussed this in length with @sobotka, and it seems WMR has an utterly
broken pixel color pipeline. So we apply a SRGB OETF for this specific
runtime to compensate.
2019-08-07 11:52:30 +02:00
Julian Eisel
3483aa57b3 Allow querying OpenXR runtime ID
Useful in case special treatment is needed for certain runtimes.
Currently only WMR gets its ID assigned correctly, others are TODO.
2019-08-07 03:22:33 +02:00
Julian Eisel
44a220f721 Merge branch 'master' into soc-2019-openxr 2019-08-07 02:20:22 +02:00
Julian Eisel
5274c5cce6 Merge branch 'master' into soc-2019-openxr 2019-08-05 12:52:57 +02:00
Julian Eisel
0d70afed19 Merge branch 'master' into soc-2019-openxr 2019-08-02 23:35:40 +02:00
Julian Eisel
03b09dbe32 Fix compile error after merge and warning 2019-08-01 21:53:57 +02:00
Julian Eisel
f04a5ad1e4 Merge branch 'master' into soc-2019-openxr 2019-08-01 21:27:08 +02:00
Julian Eisel
ab1455e972 Fix error in OpenGL version check for OpenXR 1.0 2019-08-01 01:56:35 +02:00
Julian Eisel
b94af38c31 Fix compile error on GCC 2019-08-01 01:39:27 +02:00
Julian Eisel
40db778de3 Add sources for OpenXR core API validation layer
Had to do quite some changes to CMakeLists.txt from the SDK this time.
2019-08-01 00:28:16 +02:00
Julian Eisel
22966f4d35 Address changes in OpenXR 1.0 to get rendering to work again 2019-07-31 02:19:35 +02:00
Julian Eisel
e8f66ff060 Update OpenXR to version 1.0
Only tested on Windows.

Updates loader sources from the OpenXR SDK to latest 1.0 SDK and updates
requiremed version to 1.0. The compile time generation of files is a
thing of the past now (although you can still force it).
1.0 got released yesterday. Only one line needed fixing in our OpenXR
code to get it to compile. Rendering is black though.

For now I tried to keep edits to CMakeList.txt files minimal. So now
there are OpenXR CMake options exposed (with bad names), CMake prints,
etc.
2019-07-31 02:18:28 +02:00
Julian Eisel
9ac33e56a1 Merge branch 'master' into soc-2019-openxr 2019-07-30 22:19:41 +02:00
Julian Eisel
091cc94379 Use fixed lighting, don't make it rotate with view rotation 2019-07-24 16:41:46 +02:00
Julian Eisel
fc31be5ab0 Fix broken VR viewport rotation and movement 2019-07-24 02:52:03 +02:00
Julian Eisel
aff49f607a Use draw manager offscreen context for the VR session
This way we avoid the big overhead of context switches. Makes frames
render about twice as fast here. For heavy Spring scenes I'm getting
around 20 FPS here, classroom scene is at 50 FPS.
This is great given that drawing itself still isn't optimized for dual
eye rendering.
2019-07-24 01:39:04 +02:00
Julian Eisel
57b77cd193 Print 8 Frame average FPS for --debug-xr-time
Much more useful than a per frame FPS estimation. 8 frames are used for
the Blender viewport FPS stats too.
Refactored drawing data storage a bit.
2019-07-23 19:16:39 +02:00
Julian Eisel
d58eb8d29d Add --debug-xr-time command line option for VR frame time info prints
Outputs frame render time in milliseconds and FPS this time would add up
to. We could average times so FPS is a bit more stable, but the
precision of un-averaged results may be helpful too.
2019-07-23 02:06:08 +02:00
Julian Eisel
a4310ba85f Merge branch 'master' into soc-2019-openxr 2019-07-23 00:18:08 +02:00
Julian Eisel
bd42740ef1 Silence GCC warning 2019-07-21 13:15:00 +02:00
Julian Eisel
679a4c34fc Fix compile error with bundled OpenXR sources 2019-07-21 03:18:02 +02:00
Julian Eisel
55362436d9 Fix troubling memory leak in offscreen viewport drawing
I'm not really sure why the leak happened - draw manager kept allocating
certain buffers - but I figured I could avoid it by not recreating
GPU_offscreen/GPU_viewport on every redraw.
This should also improve performance a bit.
2019-07-21 01:10:18 +02:00
Julian Eisel
c1d164070b Pure OpenGL backend works now, let it take priority over DirectX 2019-07-20 19:34:50 +02:00
Julian Eisel
3a4034a741 Make OpenGL-only session backend work
Previously, only DirectX HMD rendering would work (and still takes
priority).
2019-07-20 19:33:11 +02:00
Julian Eisel
a0be113d2e Fix DirectX context not freed on session exit
Also rename XrSurfaceData to wmXrSurfaceData
2019-07-17 15:18:27 +02:00
Julian Eisel
151fb129e7 Fix for previous commit, accidental call to xrDestroySwapchain 2019-07-17 14:51:21 +02:00
Julian Eisel
165c5a5259 Fix possible OpenXR swapchain leak by using new unique_oxr_ptr 2019-07-17 14:05:06 +02:00
Julian Eisel
74fc1db25b Add helper class to RAII manage OpenXR handles
Adds generic unique_oxr_ptr to wrap xrCreate and xrDestroy functions of
OpenXR handles into a unique_ptr like RAII interface.

While for most cases, OpenXR resources can be freed by their owning
object, sometimes errors may occor before final ownership is established.
E.g. swapchain ownership is only transfered to the session object once
its swapchain-images are created - which may fail. With this RAII
wrapper, the swapchain would be freed on error (as this triggers stack
unwinding through an exception), no matter who holds ownership to it
currently.
There are other solutions to this problem, e.g. by establishing final
ownership right after/upon creation, or by explicit freeing in case an
error is spotted; it's too easy to make mistakes here though. Plus, we
may want to experiment with using this API for all OpenXR resources, to
entirely avoid the possibility of them leaking.
2019-07-17 13:35:14 +02:00
Julian Eisel
03ff2a8dd5 Fix compile error with USE_FORCE_WINDOWED_SESSION enabled
At least get it to compile, this is still kinda broken though.
2019-07-17 11:29:34 +02:00
d99d15f48d Add helper batch file for testing on oculus rift. 2019-07-16 16:41:44 -06:00
Julian Eisel
6a998833cd Temporarily let DirectX take priority over OpenGL
OpenGL doesn't work yet. Shouldn't be too difficult to get working, but
I don't have a working OpenXR runtime with OpenGL support to test here.
2019-07-16 21:48:29 +02:00
Julian Eisel
fca4826c7f Merge branch 'master' into soc-2019-openxr 2019-07-16 21:09:30 +02:00
Julian Eisel
b0845fc133 Fix some issues, improve error message
Fixes:
* Destruct surface when destroying session on error. Fixes null pointer
  dereference when trying to draw the surface on next redraw.
* Fix trying to enable same extensions/API-layers multiple times due to
  static array usage not being cleared after error.
* Null pointer dereference with OpenGL drawing
2019-07-13 16:22:26 +02:00
Julian Eisel
70cf8bd9c6 Fix crash on OpenXR error before context is created fully 2019-07-13 01:19:58 +02:00
Julian Eisel
3a2e459f58 Show useful error reports in case of errors.
E.g. with an active OpenXR runtime installed, but no HMD plugged in,
Blender will now show: "Failed to get device information. Is a device
plugged in?".
In case of such errors, the VR-session will be cleanly exited, with
no side effects to the rest of Blender (at least if there are no bugs).

The GHOST_Xr API now allows setting a custom error handling callback
which may cleanly destroy all GHOST_Xr data.
2019-07-12 19:51:38 +02:00
Julian Eisel
330f062099 Safe and informative GHOST_Xr error handling
This wraps all functions that could fail into some proper (although
unfinished) error handling.

These were the requirements for the error handling strategy:
* If an error occurs, cleanly exit the VR session (or the context if the
  error happend during its set up), causing no resource leaks or side
  effects to the rest of Blender.
* Show a *useful* error message to the user.
* Don't impair readability of code too much with error handling.

After some back and forth I decided Ghost internal exceptions are the
best way to go about this. I get exceptions are a controversial feature,
IMHO that's because most people use them 'wrong' however. Here's the
rationale:
* Most alternatives require early exiting functions. This early exiting
  has to be 'bubbled up' the call stack to the point that performs error
  handling. So the code gets really impaired by error checking. Tried
  this first and wasn't happy with it at all. Even if error handling is
  wrapped into macros.
* All GHOST_Xr resources are managed via RAII. So stack unwinding will
  cause them to be released cleanly whenever an exception is thrown.
* GHOST_Xr has a clear boundary (the Ghost C-API) with only a handful of
  public functions. That is the only place we need to have try-catch
  blocks at.
  (Generally, try-catch blocks at kinda random places are a bad code
  smell IMHO. Module boundaries are a valid place to put them.)
* Exceptions allow us to pass multiple bits of error information through
  mulitple layers of the call stack. This information can also be made
  specific with a useful error message.
  As of now, they conain a user error message, the OpenXR error code (if
  any), as well as the exact source code location the error was caught
  at.

So if an error is caught inside GHOST_Xr code, an exception is thrown
with specific and hopefully useful information in it. In the Ghost C-API,
these exceptions are caught and passed on to a custom error handling
callback. This callback will be defined by the Blender window-manager
and output the error information via a usual user report popup (not done
yet). It can also ensure the entire session is shut down.

Note that the majority of errors OpenXR can return are for invalid API
usage. Assuming the API usage is valid though, most error messages
should never reach users and can be left a bit more vague. Maybe we can
add something like "This is probably a bug and should be reported" to
those.
2019-07-12 14:40:50 +02:00
Julian Eisel
09872df1c7 Check runtime DirectX requirements for graphics binding too 2019-07-11 21:05:13 +02:00
Julian Eisel
67d6399da6 Check runtime OpenGL requirements prior to creating graphics binding
DirectX will need these checks too.
Also fix warnings due to wrong printf formatting.
2019-07-11 20:36:54 +02:00
Julian Eisel
c29724912b Merge branch 'master' into soc-2019-openxr 2019-07-11 20:28:19 +02:00
Julian Eisel
99560d9657 Disable debug extension on Windows
Unfortunately, enabling XR_EXT_debug_utils crashes instance creation
with the Windows Mixed Reality runtime. Maybe I'm doing something wrong,
for now, just disable it.
2019-07-11 16:44:51 +02:00
Julian Eisel
b8a7b87873 General minor fixes and cleanup
* Initialize all class member variables
* Add version to runtime name printing
* Separate functionality code from debug prints
* Improve code structure using Doxygen groups
* Make accessors const functions
* Add (Doxygen) comments
* Naming
* Reorder functions
2019-07-11 16:36:04 +02:00
Julian Eisel
c9f6c1a054 Fix wrong return value causing OpenXR initialization to fail 2019-07-11 00:51:00 +02:00
Julian Eisel
dd0fcb50b4 Fix compile errors on windows and with bundled OpenXR SDK sources 2019-07-11 00:50:10 +02:00
Julian Eisel
c1e9cf00ac Refactor GHOST_XrContext into class + interface
Makes GHOST_Xr much more consistent with the rest of GHOST. Basically I
added a GHOST_IXrContext interface which can be called by the GHOST
C-API. The internal GHOST_XrContext class implements this.
Outside of GHOST only the opaque GHOST_XrContextHandle is accessible.

Kept GHOST_Xr_intern.h and GHOST_Xr.cpp for now. I'll probably remove
them soon. There's not much reason for both of them to be there.
2019-07-10 23:53:07 +02:00
Julian Eisel
84d609f67b Use OpenXR extension for extra debug messages in debug mode
Enables (or tries to) the XR_EXT_debug_utils extension which allows
setting a custom callback for additional debug prints. Note that I
haven't been able to test this really, as the Monado runtime appears to
not have this fully implemented (had to force sending a custom message
to find that out...). Will test with the Windows MR runtime in a bit. We
can also improve message quality then (it can print the exact function
name the message was sent from, print additional custom labels which
could indicate session state, etc.).
2019-07-10 15:08:52 +02:00
Julian Eisel
86178548d5 Only try to enable OpenXR API validation layer in debug mode 2019-07-10 15:08:10 +02:00
Julian Eisel
d711540a85 Cleanup: Rename XR_DEBUG_BEGIN -> XR_DEBUG_ONLY_BEGIN
Of course also renames XR_DEBUG_END accordingly.
2019-07-10 15:06:08 +02:00
Julian Eisel
6e3158cb00 Only print info messages with --debug-xr enabled 2019-07-09 17:49:54 +02:00
Julian Eisel
b216690505 Add --debug-xr commandline arg and pass on to GHOST XR contexts
Doesn't do anything yet.
2019-07-09 17:20:01 +02:00
Julian Eisel
b98896ddd9 Preparations to allow enabling OpenXR API validation layer
For this to work two environment variables have to be set:
XR_API_LAYER_PATH and LD_LIBRARY_PATH, both have to point to the API
layers built by the OpenXR SDK. It also requires you compile Blender
linked to your own SDK build (OPENXR_USE_BUNDLED_SRC disabled).
Further changes will make this set up unnecessary, so validation layers
can be enabled via some flag.
2019-07-09 16:45:21 +02:00
Julian Eisel
a05104d61f Fix warnings and compile error on GCC 2019-07-09 11:28:17 +02:00
Julian Eisel
7fe1cc8d24 Enable grid floor in VR session
Helps quite a bit orientating.
2019-07-09 10:56:37 +02:00
Julian Eisel
70e84a2c20 Merge branch 'master' into soc-2019-openxr 2019-07-08 14:18:08 +02:00
Julian Eisel
084a33ca94 Use base pose from Blender camera
I was trying to set the camera pose as OpenXR reference pose. But then I
got really strange poses for drawing back from OpenXR. Couldn't figure
out a way to solve this.
Now we just apply OpenXR's draw pose to the Blender camera pose. If we
later want to support moving around in the scene (e.g. via teleporting),
that has to be changed.

Also uses flipped drawing for DirectX surface to correct DirectX upside
down drawing (compared to OpenGL).
2019-07-08 14:13:14 +02:00
Julian Eisel
37f619aea3 Don't recreate reference local space on each redraw
Set this up on session start.
2019-07-07 13:07:51 +02:00
Julian Eisel
6904ab10f4 Add GHOST_XrSession class for cleaner & safer session management
Session code and data structures are now localized. But also, this
enables sessions to use deterministic destruction to end itself cleanly.
So whenever an error occurs, we can use stack unwinding which will cause
graceful ending of the session.
2019-07-07 12:45:37 +02:00
Julian Eisel
146ef0dd1e Properly end VR sessions fixing crash on next session start
Previously, you had to restart Blender to start another session.
2019-07-03 21:01:58 +02:00
Julian Eisel
5891e86420 Cleanup GHOST_Xr types and functions
* Move GHOST_Xr types to GHOST_Types.h
* Add GHOST_XrPose. We'll have to pass around pose data at multiple
  places.
* Don't require extra call to prepare session rendering, handle
everything through GHOST_XrSessionStart
* Naming
2019-07-01 19:04:54 +02:00
Julian Eisel
2cedad990a Initial HMD viewport rendering (DirectX only first)
Finally: This makes it possible to render a viewport to an HMD via
OpenXR. Pure OpenGL rendering will need some more tweaks to work.
To my great delight, performance is quite good for reasonably sized
scenes.

Had to do some hacks and marked some TODOs. Nothing too bad though.

Here are a couple of notes:
* Current initial pose is pretty useless, think it just looks downwards
  from world origin. Will change that soon.
* The rendered viewport has some issues: Too dark (bad lighting?), grid
  doesn't show up even though I told it to, lighting seems to change with
  view position/rotation, etc. Needs some polish.
* Ideally we'd just use the D3D11 Texture given to us via the OpenXR
  swapchain and blit the OpenGL framebuffer into that. However the
  NV_DX_interop extension fails doing this. Seems like this is a NVidia
  Optimus only issue, but I'm missing the hardware to confirm.
  So instead, we blit into the D3D11 back buffer first and then into the
  Texture.
* The draw-manager uses its own offscreen context so we have to get the
  render result from the draw-manager context to the VR session's
  context first. Luckily I've already added code to support blitting from
  one OpenGL context into another. But it requires blitting twice.
  Blitting should be very cheap, but still...
  Draw-manager could get a context to use passed instead.
2019-07-01 15:57:32 +02:00
Julian Eisel
109be29e42 Draw offscreen viewport in XR session surface callback
Not visible yet, but it should draw in the offscreen. The way this is
now, we don't depend on the Window->Workspace->bScreen->... chain. We
simply draw an offscreen viewport in the draw callback of the XR session
surface.

The drawing also uses view and projection matrices from OpenXR (or
calculated from OpenXR data).
2019-06-29 02:30:23 +02:00
Julian Eisel
13442da69f Move WM level XR functions to wm_xr.c
Operator is still in wm_operators.c, but only calls wm_xr.c functions.
2019-06-28 22:53:46 +02:00
Julian Eisel
231dbd53bf Support Window-less (offscreen) VR session on Windows
Uses the new wmSurface type (non-window drawable container) to manage
the OpenGL, DirectX and GPU module contexts. The draw callback of the XR
surface calls the GHOST_Xr session drawing routines.

What you should see when starting a VR session now (using the WMR
runtime): The Windows Mixed Reality Portal pops up, and a blue
background is drawn on the HMD. This is from the blue color clear call
we do in the drawing preparations of the GHOST_Xr session drawing.
2019-06-28 16:24:24 +02:00
Julian Eisel
d3e48fb096 Merge branch 'master' into soc-2019-openxr 2019-06-28 14:09:08 +02:00
Julian Eisel
d544a0b41c Avoid std::vector copy 2019-06-28 13:56:10 +02:00
Julian Eisel
cf4799e299 Add wmSurface for non-Window offscreen VR session drawing
Adds a wmSurface type which acts as a container for non-Window (offscreen)
draw surfaces. Ideally wmWindow would of course also just do C-style
inheritance from wmSurface, but I guess they can co-exist too.
For the VR session a surface is created on Linux and passed to the
graphics binding to use.

Note this is not used on Windows yet, it still opens a window there.
2019-06-28 13:38:34 +02:00
Julian Eisel
57d9f004aa Fix compile/CMake errors and warnings on Linux 2019-06-27 19:55:22 +02:00
Julian Eisel
62cde7a9ef Finish VR view drawing callback set up
* Allow passing custom data to session draw function, passed to the
  callback
* Actually call the callback
* Create and bind a WM level callback. Will later be used to draw the
  viewport.

Also, check if session is actually visible before drawing.
2019-06-27 19:17:12 +02:00
Julian Eisel
e4fcf25fc5 Don't use Microsoft::WRL::ComPtr<...> for COM types
Makes things difficult if you're not familar with COM.
2019-06-27 18:56:20 +02:00
Julian Eisel
215c919b33 Merge branch 'master' into soc-2019-openxr 2019-06-26 18:39:31 +02:00
Julian Eisel
da44a02d00 The first pixels pushed to Windows Mixed Reality HMDs!
Just a clear call for now, so all you see is a blue world. This blue
"world" is however drawn by Blender!

Also fixes use after destruction of compositor layer data.
2019-06-24 21:22:23 +02:00
Julian Eisel
867007d9d7 Set up OpenXR compositing layers for drawing
That should be one of the last steps to prepare pushing pixels to HMDs.
Fingers crossed!
2019-06-24 16:44:43 +02:00
Julian Eisel
e9ea814233 Merge branch 'master' into soc-2019-openxr 2019-06-24 12:52:37 +02:00
Julian Eisel
6b43c82cb5 Set up OpenXR views and spaces for drawing
Using a dummy identity pose at {0, 0, 0} to start with. This should
later use the current viewport position & orientation I guess.

Also adds function to set a draw callback. There's quite some OpenXR
related stuff to be done before and after drawing anyting, as well as
before and after drawing each view (eye). Quite some info would have to
be exposed to WM to let it manage drawing. So I think using a callback
called from GHOST_Xr to draw each eye instead is a good way to go.

VR session currently crashes after opening. Seems to be related to
blocking frame wait call. I'm not too worried about that though, might
disappear once OpenXR frame sync functions get proper timing info
passed.
2019-06-23 18:27:24 +02:00
Julian Eisel
afbb62fecd Bring back wm_xr.c for higher level XR functions 2019-06-23 15:42:18 +02:00
Julian Eisel
8a676e8fa9 Execute necessary OpenXR frame timing calls 2019-06-23 13:47:42 +02:00
Julian Eisel
c52111e983 Correctly destruct swapchain on shutdown 2019-06-23 02:46:25 +02:00
Julian Eisel
d749e8a2c4 Create graphics binding specific swapchain images
Following the OpenXR SDK's example code very closely here. We have to do
some nasty converting of graphics binding specific image vectors to
generalized base ones. The SDK's approach seems like a good way to go
about this.
2019-06-23 02:12:38 +02:00
Julian Eisel
8663aa80e6 Use abstract class/interface for generalized graphics binding operations
Rather than having switch case blocks throughout the session code, give
binding operations an own interface with dedicated implementations.
2019-06-23 00:37:17 +02:00
Julian Eisel
88b39444a0 Fix error causing sessions to not start correctly
With this, the Windows Mixed Reality Portal finally pops up when
starting the session. That is how it's supposed to work. After it's
initialization phase all you see is black. That's expected too as we
don't send anything to the device yet.
2019-06-22 22:08:50 +02:00
Julian Eisel
4cfc3caa09 OpenXR swapchain creation
Nothing special to say. Just calls needed OpenXR functions to create
swapchains. Swapchain images are not created yet.

Interestingly, the Windows Mixed Realtiy portal now pops up when closing
Blender after having created a VR session. So we're getting closer ;)
2019-06-22 21:25:58 +02:00
Julian Eisel
28428b3462 Merge branch 'master' into soc-2019-openxr 2019-06-21 22:31:01 +02:00
Julian Eisel
24146563a0 Cleanup: Use CamelCase for XR functions/types
Also silence warnings.
2019-06-21 22:27:40 +02:00
Julian Eisel
2ee9c60c20 Finish OpenXR GLX binding initialization
Monado now opens a window here when asking it to start a session. That
seems to be the case because it doesn't detect the HMD as direct mode
capable yet. But that shouldn't be an issue from our side.
2019-06-19 21:11:21 +02:00
Julian Eisel
fb64675209 Fix invalid delete operator use
Again a thing MSVC should warn about but didn't...
2019-06-19 19:09:40 +02:00
Julian Eisel
76385139cf Use friend class to access graphics data on Windows too
Also fix memory leak.
2019-06-19 18:30:19 +02:00
Julian Eisel
b18f5a6a81 Pass graphics context data to OpenXR graphics bindings on Linux too
Refactors function into a class, and make this class a friend of
GHOST_ContextGLX. That seems like a better way to access low level
graphics data for this specific case, rather than giving anyone access
via a getter.
2019-06-19 17:23:41 +02:00
Julian Eisel
9d29373b06 Init OpenXR graphics bindings with valid graphics context (Win only)
Will do this for Linux in a separate commit.

Also fixes a stupid mistake from previous commit on lazy-creation of XR
context.
2019-06-19 12:20:18 +02:00
Julian Eisel
f2f1e4dfed Remove CTX_wm_xr_context
Not really useful, plus XR-Context is now GHOST data.
2019-06-19 01:00:37 +02:00
Julian Eisel
0da0f29ade Rename of XR types (WM -> GHOST) 2019-06-19 00:57:50 +02:00
Julian Eisel
a8519dbac2 Lazy-create XR-context
Creating the context causes the OpenXR loader to try connect to a
runtime. That would involve reading the OS'es active_runtime.json and
dynamic linking based on that. So better avoid doing this on startup.
Also: don't pay for what you don't use!
2019-06-19 00:44:42 +02:00
Julian Eisel
d15d07c4f6 Rename wm_xr_ -> GHOST_XR 2019-06-19 00:28:37 +02:00
Julian Eisel
d356787a65 Merge branch 'soc-2019-openxr' into temp-ghost_openxr 2019-06-18 23:50:28 +02:00
Julian Eisel
a284fa3abb Merge branch 'master' into soc-2019-openxr 2019-06-18 23:49:54 +02:00
Julian Eisel
4eeb7523e9 Use some C++ features where useful
Also correct include guards.
2019-06-18 01:02:33 +02:00
Julian Eisel
f30fcd6c85 Initially move XR files to GHOST and compile in C++ 2019-06-17 23:45:28 +02:00
Julian Eisel
47e8133520 Merge branch 'master' into soc-2019-openxr 2019-06-17 22:24:51 +02:00
Julian Eisel
3fa7d59a04 Fail without crashing if no runtime is found
For now simply do nothing. Plan is to work on proper error handling and
reporting later.
2019-06-17 01:24:07 +02:00
Julian Eisel
df8dc43946 Fix compile errors and warnings on certain configs
Addresses:
* Compile error on Linux
* Compile error with WITH_OPENXR disabled
* Unused parameter warnings
2019-06-16 23:28:14 +02:00
Julian Eisel
3b0a2fecfc Fix missing return value... how did this work even?
Looking at the code this should've failed miserably. No idea how this
could still work fine... Maybe return vars used same stack location?
2019-06-16 23:12:13 +02:00
Julian Eisel
80af6d534d Merge branch 'master' into soc-2019-openxr 2019-06-16 22:58:56 +02:00
Julian Eisel
71c7d61808 Draw OpenGL framebuffer upside down in DirectX windows
DirectX is Y coordinates top to bottom, while OpenGL is the opposite.
For the final window manager on-screen drawing, draw to a texture first
and draw that upside down if needed.
2019-06-16 21:46:57 +02:00
Julian Eisel
637b803b97 Support drawing the VR view into a DirectX window!
Phew! That a fight. But this is also a pretty important feature as it
allows interfacing with Windows Mixed Reality OpenXR runtime and the
HMDs supported by it.

Important remaining issue: The rendered viewport is upside down :) That
is of course because DirectX has the opposite vertical direction than
OpenGL.

When creating a DirectX window, we also create an OpenGL offscreen
context to use for all drawing. Just before swapping framebuffers, the
DirectX window blits the framebuffer of the offscreen context into its
swapchain. This requires the WGL_NV_DX_interop and WGL_NV_DX_interop2
extensions.

For testing/dev purposes, also adds:
* Version of the offscreen to onscreen blitting that's OpenGL only. So
  it blits the default framebuffer of the offscreen context into the one
  of the onscreen context.
  This is disabled by a #define.
* Code to draw a colored triangle using DirectX, also for testing.
  Requires the D3DCompiler.lib to be available at compile time. This is
  also disabled using a #define.
2019-06-16 21:05:21 +02:00
Julian Eisel
314eef0df8 Merge branch 'master' into soc-2019-openxr 2019-06-14 20:41:09 +02:00
Julian Eisel
34fa0f8ac6 Set up DirectX window to support drawing
With this the VR window should open fine and get cleared in a red-ish
orange using Direct3D 11 calls (well, on Windows that is).

The window still draws a 3D view to an offscreen buffer. Where we
usually just swap the buffers, we now allow calling a GHOST function to
blit the offscreen OpenGL buffer to whatever type of graphics buffer the
window uses (DirectX here).
The nice thing about this approach is that all DirectX code stays in
GHOST_ContextD3D.cpp. And the entire compatibiliy code can go into a
single function higher level modules don't need to care about.

This also fixes a number of issues introduced in earlier commits.
2019-06-14 19:07:10 +02:00
Julian Eisel
16366724bd Draw into OpenGL offscreen context in the DirectX window.
The window doesn't show anything of course. However we draw (at least I
assume it does) as regular, just into a window offscreen context.

A valid 3D view is created in the window. It's not visible but you see
cursor changes as you move over the window. So handling works.
2019-06-14 02:41:59 +02:00
Julian Eisel
fc8127d070 (Disabled) code to open a DirectX window with the VR session
The window immediately crashes, hence keeping it disabled for now.

Not sure how much of this I'll leave in, for now this is mainly for
testing DirectX compatibility.
2019-06-13 23:24:30 +02:00
Julian Eisel
3ac37fb552 Fix compile errors with older MSVC/Win-SDK versions
Reported by @LazyDodo, thanks!
2019-06-13 18:22:26 +02:00
Julian Eisel
8e51a75772 Fix mistake causing compiler error on Windows
Stupid one...
2019-06-12 23:45:19 +02:00
Julian Eisel
ba2dab402d Merge branch 'master' into soc-2019-openxr 2019-06-12 21:28:40 +02:00
Julian Eisel
796994d222 Refactor graphics context binding to avoid memory leaks
* Retrieve graphics context to bind through callbacks so the XR code can
  manage their lifetime.
* Use static union to store system & chosen graphics lib specific
  graphics binding data.

Makes some things a bit cleaner, too.
2019-06-12 21:27:00 +02:00
Julian Eisel
66e90e9179 Fix compile error and warning on GCC 2019-06-12 19:28:51 +02:00
Julian Eisel
1404edbe3a Support DirectX Ghost context creation
Adds support for creating a DirectX 11 Ghost context. It's not used yet
and more stuff besides creation is needed. Also, other versions than 11
should probably be supported.
We need a DirectX context to support the Windows Mixed Reality OpenXR
Runtime, a rather important one to support. Idea is to use an extension
for OpenGL-DirectX interoperability for drawing the OpenGL offscreen
viewport render using DirectX.
2019-06-12 11:34:21 +02:00
Julian Eisel
2f68a76409 Split wm_xr.c into multiple files
Similar to gizmo/ and message_bus/, there's now a xr/ directory
containing header files and a intern/ directory for source and internal
header files.

Guess this is reasonable to do. And better to do early on to avoid
loosing much git history.
2019-06-11 17:52:04 +02:00
Julian Eisel
304d9a20fc Fix compile errors and crashes on Windows
* Include needed Windows/DirectX headers
* Disable zero sized arraz (GCC extension)
* Add missing break causing failling assert
* Add missing semicolon in Win only code :)
2019-06-11 16:35:31 +02:00
Julian Eisel
b169e327bf Fix compile error with system OpenXR SDK
Graphics binding types were disabled by a compiler flag then.
2019-06-11 14:18:35 +02:00
Julian Eisel
7238bbecc4 Cleanup: Rename graphics-lib to graphics-binding 2019-06-10 22:16:09 +02:00
Julian Eisel
a49b4ca402 Merge branch 'master' into soc-2019-openxr 2019-06-10 22:06:42 +02:00
Julian Eisel
eb0424c946 Proper management of OpenXR graphics bindings for session setup
OpenXR needs to interface with some graphics library (OpenGL, Vulkan,
DirectX, etc.). This is done through graphics binding extensions. The
OpenXR specification requires these to be properly set up before a
session is created.

Adds the following:
* Support priority list of multiple graphics binding extensions (e.g.
  check OpenGL extension availability first, DirectX on Windows second,
  etc.)
* Barebones for passing graphics library data to OpenXR session
  creation. This is highly system dependent, e.g. it requires GLX data
  for OpenGL on X11 systems (XrGraphicsBindingOpenGLXlibKHR). More work,
  including additions to GHOST, will be needed once I get to the more
  graphics related stuff.
* Create an own graphics context for the VR session. It's not doing
  anything useful yet. This is just to fool the Monado OpenXR runtime
  so that it actually attempts to create the OpenXR session.
* Had to add two CMake modules for platform dependent #define's required
  by the OpenXR specification.
2019-06-10 21:59:26 +02:00
Julian Eisel
5d6da57aa3 Cleanup: Move OpenXRData struct out of wmXRContext
Just to make access a bit more convenient.
2019-06-06 18:38:06 +02:00
Julian Eisel
e968bbc5d8 Fix wrong enum-type used for switch
Why doesn't MSVC warn about this, grr...
2019-06-06 17:37:18 +02:00
Julian Eisel
b1b0e05c54 Fix CMake errors after merge (?)
Not sure if this is caused by changes just merged in, or by a system
upgrade I just did. Either way, fixed it now.
2019-06-06 11:25:53 +02:00
Julian Eisel
e547026dfe Merge branch 'master' into soc-2019-openxr 2019-06-06 10:56:19 +02:00
Julian Eisel
f816380af5 Silence warning, fix mem-leak, don't destroy NULL session 2019-06-05 18:03:59 +02:00
Julian Eisel
5e642bfea1 Initial session state handling
To correctly start a session, a graphics extension specific object needs
to be passed to the OpenXR runtime. E.g. for the Windows Mixed Reality
runtime, XrGraphicsBindingD3D11KHR needs to be passed with a valid
DirectX device. Since we don't have any DirectX compatibility working,
I can't test this on Windows yet.
So to test this I finally need to get Monado to work on Linux and
correctly setup the OpenGL extension there.
2019-06-05 16:55:51 +02:00
Julian Eisel
0d1a22f74f Barebones for managing session changes
Adds initial OpenXR event querying so that session state change events
can be handled. Doesn't do any handling yet.
2019-06-05 10:20:51 +02:00
Julian Eisel
20a1af936d Enable graphics extensions if available
Check if available extensions includes the GL one, or the DirectX one on
Windows. Enable them if available.
2019-06-05 01:00:13 +02:00
Julian Eisel
c9c1b90532 Cleanup: Correct local variable name 2019-06-04 18:30:07 +02:00
Julian Eisel
4192281e14 Fix layer and extension count not stored as intended 2019-06-04 18:27:44 +02:00
Julian Eisel
329deadc9e Print OpenXR runtime name once connected 2019-06-04 17:39:12 +02:00
Julian Eisel
53845c554d Merge branch 'master' into soc-2019-openxr 2019-06-04 17:00:58 +02:00
Julian Eisel
35c9e3beed Initial VR-session starting/ending
Adds operator to toggle a VR session, exposed in the Window top-bar
menu. It triggers the needed calls for session creation and destruction.
Setting up the XR-system (a configuration of related devices) is also
done now.

Calling WMR runtime functions fails currently. Not sure why. So while
this executes required routines, it doesn't really work.
2019-06-04 16:42:42 +02:00
Julian Eisel
60f66768cf Fix GCC compile error, warnings and uninitialized use
extension_count could be used uninitialized if no valid OpenXR runtime
was run.
2019-06-02 22:04:52 +02:00
Julian Eisel
3e88974a80 Merge branch 'master' into soc-2019-openxr 2019-06-02 15:24:33 +02:00
Julian Eisel
09e7d6cd26 Correct previous commit
Intended to print out name, not address.
2019-06-02 02:24:04 +02:00
Julian Eisel
5d5ad5d6dd Gather available OpenXR extensions and API-layers on OpenXR setup
We don't actually enable any extension or layer yet. We just put their
names into arrays and print them. The printing can be disabled via a
compiler define, later we should put them behind a proper
logging/debugging mechanism (CLOG).

Also fixes a Visual Studio compile error.
2019-06-01 17:16:49 +02:00
Julian Eisel
e70894c360 Fix compiling with bundled OpenXR SDK sources
Also remove unused include.
2019-05-30 16:22:05 +02:00
Julian Eisel
4c11886c4e Corrections to previous commit
* Remove testing instance creation
* Rename function
2019-05-30 14:56:23 +02:00
Julian Eisel
41e2f2e75f Proper creation & destruction of OpenXR instances
Adds wm_xr.c for an XR management API and creates/destroys the OpenXR
instance through this. This is as planned in my proposal, to lock the
OpenXR calls behind an abstraction.
XR data will be stored in a (non-public) wmXRContext struct within the
window-manager.

For now, creates the OpenXR instance on startup. I think it's better to
lazy setup this, as in, only creating the instance once the user starts
the first XR session. Just to avoid costs for something that may not be
used (the OpenXR loader we use will try loading and parsing the system's
OpenXR active_runtime.json on instance creation). That's for later when
I introduce session management though.

Also added a context getter for the xr-context, which is unused but may
be handy later.
2019-05-30 14:48:13 +02:00
Julian Eisel
864abbd425 Support system installed OpenXR SDK
Adds OPENXR_USE_BUNDLED_SRC so that if disabled, CMake tries to find
the SDK headers and libraries in system paths or in specified root
directory.

I guess this is the way we'd want to do this in master. However for
people testing the branch the bundled sources are much more convenient
(should work out of the box, no need to compile the SDK manually).
2019-05-30 01:44:13 +02:00
Julian Eisel
f333e7eb56 Merge branch 'master' into soc-2019-openxr 2019-05-29 20:14:11 +02:00
Julian Eisel
a2ac2ec3c3 Merge branch 'master' into soc-2019-openxr 2019-05-29 15:17:41 +02:00
Julian Eisel
06d52afcda Linux: OpenXR Linking via OpenXR Loader
Calling OpenXR functions should now work on both Windows and Linux.

Also includes:
* Silence Linux only warnings
* Remove common_cmake_config.h and let CMake generate it when
  configuring (contents vary on system it's compiled on)
* Remove JsonCpp CMake install target
* Remove unnecessary CMakeLists for JsonCpp includes
* Remove unnecessary CMake commands
* Style cleanup
2019-05-28 21:58:18 +02:00
Julian Eisel
e65ba62c37 Windows: OpenXR Linking via OpenXR Loader
Adds needed headers for OpenXR, the loader from the OpenXR SDK and
JsonCpp into extern. Took a while to get this to compile/link, but on
Win10 it works fine now without patching #includes. Linux probably
needs more work.

Added a compile option WITH_OPENXR to toggle XR feature compiling.

Also does a dummy xrCreateInstance() call to test linking.
2019-05-28 01:21:25 +02:00
87 changed files with 4804 additions and 217 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View 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__

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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__ */

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

View 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 */

View 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__

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

View 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__

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

View 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 */

View 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__ */

View 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.");
}

View 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

View 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__ */

View 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__ */

View 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

View 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"
}
}

View File

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

View File

@@ -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. */
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
/** \} */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, &region)) {
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, &region)) {
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, &region);
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, &region);
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;
}

View File

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

View File

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

View File

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

View File

@@ -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, &region)) {
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, &region_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
/** \} */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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__ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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 */

View File

@@ -257,6 +257,7 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self,
(float(*)[4])py_mat_projection->matrix,
true,
true,
true,
"",
false,
self->ofs,

View File

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

View File

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

View File

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

View File

@@ -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;
/**

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View 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 */

View File

@@ -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__ */

View 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__ */

View File

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

View File

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

View File

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

View File

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