Blender V5.0
wm_xr_session.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_callbacks.hh"
10#include "BKE_context.hh"
11#include "BKE_global.hh"
12#include "BKE_idprop.hh"
13#include "BKE_main.hh"
14#include "BKE_scene.hh"
15#include "BKE_screen.hh"
16
17#include "BLI_listbase.h"
18#include "BLI_math_matrix.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_string.h"
22#include "BLI_time.h"
23
24#include "DEG_depsgraph.hh"
26
27#include "DNA_camera_types.h"
28#include "DNA_space_types.h"
29
30#include "DRW_engine.hh"
31
32#include "ED_screen.hh"
33#include "ED_space_api.hh"
34
35#include "GHOST_C-api.h"
36
37#include "GPU_batch.hh"
38#include "GPU_viewport.hh"
39
40#include "MEM_guardedalloc.h"
41
42#include "WM_api.hh"
43#include "WM_types.hh"
44
45#include "wm_event_system.hh"
46#include "wm_surface.hh"
47#include "wm_window.hh"
48#include "wm_xr_intern.hh"
49
50static wmSurface *g_xr_surface = nullptr;
51static CLG_LogRef LOG = {"xr"};
52
53/* -------------------------------------------------------------------- */
54
56{
57 Main *bmain = G_MAIN;
58 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
59 wmXrData *xr_data = &wm->xr;
61 XrSessionSettings *settings = &xr_data->session_settings;
62
63 /* Get action set data from Python. */
65
67
68 /* Initialize navigation. */
70 if (settings->base_scale < FLT_EPSILON) {
71 settings->base_scale = 1.0f;
72 }
73 state->prev_base_scale = settings->base_scale;
74
75 /* Initialize vignette. */
76 state->vignette_data = MEM_callocN<wmXrVignetteData>(__func__);
78}
79
81{
82 ListBase *lb = &state->controllers;
83 while (wmXrController *c = static_cast<wmXrController *>(BLI_pophead(lb))) {
84 if (c->model) {
85 GPU_batch_discard(c->model);
86 }
87 BLI_freelinkN(lb, c);
88 }
89}
90
92{
93 if (state->vignette_data) {
94 MEM_freeN(state->vignette_data);
95 state->vignette_data = nullptr;
96 }
97}
98
100{
101 if (state->raycast_model) {
102 GPU_batch_discard(state->raycast_model);
103 state->raycast_model = nullptr;
104 }
105}
106
113
114static void wm_xr_session_exit_cb(void *customdata)
115{
116 wmXrData *xr_data = static_cast<wmXrData *>(customdata);
117 if (!xr_data->runtime) {
118 return;
119 }
120
121 xr_data->runtime->session_state.is_started = false;
122
123 if (xr_data->runtime->exit_fn) {
124 xr_data->runtime->exit_fn(xr_data);
125 }
126
127 /* Free the entire runtime data (including session state and context), to play safe. */
129}
130
132 GHOST_XrSessionBeginInfo *r_begin_info)
133{
134 /* Callback for when the session is created. This is needed to create and bind OpenXR actions
135 * after the session is created but before it is started. */
136 r_begin_info->create_fn = wm_xr_session_create_cb;
137
138 /* WM-XR exit function, does some of its own stuff and calls callback passed to
139 * wm_xr_session_toggle(), to allow external code to execute its own session-exit logic. */
140 r_begin_info->exit_fn = wm_xr_session_exit_cb;
141 r_begin_info->exit_customdata = xr_data;
142}
143
145 wmWindow *session_root_win,
146 wmXrSessionExitFn session_exit_fn)
147{
148 wmXrData *xr_data = &wm->xr;
149
150 if (WM_xr_session_exists(xr_data)) {
151 /* Must set first, since #GHOST_XrSessionEnd() may immediately free the runtime. */
152 xr_data->runtime->session_state.is_started = false;
153
154 GHOST_XrSessionEnd(xr_data->runtime->context);
155 }
156 else {
157 GHOST_XrSessionBeginInfo begin_info;
158
159 xr_data->runtime->session_root_win = session_root_win;
160 xr_data->runtime->session_state.is_started = true;
161 xr_data->runtime->exit_fn = session_exit_fn;
162
163 wm_xr_session_begin_info_create(xr_data, &begin_info);
164 GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
165 }
166}
167
169{
170 return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
171}
172
177
179{
180 return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
181}
182
183static void wm_xr_session_base_pose_calc(const Scene *scene,
184 const XrSessionSettings *settings,
185 GHOST_XrPose *r_base_pose,
186 float *r_base_scale)
187{
188 const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
189 settings->base_pose_object) ?
190 settings->base_pose_object :
191 scene->camera;
192
193 if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
194 float tmp_quatx[4], tmp_quatz[4];
195
196 copy_v3_v3(r_base_pose->position, settings->base_pose_location);
197 axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
198 axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
199 mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
200 }
201 else if (base_pose_object) {
202 float tmp_quat[4];
203 float tmp_eul[3];
204
205 mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->object_to_world().ptr());
206
207 /* Only use rotation around Z-axis to align view with floor. */
208 quat_to_eul(tmp_eul, tmp_quat);
209 tmp_eul[0] = M_PI_2;
210 tmp_eul[1] = 0;
211 eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
212 }
213 else {
214 copy_v3_fl(r_base_pose->position, 0.0f);
215 axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
216 }
217
218 *r_base_scale = settings->base_scale;
219}
220
222 Scene *scene,
223 Depsgraph *depsgraph,
224 wmXrDrawData *r_draw_data)
225{
226 const XrSessionSettings *settings = &xr_data->session_settings;
227
228 memset(r_draw_data, 0, sizeof(*r_draw_data));
229 r_draw_data->scene = scene;
230 r_draw_data->depsgraph = depsgraph;
231 r_draw_data->xr_data = xr_data;
232 r_draw_data->surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
233
235 r_draw_data->scene, settings, &r_draw_data->base_pose, &r_draw_data->base_scale);
236}
237
239 const wmXrRuntimeData *runtime_data)
240{
241 if (runtime_data->session_root_win &&
242 BLI_findindex(&wm->windows, runtime_data->session_root_win) != -1)
243 {
244 /* Root window is still valid, use it. */
245 return runtime_data->session_root_win;
246 }
247 /* Otherwise, fall back. */
248 return static_cast<wmWindow *>(wm->windows.first);
249}
250
259 Scene **r_scene,
260 Depsgraph **r_depsgraph)
261{
263
264 /* Follow the scene & view layer shown in the root 3D View. */
265 Scene *scene = WM_window_get_active_scene(root_win);
266 ViewLayer *view_layer = WM_window_get_active_view_layer(root_win);
267
268 Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
269 BLI_assert(scene && view_layer && depsgraph);
270 *r_scene = scene;
271 *r_depsgraph = depsgraph;
272}
273
280
282 const XrSessionSettings *settings)
283{
284 if (state->force_reset_to_base_pose) {
285 return true;
286 }
287 return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) &&
288 ((state->prev_base_pose_type != settings->base_pose_type) ||
289 (state->prev_base_pose_object != settings->base_pose_object));
290}
291
293 const XrSessionSettings *settings)
294{
295 if (!state->is_view_data_set) {
297 }
300 }
301
302 const bool position_tracking_toggled = ((state->prev_settings_flag &
305 if (position_tracking_toggled) {
307 }
308
310}
311
313 const XrSessionSettings *settings,
314 const GHOST_XrDrawViewInfo *draw_view,
315 wmXrDrawData *draw_data)
316{
318 const bool use_position_tracking = (settings->flag & XR_SESSION_USE_POSITION_TRACKING);
319
320 switch (event) {
322 if (use_position_tracking) {
323 /* We want to start the session exactly at landmark position.
324 * Run-times may have a non-[0,0,0] starting position that we have to subtract for that. */
325 copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
326 }
327 else {
328 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
329 }
330 break;
331 /* This should be triggered by the VR add-on if a landmark changes. */
333 if (use_position_tracking) {
334 /* Switch exactly to base pose, so use eye offset to cancel out current position delta. */
335 copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
336 }
337 else {
338 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
339 }
340 /* Reset navigation. */
342 break;
344 if (use_position_tracking) {
345 /* Keep the current position, and let the user move from there. */
346 copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
347 }
348 else {
349 /* Back to the exact base-pose position. */
350 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
351 }
352 break;
354 /* Keep previous offset when positional tracking is disabled. */
355 copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
356 break;
357 }
358}
359
361 const wmXrDrawData *draw_data,
362 const GHOST_XrDrawViewInfo *draw_view,
364{
365 GHOST_XrPose viewer_pose;
366 float viewer_mat[4][4], base_mat[4][4], nav_mat[4][4];
367
368 /* Calculate viewer matrix. */
369 copy_qt_qt(viewer_pose.orientation_quat, draw_view->local_pose.orientation_quat);
370 if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
371 zero_v3(viewer_pose.position);
372 }
373 else {
374 copy_v3_v3(viewer_pose.position, draw_view->local_pose.position);
375 }
376 if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
377 sub_v3_v3(viewer_pose.position, draw_data->eye_position_ofs);
378 }
379 wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
380
381 /* Apply base pose and navigation. */
382 wm_xr_pose_scale_to_mat(&draw_data->base_pose, draw_data->base_scale, base_mat);
383 wm_xr_pose_scale_to_mat(&state->nav_pose_prev, state->nav_scale_prev, nav_mat);
384 mul_m4_m4m4(state->viewer_mat_base, base_mat, viewer_mat);
385 mul_m4_m4m4(viewer_mat, nav_mat, state->viewer_mat_base);
386
387 /* Save final viewer pose and viewmat. */
388 mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
390 &state->viewer_pose, draw_data->base_scale * state->nav_scale_prev, state->viewer_viewmat);
391
392 /* No idea why, but multiplying by two seems to make it match the VR view more. */
393 state->focal_len = 2.0f *
394 fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
396
397 copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
398 memcpy(&state->prev_base_pose, &draw_data->base_pose, sizeof(state->prev_base_pose));
399 state->prev_base_scale = draw_data->base_scale;
400 memcpy(&state->prev_local_pose, &draw_view->local_pose, sizeof(state->prev_local_pose));
401 copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
402
403 state->prev_settings_flag = settings->flag;
404 state->prev_base_pose_type = settings->base_pose_type;
405 state->prev_base_pose_object = settings->base_pose_object;
406 state->is_view_data_set = true;
407 /* Assume this was already done through wm_xr_session_draw_data_update(). */
408 state->force_reset_to_base_pose = false;
409
411}
412
414{
415 return xr->runtime ? &xr->runtime->session_state : nullptr;
416}
417
419{
420 return xr->runtime ? xr->runtime->area : nullptr;
421}
422
423bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
424{
426 zero_v3(r_location);
427 return false;
428 }
429
430 copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
431 return true;
432}
433
434bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
435{
437 unit_qt(r_rotation);
438 return false;
439 }
440
441 copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
442 return true;
443}
444
446 float r_viewmat[4][4],
447 float *r_focal_len)
448{
450 unit_m4(r_viewmat);
451 *r_focal_len = 0.0f;
452 return false;
453 }
454
456 *r_focal_len = xr->runtime->session_state.focal_len;
457
458 return true;
459}
460
462 uint subaction_idx,
463 float r_location[3])
464{
466 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
467 {
468 zero_v3(r_location);
469 return false;
470 }
471
472 const wmXrController *controller = static_cast<const wmXrController *>(
473 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
475 copy_v3_v3(r_location, controller->grip_pose.position);
476 return true;
477}
478
480 uint subaction_idx,
481 float r_rotation[4])
482{
484 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
485 {
486 unit_qt(r_rotation);
487 return false;
488 }
489
490 const wmXrController *controller = static_cast<const wmXrController *>(
491 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
493 copy_qt_qt(r_rotation, controller->grip_pose.orientation_quat);
494 return true;
495}
496
498 uint subaction_idx,
499 float r_location[3])
500{
502 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
503 {
504 zero_v3(r_location);
505 return false;
506 }
507
508 const wmXrController *controller = static_cast<const wmXrController *>(
509 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
511 copy_v3_v3(r_location, controller->aim_pose.position);
512 return true;
513}
514
516 uint subaction_idx,
517 float r_rotation[4])
518{
520 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
521 {
522 unit_qt(r_rotation);
523 return false;
524 }
525
526 const wmXrController *controller = static_cast<const wmXrController *>(
527 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
529 copy_qt_qt(r_rotation, controller->aim_pose.orientation_quat);
530 return true;
531}
532
533bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3])
534{
536 zero_v3(r_location);
537 return false;
538 }
539
540 copy_v3_v3(r_location, xr->runtime->session_state.nav_pose.position);
541 return true;
542}
543
544void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3])
545{
546 if (WM_xr_session_exists(xr)) {
547 copy_v3_v3(xr->runtime->session_state.nav_pose.position, location);
549 }
550}
551
552bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])
553{
555 unit_qt(r_rotation);
556 return false;
557 }
558
559 copy_qt_qt(r_rotation, xr->runtime->session_state.nav_pose.orientation_quat);
560 return true;
561}
562
563void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
564{
565 if (WM_xr_session_exists(xr)) {
566 BLI_ASSERT_UNIT_QUAT(rotation);
567 copy_qt_qt(xr->runtime->session_state.nav_pose.orientation_quat, rotation);
569 }
570}
571
572bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
573{
575 *r_scale = 1.0f;
576 return false;
577 }
578
579 *r_scale = xr->runtime->session_state.nav_scale;
580 return true;
581}
582
584{
585 if (WM_xr_session_exists(xr)) {
586 /* Clamp to reasonable values. */
588 xr->runtime->session_state.nav_scale = scale;
590 }
591}
592
594{
595 zero_v3(state->nav_pose.position);
596 unit_qt(state->nav_pose.orientation_quat);
597 state->nav_scale = 1.0f;
598 state->is_navigation_dirty = true;
599 state->swap_hands = false;
600}
601
603{
604 wmXrVignetteData *data = state->vignette_data;
605
606 /* Reset vignette state */
607 data->aperture = 1.0f;
608 data->aperture_velocity = 0.0f;
609
610 /* Set default vignette parameters */
611 data->initial_aperture = 0.25f;
612 data->initial_aperture_velocity = -0.03f;
613
614 data->aperture_min = 0.08f;
615 data->aperture_max = 0.3f;
616
617 data->aperture_velocity_max = 0.002f;
618 data->aperture_velocity_delta = 0.01f;
619}
620
622{
623 if (WM_xr_session_exists(xr)) {
625 data->aperture_velocity = data->initial_aperture_velocity;
626 data->aperture = min_ff(data->aperture, data->initial_aperture);
627 }
628}
629
631{
632 wmXrVignetteData *data = state->vignette_data;
633
634 const float vignette_intensity = U.xr_navigation.vignette_intensity;
635 const float aperture_min = interpf(
636 data->aperture_min, data->aperture_max, vignette_intensity * 0.01f);
637 data->aperture_velocity = min_ff(data->aperture_velocity_max,
638 data->aperture_velocity + data->aperture_velocity_delta);
639
640 if (data->aperture == aperture_min) {
641 data->aperture_velocity = data->aperture_velocity_max;
642 }
643
644 data->aperture = clamp_f(data->aperture + data->aperture_velocity, aperture_min, 1.0f);
645}
646
647/* -------------------------------------------------------------------- */
653
655{
656 if (!xr->runtime) {
657 return;
658 }
659
660 GHOST_XrAttachActionSets(xr->runtime->context);
661}
662
663static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
664 const float view_ofs[3],
665 const float base_mat[4][4],
666 const float nav_mat[4][4],
667 GHOST_XrPose *r_pose,
668 float r_mat[4][4],
669 float r_mat_base[4][4])
670{
671 float m[4][4];
672 /* Calculate controller matrix in world space. */
673 wm_xr_pose_to_mat(raw_pose, m);
674
675 /* Apply eye position offset. */
676 sub_v3_v3(m[3], view_ofs);
677
678 /* Apply base pose and navigation. */
679 mul_m4_m4m4(r_mat_base, base_mat, m);
680 mul_m4_m4m4(r_mat, nav_mat, r_mat_base);
681
682 /* Save final pose. */
683 mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat);
684}
685
687 const wmXrAction *grip_action,
688 const wmXrAction *aim_action,
689 GHOST_XrContextHandle xr_context,
691{
692 BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
693 BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers));
694
695 uint subaction_idx = 0;
696 float view_ofs[3], base_mat[4][4], nav_mat[4][4];
697
698 if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
699 copy_v3_v3(view_ofs, state->prev_local_pose.position);
700 }
701 else {
702 zero_v3(view_ofs);
703 }
704 if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
705 add_v3_v3(view_ofs, state->prev_eye_position_ofs);
706 }
707
708 wm_xr_pose_scale_to_mat(&state->prev_base_pose, state->prev_base_scale, base_mat);
709 wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, nav_mat);
710
711 LISTBASE_FOREACH_INDEX (wmXrController *, controller, &state->controllers, subaction_idx) {
712 controller->grip_active = ((GHOST_XrPose *)grip_action->states)[subaction_idx].is_active;
713 wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx],
714 view_ofs,
715 base_mat,
716 nav_mat,
717 &controller->grip_pose,
718 controller->grip_mat,
719 controller->grip_mat_base);
720 controller->aim_active = ((GHOST_XrPose *)aim_action->states)[subaction_idx].is_active;
721 wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx],
722 view_ofs,
723 base_mat,
724 nav_mat,
725 &controller->aim_pose,
726 controller->aim_mat,
727 controller->aim_mat_base);
728
729 if (!controller->model) {
730 /* Notify GHOST to load/continue loading the controller model data. This can be called more
731 * than once since the model may not be available from the runtime yet. The batch itself will
732 * be created in wm_xr_draw_controllers(). */
733 GHOST_XrLoadControllerModel(xr_context, controller->subaction_path);
734 }
735 else {
736 GHOST_XrUpdateControllerModelComponents(xr_context, controller->subaction_path);
737 }
738 }
739}
740
742 const char *subaction_path)
743{
744 const wmXrController *controller = static_cast<const wmXrController *>(BLI_findstring(
745 &state->controllers, subaction_path, offsetof(wmXrController, subaction_path)));
746 return controller ? &controller->aim_pose : nullptr;
747}
748
749BLI_INLINE bool test_float_state(const float *state, float threshold, eXrAxisFlag flag)
750{
751 if ((flag & XR_AXIS0_POS) != 0) {
752 if (*state > threshold) {
753 return true;
754 }
755 }
756 else if ((flag & XR_AXIS0_NEG) != 0) {
757 if (*state < -threshold) {
758 return true;
759 }
760 }
761 else {
762 if (fabsf(*state) > threshold) {
763 return true;
764 }
765 }
766 return false;
767}
768
769BLI_INLINE bool test_vec2f_state(const float state[2], float threshold, eXrAxisFlag flag)
770{
771 if ((flag & XR_AXIS0_POS) != 0) {
772 if (state[0] < 0.0f) {
773 return false;
774 }
775 }
776 else if ((flag & XR_AXIS0_NEG) != 0) {
777 if (state[0] > 0.0f) {
778 return false;
779 }
780 }
781 if ((flag & XR_AXIS1_POS) != 0) {
782 if (state[1] < 0.0f) {
783 return false;
784 }
785 }
786 else if ((flag & XR_AXIS1_NEG) != 0) {
787 if (state[1] > 0.0f) {
788 return false;
789 }
790 }
791 return (len_v2(state) > threshold);
792}
793
794static bool wm_xr_session_modal_action_test(const ListBase *active_modal_actions,
795 const wmXrAction *action,
796 bool *r_found)
797{
798 if (r_found) {
799 *r_found = false;
800 }
801
802 LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
803 wmXrAction *active_modal_action = static_cast<wmXrAction *>(ld->data);
804 if (action == active_modal_action) {
805 if (r_found) {
806 *r_found = true;
807 }
808 return true;
809 }
810 if (action->ot == active_modal_action->ot &&
811 IDP_EqualsProperties(action->op_properties, active_modal_action->op_properties))
812 {
813 /* Don't allow duplicate modal operators since this can lead to unwanted modal handler
814 * behavior. */
815 return false;
816 }
817 }
818
819 return true;
820}
821
822static void wm_xr_session_modal_action_test_add(ListBase *active_modal_actions,
823 const wmXrAction *action)
824{
825 bool found;
826 if (wm_xr_session_modal_action_test(active_modal_actions, action, &found) && !found) {
827 LinkData *ld = MEM_callocN<LinkData>(__func__);
828 ld->data = (void *)action;
829 BLI_addtail(active_modal_actions, ld);
830 }
831}
832
833static void wm_xr_session_modal_action_remove(ListBase *active_modal_actions,
834 const wmXrAction *action)
835{
836 LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
837 if (action == ld->data) {
838 BLI_freelinkN(active_modal_actions, ld);
839 return;
840 }
841 }
842}
843
845 const wmXrAction *action,
846 const char *subaction_path)
847{
848 LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
849 if ((action == ha->action) && (subaction_path == ha->subaction_path)) {
850 return ha;
851 }
852 }
853 return nullptr;
854}
855
856static void wm_xr_session_haptic_action_add(ListBase *active_haptic_actions,
857 const wmXrAction *action,
858 const char *subaction_path,
859 int64_t time_now)
860{
862 active_haptic_actions, action, subaction_path);
863 if (ha) {
864 /* Reset start time since OpenXR restarts haptics if they are already active. */
865 ha->time_start = time_now;
866 }
867 else {
868 ha = MEM_callocN<wmXrHapticAction>(__func__);
869 ha->action = (wmXrAction *)action;
870 ha->subaction_path = subaction_path;
871 ha->time_start = time_now;
872 BLI_addtail(active_haptic_actions, ha);
873 }
874}
875
876static void wm_xr_session_haptic_action_remove(ListBase *active_haptic_actions,
877 const wmXrAction *action)
878{
879 LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
880 if (action == ha->action) {
881 BLI_freelinkN(active_haptic_actions, ha);
882 return;
883 }
884 }
885}
886
887static void wm_xr_session_haptic_timers_check(ListBase *active_haptic_actions, int64_t time_now)
888{
889 LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, active_haptic_actions) {
890 if (time_now - ha->time_start >= ha->action->haptic_duration) {
891 BLI_freelinkN(active_haptic_actions, ha);
892 }
893 }
894}
895
897 const char *action_set_name,
898 wmXrAction *action,
899 uint subaction_idx,
900 ListBase *active_modal_actions,
901 ListBase *active_haptic_actions,
902 int64_t time_now,
903 bool modal,
904 bool haptic,
905 short *r_val)
906{
907 const char *haptic_subaction_path = ((action->haptic_flag & XR_HAPTIC_MATCHUSERPATHS) != 0) ?
908 action->subaction_paths[subaction_idx] :
909 nullptr;
910 bool curr = false;
911 bool prev = false;
912
913 switch (action->type) {
914 case XR_BOOLEAN_INPUT: {
915 const bool *state = &((bool *)action->states)[subaction_idx];
916 bool *state_prev = &((bool *)action->states_prev)[subaction_idx];
917 if (*state) {
918 curr = true;
919 }
920 if (*state_prev) {
921 prev = true;
922 }
923 *state_prev = *state;
924 break;
925 }
926 case XR_FLOAT_INPUT: {
927 const float *state = &((float *)action->states)[subaction_idx];
928 float *state_prev = &((float *)action->states_prev)[subaction_idx];
930 state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx]))
931 {
932 curr = true;
933 }
934 if (test_float_state(state_prev,
935 action->float_thresholds[subaction_idx],
936 action->axis_flags[subaction_idx]))
937 {
938 prev = true;
939 }
940 *state_prev = *state;
941 break;
942 }
943 case XR_VECTOR2F_INPUT: {
944 const float (*state)[2] = &((float (*)[2])action->states)[subaction_idx];
945 float (*state_prev)[2] = &((float (*)[2])action->states_prev)[subaction_idx];
947 *state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx]))
948 {
949 curr = true;
950 }
951 if (test_vec2f_state(*state_prev,
952 action->float_thresholds[subaction_idx],
953 action->axis_flags[subaction_idx]))
954 {
955 prev = true;
956 }
957 copy_v2_v2(*state_prev, *state);
958 break;
959 }
960 case XR_POSE_INPUT:
963 break;
964 }
965
966 if (curr) {
967 if (!prev) {
968 if (modal || (action->op_flag == XR_OP_PRESS)) {
969 *r_val = KM_PRESS;
970 }
971 if (haptic && (action->haptic_flag & (XR_HAPTIC_PRESS | XR_HAPTIC_REPEAT)) != 0) {
972 /* Apply haptics. */
974 action_set_name,
975 action->haptic_name,
976 haptic_subaction_path,
977 &action->haptic_duration,
978 &action->haptic_frequency,
979 &action->haptic_amplitude))
980 {
982 active_haptic_actions, action, haptic_subaction_path, time_now);
983 }
984 }
985 }
986 else if (modal) {
987 *r_val = KM_PRESS;
988 }
989 if (modal && !action->active_modal_path) {
990 /* Set active modal path. */
991 action->active_modal_path = action->subaction_paths[subaction_idx];
992 /* Add to active modal actions. */
993 wm_xr_session_modal_action_test_add(active_modal_actions, action);
994 }
995 if (haptic && ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0)) {
996 if (!wm_xr_session_haptic_action_find(active_haptic_actions, action, haptic_subaction_path))
997 {
998 /* Apply haptics. */
1000 action_set_name,
1001 action->haptic_name,
1002 haptic_subaction_path,
1003 &action->haptic_duration,
1004 &action->haptic_frequency,
1005 &action->haptic_amplitude))
1006 {
1008 active_haptic_actions, action, haptic_subaction_path, time_now);
1009 }
1010 }
1011 }
1012 }
1013 else if (prev) {
1014 if (modal || (action->op_flag == XR_OP_RELEASE)) {
1015 *r_val = KM_RELEASE;
1016 if (modal && (action->subaction_paths[subaction_idx] == action->active_modal_path)) {
1017 /* Unset active modal path. */
1018 action->active_modal_path = nullptr;
1019 /* Remove from active modal actions. */
1020 wm_xr_session_modal_action_remove(active_modal_actions, action);
1021 }
1022 }
1023 if (haptic) {
1024 if ((action->haptic_flag & XR_HAPTIC_RELEASE) != 0) {
1025 /* Apply haptics. */
1027 action_set_name,
1028 action->haptic_name,
1029 haptic_subaction_path,
1030 &action->haptic_duration,
1031 &action->haptic_frequency,
1032 &action->haptic_amplitude))
1033 {
1035 active_haptic_actions, action, haptic_subaction_path, time_now);
1036 }
1037 }
1038 else if ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0) {
1039 /* Stop any active haptics. */
1040 WM_xr_haptic_action_stop(xr, action_set_name, action->haptic_name, haptic_subaction_path);
1041 wm_xr_session_haptic_action_remove(active_haptic_actions, action);
1042 }
1043 }
1044 }
1045}
1046
1048 wmXrAction *action,
1049 uint subaction_idx,
1050 uint *r_subaction_idx_other,
1051 const GHOST_XrPose **r_aim_pose_other)
1052{
1053 if ((action->action_flag & XR_ACTION_BIMANUAL) == 0) {
1054 return false;
1055 }
1056
1057 bool bimanual = false;
1058
1059 *r_subaction_idx_other = (subaction_idx == 0) ?
1060 uint(min_ii(1, action->count_subaction_paths - 1)) :
1061 0;
1062
1063 switch (action->type) {
1064 case XR_BOOLEAN_INPUT: {
1065 const bool *state = &((bool *)action->states)[*r_subaction_idx_other];
1066 if (*state) {
1067 bimanual = true;
1068 }
1069 break;
1070 }
1071 case XR_FLOAT_INPUT: {
1072 const float *state = &((float *)action->states)[*r_subaction_idx_other];
1074 action->float_thresholds[*r_subaction_idx_other],
1075 action->axis_flags[*r_subaction_idx_other]))
1076 {
1077 bimanual = true;
1078 }
1079 break;
1080 }
1081 case XR_VECTOR2F_INPUT: {
1082 const float (*state)[2] = &((float (*)[2])action->states)[*r_subaction_idx_other];
1084 action->float_thresholds[*r_subaction_idx_other],
1085 action->axis_flags[*r_subaction_idx_other]))
1086 {
1087 bimanual = true;
1088 }
1089 break;
1090 }
1091 case XR_POSE_INPUT:
1094 break;
1095 }
1096
1097 if (bimanual) {
1098 *r_aim_pose_other = wm_xr_session_controller_aim_pose_find(
1099 session_state, action->subaction_paths[*r_subaction_idx_other]);
1100 }
1101
1102 return bimanual;
1103}
1104
1105static wmXrActionData *wm_xr_session_event_create(const char *action_set_name,
1106 const wmXrAction *action,
1107 const GHOST_XrPose *controller_aim_pose,
1108 const GHOST_XrPose *controller_aim_pose_other,
1109 uint subaction_idx,
1110 uint subaction_idx_other,
1111 bool bimanual)
1112{
1113 wmXrActionData *data = MEM_callocN<wmXrActionData>(__func__);
1114 STRNCPY(data->action_set, action_set_name);
1115 STRNCPY(data->action, action->name);
1116 STRNCPY(data->user_path, action->subaction_paths[subaction_idx]);
1117 if (bimanual) {
1118 STRNCPY(data->user_path_other, action->subaction_paths[subaction_idx_other]);
1119 }
1120 data->type = action->type;
1121
1122 switch (action->type) {
1123 case XR_BOOLEAN_INPUT:
1124 data->state[0] = ((bool *)action->states)[subaction_idx] ? 1.0f : 0.0f;
1125 if (bimanual) {
1126 data->state_other[0] = ((bool *)action->states)[subaction_idx_other] ? 1.0f : 0.0f;
1127 }
1128 break;
1129 case XR_FLOAT_INPUT:
1130 data->state[0] = ((float *)action->states)[subaction_idx];
1131 if (bimanual) {
1132 data->state_other[0] = ((float *)action->states)[subaction_idx_other];
1133 }
1134 data->float_threshold = action->float_thresholds[subaction_idx];
1135 break;
1136 case XR_VECTOR2F_INPUT:
1137 copy_v2_v2(data->state, ((float (*)[2])action->states)[subaction_idx]);
1138 if (bimanual) {
1139 copy_v2_v2(data->state_other, ((float (*)[2])action->states)[subaction_idx_other]);
1140 }
1141 data->float_threshold = action->float_thresholds[subaction_idx];
1142 break;
1143 case XR_POSE_INPUT:
1146 break;
1147 }
1148
1149 if (controller_aim_pose) {
1150 copy_v3_v3(data->controller_loc, controller_aim_pose->position);
1151 copy_qt_qt(data->controller_rot, controller_aim_pose->orientation_quat);
1152
1153 if (bimanual && controller_aim_pose_other) {
1154 copy_v3_v3(data->controller_loc_other, controller_aim_pose_other->position);
1155 copy_qt_qt(data->controller_rot_other, controller_aim_pose_other->orientation_quat);
1156 }
1157 else {
1158 data->controller_rot_other[0] = 1.0f;
1159 }
1160 }
1161 else {
1162 data->controller_rot[0] = 1.0f;
1163 data->controller_rot_other[0] = 1.0f;
1164 }
1165
1166 data->ot = action->ot;
1167 data->op_properties = action->op_properties;
1168
1169 data->bimanual = bimanual;
1170
1171 return data;
1172}
1173
1174/* Dispatch events to window queues. */
1176 GHOST_XrContextHandle xr_context,
1177 wmXrActionSet *action_set,
1178 wmXrSessionState *session_state,
1179 wmWindow *win)
1180{
1181 const char *action_set_name = action_set->name;
1182
1183 const uint count = GHOST_XrGetActionCount(xr_context, action_set_name);
1184 if (count < 1) {
1185 return;
1186 }
1187
1188 const int64_t time_now = int64_t(BLI_time_now_seconds() * 1000);
1189
1190 ListBase *active_modal_actions = &action_set->active_modal_actions;
1191 ListBase *active_haptic_actions = &action_set->active_haptic_actions;
1192
1193 wmXrAction **actions = MEM_calloc_arrayN<wmXrAction *>(count, __func__);
1194
1195 GHOST_XrGetActionCustomdataArray(xr_context, action_set_name, (void **)actions);
1196
1197 /* Check haptic action timers. */
1198 wm_xr_session_haptic_timers_check(active_haptic_actions, time_now);
1199
1200 for (uint action_idx = 0; action_idx < count; ++action_idx) {
1201 wmXrAction *action = actions[action_idx];
1202 if (action && action->ot) {
1203 const bool modal = action->ot->modal;
1204 const bool haptic = (GHOST_XrGetActionCustomdata(
1205 xr_context, action_set_name, action->haptic_name) != nullptr);
1206
1207 for (uint subaction_idx = 0; subaction_idx < action->count_subaction_paths; ++subaction_idx)
1208 {
1209 short val = KM_NOTHING;
1210
1211 /* Interpret action states (update modal/haptic action lists, apply haptics, etc). */
1213 action_set_name,
1214 action,
1215 subaction_idx,
1216 active_modal_actions,
1217 active_haptic_actions,
1218 time_now,
1219 modal,
1220 haptic,
1221 &val);
1222
1223 const bool is_active_modal_action = wm_xr_session_modal_action_test(
1224 active_modal_actions, action, nullptr);
1225 const bool is_active_modal_subaction = (!action->active_modal_path ||
1226 (action->subaction_paths[subaction_idx] ==
1227 action->active_modal_path));
1228
1229 if ((val != KM_NOTHING) &&
1230 (!modal || (is_active_modal_action && is_active_modal_subaction)))
1231 {
1232 const GHOST_XrPose *aim_pose = wm_xr_session_controller_aim_pose_find(
1233 session_state, action->subaction_paths[subaction_idx]);
1234 const GHOST_XrPose *aim_pose_other = nullptr;
1235 uint subaction_idx_other = 0;
1236
1237 /* Test for bimanual interaction. */
1238 const bool bimanual = wm_xr_session_action_test_bimanual(
1239 session_state, action, subaction_idx, &subaction_idx_other, &aim_pose_other);
1240
1241 wmXrActionData *actiondata = wm_xr_session_event_create(action_set_name,
1242 action,
1243 aim_pose,
1244 aim_pose_other,
1245 subaction_idx,
1246 subaction_idx_other,
1247 bimanual);
1248 wm_event_add_xrevent(win, actiondata, val);
1249 }
1250 }
1251 }
1252 }
1253
1254 MEM_freeN(actions);
1255}
1256
1258{
1259 wmXrData *xr = &wm->xr;
1260 if (!xr->runtime) {
1261 return;
1262 }
1263
1264 XrSessionSettings *settings = &xr->session_settings;
1265 GHOST_XrContextHandle xr_context = xr->runtime->context;
1267
1268 if (state->is_navigation_dirty) {
1269 memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
1270 state->nav_scale_prev = state->nav_scale;
1271 state->is_navigation_dirty = false;
1272
1273 /* Update viewer pose with any navigation changes since the last actions sync so that data
1274 * is correct for queries. */
1275 float m[4][4], viewer_mat[4][4];
1276 wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, m);
1277 mul_m4_m4m4(viewer_mat, m, state->viewer_mat_base);
1278 mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
1280 &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
1281 }
1282
1283 /* Set active action set if requested previously. */
1284 if (state->active_action_set_next[0]) {
1285 WM_xr_active_action_set_set(xr, state->active_action_set_next, false);
1286 state->active_action_set_next[0] = '\0';
1287 }
1288 wmXrActionSet *active_action_set = state->active_action_set;
1289
1290 const bool synced = GHOST_XrSyncActions(xr_context,
1291 active_action_set ? active_action_set->name : nullptr);
1292 if (!synced) {
1293 return;
1294 }
1295
1296 /* Only update controller data and dispatch events for active action set. */
1297 if (active_action_set) {
1299
1300 if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
1302 active_action_set->controller_grip_action,
1303 active_action_set->controller_aim_action,
1304 xr_context,
1305 state);
1306 }
1307
1308 if (win) {
1309 /* Ensure an XR area exists for events. */
1310 if (!xr->runtime->area) {
1312 }
1313
1314 /* Set XR area object type flags for operators. */
1315 View3D *v3d = static_cast<View3D *>(xr->runtime->area->spacedata.first);
1318
1319 wm_xr_session_events_dispatch(xr, xr_context, active_action_set, state, win);
1320 }
1321 }
1322}
1323
1325 const wmXrAction *aim_action,
1326 wmXrData *xr)
1327{
1328 UNUSED_VARS(aim_action); /* Only used for asserts. */
1329
1331 ListBase *controllers = &state->controllers;
1332
1333 BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
1334 const uint count = grip_action->count_subaction_paths;
1335
1337
1338 for (uint i = 0; i < count; ++i) {
1340
1341 BLI_assert(STREQ(grip_action->subaction_paths[i], aim_action->subaction_paths[i]));
1342 STRNCPY(controller->subaction_path, grip_action->subaction_paths[i]);
1343
1344 BLI_addtail(controllers, controller);
1345 }
1346
1347 /* Activate draw callback. */
1348 if (g_xr_surface) {
1349 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1350 if (surface_data && !surface_data->controller_draw_handle) {
1351 if (surface_data->controller_art) {
1354 }
1355 }
1356 }
1357}
1358
1360{
1362
1363 /* Deactivate draw callback. */
1364 if (g_xr_surface) {
1365 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1366 if (surface_data && surface_data->controller_draw_handle) {
1367 if (surface_data->controller_art) {
1368 ED_region_draw_cb_exit(surface_data->controller_art, surface_data->controller_draw_handle);
1369 }
1370 surface_data->controller_draw_handle = nullptr;
1371 }
1372 }
1373}
1374 /* XR-Session Actions. */
1376
1377/* -------------------------------------------------------------------- */
1384
1393{
1395 wmXrDrawData draw_data;
1396
1397 if (!WM_xr_session_is_ready(&wm->xr)) {
1398 return;
1399 }
1400
1401 Scene *scene;
1402 Depsgraph *depsgraph;
1404 /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
1405 * writing for example. */
1406 // BLI_assert(DEG_is_fully_evaluated(depsgraph));
1407 wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
1408
1409 GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
1410
1411 /* There's no active frame-buffer if the session was canceled (exception while drawing views). */
1414 }
1415}
1416
1418{
1420
1421 if (!WM_xr_session_is_ready(&wm->xr)) {
1422 return;
1423 }
1424
1425 Scene *scene;
1426 Depsgraph *depsgraph;
1429}
1430
1432 const GHOST_XrDrawViewInfo *draw_view)
1433{
1434 wmXrViewportPair *vp = nullptr;
1435 if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) {
1436 vp = MEM_callocN<wmXrViewportPair>(__func__);
1437 BLI_addtail(&surface_data->viewports, vp);
1438 }
1439 else {
1440 vp = static_cast<wmXrViewportPair *>(
1441 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
1442 }
1443 BLI_assert(vp);
1444
1445 GPUOffScreen *offscreen = vp->offscreen;
1446 GPUViewport *viewport = vp->viewport;
1447 const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) &&
1448 (GPU_offscreen_height(offscreen) != draw_view->height);
1449 if (offscreen) {
1450 BLI_assert(viewport);
1451
1452 if (!size_changed) {
1453 return true;
1454 }
1455 GPU_viewport_free(viewport);
1456 GPU_offscreen_free(offscreen);
1457 }
1458
1459 char err_out[256] = "unknown";
1460 bool failure = false;
1461
1462 /* Initialize with some unsupported format to check following switch statement. */
1463 blender::gpu::TextureFormat format = blender::gpu::TextureFormat::UNORM_8;
1464
1465 switch (draw_view->swapchain_format) {
1466 case GHOST_kXrSwapchainFormatRGBA8:
1467 format = blender::gpu::TextureFormat::UNORM_8_8_8_8;
1468 break;
1469 case GHOST_kXrSwapchainFormatRGBA16:
1470 format = blender::gpu::TextureFormat::UNORM_16_16_16_16;
1471 break;
1472 case GHOST_kXrSwapchainFormatRGBA16F:
1473 format = blender::gpu::TextureFormat::SFLOAT_16_16_16_16;
1474 break;
1475 case GHOST_kXrSwapchainFormatRGB10_A2:
1476 format = blender::gpu::TextureFormat::UNORM_10_10_10_2;
1477 break;
1478 }
1479 BLI_assert(format != blender::gpu::TextureFormat::UNORM_8);
1480
1481 offscreen = vp->offscreen = GPU_offscreen_create(draw_view->width,
1482 draw_view->height,
1483 true,
1484 format,
1487 false,
1488 err_out);
1489 if (offscreen) {
1490 viewport = vp->viewport = GPU_viewport_create();
1491 if (!viewport) {
1492 GPU_offscreen_free(offscreen);
1493 offscreen = vp->offscreen = nullptr;
1494 failure = true;
1495 }
1496 }
1497 else {
1498 failure = true;
1499 }
1500
1501 if (failure) {
1502 CLOG_ERROR(&LOG, "Failed to get buffer, %s", err_out);
1503 return false;
1504 }
1505
1506 return true;
1507}
1508
1510{
1511 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(surface->customdata);
1512 ListBase *lb = &data->viewports;
1513
1514 while (wmXrViewportPair *vp = static_cast<wmXrViewportPair *>(BLI_pophead(lb))) {
1515 if (vp->viewport) {
1516 GPU_viewport_free(vp->viewport);
1517 }
1518 if (vp->offscreen) {
1519 GPU_offscreen_free(vp->offscreen);
1520 }
1521 BLI_freelinkN(lb, vp);
1522 }
1523
1524 if (data->controller_art) {
1525 BLI_freelistN(&data->controller_art->drawcalls);
1526 MEM_freeN(data->controller_art);
1527 }
1528
1529 MEM_freeN(surface->customdata);
1530
1531 g_xr_surface = nullptr;
1532}
1533
1535{
1536 if (g_xr_surface) {
1537 BLI_assert(false);
1538 return g_xr_surface;
1539 }
1540
1541 wmSurface *surface = MEM_callocN<wmSurface>(__func__);
1543 data->controller_art = MEM_callocN<ARegionType>("XrControllerRegionType");
1544
1548 surface->activate = DRW_xr_drawing_begin;
1549 surface->deactivate = DRW_xr_drawing_end;
1550
1551 surface->system_gpu_context = static_cast<GHOST_ContextHandle>(DRW_system_gpu_context_get());
1552 surface->blender_gpu_context = static_cast<GPUContext *>(DRW_xr_blender_gpu_context_get());
1553
1554 data->controller_art->regionid = RGN_TYPE_XR;
1555 surface->customdata = data;
1556
1557 g_xr_surface = surface;
1558
1559 return surface;
1560}
1561
1563{
1565
1566 wm_surface_add(surface);
1567
1568 /* Some regions may need to redraw with updated session state after the session is entirely up
1569 * and running. */
1571
1572 return surface->system_gpu_context;
1573}
1574
1575void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle /*context*/)
1576{
1577 if (g_xr_surface) { /* Might have been freed already. */
1579 }
1580
1582
1583 /* Some regions may need to redraw with updated session state after the session is entirely
1584 * stopped. */
1586}
1587
1589{
1590 if (g_xr_surface) {
1591 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1592 return data->controller_art;
1593 }
1594
1595 return nullptr;
1596}
1597 /* XR-Session Surface. */
void BKE_callback_exec_null(Main *bmain, eCbEvent evt)
Definition callbacks.cc:38
@ BKE_CB_EVT_XR_SESSION_START_PRE
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define G_MAIN
bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:1004
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2626
Depsgraph * BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_layer)
Definition scene.cc:3403
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
MINLINE int min_ii(int a, int b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
#define BLI_ASSERT_UNIT_QUAT(q)
MINLINE float interpf(float target, float origin, float t)
#define M_PI_2
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4])
void unit_m4(float m[4][4])
void axis_angle_to_quat_single(float q[4], char axis, float angle)
void unit_qt(float q[4])
void eul_to_quat(float quat[4], const float eul[3])
float fov_to_focallength(float hfov, float sensor)
void quat_to_eul(float eul[3], const float quat[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define CLAMP(a, b, c)
#define UNUSED_VARS(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define DEFAULT_SENSOR_WIDTH
@ RGN_TYPE_XR
@ SPACE_VIEW3D
@ XR_OP_RELEASE
@ XR_OP_PRESS
eXrAxisFlag
@ XR_AXIS0_POS
@ XR_AXIS1_NEG
@ XR_AXIS1_POS
@ XR_AXIS0_NEG
@ XR_SESSION_USE_ABSOLUTE_TRACKING
@ XR_SESSION_USE_POSITION_TRACKING
@ XR_FLOAT_INPUT
@ XR_BOOLEAN_INPUT
@ XR_VECTOR2F_INPUT
@ XR_POSE_INPUT
@ XR_VIBRATION_OUTPUT
@ XR_BASE_POSE_CUSTOM
@ XR_BASE_POSE_OBJECT
@ XR_ACTION_BIMANUAL
@ XR_HAPTIC_PRESS
@ XR_HAPTIC_RELEASE
@ XR_HAPTIC_MATCHUSERPATHS
@ XR_HAPTIC_REPEAT
ScrArea * ED_area_offscreen_create(wmWindow *win, eSpace_Type space_type)
Definition area.cc:2238
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
static Controller * controller
GHOST C-API function and type declarations.
void GPU_batch_discard(blender::gpu::Batch *batch)
int GPU_offscreen_width(const GPUOffScreen *offscreen)
void GPU_framebuffer_restore()
int GPU_offscreen_height(const GPUOffScreen *offscreen)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, blender::gpu::TextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
void GPU_offscreen_free(GPUOffScreen *offscreen)
blender::gpu::FrameBuffer * GPU_framebuffer_active_get()
@ GPU_TEXTURE_USAGE_MEMORY_EXPORT
@ GPU_TEXTURE_USAGE_SHADER_READ
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define NC_WM
Definition WM_types.hh:374
@ KM_NOTHING
Definition WM_types.hh:310
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
#define ND_XR_DATA_CHANGED
Definition WM_types.hh:418
#define U
BMesh const char void * data
BPy_StructRNA * depsgraph
long long int int64_t
nullptr float
#define offsetof(t, d)
int count
format
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong state[N]
#define fabsf
void * data
void * first
ListBase wm
Definition BKE_main.hh:307
struct Object * camera
ListBase spacedata
int object_type_exclude_select
int object_type_exclude_viewport
float base_pose_location[3]
Object * base_pose_object
int object_type_exclude_viewport
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1081
void(* activate)()
Definition wm_surface.hh:35
GPUContext * blender_gpu_context
Definition wm_surface.hh:24
void(* draw)(bContext *)
Definition wm_surface.hh:28
GHOST_ContextHandle system_gpu_context
Definition wm_surface.hh:23
void * customdata
Definition wm_surface.hh:26
void(* deactivate)()
Definition wm_surface.hh:37
void(* do_depsgraph)(bContext *C)
Definition wm_surface.hh:30
void(* free_data)(wmSurface *)
Definition wm_surface.hh:32
wmXrAction * controller_aim_action
wmXrAction * controller_grip_action
ListBase active_modal_actions
ListBase active_haptic_actions
eXrActionType type
struct wmOperatorType * ot
eXrAxisFlag * axis_flags
char * haptic_name
unsigned int count_subaction_paths
void * states_prev
eXrOpFlag op_flag
float haptic_frequency
int64_t haptic_duration
eXrActionFlag action_flag
const char * active_modal_path
char ** subaction_paths
float * float_thresholds
float haptic_amplitude
eXrHapticFlag haptic_flag
IDProperty * op_properties
XrSessionSettings session_settings
struct wmXrRuntimeData * runtime
wmXrData * xr_data
float eye_position_ofs[3]
struct Depsgraph * depsgraph
GHOST_XrPose base_pose
wmXrSurfaceData * surface_data
struct Scene * scene
const char * subaction_path
wmXrAction * action
GHOST_XrContextHandle context
wmXrSessionExitFn exit_fn
wmXrSessionState session_state
wmWindow * session_root_win
struct ScrArea * area
float viewer_viewmat[4][4]
GHOST_XrPose nav_pose
bool force_reset_to_base_pose
GHOST_XrPose viewer_pose
struct wmXrVignetteData * vignette_data
struct ARegionType * controller_art
void * controller_draw_handle
struct GPUViewport * viewport
struct GPUOffScreen * offscreen
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
void wm_surface_add(wmSurface *surface)
Definition wm_surface.cc:97
void wm_surface_remove(wmSurface *surface)
void wm_window_reset_drawable()
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:145
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
Definition wm_xr.cc:170
void(*)(const wmXrData *xr_data) wmXrSessionExitFn
Definition wm_xr.hh:15
void WM_xr_haptic_action_stop(wmXrData *xr, const char *action_set_name, const char *action_name, const char *subaction_path)
bool WM_xr_haptic_action_apply(wmXrData *xr, const char *action_set_name, const char *action_name, const char *subaction_path, const int64_t *duration, const float *frequency, const float *amplitude)
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool delayed)
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
Definition wm_xr_draw.cc:39
void wm_xr_draw_controllers(const bContext *, ARegion *, void *customdata)
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
Definition wm_xr_draw.cc:45
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
Definition wm_xr_draw.cc:63
void WM_xr_session_state_vignette_activate(wmXrData *xr)
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale)
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle)
BLI_INLINE bool test_float_state(const float *state, float threshold, eXrAxisFlag flag)
void wm_xr_session_actions_update(wmWindowManager *wm)
ScrArea * WM_xr_session_area_get(const wmXrData *xr)
void wm_xr_session_draw_data_update(wmXrSessionState *state, const XrSessionSettings *settings, const GHOST_XrDrawViewInfo *draw_view, wmXrDrawData *draw_data)
static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose, const float view_ofs[3], const float base_mat[4][4], const float nav_mat[4][4], GHOST_XrPose *r_pose, float r_mat[4][4], float r_mat_base[4][4])
void * wm_xr_session_gpu_binding_context_create()
static void wm_xr_session_haptic_timers_check(ListBase *active_haptic_actions, int64_t time_now)
wmXrSessionState * WM_xr_session_state_handle_get(const wmXrData *xr)
static wmXrActionData * wm_xr_session_event_create(const char *action_set_name, const wmXrAction *action, const GHOST_XrPose *controller_aim_pose, const GHOST_XrPose *controller_aim_pose_other, uint subaction_idx, uint subaction_idx_other, bool bimanual)
void WM_xr_session_base_pose_reset(wmXrData *xr)
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
static void wm_xr_session_haptic_action_remove(ListBase *active_haptic_actions, const wmXrAction *action)
static void wm_xr_session_exit_cb(void *customdata)
bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr, uint subaction_idx, float r_location[3])
static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState *state, const XrSessionSettings *settings)
static void wm_xr_session_events_dispatch(wmXrData *xr, GHOST_XrContextHandle xr_context, wmXrActionSet *action_set, wmXrSessionState *session_state, wmWindow *win)
static void wm_xr_session_do_depsgraph(bContext *C)
static wmXrHapticAction * wm_xr_session_haptic_action_find(ListBase *active_haptic_actions, const wmXrAction *action, const char *subaction_path)
static void wm_xr_session_raycast_model_free(wmXrSessionState *state)
static void wm_xr_session_base_pose_calc(const Scene *scene, const XrSessionSettings *settings, GHOST_XrPose *r_base_pose, float *r_base_scale)
static void wm_xr_session_modal_action_test_add(ListBase *active_modal_actions, const wmXrAction *action)
void WM_xr_session_state_navigation_reset(wmXrSessionState *state)
BLI_INLINE bool test_vec2f_state(const float state[2], float threshold, eXrAxisFlag flag)
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr, uint subaction_idx, float r_rotation[4])
static void wm_xr_session_modal_action_remove(ListBase *active_modal_actions, const wmXrAction *action)
static void wm_xr_session_surface_free_data(wmSurface *surface)
static wmSurface * g_xr_surface
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *session_root_win, wmXrSessionExitFn session_exit_fn)
void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, const wmXrAction *aim_action, wmXrData *xr)
static void wm_xr_session_vignette_data_free(wmXrSessionState *state)
static void wm_xr_session_surface_draw(bContext *C)
Call Ghost-XR to draw a frame.
static void wm_xr_session_controller_data_update(const XrSessionSettings *settings, const wmXrAction *grip_action, const wmXrAction *aim_action, GHOST_XrContextHandle xr_context, wmXrSessionState *state)
wmWindow * wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm, const wmXrRuntimeData *runtime_data)
void WM_xr_session_state_vignette_reset(wmXrSessionState *state)
void WM_xr_session_state_vignette_update(wmXrSessionState *state)
void wm_xr_session_state_update(const XrSessionSettings *settings, const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, wmXrSessionState *state)
static bool wm_xr_session_modal_action_test(const ListBase *active_modal_actions, const wmXrAction *action, bool *r_found)
static void wm_xr_session_controller_data_free(wmXrSessionState *state)
void wm_xr_session_controller_data_clear(wmXrSessionState *state)
static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, const XrSessionSettings *settings)
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])
static void wm_xr_session_scene_and_depsgraph_get(const wmWindowManager *wm, Scene **r_scene, Depsgraph **r_depsgraph)
static const GHOST_XrPose * wm_xr_session_controller_aim_pose_find(const wmXrSessionState *state, const char *subaction_path)
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, float r_viewmat[4][4], float *r_focal_len)
void wm_xr_session_data_free(wmXrSessionState *state)
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
wmXrSessionStateEvent
@ SESSION_STATE_EVENT_NONE
@ SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE
@ SESSION_STATE_EVENT_START
@ SESSION_STATE_EVENT_RESET_TO_BASE_POSE
bool WM_xr_session_is_ready(const wmXrData *xr)
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
bool WM_xr_session_exists(const wmXrData *xr)
ARegionType * WM_xr_surface_controller_region_type_get()
static wmSurface * wm_xr_session_surface_create()
bool WM_xr_session_state_controller_grip_location_get(const wmXrData *xr, uint subaction_idx, float r_location[3])
void wm_xr_session_actions_init(wmXrData *xr)
bool WM_xr_session_state_controller_grip_rotation_get(const wmXrData *xr, uint subaction_idx, float r_rotation[4])
static void wm_xr_session_begin_info_create(wmXrData *xr_data, GHOST_XrSessionBeginInfo *r_begin_info)
void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
static void wm_xr_session_haptic_action_add(ListBase *active_haptic_actions, const wmXrAction *action, const char *subaction_path, int64_t time_now)
static void wm_xr_session_draw_data_populate(wmXrData *xr_data, Scene *scene, Depsgraph *depsgraph, wmXrDrawData *r_draw_data)
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])
static bool wm_xr_session_action_test_bimanual(const wmXrSessionState *session_state, wmXrAction *action, uint subaction_idx, uint *r_subaction_idx_other, const GHOST_XrPose **r_aim_pose_other)
static void wm_xr_session_action_states_interpret(wmXrData *xr, const char *action_set_name, wmXrAction *action, uint subaction_idx, ListBase *active_modal_actions, ListBase *active_haptic_actions, int64_t time_now, bool modal, bool haptic, short *r_val)
static void wm_xr_session_create_cb()