1
1

Compare commits

...

246 Commits

Author SHA1 Message Date
6fc81d6bca Merge branch 'master' into xr-controller-support 2021-10-03 12:22:05 +09:00
85e1f28fca Fix controller model loading for no stb image 2021-10-03 12:16:07 +09:00
c4f65fa5da Cleanup
- Use doxygen style comments
- Improve comment for XR region type
- Improve RNA descriptions for XR nav location/rotation/scale
- Split controller draw callback into separate model and aim functions
2021-10-03 12:11:10 +09:00
dda9762a16 Remove old TinyGLTF files 2021-09-22 19:38:33 -07:00
fa23369373 Merge branch 'master' into xr-controller-support 2021-09-22 19:24:20 -07:00
1ef02d8f4b Update with changes from D10948, D12472 2021-09-22 19:16:52 -07:00
6d7113c363 Merge branch 'master' into xr-controller-support 2021-09-10 17:57:57 +09:00
33306067da Update based on D10948 2021-09-10 17:23:56 +09:00
ff5733ef2f Merge branch 'master' into xr-controller-support 2021-09-02 13:39:59 +09:00
c996926c05 Remove XrSessionState.reset_navigation() RNA func
Function was unnecessary since XrSessionState.reset_to_base_pose()
will also reset navigation deltas.
2021-09-02 13:27:55 +09:00
593621fdfb Merge branch 'master' into xr-controller-support 2021-08-31 18:05:42 +09:00
07a92c616f XR: Add reset navigation operator
Resets XR navigation deltas relative to session base pose. Primarily
useful for undoing elevation/scale changes. Will be added to the
default VR actions.
2021-08-31 17:58:22 +09:00
99ce2f3e4d XR: Replace invoke/modal_3d for XR operators
Special 3D-to-2D handling (as invoke/modal_3d is used for) is not
necessary for regular XR operators, so they can use the normal
invoke/modal callbacks.
2021-08-31 17:48:29 +09:00
c8c782fbf4 Cleanup: remove unused struct member, null checks 2021-08-31 17:42:55 +09:00
0f1ef110a4 Merge branch 'master' into xr-controller-support 2021-08-26 19:29:20 +09:00
5fd158bb87 XR: Refactor motion capture objects
This refactors the feature of binding objects to controllers
and recording auto-keyframes, or "motion capture objects", by
providing a more complete API for managing objects and moving the
implementation out of wm_xr_session.c and into its own file
(wm_xr_mocap.c).

In addition, motion capture objects are now stored as a dynamic array
instead of a fixed array, which was previously hard-coded for
specific devices. Each entry in this dynamic array is uniquely
identified by an Object pointer and is mapped to a VR device via an
OpenXR user path. For example, an object can be bound to the headset
via "/user/head", and the left controller via "/user/hand/left".
2021-08-26 19:23:14 +09:00
21a24aa61e Fix view3d.toggle_shading() not updating VR view
Reason was that the WM notifier did not set the NS_VIEW3D_SHADING
subtype, which the VR view listens for for a shading update.

In the case of view3d.toggle_xray(), a notifier was absent
altogether.
2021-08-26 18:55:50 +09:00
c9a4c29589 Cleanup: remove unnecessary #ifdefs 2021-08-26 18:36:29 +09:00
a063d58080 Merge branch 'master' into xr-controller-support 2021-08-20 20:50:24 +09:00
f58bebf688 XR: Fix controller model world transforms
Fixes incorrect display of Reverb G2 controller model/animated parts.

Thanks to Werner Trunk for help with debugging.
2021-08-20 20:46:15 +09:00
ba79625f9e Merge branch 'master' into xr-controller-support 2021-08-16 18:57:48 +09:00
72381da800 XR: Don't store controller node world transforms
Removes unnecessary storage of world space transforms for controller
model nodes. Now, only local space transforms are stored and the
world transforms are calculated from these local transforms when
needed.
2021-08-16 18:55:36 +09:00
9d68c34a75 Merge branch 'master' into xr-controller-support 2021-08-16 12:04:19 +09:00
e41cc8162a Merge branch 'master' into xr-controller-support 2021-08-15 15:21:01 +09:00
1990bb921f XR: Support dynamic controller model components
Updating the transforms, or "animating", supported controller
model parts (trigger, grip, thumbstick, etc.) provides better visual
feedback for the user and adds little overhead due to caching of node
transforms/indices.
2021-08-15 15:18:34 +09:00
567c22f0d8 Merge branch 'master' into xr-controller-support 2021-08-13 07:28:34 +09:00
be0a272d91 XR: Fix crash/assert on loading controller model
When calculating controller model component transforms from glTF node
data, it was previously wrongly assumed that the glTF nodes would
always contain transform matrix values. However, nodes can instead
store their transforms as separate translation/rotation/scale values,
in which case the transform matrix needs to be explicitly calculated.
This was the case for the Reverb G2 controller models using the
Windows Mixed Reality runtime.

Special thanks to Werner Trunk for help with testing/debugging.
2021-08-13 06:44:50 +09:00
5f5289512c XR: Improve "Invalid stage ref space" warning
Originally mentioned that absolute tracking was disabled, which is
wrong because absolute tracking (skipping application of eye offsets)
is always available, although it may not give the expected result of
persistent tracking origins across sessions if the stage space is
unavailable (hence the need for a warning).

Now, the warning makes no mention of absolute tracking, instead
informing the user that the local space fallback will be used and
that they should define tracking bounds via the XR runtime if they
wish to use the stage space.
2021-08-13 06:23:01 +09:00
05c3e5c433 Cleanup
- Remove unused wmSurface.is_xr member
- Rename "actionmap" to "action_set" in wmXrActionData
- Use BLI_findstring()
- Add modifications note to tinygltf readme
2021-08-08 13:17:18 +09:00
9f6b8bc3a1 Re-update pipeline config
Accidentally updated wrong submodule in previous commit.
2021-08-07 20:55:00 +09:00
d870b85dab Update pipeline config 2021-08-07 20:46:41 +09:00
2f4712841a Merge branch 'master' into xr-controller-support 2021-08-07 18:36:55 +09:00
6dec69daa8 XR: Fix crash on file read with active session
Add null check for runtime data since it could already have been
freed via wm_xr_exit() prior to the session exit callback.
2021-08-07 18:31:12 +09:00
be7653fe52 Cleanup: remove unnecessary double pointer usage 2021-08-07 17:30:27 +09:00
c600251eae XR: Use regular window queues for XR events
Removes special queueing of events to the XR surface, which was
originally done to bypass filtering by mouse region when
invoking/executing XR operators.

Now, finding an appropriate region for XR events will simply be done in
the regular window event handling by checking the event type and
skipping mouse-specific processing.
2021-08-07 17:04:34 +09:00
d2c4094425 Merge branch 'master' into xr-controller-support 2021-08-06 16:20:44 +09:00
14fc1c73e8 Update with changes from D10943 2021-08-06 15:58:41 +09:00
ef07af330a Add missing unused variable 2021-08-02 17:00:57 +09:00
9561a0a0a3 Merge branch 'master' into xr-controller-support 2021-08-02 16:56:42 +09:00
9f5089b67a XR: Simplify action creation API
By passing an XrActionMap struct instead of individual action
parameters, action creation from Python can be reduced to a simple
call to XrSessionState.create_action_set().

This will also set any controller pose actions and optionally the
active action set for the session.
2021-08-02 16:53:04 +09:00
f34cb9f8bf Merge branch 'master' into xr-controller-support 2021-07-29 13:13:12 +09:00
5a640b94b4 Cleanup: use LISTBASE_FOREACH_INDEX macro 2021-07-29 13:12:30 +09:00
9025f2adc6 XR: Fix action map load/save
Forgot to add action bindings list.
2021-07-29 13:10:43 +09:00
d5989308fb Fix build warnings 2021-07-28 13:40:12 +09:00
8a103470c9 Merge branch 'master' into xr-controller-support 2021-07-28 13:08:26 +09:00
be59b7699e XR: Fix crash on close with active session
Fixes an issue introduced in 99beac7b3f due to duplicate call to
wm_xr_session_data_free().
2021-07-28 13:06:41 +09:00
6b67760bd8 XR: Refactor action maps, bindings
This removes the previous limitation of one interaction profile
(device) per action map by moving the profiles to action bindings.
By doing so, there is no longer the need for users to manually select
an action map, as the XR runtime will automatically select the most
appropriate profile.

An additional DNA action map layer, "XrActionMapBinding", was also
added to store profiles and input-specific properties for actions,
allowing for flexible inputs across devices.
2021-07-28 13:02:37 +09:00
fb3154447b Fix build warnings 2021-07-24 19:10:19 +09:00
c56b73277e Merge branch 'master' into xr-controller-support 2021-07-24 18:20:19 +09:00
99beac7b3f XR: Use dynamic arrays for eye, controller data
Makes API/functionality more adaptable to different systems.
2021-07-24 18:08:29 +09:00
c4c4b1a03d XR: Move controller batch creation to draw func
Ensures that a valid GPU context is available during batch creation,
which fixes potential access violation issues.
2021-07-24 15:51:23 +09:00
af90b8aaa3 Update with changes from master
36c0649d32, c41b93bda5
2021-07-24 14:23:07 +09:00
2c5241ad01 Merge branch 'master' into xr-controller-support 2021-07-22 17:36:49 +09:00
6daab062b4 Fix build errors/warnings on some platforms 2021-07-22 17:35:14 +09:00
4b3aaa76bd Merge branch 'master' into xr-controller-support 2021-07-22 15:36:54 +09:00
707bc260d8 XR: Add basic controller model drawing
Uses the OpenXR XR_MSFT_controller_model extension to load a glTF
model provided by the XR runtime. The model's vertex data is then
used to create a GPUBatch in the XR session state. Finally, this
batch is drawn via an XR surface draw callback.

Currently does not use the model's texture data, but this can be
supported in the future.
2021-07-22 15:31:36 +09:00
5b45070024 XR: Refactor controller poses
Separates controller poses into two components, "grip" and "aim",
which are both required to accurately represent the controllers
without manual offsets.

Following their OpenXR definitions, the grip pose represents the
user's hand when holding the controller, and the aim pose represents
the controller's aiming source.
2021-07-22 00:58:17 +09:00
bd8b3f57df Fix build warnings 2021-07-09 13:58:12 +09:00
4040ebd1ff Merge branch 'master' into xr-controller-support 2021-07-09 11:28:47 +09:00
3feb3a4707 XR: Fix grab interp/offsets for parented objects 2021-07-09 11:23:02 +09:00
aa92c23430 Merge branch 'master' into xr-controller-support 2021-07-07 20:04:13 +09:00
7863f2fbe0 XR: Add teleport offset option 2021-07-07 19:22:36 +09:00
872484dfaa XR: Fix action state querying from Python
Credit: Jacob Merrill
2021-07-07 19:22:10 +09:00
1185259db8 Merge branch 'master' into xr-controller-support 2021-07-04 15:48:26 +09:00
1f1589b4df XR: Show selection/controller overlays by default 2021-07-04 15:42:55 +09:00
6ee46d5e83 XR: Fix mirror view not matching navigation
Forgot to update eye poses with viewer pose.
2021-07-04 15:40:38 +09:00
a177eb3dd2 Merge branch 'master' into xr-controller-support 2021-07-03 13:06:04 +09:00
f7d42065eb XR: Fix render artifacts with viewport denoising
Addresses T76003. When using VR with Eevee and viewport denoising,
scene geometry could sometimes be occluded for one eye. Solution was,
as Clement suggested, to use a separate GPUViewport/GPUOffscreen for
each VR view instead of reusing a single one for rendering.
2021-07-03 13:05:32 +09:00
7a7ee11f13 XR: Direction lock, frame based speed fly options 2021-07-03 13:05:10 +09:00
5465112930 Cleanup: RNA text 2021-07-03 13:04:49 +09:00
f89f63eefd Merge branch 'master' into xr-controller-support 2021-07-02 18:17:29 +09:00
714224ee1f XR: Support haptic feedback for actions
Adds haptic settings to float (button) actions that can be used to
apply haptics when an action is active. Users can configure the
duration, frequency, and amplitude of the feedback as well as when
it will be applied (press, release, press/release, or repeat).

The haptic output path/target is specified via the name of an
existing action of type "haptic". This allows float actions to target
the same output paths without the need for multiple haptic actions.
2021-07-02 18:10:34 +09:00
1184da2974 XR: Add cubic interpolation option for fly speed 2021-07-02 18:09:46 +09:00
e8926d40c8 XR: Add option to raycast from viewer pose
Useful when using a gamepad or for systems without motion
controllers.
2021-07-02 18:07:55 +09:00
004034f8c5 XR: Fix grab transform for parented objects 2021-07-02 17:59:14 +09:00
7b867dd00a Merge branch 'master' into xr-controller-support 2021-06-26 19:33:17 +09:00
e022f99e5c XR: Allow multiple modal actions at a time
This was disabled before since modal handlers for action operators
could receive events from other actions and exit prematurely. Now,
the XR operators check for events with the matching operator and
properties to avoid this. In addition, a list of active modal actions
is stored in the session state so that duplicate operators can be
filtered out when dispatching events.
2021-06-26 19:25:52 +09:00
80c80f5e18 XR: Use prior nav data to calculate viewer pose
Fixes an issue where draw callbacks were not drawn correctly if an
operator changed the navigation. Now, the navigation transforms are
saved before dispatching action events and are later used to
calculate the viewer/controller poses.
2021-06-26 19:11:48 +09:00
0d6c6a6787 Merge branch 'master' into xr-controller-support 2021-06-23 20:35:06 +09:00
e3cab5c206 XR: Add fly navigation operator
Navigates the scene by moving/turning relative to navigation space
or the XR viewer/controller. Users can select from a variety of
these modes as well as specify the min/max speed and whether to lock
elevation.

Also: pass float threshold to XR action events.
2021-06-23 20:30:32 +09:00
8ace7897a8 XR: Update controller data again in viewer update
This is needed to draw the controllers with correct transforms in the
event that an operator changed the navigation.
2021-06-23 20:24:31 +09:00
e5089d3924 Merge branch 'master' into xr-controller-support 2021-06-19 18:18:39 +09:00
65804b203e XR: Add location/rotation locks for navigation 2021-06-19 18:12:43 +09:00
2a768ffe43 Merge branch 'master' into xr-controller-support 2021-06-18 21:36:13 +09:00
2585d7f1b8 XR: Add grab navigation operator
Similar to the XR grab transform operator but applies deltas to the
navigation matrix instead of objects. Supports bimanual interaction
for viewer/navigation scaling and locks for rotation and scale.
2021-06-18 21:32:18 +09:00
eed31613e5 XR: Smooth transition between modal actions
Although only one modal action is allowed at a time, if another
modal action is pressed when the current modal action ends, then
transition immediately to that one.
2021-06-18 21:26:38 +09:00
6732d31f18 XR: Fixes/adjustments when viewer scale != 1.0
This corrects some clipping and shading issues when a scale factor
is applied to the XR viewmat. Also fixes the viewer pose calculation
with VR navigation.
2021-06-18 21:22:15 +09:00
1bd403430d Remove duplicate file
Was renamed to "wm_xr_action.c".
2021-06-18 21:14:13 +09:00
9926553255 Merge branch 'master' into xr-controller-support 2021-06-12 19:32:20 +09:00
0c92bf5e37 XR: Fix viewer pose and teleport calculation 2021-06-12 19:28:07 +09:00
9ce38d17ed XR: Add bimanual scale mode for grab operator
Also renamed operator to "Transform Grab".
2021-06-12 19:25:42 +09:00
40741a8942 Merge branch 'master' into xr-controller-support 2021-06-11 21:05:57 +09:00
eeb948f428 XR: Add axis region, bimanual action flags
The axis flags allow binding actions to certain regions of an input
axis (positive or negative). In this way, two different actions can
be bound to the input path "/input/thumbstick/x" without overlapping.

The bimanual flag signifies that the action depends on inputs from
both of its subaction paths, and both states, if available, will then
be passed to the operator. This will be used in the future for
two-handed navigation and transform.
2021-06-11 20:48:41 +09:00
9c3ac44c89 Merge branch 'master' into xr-controller-support 2021-06-08 19:35:24 +09:00
819a7e7900 Update pipeline config 2021-06-08 19:31:24 +09:00
5544ffabd5 Merge branch 'master' into xr-controller-support 2021-06-08 13:52:45 +09:00
2a3b8880e3 Fix build warnings 2021-06-08 13:51:22 +09:00
05f5d2791f Merge branch 'master' into xr-controller-support 2021-06-04 19:18:44 +09:00
29702c6d8b XR: Add teleport navigation operator
Mostly the same as the XR raycast select operator. Users can
optionally constrain the result to specific axes, for example to
achieve "elevation snapping" behavior by constraining to the Z-axis.

Credit to KISKA for the elevation snapping concept.
2021-06-04 19:10:53 +09:00
36463a16bb XR: Add initial navigation support
Adds navigation transforms (pose, scale) to the XR session state
that will be applied to the viewer/controller poses.

Users can access these transforms via Python
(xr_session_state.navigation_location/rotation/scale) to use with
custom operators.
2021-06-04 19:01:50 +09:00
b57cc27ec9 Fix build errors on some platforms 2021-05-26 18:13:35 +09:00
8b53855371 Clang format 2021-05-26 18:12:14 +09:00
af1c2869a6 Merge branch 'master' into xr-controller-support 2021-05-26 17:34:35 +09:00
9df2fae994 XR: Enable controller profile extensions 2021-05-26 17:08:35 +09:00
daf5570c42 Cleanup GHOST_Xr 2021-05-26 17:06:14 +09:00
795ae6433d XR: Change raycast color 2021-05-26 17:05:19 +09:00
1e8b3692b9 XR: Deactivate draw callbacks on session end 2021-05-26 17:04:39 +09:00
544c6fd1b6 Merge branch 'master' into xr-controller-support 2021-05-18 22:14:12 +09:00
963a6c3c12 Update addons submodule 2021-05-18 22:13:22 +09:00
f799fc3033 Merge branch 'master' into temp-xr-actions-D9124 2021-05-18 19:28:04 +09:00
5a786038cb Fix RNA error 2021-05-18 19:14:34 +09:00
7343845d7b Update with changes from D10943 2021-05-18 18:47:17 +09:00
ce5fc090a8 Move customdata wrapper to GHOST_Util.h 2021-05-16 03:13:07 +09:00
2fa8e2686e Rename "threshold" to "float_threshold" 2021-05-16 03:12:56 +09:00
f89460a872 Use RAII customdata wrapper for ctor exceptions 2021-05-16 01:09:39 +09:00
8c8bc114b8 Fix errors/warnings on Linux, gcc 2021-05-15 22:15:06 +09:00
11a63417ea Update with changes from D10942
- GHOST_XrException: Use std::string instead of const char*
- GHOST_XrActionProfile: Move default dtor declaration to header
- GHOST_XrActionSet/Action: Fix mem leak on exception in ctor
2021-05-15 10:58:53 +09:00
ed869a2609 Revert changes to wm_xr_controller_pose_to_mat() 2021-05-15 08:45:16 +09:00
79ed8f21f7 Fix merge-related error 2021-05-14 22:02:58 +09:00
a5d1f3e4c5 Merge branch 'master' into temp-xr-actions-D9124 2021-05-14 21:36:39 +09:00
7c05339597 Update with changes from D10942
Mainly cleanup-related but also adds wmXrPose and wmXrActionState
structs to replace float[7] and void* uses, respectively.
2021-05-14 21:32:23 +09:00
cd3030bb8d Fix RNG_TYPE_LEN value 2021-05-14 21:30:16 +09:00
5677c02954 Pass context to wm_xr_session_actions_update()
Restores motion capture object autokeying functionality.
2021-05-03 11:07:00 +09:00
3e7524b52b Clang format 2021-05-03 11:04:07 +09:00
c34d0fbee2 Update with changes from D10942
Except for motion capture object autokeying (will be added again once
a good way to get the blender context from wm_xr_session is found),
functionality remains the same as before.
2021-04-30 19:54:03 +09:00
63f0dcf6b7 Merge branch 'master' into temp-xr-actions-D9124 2021-04-29 15:36:47 +09:00
517a3cdad1 Adjust CMakeLists, fix typo 2021-04-29 15:32:27 +09:00
585f98784c Merge branch 'master' into xr-actions-D9124 2021-04-10 13:28:17 +09:00
c9c052aae0 Merge branch 'master' into xr-actions-D9124 2021-03-21 20:37:56 +09:00
9cfc8ebcc9 XR: Add op_name property to XrActionMapItem
Improves readability over operator ID string when displaying action
properties.
2021-03-21 20:37:05 +09:00
dfc8860502 Revert edit to blender_default.py
Leftover from keymap->actionmap refactor.
2021-03-21 20:12:32 +09:00
97c8878753 Fix warnings on Linux / gcc 2021-03-14 19:54:43 +09:00
49707f5d83 Merge branch 'master' into xr-actions-D9124 2021-03-14 19:14:50 +09:00
334114d287 XR: Cleanup after actionmap refactoring
Aside from general cleanup, changed that only user actionconfigs and
the builtin user config can be saved to blend files (the builtin
default and addon configs are excluded).
2021-03-14 19:02:34 +09:00
034dd0d702 XR: Move actions from keymaps to actionmaps
Previously, properties for XR actions were stored in keymaps but they
are now stored in a separate XR "actionmaps" system. Although the
actionmap system/API has many similarities to the keymaps, it is
significantly less complex since it does not involve any diff-ing of
default/addon/user configurations (at least at the moment).

Another big distinction between keymaps and actionmaps is that
actionmaps and properties are saved to blend files. This allows users
to set up a VR scene with actions and properties and share working
versions with others, without the need to import/export config files.
However, actionmap import/export is also supported via the addon.

There is still a fair amount of refactoring left to do but at least
this commit removes XR involvement from the keymaps while preserving
most of the existing XR action functionality (i.e. default actions
and user-configurable actions).
2021-03-07 21:40:38 +09:00
d8cf5e7f4d Merge branch 'master' into xr-actions-D9124 2021-03-07 18:54:26 +09:00
854d115d68 XR: "deselect_all" by default for raycast select 2021-03-07 18:33:19 +09:00
886cba7fe8 Fix build error when disabling WITH_XR_OPENXR 2021-03-07 18:29:46 +09:00
f21eb52ecc Merge branch 'master' into xr-actions-D9124 2021-02-16 20:15:34 +09:00
81944920a7 Fix build error on Linux / gcc 2021-02-16 20:12:57 +09:00
cf12206311 Merge branch 'master' into xr-actions-D9124 2021-02-09 00:44:48 +09:00
247267dee4 XR: Use common functions for modal_3d operators
Reduces the amount of similar code for XR invoke_3d/modal_3d
operators that manipulate view3d params.
2021-02-09 00:11:49 +09:00
2370781389 Add TODO for merging into master 2021-02-08 23:57:52 +09:00
1aecb31acc Merge branch 'master' into xr-actions-D9124 2021-01-31 23:53:02 +09:00
2092d39dfd Fix merge-related error 2021-01-31 23:51:36 +09:00
412ea63063 Merge branch 'master' into xr-actions-D9124 2021-01-31 22:31:07 +09:00
0f236af817 XR: Remove remaining use of GHOST types in RNA
It might be good to have a WM equivalent for GHOST_XrPose (e.g.
wmXrPose) since converting from location/rotation or float[7] to
GHOST_XrPose can be pretty awkward.
2021-01-31 22:07:13 +09:00
798c33ab3b XR: Start refactoring internal API
Remove unnecessary data from GHOST types and mostly eliminate use of
GHOST types at RNA level. At the WM level, action creation functions
deal with single actions (instead of multiple actions at once) to
simplify the API.
2021-01-30 12:17:50 +09:00
a87b142e51 Fix build errors after merge
Also fixes incorrect use of RNA_def_struct_name_property().
2021-01-17 19:19:41 +09:00
2ddf55f358 Merge branch 'master' into xr-actions-D9124 2021-01-17 18:45:20 +09:00
84f821f271 Merge branch 'master' into xr-actions-D9124 2020-12-13 13:52:25 +09:00
29ed6a6872 Merge branch 'master' into xr-actions-D9124 2020-11-26 13:32:35 +09:00
78563e9bf1 XR: Add "controller draw style" session setting
Allows users to choose their preferred controller visualization
(controller local axes or -Z axis ray). The enum can be extended in
the future for additional visualizations.
2020-11-25 22:57:33 +09:00
8916a04df8 XR: Restore XR object transforms at session end
If an object was constrained to a headset/controller pose during the
session, then its original transform will be restored at session end
to prevent unwanted changes to the scene. This will also occur when
toggling the constraint or changing the constrained object.
2020-11-25 22:51:58 +09:00
c9f0da5b20 XR: Adjust raycast select property behavior
Combinations of properties (extend/deselect/toggle/deselect on empty)
now match view3d.select behavior.
2020-11-25 22:32:43 +09:00
f7a72a238b Merge branch 'master' into xr-actions-D9124 2020-11-23 16:17:12 +09:00
c8db91fc93 XR: Only allow one active modal action/subaction
Prevents unwanted behavior when a modal operator is bound to multiple
inputs (e.g. when an action has multiple subaction paths). Can be
refactored in the future to support "bimanual" interaction for some
operators.
2020-11-23 16:16:41 +09:00
e089ad2b4b Merge branch 'master' into xr-actions-D9124 2020-11-22 19:40:36 +09:00
6c67d808b7 XR: Add raycast option to ignore non-selectables
Useful when user does not want non-selectable objects to block
selectable objects in raycast result.
2020-11-22 19:35:16 +09:00
d3e352a7ec Keymap I/O: Add "exec" versions of import/export
The new "exec" functions are added for the sake of the VR Scene
Inspection add-on and do not affect the behavior of the existing
keymap I/O functions.

keyconfig_export_as_data_exec() enables exporting a specified keymap
instead of all user-modified keymaps. The VR add-on uses this to
selectively export the "XR Session" add-on keymap.

keyconfig_import_as_data_exec() enables adding keymap data to an
existing keyconfig instead of creating a new keyconfig. The VR add-on
uses this to add the "XR Session" keymap to the add-on keyconfig.
2020-11-22 18:52:17 +09:00
4423ab787b XR: Improve error logs when creating actions
Include action set name in case multiple action sets have an action
with the same name.
2020-11-22 18:29:14 +09:00
57f7e1ff97 Merge branch 'master' into xr-actions-D9124 2020-11-16 18:15:35 +09:00
f8ad9c696e Merge branch 'master' into xr-actions-D9124 2020-11-15 23:52:40 +09:00
79733505bf XR: Enable switching action sets during session
Since xrSuggestInteractionProfileBindings() overwrites any existing
profile bindings, the solution is to suggest bindings from all action
sets at the same time (done just before attaching action sets to the
session).
2020-11-15 23:46:40 +09:00
b4a21355d7 Cleanup: Comments 2020-11-15 23:38:37 +09:00
d685b9ca57 Cleanup: comments, variables 2020-11-14 22:22:46 +09:00
d3b07d5ad5 XR: Support axis (vector2f) input actions 2020-11-14 15:52:41 +09:00
86faaaa934 XR: Improve raycast select in edit mode
Limit raycast test to selected objects.
2020-11-14 15:50:56 +09:00
4d5f104faf Merge branch 'master' into xr-actions-D9124 2020-11-14 01:45:59 +09:00
6fdf493028 XR: Support mesh editing with grab operator
Uses similar mechanics as object mode, but interpolation and offsets
are not yet supported.
2020-11-14 01:26:50 +09:00
43dd6ba330 XR: Ensure mesh object for edit mode raycast 2020-11-14 01:23:09 +09:00
423619fd3d Increase line width for controllers / raycast 2020-11-14 01:10:31 +09:00
6489002982 XR: Remove Z-up conversion for pose actions
Not applying an implicit Z-up conversion for OpenXR coordinates may
be better since poses may have different orientations / tracking
spaces. Users can instead apply custom pose offsets via the UI /
Python API if necessary.
2020-11-14 01:08:28 +09:00
634812e579 Merge branch 'master' into xr-actions-D9124 2020-11-11 23:42:43 +09:00
8ccdd43fc1 XR: Implement XR grab operator
Transforms selected objects' location / rotation relative to a
controller's pose. Very basic compared to the existing transform
operators (which can also be used in VR via modal_3d), but provides
a more natural interaction in VR.
2020-11-11 23:30:24 +09:00
78d7dbbad9 Merge branch 'master' into xr-actions-D9124 2020-11-08 22:55:44 +09:00
4ec85983af XR: Remove controller overlay object
Object was originally meant to visualize the controller and be drawn
by the overlay engine, however it was unused since controllers are
now drawn via draw handlers. It might be added again in the future
for drawing more complex controller geometry.
2020-11-07 21:08:17 +09:00
dc0b81bc99 XR: Add XR region type to View3D space type
Enables add-ons to draw to the XR surface and mirror window by
adding a View3D draw handler of region type 'XR' and draw type
'POST_VIEW'. Also allows individual toggling of controller drawing
and custom overlays.
2020-11-07 19:04:36 +09:00
f6e71179fe XR: Draw controller overlays in mirror view 2020-11-07 17:44:56 +09:00
36bdbe6ce3 XR: Store multiple paths in GHOST_XrActionBinding
Facilitates action binding creation debugging by narrowing
errors down to an interaction profile and action.
2020-11-07 16:46:33 +09:00
5f7285d4af XR: Check for valid stage reference space bounds
Even if the stage reference space is supported by the XR runtime, the
bounds may be invalid (0, 0) if the user did not define a tracking
space via the runtime's UI. In this case, fall back to the local
tracking space.
2020-11-07 15:19:38 +09:00
1625bb3e71 Merge branch 'master' into xr-actions-D9124 2020-11-06 23:58:06 +09:00
a399445b3c XR: Fix projection selection in edit mode
Use window region dimensions instead of XR surface dimensions. Add
winrct offset for box select.
2020-11-06 23:56:31 +09:00
f32d320e90 XR: Fix raycast deselect empty for edit mode 2020-11-06 23:42:28 +09:00
78cd4e8cee Merge branch 'master' into xr-actions-D9124 2020-11-06 21:48:15 +09:00
848c87c6d9 Fix errors after merge 2020-11-06 21:46:56 +09:00
f5ff515085 Merge branch 'master' into xr-actions-D9124 2020-11-06 21:40:58 +09:00
07a7c88918 XR: Use stage ref space for absolute tracking 2020-11-06 21:31:43 +09:00
48ec546911 XR: Add axis property to raycast select operator
Allows users to adjust the raycast axis to fit different poses and
controllers.
2020-11-06 17:13:17 +09:00
8335da48f9 Cleanup: Comments 2020-11-06 17:08:42 +09:00
8fae3debf3 Merge branch 'master' into xr-actions-D9124 2020-11-05 22:33:39 +09:00
2ed0965e97 XR: Add "absolute tracking" session setting
Enables users to define the tracking origin in a way that is not
linked to the headset position. Instead, the tracking values given by
the XR runtime are left unadjusted and a user can manually calibrate
an "origin" landmark object to adjust to their real world space.

Can be useful for applications that use external tracking systems
and those that primarily only need to use controllers (e.g. for
motion capture).
2020-11-05 22:31:34 +09:00
2b338373d7 XR: Ensure valid region for invoking operators
Check for a valid v3d, even if the area / region uses a viewport.
2020-11-04 21:33:14 +09:00
c565bb8985 XR: Use TransInfo viewmat for transform modal_3d
Fixes static variable TODO.
2020-11-04 21:30:03 +09:00
03bb02337f XR: Compare absolute input value with threshold
Trackpad / thumbstick input values range from -1 to 1, so the
absolute value must be compared against the input threshold.
2020-11-04 21:24:43 +09:00
618df6b0b7 Fix build warnings on Linux / gcc 2020-11-04 21:13:42 +09:00
0c246b2b52 Merge branch 'master' into xr-actions-D9124 2020-11-03 18:50:07 +09:00
ff2dcdb447 XR: Implement XR constraints toggle operator
Useful for quickly playing back recorded animations without
overwriting existing data.
2020-11-03 18:47:11 +09:00
73daf1f721 XR: Support auto keying XR constraint objects
If specified, headset / controller objects will auto key on animation
playback. This can be useful for virtual camera applications.
2020-11-03 17:37:41 +09:00
9c28e6e62f XR: Fix crash when reading "constraint" objects
Pointers were not being relinked from file.
2020-11-03 10:46:42 +09:00
9c288d3e20 Merge branch 'master' into xr-actions-D9124 2020-11-02 00:09:10 +09:00
86f76f46f9 XR: Remove view space limitation for transform op
Not needed now that XR supports calling operators with properties.
2020-11-02 00:04:53 +09:00
498804edc8 XR: Implement raycast select operator
Uses the same raycast method as Scene.ray_cast() and works in object
and edit mode. Although it gives users an alternative to the existing
projection-based VR selection method, it is limited to objects with
real geometry (i.e. meshes).
2020-11-01 23:50:46 +09:00
3d24ef827c Merge branch 'master' into xr-actions-D9124 2020-10-31 23:38:14 +09:00
c8be04b7f8 Cleanup: Rename controller pose properties
Makes naming consistent with controller#_object session settings.
2020-10-31 23:31:33 +09:00
58ecc0d1bf XR: Add "constraint" objects to session settings
These objects (3 in total, corresponding to headset and left/right
controllers) will have their location and rotation determined by the
associated XR pose. This provides a way for add-ons to achieve
this "VR constraint" behavior without the need to constantly query
pose information.
2020-10-31 23:00:43 +09:00
1a6d76c5c7 Remove unused parameter 2020-10-31 22:27:00 +09:00
a1333cf2c3 Merge branch 'master' into xr-actions-D9124 2020-10-29 23:51:32 +09:00
9be27de831 XR: Improve error handling / messages
Originally thought that not terminating the session for certain "non-
fatal" errors (e.g. an incorrect action path) would make sense.
However, realized that error messages can pile up this way and it
is better for user feedback and debugging to always exit the session
when encountering an OpenXR-level error.
2020-10-29 23:49:59 +09:00
a90bfa17a9 XR: Include action set name in XR event data
Needed to match keymap items with XR events.
2020-10-29 21:01:49 +09:00
d72fafd62a Merge branch 'master' into xr-actions-D9124 2020-10-28 01:05:45 +09:00
62c5f71da1 XR: Add XR identifiers to key config I/O
Allows XR action properties to be shared with others.
2020-10-28 01:04:01 +09:00
09377b4c9c Merge branch 'master' into xr-actions-D9124 2020-10-27 02:17:20 +09:00
b596d70a1f Apply formatting 2020-10-27 02:05:24 +09:00
1d86e1ff46 XR: Support operator properties for actions
Pointers to op properties are stored in the XR session state as
IDProperty* and applied upon op execution. The actual properties
themselves are stored as key map items (new "XR" and "XR Session"
key maps were added to the blender default key maps).

The "XR" key map is intended to store op properties for action sets
that are saved in add-on (e.g. the VR Scene Inspection add-on) prefs.
The "XR Session" key map is intended to store op properties for scene
action sets, with these properties used for the XR session.

In this way, scene action sets can configure properties without
worrying about overwriting properties for action sets saved in prefs.
2020-10-27 01:54:03 +09:00
3e0acdfe94 Fix build error when disabling WITH_XR_OPENXR 2020-10-27 01:30:47 +09:00
a6c5a1a2dc Merge branch 'master' into xr-actions-D9124 2020-10-21 23:59:08 +09:00
ceab20d5e5 Cleanup: Comment style 2020-10-21 23:57:09 +09:00
cb75a83df0 XR: Draw controllers via draw handler
Callbacks for controllers and other custom drawing will be registered
with the XR surface's region type (RGN_TYPE_XR_DISPLAY) and called
post-view.
2020-10-21 23:47:29 +09:00
db1cdcdafe Merge branch 'master' into xr-actions-D9124 2020-10-20 00:59:21 +09:00
297decbe1f XR: Add input threshold for float actions
Fixes button release events not being sent due to non-zero state.
2020-10-20 00:52:49 +09:00
8af91a18e0 XR: Support basic transform operators
Uses same invoke_3d / modal_3d approach as select operators.
2020-10-20 00:48:29 +09:00
9ec8ca2d55 Merge branch 'master' into xr-actions-D9124 2020-10-19 01:06:04 +09:00
5561fbf1f8 XR: Apply VR clip settings when selecting
Fixes projection matrix calculation for GPU select.
2020-10-19 01:04:04 +09:00
de026d1395 Remove unused function
Was meant to be removed in 2eb44677.
2020-10-18 15:31:15 +09:00
07e5488c61 Merge branch 'master' into xr-actions-D9124 2020-10-18 15:18:51 +09:00
2eb44677dd Fix build error when disabling WITH_XR_OPENXR 2020-10-18 15:11:12 +09:00
3e33c89828 Fix build error on Linux / gcc 2020-10-18 15:06:12 +09:00
f2385a3f05 Merge branch 'master' into xr-actions-D9124
# Conflicts:
#	source/blender/windowmanager/intern/wm_event_system.c
2020-10-17 23:42:47 +09:00
f6a7d5336b XR: Add "selection eye" session setting
The "selection eye" is the XR eye (view) used for 3D-to-2D projection.
Its parameters are used to override the window view when selecting
with VR controllers.
2020-10-17 11:59:50 +09:00
336c8a628a Merge branch 'master' into xr-actions-D9124 2020-10-15 00:43:31 +09:00
66e22a2ed7 Operators: Add modal_3d() and implement for box select
This follows the same logic as invoke_3d(). That is, we wrap an
operator's modal() with modal_3d() and project 3D controller coords to
2D mouse coords.
2020-10-15 00:41:34 +09:00
6920906f75 XR: Remove "replace existing" param from action bindings creation
Since action bindings are only created once at the beginning of an XR
session, overwriting all existing bindings will not be needed.
2020-10-15 00:23:48 +09:00
ae1d8f4c35 Fix: Use correct add-on branch for 'make update'
Credit to Julian Eisel for the fix.
2020-10-14 08:47:14 +09:00
e0eafd2757 XR: Add selection outline offscreen draw flag 2020-10-13 21:39:03 +09:00
5e8d3f6d28 Operators: Add invoke_3d() and implement for VIEW3D_OT_select 2020-10-13 21:39:03 +09:00
090c1b7dda Disable XR object saving and (for now) creation 2020-10-13 21:39:03 +09:00
f126ce2d5b Add safety checks when accessing XR window and controller objects. 2020-10-13 21:39:03 +09:00
3b3955d9e2 Update comment. 2020-10-13 21:39:03 +09:00
9c9081bf83 Fix annotations not being shown in XR view. 2020-10-13 21:39:03 +09:00
cfc5c1b46d Improve error logging and controller data management. 2020-10-13 21:39:03 +09:00
45194962c1 Add wm_xr_operators.c. 2020-10-13 21:39:03 +09:00
921510f34f Add xr overlay and controller object. 2020-10-13 21:39:02 +09:00
d7083de46d Update controller data when setting controller pose action. 2020-10-13 21:39:02 +09:00
b44173754f Fix condition for processing xr actions. 2020-10-13 21:39:02 +09:00
e0da725075 Add basic controller visualization.
Differential Revision: https://developer.blender.org/D9124
2020-10-13 21:39:02 +09:00
71 changed files with 7214 additions and 473 deletions

View File

@@ -5,7 +5,7 @@
update-code:
git:
submodules:
- branch: master
- branch: xr-controller-support
commit_id: HEAD
path: release/scripts/addons
- branch: master

View File

@@ -178,7 +178,7 @@ def submodules_update(args, release_version, branch):
branch = branch_fallback
submodules = [
("release/scripts/addons", branch, branch_fallback),
("release/scripts/addons", "xr-controller-support", branch_fallback),
("release/scripts/addons_contrib", branch, branch_fallback),
("release/datafiles/locale", branch, branch_fallback),
("source/tools", branch, branch_fallback),

View File

@@ -473,6 +473,7 @@ if(WITH_XR_OPENXR)
intern/GHOST_Xr.cpp
intern/GHOST_XrAction.cpp
intern/GHOST_XrContext.cpp
intern/GHOST_XrControllerModel.cpp
intern/GHOST_XrEvent.cpp
intern/GHOST_XrGraphicsBinding.cpp
intern/GHOST_XrSession.cpp
@@ -482,13 +483,19 @@ if(WITH_XR_OPENXR)
intern/GHOST_IXrGraphicsBinding.h
intern/GHOST_XrAction.h
intern/GHOST_XrContext.h
intern/GHOST_XrControllerModel.h
intern/GHOST_XrException.h
intern/GHOST_XrSession.h
intern/GHOST_XrSwapchain.h
intern/GHOST_Xr_intern.h
intern/GHOST_Xr_openxr_includes.h
)
list(APPEND INC
../../extern/json/include
../../extern/tinygltf
)
list(APPEND INC_SYS
${EIGEN3_INCLUDE_DIRS}
${XR_OPENXR_SDK_INCLUDE_DIR}
)
list(APPEND LIB

View File

@@ -1140,6 +1140,30 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_context,
const char *action_set_name,
void **r_customdata_array);
/* controller model */
/**
* Load the OpenXR controller model.
*/
int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
/**
* Unload the OpenXR controller model.
*/
void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
/**
* Update component transforms for the OpenXR controller model.
*/
int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_context,
const char *subaction_path);
/**
* Get vertex data for the OpenXR controller model.
*/
int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_context,
const char *subaction_path,
GHOST_XrControllerModelData *r_data);
#endif /* WITH_XR_OPENXR */
#ifdef __cplusplus

View File

@@ -643,7 +643,7 @@ typedef void (*GHOST_XrDrawViewFn)(const struct GHOST_XrDrawViewInfo *draw_view,
*/
typedef const GHOST_TXrGraphicsBinding *GHOST_XrGraphicsBindingCandidates;
typedef struct {
typedef struct GHOST_XrPose {
float position[3];
/* Blender convention (w, x, y, z) */
float orientation_quat[4];
@@ -753,8 +753,31 @@ typedef struct GHOST_XrActionProfileInfo {
const char *profile_path;
uint32_t count_subaction_paths;
const char **subaction_paths;
/* Bindings for each subaction path. */
/** Bindings for each subaction path. */
const GHOST_XrActionBindingInfo *bindings;
} GHOST_XrActionProfileInfo;
typedef struct GHOST_XrControllerModelVertex {
float position[3];
float normal[3];
} GHOST_XrControllerModelVertex;
typedef struct GHOST_XrControllerModelComponent {
/** World space transform. */
float transform[4][4];
uint32_t vertex_offset;
uint32_t vertex_count;
uint32_t index_offset;
uint32_t index_count;
} GHOST_XrControllerModelComponent;
typedef struct GHOST_XrControllerModelData {
uint32_t count_vertices;
const GHOST_XrControllerModelVertex *vertices;
uint32_t count_indices;
const uint32_t *indices;
uint32_t count_components;
const GHOST_XrControllerModelComponent *components;
} GHOST_XrControllerModelData;
#endif /* WITH_XR_OPENXR */

View File

@@ -1069,4 +1069,39 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_contexthandle,
xr_context);
}
int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_contexthandle, const char *subaction_path)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
GHOST_XR_CAPI_CALL_RET(xr_session->loadControllerModel(subaction_path), xr_context);
return 0;
}
void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_contexthandle,
const char *subaction_path)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
GHOST_XR_CAPI_CALL(xr_session->unloadControllerModel(subaction_path), xr_context);
}
int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_contexthandle,
const char *subaction_path)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
GHOST_XR_CAPI_CALL_RET(xr_session->updateControllerModelComponents(subaction_path), xr_context);
return 0;
}
int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_contexthandle,
const char *subaction_path,
GHOST_XrControllerModelData *r_data)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
GHOST_XR_CAPI_CALL_RET(xr_session->getControllerModelData(subaction_path, *r_data), xr_context);
return 0;
}
#endif /* WITH_XR_OPENXR */

View File

@@ -22,7 +22,6 @@
#include <cstring>
#include "GHOST_Types.h"
#include "GHOST_XrException.h"
#include "GHOST_Xr_intern.h"

View File

@@ -26,6 +26,7 @@
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "GHOST_Util.h"

View File

@@ -412,11 +412,14 @@ void GHOST_XrContext::getExtensionsToEnable(
try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
/* Try enabling interaction profile extensions. */
/* Interaction profile extensions. */
try_ext.push_back(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
try_ext.push_back(XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
try_ext.push_back(XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
/* Controller model extension. */
try_ext.push_back(XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME);
/* Varjo quad view extension. */
try_ext.push_back(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME);

View File

@@ -0,0 +1,629 @@
/*
* 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 <Eigen/Core>
#include <Eigen/Geometry>
#include "GHOST_Types.h"
#include "GHOST_XrException.h"
#include "GHOST_Xr_intern.h"
#include "GHOST_XrControllerModel.h"
#define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_NO_STB_IMAGE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#define STBIWDEF static inline
#include "tiny_gltf.h"
struct GHOST_XrControllerModelNode {
int32_t parent_idx = -1;
int32_t component_idx = -1;
float local_transform[4][4];
};
/* -------------------------------------------------------------------- */
/** \name glTF Utilities
*
* Adapted from Microsoft OpenXR-Mixed Reality Samples (MIT License):
* https://github.com/microsoft/OpenXR-MixedReality
* \{ */
struct GHOST_XrPrimitive {
std::vector<GHOST_XrControllerModelVertex> vertices;
std::vector<uint32_t> indices;
};
/**
* Validate that an accessor does not go out of bounds of the buffer view that it references and
* that the buffer view does not exceed the bounds of the buffer that it references
*/
static void validate_accessor(const tinygltf::Accessor &accessor,
const tinygltf::BufferView &buffer_view,
const tinygltf::Buffer &buffer,
size_t byte_stride,
size_t element_size)
{
/* Make sure the accessor does not go out of range of the buffer view. */
if (accessor.byteOffset + (accessor.count - 1) * byte_stride + element_size >
buffer_view.byteLength) {
throw GHOST_XrException("glTF: Accessor goes out of range of bufferview.");
}
/* Make sure the buffer view does not go out of range of the buffer. */
if (buffer_view.byteOffset + buffer_view.byteLength > buffer.data.size()) {
throw GHOST_XrException("glTF: BufferView goes out of range of buffer.");
}
}
template<float (GHOST_XrControllerModelVertex::*field)[3]>
static void read_vertices(const tinygltf::Accessor &accessor,
const tinygltf::BufferView &buffer_view,
const tinygltf::Buffer &buffer,
GHOST_XrPrimitive &primitive)
{
if (accessor.type != TINYGLTF_TYPE_VEC3) {
throw GHOST_XrException(
"glTF: Accessor for primitive attribute has incorrect type (VEC3 expected).");
}
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
throw GHOST_XrException(
"glTF: Accessor for primitive attribute has incorrect component type (FLOAT expected).");
}
/* If stride is not specified, it is tightly packed. */
constexpr size_t packed_size = sizeof(float) * 3;
const size_t stride = buffer_view.byteStride == 0 ? packed_size : buffer_view.byteStride;
validate_accessor(accessor, buffer_view, buffer, stride, packed_size);
/* Resize the vertices vector, if necessary, to include room for the attribute data.
If there are multiple attributes for a primitive, the first one will resize, and the
subsequent will not need to. */
primitive.vertices.resize(accessor.count);
/* Copy the attribute value over from the glTF buffer into the appropriate vertex field. */
const uint8_t *buffer_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
for (size_t i = 0; i < accessor.count; i++, buffer_ptr += stride) {
memcpy(primitive.vertices[i].*field, buffer_ptr, stride);
}
}
static void load_attribute_accessor(const tinygltf::Model &gltf_model,
const std::string &attribute_name,
int accessor_id,
GHOST_XrPrimitive &primitive)
{
const auto &accessor = gltf_model.accessors.at(accessor_id);
if (accessor.bufferView == -1) {
throw GHOST_XrException("glTF: Accessor for primitive attribute specifies no bufferview.");
}
const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
if (buffer_view.target != TINYGLTF_TARGET_ARRAY_BUFFER && buffer_view.target != 0) {
throw GHOST_XrException(
"glTF: Accessor for primitive attribute uses bufferview with invalid 'target' type.");
}
const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
if (attribute_name.compare("POSITION") == 0) {
read_vertices<&GHOST_XrControllerModelVertex::position>(
accessor, buffer_view, buffer, primitive);
}
else if (attribute_name.compare("NORMAL") == 0) {
read_vertices<&GHOST_XrControllerModelVertex::normal>(
accessor, buffer_view, buffer, primitive);
}
}
/**
* Reads index data from a glTF primitive into a GHOST_XrPrimitive. glTF indices may be 8bit, 16bit
* or 32bit integers. This will coalesce indices from the source type(s) into a 32bit integer.
*/
template<typename TSrcIndex>
static void read_indices(const tinygltf::Accessor &accessor,
const tinygltf::BufferView &buffer_view,
const tinygltf::Buffer &buffer,
GHOST_XrPrimitive &primitive)
{
if (buffer_view.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER &&
buffer_view.target != 0) { /* Allow 0 (not specified) even though spec doesn't seem to allow
this (BoomBox GLB fails). */
throw GHOST_XrException(
"glTF: Accessor for indices uses bufferview with invalid 'target' type.");
}
constexpr size_t component_size_bytes = sizeof(TSrcIndex);
if (buffer_view.byteStride != 0 &&
buffer_view.byteStride !=
component_size_bytes) { /* Index buffer must be packed per glTF spec. */
throw GHOST_XrException(
"glTF: Accessor for indices uses bufferview with invalid 'byteStride'.");
}
validate_accessor(accessor, buffer_view, buffer, component_size_bytes, component_size_bytes);
if ((accessor.count % 3) != 0) { /* Since only triangles are supported, enforce that the number
of indices is divisible by 3. */
throw GHOST_XrException("glTF: Unexpected number of indices for triangle primitive");
}
const TSrcIndex *index_buffer = reinterpret_cast<const TSrcIndex *>(
buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset);
for (uint32_t i = 0; i < accessor.count; i++) {
primitive.indices.push_back(*(index_buffer + i));
}
}
/**
* Reads index data from a glTF primitive into a GHOST_XrPrimitive.
*/
static void load_index_accessor(const tinygltf::Model &gltf_model,
const tinygltf::Accessor &accessor,
GHOST_XrPrimitive &primitive)
{
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'type'.");
}
if (accessor.bufferView == -1) {
throw GHOST_XrException("glTF: Index accessor without bufferView is currently not supported.");
}
const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
read_indices<uint8_t>(accessor, buffer_view, buffer, primitive);
}
else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
read_indices<uint16_t>(accessor, buffer_view, buffer, primitive);
}
else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
read_indices<uint32_t>(accessor, buffer_view, buffer, primitive);
}
else {
throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'componentType'.");
}
}
static GHOST_XrPrimitive read_primitive(const tinygltf::Model &gltf_model,
const tinygltf::Primitive &gltf_primitive)
{
if (gltf_primitive.mode != TINYGLTF_MODE_TRIANGLES) {
throw GHOST_XrException(
"glTF: Unsupported primitive mode. Only TINYGLTF_MODE_TRIANGLES is supported.");
}
GHOST_XrPrimitive primitive;
/* glTF vertex data is stored in an attribute dictionary.Loop through each attribute and insert
* it into the GHOST_XrPrimitive. */
for (const auto &[attr_name, accessor_idx] : gltf_primitive.attributes) {
load_attribute_accessor(gltf_model, attr_name, accessor_idx, primitive);
}
if (gltf_primitive.indices != -1) {
/* If indices are specified for the glTF primitive, read them into the GHOST_XrPrimitive. */
load_index_accessor(gltf_model, gltf_model.accessors.at(gltf_primitive.indices), primitive);
}
return primitive;
}
/**
* Calculate node local and world transforms.
*/
static void calc_node_transforms(const tinygltf::Node &gltf_node,
const float parent_transform[4][4],
float r_local_transform[4][4],
float r_world_transform[4][4])
{
/* A node may specify either a 4x4 matrix or TRS (Translation - Rotation - Scale) values, but not
* both. */
if (gltf_node.matrix.size() == 16) {
const std::vector<double> &dm = gltf_node.matrix;
float m[4][4] = {(float)dm[0],
(float)dm[1],
(float)dm[2],
(float)dm[3],
(float)dm[4],
(float)dm[5],
(float)dm[6],
(float)dm[7],
(float)dm[8],
(float)dm[9],
(float)dm[10],
(float)dm[11],
(float)dm[12],
(float)dm[13],
(float)dm[14],
(float)dm[15]};
memcpy(r_local_transform, m, sizeof(float) * 16);
}
else {
/* No matrix is present, so construct a matrix from the TRS values (each one is optional). */
std::vector<double> translation = gltf_node.translation;
std::vector<double> rotation = gltf_node.rotation;
std::vector<double> scale = gltf_node.scale;
Eigen::Matrix4f &m = *(Eigen::Matrix4f *)r_local_transform;
Eigen::Quaternionf q;
Eigen::Matrix3f scalemat;
if (translation.size() != 3) {
translation.resize(3);
translation[0] = translation[1] = translation[2] = 0.0;
}
if (rotation.size() != 4) {
rotation.resize(4);
rotation[0] = rotation[1] = rotation[2] = 0.0;
rotation[3] = 1.0;
}
if (scale.size() != 3) {
scale.resize(3);
scale[0] = scale[1] = scale[2] = 1.0;
}
q.w() = (float)rotation[3];
q.x() = (float)rotation[0];
q.y() = (float)rotation[1];
q.z() = (float)rotation[2];
q.normalize();
scalemat.setIdentity();
scalemat(0, 0) = (float)scale[0];
scalemat(1, 1) = (float)scale[1];
scalemat(2, 2) = (float)scale[2];
m.setIdentity();
m.block<3, 3>(0, 0) = q.toRotationMatrix() * scalemat;
m.block<3, 1>(0, 3) = Eigen::Vector3f(
(float)translation[0], (float)translation[1], (float)translation[2]);
}
*(Eigen::Matrix4f *)r_world_transform = *(Eigen::Matrix4f *)parent_transform *
*(Eigen::Matrix4f *)r_local_transform;
}
static void load_node(const tinygltf::Model &gltf_model,
int gltf_node_id,
int32_t parent_idx,
const float parent_transform[4][4],
const std::string &parent_name,
const std::vector<XrControllerModelNodePropertiesMSFT> &node_properties,
std::vector<GHOST_XrControllerModelVertex> &vertices,
std::vector<uint32_t> &indices,
std::vector<GHOST_XrControllerModelComponent> &components,
std::vector<GHOST_XrControllerModelNode> &nodes,
std::vector<int32_t> &node_state_indices)
{
const tinygltf::Node &gltf_node = gltf_model.nodes.at(gltf_node_id);
float world_transform[4][4];
GHOST_XrControllerModelNode &node = nodes.emplace_back();
const int32_t node_idx = (int32_t)(nodes.size() - 1);
node.parent_idx = parent_idx;
calc_node_transforms(gltf_node, parent_transform, node.local_transform, world_transform);
for (size_t i = 0; i < node_properties.size(); ++i) {
if ((node_state_indices[i] < 0) && (parent_name == node_properties[i].parentNodeName) &&
(gltf_node.name == node_properties[i].nodeName)) {
node_state_indices[i] = node_idx;
break;
}
}
if (gltf_node.mesh != -1) {
const tinygltf::Mesh &gltf_mesh = gltf_model.meshes.at(gltf_node.mesh);
GHOST_XrControllerModelComponent &component = components.emplace_back();
node.component_idx = components.size() - 1;
memcpy(component.transform, world_transform, sizeof(component.transform));
component.vertex_offset = vertices.size();
component.index_offset = indices.size();
for (const tinygltf::Primitive &gltf_primitive : gltf_mesh.primitives) {
/* Read the primitive data from the glTF buffers. */
const GHOST_XrPrimitive primitive = read_primitive(gltf_model, gltf_primitive);
const size_t start_vertex = vertices.size();
size_t offset = start_vertex;
size_t count = primitive.vertices.size();
vertices.resize(offset + count);
memcpy(vertices.data() + offset,
primitive.vertices.data(),
count * sizeof(decltype(primitive.vertices)::value_type));
offset = indices.size();
count = primitive.indices.size();
indices.resize(offset + count);
for (size_t i = 0; i < count; i += 3) {
indices[offset + i + 0] = start_vertex + primitive.indices[i + 0];
indices[offset + i + 1] = start_vertex + primitive.indices[i + 2];
indices[offset + i + 2] = start_vertex + primitive.indices[i + 1];
}
}
component.vertex_count = vertices.size() - component.vertex_offset;
component.index_count = indices.size() - component.index_offset;
}
/* Recursively load all children. */
for (const int child_node_id : gltf_node.children) {
load_node(gltf_model,
child_node_id,
node_idx,
world_transform,
gltf_node.name,
node_properties,
vertices,
indices,
components,
nodes,
node_state_indices);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name OpenXR Extension Functions
*
* \{ */
static PFN_xrGetControllerModelKeyMSFT g_xrGetControllerModelKeyMSFT = nullptr;
static PFN_xrLoadControllerModelMSFT g_xrLoadControllerModelMSFT = nullptr;
static PFN_xrGetControllerModelPropertiesMSFT g_xrGetControllerModelPropertiesMSFT = nullptr;
static PFN_xrGetControllerModelStateMSFT g_xrGetControllerModelStateMSFT = nullptr;
static XrInstance g_instance = XR_NULL_HANDLE;
#define INIT_EXTENSION_FUNCTION(name) \
CHECK_XR( \
xrGetInstanceProcAddr(instance, #name, reinterpret_cast<PFN_xrVoidFunction *>(&g_##name)), \
"Failed to get pointer to extension function: " #name);
static void init_controller_model_extension_functions(XrInstance instance)
{
if (instance != g_instance) {
g_instance = instance;
g_xrGetControllerModelKeyMSFT = nullptr;
g_xrLoadControllerModelMSFT = nullptr;
g_xrGetControllerModelPropertiesMSFT = nullptr;
g_xrGetControllerModelStateMSFT = nullptr;
}
if (g_xrGetControllerModelKeyMSFT == nullptr) {
INIT_EXTENSION_FUNCTION(xrGetControllerModelKeyMSFT);
}
if (g_xrLoadControllerModelMSFT == nullptr) {
INIT_EXTENSION_FUNCTION(xrLoadControllerModelMSFT);
}
if (g_xrGetControllerModelPropertiesMSFT == nullptr) {
INIT_EXTENSION_FUNCTION(xrGetControllerModelPropertiesMSFT);
}
if (g_xrGetControllerModelStateMSFT == nullptr) {
INIT_EXTENSION_FUNCTION(xrGetControllerModelStateMSFT);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name GHOST_XrControllerModel
*
* \{ */
GHOST_XrControllerModel::GHOST_XrControllerModel(XrInstance instance,
const char *subaction_path_str)
{
init_controller_model_extension_functions(instance);
CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_path),
(std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
}
GHOST_XrControllerModel::~GHOST_XrControllerModel()
{
if (m_load_task.valid()) {
m_load_task.wait();
}
}
void GHOST_XrControllerModel::load(XrSession session)
{
if (m_data_loaded || m_load_task.valid()) {
return;
}
/* Get model key. */
XrControllerModelKeyStateMSFT key_state{XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT};
CHECK_XR(g_xrGetControllerModelKeyMSFT(session, m_subaction_path, &key_state),
"Failed to get controller model key state.");
if (key_state.modelKey != XR_NULL_CONTROLLER_MODEL_KEY_MSFT) {
m_model_key = key_state.modelKey;
/* Load asynchronously. */
m_load_task = std::async(std::launch::async,
[&, session = session]() { return loadControllerModel(session); });
}
}
void GHOST_XrControllerModel::loadControllerModel(XrSession session)
{
/* Load binary buffers. */
uint32_t buf_size = 0;
CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, 0, &buf_size, nullptr),
"Failed to get controller model buffer size.");
std::vector<uint8_t> buf((size_t)buf_size);
CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, buf_size, &buf_size, buf.data()),
"Failed to load controller model binary buffers.");
/* Convert to glTF model. */
tinygltf::TinyGLTF gltf_loader;
tinygltf::Model gltf_model;
std::string err_msg;
{
/* Workaround for TINYGLTF_NO_STB_IMAGE define. Set custom image loader to prevent failure when
* parsing image data. */
auto load_img_func = [](tinygltf::Image *img,
const int p0,
std::string *p1,
std::string *p2,
int p3,
int p4,
const unsigned char *p5,
int p6,
void *user_pointer) -> bool {
(void)img;
(void)p0;
(void)p1;
(void)p2;
(void)p3;
(void)p4;
(void)p5;
(void)p6;
(void)user_pointer;
return true;
};
gltf_loader.SetImageLoader(load_img_func, nullptr);
}
if (!gltf_loader.LoadBinaryFromMemory(&gltf_model, &err_msg, nullptr, buf.data(), buf_size)) {
throw GHOST_XrException(("Failed to load glTF controller model: " + err_msg).c_str());
}
/* Get node properties. */
XrControllerModelPropertiesMSFT model_properties{XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT};
model_properties.nodeCapacityInput = 0;
CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
"Failed to get controller model node properties count.");
std::vector<XrControllerModelNodePropertiesMSFT> node_properties(
model_properties.nodeCountOutput, {XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT});
model_properties.nodeCapacityInput = (uint32_t)node_properties.size();
model_properties.nodeProperties = node_properties.data();
CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
"Failed to get controller model node properties.");
m_node_state_indices.resize(node_properties.size(), -1);
/* Get mesh vertex data. */
const tinygltf::Scene &default_scene = gltf_model.scenes.at(
(gltf_model.defaultScene == -1) ? 0 : gltf_model.defaultScene);
const int32_t root_idx = -1;
const std::string root_name = "";
float root_transform[4][4] = {0};
root_transform[0][0] = root_transform[1][1] = root_transform[2][2] = root_transform[3][3] = 1.0f;
for (const int node_id : default_scene.nodes) {
load_node(gltf_model,
node_id,
root_idx,
root_transform,
root_name,
node_properties,
m_vertices,
m_indices,
m_components,
m_nodes,
m_node_state_indices);
}
m_data_loaded = true;
}
void GHOST_XrControllerModel::updateComponents(XrSession session)
{
if (!m_data_loaded) {
return;
}
/* Get node states. */
XrControllerModelStateMSFT model_state{XR_TYPE_CONTROLLER_MODEL_STATE_MSFT};
model_state.nodeCapacityInput = 0;
CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
"Failed to get controller model node state count.");
const uint32_t count = model_state.nodeCountOutput;
std::vector<XrControllerModelNodeStateMSFT> node_states(
count, {XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT});
model_state.nodeCapacityInput = count;
model_state.nodeStates = node_states.data();
CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
"Failed to get controller model node states.");
/* Update node local transforms. */
assert(m_node_state_indices.size() == count);
for (uint32_t state_idx = 0; state_idx < count; ++state_idx) {
const int32_t &node_idx = m_node_state_indices[state_idx];
if (node_idx >= 0) {
const XrPosef &pose = node_states[state_idx].nodePose;
Eigen::Matrix4f &m = *(Eigen::Matrix4f *)m_nodes[node_idx].local_transform;
Eigen::Quaternionf q(
pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
m.setIdentity();
m.block<3, 3>(0, 0) = q.toRotationMatrix();
m.block<3, 1>(0, 3) = Eigen::Vector3f(pose.position.x, pose.position.y, pose.position.z);
}
}
/* Calculate component transforms (in world space). */
std::vector<Eigen::Matrix4f> world_transforms(m_nodes.size());
uint32_t i = 0;
for (const GHOST_XrControllerModelNode &node : m_nodes) {
world_transforms[i] = (node.parent_idx >= 0) ? world_transforms[node.parent_idx] *
*(Eigen::Matrix4f *)node.local_transform :
*(Eigen::Matrix4f *)node.local_transform;
if (node.component_idx >= 0) {
memcpy(m_components[node.component_idx].transform,
world_transforms[i].data(),
sizeof(m_components[node.component_idx].transform));
}
++i;
}
}
void GHOST_XrControllerModel::getData(GHOST_XrControllerModelData &r_data)
{
if (m_data_loaded) {
r_data.count_vertices = (uint32_t)m_vertices.size();
r_data.vertices = m_vertices.data();
r_data.count_indices = (uint32_t)m_indices.size();
r_data.indices = m_indices.data();
r_data.count_components = (uint32_t)m_components.size();
r_data.components = m_components.data();
}
else {
r_data.count_vertices = 0;
r_data.vertices = nullptr;
r_data.count_indices = 0;
r_data.indices = nullptr;
r_data.count_components = 0;
r_data.components = nullptr;
}
}
/** \} */

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
*/
/* Note: Requires OpenXR headers to be included before this one for OpenXR types (XrInstance,
* XrSession, etc.). */
#pragma once
#include <atomic>
#include <future>
#include <vector>
struct GHOST_XrControllerModelNode;
/**
* OpenXR glTF controller model.
*/
class GHOST_XrControllerModel {
public:
GHOST_XrControllerModel(XrInstance instance, const char *subaction_path);
~GHOST_XrControllerModel();
void load(XrSession session);
void updateComponents(XrSession session);
void getData(GHOST_XrControllerModelData &r_data);
private:
XrPath m_subaction_path = XR_NULL_PATH;
XrControllerModelKeyMSFT m_model_key = XR_NULL_CONTROLLER_MODEL_KEY_MSFT;
std::future<void> m_load_task;
std::atomic<bool> m_data_loaded = false;
std::vector<GHOST_XrControllerModelVertex> m_vertices;
std::vector<uint32_t> m_indices;
std::vector<GHOST_XrControllerModelComponent> m_components;
std::vector<GHOST_XrControllerModelNode> m_nodes;
/** Maps node states to nodes. */
std::vector<int32_t> m_node_state_indices;
void loadControllerModel(XrSession session);
};

View File

@@ -30,6 +30,7 @@
#include "GHOST_IXrGraphicsBinding.h"
#include "GHOST_XrAction.h"
#include "GHOST_XrContext.h"
#include "GHOST_XrControllerModel.h"
#include "GHOST_XrException.h"
#include "GHOST_XrSwapchain.h"
#include "GHOST_Xr_intern.h"
@@ -52,6 +53,8 @@ struct OpenXRSessionData {
std::vector<GHOST_XrSwapchain> swapchains;
std::map<std::string, GHOST_XrActionSet> action_sets;
/* Controller models identified by subaction path. */
std::map<std::string, GHOST_XrControllerModel> controller_models;
};
struct GHOST_XrDrawInfo {
@@ -916,3 +919,71 @@ void GHOST_XrSession::getActionCustomdataArray(const char *action_set_name,
}
/** \} */ /* Actions */
/* -------------------------------------------------------------------- */
/** \name Controller Model
*
* \{ */
bool GHOST_XrSession::loadControllerModel(const char *subaction_path)
{
if (!m_context->isExtensionEnabled(XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME)) {
return false;
}
XrSession session = m_oxr->session;
std::map<std::string, GHOST_XrControllerModel> &controller_models = m_oxr->controller_models;
std::map<std::string, GHOST_XrControllerModel>::iterator it = controller_models.find(
subaction_path);
if (it == controller_models.end()) {
XrInstance instance = m_context->getInstance();
it = controller_models
.emplace(std::piecewise_construct,
std::make_tuple(subaction_path),
std::make_tuple(instance, subaction_path))
.first;
}
it->second.load(session);
return true;
}
void GHOST_XrSession::unloadControllerModel(const char *subaction_path)
{
std::map<std::string, GHOST_XrControllerModel> &controller_models = m_oxr->controller_models;
if (controller_models.find(subaction_path) != controller_models.end()) {
controller_models.erase(subaction_path);
}
}
bool GHOST_XrSession::updateControllerModelComponents(const char *subaction_path)
{
XrSession session = m_oxr->session;
std::map<std::string, GHOST_XrControllerModel>::iterator it = m_oxr->controller_models.find(
subaction_path);
if (it == m_oxr->controller_models.end()) {
return false;
}
it->second.updateComponents(session);
return true;
}
bool GHOST_XrSession::getControllerModelData(const char *subaction_path,
GHOST_XrControllerModelData &r_data)
{
std::map<std::string, GHOST_XrControllerModel>::iterator it = m_oxr->controller_models.find(
subaction_path);
if (it == m_oxr->controller_models.end()) {
return false;
}
it->second.getData(r_data);
return true;
}
/** \} */ /* Controller Model */

View File

@@ -69,10 +69,8 @@ class GHOST_XrSession {
const char *const *profile_paths);
bool attachActionSets();
/**
* Action functions to be called post-session start.
* \param action_set_name: When `nullptr`, all attached action sets will be synced.
*/
/** Action functions to be called post-session start. */
/** param action_set_name : When `nullptr`, all attached action sets will be synced. */
bool syncActions(const char *action_set_name = nullptr);
bool applyHapticAction(const char *action_set_name,
const char *action_name,
@@ -84,12 +82,18 @@ class GHOST_XrSession {
const char *action_name,
const char *subaction_path);
/* Custom data (owned by Blender, not GHOST) accessors. */
/** Custom data (owned by Blender, not GHOST) accessors. */
void *getActionSetCustomdata(const char *action_set_name);
void *getActionCustomdata(const char *action_set_name, const char *action_name);
uint32_t getActionCount(const char *action_set_name);
void getActionCustomdataArray(const char *action_set_name, void **r_customdata_array);
/** Controller model functions. */
bool loadControllerModel(const char *subaction_path);
void unloadControllerModel(const char *subaction_path);
bool updateControllerModelComponents(const char *subaction_path);
bool getControllerModelData(const char *subaction_path, GHOST_XrControllerModelData &r_data);
private:
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
* custom callbacks set before session start. */

View File

@@ -21,6 +21,7 @@
#pragma once
#include <memory>
#include <string.h>
#include <vector>
#include "GHOST_Xr_openxr_includes.h"

View File

@@ -717,6 +717,12 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
const float co[3],
const float axis[3],
const float angle);
void map_to_pixel(int r_co[2],
const float co[3],
const float viewmat[4][4],
const float winmat[4][4],
int winx,
int winy);
/********************************** Normals **********************************/

View File

@@ -5277,6 +5277,23 @@ void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
copy_v2_v2(r_co, tmp);
}
void map_to_pixel(int r_co[2],
const float co[3],
const float viewmat[4][4],
const float winmat[4][4],
int winx,
int winy)
{
float persmat[4][4];
float vec[3];
mul_m4_m4m4(persmat, winmat, viewmat);
mul_v3_project_m4_v3(vec, persmat, co);
r_co[0] = (int)(((float)winx / 2.0f) * (1.0f + vec[0]));
r_co[1] = (int)(((float)winy / 2.0f) * (1.0f + vec[1]));
}
/********************************* Normals **********************************/
void accumulate_vertex_normals_tri_v3(float n1[3],

View File

@@ -2489,6 +2489,10 @@ static void lib_link_wm_xr_data_restore(struct IDNameLib_Map *id_map, wmXrData *
{
xr_data->session_settings.base_pose_object = restore_pointer_by_name(
id_map, (ID *)xr_data->session_settings.base_pose_object, USER_REAL);
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
mocap_ob->ob = restore_pointer_by_name(id_map, (ID *)mocap_ob->ob, USER_REAL);
}
}
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)

View File

@@ -1189,6 +1189,14 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 7)) {
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
wm->xr.session_settings.draw_flags |= (V3D_OFSDRAW_SHOW_SELECTION |
V3D_OFSDRAW_XR_SHOW_CONTROLLERS |
V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 8)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection != NULL) {

View File

@@ -200,6 +200,15 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
shd->grid_distance = dist / 2.0f;
ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
if (((v3d->flag & V3D_XR_SESSION_SURFACE) != 0) || ((v3d->flag & V3D_XR_SESSION_MIRROR) != 0)) {
/* The calculations for the grid parameters assume that the view matrix has no scale component,
* which may not be correct if the user is "shrunk" or "enlarged" by zooming in or out.
* Therefore, we need to compensate the values here. */
float viewinvscale = len_v3(
viewinv[0]); /* Assumption is uniform scaling (all column vectors are of same length). */
shd->grid_distance *= viewinvscale;
}
}
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)

View File

@@ -51,6 +51,7 @@
#include "BKE_pbvh.h"
#include "BKE_pointcache.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
#include "BKE_volume.h"
#include "DNA_camera_types.h"
@@ -1402,6 +1403,27 @@ void DRW_draw_callbacks_post_scene(void)
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW);
#ifdef WITH_XR_OPENXR
/* XR callbacks (controllers, custom draw functions). */
if ((v3d->flag & V3D_XR_SESSION_MIRROR) != 0) {
if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
ARegionType *art = WM_xr_surface_controller_region_type_get();
if (art) {
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
}
}
if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
if (st) {
ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
if (art) {
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
}
}
}
}
#endif
/* Callback can be nasty and do whatever they want with the state.
* Don't trust them! */
DRW_state_reset();
@@ -1448,6 +1470,46 @@ void DRW_draw_callbacks_post_scene(void)
ED_annotation_draw_view3d(DEG_get_input_scene(depsgraph), depsgraph, v3d, region, true);
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
#ifdef WITH_XR_OPENXR
if ((v3d->flag & V3D_XR_SESSION_SURFACE) != 0) {
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DRW_state_reset();
GPU_framebuffer_bind(dfbl->overlay_fb);
GPU_matrix_projection_set(rv3d->winmat);
GPU_matrix_set(rv3d->viewmat);
/* Callbacks (controllers, custom draw functions). */
if (((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) ||
((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0)) {
GPU_depth_test(GPU_DEPTH_NONE);
GPU_apply_state();
if ((v3d->flag2 & V3D_XR_SHOW_CONTROLLERS) != 0) {
ARegionType *art = WM_xr_surface_controller_region_type_get();
if (art) {
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
}
}
if ((v3d->flag2 & V3D_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D);
if (st) {
ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_XR);
if (art) {
ED_region_surface_draw_cb_draw(art, REGION_DRAW_POST_VIEW);
}
}
}
DRW_state_reset();
}
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
#endif
}
}

View File

@@ -1682,10 +1682,12 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
bsphere->center[0] = farcenter[0] * z / e;
bsphere->center[1] = farcenter[1] * z / e;
bsphere->center[2] = z;
bsphere->radius = len_v3v3(bsphere->center, farpoint);
/* Transform to world space. */
mul_m4_v3(viewinv, bsphere->center);
/* For XR, the view matrix may contain a scale factor. Then, transforming only the center
* into world space after calculating the radius will result in incorrect behavior. */
mul_m4_v3(viewinv, bsphere->center); /* Transform to world space. */
mul_m4_v3(viewinv, farpoint);
bsphere->radius = len_v3v3(bsphere->center, farpoint);
}
}

View File

@@ -72,7 +72,8 @@ void *ED_region_draw_cb_activate(struct ARegionType *art,
void (*draw)(const struct bContext *, struct ARegion *, void *),
void *customdata,
int type);
void ED_region_draw_cb_draw(const struct bContext *, struct ARegion *, int);
void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type);
void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type);
void ED_region_draw_cb_exit(struct ARegionType *, void *);
void ED_region_draw_cb_remove_by_type(struct ARegionType *art,
void *draw_fn,

View File

@@ -31,8 +31,10 @@ extern "C" {
struct Object;
struct bContext;
struct ViewLayer;
struct wmKeyConfig;
struct wmOperatorType;
struct wmTimer;
void ED_keymap_transform(struct wmKeyConfig *keyconf);
void transform_operatortypes(void);
@@ -193,6 +195,19 @@ int ED_transform_calc_gizmo_stats(const struct bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds);
/* transform_convert.c */
void ED_transform_animrecord_check_state(struct Scene *scene,
struct wmTimer *animtimer,
struct Object *ob);
/* transform_convert_object.c */
void ED_transform_autokeyframe_object(struct bContext *C,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Object *ob,
int tmode);
bool ED_transform_motionpath_need_update_object(struct Scene *scene, struct Object *ob);
#ifdef __cplusplus
}
#endif

View File

@@ -44,6 +44,8 @@ typedef enum {
SNAP_NOT_SELECTED = 1,
SNAP_NOT_ACTIVE = 2,
SNAP_ONLY_ACTIVE = 3,
SNAP_SELECTED = 4,
SNAP_SELECTABLE = 5,
} eSnapSelect;
typedef enum {

View File

@@ -595,6 +595,7 @@ void ED_view3d_viewcontext_init(struct bContext *C,
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region);
bool object_deselect_all_except(struct ViewLayer *view_layer, struct Base *b);
/* XXX should move to BLI_math */
bool edge_inside_circle(const float cent[2],
@@ -776,12 +777,27 @@ 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);
void ED_view3d_view_params_get(const struct View3D *v3d,
const struct RegionView3D *rv3d,
float *r_lens,
float *r_clip_start,
float *r_clip_end,
float r_viewmat[4][4]);
void ED_view3d_view_params_set(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
const float lens,
const float clip_start,
const float clip_end,
const float viewmat[4][4]);
#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,
const struct View3D *v3d,
const struct Scene *scene);
bool ED_view3d_is_region_xr_mirror_active(const struct wmWindowManager *wm,
const struct View3D *v3d,

View File

@@ -60,7 +60,7 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3DShading *shading_override,
int drawtype,
eDrawType drawtype,
int winx,
int winy,
unsigned int draw_flags,
@@ -68,6 +68,7 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
const float winmat[4][4],
float clip_start,
float clip_end,
bool is_xr_surface,
bool is_image_render,
bool draw_background,
const char *viewname,

View File

@@ -2192,6 +2192,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateInputStatus(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateXrActionmapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
bool uiTemplateEventFromKeymapItem(struct uiLayout *layout,
const char *text,

View File

@@ -113,5 +113,8 @@ if(WIN32 OR APPLE)
endif()
endif()
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -6235,6 +6235,44 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
/** \} */
/* -------------------------------------------------------------------- */
/** \name XR Actionmap Template
* \{ */
#ifdef WITH_XR_OPENXR
static void xr_actionmap_item_modified(bContext *UNUSED(C), void *ami_p, void *UNUSED(unused))
{
XrActionMapItem *ami = (XrActionMapItem *)ami_p;
WM_xr_actionconfig_update_tag(NULL, ami);
}
#endif
void uiTemplateXrActionmapItemProperties(uiLayout *layout, PointerRNA *ptr)
{
#ifdef WITH_XR_OPENXR
PointerRNA propptr = RNA_pointer_get(ptr, "op_properties");
if (propptr.data) {
uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
WM_operator_properties_sanitize(&propptr, false);
/* Use same template as keymap item properties. */
template_keymap_item_properties(layout, NULL, &propptr);
for (; but; but = but->next) {
if (but->rnaprop) {
UI_but_func_set(but, xr_actionmap_item_modified, ptr->data, NULL);
UI_but_flag_enable(but, UI_BUT_UPDATE_DELAY);
}
}
}
#else
UNUSED_VARS(layout, ptr);
#endif
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Event Icon Template
* \{ */

View File

@@ -264,9 +264,9 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
}
}
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type)
{
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &region->type->drawcalls) {
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc->type == type) {
rdc->draw(C, region, rdc->customdata);
@@ -276,6 +276,16 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
}
}
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
{
ed_region_draw_cb_draw(C, region, region->type, type);
}
void ED_region_surface_draw_cb_draw(ARegionType *art, int type)
{
ed_region_draw_cb_draw(NULL, NULL, art, type);
}
void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *))
{
LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) {

View File

@@ -1798,5 +1798,10 @@ void ED_spacetype_view3d(void)
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);
/* regions: xr */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d xr region");
art->regionid = RGN_TYPE_XR;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
}

View File

@@ -328,19 +328,44 @@ static void view3d_xr_mirror_setup(const wmWindowManager *wm,
ARegion *region,
const rcti *rect)
{
RegionView3D *rv3d = region->regiondata;
float viewmat[4][4];
const float lens_old = v3d->lens;
const float clip_start_old = v3d->clip_start;
const float clip_end_old = v3d->clip_end;
/* Here we need to use the viewmat from the selection eye instead of the eye centroid because
* this function may be called from a GPU select operation. In that case we need to match the
* selection eye's view, which was used to project 3D to 2D, for a correct result. */
const bool from_selection_eye = true;
if (!WM_xr_session_state_viewer_pose_matrix_info_get(&wm->xr, viewmat, &v3d->lens)) {
if (!WM_xr_session_state_viewer_pose_matrix_info_get(
&wm->xr, from_selection_eye, viewmat, &v3d->lens, &v3d->clip_start, &v3d->clip_end)) {
/* Can't get info from XR session, use fallback values. */
copy_m4_m4(viewmat, rv3d->viewmat);
copy_m4_m4(viewmat, ((RegionView3D *)region->regiondata)->viewmat);
v3d->lens = lens_old;
v3d->clip_start = clip_start_old;
v3d->clip_end = clip_end_old;
}
view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
/* Reset overridden View3D data */
if ((wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) != 0) {
v3d->flag2 |= V3D_XR_SHOW_CONTROLLERS;
}
else {
v3d->flag2 &= ~V3D_XR_SHOW_CONTROLLERS;
}
if ((wm->xr.session_settings.draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) != 0) {
v3d->flag2 |= V3D_XR_SHOW_CUSTOM_OVERLAYS;
}
else {
v3d->flag2 &= ~V3D_XR_SHOW_CUSTOM_OVERLAYS;
}
/* Hide navigation gizmo. */
v3d->gizmo_flag |= V3D_GIZMO_HIDE_NAVIGATE;
/* Reset overridden View3D data. */
v3d->lens = lens_old;
v3d->clip_start = clip_start_old;
v3d->clip_end = clip_end_old;
}
#endif /* WITH_XR_OPENXR */
@@ -1750,7 +1775,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
Scene *scene,
View3DShading *shading_override,
int drawtype,
eDrawType drawtype,
int winx,
int winy,
uint draw_flags,
@@ -1758,6 +1783,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
const float winmat[4][4],
float clip_start,
float clip_end,
bool is_xr_surface,
bool is_image_render,
bool draw_background,
const char *viewname,
@@ -1787,23 +1813,37 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
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_OVERRIDE_SCENE_SETTINGS) == V3D_OFSDRAW_NONE) {
v3d.flag2 = V3D_HIDE_OVERLAYS;
}
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). */
else {
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;
}
if (draw_flags & V3D_OFSDRAW_SHOW_SELECTION) {
v3d.flag |= V3D_SELECT_OUTLINE;
}
if (draw_flags & V3D_OFSDRAW_XR_SHOW_CONTROLLERS) {
v3d.flag2 |= V3D_XR_SHOW_CONTROLLERS;
}
if (draw_flags & V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS) {
v3d.flag2 |= V3D_XR_SHOW_CUSTOM_OVERLAYS;
}
/* 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;
if (is_xr_surface) {
v3d.flag |= V3D_XR_SESSION_SURFACE;
}
rv3d.persp = RV3D_PERSP;

View File

@@ -169,7 +169,7 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
}
/* deselect all except b */
static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
{
bool changed = false;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
@@ -2818,6 +2818,57 @@ static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *even
return WM_operator_flag_only_pass_through_on_press(retval, event);
}
static int view3d_select_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
{
BLI_assert(event->type == EVT_XR_ACTION);
BLI_assert(event->custom == EVT_DATA_XR);
BLI_assert(event->customdata);
const wmXrActionData *actiondata = event->customdata;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
float lens_prev;
float clip_start_prev, clip_end_prev;
float viewmat_prev[4][4];
int mval[2];
int retval;
/* Since this function is called in a window context, we need to replace the
* window view parameters with the XR surface counterparts to get a correct
* result for GPU select. */
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
ED_view3d_view_params_set(depsgraph,
scene,
v3d,
region,
actiondata->eye_lens,
xr->session_settings.clip_start,
xr->session_settings.clip_end,
actiondata->eye_viewmat);
map_to_pixel(mval,
actiondata->controller_loc,
actiondata->eye_viewmat,
rv3d->winmat,
region->winx,
region->winy);
RNA_int_set_array(op->ptr, "location", mval);
retval = view3d_select_exec(C, op);
/* Restore window view. */
ED_view3d_view_params_set(
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
return retval;
}
void VIEW3D_OT_select(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2829,6 +2880,7 @@ void VIEW3D_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->invoke = view3d_select_invoke;
ot->invoke_3d = view3d_select_invoke_3d;
ot->exec = view3d_select_exec;
ot->poll = ED_operator_view3d_active;
@@ -3698,8 +3750,10 @@ void VIEW3D_OT_select_box(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_gesture_box_invoke;
ot->invoke_3d = WM_gesture_box_invoke_3d;
ot->exec = view3d_box_select_exec;
ot->modal = WM_gesture_box_modal;
ot->modal_3d = WM_gesture_box_modal_3d;
ot->poll = view3d_selectable_data;
ot->cancel = WM_gesture_box_cancel;

View File

@@ -1692,6 +1692,44 @@ void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all)
/** \name XR Functionality
* \{ */
/* Used for invoke_3d/modal_3d (XR) operators. */
void ED_view3d_view_params_get(const struct View3D *v3d,
const struct RegionView3D *rv3d,
float *r_lens,
float *r_clip_start,
float *r_clip_end,
float r_viewmat[4][4])
{
*r_lens = v3d->lens;
*r_clip_start = v3d->clip_start;
*r_clip_end = v3d->clip_end;
if (r_viewmat) {
copy_m4_m4(r_viewmat, rv3d->viewmat);
}
}
void ED_view3d_view_params_set(struct Depsgraph *depsgraph,
struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
const float lens,
const float clip_start,
const float clip_end,
const float viewmat[4][4])
{
v3d->lens = lens;
v3d->clip_start = clip_start;
v3d->clip_end = clip_end;
if (viewmat) {
ED_view3d_update_viewmat(depsgraph, scene, v3d, region, viewmat, NULL, NULL, false);
}
else {
view3d_winmatrix_set(depsgraph, region, v3d, NULL);
}
}
#ifdef WITH_XR_OPENXR
static void view3d_xr_mirror_begin(RegionView3D *rv3d)
@@ -1729,8 +1767,6 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
{
if (v3d->runtime.flag & V3D_RUNTIME_XR_SESSION_ROOT) {
View3DShading *xr_shading = &wm->xr.session_settings.shading;
/* Flags that shouldn't be overridden by the 3D View shading. */
const int flag_copy = V3D_SHADING_WORLD_ORIENTATION;
BLI_assert(WM_xr_session_exists(&wm->xr));
@@ -1748,9 +1784,7 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S
}
/* Copy shading from View3D to VR view. */
const int old_xr_shading_flag = xr_shading->flag;
*xr_shading = v3d->shading;
xr_shading->flag = (xr_shading->flag & ~flag_copy) | (old_xr_shading_flag & flag_copy);
if (v3d->shading.prop) {
xr_shading->prop = IDP_CopyProperty(xr_shading->prop);
}

View File

@@ -129,5 +129,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -1597,11 +1597,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
/* for the realtime animation recording feature, handle overlapping data */
void animrecord_check_state(TransInfo *t, struct Object *ob)
void ED_transform_animrecord_check_state(Scene *scene, wmTimer *animtimer, struct Object *ob)
{
Scene *scene = t->scene;
ID *id = &ob->id;
wmTimer *animtimer = t->animtimer;
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
/* sanity checks */

View File

@@ -65,7 +65,6 @@ struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struc
char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
void animrecord_check_state(TransInfo *t, struct Object *ob);
/* transform_convert_action.c */
void createTransActionData(bContext *C, TransInfo *t);

View File

@@ -1449,7 +1449,7 @@ void recalcData_pose(TransInfo *t)
/* XXX: this currently doesn't work, since flags aren't set yet! */
int targetless_ik = (t->flag & T_AUTOIK);
animrecord_check_state(t, ob);
ED_transform_animrecord_check_state(t->scene, t->animtimer, ob);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
}

View File

@@ -728,7 +728,7 @@ void createTransObject(bContext *C, TransInfo *t)
* \note Context may not always be available,
* so must check before using it as it's a luxury for a few cases.
*/
static void autokeyframe_object(
void ED_transform_autokeyframe_object(
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
{
Main *bmain = CTX_data_main(C);
@@ -850,7 +850,7 @@ static void autokeyframe_object(
/* Return if we need to update motion paths, only if they already exist,
* and we will insert a keyframe at the end of transform. */
static bool motionpath_need_update_object(Scene *scene, Object *ob)
bool ED_transform_motionpath_need_update_object(Scene *scene, Object *ob)
{
/* XXX: there's potential here for problems with unkeyed rotations/scale,
* but for now (until proper data-locality for baking operations),
@@ -895,11 +895,11 @@ void recalcData_objects(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
animrecord_check_state(t, ob);
autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
ED_transform_animrecord_check_state(t->scene, t->animtimer, ob);
ED_transform_autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
}
motionpath_update |= motionpath_need_update_object(t->scene, ob);
motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
/* sets recalc flags fully, instead of flushing existing ones
* otherwise proxies don't function correctly
@@ -971,10 +971,10 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
/* Set auto-key if necessary. */
if (!canceled) {
autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
ED_transform_autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
}
motionpath_update |= motionpath_need_update_object(t->scene, ob);
motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
/* Restore rigid body transform. */
if (ob->rigidbody_object && canceled) {

View File

@@ -470,6 +470,68 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
return exit_code;
}
static int transform_modal_3d(bContext *C, wmOperator *op, const wmEvent *event)
{
BLI_assert(event->type == EVT_XR_ACTION);
BLI_assert(event->custom == EVT_DATA_XR);
BLI_assert(event->customdata);
const wmXrActionData *actiondata = event->customdata;
TransInfo *t = op->customdata;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
float lens_prev;
float clip_start_prev, clip_end_prev;
float viewmat_prev[4][4];
int retval;
wmEvent event_mut;
memcpy(&event_mut, event, sizeof(wmEvent));
/* Replace window view parameters with XR surface counterparts. */
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
ED_view3d_view_params_set(
depsgraph,
scene,
v3d,
region,
actiondata->eye_lens,
xr->session_settings.clip_start,
xr->session_settings.clip_end,
t->viewmat); /* Use viewmat from when transform was invoked instead of latest XR viewmat. */
map_to_pixel(event_mut.mval,
actiondata->controller_loc,
t->viewmat,
rv3d->winmat,
region->winx,
region->winy);
if (event->val == KM_PRESS) {
event_mut.type = MOUSEMOVE;
}
else if (event->val == KM_RELEASE) {
event_mut.type = LEFTMOUSE;
}
else {
/* XR events currently only support press and release. */
BLI_assert(false);
}
retval = transform_modal(C, op, &event_mut);
/* Restore window view. */
ED_view3d_view_params_set(
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
return retval;
}
static void transform_cancel(bContext *C, wmOperator *op)
{
TransInfo *t = op->customdata;
@@ -530,6 +592,56 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
static int transform_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
{
BLI_assert(event->type == EVT_XR_ACTION);
BLI_assert(event->custom == EVT_DATA_XR);
BLI_assert(event->customdata);
const wmXrActionData *actiondata = event->customdata;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
float lens_prev;
float clip_start_prev, clip_end_prev;
float viewmat_prev[4][4];
int retval;
wmEvent event_mut;
memcpy(&event_mut, event, sizeof(wmEvent));
event_mut.type = LEFTMOUSE;
/* Replace window view parameters with XR surface counterparts. */
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, viewmat_prev);
ED_view3d_view_params_set(depsgraph,
scene,
v3d,
region,
actiondata->eye_lens,
xr->session_settings.clip_start,
xr->session_settings.clip_end,
actiondata->eye_viewmat);
map_to_pixel(event_mut.mval,
actiondata->controller_loc,
actiondata->eye_viewmat,
rv3d->winmat,
region->winx,
region->winy);
retval = transform_invoke(C, op, &event_mut);
/* Restore window view. */
ED_view3d_view_params_set(
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, viewmat_prev);
return retval;
}
static bool transform_poll_property(const bContext *UNUSED(C),
wmOperator *op,
const PropertyRNA *prop)
@@ -747,8 +859,10 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = transform_invoke;
ot->invoke_3d = transform_invoke_3d;
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->modal_3d = transform_modal_3d;
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
@@ -774,8 +888,10 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = transform_invoke;
ot->invoke_3d = transform_invoke_3d;
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->modal_3d = transform_modal_3d;
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
@@ -862,8 +978,10 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = transform_invoke;
ot->invoke_3d = transform_invoke_3d;
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->modal_3d = transform_modal_3d;
ot->cancel = transform_cancel;
ot->poll = transform_rotate_poll;
ot->poll_property = transform_poll_property;
@@ -1264,8 +1382,10 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = transform_invoke;
ot->invoke_3d = transform_invoke_3d;
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->modal_3d = transform_modal_3d;
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;

View File

@@ -499,6 +499,16 @@ static void iter_snap_objects(SnapObjectContext *sctx,
continue;
}
}
else if (snap_select == SNAP_SELECTED) {
if (!(base->flag & BASE_SELECTED) && !(base->flag_legacy & BA_WAS_SEL)) {
continue;
}
}
else if (snap_select == SNAP_SELECTABLE) {
if (!(base->flag & BASE_SELECTABLE)) {
continue;
}
}
Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {

View File

@@ -666,8 +666,11 @@ typedef enum eRegionType {
RGN_TYPE_EXECUTE = 10,
RGN_TYPE_FOOTER = 11,
RGN_TYPE_TOOL_HEADER = 12,
/* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR
context (surface, mirror view). Does not represent any real region. */
RGN_TYPE_XR = 13,
#define RGN_TYPE_LEN (RGN_TYPE_TOOL_HEADER + 1)
#define RGN_TYPE_LEN (RGN_TYPE_XR + 1)
} eRegionType;
/* use for function args */

View File

@@ -30,6 +30,9 @@ typedef enum eV3DOffscreenDrawFlag {
V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0),
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1),
V3D_OFSDRAW_SHOW_GRIDFLOOR = (1 << 2),
V3D_OFSDRAW_SHOW_SELECTION = (1 << 3),
V3D_OFSDRAW_XR_SHOW_CONTROLLERS = (1 << 4),
V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS = (1 << 5),
} eV3DOffscreenDrawFlag;
/** #View3DShading.light */

View File

@@ -373,6 +373,7 @@ typedef struct View3D {
#define V3D_HIDE_HELPLINES (1 << 2)
#define V3D_FLAG_UNUSED_2 (1 << 3) /* cleared */
#define V3D_XR_SESSION_MIRROR (1 << 4)
#define V3D_XR_SESSION_SURFACE (1 << 5)
#define V3D_FLAG_UNUSED_10 (1 << 10) /* cleared */
#define V3D_SELECT_OUTLINE (1 << 11)
@@ -465,6 +466,8 @@ enum {
#define V3D_FLAG2_UNUSED_13 (1 << 13) /* cleared */
#define V3D_FLAG2_UNUSED_14 (1 << 14) /* cleared */
#define V3D_FLAG2_UNUSED_15 (1 << 15) /* cleared */
#define V3D_XR_SHOW_CONTROLLERS (1 << 16)
#define V3D_XR_SHOW_CUSTOM_OVERLAYS (1 << 17)
/** #View3D.gp_flag (short) */
#define V3D_GP_FADE_OBJECTS (1 << 0) /* Fade all non GP objects */

View File

@@ -26,15 +26,17 @@
extern "C" {
#endif
struct XrActionConfig;
/* -------------------------------------------------------------------- */
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 */
float base_scale;
char _pad[3];
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];
@@ -42,12 +44,30 @@ typedef struct XrSessionSettings {
/** View3D draw flags (V3D_OFSDRAW_NONE, V3D_OFSDRAW_SHOW_ANNOTATION, ...). */
char draw_flags;
char _pad2[3];
/** Draw style for controller visualization. */
char controller_draw_style;
/** The eye (view) used when projecting 3D to 2D (e.g. when performing GPU select). */
char selection_eye;
char _pad2;
/** Clipping distance. */
float clip_start, clip_end;
int flag;
int flag; /* eXrSessionFlag */
/** Known action configurations. */
ListBase actionconfigs; /* XrActionConfig */
/** Default configuration. */
struct XrActionConfig *defaultconf;
/** Addon configuration. */
struct XrActionConfig *addonconf;
/** User configuration. */
struct XrActionConfig *userconf;
/** Objects to bind to headset/controller poses. */
ListBase mocap_objects; /* XrMotionCaptureObject */
short sel_mocap_object;
char _pad3[6];
} XrSessionSettings;
typedef enum eXrSessionFlag {
@@ -55,11 +75,23 @@ typedef enum eXrSessionFlag {
XR_SESSION_USE_ABSOLUTE_TRACKING = (1 << 1),
} eXrSessionFlag;
typedef enum eXRSessionBasePoseType {
typedef enum eXrSessionBasePoseType {
XR_BASE_POSE_SCENE_CAMERA = 0,
XR_BASE_POSE_OBJECT = 1,
XR_BASE_POSE_CUSTOM = 2,
} eXRSessionBasePoseType;
} eXrSessionBasePoseType;
typedef enum eXrSessionControllerDrawStyle {
XR_CONTROLLER_DRAW_DARK = 0,
XR_CONTROLLER_DRAW_LIGHT = 1,
XR_CONTROLLER_DRAW_DARK_RAY = 2,
XR_CONTROLLER_DRAW_LIGHT_RAY = 3,
} eXrSessionControllerDrawStyle;
typedef enum eXrSessionEye {
XR_EYE_LEFT = 0,
XR_EYE_RIGHT = 1,
} eXrSessionEye;
/** XR action type. Enum values match those in GHOST_XrActionType enum for consistency. */
typedef enum eXrActionType {
@@ -94,11 +126,11 @@ typedef enum eXrHapticFlag {
XR_HAPTIC_REPEAT = (1 << 3),
} eXrHapticFlag;
/**
* For axis-based inputs (thumb-stick/track-pad/etc).
* Determines the region for action execution (mutually exclusive per axis).
*/
typedef enum eXrAxisFlag {
/**
* For axis-based inputs (thumb-stick/track-pad/etc).
* Determines the region for action execution (mutually exclusive per axis).
*/
XR_AXIS0_POS = (1 << 0),
XR_AXIS0_NEG = (1 << 1),
XR_AXIS1_POS = (1 << 2),
@@ -111,6 +143,11 @@ typedef enum eXrPoseFlag {
XR_POSE_AIM = (1 << 1),
} eXrPoseFlag;
typedef enum eXrMotionCaptureFlag {
XR_MOCAP_OBJECT_ENABLE = (1 << 0),
XR_MOCAP_OBJECT_AUTOKEY = (1 << 1),
} eXrMotionCaptureFlag;
/* -------------------------------------------------------------------- */
typedef struct XrActionMapBinding {
@@ -151,7 +188,7 @@ typedef struct XrActionMapItem {
char user_path1[64];
/** Operator to be called on XR events. */
char op[64]; /* OP_MAX_TYPENAME */
char op[64];
/** Operator properties, assigned to ptr->data and can be written to a file. */
IDProperty *op_properties;
/** RNA pointer to access properties. */
@@ -171,10 +208,15 @@ typedef struct XrActionMapItem {
float haptic_amplitude;
short selbinding;
char _pad3[2];
short flag;
ListBase bindings; /* XrActionMapBinding */
} XrActionMapItem;
/** #XrActionMapItem.flag */
enum {
XR_ACTIONMAP_ITEM_UPDATE = (1 << 0),
};
/* -------------------------------------------------------------------- */
typedef struct XrActionMap {
@@ -185,9 +227,53 @@ typedef struct XrActionMap {
ListBase items; /* XrActionMapItem */
short selitem;
char _pad[6];
short flag;
char _pad[4];
} XrActionMap;
/** #XrActionMap.flag */
enum {
XR_ACTIONMAP_UPDATE = (1 << 0),
};
/* -------------------------------------------------------------------- */
typedef struct XrActionConfig {
struct XrActionConfig *next, *prev;
/** Unique name. */
char name[64]; /* MAX_NAME */
ListBase actionmaps; /* XrActionMap */
short actactionmap;
short selactionmap;
short flag;
char _pad[2];
} XrActionConfig;
/** #XrActionConfig.flag */
enum {
XR_ACTIONCONF_USER = (1 << 0), /* User action config. */
};
/* -------------------------------------------------------------------- */
typedef struct XrMotionCaptureObject {
struct XrMotionCaptureObject *next, *prev;
/** Object to bind to a VR device. Used as struct identifier. */
Object *ob;
/** OpenXR user path, identifies the target headset/controller. */
char user_path[64];
/** Location/rotation offsets. */
float location_offset[3];
float rotation_offset[3];
short flag; /* eXrMotionCaptureFlag */
char _pad[6];
} XrMotionCaptureObject;
/* -------------------------------------------------------------------- */
#ifdef __cplusplus

View File

@@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_EXECUTE, "EXECUTE", 0, "Execute Buttons", ""},
{RGN_TYPE_FOOTER, "FOOTER", 0, "Footer", ""},
{RGN_TYPE_TOOL_HEADER, "TOOL_HEADER", 0, "Tool Header", ""},
{RGN_TYPE_XR, "XR", 0, "XR", ""},
{0, NULL, 0, NULL, NULL},
};

View File

@@ -1755,6 +1755,11 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(
srna, "template_xr_actionmap_item_properties", "uiTemplateXrActionmapItemProperties");
parm = RNA_def_pointer(func, "item", "XrActionMapItem", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu");
RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");

View File

@@ -362,6 +362,8 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
0,
"ActionZone Fullscreen",
"AZone FullScr"},
/* xr */
{EVT_XR_ACTION, "XR_ACTION", 0, "XR Action", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -700,6 +702,238 @@ static void rna_Event_tilt_get(PointerRNA *ptr, float *values)
WM_event_tablet_data(event, NULL, values);
}
static bool rna_Event_is_xr_get(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
return WM_event_is_xr(event);
}
static void rna_Event_xr_action_set_get(PointerRNA *ptr, char *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, &value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else {
value[0] = '\0';
}
}
static int rna_Event_xr_action_set_length(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
wmXrActionData *data = event->customdata;
return strlen(data->action_set) + 1;
}
else {
return 0;
}
}
static void rna_Event_xr_action_get(PointerRNA *ptr, char *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, &value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else {
value[0] = '\0';
}
}
static int rna_Event_xr_action_length(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
wmXrActionData *data = event->customdata;
return strlen(data->action) + 1;
}
else {
return 0;
}
}
static int rna_Event_xr_type_get(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
int type;
WM_event_xr_data(event,
NULL,
NULL,
(char *)&type,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
return type;
}
else {
return 0;
}
}
static void rna_Event_xr_state_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else {
memset(value, 0, sizeof(float[2]));
}
}
static void rna_Event_xr_state_other_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else {
memset(value, 0, sizeof(float[2]));
}
}
static float rna_Event_xr_float_threshold_get(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
float float_threshold;
WM_event_xr_data(event,
NULL,
NULL,
NULL,
NULL,
NULL,
&float_threshold,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
return float_threshold;
}
else {
return 0.0f;
}
}
static void rna_Event_xr_controller_location_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL, NULL);
}
else {
memset(value, 0, sizeof(float[3]));
}
}
static void rna_Event_xr_controller_rotation_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL, NULL);
}
else {
value[0] = 1.0f;
value[1] = value[2] = value[3] = 0.0f;
}
}
static void rna_Event_xr_controller_location_other_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL, NULL);
}
else {
memset(value, 0, sizeof(float[3]));
}
}
static void rna_Event_xr_controller_rotation_other_get(PointerRNA *ptr, float *value)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, value, NULL, NULL, NULL);
}
else {
value[0] = 1.0f;
value[1] = value[2] = value[3] = 0.0f;
}
}
static float rna_Event_xr_focal_length_get(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
float focal_len;
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &focal_len, NULL, NULL);
return focal_len;
}
else {
return 0.0f;
}
}
static void rna_Event_xr_view_matrix_get(PointerRNA *ptr, float values[16])
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
WM_event_xr_data(event,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
(float(*)[4])values,
NULL);
}
else {
memset(values, 0, sizeof(float[16]));
}
}
static bool rna_Event_xr_bimanual_get(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
if (WM_event_is_xr(event)) {
bool bimanual;
WM_event_xr_data(
event, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bimanual);
return bimanual;
}
else {
return false;
}
}
static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
{
struct uiPopupMenu *pup = ptr->data;
@@ -2130,6 +2364,13 @@ static void rna_def_event(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem xr_action_types[] = {
{XR_BOOLEAN_INPUT, "BOOLEAN", 0, "Boolean", "Boolean value"},
{XR_FLOAT_INPUT, "FLOAT", 0, "Float", "Float value"},
{XR_VECTOR2F_INPUT, "VECTOR2F", 0, "Vector2f", "2D float vector value"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "Event", NULL);
RNA_def_struct_ui_text(srna, "Event", "Window Manager Event");
RNA_def_struct_sdna(srna, "wmEvent");
@@ -2250,6 +2491,97 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "OS Key", "True when the Cmd key is held");
/* xr */
prop = RNA_def_property(srna, "is_xr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Event_is_xr_get", NULL);
RNA_def_property_ui_text(prop, "Is XR", "The event has XR data");
prop = RNA_def_property(srna, "xr_action_set", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(
prop, "rna_Event_xr_action_set_get", "rna_Event_xr_action_set_length", NULL);
RNA_def_property_ui_text(prop, "XR Action Set", "XR action set name");
prop = RNA_def_property(srna, "xr_action", PROP_STRING, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_string_funcs(
prop, "rna_Event_xr_action_get", "rna_Event_xr_action_length", NULL);
RNA_def_property_ui_text(prop, "XR Action", "XR action name");
prop = RNA_def_property(srna, "xr_type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_items(prop, xr_action_types);
RNA_def_property_enum_funcs(prop, "rna_Event_xr_type_get", NULL, NULL);
RNA_def_property_ui_text(prop, "XR Type", "XR action type");
prop = RNA_def_property(srna, "xr_state", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_state_get", NULL, NULL);
RNA_def_property_ui_text(prop, "XR State", "XR action values corresponding to type");
prop = RNA_def_property(srna, "xr_state_other", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_state_other_get", NULL, NULL);
RNA_def_property_ui_text(
prop, "XR State Other", "State of the other user path for bimanual actions");
prop = RNA_def_property(srna, "xr_float_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_float_threshold_get", NULL, NULL);
RNA_def_property_ui_text(
prop, "XR Float Threshold", "Input threshold for Float/Vector2f actions");
prop = RNA_def_property(srna, "xr_controller_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_location_get", NULL, NULL);
RNA_def_property_ui_text(prop,
"XR Controller Location",
"Location of the action's corresponding controller aim in world space");
prop = RNA_def_property(srna, "xr_controller_rotation", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_array(prop, 4);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_rotation_get", NULL, NULL);
RNA_def_property_ui_text(prop,
"XR Controller Rotation",
"Rotation of the action's corresponding controller aim in world space");
prop = RNA_def_property(srna, "xr_controller_location_other", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_location_other_get", NULL, NULL);
RNA_def_property_ui_text(prop,
"XR Controller Location Other",
"Controller aim location of the other user path for bimanual actions");
prop = RNA_def_property(srna, "xr_controller_rotation_other", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_array(prop, 4);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_controller_rotation_other_get", NULL, NULL);
RNA_def_property_ui_text(prop,
"XR Controller Rotation Other",
"Controller aim rotation of the other user path for bimanual actions");
prop = RNA_def_property(srna, "xr_focal_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_focal_length_get", NULL, NULL);
RNA_def_property_ui_text(prop, "XR Focal Length", "Focal length of the XR selection eye");
prop = RNA_def_property(srna, "xr_view_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_array(prop, 16);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Event_xr_view_matrix_get", NULL, NULL);
RNA_def_property_ui_text(prop, "XR View Matrix", "View matrix of the XR selection eye");
prop = RNA_def_property(srna, "xr_bimanual", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Event_xr_bimanual_get", NULL);
RNA_def_property_ui_text(prop, "XR Bimanual", "Bimanual interaction is occurring");
RNA_define_verify_sdna(1); /* not in sdna */
}

View File

@@ -40,24 +40,7 @@
# include "WM_api.h"
/* -------------------------------------------------------------------- */
# ifdef WITH_XR_OPENXR
static wmXrData *rna_XrSession_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_XrSessionSettings) || (ptr->type == &RNA_XrSessionState));
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
return &wm->xr;
}
# endif
/* -------------------------------------------------------------------- */
/** \name XR Action Map
/** \name XR Action Configuration
* \{ */
static XrActionMapBinding *rna_XrActionMapBinding_new(XrActionMapItem *ami,
@@ -171,15 +154,17 @@ static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene)
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->xr.runtime) {
ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
if (actionmap) {
XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
if (ami) {
XrActionMapBinding *amb = ptr->data;
WM_xr_actionmap_binding_ensure_unique(ami, amb);
if (wm) {
XrSessionSettings *settings = &wm->xr.session_settings;
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
if (actionconf) {
XrActionMap *actionmap = BLI_findlink(&actionconf->actionmaps, actionconf->selactionmap);
if (actionmap) {
XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
if (ami) {
XrActionMapBinding *amb = ptr->data;
WM_xr_actionmap_binding_ensure_unique(ami, amb);
}
}
}
}
@@ -413,13 +398,15 @@ static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), P
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->xr.runtime) {
ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
if (actionmap) {
XrActionMapItem *ami = ptr->data;
WM_xr_actionmap_item_ensure_unique(actionmap, ami);
if (wm) {
XrSessionSettings *settings = &wm->xr.session_settings;
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
if (actionconf) {
XrActionMap *actionmap = BLI_findlink(&actionconf->actionmaps, actionconf->selactionmap);
if (actionmap) {
XrActionMapItem *ami = ptr->data;
WM_xr_actionmap_item_ensure_unique(actionmap, ami);
}
}
}
# else
@@ -437,50 +424,51 @@ static void rna_XrActionMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
# endif
}
static XrActionMap *rna_XrActionMap_new(PointerRNA *ptr, const char *name, bool replace_existing)
static XrActionMap *rna_XrActionMap_new(XrActionConfig *actionconf,
const char *name,
bool replace_existing)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
return WM_xr_actionmap_new(xr->runtime, name, replace_existing);
return WM_xr_actionmap_new(actionconf, name, replace_existing);
# else
UNUSED_VARS(ptr, name, replace_existing);
UNUSED_VARS(actionconf, name, replace_existing);
return NULL;
# endif
}
static XrActionMap *rna_XrActionMap_new_from_actionmap(PointerRNA *ptr, XrActionMap *am_src)
static XrActionMap *rna_XrActionMap_new_from_actionmap(XrActionConfig *actionconf,
XrActionMap *am_src)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
return WM_xr_actionmap_add_copy(xr->runtime, am_src);
return WM_xr_actionmap_add_copy(actionconf, am_src);
# else
UNUSED_VARS(ptr, am_src);
UNUSED_VARS(actionconf, am_src);
return NULL;
# endif
}
static void rna_XrActionMap_remove(ReportList *reports, PointerRNA *ptr, PointerRNA *actionmap_ptr)
static void rna_XrActionMap_remove(XrActionConfig *actionconf,
ReportList *reports,
PointerRNA *actionmap_ptr)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
XrActionMap *actionmap = actionmap_ptr->data;
if (WM_xr_actionmap_remove(xr->runtime, actionmap) == false) {
if (WM_xr_actionmap_remove(actionconf, actionmap) == false) {
BKE_reportf(reports, RPT_ERROR, "ActionMap '%s' cannot be removed", actionmap->name);
return;
}
RNA_POINTER_INVALIDATE(actionmap_ptr);
# else
UNUSED_VARS(ptr, reports, actionmap_ptr);
UNUSED_VARS(actionconf, reports, actionmap_ptr);
# endif
}
static XrActionMap *rna_XrActionMap_find(PointerRNA *ptr, const char *name)
static XrActionMap *rna_XrActionMap_find(XrActionConfig *actionconf, const char *name)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
return WM_xr_actionmap_find(xr->runtime, name);
return WM_xr_actionmap_find(actionconf, name);
# else
UNUSED_VARS(ptr, name);
UNUSED_VARS(actionconf, name);
return NULL;
# endif
}
@@ -489,17 +477,223 @@ static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), Point
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->xr.runtime) {
XrActionMap *actionmap = ptr->data;
WM_xr_actionmap_ensure_unique(wm->xr.runtime, actionmap);
if (wm) {
XrSessionSettings *settings = &wm->xr.session_settings;
XrActionConfig *actionconf = WM_xr_actionconfig_active_get(settings);
if (actionconf) {
XrActionMap *actionmap = ptr->data;
WM_xr_actionmap_ensure_unique(actionconf, actionmap);
}
}
# else
UNUSED_VARS(bmain, ptr);
# endif
}
static XrActionConfig *rna_XrActionConfig_new(XrSessionSettings *settings, const char *name)
{
# ifdef WITH_XR_OPENXR
return WM_xr_actionconfig_new(settings, name, true);
# else
UNUSED_VARS(settings, name);
return NULL;
# endif
}
static void rna_XrActionConfig_remove(XrSessionSettings *settings,
ReportList *reports,
PointerRNA *actionconf_ptr)
{
# ifdef WITH_XR_OPENXR
XrActionConfig *actionconf = actionconf_ptr->data;
if (WM_xr_actionconfig_remove(settings, actionconf) == false) {
BKE_reportf(reports, RPT_ERROR, "ActionConfig '%s' cannot be removed", actionconf->name);
return;
}
RNA_POINTER_INVALIDATE(actionconf_ptr);
# else
UNUSED_VARS(settings, reports, actionconf_ptr);
# endif
}
static void rna_XrActionConfig_update(XrSessionSettings *settings)
{
# ifdef WITH_XR_OPENXR
WM_xr_actionconfig_update(settings);
# else
UNUSED_VARS(settings);
# endif
}
static PointerRNA rna_XrSessionSettings_actionconfig_active_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrSessionSettings *settings = ptr->data;
XrActionConfig *ac = WM_xr_actionconfig_active_get(settings);
if (!ac) {
ac = settings->defaultconf;
}
return rna_pointer_inherit_refine(ptr, &RNA_XrActionConfig, ac);
# else
UNUSED_VARS(ptr);
return PointerRNA_NULL;
# endif
}
static void rna_XrSessionSettings_actionconfig_active_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
{
# ifdef WITH_XR_OPENXR
XrSessionSettings *settings = ptr->data;
XrActionConfig *ac = value.data;
if (ac) {
WM_xr_actionconfig_active_set(settings, ac->name);
}
# else
UNUSED_VARS(ptr, value);
# endif
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name XR Motion Capture
* \{ */
static XrMotionCaptureObject *rna_XrMotionCaptureObject_new(XrSessionSettings *settings,
PointerRNA *ob_ptr)
{
# ifdef WITH_XR_OPENXR
Object *ob = ob_ptr->data;
return WM_xr_mocap_object_new(settings, ob);
# else
UNUSED_VARS(settings, ob_ptr);
return NULL;
# endif
}
static void rna_XrMotionCaptureObject_remove(XrSessionSettings *settings, PointerRNA *mocap_ob_ptr)
{
# ifdef WITH_XR_OPENXR
XrMotionCaptureObject *mocap_ob = mocap_ob_ptr->data;
WM_xr_mocap_object_remove(settings, mocap_ob);
RNA_POINTER_INVALIDATE(mocap_ob_ptr);
# else
UNUSED_VARS(settings, mocap_ob_ptr);
# endif
}
static XrMotionCaptureObject *rna_XrMotionCaptureObject_find(XrSessionSettings *settings,
PointerRNA *ob_ptr)
{
# ifdef WITH_XR_OPENXR
Object *ob = ob_ptr->data;
return WM_xr_mocap_object_find(settings, ob);
# else
UNUSED_VARS(settings, ob_ptr);
return NULL;
# endif
}
static void rna_XrMotionCaptureObject_object_update(Main *bmain,
Scene *UNUSED(scene),
PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
if (wm) {
XrMotionCaptureObject *mocap_ob = ptr->data;
WM_xr_mocap_object_ensure_unique(&wm->xr.session_settings, mocap_ob);
}
# else
UNUSED_VARS(bmain, ptr);
# endif
}
static bool rna_XrMotionCaptureObject_enable_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
const XrMotionCaptureObject *mocap_ob = ptr->data;
return (mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0;
# else
UNUSED_VARS(ptr);
return false;
# endif
}
static void rna_XrMotionCaptureObject_enable_set(PointerRNA *ptr, bool value)
{
# ifdef WITH_XR_OPENXR
XrMotionCaptureObject *mocap_ob = ptr->data;
SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_ENABLE);
# else
UNUSED_VARS(ptr, value);
# endif
}
static void rna_XrMotionCaptureObject_enable_update(Main *bmain,
Scene *UNUSED(scene),
PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
if (wm) {
XrMotionCaptureObject *mocap_ob = ptr->data;
if ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) {
/* Store object's original pose. */
WM_xr_session_state_mocap_pose_set(&wm->xr, mocap_ob);
}
else {
/* Restore object's original pose. */
WM_xr_session_state_mocap_pose_get(&wm->xr, mocap_ob);
}
}
# else
UNUSED_VARS(bmain, ptr);
# endif
}
static bool rna_XrMotionCaptureObject_autokey_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
const XrMotionCaptureObject *mocap_ob = ptr->data;
return (mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0;
# else
UNUSED_VARS(ptr);
return false;
# endif
}
static void rna_XrMotionCaptureObject_autokey_set(PointerRNA *ptr, bool value)
{
# ifdef WITH_XR_OPENXR
XrMotionCaptureObject *mocap_ob = ptr->data;
SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_AUTOKEY);
# else
UNUSED_VARS(ptr, value);
# endif
}
/** \} */
/* -------------------------------------------------------------------- */
# ifdef WITH_XR_OPENXR
static wmXrData *rna_XrSession_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_XrSessionSettings) || (ptr->type == &RNA_XrSessionState));
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
return &wm->xr;
}
# endif
/* -------------------------------------------------------------------- */
/** \name XR Session Settings
* \{ */
@@ -892,54 +1086,66 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
# endif
}
static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
ListBase *lb = WM_xr_actionmaps_get(xr->runtime);
rna_iterator_listbase_begin(iter, lb, NULL);
# else
UNUSED_VARS(iter, ptr);
# endif
}
static int rna_XrSessionState_active_actionmap_get(PointerRNA *ptr)
static void rna_XrSessionState_nav_location_get(PointerRNA *ptr, float *r_values)
{
# ifdef WITH_XR_OPENXR
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
return WM_xr_actionmap_active_index_get(xr->runtime);
WM_xr_session_state_nav_location_get(xr, r_values);
# else
UNUSED_VARS(ptr);
return -1;
zero_v3(r_values);
# endif
}
static void rna_XrSessionState_active_actionmap_set(PointerRNA *ptr, int value)
static void rna_XrSessionState_nav_location_set(PointerRNA *ptr, const float *values)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_actionmap_active_index_set(xr->runtime, (short)value);
WM_xr_session_state_nav_location_set(xr, values);
# else
UNUSED_VARS(ptr, value);
UNUSED_VARS(ptr, values);
# endif
}
static int rna_XrSessionState_selected_actionmap_get(PointerRNA *ptr)
static void rna_XrSessionState_nav_rotation_get(PointerRNA *ptr, float *r_values)
{
# ifdef WITH_XR_OPENXR
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
return WM_xr_actionmap_selected_index_get(xr->runtime);
WM_xr_session_state_nav_rotation_get(xr, r_values);
# else
UNUSED_VARS(ptr);
return -1;
unit_qt(r_values);
# endif
}
static void rna_XrSessionState_selected_actionmap_set(PointerRNA *ptr, int value)
static void rna_XrSessionState_nav_rotation_set(PointerRNA *ptr, const float *values)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_actionmap_selected_index_set(xr->runtime, (short)value);
WM_xr_session_state_nav_rotation_set(xr, values);
# else
UNUSED_VARS(ptr, values);
# endif
}
static float rna_XrSessionState_nav_scale_get(PointerRNA *ptr)
{
float value;
# ifdef WITH_XR_OPENXR
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_session_state_nav_scale_get(xr, &value);
# else
UNUSED_VARS(ptr);
value = 1.0f;
# endif
return value;
}
static void rna_XrSessionState_nav_scale_set(PointerRNA *ptr, float value)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
WM_xr_session_state_nav_scale_set(xr, value);
# else
UNUSED_VARS(ptr, value);
# endif
@@ -1037,7 +1243,7 @@ static const EnumPropertyItem rna_enum_xr_axis1_flags[] = {
};
/* -------------------------------------------------------------------- */
/** \name XR Action Map
/** \name XR Action Configuration
* \{ */
static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1058,7 +1264,7 @@ static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
"replace_existing",
true,
"Replace Existing",
"Replace any existing binding with the same name");
"Replace any existing binding with same name");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
func, "binding", "XrActionMapBinding", "Binding", "Added action map binding");
@@ -1107,7 +1313,7 @@ static void rna_def_xr_actionmap_items(BlenderRNA *brna, PropertyRNA *cprop)
"replace_existing",
true,
"Replace Existing",
"Replace any existing item with the same name");
"Replace any existing item with same name");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "item", "XrActionMapItem", "Item", "Added action map item");
RNA_def_function_return(func, parm);
@@ -1140,27 +1346,22 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "XrActionMaps");
srna = RNA_def_struct(brna, "XrActionMaps", NULL);
RNA_def_struct_sdna(srna, "XrActionConfig");
RNA_def_struct_ui_text(srna, "XR Action Maps", "Collection of XR action maps");
func = RNA_def_function(srna, "new", "rna_XrActionMap_new");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func,
"replace_existing",
true,
"Replace Existing",
"Replace any existing actionmap with the same name");
"Replace any existing actionmap with same name");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Added action map");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_from_actionmap", "rna_XrActionMap_new_from_actionmap");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(
func, "actionmap", "XrActionMap", "Action Map", "Action map to use as a reference");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
@@ -1168,17 +1369,12 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrActionMap_remove");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Removed action map");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "find", "rna_XrActionMap_find");
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
@@ -1186,11 +1382,106 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
static void rna_def_xr_actionmap(BlenderRNA *brna)
static void rna_def_xr_actionconfigs(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *prop, *parm;
RNA_def_property_srna(cprop, "XrActionConfigurations");
srna = RNA_def_struct(brna, "XrActionConfigurations", NULL);
RNA_def_struct_sdna(srna, "XrSessionSettings");
RNA_def_struct_ui_text(
srna, "XR Action Configurations", "Collection of XR action configurations");
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionConfig");
RNA_def_property_pointer_funcs(prop,
"rna_XrSessionSettings_actionconfig_active_get",
"rna_XrSessionSettings_actionconfig_active_set",
NULL,
NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Active XR Action Configuration", "Active XR action configuration (preset)");
prop = RNA_def_property(srna, "default", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "defaultconf");
RNA_def_property_struct_type(prop, "XrActionConfig");
RNA_def_property_ui_text(
prop, "Default XR Action Configuration", "Default builtin XR action configuration");
prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
RNA_def_property_struct_type(prop, "XrActionConfig");
RNA_def_property_ui_text(prop,
"Add-on XR Action Configuration",
"XR action configuration that can be extended by add-ons");
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "userconf");
RNA_def_property_struct_type(prop, "XrActionConfig");
RNA_def_property_ui_text(prop,
"User XR Action Configuration",
"XR action configuration that can be extended by users");
func = RNA_def_function(srna, "new", "rna_XrActionConfig_new");
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func,
"actionconfig",
"XrActionConfig",
"Action Configuration",
"Added action configuration");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrActionConfig_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func,
"actionconfig",
"XrActionConfig",
"Action Configuration",
"Removed action configuration");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_function(srna, "update", "rna_XrActionConfig_update");
}
static void rna_def_xr_actionconfig(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
/* XrActionConfig */
srna = RNA_def_struct(brna, "XrActionConfig", NULL);
RNA_def_struct_sdna(srna, "XrActionConfig");
RNA_def_struct_ui_text(srna, "XR Action Configuration", "");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Name of the action configuration");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionMap");
RNA_def_property_ui_text(
prop, "Action Maps", "Action maps configured as part of this configuration");
rna_def_xr_actionmaps(brna, prop);
prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "actactionmap");
RNA_def_property_ui_text(prop, "Active Action Map", "");
prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "selactionmap");
RNA_def_property_ui_text(prop, "Selected Action Map", "");
prop = RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYCONF_USER);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "User Defined", "Indicates that an action configuration was defined by the user");
/* XrActionMap */
srna = RNA_def_struct(brna, "XrActionMap", NULL);
RNA_def_struct_sdna(srna, "XrActionMap");
@@ -1321,7 +1612,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
prop = RNA_def_property(srna, "bindings", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionMapBinding");
RNA_def_property_ui_text(
prop, "Bindings", "Bindings for the action map item, mapping the action to an XR input");
prop, "Bindings", "Bindings in the actionmap, linking an action to an XR input");
rna_def_xr_actionmap_bindings(brna, prop);
prop = RNA_def_property(srna, "selected_binding", PROP_INT, PROP_NONE);
@@ -1331,7 +1622,9 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
/* XrActionMapBinding */
srna = RNA_def_struct(brna, "XrActionMapBinding", NULL);
RNA_def_struct_sdna(srna, "XrActionMapBinding");
RNA_def_struct_ui_text(srna, "XR Action Map Binding", "Binding in an XR action map item");
RNA_def_struct_ui_text(srna,
"XR Action Map Binding",
"Bindings for the action map item, mapping the action to an XR input");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Name of the action map binding");
@@ -1353,7 +1646,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "float_threshold");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_text(prop, "Threshold", "Input threshold for button/axis actions");
RNA_def_property_ui_text(prop, "Input Threshold", "Input threshold for button/axis actions");
prop = RNA_def_property(srna, "axis0_region", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_xr_axis0_flags);
@@ -1374,10 +1667,101 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
prop, "Axis 1 Region", "Action execution region for the second input axis");
prop = RNA_def_property(srna, "pose_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_ui_text(prop, "Pose Location Offset", "");
RNA_def_property_ui_text(prop, "Pose Location Offset", "Pose location offset");
prop = RNA_def_property(srna, "pose_rotation", PROP_FLOAT, PROP_EULER);
RNA_def_property_ui_text(prop, "Pose Rotation Offset", "");
RNA_def_property_ui_text(prop, "Pose Rotation Offset", "Pose rotation offset");
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name XR Motion Capture
* \{ */
static void rna_def_xr_motioncapture_objects(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "XrMotionCaptureObjects");
srna = RNA_def_struct(brna, "XrMotionCaptureObjects", NULL);
RNA_def_struct_sdna(srna, "XrSessionSettings");
RNA_def_struct_ui_text(
srna, "XR Motion Capture Objects", "Collection of XR motion capture objects");
func = RNA_def_function(srna, "new", "rna_XrMotionCaptureObject_new");
parm = RNA_def_pointer(func,
"object",
"Object",
"Object",
"Blender object used to identify the motion capture object");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func,
"mocap_object",
"XrMotionCaptureObject",
"Motion Capture Object",
"Added motion capture object");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrMotionCaptureObject_remove");
parm = RNA_def_pointer(func,
"mocap_object",
"XrMotionCaptureObject",
"Motion Capture Object",
"Removed motion capture object");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "find", "rna_XrMotionCaptureObject_find");
parm = RNA_def_pointer(
func, "object", "Object", "Object", "Blender object identifying the motion capture object");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(func,
"mocap_object",
"XrMotionCaptureObject",
"Motion Capture Object",
"The motion capture object with the given name");
RNA_def_function_return(func, parm);
}
static void rna_def_xr_motioncapture_object(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "XrMotionCaptureObject", NULL);
RNA_def_struct_sdna(srna, "XrMotionCaptureObject");
RNA_def_struct_ui_text(srna, "XR Motion Capture Object", "");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "ob");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "Object to bind to a VR device");
RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_object_update");
prop = RNA_def_property(srna, "user_path", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 64);
RNA_def_property_ui_text(prop, "User Path", "OpenXR user path identifying the target VR device");
prop = RNA_def_property(srna, "location_offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_ui_text(prop, "Location Offset", "Location offset in device space");
prop = RNA_def_property(srna, "rotation_offset", PROP_FLOAT, PROP_EULER);
RNA_def_property_ui_text(prop, "Rotation Offset", "Rotation offset in device space");
prop = RNA_def_property(srna, "enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(
prop, "rna_XrMotionCaptureObject_enable_get", "rna_XrMotionCaptureObject_enable_set");
RNA_def_property_ui_text(prop, "Enable", "Bind object to target VR device");
RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_enable_update");
prop = RNA_def_property(srna, "autokey", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_XrMotionCaptureObject_autokey_get", "rna_XrMotionCaptureObject_autokey_set");
RNA_def_property_ui_text(prop, "Auto Key", "Auto-insert keyframes on animation playback");
}
/** \} */
@@ -1410,6 +1794,32 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem controller_draw_styles[] = {
{XR_CONTROLLER_DRAW_DARK, "DARK", 0, "Dark", "Draw dark controller"},
{XR_CONTROLLER_DRAW_LIGHT, "LIGHT", 0, "Light", "Draw light controller"},
{XR_CONTROLLER_DRAW_DARK_RAY,
"DARK_RAY",
0,
"Dark + Ray",
"Draw dark controller with aiming axis ray"},
{XR_CONTROLLER_DRAW_LIGHT_RAY,
"LIGHT_RAY",
0,
"Light + Ray",
"Draw light controller with aiming axis ray"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem selection_eyes[] = {
{XR_EYE_LEFT, "EYE_LEFT", 0, "Left Eye", "Use the left eye's perspective for VR selection"},
{XR_EYE_RIGHT,
"EYE_RIGHT",
0,
"Right Eye",
"Use the right eye's perspective for VR selection"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "XrSessionSettings", NULL);
RNA_def_struct_ui_text(srna, "XR Session Settings", "");
@@ -1450,6 +1860,13 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"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, "base_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Base Scale", "Uniform scale to apply to VR view");
RNA_def_property_range(prop, 0.001f, 1000.0f);
RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 1, 3);
RNA_def_property_float_default(prop, 1.0f);
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");
@@ -1460,6 +1877,36 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
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, "show_selection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_SHOW_SELECTION);
RNA_def_property_ui_text(prop, "Show Selection", "Show selection outlines");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "show_controllers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CONTROLLERS);
RNA_def_property_ui_text(
prop, "Show Controllers", "Show VR controllers (requires VR actions for controller poses)");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "show_custom_overlays", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_flags", V3D_OFSDRAW_XR_SHOW_CUSTOM_OVERLAYS);
RNA_def_property_ui_text(prop, "Show Custom Overlays", "Show custom VR overlays");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "controller_draw_style", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, controller_draw_styles);
RNA_def_property_ui_text(
prop, "Controller Draw Style", "Style to use when drawing VR controllers");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "selection_eye", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, selection_eyes);
RNA_def_property_ui_text(
prop, "Selection Eye", "Which eye's perspective to use when selecting in VR (GPU select)");
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);
@@ -1489,6 +1936,23 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Absolute Tracking", "Use unadjusted location/rotation as defined by the XR runtime");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
prop = RNA_def_property(srna, "actionconfigs", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionConfig");
RNA_def_property_ui_text(
prop, "XR Action Configurations", "Registered XR action configurations");
rna_def_xr_actionconfigs(brna, prop);
prop = RNA_def_property(srna, "mocap_objects", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrMotionCaptureObject");
RNA_def_property_ui_text(
prop, "XR Motion Capture Objects", "Objects to bind to headset/controller poses");
rna_def_xr_motioncapture_objects(brna, prop);
prop = RNA_def_property(srna, "selected_mocap_object", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sel_mocap_object");
RNA_def_property_ui_text(
prop, "Selected Motion Capture Object", "Currently selected motion capture object");
}
/** \} */
@@ -1793,33 +2257,30 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
"Viewer Pose Rotation",
"Last known rotation of the viewer pose (center between the eyes) in world space");
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop,
"rna_XrSessionState_actionmaps_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
NULL,
NULL,
NULL,
NULL);
RNA_def_property_struct_type(prop, "XrActionMap");
RNA_def_property_ui_text(prop, "XR Action Maps", "");
rna_def_xr_actionmaps(brna, prop);
prop = RNA_def_property(srna, "navigation_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(
prop, "rna_XrSessionState_nav_location_get", "rna_XrSessionState_nav_location_set", NULL);
RNA_def_property_ui_text(
prop,
"Navigation Location",
"Location offset to apply to base pose when determining viewer location");
prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop,
"rna_XrSessionState_active_actionmap_get",
"rna_XrSessionState_active_actionmap_set",
NULL);
RNA_def_property_ui_text(prop, "Active Action Map", "");
prop = RNA_def_property(srna, "navigation_rotation", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(
prop, "rna_XrSessionState_nav_rotation_get", "rna_XrSessionState_nav_rotation_set", NULL);
RNA_def_property_ui_text(
prop,
"Navigation Rotation",
"Rotation offset to apply to base pose when determining viewer rotation");
prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop,
"rna_XrSessionState_selected_actionmap_get",
"rna_XrSessionState_selected_actionmap_set",
NULL);
RNA_def_property_ui_text(prop, "Selected Action Map", "");
prop = RNA_def_property(srna, "navigation_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(
prop, "rna_XrSessionState_nav_scale_get", "rna_XrSessionState_nav_scale_set", NULL);
RNA_def_property_ui_text(prop,
"Navigation Scale",
"Scale multiplier to apply to base pose when determining viewer scale");
}
/** \} */
@@ -1828,7 +2289,8 @@ void RNA_def_xr(BlenderRNA *brna)
{
RNA_define_animate_sdna(false);
rna_def_xr_actionmap(brna);
rna_def_xr_actionconfig(brna);
rna_def_xr_motioncapture_object(brna);
rna_def_xr_session_settings(brna);
rna_def_xr_session_state(brna);

View File

@@ -195,6 +195,8 @@ if(WITH_XR_OPENXR)
list(APPEND INC
xr
# for wm_xr_operators.c: BKE_editmesh.h
../bmesh
)
list(APPEND SRC
@@ -202,6 +204,8 @@ if(WITH_XR_OPENXR)
xr/intern/wm_xr_action.c
xr/intern/wm_xr_actionmap.c
xr/intern/wm_xr_draw.c
xr/intern/wm_xr_mocap.c
xr/intern/wm_xr_operators.c
xr/intern/wm_xr_session.c
xr/wm_xr.h

View File

@@ -73,10 +73,6 @@ struct wmTabletData;
struct wmNDOFMotionData;
#endif
#ifdef WITH_XR_OPENXR
struct wmXrRuntimeData;
#endif
typedef struct wmGizmo wmGizmo;
typedef struct wmGizmoMap wmGizmoMap;
typedef struct wmGizmoMapType wmGizmoMapType;
@@ -664,7 +660,13 @@ void WM_paneltype_remove(struct PanelType *pt);
/* wm_gesture_ops.c */
int WM_gesture_box_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_gesture_box_invoke_3d(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
int WM_gesture_box_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_gesture_box_modal_3d(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
void WM_gesture_box_cancel(struct bContext *C, struct wmOperator *op);
int WM_gesture_circle_invoke(struct bContext *C,
struct wmOperator *op,
@@ -932,6 +934,22 @@ bool WM_event_is_tablet(const struct wmEvent *event);
int WM_event_absolute_delta_x(const struct wmEvent *event);
int WM_event_absolute_delta_y(const struct wmEvent *event);
void WM_event_xr_data(const struct wmEvent *event,
char **action_set,
char **action,
char *type,
float state[2],
float state_other[2],
float *float_threshold,
float controller_loc[3],
float controller_rot[4],
float controller_loc_other[3],
float controller_rot_other[4],
float *eye_lens,
float eye_viewmat[4][4],
bool *bimanual);
bool WM_event_is_xr(const struct wmEvent *event);
#ifdef WITH_INPUT_IME
bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
@@ -982,8 +1000,11 @@ void WM_xr_session_base_pose_reset(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,
bool from_selection_eye,
float r_viewmat[4][4],
float *r_focal_len);
float *r_focal_len,
float *r_clip_start,
float *r_clip_end);
bool WM_xr_session_state_controller_grip_location_get(const wmXrData *xr,
unsigned int subaction_idx,
float r_location[3]);
@@ -996,6 +1017,15 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr,
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
unsigned int subaction_idx,
float r_rotation[4]);
bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]);
void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]);
bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]);
void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4]);
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state);
struct ARegionType *WM_xr_surface_controller_region_type_get(void);
/* wm_xr_actions.c */
/* XR action functions to be called pre-XR session start.
@@ -1060,20 +1090,24 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
const char *subaction_path);
/* wm_xr_actionmap.c */
XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
void WM_xr_actionconfig_init(struct bContext *C);
void WM_xr_actionconfig_update_tag(XrActionMap *actionmap, XrActionMapItem *ami);
void WM_xr_actionconfig_update(XrSessionSettings *settings);
XrActionConfig *WM_xr_actionconfig_new(XrSessionSettings *settings,
const char *name,
bool user_defined);
bool WM_xr_actionconfig_remove(XrSessionSettings *settings, XrActionConfig *actionconf);
XrActionConfig *WM_xr_actionconfig_active_get(XrSessionSettings *settings);
void WM_xr_actionconfig_active_set(XrSessionSettings *settings, const char *name);
XrActionMap *WM_xr_actionmap_new(XrActionConfig *actionconf,
const char *name,
bool replace_existing);
void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_find(struct wmXrRuntimeData *runtime, const char *name);
void WM_xr_actionmap_clear(XrActionMap *actionmap);
void WM_xr_actionmaps_clear(struct wmXrRuntimeData *runtime);
ListBase *WM_xr_actionmaps_get(struct wmXrRuntimeData *runtime);
short WM_xr_actionmap_active_index_get(const struct wmXrRuntimeData *runtime);
void WM_xr_actionmap_active_index_set(struct wmXrRuntimeData *runtime, short idx);
short WM_xr_actionmap_selected_index_get(const struct wmXrRuntimeData *runtime);
void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short idx);
void WM_xr_actionmap_ensure_unique(XrActionConfig *actionconf, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_add_copy(XrActionConfig *actionconf, XrActionMap *am_src);
bool WM_xr_actionmap_remove(XrActionConfig *actionconf, XrActionMap *actionmap);
XrActionMap *WM_xr_actionmap_find(XrActionConfig *actionconf, const char *name);
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
const char *name,
@@ -1094,6 +1128,25 @@ bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *am
XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name);
#endif /* WITH_XR_OPENXR */
/* wm.c */
/* These need to be accessible even when WITH_XR_OPENXR is not defined since actionmaps can be
* stored in files. */
void WM_xr_actionconfig_free(XrActionConfig *actionconf);
void WM_xr_actionconfig_clear(XrActionConfig *actionconf);
void WM_xr_actionmap_clear(XrActionMap *actionmap);
void WM_xr_actionmap_item_properties_free(XrActionMapItem *ami);
void WM_xr_actionmap_item_bindings_clear(XrActionMapItem *ami);
/* wm_xr_mocap.c */
XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob);
void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings,
XrMotionCaptureObject *mocap_ob);
void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob);
XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings,
const Object *ob);
bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob);
void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob);
#ifdef __cplusplus
}
#endif

View File

@@ -109,17 +109,20 @@
#pragma once
struct ID;
struct IDProperty;
struct ImBuf;
struct bContext;
struct wmDrag;
struct wmDropBox;
struct wmEvent;
struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
#include "BLI_compiler_attrs.h"
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
#include "DNA_xr_types.h"
#include "RNA_types.h"
/* exported types for WM */
@@ -723,6 +726,41 @@ typedef struct wmXrActionState {
} wmXrActionState;
#endif
typedef struct wmXrActionData {
/** Action set name. */
char action_set[64];
/** Action name. */
char action[64];
/** Type. */
eXrActionType type;
/** State. Set appropriately based on type. */
float state[2];
/** State of the other subaction path for bimanual actions. */
float state_other[2];
/** Input threshold for float/vector2f actions. */
float float_threshold;
/** Controller aim pose corresponding to the action's subaction path. */
float controller_loc[3];
float controller_rot[4];
/** Controller aim pose of the other subaction path for bimanual actions. */
float controller_loc_other[3];
float controller_rot_other[4];
/** Lens (focal length) of the selection eye. */
float eye_lens;
/** Viewmat of the selection eye. */
float eye_viewmat[4][4];
/** Operator. */
struct wmOperatorType *ot;
struct IDProperty *op_properties;
/** Whether bimanual interaction is occuring. */
bool bimanual;
} wmXrActionData;
/** Timer flags. */
typedef enum {
/** Do not attempt to free customdata pointer even if non-NULL. */
@@ -796,6 +834,14 @@ typedef struct wmOperatorType {
struct wmOperator *,
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/**
* Same as invoke() but intended to be called from an XR session.
* The event type should be EVT_XR_ACTION and custom data type EVT_DATA_XR.
*/
int (*invoke_3d)(struct bContext *,
struct wmOperator *,
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/**
* Called when a modal operator is canceled (not used often).
* Internal cleanup can be done here if needed.
@@ -812,6 +858,14 @@ typedef struct wmOperatorType {
struct wmOperator *,
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/**
* Same as modal() but intended to be called from an XR session.
* The event type should be EVT_XR_ACTION and custom data type EVT_DATA_XR.
*/
int (*modal_3d)(struct bContext *,
struct wmOperator *,
const struct wmEvent *) ATTR_WARN_UNUSED_RESULT;
/**
* Verify if the operator can be executed in the current context, note
* that the operator might still fail to execute even if this return true.

View File

@@ -106,6 +106,32 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
{
BKE_screen_view3d_shading_blend_write(writer, &xr_data->session_settings.shading);
LISTBASE_FOREACH (XrActionConfig *, ac, &xr_data->session_settings.actionconfigs) {
BLO_write_struct(writer, XrActionConfig, ac);
/* Only write actionmaps for user configs. */
if ((ac->flag & XR_ACTIONCONF_USER) != 0) {
LISTBASE_FOREACH (XrActionMap *, am, &ac->actionmaps) {
BLO_write_struct(writer, XrActionMap, am);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
BLO_write_struct(writer, XrActionMapItem, ami);
if (ami->op[0] && ami->op_properties) {
IDP_BlendWrite(writer, ami->op_properties);
}
LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
BLO_write_struct(writer, XrActionMapBinding, amb);
}
}
}
}
}
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
BLO_write_struct(writer, XrMotionCaptureObject, mocap_ob);
}
}
static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -134,6 +160,39 @@ static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *
static void direct_link_wm_xr_data(BlendDataReader *reader, wmXrData *xr_data)
{
BKE_screen_view3d_shading_blend_read_data(reader, &xr_data->session_settings.shading);
BLO_read_list(reader, &xr_data->session_settings.actionconfigs);
LISTBASE_FOREACH (XrActionConfig *, ac, &xr_data->session_settings.actionconfigs) {
BLO_read_list(reader, &ac->actionmaps);
LISTBASE_FOREACH (XrActionMap *, am, &ac->actionmaps) {
BLO_read_list(reader, &am->items);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
if (ami->op[0] && ami->op_properties) {
BLO_read_data_address(reader, &ami->op_properties);
IDP_BlendDataRead(reader, &ami->op_properties);
ami->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
WM_operator_properties_create(ami->op_properties_ptr, ami->op);
ami->op_properties_ptr->data = ami->op_properties;
}
else {
ami->op_properties = NULL;
ami->op_properties_ptr = NULL;
}
BLO_read_list(reader, &ami->bindings);
}
}
}
BLO_read_data_address(reader, &xr_data->session_settings.defaultconf);
BLO_read_data_address(reader, &xr_data->session_settings.addonconf);
BLO_read_data_address(reader, &xr_data->session_settings.userconf);
BLO_read_list(reader, &xr_data->session_settings.mocap_objects);
}
static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
@@ -227,6 +286,10 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
static void lib_link_wm_xr_data(BlendLibReader *reader, ID *parent_id, wmXrData *xr_data)
{
BLO_read_id_address(reader, parent_id->lib, &xr_data->session_settings.base_pose_object);
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
BLO_read_id_address(reader, parent_id->lib, &mocap_ob->ob);
}
}
static void lib_link_workspace_instance_hook(BlendLibReader *reader,
@@ -433,6 +496,55 @@ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
}
}
void WM_xr_actionmap_item_bindings_clear(XrActionMapItem *ami)
{
BLI_freelistN(&ami->bindings);
ami->selbinding = 0;
}
void WM_xr_actionmap_item_properties_free(XrActionMapItem *ami)
{
if (ami->op_properties_ptr) {
WM_operator_properties_free(ami->op_properties_ptr);
MEM_freeN(ami->op_properties_ptr);
ami->op_properties_ptr = NULL;
ami->op_properties = NULL;
}
else {
BLI_assert(ami->op_properties == NULL);
}
}
void WM_xr_actionmap_clear(XrActionMap *actionmap)
{
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
WM_xr_actionmap_item_bindings_clear(ami);
WM_xr_actionmap_item_properties_free(ami);
}
BLI_freelistN(&actionmap->items);
actionmap->selitem = 0;
}
void WM_xr_actionconfig_clear(XrActionConfig *actionconf)
{
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
WM_xr_actionmap_clear(am);
}
BLI_freelistN(&actionconf->actionmaps);
actionconf->selactionmap = actionconf->actactionmap = 0;
}
void WM_xr_actionconfig_free(XrActionConfig *actionconf)
{
WM_xr_actionconfig_clear(actionconf);
MEM_freeN(actionconf);
}
/* ****************************************** */
void WM_keyconfig_reload(bContext *C)
@@ -507,6 +619,9 @@ void WM_check(bContext *C)
/* Case: fileread. */
if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
WM_keyconfig_init(C);
#ifdef WITH_XR_OPENXR
WM_xr_actionconfig_init(C);
#endif
WM_autosave_init(wm);
}
@@ -595,6 +710,13 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
WM_keyconfig_free(keyconf);
}
XrActionConfig *actionconf;
while ((actionconf = BLI_pophead(&wm->xr.session_settings.actionconfigs))) {
WM_xr_actionconfig_free(actionconf);
}
BLI_freelistN(&wm->xr.session_settings.mocap_objects);
BLI_freelistN(&wm->notifier_queue);
if (wm->message_bus != NULL) {

View File

@@ -485,6 +485,75 @@ int WM_event_absolute_delta_y(const struct wmEvent *event)
/** \} */
/* -------------------------------------------------------------------- */
/** \name XR Input Access
* \{ */
void WM_event_xr_data(const wmEvent *event,
char **action_set,
char **action,
char *type,
float state[2],
float state_other[2],
float *float_threshold,
float controller_loc[3],
float controller_rot[4],
float controller_loc_other[3],
float controller_rot_other[4],
float *eye_lens,
float eye_viewmat[4][4],
bool *bimanual)
{
const wmXrActionData *data = event->customdata;
if (action_set) {
strcpy(*action_set, data->action_set);
}
if (action) {
strcpy(*action, data->action);
}
if (type) {
*type = data->type;
}
if (state) {
copy_v2_v2(state, data->state);
}
if (state_other) {
copy_v2_v2(state_other, data->state_other);
}
if (float_threshold) {
*float_threshold = data->float_threshold;
}
if (controller_loc) {
copy_v3_v3(controller_loc, data->controller_loc);
}
if (controller_rot) {
copy_v4_v4(controller_rot, data->controller_rot);
}
if (controller_loc_other) {
copy_v3_v3(controller_loc_other, data->controller_loc_other);
}
if (controller_rot_other) {
copy_v4_v4(controller_rot_other, data->controller_rot_other);
}
if (eye_lens) {
*eye_lens = data->eye_lens;
}
if (eye_viewmat) {
copy_m4_m4(eye_viewmat, data->eye_viewmat);
}
if (bimanual) {
*bimanual = data->bimanual;
}
}
bool WM_event_is_xr(const struct wmEvent *event)
{
return (event->custom == EVT_DATA_XR);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Event IME Input Access
* \{ */

View File

@@ -83,6 +83,7 @@
#include "wm.h"
#include "wm_event_system.h"
#include "wm_event_types.h"
#include "wm_surface.h"
#include "wm_window.h"
#include "DEG_depsgraph.h"
@@ -1341,7 +1342,19 @@ static int wm_operator_invoke(bContext *C,
ot->idname);
}
if (op->type->invoke && event) {
if (op->type->invoke_3d && event && (event->type == EVT_XR_ACTION)) {
if (op->type->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
}
retval = op->type->invoke_3d(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
}
}
else if (op->type->invoke && event) {
wm_region_mouse_co(C, event);
if (op->type->flag & OPTYPE_UNDO) {
@@ -2227,7 +2240,7 @@ static int wm_handler_operator_call(bContext *C,
* nothing to do in this case.
*/
}
else if (ot->modal) {
else if (ot->modal || ot->modal_3d) {
/* We set context to where modal handler came from. */
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -2245,7 +2258,15 @@ static int wm_handler_operator_call(bContext *C,
}
/* Warning, after this call all context data and 'event' may be freed. see check below. */
retval = ot->modal(C, op, event);
if (ot->modal_3d && event->type == EVT_XR_ACTION) {
retval = ot->modal_3d(C, op, event);
}
else if (ot->modal) {
retval = ot->modal(C, op, event);
}
else {
/* Pass through. An "XR operator" (only modal_3d) received a non-XR event.*/
}
OPERATOR_RETVAL_CHECK(retval);
if (ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
@@ -3434,6 +3455,71 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
* Handle events for all windows, run from the #WM_main event loop.
* \{ */
#ifdef WITH_XR_OPENXR
static void wm_event_handle_xrevent(
bContext *C, wmWindowManager *wm, wmWindow *win, bScreen *screen, wmEvent *event)
{
int action = 0;
/* Find a valid region for XR operator execution and modal handling. */
ED_screen_areas_iter (win, screen, area) {
CTX_wm_area_set(C, area);
if (!CTX_wm_view3d(C)) {
continue;
}
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (!WM_region_use_viewport(area, region)) {
continue;
}
CTX_wm_region_set(C, region);
action |= wm_handlers_do(C, event, &win->modalhandlers);
if ((action & WM_HANDLER_BREAK) == 0) {
wmXrActionData *actiondata = event->customdata;
if ((actiondata->ot->modal || actiondata->ot->modal_3d) && event->val == KM_RELEASE) {
/* Don't execute modal operators on release. */
}
else {
PointerRNA properties = {.type = actiondata->ot->srna,
.data = actiondata->op_properties};
if (actiondata->ot->invoke || actiondata->ot->invoke_3d) {
/* Invoke operator, either executing operator or transferring responsibility to window
* modal handlers. */
wm_operator_invoke(C,
actiondata->ot,
event,
actiondata->op_properties ? &properties : NULL,
NULL,
false,
false);
}
else {
/* Execute operator. */
wmOperator *op = wm_operator_create(
wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
WM_operator_free(op);
}
}
}
action |= WM_HANDLER_BREAK;
}
CTX_wm_region_set(C, NULL);
break;
}
if (action & WM_HANDLER_BREAK) {
break;
}
}
CTX_wm_area_set(C, NULL);
}
#endif /* WITH_XR_OPENXR */
/* Called in main loop. */
/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */
void wm_event_do_handlers(bContext *C)
@@ -3531,6 +3617,16 @@ void wm_event_do_handlers(bContext *C)
CTX_wm_window_set(C, win);
#ifdef WITH_XR_OPENXR
if (event->type == EVT_XR_ACTION) {
wm_event_handle_xrevent(C, wm, win, screen, event);
BLI_remlink(&win->event_queue, event);
wm_event_free(event);
/* Skip mouse event handling below, which is unnecessary for XR events. */
continue;
}
#endif
/* Clear tool-tip on mouse move. */
if (screen->tool_tip && screen->tool_tip->exit_on_event) {
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
@@ -5083,6 +5179,24 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#endif
}
#ifdef WITH_XR_OPENXR
void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
{
BLI_assert(val == KM_PRESS || val == KM_RELEASE);
wmEvent event = {
.type = EVT_XR_ACTION,
.val = val,
.is_repeat = false,
.custom = EVT_DATA_XR,
.customdata = actiondata,
.customdatafree = 1,
};
wm_event_add(win, &event);
}
#endif /* WITH_XR_OPENXR */
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -204,6 +204,18 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
WM_event_remove_handlers(C, &win->modalhandlers);
ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
/* Free XR actionconfigs and motion capture objects. */
XrSessionSettings *xrsettings = &wm->xr.session_settings;
XrActionConfig *actionconf;
while ((actionconf = BLI_pophead(&xrsettings->actionconfigs))) {
WM_xr_actionconfig_free(actionconf);
}
xrsettings->defaultconf = NULL;
xrsettings->addonconf = NULL;
xrsettings->userconf = NULL;
BLI_freelistN(&xrsettings->mocap_objects);
}
/* reset active window */

View File

@@ -36,6 +36,8 @@
#include "BKE_context.h"
#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -45,6 +47,9 @@
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "../editors/space_view3d/view3d_intern.h"
#include "UI_interface.h"
@@ -202,6 +207,60 @@ int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
int WM_gesture_box_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
{
BLI_assert(event->type == EVT_XR_ACTION);
BLI_assert(event->custom == EVT_DATA_XR);
BLI_assert(event->customdata);
const wmXrActionData *actiondata = event->customdata;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
float lens_prev;
float clip_start_prev, clip_end_prev;
int mval[2];
int retval;
wmEvent event_mut;
memcpy(&event_mut, event, sizeof(wmEvent));
/* Replace window view parameters with XR surface counterparts. */
ED_view3d_view_params_get(v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, NULL);
ED_view3d_view_params_set(depsgraph,
scene,
v3d,
region,
actiondata->eye_lens,
xr->session_settings.clip_start,
xr->session_settings.clip_end,
NULL);
map_to_pixel(mval,
actiondata->controller_loc,
actiondata->eye_viewmat,
rv3d->winmat,
region->winx,
region->winy);
event_mut.x = region->winrct.xmin + mval[0];
event_mut.y = region->winrct.ymin + mval[1];
RNA_boolean_set(op->ptr, "wait_for_input", false);
retval = WM_gesture_box_invoke(C, op, &event_mut);
/* Restore window view. */
ED_view3d_view_params_set(
depsgraph, scene, v3d, region, lens_prev, clip_start_prev, clip_end_prev, NULL);
return retval;
}
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
@@ -280,6 +339,85 @@ int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
int WM_gesture_box_modal_3d(bContext *C, wmOperator *op, const wmEvent *event)
{
BLI_assert(event->type == EVT_XR_ACTION);
BLI_assert(event->custom == EVT_DATA_XR);
BLI_assert(event->customdata);
const bool release = (event->val == KM_RELEASE);
const wmXrActionData *actiondata = event->customdata;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
float lens_prev;
float clip_start_prev, clip_end_prev;
float viewmat_prev[4][4];
int mval[2];
int retval;
wmEvent event_mut;
memcpy(&event_mut, event, sizeof(wmEvent));
/* Since this function is called in a window context, we need to replace the
* window view parameters with the XR surface counterparts to get a correct
* result for some operators (e.g. GPU select). */
ED_view3d_view_params_get(
v3d, rv3d, &lens_prev, &clip_start_prev, &clip_end_prev, release ? viewmat_prev : NULL);
ED_view3d_view_params_set(depsgraph,
scene,
v3d,
region,
actiondata->eye_lens,
xr->session_settings.clip_start,
xr->session_settings.clip_end,
release ? actiondata->eye_viewmat : NULL);
map_to_pixel(mval,
actiondata->controller_loc,
actiondata->eye_viewmat,
rv3d->winmat,
region->winx,
region->winy);
if (event->val == KM_PRESS) {
event_mut.type = MOUSEMOVE;
{
wmGesture *gesture = op->customdata;
gesture->is_active = true;
}
event_mut.x = region->winrct.xmin + mval[0];
event_mut.y = region->winrct.ymin + mval[1];
}
else if (event->val == KM_RELEASE) {
event_mut.type = EVT_MODAL_MAP;
event_mut.val = GESTURE_MODAL_SELECT;
}
else {
/* XR events currently only support press and release. */
BLI_assert(false);
}
retval = WM_gesture_box_modal(C, op, &event_mut);
/* Restore window view. */
ED_view3d_view_params_set(depsgraph,
scene,
v3d,
region,
lens_prev,
clip_start_prev,
clip_end_prev,
release ? viewmat_prev : NULL);
return retval;
}
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
{
gesture_modal_end(C, op);

View File

@@ -3760,87 +3760,6 @@ 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) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
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) {
wmWindowManager *wm = bmain->wm.first;
const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
ED_view3d_xr_shading_update(wm, v3d, scene);
}
/* Ensure no 3D View is tagged as session root. */
else {
v3d->runtime.flag &= ~V3D_RUNTIME_XR_SESSION_ROOT;
}
}
}
}
}
WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
}
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);
wmWindow *win = CTX_wm_window(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, win, 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
* \{ */
@@ -3882,9 +3801,6 @@ 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
@@ -3895,6 +3811,10 @@ void wm_operatortypes_register(void)
/* gizmos */
WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
#ifdef WITH_XR_OPENXR
wm_xr_operatortypes_register();
#endif
}
/* circleselect-like modal operators */

View File

@@ -1561,7 +1561,7 @@ void wm_window_process_events(const bContext *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. */
has_event |= wm_xr_events_handle(CTX_wm_manager(C));
has_event |= wm_xr_events_handle(C);
#endif
/* When there is no event, sleep 5 milliseconds not to use too much CPU when idle.

View File

@@ -33,6 +33,10 @@ struct ARegion;
struct GHOST_TabletData;
struct ScrArea;
#ifdef WITH_XR_OPENXR
struct wmXrActionData;
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -147,6 +151,9 @@ void wm_event_free_handler(wmEventHandler *handler);
void wm_event_do_handlers(bContext *C);
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata);
#ifdef WITH_XR_OPENXR
void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val);
#endif
void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);

View File

@@ -34,6 +34,7 @@ enum {
EVT_DATA_TIMER = 2,
EVT_DATA_DRAGDROP = 3,
EVT_DATA_NDOF_MOTION = 4,
EVT_DATA_XR = 5,
};
/* tablet active, matches GHOST_TTabletMode */
@@ -341,6 +342,10 @@ enum {
/* could become gizmo callback */
EVT_GIZMO_UPDATE = 0x5025, /* 20517 */
/* XR events: 0x503x */
EVT_XR_ACTION = 0x5030, /* 20528 */
/* ********** End of Blender internal events. ********** */
};

View File

@@ -22,6 +22,7 @@
* representation of the OpenXR runtime connection within the application.
*/
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_report.h"
@@ -54,6 +55,7 @@ static void wm_xr_error_handler(const GHOST_XrError *error)
wmWindowManager *wm = handler_data->wm;
BKE_reports_clear(&wm->reports);
WM_report(RPT_ERROR, error->user_message);
WM_report_banner_show();
@@ -130,14 +132,16 @@ void wm_xr_exit(wmWindowManager *wm)
}
}
bool wm_xr_events_handle(wmWindowManager *wm)
bool wm_xr_events_handle(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
if (wm->xr.runtime && wm->xr.runtime->context) {
GHOST_XrEventsHandle(wm->xr.runtime->context);
/* Process OpenXR action events. */
/* Process OpenXR action events and dispatch to XR surface / window queues. */
if (WM_xr_session_is_ready(&wm->xr)) {
wm_xr_session_actions_update(&wm->xr);
wm_xr_session_actions_update(C);
}
/* wm_window_process_events() uses the return value to determine if it can put the main thread
@@ -173,7 +177,6 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
(*runtime)->context = NULL;
wm_xr_session_data_free(&(*runtime)->session_state);
WM_xr_actionmaps_clear(*runtime);
GHOST_XrContextDestroy(context);
}

View File

@@ -26,24 +26,67 @@
#include <string.h>
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "GHOST_Types.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm_xr_intern.h"
#define WM_XR_ACTIONCONF_STR_DEFAULT "blender"
#define WM_XR_ACTIONMAP_STR_DEFAULT "actionmap"
#define WM_XR_ACTIONMAP_ITEM_STR_DEFAULT "action"
#define WM_XR_ACTIONMAP_BINDING_STR_DEFAULT "binding"
/* Replacement for U.keyconfigstr for actionconfigs. */
static char g_xr_actionconfigstr[64];
/* Actionconfig update flag. */
enum {
WM_XR_ACTIONCONF_UPDATE_ACTIVE = (1 << 0), /* Update active actionconfig. */
WM_XR_ACTIONCONF_UPDATE_ALL = (1 << 1), /* Update all actionconfigs. */
WM_XR_ACTIONCONF_UPDATE_ENSURE =
(1 << 2), /* Skip actionmap/item flag checks when updating actionconfigs. */
};
static char g_xr_actionconfig_update_flag = 0;
/* -------------------------------------------------------------------- */
void WM_xr_actionconfig_update_tag(XrActionMap *actionmap, XrActionMapItem *ami)
{
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ACTIVE;
if (actionmap) {
actionmap->flag |= XR_ACTIONMAP_UPDATE;
}
if (ami) {
ami->flag |= XR_ACTIONMAP_ITEM_UPDATE;
}
}
#if 0 /* Currently unused. */
static void wm_xr_actionconfig_update_active(XrActionMap *actionmap, XrActionMapItem *ami, bool ensure)
{
WM_xr_actionconfig_update_tag(actionmap, ami);
if (ensure) {
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ENSURE;
}
}
static void wm_xr_actionconfig_update_all(bool ensure)
{
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ALL;
if (ensure) {
g_xr_actionconfig_update_flag |= WM_XR_ACTIONCONF_UPDATE_ENSURE;
}
}
#endif
/* -------------------------------------------------------------------- */
/** \name Action Map Binding
*
@@ -51,16 +94,16 @@
* \{ */
XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
const char *name,
const char *idname,
bool replace_existing)
{
XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, name);
XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, idname);
if (amb_prev && replace_existing) {
return amb_prev;
}
XrActionMapBinding *amb = MEM_callocN(sizeof(XrActionMapBinding), __func__);
BLI_strncpy(amb->name, name, MAX_NAME);
BLI_strncpy(amb->name, idname, MAX_NAME);
if (amb_prev) {
WM_xr_actionmap_binding_ensure_unique(ami, amb);
}
@@ -173,31 +216,12 @@ XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const cha
* Item in an XR action map, that maps an XR event to an operator, pose, or haptic output.
* \{ */
static void wm_xr_actionmap_item_bindings_clear(XrActionMapItem *ami)
{
BLI_freelistN(&ami->bindings);
ami->selbinding = 0;
}
static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami)
{
WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op);
WM_operator_properties_sanitize(ami->op_properties_ptr, 1);
}
static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
{
if (ami->op_properties_ptr) {
WM_operator_properties_free(ami->op_properties_ptr);
MEM_freeN(ami->op_properties_ptr);
ami->op_properties_ptr = NULL;
ami->op_properties = NULL;
}
else {
BLI_assert(ami->op_properties == NULL);
}
}
/**
* Similar to #wm_xr_actionmap_item_properties_set()
* but checks for the #eXrActionType and #wmOperatorType having changed.
@@ -211,13 +235,13 @@ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
break;
case XR_POSE_INPUT:
case XR_VIBRATION_OUTPUT:
wm_xr_actionmap_item_properties_free(ami);
WM_xr_actionmap_item_properties_free(ami);
memset(ami->op, 0, sizeof(ami->op));
return;
}
if (ami->op[0] == 0) {
wm_xr_actionmap_item_properties_free(ami);
WM_xr_actionmap_item_properties_free(ami);
return;
}
@@ -237,7 +261,33 @@ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
}
}
else {
wm_xr_actionmap_item_properties_free(ami);
WM_xr_actionmap_item_properties_free(ami);
}
}
}
static void wm_xr_actionmap_item_properties_update_ot_from_list(ListBase *am_lb, bool ensure)
{
if (ensure) {
LISTBASE_FOREACH (XrActionMap *, am, am_lb) {
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
WM_xr_actionmap_item_properties_update_ot(ami);
ami->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
}
am->flag &= ~XR_ACTIONMAP_UPDATE;
}
}
else {
LISTBASE_FOREACH (XrActionMap *, am, am_lb) {
if ((am->flag & XR_ACTIONMAP_UPDATE) != 0) {
LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
if ((ami->flag & XR_ACTIONMAP_ITEM_UPDATE) != 0) {
WM_xr_actionmap_item_properties_update_ot(ami);
ami->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
}
}
am->flag &= ~XR_ACTIONMAP_UPDATE;
}
}
}
}
@@ -248,7 +298,7 @@ XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
{
XrActionMapItem *ami_prev = WM_xr_actionmap_item_find(actionmap, name);
if (ami_prev && replace_existing) {
wm_xr_actionmap_item_properties_free(ami_prev);
WM_xr_actionmap_item_properties_free(ami_prev);
return ami_prev;
}
@@ -263,12 +313,14 @@ XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
/* Set type to float (button) input by default. */
ami->type = XR_FLOAT_INPUT;
WM_xr_actionconfig_update_tag(actionmap, ami);
return ami;
}
static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
const char *name,
const XrActionMapItem *amiexcept)
XrActionMapItem *amiexcept)
{
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
if (STREQLEN(name, ami->name, MAX_NAME) && (ami != amiexcept)) {
@@ -308,25 +360,32 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem
BLI_strncpy(ami->name, name, MAX_NAME);
}
static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
{
XrActionMapItem *amin = MEM_dupallocN(ami);
XrActionMapItem *ami_dst = MEM_dupallocN(ami_src);
amin->prev = amin->next = NULL;
ami_dst->prev = ami_dst->next = NULL;
BLI_listbase_clear(&ami_dst->bindings);
ami_dst->flag &= ~XR_ACTIONMAP_ITEM_UPDATE;
if (amin->op_properties) {
amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
WM_operator_properties_create(amin->op_properties_ptr, amin->op);
LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) {
XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb);
BLI_addtail(&ami_dst->bindings, amb_new);
}
amin->op_properties = IDP_CopyProperty(amin->op_properties);
amin->op_properties_ptr->data = amin->op_properties;
if (ami_dst->op_properties) {
ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
ami_dst->op_properties = IDP_CopyProperty(ami_dst->op_properties);
ami_dst->op_properties_ptr->data = ami_dst->op_properties;
}
else {
amin->op_properties = NULL;
amin->op_properties_ptr = NULL;
ami_dst->op_properties = NULL;
ami_dst->op_properties_ptr = NULL;
}
return amin;
return ami_dst;
}
XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
@@ -337,6 +396,8 @@ XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionM
BLI_addtail(&actionmap->items, ami_dst);
WM_xr_actionconfig_update_tag(actionmap, ami_dst);
return ami_dst;
}
@@ -345,8 +406,8 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
int idx = BLI_findindex(&actionmap->items, ami);
if (idx != -1) {
wm_xr_actionmap_item_bindings_clear(ami);
wm_xr_actionmap_item_properties_free(ami);
WM_xr_actionmap_item_bindings_clear(ami);
WM_xr_actionmap_item_properties_free(ami);
BLI_freelinkN(&actionmap->items, ami);
if (idx <= actionmap->selitem) {
@@ -355,6 +416,8 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
}
}
WM_xr_actionconfig_update_tag(actionmap, NULL);
return true;
}
@@ -379,9 +442,11 @@ XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *n
* List of XR action map items.
* \{ */
XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, bool replace_existing)
XrActionMap *WM_xr_actionmap_new(XrActionConfig *actionconf,
const char *name,
bool replace_existing)
{
XrActionMap *am_prev = WM_xr_actionmap_find(runtime, name);
XrActionMap *am_prev = WM_xr_actionmap_find(actionconf, name);
if (am_prev && replace_existing) {
WM_xr_actionmap_clear(am_prev);
return am_prev;
@@ -390,31 +455,32 @@ XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, boo
XrActionMap *am = MEM_callocN(sizeof(struct XrActionMap), __func__);
BLI_strncpy(am->name, name, MAX_NAME);
if (am_prev) {
WM_xr_actionmap_ensure_unique(runtime, am);
WM_xr_actionmap_ensure_unique(actionconf, am);
}
BLI_addtail(&runtime->actionmaps, am);
BLI_addtail(&actionconf->actionmaps, am);
WM_xr_actionconfig_update_tag(am, NULL);
return am;
}
static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
static XrActionMap *wm_xr_actionmap_find_except(XrActionConfig *actionconf,
const char *name,
const XrActionMap *am_except)
XrActionMap *am_except)
{
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
if (STREQLEN(name, am->name, MAX_NAME) && (am != am_except)) {
return am;
}
}
return NULL;
}
/**
* Ensure unique name among all action maps.
*/
void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
void WM_xr_actionmap_ensure_unique(XrActionConfig *actionconf, XrActionMap *actionmap)
{
char name[MAX_NAME];
char *suffix;
@@ -425,7 +491,7 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
baselen = BLI_strnlen(name, MAX_NAME);
suffix = &name[baselen];
while (wm_xr_actionmap_find_except(runtime, name, actionmap)) {
while (wm_xr_actionmap_find_except(actionconf, name, actionmap)) {
if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
/* Use default base name. */
BLI_strncpy(name, WM_XR_ACTIONMAP_STR_DEFAULT, MAX_NAME);
@@ -447,6 +513,7 @@ static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
am_dst->prev = am_dst->next = NULL;
BLI_listbase_clear(&am_dst->items);
am_dst->flag &= ~(XR_ACTIONMAP_UPDATE);
LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
@@ -456,33 +523,35 @@ static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
return am_dst;
}
XrActionMap *WM_xr_actionmap_add_copy(wmXrRuntimeData *runtime, XrActionMap *am_src)
XrActionMap *WM_xr_actionmap_add_copy(XrActionConfig *actionconf, XrActionMap *am_src)
{
XrActionMap *am_dst = wm_xr_actionmap_copy(am_src);
WM_xr_actionmap_ensure_unique(runtime, am_dst);
WM_xr_actionmap_ensure_unique(actionconf, am_dst);
BLI_addtail(&runtime->actionmaps, am_dst);
BLI_addtail(&actionconf->actionmaps, am_dst);
WM_xr_actionconfig_update_tag(am_dst, NULL);
return am_dst;
}
bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
bool WM_xr_actionmap_remove(XrActionConfig *actionconf, XrActionMap *actionmap)
{
int idx = BLI_findindex(&runtime->actionmaps, actionmap);
int idx = BLI_findindex(&actionconf->actionmaps, actionmap);
if (idx != -1) {
WM_xr_actionmap_clear(actionmap);
BLI_freelinkN(&runtime->actionmaps, actionmap);
BLI_freelinkN(&actionconf->actionmaps, actionmap);
if (idx <= runtime->actactionmap) {
if (--runtime->actactionmap < 0) {
runtime->actactionmap = 0;
if (idx <= actionconf->actactionmap) {
if (--actionconf->actactionmap < 0) {
actionconf->actactionmap = 0;
}
}
if (idx <= runtime->selactionmap) {
if (--runtime->selactionmap < 0) {
runtime->selactionmap = 0;
if (idx <= actionconf->selactionmap) {
if (--actionconf->selactionmap < 0) {
actionconf->selactionmap = 0;
}
}
@@ -492,9 +561,9 @@ bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
return false;
}
XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
XrActionMap *WM_xr_actionmap_find(XrActionConfig *actionconf, const char *name)
{
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
LISTBASE_FOREACH (XrActionMap *, am, &actionconf->actionmaps) {
if (STREQLEN(name, am->name, MAX_NAME)) {
return am;
}
@@ -502,52 +571,147 @@ XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
return NULL;
}
void WM_xr_actionmap_clear(XrActionMap *actionmap)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Action Configuration
*
* List of XR action maps.
* \{ */
XrActionConfig *WM_xr_actionconfig_new(XrSessionSettings *settings,
const char *name,
bool user_defined)
{
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
wm_xr_actionmap_item_bindings_clear(ami);
wm_xr_actionmap_item_properties_free(ami);
XrActionConfig *actionconf = BLI_findstring(
&settings->actionconfigs, name, offsetof(XrActionConfig, name));
if (actionconf) {
WM_xr_actionconfig_clear(actionconf);
return actionconf;
}
BLI_freelistN(&actionmap->items);
actionconf = MEM_callocN(sizeof(XrActionConfig), __func__);
BLI_strncpy(actionconf->name, name, sizeof(actionconf->name));
BLI_addtail(&settings->actionconfigs, actionconf);
actionmap->selitem = 0;
}
void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
{
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
WM_xr_actionmap_clear(am);
if (user_defined) {
actionconf->flag |= XR_ACTIONCONF_USER;
}
BLI_freelistN(&runtime->actionmaps);
runtime->actactionmap = runtime->selactionmap = 0;
return actionconf;
}
ListBase *WM_xr_actionmaps_get(wmXrRuntimeData *runtime)
bool WM_xr_actionconfig_remove(XrSessionSettings *settings, XrActionConfig *actionconf)
{
return &runtime->actionmaps;
if (BLI_findindex(&settings->actionconfigs, actionconf) != -1) {
if (STREQLEN(g_xr_actionconfigstr, actionconf->name, sizeof(g_xr_actionconfigstr))) {
BLI_strncpy(g_xr_actionconfigstr, settings->defaultconf->name, sizeof(g_xr_actionconfigstr));
WM_xr_actionconfig_update_tag(NULL, NULL);
}
BLI_remlink(&settings->actionconfigs, actionconf);
WM_xr_actionconfig_free(actionconf);
return true;
}
return false;
}
short WM_xr_actionmap_active_index_get(const wmXrRuntimeData *runtime)
XrActionConfig *WM_xr_actionconfig_active_get(XrSessionSettings *settings)
{
return runtime->actactionmap;
XrActionConfig *actionconf;
/* First try from preset. */
actionconf = BLI_findstring(
&settings->actionconfigs, g_xr_actionconfigstr, offsetof(XrActionConfig, name));
if (actionconf) {
return actionconf;
}
/* Otherwise use default. */
return settings->defaultconf;
}
void WM_xr_actionmap_active_index_set(wmXrRuntimeData *runtime, short idx)
void WM_xr_actionconfig_active_set(XrSessionSettings *settings, const char *idname)
{
runtime->actactionmap = idx;
}
/* Setting a different action configuration as active: we ensure all is
* updated properly before and after making the change. */
short WM_xr_actionmap_selected_index_get(const wmXrRuntimeData *runtime)
{
return runtime->selactionmap;
}
WM_xr_actionconfig_update(settings);
void WM_xr_actionmap_selected_index_set(wmXrRuntimeData *runtime, short idx)
{
runtime->selactionmap = idx;
BLI_strncpy(g_xr_actionconfigstr, idname, sizeof(g_xr_actionconfigstr));
WM_xr_actionconfig_update_tag(NULL, NULL);
WM_xr_actionconfig_update(settings);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name XR Action Configuration API
*
* API functions for managing XR action configurations.
*
* \{ */
void WM_xr_actionconfig_init(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
XrSessionSettings *settings = &wm->xr.session_settings;
/* Create standard action configs. */
if (settings->defaultconf == NULL) {
settings->defaultconf = WM_xr_actionconfig_new(settings, WM_XR_ACTIONCONF_STR_DEFAULT, false);
}
if (settings->addonconf == NULL) {
settings->addonconf = WM_xr_actionconfig_new(
settings, WM_XR_ACTIONCONF_STR_DEFAULT " addon", false);
}
if (settings->userconf == NULL) {
/* Treat user config as user-defined so its actionmaps can be saved to files. */
settings->userconf = WM_xr_actionconfig_new(
settings, WM_XR_ACTIONCONF_STR_DEFAULT " user", true);
}
}
void WM_xr_actionconfig_update(XrSessionSettings *settings)
{
if (G.background) {
return;
}
if (g_xr_actionconfig_update_flag == 0) {
return;
}
const bool ensure = ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ENSURE) != 0);
if ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ALL) != 0) {
/* Update properties for all actionconfigs. */
LISTBASE_FOREACH (XrActionConfig *, ac, &settings->actionconfigs) {
wm_xr_actionmap_item_properties_update_ot_from_list(&ac->actionmaps, ensure);
}
g_xr_actionconfig_update_flag &= ~(WM_XR_ACTIONCONF_UPDATE_ALL |
WM_XR_ACTIONCONF_UPDATE_ACTIVE);
}
if ((g_xr_actionconfig_update_flag & WM_XR_ACTIONCONF_UPDATE_ACTIVE) != 0) {
/* Update properties for active actionconfig. */
XrActionConfig *ac = WM_xr_actionconfig_active_get(settings);
if (ac) {
wm_xr_actionmap_item_properties_update_ot_from_list(&ac->actionmaps, ensure);
}
g_xr_actionconfig_update_flag &= ~WM_XR_ACTIONCONF_UPDATE_ACTIVE;
}
if (ensure) {
g_xr_actionconfig_update_flag &= ~WM_XR_ACTIONCONF_UPDATE_ENSURE;
}
BLI_assert(g_xr_actionconfig_update_flag == 0);
}
/** \} */

View File

@@ -24,6 +24,8 @@
#include <string.h>
#include "BKE_context.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -31,6 +33,9 @@
#include "GHOST_C-api.h"
#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_viewport.h"
#include "WM_api.h"
@@ -44,6 +49,16 @@ void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
copy_v3_v3(r_mat[3], pose->position);
}
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
{
wm_xr_pose_to_mat(pose, r_mat);
BLI_assert(scale > 0.0f);
mul_v3_fl(r_mat[0], scale);
mul_v3_fl(r_mat[1], scale);
mul_v3_fl(r_mat[2], scale);
}
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
{
float iquat[4];
@@ -52,15 +67,33 @@ void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
}
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
{
float iquat[4];
invert_qt_qt_normalized(iquat, pose->orientation_quat);
quat_to_mat4(r_imat, iquat);
BLI_assert(scale > 0.0f);
scale = 1.0f / scale;
mul_v3_fl(r_imat[0], scale);
mul_v3_fl(r_imat[1], scale);
mul_v3_fl(r_imat[2], scale);
translate_m4(r_imat, -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])
const wmXrSessionState *session_state,
float r_viewmat[4][4],
float r_viewmat_base[4][4],
float r_projmat[4][4])
{
GHOST_XrPose eye_pose;
float eye_inv[4][4], base_inv[4][4];
float eye_inv[4][4], base_inv[4][4], nav_inv[4][4];
/* Calculate inverse eye matrix. */
copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
@@ -69,14 +102,15 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
}
wm_xr_pose_to_imat(&eye_pose, eye_inv);
/* Calculate the base pose matrix (in world space!). */
wm_xr_pose_to_imat(&draw_data->base_pose, base_inv);
mul_m4_m4m4(r_view_mat, eye_inv, base_inv);
/* Apply base pose and navigation. */
wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
mul_m4_m4m4(r_viewmat_base, eye_inv, base_inv);
mul_m4_m4m4(r_viewmat, r_viewmat_base, nav_inv);
perspective_m4_fov(r_proj_mat,
perspective_m4_fov(r_projmat,
draw_view->fov.angle_left,
draw_view->fov.angle_right,
draw_view->fov.angle_up,
@@ -121,13 +155,14 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
float viewmat[4][4], winmat[4][4];
float viewmat[4][4], viewmat_base[4][4], winmat[4][4];
BLI_assert(WM_xr_session_is_ready(xr_data));
wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat);
wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
wm_xr_draw_matrices_create(
draw_data, draw_view, settings, session_state, viewmat, viewmat_base, winmat);
wm_xr_session_state_update(settings, draw_data, draw_view, viewmat, viewmat_base, session_state);
if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
return;
@@ -153,6 +188,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
winmat,
settings->clip_start,
settings->clip_end,
true,
false,
true,
NULL,
@@ -172,3 +208,200 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
}
static GPUBatch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context,
const char *subaction_path)
{
GHOST_XrControllerModelData model_data;
if (!GHOST_XrGetControllerModelData(xr_context, subaction_path, &model_data) ||
model_data.count_vertices < 1) {
return NULL;
}
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, model_data.count_vertices);
void *vbo_data = GPU_vertbuf_get_data(vbo);
memcpy(
vbo_data, model_data.vertices, model_data.count_vertices * sizeof(model_data.vertices[0]));
GPUIndexBuf *ibo = NULL;
if (model_data.count_indices > 0 && ((model_data.count_indices % 3) == 0)) {
GPUIndexBufBuilder ibo_builder;
const unsigned int prim_len = model_data.count_indices / 3;
GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, prim_len, model_data.count_vertices);
for (unsigned int i = 0; i < prim_len; ++i) {
const uint32_t *idx = &model_data.indices[i * 3];
GPU_indexbuf_add_tri_verts(&ibo_builder, idx[0], idx[1], idx[2]);
}
ibo = GPU_indexbuf_build(&ibo_builder);
}
return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
static void wm_xr_controller_model_draw(const XrSessionSettings *settings,
GHOST_XrContextHandle xr_context,
wmXrSessionState *state)
{
GHOST_XrControllerModelData model_data;
float color[4];
switch (settings->controller_draw_style) {
case XR_CONTROLLER_DRAW_DARK:
case XR_CONTROLLER_DRAW_DARK_RAY:
color[0] = color[1] = color[2] = 0.0f, color[3] = 0.4f;
break;
case XR_CONTROLLER_DRAW_LIGHT:
case XR_CONTROLLER_DRAW_LIGHT_RAY:
color[0] = 0.422f, color[1] = 0.438f, color[2] = 0.446f, color[3] = 0.4f;
break;
}
GPU_depth_test(GPU_DEPTH_NONE);
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
GPUBatch *model = controller->model;
if (!model) {
model = controller->model = wm_xr_controller_model_batch_create(xr_context,
controller->subaction_path);
}
if (model &&
GHOST_XrGetControllerModelData(xr_context, controller->subaction_path, &model_data) &&
model_data.count_components > 0) {
GPU_batch_program_set_builtin(model, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4fv(model, "color", color);
GPU_matrix_push();
GPU_matrix_mul(controller->grip_mat);
for (unsigned int component_idx = 0; component_idx < model_data.count_components;
++component_idx) {
const GHOST_XrControllerModelComponent *component = &model_data.components[component_idx];
GPU_matrix_push();
GPU_matrix_mul(component->transform);
GPU_batch_draw_range(model,
model->elem ? component->index_offset : component->vertex_offset,
model->elem ? component->index_count : component->vertex_count);
GPU_matrix_pop();
}
GPU_matrix_pop();
}
else {
/* Fallback. */
const float scale = 0.05f;
GPUBatch *sphere = GPU_batch_preset_sphere(2);
GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
GPU_batch_uniform_4fv(sphere, "color", color);
GPU_matrix_push();
GPU_matrix_mul(controller->grip_mat);
GPU_matrix_scale_1f(scale);
GPU_batch_draw(sphere);
GPU_matrix_pop();
}
}
}
static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSessionState *state)
{
bool draw_ray;
switch (settings->controller_draw_style) {
case XR_CONTROLLER_DRAW_DARK:
case XR_CONTROLLER_DRAW_LIGHT:
draw_ray = false;
break;
case XR_CONTROLLER_DRAW_DARK_RAY:
case XR_CONTROLLER_DRAW_LIGHT_RAY:
draw_ray = true;
break;
}
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
float viewport[4];
GPU_viewport_size_get_f(viewport);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", 3.0f * U.pixelsize);
if (draw_ray) {
const uchar color[4] = {89, 89, 255, 127};
const float scale = settings->clip_end;
float ray[3];
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
GPU_blend(GPU_BLEND_ALPHA);
immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 2);
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
const float(*mat)[4] = controller->aim_mat;
madd_v3_v3v3fl(ray, mat[3], mat[2], -scale);
immAttrSkip(col);
immVertex3fv(pos, mat[3]);
immAttr4ubv(col, color);
immVertex3fv(pos, ray);
}
immEnd();
}
else {
const uchar r[4] = {255, 51, 82, 255};
const uchar g[4] = {139, 220, 0, 255};
const uchar b[4] = {40, 144, 255, 255};
const float scale = 0.01f;
float x_axis[3], y_axis[3], z_axis[3];
GPU_depth_test(GPU_DEPTH_NONE);
GPU_blend(GPU_BLEND_NONE);
immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 6);
LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
const float(*mat)[4] = controller->aim_mat;
madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale);
madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale);
madd_v3_v3v3fl(z_axis, mat[3], mat[2], scale);
immAttrSkip(col);
immVertex3fv(pos, mat[3]);
immAttr4ubv(col, r);
immVertex3fv(pos, x_axis);
immAttrSkip(col);
immVertex3fv(pos, mat[3]);
immAttr4ubv(col, g);
immVertex3fv(pos, y_axis);
immAttrSkip(col);
immVertex3fv(pos, mat[3]);
immAttr4ubv(col, b);
immVertex3fv(pos, z_axis);
}
immEnd();
}
immUnbindProgram();
}
void wm_xr_draw_controllers(const bContext *UNUSED(C), ARegion *UNUSED(region), void *customdata)
{
wmXrData *xr = customdata;
const XrSessionSettings *settings = &xr->session_settings;
GHOST_XrContextHandle xr_context = xr->runtime->context;
wmXrSessionState *state = &xr->runtime->session_state;
wm_xr_controller_model_draw(settings, xr_context, state);
wm_xr_controller_aim_draw(settings, state);
}

View File

@@ -20,10 +20,23 @@
#pragma once
#include "BLI_sys_types.h"
#include "CLG_log.h"
#include "wm_xr.h"
struct ARegion;
struct ARegionType;
struct bContext;
struct bScreen;
struct Depsgraph;
struct GPUBatch;
struct GPUOffScreen;
struct GPUViewport;
struct Scene;
struct ViewLayer;
struct wmOperatorType;
struct wmXrActionSet;
typedef struct wmXrSessionState {
@@ -31,18 +44,25 @@ typedef struct wmXrSessionState {
/** 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. */
/** The last known view matrix (inverse viewer matrix), calculated from above's viewer pose. */
float viewer_viewmat[4][4];
float focal_len;
/** The last known viewer matrix, without navigation applied. */
float viewer_mat_base[4][4];
/** Last known eye data. */
ListBase eyes; /* wmXrEye */
/** Last known controller data. */
ListBase controllers; /* wmXrController */
/** Copy of XrSessionSettings.base_pose_ data to detect changes that need
* resetting to base pose. */
char prev_base_pose_type; /* eXRSessionBasePoseType */
char prev_base_pose_type; /* eXrSessionBasePoseType */
Object *prev_base_pose_object;
/** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
int prev_settings_flag;
/** Copy of wmXrDrawData.base_pose. */
GHOST_XrPose prev_base_pose;
/** Copy of wmXrDrawData.base_scale. */
float prev_base_scale;
/** Copy of GHOST_XrDrawViewInfo.local_pose. */
GHOST_XrPose prev_local_pose;
/** Copy of wmXrDrawData.eye_position_ofs. */
@@ -51,13 +71,23 @@ typedef struct wmXrSessionState {
bool force_reset_to_base_pose;
bool is_view_data_set;
/** Last known controller data. */
ListBase controllers; /* wmXrController */
/** Current navigation transforms. */
GHOST_XrPose nav_pose;
float nav_scale;
/** Navigation transforms from the last actions sync, used to calculate the viewer/controller
* poses. */
GHOST_XrPose nav_pose_prev;
float nav_scale_prev;
bool is_navigation_dirty;
/** The currently active action set that will be updated on calls to
* wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
* updated. */
struct wmXrActionSet *active_action_set;
/* Original poses for motion capture objects. Used to properly restore object transforms on
* session end. */
ListBase mocap_orig_poses; /* wmXrMotionCapturePose */
} wmXrSessionState;
typedef struct wmXrRuntimeData {
@@ -70,10 +100,6 @@ typedef struct wmXrRuntimeData {
/** Although this struct is internal, RNA gets a handle to this for state information queries. */
wmXrSessionState session_state;
wmXrSessionExitFn exit_fn;
ListBase actionmaps; /* XrActionMap */
short actactionmap;
short selactionmap;
} wmXrRuntimeData;
typedef struct wmXrViewportPair {
@@ -85,6 +111,11 @@ typedef struct wmXrViewportPair {
typedef struct {
/** Off-screen buffers/viewports for each view. */
ListBase viewports; /* wmXrViewportPair */
/** Dummy region type for controller draw callback. */
struct ARegionType *controller_art;
/** Controller draw callback handle. */
void *controller_draw_handle;
} wmXrSurfaceData;
typedef struct wmXrDrawData {
@@ -98,11 +129,21 @@ typedef struct wmXrDrawData {
* 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;
/** Base scale (uniform, world space). */
float base_scale;
/** Offset to _substract_ from the OpenXR eye and viewer pose to get the wanted effective pose
* (e.g. a pose exactly at the landmark position). */
float eye_position_ofs[3]; /* Local/view space. */
} wmXrDrawData;
typedef struct wmXrEye {
struct wmXrEye *next, *prev;
float focal_len;
float viewmat[4][4];
/** Viewmat without navigation applied. */
float viewmat_base[4][4];
} wmXrEye;
typedef struct wmXrController {
struct wmXrController *next, *prev;
/** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256).
@@ -111,12 +152,18 @@ typedef struct wmXrController {
/input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
*/
char subaction_path[64];
/* Pose (in world space) that represents the user's hand when holding the controller.*/
GHOST_XrPose grip_pose;
float grip_mat[4][4];
float grip_mat_base[4][4];
/* Pose (in world space) that represents the controller's aiming source. */
GHOST_XrPose aim_pose;
float aim_mat[4][4];
float aim_mat_base[4][4];
/** Controller model. */
struct GPUBatch *model;
} wmXrController;
typedef struct wmXrAction {
@@ -167,22 +214,32 @@ typedef struct wmXrActionSet {
wmXrAction *controller_aim_action;
/** Currently active modal actions. */
ListBase active_modal_actions;
ListBase active_modal_actions; /* wmXrAction */
/** Currently active haptic actions. */
ListBase active_haptic_actions;
ListBase active_haptic_actions; /* wmXrHapticAction */
} wmXrActionSet;
typedef struct wmXrMotionCapturePose {
struct wmXrMotionCapturePose *next, *prev;
const Object *ob;
GHOST_XrPose pose;
} wmXrMotionCapturePose;
/* wm_xr.c */
wmXrRuntimeData *wm_xr_runtime_data_create(void);
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime);
void wm_xr_session_data_free(wmXrSessionState *state);
void wm_xr_session_draw_data_update(const wmXrSessionState *state,
/* wm_xr_session.c */
void wm_xr_session_data_free(wmXrSessionState *state);
void wm_xr_session_draw_data_update(wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data);
void wm_xr_session_state_update(const XrSessionSettings *settings,
const wmXrDrawData *draw_data,
const GHOST_XrDrawViewInfo *draw_view,
const float viewmat[4][4],
const float viewmat_base[4][4],
wmXrSessionState *state);
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
const GHOST_XrDrawViewInfo *draw_view);
@@ -190,12 +247,36 @@ void *wm_xr_session_gpu_binding_context_create(void);
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context);
void wm_xr_session_actions_init(wmXrData *xr);
void wm_xr_session_actions_update(wmXrData *xr);
void wm_xr_session_actions_update(const struct bContext *C);
void wm_xr_session_controller_data_populate(const wmXrAction *grip_action,
const wmXrAction *aim_action,
wmXrData *xr);
void wm_xr_session_controller_data_clear(wmXrSessionState *state);
/* wm_xr_draw.c */
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]);
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]);
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata);
/* wm_xr_mocap.c */
void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state);
void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings);
void wm_xr_mocap_object_autokey(struct bContext *C,
struct Scene *scene,
struct ViewLayer *view_layer,
wmWindow *win,
Object *ob,
bool notify);
void wm_xr_mocap_objects_update(const char *user_path,
const GHOST_XrPose *pose,
struct bContext *C,
XrSessionSettings *settings,
struct Scene *scene,
struct ViewLayer *view_layer,
wmWindow *win,
struct bScreen *screen_anim,
bool notify);

View File

@@ -0,0 +1,267 @@
/*
* 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 Motion Capture
*
* API for XR motion capture objects.
*/
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DEG_depsgraph.h"
#include "DNA_object_types.h"
#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "GHOST_C-api.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "wm_xr_intern.h"
/* -------------------------------------------------------------------- */
/** \name XR Motion Capture Objects
*
* List of XR motion capture objects. Stored in session settings and can be written to files.
* \{ */
XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob)
{
XrMotionCaptureObject *mocap_ob = WM_xr_mocap_object_find(settings, ob);
if (!mocap_ob) {
mocap_ob = MEM_callocN(sizeof(XrMotionCaptureObject), __func__);
mocap_ob->ob = ob;
BLI_addtail(&settings->mocap_objects, mocap_ob);
}
return mocap_ob;
}
void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
{
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob_other, &settings->mocap_objects) {
if ((mocap_ob_other != mocap_ob) && (mocap_ob_other->ob == mocap_ob->ob)) {
mocap_ob->ob = NULL;
return;
}
}
}
void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
{
int idx = BLI_findindex(&settings->mocap_objects, mocap_ob);
if (idx != -1) {
BLI_freelinkN(&settings->mocap_objects, mocap_ob);
if (idx <= settings->sel_mocap_object) {
if (--settings->sel_mocap_object < 0) {
settings->sel_mocap_object = 0;
}
}
}
}
XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings, const Object *ob)
{
return ob ? BLI_findptr(&settings->mocap_objects, ob, offsetof(XrMotionCaptureObject, ob)) :
NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Motion Capture Runtime
*
* Runtime functions for motion capture object poses and autokeying.
* \{ */
static void wm_xr_mocap_object_pose_get(const XrMotionCaptureObject *mocap_ob, GHOST_XrPose *pose)
{
BLI_assert(mocap_ob->ob);
copy_v3_v3(pose->position, mocap_ob->ob->loc);
eul_to_quat(pose->orientation_quat, mocap_ob->ob->rot);
}
static void wm_xr_mocap_object_pose_set(const GHOST_XrPose *pose,
XrMotionCaptureObject *mocap_ob,
bool apply_offset)
{
BLI_assert(mocap_ob->ob);
if (apply_offset) {
/* Convert offsets to pose (device) space. */
float loc_ofs[3], rot_ofs[4];
copy_v3_v3(loc_ofs, mocap_ob->location_offset);
mul_qt_v3(pose->orientation_quat, loc_ofs);
eul_to_quat(rot_ofs, mocap_ob->rotation_offset);
normalize_qt(rot_ofs);
invert_qt_normalized(rot_ofs);
mul_qt_qtqt(rot_ofs, pose->orientation_quat, rot_ofs);
normalize_qt(rot_ofs);
add_v3_v3v3(mocap_ob->ob->loc, pose->position, loc_ofs);
quat_to_eul(mocap_ob->ob->rot, rot_ofs);
}
else {
copy_v3_v3(mocap_ob->ob->loc, pose->position);
quat_to_eul(mocap_ob->ob->rot, pose->orientation_quat);
}
DEG_id_tag_update(&mocap_ob->ob->id, ID_RECALC_TRANSFORM);
}
void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state)
{
ListBase *mocap_orig_poses = &state->mocap_orig_poses;
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
wmXrMotionCapturePose *mocap_pose = MEM_callocN(sizeof(wmXrMotionCapturePose), __func__);
mocap_pose->ob = mocap_ob->ob;
if (mocap_ob->ob) {
wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
}
BLI_addtail(mocap_orig_poses, mocap_pose);
}
}
void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings)
{
ListBase *mocap_objects = &settings->mocap_objects;
LISTBASE_FOREACH (wmXrMotionCapturePose *, mocap_pose, &state->mocap_orig_poses) {
XrMotionCaptureObject *mocap_ob = BLI_findptr(
mocap_objects, mocap_pose->ob, offsetof(XrMotionCaptureObject, ob));
if (mocap_ob && mocap_ob->ob) {
wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
}
}
}
void wm_xr_mocap_object_autokey(
bContext *C, Scene *scene, ViewLayer *view_layer, wmWindow *win, Object *ob, bool notify)
{
/* Poll functions in keyingsets_utils.py require an active window and object. */
wmWindow *win_prev = win ? CTX_wm_window(C) : NULL;
if (win) {
CTX_wm_window_set(C, win);
}
Object *obact = CTX_data_active_object(C);
if (!obact) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
ED_object_base_select(base, BA_SELECT);
ED_object_base_activate(C, base);
}
}
bScreen *screen = CTX_wm_screen(C);
if (screen && screen->animtimer && (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0) &&
((scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA) != 0)) {
ED_transform_animrecord_check_state(scene, screen->animtimer, ob);
}
ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_TRANSLATION);
if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_ROTATION);
}
if (ED_transform_motionpath_need_update_object(scene, ob)) {
ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
}
if (notify) {
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
if (win) {
CTX_wm_window_set(C, win_prev);
}
}
void wm_xr_mocap_objects_update(const char *user_path,
const GHOST_XrPose *pose,
bContext *C,
XrSessionSettings *settings,
Scene *scene,
ViewLayer *view_layer,
wmWindow *win,
bScreen *screen_anim,
bool notify)
{
LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
if (mocap_ob->ob && ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) &&
STREQ(mocap_ob->user_path, user_path)) {
wm_xr_mocap_object_pose_set(pose, mocap_ob, true);
if (((mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0) && screen_anim &&
autokeyframe_cfra_can_key(scene, &mocap_ob->ob->id)) {
wm_xr_mocap_object_autokey(C, scene, view_layer, win, mocap_ob->ob, notify);
notify = false;
}
}
}
}
bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob)
{
if (!WM_xr_session_exists(xr)) {
return false;
}
if (mocap_ob->ob) {
wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
mocap_ob->ob,
offsetof(wmXrMotionCapturePose, ob));
if (!mocap_pose) {
return false;
}
wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
}
return true;
}
void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob)
{
if (WM_xr_session_exists(xr) && mocap_ob->ob) {
wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
mocap_ob->ob,
offsetof(wmXrMotionCapturePose, ob));
if (mocap_pose) {
wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
}
}
}
/** \} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
struct wmWindowManager;
struct wmXrData;
struct bContext;
typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
@@ -29,4 +30,7 @@ typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
bool wm_xr_init(wmWindowManager *wm);
void wm_xr_exit(wmWindowManager *wm);
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
bool wm_xr_events_handle(wmWindowManager *wm);
bool wm_xr_events_handle(const struct bContext *C);
/* wm_xr_operators.c */
void wm_xr_operatortypes_register(void);

View File

@@ -513,6 +513,10 @@ int main(int argc,
CTX_py_init_set(C, true);
WM_keyconfig_init(C);
#ifdef WITH_XR_OPENXR
WM_xr_actionconfig_init(C);
#endif
#ifdef WITH_FREESTYLE
/* Initialize Freestyle. */
FRS_init();