Blender V4.5
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 = {"wm.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
77{
78 ListBase *lb = &state->controllers;
79 while (wmXrController *c = static_cast<wmXrController *>(BLI_pophead(lb))) {
80 if (c->model) {
81 GPU_batch_discard(c->model);
82 }
83 BLI_freelinkN(lb, c);
84 }
85}
86
91
92static void wm_xr_session_exit_cb(void *customdata)
93{
94 wmXrData *xr_data = static_cast<wmXrData *>(customdata);
95 if (!xr_data->runtime) {
96 return;
97 }
98
99 xr_data->runtime->session_state.is_started = false;
100
101 if (xr_data->runtime->exit_fn) {
102 xr_data->runtime->exit_fn(xr_data);
103 }
104
105 /* Free the entire runtime data (including session state and context), to play safe. */
107}
108
110 GHOST_XrSessionBeginInfo *r_begin_info)
111{
112 /* Callback for when the session is created. This is needed to create and bind OpenXR actions
113 * after the session is created but before it is started. */
114 r_begin_info->create_fn = wm_xr_session_create_cb;
115
116 /* WM-XR exit function, does some of its own stuff and calls callback passed to
117 * wm_xr_session_toggle(), to allow external code to execute its own session-exit logic. */
118 r_begin_info->exit_fn = wm_xr_session_exit_cb;
119 r_begin_info->exit_customdata = xr_data;
120}
121
123 wmWindow *session_root_win,
124 wmXrSessionExitFn session_exit_fn)
125{
126 wmXrData *xr_data = &wm->xr;
127
128 if (WM_xr_session_exists(xr_data)) {
129 /* Must set first, since #GHOST_XrSessionEnd() may immediately free the runtime. */
130 xr_data->runtime->session_state.is_started = false;
131
132 GHOST_XrSessionEnd(xr_data->runtime->context);
133 }
134 else {
135 GHOST_XrSessionBeginInfo begin_info;
136
137 xr_data->runtime->session_root_win = session_root_win;
138 xr_data->runtime->session_state.is_started = true;
139 xr_data->runtime->exit_fn = session_exit_fn;
140
141 wm_xr_session_begin_info_create(xr_data, &begin_info);
142 GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
143 }
144}
145
147{
148 return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
149}
150
155
157{
158 return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
159}
160
161static void wm_xr_session_base_pose_calc(const Scene *scene,
162 const XrSessionSettings *settings,
163 GHOST_XrPose *r_base_pose,
164 float *r_base_scale)
165{
166 const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
167 settings->base_pose_object) ?
168 settings->base_pose_object :
169 scene->camera;
170
171 if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
172 float tmp_quatx[4], tmp_quatz[4];
173
174 copy_v3_v3(r_base_pose->position, settings->base_pose_location);
175 axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
176 axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
177 mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
178 }
179 else if (base_pose_object) {
180 float tmp_quat[4];
181 float tmp_eul[3];
182
183 mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->object_to_world().ptr());
184
185 /* Only use rotation around Z-axis to align view with floor. */
186 quat_to_eul(tmp_eul, tmp_quat);
187 tmp_eul[0] = M_PI_2;
188 tmp_eul[1] = 0;
189 eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
190 }
191 else {
192 copy_v3_fl(r_base_pose->position, 0.0f);
193 axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
194 }
195
196 *r_base_scale = settings->base_scale;
197}
198
200 Scene *scene,
201 Depsgraph *depsgraph,
202 wmXrDrawData *r_draw_data)
203{
204 const XrSessionSettings *settings = &xr_data->session_settings;
205
206 memset(r_draw_data, 0, sizeof(*r_draw_data));
207 r_draw_data->scene = scene;
208 r_draw_data->depsgraph = depsgraph;
209 r_draw_data->xr_data = xr_data;
210 r_draw_data->surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
211
213 r_draw_data->scene, settings, &r_draw_data->base_pose, &r_draw_data->base_scale);
214}
215
217 const wmXrRuntimeData *runtime_data)
218{
219 if (runtime_data->session_root_win &&
220 BLI_findindex(&wm->windows, runtime_data->session_root_win) != -1)
221 {
222 /* Root window is still valid, use it. */
223 return runtime_data->session_root_win;
224 }
225 /* Otherwise, fall back. */
226 return static_cast<wmWindow *>(wm->windows.first);
227}
228
237 Scene **r_scene,
238 Depsgraph **r_depsgraph)
239{
241
242 /* Follow the scene & view layer shown in the root 3D View. */
243 Scene *scene = WM_window_get_active_scene(root_win);
244 ViewLayer *view_layer = WM_window_get_active_view_layer(root_win);
245
246 Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
247 BLI_assert(scene && view_layer && depsgraph);
248 *r_scene = scene;
249 *r_depsgraph = depsgraph;
250}
251
258
260 const XrSessionSettings *settings)
261{
262 if (state->force_reset_to_base_pose) {
263 return true;
264 }
265 return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) &&
266 ((state->prev_base_pose_type != settings->base_pose_type) ||
267 (state->prev_base_pose_object != settings->base_pose_object));
268}
269
271 const XrSessionSettings *settings)
272{
273 if (!state->is_view_data_set) {
275 }
278 }
279
280 const bool position_tracking_toggled = ((state->prev_settings_flag &
283 if (position_tracking_toggled) {
285 }
286
288}
289
291 const XrSessionSettings *settings,
292 const GHOST_XrDrawViewInfo *draw_view,
293 wmXrDrawData *draw_data)
294{
296 const bool use_position_tracking = (settings->flag & XR_SESSION_USE_POSITION_TRACKING);
297
298 switch (event) {
300 if (use_position_tracking) {
301 /* We want to start the session exactly at landmark position.
302 * Run-times may have a non-[0,0,0] starting position that we have to subtract for that. */
303 copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
304 }
305 else {
306 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
307 }
308 break;
309 /* This should be triggered by the VR add-on if a landmark changes. */
311 if (use_position_tracking) {
312 /* Switch exactly to base pose, so use eye offset to cancel out current position delta. */
313 copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
314 }
315 else {
316 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
317 }
318 /* Reset navigation. */
320 break;
322 if (use_position_tracking) {
323 /* Keep the current position, and let the user move from there. */
324 copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
325 }
326 else {
327 /* Back to the exact base-pose position. */
328 copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
329 }
330 break;
332 /* Keep previous offset when positional tracking is disabled. */
333 copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
334 break;
335 }
336}
337
339 const wmXrDrawData *draw_data,
340 const GHOST_XrDrawViewInfo *draw_view,
342{
343 GHOST_XrPose viewer_pose;
344 float viewer_mat[4][4], base_mat[4][4], nav_mat[4][4];
345
346 /* Calculate viewer matrix. */
347 copy_qt_qt(viewer_pose.orientation_quat, draw_view->local_pose.orientation_quat);
348 if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
349 zero_v3(viewer_pose.position);
350 }
351 else {
352 copy_v3_v3(viewer_pose.position, draw_view->local_pose.position);
353 }
354 if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
355 sub_v3_v3(viewer_pose.position, draw_data->eye_position_ofs);
356 }
357 wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
358
359 /* Apply base pose and navigation. */
360 wm_xr_pose_scale_to_mat(&draw_data->base_pose, draw_data->base_scale, base_mat);
361 wm_xr_pose_scale_to_mat(&state->nav_pose_prev, state->nav_scale_prev, nav_mat);
362 mul_m4_m4m4(state->viewer_mat_base, base_mat, viewer_mat);
363 mul_m4_m4m4(viewer_mat, nav_mat, state->viewer_mat_base);
364
365 /* Save final viewer pose and viewmat. */
366 mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
368 &state->viewer_pose, draw_data->base_scale * state->nav_scale_prev, state->viewer_viewmat);
369
370 /* No idea why, but multiplying by two seems to make it match the VR view more. */
371 state->focal_len = 2.0f *
372 fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
374
375 copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
376 memcpy(&state->prev_base_pose, &draw_data->base_pose, sizeof(state->prev_base_pose));
377 state->prev_base_scale = draw_data->base_scale;
378 memcpy(&state->prev_local_pose, &draw_view->local_pose, sizeof(state->prev_local_pose));
379 copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
380
381 state->prev_settings_flag = settings->flag;
382 state->prev_base_pose_type = settings->base_pose_type;
383 state->prev_base_pose_object = settings->base_pose_object;
384 state->is_view_data_set = true;
385 /* Assume this was already done through wm_xr_session_draw_data_update(). */
386 state->force_reset_to_base_pose = false;
387}
388
390{
391 return xr->runtime ? &xr->runtime->session_state : nullptr;
392}
393
395{
396 return xr->runtime ? xr->runtime->area : nullptr;
397}
398
399bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
400{
402 zero_v3(r_location);
403 return false;
404 }
405
406 copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
407 return true;
408}
409
410bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
411{
413 unit_qt(r_rotation);
414 return false;
415 }
416
417 copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
418 return true;
419}
420
422 float r_viewmat[4][4],
423 float *r_focal_len)
424{
426 unit_m4(r_viewmat);
427 *r_focal_len = 0.0f;
428 return false;
429 }
430
432 *r_focal_len = xr->runtime->session_state.focal_len;
433
434 return true;
435}
436
438 uint subaction_idx,
439 float r_location[3])
440{
442 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
443 {
444 zero_v3(r_location);
445 return false;
446 }
447
448 const wmXrController *controller = static_cast<const wmXrController *>(
449 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
451 copy_v3_v3(r_location, controller->grip_pose.position);
452 return true;
453}
454
456 uint subaction_idx,
457 float r_rotation[4])
458{
460 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
461 {
462 unit_qt(r_rotation);
463 return false;
464 }
465
466 const wmXrController *controller = static_cast<const wmXrController *>(
467 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
469 copy_qt_qt(r_rotation, controller->grip_pose.orientation_quat);
470 return true;
471}
472
474 uint subaction_idx,
475 float r_location[3])
476{
478 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
479 {
480 zero_v3(r_location);
481 return false;
482 }
483
484 const wmXrController *controller = static_cast<const wmXrController *>(
485 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
487 copy_v3_v3(r_location, controller->aim_pose.position);
488 return true;
489}
490
492 uint subaction_idx,
493 float r_rotation[4])
494{
496 (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers)))
497 {
498 unit_qt(r_rotation);
499 return false;
500 }
501
502 const wmXrController *controller = static_cast<const wmXrController *>(
503 BLI_findlink(&xr->runtime->session_state.controllers, subaction_idx));
505 copy_qt_qt(r_rotation, controller->aim_pose.orientation_quat);
506 return true;
507}
508
509bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3])
510{
512 zero_v3(r_location);
513 return false;
514 }
515
516 copy_v3_v3(r_location, xr->runtime->session_state.nav_pose.position);
517 return true;
518}
519
520void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3])
521{
522 if (WM_xr_session_exists(xr)) {
523 copy_v3_v3(xr->runtime->session_state.nav_pose.position, location);
525 }
526}
527
528bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])
529{
531 unit_qt(r_rotation);
532 return false;
533 }
534
535 copy_qt_qt(r_rotation, xr->runtime->session_state.nav_pose.orientation_quat);
536 return true;
537}
538
539void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
540{
541 if (WM_xr_session_exists(xr)) {
542 BLI_ASSERT_UNIT_QUAT(rotation);
543 copy_qt_qt(xr->runtime->session_state.nav_pose.orientation_quat, rotation);
545 }
546}
547
548bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
549{
551 *r_scale = 1.0f;
552 return false;
553 }
554
555 *r_scale = xr->runtime->session_state.nav_scale;
556 return true;
557}
558
560{
561 if (WM_xr_session_exists(xr)) {
562 /* Clamp to reasonable values. */
564 xr->runtime->session_state.nav_scale = scale;
566 }
567}
568
570{
571 zero_v3(state->nav_pose.position);
572 unit_qt(state->nav_pose.orientation_quat);
573 state->nav_scale = 1.0f;
574 state->is_navigation_dirty = true;
575}
576
577/* -------------------------------------------------------------------- */
583
585{
586 if (!xr->runtime) {
587 return;
588 }
589
590 GHOST_XrAttachActionSets(xr->runtime->context);
591}
592
593static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
594 const float view_ofs[3],
595 const float base_mat[4][4],
596 const float nav_mat[4][4],
597 GHOST_XrPose *r_pose,
598 float r_mat[4][4],
599 float r_mat_base[4][4])
600{
601 float m[4][4];
602 /* Calculate controller matrix in world space. */
603 wm_xr_pose_to_mat(raw_pose, m);
604
605 /* Apply eye position offset. */
606 sub_v3_v3(m[3], view_ofs);
607
608 /* Apply base pose and navigation. */
609 mul_m4_m4m4(r_mat_base, base_mat, m);
610 mul_m4_m4m4(r_mat, nav_mat, r_mat_base);
611
612 /* Save final pose. */
613 mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat);
614}
615
617 const wmXrAction *grip_action,
618 const wmXrAction *aim_action,
619 GHOST_XrContextHandle xr_context,
621{
622 BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
623 BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers));
624
625 uint subaction_idx = 0;
626 float view_ofs[3], base_mat[4][4], nav_mat[4][4];
627
628 if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
629 copy_v3_v3(view_ofs, state->prev_local_pose.position);
630 }
631 else {
632 zero_v3(view_ofs);
633 }
634 if ((settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
635 add_v3_v3(view_ofs, state->prev_eye_position_ofs);
636 }
637
638 wm_xr_pose_scale_to_mat(&state->prev_base_pose, state->prev_base_scale, base_mat);
639 wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, nav_mat);
640
641 LISTBASE_FOREACH_INDEX (wmXrController *, controller, &state->controllers, subaction_idx) {
642 controller->grip_active = ((GHOST_XrPose *)grip_action->states)[subaction_idx].is_active;
643 wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx],
644 view_ofs,
645 base_mat,
646 nav_mat,
647 &controller->grip_pose,
648 controller->grip_mat,
649 controller->grip_mat_base);
650 controller->aim_active = ((GHOST_XrPose *)aim_action->states)[subaction_idx].is_active;
651 wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx],
652 view_ofs,
653 base_mat,
654 nav_mat,
655 &controller->aim_pose,
656 controller->aim_mat,
657 controller->aim_mat_base);
658
659 if (!controller->model) {
660 /* Notify GHOST to load/continue loading the controller model data. This can be called more
661 * than once since the model may not be available from the runtime yet. The batch itself will
662 * be created in wm_xr_draw_controllers(). */
663 GHOST_XrLoadControllerModel(xr_context, controller->subaction_path);
664 }
665 else {
666 GHOST_XrUpdateControllerModelComponents(xr_context, controller->subaction_path);
667 }
668 }
669}
670
672 const char *subaction_path)
673{
674 const wmXrController *controller = static_cast<const wmXrController *>(BLI_findstring(
675 &state->controllers, subaction_path, offsetof(wmXrController, subaction_path)));
676 return controller ? &controller->aim_pose : nullptr;
677}
678
679BLI_INLINE bool test_float_state(const float *state, float threshold, eXrAxisFlag flag)
680{
681 if ((flag & XR_AXIS0_POS) != 0) {
682 if (*state > threshold) {
683 return true;
684 }
685 }
686 else if ((flag & XR_AXIS0_NEG) != 0) {
687 if (*state < -threshold) {
688 return true;
689 }
690 }
691 else {
692 if (fabsf(*state) > threshold) {
693 return true;
694 }
695 }
696 return false;
697}
698
699BLI_INLINE bool test_vec2f_state(const float state[2], float threshold, eXrAxisFlag flag)
700{
701 if ((flag & XR_AXIS0_POS) != 0) {
702 if (state[0] < 0.0f) {
703 return false;
704 }
705 }
706 else if ((flag & XR_AXIS0_NEG) != 0) {
707 if (state[0] > 0.0f) {
708 return false;
709 }
710 }
711 if ((flag & XR_AXIS1_POS) != 0) {
712 if (state[1] < 0.0f) {
713 return false;
714 }
715 }
716 else if ((flag & XR_AXIS1_NEG) != 0) {
717 if (state[1] > 0.0f) {
718 return false;
719 }
720 }
721 return (len_v2(state) > threshold);
722}
723
724static bool wm_xr_session_modal_action_test(const ListBase *active_modal_actions,
725 const wmXrAction *action,
726 bool *r_found)
727{
728 if (r_found) {
729 *r_found = false;
730 }
731
732 LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
733 wmXrAction *active_modal_action = static_cast<wmXrAction *>(ld->data);
734 if (action == active_modal_action) {
735 if (r_found) {
736 *r_found = true;
737 }
738 return true;
739 }
740 if (action->ot == active_modal_action->ot &&
741 IDP_EqualsProperties(action->op_properties, active_modal_action->op_properties))
742 {
743 /* Don't allow duplicate modal operators since this can lead to unwanted modal handler
744 * behavior. */
745 return false;
746 }
747 }
748
749 return true;
750}
751
752static void wm_xr_session_modal_action_test_add(ListBase *active_modal_actions,
753 const wmXrAction *action)
754{
755 bool found;
756 if (wm_xr_session_modal_action_test(active_modal_actions, action, &found) && !found) {
757 LinkData *ld = MEM_callocN<LinkData>(__func__);
758 ld->data = (void *)action;
759 BLI_addtail(active_modal_actions, ld);
760 }
761}
762
763static void wm_xr_session_modal_action_remove(ListBase *active_modal_actions,
764 const wmXrAction *action)
765{
766 LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
767 if (action == ld->data) {
768 BLI_freelinkN(active_modal_actions, ld);
769 return;
770 }
771 }
772}
773
775 const wmXrAction *action,
776 const char *subaction_path)
777{
778 LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
779 if ((action == ha->action) && (subaction_path == ha->subaction_path)) {
780 return ha;
781 }
782 }
783 return nullptr;
784}
785
786static void wm_xr_session_haptic_action_add(ListBase *active_haptic_actions,
787 const wmXrAction *action,
788 const char *subaction_path,
789 int64_t time_now)
790{
792 active_haptic_actions, action, subaction_path);
793 if (ha) {
794 /* Reset start time since OpenXR restarts haptics if they are already active. */
795 ha->time_start = time_now;
796 }
797 else {
798 ha = MEM_callocN<wmXrHapticAction>(__func__);
799 ha->action = (wmXrAction *)action;
800 ha->subaction_path = subaction_path;
801 ha->time_start = time_now;
802 BLI_addtail(active_haptic_actions, ha);
803 }
804}
805
806static void wm_xr_session_haptic_action_remove(ListBase *active_haptic_actions,
807 const wmXrAction *action)
808{
809 LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
810 if (action == ha->action) {
811 BLI_freelinkN(active_haptic_actions, ha);
812 return;
813 }
814 }
815}
816
817static void wm_xr_session_haptic_timers_check(ListBase *active_haptic_actions, int64_t time_now)
818{
819 LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, active_haptic_actions) {
820 if (time_now - ha->time_start >= ha->action->haptic_duration) {
821 BLI_freelinkN(active_haptic_actions, ha);
822 }
823 }
824}
825
827 const char *action_set_name,
828 wmXrAction *action,
829 uint subaction_idx,
830 ListBase *active_modal_actions,
831 ListBase *active_haptic_actions,
832 int64_t time_now,
833 bool modal,
834 bool haptic,
835 short *r_val)
836{
837 const char *haptic_subaction_path = ((action->haptic_flag & XR_HAPTIC_MATCHUSERPATHS) != 0) ?
838 action->subaction_paths[subaction_idx] :
839 nullptr;
840 bool curr = false;
841 bool prev = false;
842
843 switch (action->type) {
844 case XR_BOOLEAN_INPUT: {
845 const bool *state = &((bool *)action->states)[subaction_idx];
846 bool *state_prev = &((bool *)action->states_prev)[subaction_idx];
847 if (*state) {
848 curr = true;
849 }
850 if (*state_prev) {
851 prev = true;
852 }
853 *state_prev = *state;
854 break;
855 }
856 case XR_FLOAT_INPUT: {
857 const float *state = &((float *)action->states)[subaction_idx];
858 float *state_prev = &((float *)action->states_prev)[subaction_idx];
860 state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx]))
861 {
862 curr = true;
863 }
864 if (test_float_state(state_prev,
865 action->float_thresholds[subaction_idx],
866 action->axis_flags[subaction_idx]))
867 {
868 prev = true;
869 }
870 *state_prev = *state;
871 break;
872 }
873 case XR_VECTOR2F_INPUT: {
874 const float(*state)[2] = &((float(*)[2])action->states)[subaction_idx];
875 float(*state_prev)[2] = &((float(*)[2])action->states_prev)[subaction_idx];
877 *state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx]))
878 {
879 curr = true;
880 }
881 if (test_vec2f_state(*state_prev,
882 action->float_thresholds[subaction_idx],
883 action->axis_flags[subaction_idx]))
884 {
885 prev = true;
886 }
887 copy_v2_v2(*state_prev, *state);
888 break;
889 }
890 case XR_POSE_INPUT:
893 break;
894 }
895
896 if (curr) {
897 if (!prev) {
898 if (modal || (action->op_flag == XR_OP_PRESS)) {
899 *r_val = KM_PRESS;
900 }
901 if (haptic && (action->haptic_flag & (XR_HAPTIC_PRESS | XR_HAPTIC_REPEAT)) != 0) {
902 /* Apply haptics. */
904 action_set_name,
905 action->haptic_name,
906 haptic_subaction_path,
907 &action->haptic_duration,
908 &action->haptic_frequency,
909 &action->haptic_amplitude))
910 {
912 active_haptic_actions, action, haptic_subaction_path, time_now);
913 }
914 }
915 }
916 else if (modal) {
917 *r_val = KM_PRESS;
918 }
919 if (modal && !action->active_modal_path) {
920 /* Set active modal path. */
921 action->active_modal_path = action->subaction_paths[subaction_idx];
922 /* Add to active modal actions. */
923 wm_xr_session_modal_action_test_add(active_modal_actions, action);
924 }
925 if (haptic && ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0)) {
926 if (!wm_xr_session_haptic_action_find(active_haptic_actions, action, haptic_subaction_path))
927 {
928 /* Apply haptics. */
930 action_set_name,
931 action->haptic_name,
932 haptic_subaction_path,
933 &action->haptic_duration,
934 &action->haptic_frequency,
935 &action->haptic_amplitude))
936 {
938 active_haptic_actions, action, haptic_subaction_path, time_now);
939 }
940 }
941 }
942 }
943 else if (prev) {
944 if (modal || (action->op_flag == XR_OP_RELEASE)) {
945 *r_val = KM_RELEASE;
946 if (modal && (action->subaction_paths[subaction_idx] == action->active_modal_path)) {
947 /* Unset active modal path. */
948 action->active_modal_path = nullptr;
949 /* Remove from active modal actions. */
950 wm_xr_session_modal_action_remove(active_modal_actions, action);
951 }
952 }
953 if (haptic) {
954 if ((action->haptic_flag & XR_HAPTIC_RELEASE) != 0) {
955 /* Apply haptics. */
957 action_set_name,
958 action->haptic_name,
959 haptic_subaction_path,
960 &action->haptic_duration,
961 &action->haptic_frequency,
962 &action->haptic_amplitude))
963 {
965 active_haptic_actions, action, haptic_subaction_path, time_now);
966 }
967 }
968 else if ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0) {
969 /* Stop any active haptics. */
970 WM_xr_haptic_action_stop(xr, action_set_name, action->haptic_name, haptic_subaction_path);
971 wm_xr_session_haptic_action_remove(active_haptic_actions, action);
972 }
973 }
974 }
975}
976
978 wmXrAction *action,
979 uint subaction_idx,
980 uint *r_subaction_idx_other,
981 const GHOST_XrPose **r_aim_pose_other)
982{
983 if ((action->action_flag & XR_ACTION_BIMANUAL) == 0) {
984 return false;
985 }
986
987 bool bimanual = false;
988
989 *r_subaction_idx_other = (subaction_idx == 0) ?
990 uint(min_ii(1, action->count_subaction_paths - 1)) :
991 0;
992
993 switch (action->type) {
994 case XR_BOOLEAN_INPUT: {
995 const bool *state = &((bool *)action->states)[*r_subaction_idx_other];
996 if (*state) {
997 bimanual = true;
998 }
999 break;
1000 }
1001 case XR_FLOAT_INPUT: {
1002 const float *state = &((float *)action->states)[*r_subaction_idx_other];
1004 action->float_thresholds[*r_subaction_idx_other],
1005 action->axis_flags[*r_subaction_idx_other]))
1006 {
1007 bimanual = true;
1008 }
1009 break;
1010 }
1011 case XR_VECTOR2F_INPUT: {
1012 const float(*state)[2] = &((float(*)[2])action->states)[*r_subaction_idx_other];
1014 action->float_thresholds[*r_subaction_idx_other],
1015 action->axis_flags[*r_subaction_idx_other]))
1016 {
1017 bimanual = true;
1018 }
1019 break;
1020 }
1021 case XR_POSE_INPUT:
1024 break;
1025 }
1026
1027 if (bimanual) {
1028 *r_aim_pose_other = wm_xr_session_controller_aim_pose_find(
1029 session_state, action->subaction_paths[*r_subaction_idx_other]);
1030 }
1031
1032 return bimanual;
1033}
1034
1035static wmXrActionData *wm_xr_session_event_create(const char *action_set_name,
1036 const wmXrAction *action,
1037 const GHOST_XrPose *controller_aim_pose,
1038 const GHOST_XrPose *controller_aim_pose_other,
1039 uint subaction_idx,
1040 uint subaction_idx_other,
1041 bool bimanual)
1042{
1043 wmXrActionData *data = MEM_callocN<wmXrActionData>(__func__);
1044 STRNCPY(data->action_set, action_set_name);
1045 STRNCPY(data->action, action->name);
1046 STRNCPY(data->user_path, action->subaction_paths[subaction_idx]);
1047 if (bimanual) {
1048 STRNCPY(data->user_path_other, action->subaction_paths[subaction_idx_other]);
1049 }
1050 data->type = action->type;
1051
1052 switch (action->type) {
1053 case XR_BOOLEAN_INPUT:
1054 data->state[0] = ((bool *)action->states)[subaction_idx] ? 1.0f : 0.0f;
1055 if (bimanual) {
1056 data->state_other[0] = ((bool *)action->states)[subaction_idx_other] ? 1.0f : 0.0f;
1057 }
1058 break;
1059 case XR_FLOAT_INPUT:
1060 data->state[0] = ((float *)action->states)[subaction_idx];
1061 if (bimanual) {
1062 data->state_other[0] = ((float *)action->states)[subaction_idx_other];
1063 }
1064 data->float_threshold = action->float_thresholds[subaction_idx];
1065 break;
1066 case XR_VECTOR2F_INPUT:
1067 copy_v2_v2(data->state, ((float(*)[2])action->states)[subaction_idx]);
1068 if (bimanual) {
1069 copy_v2_v2(data->state_other, ((float(*)[2])action->states)[subaction_idx_other]);
1070 }
1071 data->float_threshold = action->float_thresholds[subaction_idx];
1072 break;
1073 case XR_POSE_INPUT:
1076 break;
1077 }
1078
1079 if (controller_aim_pose) {
1080 copy_v3_v3(data->controller_loc, controller_aim_pose->position);
1081 copy_qt_qt(data->controller_rot, controller_aim_pose->orientation_quat);
1082
1083 if (bimanual && controller_aim_pose_other) {
1084 copy_v3_v3(data->controller_loc_other, controller_aim_pose_other->position);
1085 copy_qt_qt(data->controller_rot_other, controller_aim_pose_other->orientation_quat);
1086 }
1087 else {
1088 data->controller_rot_other[0] = 1.0f;
1089 }
1090 }
1091 else {
1092 data->controller_rot[0] = 1.0f;
1093 data->controller_rot_other[0] = 1.0f;
1094 }
1095
1096 data->ot = action->ot;
1097 data->op_properties = action->op_properties;
1098
1099 data->bimanual = bimanual;
1100
1101 return data;
1102}
1103
1104/* Dispatch events to window queues. */
1106 GHOST_XrContextHandle xr_context,
1107 wmXrActionSet *action_set,
1108 wmXrSessionState *session_state,
1109 wmWindow *win)
1110{
1111 const char *action_set_name = action_set->name;
1112
1113 const uint count = GHOST_XrGetActionCount(xr_context, action_set_name);
1114 if (count < 1) {
1115 return;
1116 }
1117
1118 const int64_t time_now = int64_t(BLI_time_now_seconds() * 1000);
1119
1120 ListBase *active_modal_actions = &action_set->active_modal_actions;
1121 ListBase *active_haptic_actions = &action_set->active_haptic_actions;
1122
1123 wmXrAction **actions = MEM_calloc_arrayN<wmXrAction *>(count, __func__);
1124
1125 GHOST_XrGetActionCustomdataArray(xr_context, action_set_name, (void **)actions);
1126
1127 /* Check haptic action timers. */
1128 wm_xr_session_haptic_timers_check(active_haptic_actions, time_now);
1129
1130 for (uint action_idx = 0; action_idx < count; ++action_idx) {
1131 wmXrAction *action = actions[action_idx];
1132 if (action && action->ot) {
1133 const bool modal = action->ot->modal;
1134 const bool haptic = (GHOST_XrGetActionCustomdata(
1135 xr_context, action_set_name, action->haptic_name) != nullptr);
1136
1137 for (uint subaction_idx = 0; subaction_idx < action->count_subaction_paths; ++subaction_idx)
1138 {
1139 short val = KM_NOTHING;
1140
1141 /* Interpret action states (update modal/haptic action lists, apply haptics, etc). */
1143 action_set_name,
1144 action,
1145 subaction_idx,
1146 active_modal_actions,
1147 active_haptic_actions,
1148 time_now,
1149 modal,
1150 haptic,
1151 &val);
1152
1153 const bool is_active_modal_action = wm_xr_session_modal_action_test(
1154 active_modal_actions, action, nullptr);
1155 const bool is_active_modal_subaction = (!action->active_modal_path ||
1156 (action->subaction_paths[subaction_idx] ==
1157 action->active_modal_path));
1158
1159 if ((val != KM_NOTHING) &&
1160 (!modal || (is_active_modal_action && is_active_modal_subaction)))
1161 {
1162 const GHOST_XrPose *aim_pose = wm_xr_session_controller_aim_pose_find(
1163 session_state, action->subaction_paths[subaction_idx]);
1164 const GHOST_XrPose *aim_pose_other = nullptr;
1165 uint subaction_idx_other = 0;
1166
1167 /* Test for bimanual interaction. */
1168 const bool bimanual = wm_xr_session_action_test_bimanual(
1169 session_state, action, subaction_idx, &subaction_idx_other, &aim_pose_other);
1170
1171 wmXrActionData *actiondata = wm_xr_session_event_create(action_set_name,
1172 action,
1173 aim_pose,
1174 aim_pose_other,
1175 subaction_idx,
1176 subaction_idx_other,
1177 bimanual);
1178 wm_event_add_xrevent(win, actiondata, val);
1179 }
1180 }
1181 }
1182 }
1183
1184 MEM_freeN(actions);
1185}
1186
1188{
1189 wmXrData *xr = &wm->xr;
1190 if (!xr->runtime) {
1191 return;
1192 }
1193
1194 XrSessionSettings *settings = &xr->session_settings;
1195 GHOST_XrContextHandle xr_context = xr->runtime->context;
1197
1198 if (state->is_navigation_dirty) {
1199 memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
1200 state->nav_scale_prev = state->nav_scale;
1201 state->is_navigation_dirty = false;
1202
1203 /* Update viewer pose with any navigation changes since the last actions sync so that data
1204 * is correct for queries. */
1205 float m[4][4], viewer_mat[4][4];
1206 wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, m);
1207 mul_m4_m4m4(viewer_mat, m, state->viewer_mat_base);
1208 mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
1210 &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
1211 }
1212
1213 /* Set active action set if requested previously. */
1214 if (state->active_action_set_next[0]) {
1215 WM_xr_active_action_set_set(xr, state->active_action_set_next, false);
1216 state->active_action_set_next[0] = '\0';
1217 }
1218 wmXrActionSet *active_action_set = state->active_action_set;
1219
1220 const bool synced = GHOST_XrSyncActions(xr_context,
1221 active_action_set ? active_action_set->name : nullptr);
1222 if (!synced) {
1223 return;
1224 }
1225
1226 /* Only update controller data and dispatch events for active action set. */
1227 if (active_action_set) {
1229
1230 if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
1232 active_action_set->controller_grip_action,
1233 active_action_set->controller_aim_action,
1234 xr_context,
1235 state);
1236 }
1237
1238 if (win) {
1239 /* Ensure an XR area exists for events. */
1240 if (!xr->runtime->area) {
1242 }
1243
1244 /* Set XR area object type flags for operators. */
1245 View3D *v3d = static_cast<View3D *>(xr->runtime->area->spacedata.first);
1248
1249 wm_xr_session_events_dispatch(xr, xr_context, active_action_set, state, win);
1250 }
1251 }
1252}
1253
1255 const wmXrAction *aim_action,
1256 wmXrData *xr)
1257{
1258 UNUSED_VARS(aim_action); /* Only used for asserts. */
1259
1261 ListBase *controllers = &state->controllers;
1262
1263 BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
1264 const uint count = grip_action->count_subaction_paths;
1265
1267
1268 for (uint i = 0; i < count; ++i) {
1270
1271 BLI_assert(STREQ(grip_action->subaction_paths[i], aim_action->subaction_paths[i]));
1272 STRNCPY(controller->subaction_path, grip_action->subaction_paths[i]);
1273
1274 BLI_addtail(controllers, controller);
1275 }
1276
1277 /* Activate draw callback. */
1278 if (g_xr_surface) {
1279 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1280 if (surface_data && !surface_data->controller_draw_handle) {
1281 if (surface_data->controller_art) {
1284 }
1285 }
1286 }
1287}
1288
1290{
1292
1293 /* Deactivate draw callback. */
1294 if (g_xr_surface) {
1295 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1296 if (surface_data && surface_data->controller_draw_handle) {
1297 if (surface_data->controller_art) {
1298 ED_region_draw_cb_exit(surface_data->controller_art, surface_data->controller_draw_handle);
1299 }
1300 surface_data->controller_draw_handle = nullptr;
1301 }
1302 }
1303}
1304 /* XR-Session Actions. */
1306
1307/* -------------------------------------------------------------------- */
1314
1323{
1325 wmXrDrawData draw_data;
1326
1327 if (!WM_xr_session_is_ready(&wm->xr)) {
1328 return;
1329 }
1330
1331 Scene *scene;
1332 Depsgraph *depsgraph;
1334 /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
1335 * writing for example. */
1336 // BLI_assert(DEG_is_fully_evaluated(depsgraph));
1337 wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
1338
1339 GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
1340
1341 /* There's no active frame-buffer if the session was canceled (exception while drawing views). */
1344 }
1345}
1346
1348{
1350
1351 if (!WM_xr_session_is_ready(&wm->xr)) {
1352 return;
1353 }
1354
1355 Scene *scene;
1356 Depsgraph *depsgraph;
1359}
1360
1362 const GHOST_XrDrawViewInfo *draw_view)
1363{
1364 wmXrViewportPair *vp = nullptr;
1365 if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) {
1366 vp = MEM_callocN<wmXrViewportPair>(__func__);
1367 BLI_addtail(&surface_data->viewports, vp);
1368 }
1369 else {
1370 vp = static_cast<wmXrViewportPair *>(
1371 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
1372 }
1373 BLI_assert(vp);
1374
1375 GPUOffScreen *offscreen = vp->offscreen;
1376 GPUViewport *viewport = vp->viewport;
1377 const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) &&
1378 (GPU_offscreen_height(offscreen) != draw_view->height);
1379 if (offscreen) {
1380 BLI_assert(viewport);
1381
1382 if (!size_changed) {
1383 return true;
1384 }
1385 GPU_viewport_free(viewport);
1386 GPU_offscreen_free(offscreen);
1387 }
1388
1389 char err_out[256] = "unknown";
1390 bool failure = false;
1391
1392 /* Initialize with some unsupported format to check following switch statement. */
1394
1395 switch (draw_view->swapchain_format) {
1396 case GHOST_kXrSwapchainFormatRGBA8:
1397 format = GPU_RGBA8;
1398 break;
1399 case GHOST_kXrSwapchainFormatRGBA16:
1401 break;
1402 case GHOST_kXrSwapchainFormatRGBA16F:
1404 break;
1405 case GHOST_kXrSwapchainFormatRGB10_A2:
1407 break;
1408 }
1410
1411 offscreen = vp->offscreen = GPU_offscreen_create(draw_view->width,
1412 draw_view->height,
1413 true,
1414 format,
1417 false,
1418 err_out);
1419 if (offscreen) {
1420 viewport = vp->viewport = GPU_viewport_create();
1421 if (!viewport) {
1422 GPU_offscreen_free(offscreen);
1423 offscreen = vp->offscreen = nullptr;
1424 failure = true;
1425 }
1426 }
1427 else {
1428 failure = true;
1429 }
1430
1431 if (failure) {
1432 CLOG_ERROR(&LOG, "Failed to get buffer, %s", err_out);
1433 return false;
1434 }
1435
1436 return true;
1437}
1438
1440{
1441 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(surface->customdata);
1442 ListBase *lb = &data->viewports;
1443
1444 while (wmXrViewportPair *vp = static_cast<wmXrViewportPair *>(BLI_pophead(lb))) {
1445 if (vp->viewport) {
1446 GPU_viewport_free(vp->viewport);
1447 }
1448 if (vp->offscreen) {
1449 GPU_offscreen_free(vp->offscreen);
1450 }
1451 BLI_freelinkN(lb, vp);
1452 }
1453
1454 if (data->controller_art) {
1455 BLI_freelistN(&data->controller_art->drawcalls);
1456 MEM_freeN(data->controller_art);
1457 }
1458
1459 MEM_freeN(surface->customdata);
1460
1461 g_xr_surface = nullptr;
1462}
1463
1465{
1466 if (g_xr_surface) {
1467 BLI_assert(false);
1468 return g_xr_surface;
1469 }
1470
1471 wmSurface *surface = MEM_callocN<wmSurface>(__func__);
1473 data->controller_art = MEM_callocN<ARegionType>("XrControllerRegionType");
1474
1478 surface->activate = DRW_xr_drawing_begin;
1479 surface->deactivate = DRW_xr_drawing_end;
1480
1481 surface->system_gpu_context = static_cast<GHOST_ContextHandle>(DRW_system_gpu_context_get());
1482 surface->blender_gpu_context = static_cast<GPUContext *>(DRW_xr_blender_gpu_context_get());
1483
1484 data->controller_art->regionid = RGN_TYPE_XR;
1485 surface->customdata = data;
1486
1487 g_xr_surface = surface;
1488
1489 return surface;
1490}
1491
1493{
1495
1496 wm_surface_add(surface);
1497
1498 /* Some regions may need to redraw with updated session state after the session is entirely up
1499 * and running. */
1501
1502 return surface->system_gpu_context;
1503}
1504
1505void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle /*context*/)
1506{
1507 if (g_xr_surface) { /* Might have been freed already. */
1509 }
1510
1512
1513 /* Some regions may need to redraw with updated session state after the session is entirely
1514 * stopped. */
1516}
1517
1519{
1520 if (g_xr_surface) {
1521 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1522 return data->controller_art;
1523 }
1524
1525 return nullptr;
1526}
1527 /* 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:996
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2623
Depsgraph * BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_layer)
Definition scene.cc:3414
#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)
#define BLI_ASSERT_UNIT_QUAT(q)
#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:688
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
#define CLAMP(a, b, c)
#define UNUSED_VARS(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#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:2242
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)
GPUFrameBuffer * GPU_framebuffer_active_get()
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, eGPUTextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
void GPU_offscreen_free(GPUOffScreen *offscreen)
@ GPU_TEXTURE_USAGE_MEMORY_EXPORT
@ GPU_TEXTURE_USAGE_SHADER_READ
eGPUTextureFormat
@ GPU_RGB10_A2
@ GPU_RGBA16F
@ GPU_RGBA16
@ GPU_R8
@ GPU_RGBA8
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:371
#define ND_XR_DATA_CHANGED
Definition WM_types.hh:415
@ KM_NOTHING
Definition WM_types.hh:307
@ KM_PRESS
Definition WM_types.hh:308
@ KM_RELEASE
Definition WM_types.hh:309
BMesh const char void * data
BPy_StructRNA * depsgraph
long long int int64_t
#define offsetof(t, d)
#define fabsf(x)
int count
format
#define LOG(severity)
Definition log.h:32
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]
void * data
void * first
ListBase wm
Definition BKE_main.hh:276
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:1078
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 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:139
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:37
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:43
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
Definition wm_xr_draw.cc:61
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_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_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_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()