Blender V4.3
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
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, fallback. */
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 &
282 (settings->flag & XR_SESSION_USE_POSITION_TRACKING));
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/* -------------------------------------------------------------------- */
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 = static_cast<LinkData *>(MEM_callocN(sizeof(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 = static_cast<wmXrHapticAction *>(MEM_callocN(sizeof(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 = static_cast<wmXrActionData *>(
1044 MEM_callocN(sizeof(wmXrActionData), __func__));
1045 STRNCPY(data->action_set, action_set_name);
1046 STRNCPY(data->action, action->name);
1047 STRNCPY(data->user_path, action->subaction_paths[subaction_idx]);
1048 if (bimanual) {
1049 STRNCPY(data->user_path_other, action->subaction_paths[subaction_idx_other]);
1050 }
1051 data->type = action->type;
1052
1053 switch (action->type) {
1054 case XR_BOOLEAN_INPUT:
1055 data->state[0] = ((bool *)action->states)[subaction_idx] ? 1.0f : 0.0f;
1056 if (bimanual) {
1057 data->state_other[0] = ((bool *)action->states)[subaction_idx_other] ? 1.0f : 0.0f;
1058 }
1059 break;
1060 case XR_FLOAT_INPUT:
1061 data->state[0] = ((float *)action->states)[subaction_idx];
1062 if (bimanual) {
1063 data->state_other[0] = ((float *)action->states)[subaction_idx_other];
1064 }
1065 data->float_threshold = action->float_thresholds[subaction_idx];
1066 break;
1067 case XR_VECTOR2F_INPUT:
1068 copy_v2_v2(data->state, ((float(*)[2])action->states)[subaction_idx]);
1069 if (bimanual) {
1070 copy_v2_v2(data->state_other, ((float(*)[2])action->states)[subaction_idx_other]);
1071 }
1072 data->float_threshold = action->float_thresholds[subaction_idx];
1073 break;
1074 case XR_POSE_INPUT:
1077 break;
1078 }
1079
1080 if (controller_aim_pose) {
1081 copy_v3_v3(data->controller_loc, controller_aim_pose->position);
1082 copy_qt_qt(data->controller_rot, controller_aim_pose->orientation_quat);
1083
1084 if (bimanual && controller_aim_pose_other) {
1085 copy_v3_v3(data->controller_loc_other, controller_aim_pose_other->position);
1086 copy_qt_qt(data->controller_rot_other, controller_aim_pose_other->orientation_quat);
1087 }
1088 else {
1089 data->controller_rot_other[0] = 1.0f;
1090 }
1091 }
1092 else {
1093 data->controller_rot[0] = 1.0f;
1094 data->controller_rot_other[0] = 1.0f;
1095 }
1096
1097 data->ot = action->ot;
1098 data->op_properties = action->op_properties;
1099
1100 data->bimanual = bimanual;
1101
1102 return data;
1103}
1104
1105/* Dispatch events to window queues. */
1107 GHOST_XrContextHandle xr_context,
1108 wmXrActionSet *action_set,
1109 wmXrSessionState *session_state,
1110 wmWindow *win)
1111{
1112 const char *action_set_name = action_set->name;
1113
1114 const uint count = GHOST_XrGetActionCount(xr_context, action_set_name);
1115 if (count < 1) {
1116 return;
1117 }
1118
1119 const int64_t time_now = int64_t(BLI_time_now_seconds() * 1000);
1120
1121 ListBase *active_modal_actions = &action_set->active_modal_actions;
1122 ListBase *active_haptic_actions = &action_set->active_haptic_actions;
1123
1124 wmXrAction **actions = static_cast<wmXrAction **>(
1125 MEM_calloc_arrayN(count, sizeof(*actions), __func__));
1126
1127 GHOST_XrGetActionCustomdataArray(xr_context, action_set_name, (void **)actions);
1128
1129 /* Check haptic action timers. */
1130 wm_xr_session_haptic_timers_check(active_haptic_actions, time_now);
1131
1132 for (uint action_idx = 0; action_idx < count; ++action_idx) {
1133 wmXrAction *action = actions[action_idx];
1134 if (action && action->ot) {
1135 const bool modal = action->ot->modal;
1136 const bool haptic = (GHOST_XrGetActionCustomdata(
1137 xr_context, action_set_name, action->haptic_name) != nullptr);
1138
1139 for (uint subaction_idx = 0; subaction_idx < action->count_subaction_paths; ++subaction_idx)
1140 {
1141 short val = KM_NOTHING;
1142
1143 /* Interpret action states (update modal/haptic action lists, apply haptics, etc). */
1145 action_set_name,
1146 action,
1147 subaction_idx,
1148 active_modal_actions,
1149 active_haptic_actions,
1150 time_now,
1151 modal,
1152 haptic,
1153 &val);
1154
1155 const bool is_active_modal_action = wm_xr_session_modal_action_test(
1156 active_modal_actions, action, nullptr);
1157 const bool is_active_modal_subaction = (!action->active_modal_path ||
1158 (action->subaction_paths[subaction_idx] ==
1159 action->active_modal_path));
1160
1161 if ((val != KM_NOTHING) &&
1162 (!modal || (is_active_modal_action && is_active_modal_subaction)))
1163 {
1164 const GHOST_XrPose *aim_pose = wm_xr_session_controller_aim_pose_find(
1165 session_state, action->subaction_paths[subaction_idx]);
1166 const GHOST_XrPose *aim_pose_other = nullptr;
1167 uint subaction_idx_other = 0;
1168
1169 /* Test for bimanual interaction. */
1170 const bool bimanual = wm_xr_session_action_test_bimanual(
1171 session_state, action, subaction_idx, &subaction_idx_other, &aim_pose_other);
1172
1173 wmXrActionData *actiondata = wm_xr_session_event_create(action_set_name,
1174 action,
1175 aim_pose,
1176 aim_pose_other,
1177 subaction_idx,
1178 subaction_idx_other,
1179 bimanual);
1180 wm_event_add_xrevent(win, actiondata, val);
1181 }
1182 }
1183 }
1184 }
1185
1186 MEM_freeN(actions);
1187}
1188
1190{
1191 wmXrData *xr = &wm->xr;
1192 if (!xr->runtime) {
1193 return;
1194 }
1195
1196 XrSessionSettings *settings = &xr->session_settings;
1197 GHOST_XrContextHandle xr_context = xr->runtime->context;
1199
1200 if (state->is_navigation_dirty) {
1201 memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
1202 state->nav_scale_prev = state->nav_scale;
1203 state->is_navigation_dirty = false;
1204
1205 /* Update viewer pose with any navigation changes since the last actions sync so that data
1206 * is correct for queries. */
1207 float m[4][4], viewer_mat[4][4];
1208 wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, m);
1209 mul_m4_m4m4(viewer_mat, m, state->viewer_mat_base);
1210 mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
1212 &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
1213 }
1214
1215 /* Set active action set if requested previously. */
1216 if (state->active_action_set_next[0]) {
1217 WM_xr_active_action_set_set(xr, state->active_action_set_next, false);
1218 state->active_action_set_next[0] = '\0';
1219 }
1220 wmXrActionSet *active_action_set = state->active_action_set;
1221
1222 const bool synced = GHOST_XrSyncActions(xr_context,
1223 active_action_set ? active_action_set->name : nullptr);
1224 if (!synced) {
1225 return;
1226 }
1227
1228 /* Only update controller data and dispatch events for active action set. */
1229 if (active_action_set) {
1231
1232 if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
1234 active_action_set->controller_grip_action,
1235 active_action_set->controller_aim_action,
1236 xr_context,
1237 state);
1238 }
1239
1240 if (win) {
1241 /* Ensure an XR area exists for events. */
1242 if (!xr->runtime->area) {
1244 }
1245
1246 /* Set XR area object type flags for operators. */
1247 View3D *v3d = static_cast<View3D *>(xr->runtime->area->spacedata.first);
1248 v3d->object_type_exclude_viewport = settings->object_type_exclude_viewport;
1249 v3d->object_type_exclude_select = settings->object_type_exclude_select;
1250
1251 wm_xr_session_events_dispatch(xr, xr_context, active_action_set, state, win);
1252 }
1253 }
1254}
1255
1257 const wmXrAction *aim_action,
1258 wmXrData *xr)
1259{
1260 UNUSED_VARS(aim_action); /* Only used for asserts. */
1261
1263 ListBase *controllers = &state->controllers;
1264
1265 BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths);
1266 const uint count = grip_action->count_subaction_paths;
1267
1269
1270 for (uint i = 0; i < count; ++i) {
1271 wmXrController *controller = static_cast<wmXrController *>(
1272 MEM_callocN(sizeof(*controller), __func__));
1273
1274 BLI_assert(STREQ(grip_action->subaction_paths[i], aim_action->subaction_paths[i]));
1275 STRNCPY(controller->subaction_path, grip_action->subaction_paths[i]);
1276
1277 BLI_addtail(controllers, controller);
1278 }
1279
1280 /* Activate draw callback. */
1281 if (g_xr_surface) {
1282 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1283 if (surface_data && !surface_data->controller_draw_handle) {
1284 if (surface_data->controller_art) {
1287 }
1288 }
1289 }
1290}
1291
1293{
1295
1296 /* Deactivate draw callback. */
1297 if (g_xr_surface) {
1298 wmXrSurfaceData *surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1299 if (surface_data && surface_data->controller_draw_handle) {
1300 if (surface_data->controller_art) {
1301 ED_region_draw_cb_exit(surface_data->controller_art, surface_data->controller_draw_handle);
1302 }
1303 surface_data->controller_draw_handle = nullptr;
1304 }
1305 }
1306}
1307
1308 /* XR-Session Actions. */
1309
1310/* -------------------------------------------------------------------- */
1326{
1328 wmXrDrawData draw_data;
1329
1330 if (!WM_xr_session_is_ready(&wm->xr)) {
1331 return;
1332 }
1333
1334 Scene *scene;
1335 Depsgraph *depsgraph;
1337 /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file
1338 * writing for example. */
1339 // BLI_assert(DEG_is_fully_evaluated(depsgraph));
1340 wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
1341
1342 GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
1343
1344 /* There's no active frame-buffer if the session was canceled (exception while drawing views). */
1347 }
1348}
1349
1351{
1353
1354 if (!WM_xr_session_is_ready(&wm->xr)) {
1355 return;
1356 }
1357
1358 Scene *scene;
1359 Depsgraph *depsgraph;
1362}
1363
1365 const GHOST_XrDrawViewInfo *draw_view)
1366{
1367 wmXrViewportPair *vp = nullptr;
1368 if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) {
1369 vp = static_cast<wmXrViewportPair *>(MEM_callocN(sizeof(*vp), __func__));
1370 BLI_addtail(&surface_data->viewports, vp);
1371 }
1372 else {
1373 vp = static_cast<wmXrViewportPair *>(
1374 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
1375 }
1376 BLI_assert(vp);
1377
1378 GPUOffScreen *offscreen = vp->offscreen;
1379 GPUViewport *viewport = vp->viewport;
1380 const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) &&
1381 (GPU_offscreen_height(offscreen) != draw_view->height);
1382 if (offscreen) {
1383 BLI_assert(viewport);
1384
1385 if (!size_changed) {
1386 return true;
1387 }
1388 GPU_viewport_free(viewport);
1389 GPU_offscreen_free(offscreen);
1390 }
1391
1392 char err_out[256] = "unknown";
1393 bool failure = false;
1394
1395 /* Initialize with some unsupported format to check following switch statement. */
1397
1398 switch (draw_view->swapchain_format) {
1399 case GHOST_kXrSwapchainFormatRGBA8:
1400 format = GPU_RGBA8;
1401 break;
1402 case GHOST_kXrSwapchainFormatRGBA16:
1404 break;
1405 case GHOST_kXrSwapchainFormatRGBA16F:
1407 break;
1408 case GHOST_kXrSwapchainFormatRGB10_A2:
1410 break;
1411 }
1413
1414 offscreen = vp->offscreen = GPU_offscreen_create(
1415 draw_view->width, draw_view->height, true, format, GPU_TEXTURE_USAGE_SHADER_READ, err_out);
1416 if (offscreen) {
1417 viewport = vp->viewport = GPU_viewport_create();
1418 if (!viewport) {
1419 GPU_offscreen_free(offscreen);
1420 offscreen = vp->offscreen = nullptr;
1421 failure = true;
1422 }
1423 }
1424 else {
1425 failure = true;
1426 }
1427
1428 if (failure) {
1429 CLOG_ERROR(&LOG, "Failed to get buffer, %s", err_out);
1430 return false;
1431 }
1432
1433 return true;
1434}
1435
1437{
1438 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(surface->customdata);
1439 ListBase *lb = &data->viewports;
1440
1441 while (wmXrViewportPair *vp = static_cast<wmXrViewportPair *>(BLI_pophead(lb))) {
1442 if (vp->viewport) {
1443 GPU_viewport_free(vp->viewport);
1444 }
1445 if (vp->offscreen) {
1446 GPU_offscreen_free(vp->offscreen);
1447 }
1448 BLI_freelinkN(lb, vp);
1449 }
1450
1451 if (data->controller_art) {
1452 BLI_freelistN(&data->controller_art->drawcalls);
1453 MEM_freeN(data->controller_art);
1454 }
1455
1456 MEM_freeN(surface->customdata);
1457
1458 g_xr_surface = nullptr;
1459}
1460
1462{
1463 if (g_xr_surface) {
1464 BLI_assert(false);
1465 return g_xr_surface;
1466 }
1467
1468 wmSurface *surface = static_cast<wmSurface *>(MEM_callocN(sizeof(*surface), __func__));
1469 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(
1470 MEM_callocN(sizeof(*data), "XrSurfaceData"));
1471 data->controller_art = static_cast<ARegionType *>(
1472 MEM_callocN(sizeof(*(data->controller_art)), "XrControllerRegionType"));
1473
1475 surface->do_depsgraph = wm_xr_session_do_depsgraph;
1476 surface->free_data = wm_xr_session_surface_free_data;
1477 surface->activate = DRW_xr_drawing_begin;
1478 surface->deactivate = DRW_xr_drawing_end;
1479
1480 surface->system_gpu_context = static_cast<GHOST_ContextHandle>(DRW_system_gpu_context_get());
1481 surface->blender_gpu_context = static_cast<GPUContext *>(DRW_xr_blender_gpu_context_get());
1482
1483 data->controller_art->regionid = RGN_TYPE_XR;
1484 surface->customdata = data;
1485
1486 g_xr_surface = surface;
1487
1488 return surface;
1489}
1490
1492{
1494
1495 wm_surface_add(surface);
1496
1497 /* Some regions may need to redraw with updated session state after the session is entirely up
1498 * and running. */
1500
1501 return surface->system_gpu_context;
1502}
1503
1504void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle /*context*/)
1505{
1506 if (g_xr_surface) { /* Might have been freed already. */
1508 }
1509
1511
1512 /* Some regions may need to redraw with updated session state after the session is entirely
1513 * stopped. */
1515}
1516
1518{
1519 if (g_xr_surface) {
1520 wmXrSurfaceData *data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
1521 return data->controller_art;
1522 }
1523
1524 return nullptr;
1525}
1526
1527 /* XR-Session Surface. */
void BKE_callback_exec_null(Main *bmain, eCbEvent evt)
Definition callbacks.cc:39
@ 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:984
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2573
Depsgraph * BKE_scene_get_depsgraph(const Scene *scene, const ViewLayer *view_layer)
Definition scene.cc:3364
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int min_ii(int a, int b)
#define M_PI_2
#define BLI_ASSERT_UNIT_QUAT(q)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
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 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])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c: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:2143
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)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, char err_out[256])
GPUFrameBuffer * GPU_framebuffer_active_get()
int GPU_offscreen_width(const GPUOffScreen *offscreen)
void GPU_framebuffer_restore()
int GPU_offscreen_height(const GPUOffScreen *offscreen)
void GPU_offscreen_free(GPUOffScreen *offscreen)
@ GPU_TEXTURE_USAGE_SHADER_READ
eGPUTextureFormat
@ GPU_RGB10_A2
@ GPU_RGBA16
@ GPU_R8
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
Read Guarded memory(de)allocation.
#define NC_WM
Definition WM_types.hh:341
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define ND_XR_DATA_CHANGED
Definition WM_types.hh:385
struct GPUContext GPUContext
const Depsgraph * depsgraph
#define offsetof(t, d)
#define fabsf(x)
direct_radiance_1_tx direct_radiance_3_tx indirect_radiance_2_tx radiance_feedback_img draw_fullscreen fragment_source("eevee_deferred_combine_frag.glsl") .specialization_constant(Type out_radiance draw_view
draw_view in_light_buf[] float
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
int count
format
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong state[N]
__int64 int64_t
Definition stdint.h:89
void(* draw)(const bContext *C, ARegion *region)
void * data
void * first
ListBase wm
Definition BKE_main.hh:239
ListBase spacedata
int object_type_exclude_select
int object_type_exclude_viewport
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
void * customdata
Definition wm_surface.hh:24
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
GHOST_XrPose aim_pose
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
void WM_main_add_notifier(uint type, void *reference)
void wm_surface_add(wmSurface *surface)
Definition wm_surface.cc:99
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:138
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
Definition wm_xr.cc:156
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:33
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:39
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
Definition wm_xr_draw.cc:57
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)
static CLG_LogRef LOG
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()