-
-
Notifications
You must be signed in to change notification settings - Fork 251
Expand file tree
/
Copy pathVR.hpp
More file actions
1191 lines (950 loc) · 45.2 KB
/
Copy pathVR.hpp
File metadata and controls
1191 lines (950 loc) · 45.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#pragma once
#define NOMINMAX
#include <memory>
#include <string>
#include <sdk/Math.hpp>
#include "vr/runtimes/OpenVR.hpp"
#include "vr/runtimes/OpenXR.hpp"
#include "vr/D3D11Component.hpp"
#include "vr/D3D12Component.hpp"
#include "vr/OverlayComponent.hpp"
#include "vr/FFakeStereoRenderingHook.hpp"
#include "vr/RenderTargetPoolHook.hpp"
#include "vr/CVarManager.hpp"
#include "Mod.hpp"
#undef max
#include <tracy/Tracy.hpp>
class VR : public Mod {
public:
enum RenderingMethod {
NATIVE_STEREO = 0,
SYNCHRONIZED = 1,
ALTERNATING = 2,
};
enum SyncedSequentialMethod {
SKIP_TICK = 0,
SKIP_DRAW = 1,
};
enum AimMethod : int32_t {
GAME,
HEAD,
RIGHT_CONTROLLER,
LEFT_CONTROLLER,
TWO_HANDED_RIGHT,
TWO_HANDED_LEFT,
};
enum DPadMethod : int32_t {
RIGHT_TOUCH,
LEFT_TOUCH,
LEFT_JOYSTICK,
RIGHT_JOYSTICK,
GESTURE_HEAD,
GESTURE_HEAD_RIGHT,
};
static const inline std::string s_action_pose = "/actions/default/in/Pose";
static const inline std::string s_action_grip_pose = "/actions/default/in/GripPose";
static const inline std::string s_action_trigger = "/actions/default/in/Trigger";
static const inline std::string s_action_grip = "/actions/default/in/Grip";
static const inline std::string s_action_joystick = "/actions/default/in/Joystick";
static const inline std::string s_action_joystick_click = "/actions/default/in/JoystickClick";
static const inline std::string s_action_a_button_left = "/actions/default/in/AButtonLeft";
static const inline std::string s_action_b_button_left = "/actions/default/in/BButtonLeft";
static const inline std::string s_action_a_button_touch_left = "/actions/default/in/AButtonTouchLeft";
static const inline std::string s_action_b_button_touch_left = "/actions/default/in/BButtonTouchLeft";
static const inline std::string s_action_a_button_right = "/actions/default/in/AButtonRight";
static const inline std::string s_action_b_button_right = "/actions/default/in/BButtonRight";
static const inline std::string s_action_a_button_touch_right = "/actions/default/in/AButtonTouchRight";
static const inline std::string s_action_b_button_touch_right = "/actions/default/in/BButtonTouchRight";
static const inline std::string s_action_dpad_up = "/actions/default/in/DPad_Up";
static const inline std::string s_action_dpad_right = "/actions/default/in/DPad_Right";
static const inline std::string s_action_dpad_down = "/actions/default/in/DPad_Down";
static const inline std::string s_action_dpad_left = "/actions/default/in/DPad_Left";
static const inline std::string s_action_system_button = "/actions/default/in/SystemButton";
static const inline std::string s_action_thumbrest_touch_left = "/actions/default/in/ThumbrestTouchLeft";
static const inline std::string s_action_thumbrest_touch_right = "/actions/default/in/ThumbrestTouchRight";
public:
static std::shared_ptr<VR>& get();
std::string_view get_name() const override { return "VR"; }
std::optional<std::string> clean_initialize();
std::optional<std::string> on_initialize_d3d_thread() {
return clean_initialize();
}
std::vector<SidebarEntryInfo> get_sidebar_entries() override {
return {
{"Runtime", false},
{"Unreal", false},
{"Input", false},
{"Camera", false},
{"Keybinds", false},
{"Console/CVars", true},
{"Compatibility", true},
{"Debug", true},
};
}
void on_config_load(const utility::Config& cfg, bool set_defaults) override;
void on_config_save(utility::Config& cfg) override;
void on_draw_ui() override;
void on_draw_sidebar_entry(std::string_view name) override;
void on_pre_imgui_frame() override;
void handle_keybinds();
void on_frame() override;
void on_present() override;
void on_post_present() override;
void on_device_reset() override {
get_runtime()->on_device_reset();
if (m_fake_stereo_hook != nullptr) {
m_fake_stereo_hook->on_device_reset();
}
if (m_is_d3d12) {
m_d3d12.on_reset(this);
} else {
m_d3d11.on_reset(this);
}
}
bool on_message(HWND wnd, UINT message, WPARAM w_param, LPARAM l_param) override;
void on_xinput_get_state(uint32_t* retval, uint32_t user_index, XINPUT_STATE* state) override;
void on_xinput_set_state(uint32_t* retval, uint32_t user_index, XINPUT_VIBRATION* vibration) override;
void update_imgui_state_from_xinput_state(XINPUT_STATE& state, bool is_vr_controller);
void on_pre_engine_tick(sdk::UGameEngine* engine, float delta) override;
void on_pre_calculate_stereo_view_offset(void* stereo_device, const int32_t view_index, Rotator<float>* view_rotation,
const float world_to_meters, Vector3f* view_location, bool is_double) override;
void on_pre_viewport_client_draw(void* viewport_client, void* viewport, void* canvas) override;
void update_hmd_state(bool from_view_extensions = false, uint32_t frame_count = 0);
void update_action_states();
void update_dpad_gestures();
void reinitialize_renderer() {
if (m_is_d3d12) {
m_d3d12.force_reset();
} else {
m_d3d11.force_reset();
}
}
Vector4f get_position(uint32_t index, bool grip = true) const;
Vector4f get_velocity(uint32_t index) const;
Vector4f get_angular_velocity(uint32_t index) const;
Matrix4x4f get_hmd_rotation(uint32_t frame_count) const;
Matrix4x4f get_hmd_transform(uint32_t frame_count) const;
Matrix4x4f get_rotation(uint32_t index, bool grip = true) const;
Matrix4x4f get_transform(uint32_t index, bool grip = true) const;
vr::HmdMatrix34_t get_raw_transform(uint32_t index) const;
Vector4f get_aim_position(uint32_t index) const {
return get_position(index, false);
}
glm::vec3 get_controller_position_with_offset(VRRuntime::Hand hand) {
float x_offset = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_position_offset_x() : get_right_controller_position_offset_x();
float y_offset = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_position_offset_y() : get_right_controller_position_offset_y();
float z_offset = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_position_offset_z() : get_right_controller_position_offset_z();
// if there's no offsets defined, return the original:
auto const position = get_position((hand == VRRuntime::Hand::LEFT) ? get_left_controller_index() : get_right_controller_index(), false);
if (x_offset == 0 && y_offset == 0 && z_offset == 0) {
return position;
} else {
// if we offset the controller by some specified distance we need a frame of reference - what direction is "x"?. If we use
// the HMD direction then turning your head will make the gun move in the world independently of your hand position. If
// we use the controller's direction then the gun will move around when you rotate it (i.e. it will be on the end of an
// invisible 'stick' that's attached to the rotating controller). As there's no other frame of reference that makes any sense here,
// a stick it is. Whether the stick orientation is the offset or raw orientation is another complication
auto const actual_controller_rotation = get_rotation((hand == VRRuntime::Hand::LEFT) ? get_left_controller_index() : get_right_controller_index(), false);
return position - actual_controller_rotation * glm::vec4{-x_offset, -y_offset, z_offset, 0};
}
}
Matrix4x4f get_controller_rotation_with_offset(VRRuntime::Hand hand) {
float x_offset_degrees = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_rotation_offset_x() : get_right_controller_rotation_offset_x();
float y_offset_degrees = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_rotation_offset_y() : get_right_controller_rotation_offset_y();
float z_offset_degrees = (hand == VRRuntime::Hand::LEFT) ? get_left_controller_rotation_offset_z() : get_right_controller_rotation_offset_z();
// if there's no offsets defined, return the original:
auto const rotation = get_rotation((hand == VRRuntime::Hand::LEFT) ? get_left_controller_index() : get_right_controller_index(), false);
if (x_offset_degrees == 0 && y_offset_degrees == 0 && z_offset_degrees == 0) {
return rotation;
} else {
auto const requested_rotation_offset =
utility::math::ue_rotation_matrix(glm::vec3{y_offset_degrees, z_offset_degrees, -x_offset_degrees});
return rotation * requested_rotation_offset;
}
}
Matrix4x4f get_grip_transform(uint32_t hand_index) const;
Matrix4x4f get_aim_transform(uint32_t hand_index) const;
Vector4f get_eye_offset(VRRuntime::Eye eye) const;
Vector4f get_current_offset();
Matrix4x4f get_eye_transform(uint32_t index);
Matrix4x4f get_current_eye_transform(bool flip = false);
Matrix4x4f get_projection_matrix(VRRuntime::Eye eye, bool flip = false);
Matrix4x4f get_current_projection_matrix(bool flip = false);
bool is_action_active(vr::VRActionHandle_t action, vr::VRInputValueHandle_t source = vr::k_ulInvalidInputValueHandle) const;
bool is_action_active_any_joystick(vr::VRActionHandle_t action) const {
if (is_action_active(action, m_left_joystick)) {
return true;
}
if (is_action_active(action, m_right_joystick)) {
return true;
}
return false;
}
Vector2f get_joystick_axis(vr::VRInputValueHandle_t handle) const;
vr::VRActionHandle_t get_action_handle(std::string_view action_path) {
if (auto it = m_action_handles.find(action_path.data()); it != m_action_handles.end()) {
return it->second;
}
return vr::k_ulInvalidActionHandle;
}
Vector2f get_left_stick_axis() const;
Vector2f get_right_stick_axis() const;
void trigger_haptic_vibration(float seconds_from_now, float duration, float frequency, float amplitude, vr::VRInputValueHandle_t source = vr::k_ulInvalidInputValueHandle);
float get_standing_height();
Vector4f get_standing_origin();
void set_standing_origin(const Vector4f& origin);
glm::quat get_rotation_offset();
void set_rotation_offset(const glm::quat& offset);
void recenter_view();
template<typename T = VRRuntime>
T* get_runtime() const {
return (T*)m_runtime.get();
}
runtimes::OpenXR* get_openxr_runtime() const {
return m_openxr.get();
}
runtimes::OpenVR* get_openvr_runtime() const {
return m_openvr.get();
}
bool is_hmd_active() const {
if (m_disable_vr) {
return false;
}
auto runtime = get_runtime();
if (runtime == nullptr) {
return false;
}
return runtime->ready() || (m_stereo_emulation_mode && runtime->loaded);
}
auto get_hmd() const {
return m_openvr->hmd;
}
auto& get_openvr_poses() const {
return m_openvr->render_poses;
}
auto& get_overlay_component() {
return m_overlay_component;
}
uint32_t get_hmd_width() const;
uint32_t get_hmd_height() const;
const auto& get_eyes() const {
return get_runtime()->eyes;
}
auto get_frame_count() const {
return m_frame_count;
}
auto& get_controllers() const {
return m_controllers;
}
bool is_using_controllers() const {
return m_controller_test_mode || (m_controllers_allowed &&
is_hmd_active() && !m_controllers.empty() && (std::chrono::steady_clock::now() - m_last_controller_update) <= std::chrono::seconds((int32_t)m_motion_controls_inactivity_timer->value()));
}
bool is_using_controllers_within(std::chrono::seconds seconds) const {
return is_hmd_active() && !m_controllers.empty() && (std::chrono::steady_clock::now() - m_last_controller_update) <= seconds;
}
int get_hmd_index() const {
return 0;
}
int get_left_controller_index() const {
if (m_runtime->is_openxr()) {
return 1;
} else if (m_runtime->is_openvr()) {
return !m_controllers.empty() ? m_controllers[0] : -1;
}
return -1;
}
int get_right_controller_index() const {
if (m_runtime->is_openxr()) {
return 2;
} else if (m_runtime->is_openvr()) {
return !m_controllers.empty() ? m_controllers[1] : -1;
}
return -1;
}
auto get_left_joystick() const {
if (!m_swap_controllers->value()) {
return m_left_joystick;
}
return m_right_joystick;
}
auto get_right_joystick() const {
if (!m_swap_controllers->value()) {
return m_right_joystick;
}
return m_left_joystick;
}
bool is_gui_enabled() const {
return m_enable_gui->value();
}
auto get_camera_forward_offset() const {
return m_camera_forward_offset->value();
}
auto get_camera_right_offset() const {
return m_camera_right_offset->value();
}
auto get_camera_up_offset() const {
return m_camera_up_offset->value();
}
auto get_world_scale() const {
return m_world_scale->value();
}
auto is_stereo_emulation_enabled() const {
return m_stereo_emulation_mode;
}
void reset_present_event() {
ResetEvent(m_present_finished_event);
}
void wait_for_present() {
if (!m_wait_for_present) {
return;
}
if (m_frame_count <= m_game_frame_count) {
//return;
}
if (WaitForSingleObject(m_present_finished_event, 11) == WAIT_TIMEOUT) {
//timed_out = true;
}
m_game_frame_count = m_frame_count;
//ResetEvent(m_present_finished_event);
}
auto& get_vr_mutex() {
return m_openvr_mtx;
}
bool is_using_afr() const {
return m_rendering_method->value() == RenderingMethod::ALTERNATING ||
m_rendering_method->value() == RenderingMethod::SYNCHRONIZED ||
m_extreme_compat_mode->value() == true;
}
bool is_using_synchronized_afr() const {
return m_rendering_method->value() == RenderingMethod::SYNCHRONIZED ||
(m_extreme_compat_mode->value() && m_rendering_method->value() == RenderingMethod::NATIVE_STEREO);
}
SyncedSequentialMethod get_synced_sequential_method() const {
return (SyncedSequentialMethod)m_synced_afr_method->value();
}
uint32_t get_lowest_xinput_index() const {
return m_lowest_xinput_user_index;
}
auto& get_render_target_pool_hook() {
return m_render_target_pool_hook;
}
void set_world_to_meters(float value) {
m_world_to_meters = value;
}
float get_world_to_meters() const {
return m_world_to_meters * m_world_scale->value();
}
float get_depth_scale() const {
return m_depth_scale->value();
}
bool is_depth_enabled() const {
return m_enable_depth->value();
}
bool is_decoupled_pitch_enabled() const {
return m_decoupled_pitch->value();
}
bool is_decoupled_pitch_ui_adjust_enabled() const {
return m_decoupled_pitch_ui_adjust->value();
}
void set_decoupled_pitch(bool value) {
m_decoupled_pitch->value() = value;
}
void set_aim_allowed(bool value) {
m_aim_temp_disabled = !value;
}
AimMethod get_aim_method() const {
if (m_aim_temp_disabled) {
return AimMethod::GAME;
}
return (AimMethod)m_aim_method->value();
}
AimMethod get_movement_orientation() const {
return (AimMethod)m_movement_orientation->value();
}
float get_aim_speed() const {
return m_aim_speed->value();
}
float get_left_controller_rotation_offset_x() const {
return m_left_controller_rotation_offset_x->value();
}
float get_left_controller_rotation_offset_y() const {
return m_left_controller_rotation_offset_y->value();
}
float get_left_controller_rotation_offset_z() const {
return m_left_controller_rotation_offset_z->value();
}
float get_right_controller_rotation_offset_x() const {
return m_right_controller_rotation_offset_x->value();
}
float get_right_controller_rotation_offset_y() const {
return m_right_controller_rotation_offset_y->value();
}
float get_right_controller_rotation_offset_z() const {
return m_right_controller_rotation_offset_z->value();
}
float get_left_controller_position_offset_x() const {
return m_left_controller_position_offset_x->value();
}
float get_left_controller_position_offset_y() const {
return m_left_controller_position_offset_y->value();
}
float get_left_controller_position_offset_z() const {
return m_left_controller_position_offset_z->value();
}
float get_right_controller_position_offset_x() const {
return m_right_controller_position_offset_x->value();
}
float get_right_controller_position_offset_y() const {
return m_right_controller_position_offset_y->value();
}
float get_right_controller_position_offset_z() const {
return m_right_controller_position_offset_z->value();
}
bool is_aim_multiplayer_support_enabled() const {
return m_aim_multiplayer_support->value();
}
bool is_aim_pawn_control_rotation_enabled() const {
return m_aim_use_pawn_control_rotation->value();
}
bool is_aim_modify_player_control_rotation_enabled() const {
return m_aim_modify_player_control_rotation->value();
}
bool is_aim_interpolation_enabled() const {
return m_aim_interp->value();
}
bool is_any_aim_method_active() const {
return m_aim_method->value() > AimMethod::GAME && !m_aim_temp_disabled;
}
bool is_headlocked_aim_enabled() const {
return m_aim_method->value() == AimMethod::HEAD && !m_aim_temp_disabled;
}
bool is_controller_aim_enabled() const {
const auto value = m_aim_method->value();
return !m_aim_temp_disabled && (value == AimMethod::LEFT_CONTROLLER || value == AimMethod::RIGHT_CONTROLLER || value == AimMethod::TWO_HANDED_LEFT || value == AimMethod::TWO_HANDED_RIGHT);
}
bool is_controller_movement_enabled() const {
const auto value = m_movement_orientation->value();
return value == AimMethod::LEFT_CONTROLLER || value == AimMethod::RIGHT_CONTROLLER || value == AimMethod::TWO_HANDED_LEFT || value == AimMethod::TWO_HANDED_RIGHT;
}
bool wants_blueprint_load() const {
return m_load_blueprint_code->value();
}
bool is_splitscreen_compatibility_enabled() const {
return m_splitscreen_compatibility_mode->value();
}
uint32_t get_requested_splitscreen_index() const {
return m_splitscreen_view_index->value();
}
bool is_sceneview_compatibility_enabled() const {
return m_sceneview_compatibility_mode->value();
}
bool is_ahud_compatibility_enabled() const {
return m_compatibility_ahud->value();
}
bool is_ghosting_fix_enabled() const {
return m_ghosting_fix->value();
}
auto& get_fake_stereo_hook() {
return m_fake_stereo_hook;
}
void set_pre_flattened_rotation(const glm::quat& rot) {
std::unique_lock _{m_decoupled_pitch_data.mtx};
m_decoupled_pitch_data.pre_flattened_rotation = rot;
}
auto get_pre_flattened_rotation() const {
std::shared_lock _{m_decoupled_pitch_data.mtx};
return m_decoupled_pitch_data.pre_flattened_rotation;
}
bool is_using_2d_screen() const {
return m_2d_screen_mode->value();
}
bool is_roomscale_enabled() const {
return m_roomscale_movement->value() && !m_aim_temp_disabled;
}
bool is_dpad_shifting_enabled() const {
return m_dpad_shifting->value();
}
DPadMethod get_dpad_method() const {
return (DPadMethod)m_dpad_shifting_method->value();
}
bool is_snapturn_enabled() const {
return m_snapturn->value();
}
float get_snapturn_js_deadzone() const {
return m_snapturn_joystick_deadzone->value();
}
int get_snapturn_angle() const {
return m_snapturn_angle->value();
}
float get_controller_pitch_offset() const {
return m_controller_pitch_offset->value();
}
bool should_skip_post_init_properties() const {
return m_compatibility_skip_pip->value();
}
bool should_skip_uobjectarray_init() const {
return m_compatibility_skip_uobjectarray_init->value();
}
bool is_extreme_compatibility_mode_enabled() const {
return m_extreme_compat_mode->value();
}
private:
Vector4f get_position_unsafe(uint32_t index) const;
Vector4f get_velocity_unsafe(uint32_t index) const;
Vector4f get_angular_velocity_unsafe(uint32_t index) const;
private:
std::optional<std::string> initialize_openvr();
std::optional<std::string> initialize_openvr_input();
std::optional<std::string> initialize_openxr();
std::optional<std::string> initialize_openxr_input();
std::optional<std::string> initialize_openxr_swapchains();
bool detect_controllers();
bool is_any_action_down();
std::optional<std::string> reinitialize_openvr() {
spdlog::info("Reinitializing OpenVR");
std::scoped_lock _{m_openvr_mtx};
m_runtime.reset();
m_runtime = std::make_shared<VRRuntime>();
m_openvr.reset();
// Reinitialize openvr input, hopefully this fixes the issue
m_controllers.clear();
m_controllers_set.clear();
auto e = initialize_openvr();
if (e) {
spdlog::error("Failed to reinitialize OpenVR: {}", *e);
}
return e;
}
std::optional<std::string> reinitialize_openxr() {
spdlog::info("Reinitializing OpenXR");
std::scoped_lock _{m_openvr_mtx};
if (m_is_d3d12) {
m_d3d12.openxr().destroy_swapchains();
} else {
m_d3d11.openxr().destroy_swapchains();
}
m_openxr.reset();
m_runtime.reset();
m_runtime = std::make_shared<VRRuntime>();
m_controllers.clear();
m_controllers_set.clear();
auto e = initialize_openxr();
if (e) {
spdlog::error("Failed to reinitialize OpenXR: {}", *e);
}
return e;
}
float m_nearz{ 0.1f };
float m_farz{ 3000.0f };
float m_world_to_meters{1.0f}; // Placeholder, it gets set later in a hook
std::unique_ptr<FFakeStereoRenderingHook> m_fake_stereo_hook{ std::make_unique<FFakeStereoRenderingHook>() };
std::unique_ptr<RenderTargetPoolHook> m_render_target_pool_hook{ std::make_unique<RenderTargetPoolHook>() };
std::unique_ptr<CVarManager> m_cvar_manager{ std::make_unique<CVarManager>() };
std::shared_ptr<VRRuntime> m_runtime{std::make_shared<VRRuntime>()}; // will point to the real runtime if it exists
std::shared_ptr<runtimes::OpenVR> m_openvr{std::make_shared<runtimes::OpenVR>()};
std::shared_ptr<runtimes::OpenXR> m_openxr{std::make_shared<runtimes::OpenXR>()};
mutable TracyLockable(std::recursive_mutex, m_openvr_mtx);
mutable TracyLockable(std::recursive_mutex, m_reinitialize_mtx);
mutable TracyLockable(std::recursive_mutex, m_actions_mtx);
mutable std::shared_mutex m_rotation_mtx{};
std::vector<int32_t> m_controllers{};
std::unordered_set<int32_t> m_controllers_set{};
vr::VRTextureBounds_t m_right_bounds{ 0.0f, 0.0f, 1.0f, 1.0f };
vr::VRTextureBounds_t m_left_bounds{ 0.0f, 0.0f, 1.0f, 1.0f };
glm::vec3 m_overlay_rotation{-1.550f, 0.0f, -1.330f};
glm::vec4 m_overlay_position{0.0f, 0.06f, -0.07f, 1.0f};
Vector4f m_standing_origin{ 0.0f, 1.5f, 0.0f, 0.0f };
glm::quat m_rotation_offset{ glm::identity<glm::quat>() };
HANDLE m_present_finished_event{CreateEvent(nullptr, TRUE, FALSE, nullptr)};
Vector4f m_raw_projections[2]{};
vrmod::D3D11Component m_d3d11{};
vrmod::D3D12Component m_d3d12{};
vrmod::OverlayComponent m_overlay_component;
bool m_disable_overlay{false};
// Action set handles
vr::VRActionSetHandle_t m_action_set{};
vr::VRActiveActionSet_t m_active_action_set{};
// Action handles
vr::VRActionHandle_t m_action_pose{ };
vr::VRActionHandle_t m_action_trigger{ };
vr::VRActionHandle_t m_action_grip{ };
vr::VRActionHandle_t m_action_grip_pose{ };
vr::VRActionHandle_t m_action_joystick{};
vr::VRActionHandle_t m_action_joystick_click{};
vr::VRActionHandle_t m_action_a_button_right{};
vr::VRActionHandle_t m_action_a_button_touch_right{};
vr::VRActionHandle_t m_action_b_button_right{};
vr::VRActionHandle_t m_action_b_button_touch_right{};
vr::VRActionHandle_t m_action_a_button_left{};
vr::VRActionHandle_t m_action_a_button_touch_left{};
vr::VRActionHandle_t m_action_b_button_left{};
vr::VRActionHandle_t m_action_b_button_touch_left{};
vr::VRActionHandle_t m_action_dpad_up{};
vr::VRActionHandle_t m_action_dpad_right{};
vr::VRActionHandle_t m_action_dpad_down{};
vr::VRActionHandle_t m_action_dpad_left{};
vr::VRActionHandle_t m_action_system_button{};
vr::VRActionHandle_t m_action_haptic{};
vr::VRActionHandle_t m_action_thumbrest_touch_left{};
vr::VRActionHandle_t m_action_thumbrest_touch_right{};
std::unordered_map<std::string, std::reference_wrapper<vr::VRActionHandle_t>> m_action_handles {
{ s_action_pose, m_action_pose },
{ s_action_grip_pose, m_action_grip_pose },
{ s_action_trigger, m_action_trigger },
{ s_action_grip, m_action_grip },
{ s_action_joystick, m_action_joystick },
{ s_action_joystick_click, m_action_joystick_click },
{ s_action_a_button_left, m_action_a_button_left },
{ s_action_b_button_left, m_action_b_button_left },
{ s_action_a_button_touch_left, m_action_a_button_touch_left },
{ s_action_b_button_touch_left, m_action_b_button_touch_left },
{ s_action_a_button_right, m_action_a_button_right },
{ s_action_b_button_right, m_action_b_button_right },
{ s_action_a_button_touch_right, m_action_a_button_touch_right },
{ s_action_b_button_touch_right, m_action_b_button_touch_right },
{ s_action_dpad_up, m_action_dpad_up },
{ s_action_dpad_right, m_action_dpad_right },
{ s_action_dpad_down, m_action_dpad_down },
{ s_action_dpad_left, m_action_dpad_left },
{ s_action_system_button, m_action_system_button },
{ s_action_thumbrest_touch_left, m_action_thumbrest_touch_left },
{ s_action_thumbrest_touch_right, m_action_thumbrest_touch_right },
// Out
{ "/actions/default/out/Haptic", m_action_haptic },
};
// Input sources
vr::VRInputValueHandle_t m_left_joystick{};
vr::VRInputValueHandle_t m_right_joystick{};
std::chrono::steady_clock::time_point m_last_controller_update{};
std::chrono::steady_clock::time_point m_last_xinput_update{};
std::chrono::steady_clock::time_point m_last_xinput_spoof_sent{};
std::chrono::steady_clock::time_point m_last_xinput_l3_r3_menu_open{};
std::chrono::steady_clock::time_point m_last_interaction_display{};
std::chrono::steady_clock::time_point m_last_engine_tick{};
uint32_t m_lowest_xinput_user_index{};
std::chrono::nanoseconds m_last_input_delay{};
std::chrono::nanoseconds m_avg_input_delay{};
static const inline std::vector<std::string> s_rendering_method_names {
"Native Stereo",
"Synchronized Sequential",
"Alternating/AFR",
};
static const inline std::vector<std::string> s_synced_afr_method_names {
"Skip Tick",
"Skip Draw",
};
static const inline std::vector<std::string> s_aim_method_names {
"Game",
"Head/HMD",
"Right Controller",
"Left Controller",
"Two Handed (Right)",
"Two Handed (Left)",
};
static const inline std::vector<std::string> s_dpad_method_names {
"Right Thumbrest + Left Joystick",
"Left Thumbrest + Right Joystick",
"Left Joystick (Disables Standard Joystick Input)",
"Right Joystick (Disables Standard Joystick Input)",
"Gesture (Head) + Left Joystick",
"Gesture (Head) + Right Joystick",
};
const ModCombo::Ptr m_rendering_method{ ModCombo::create(generate_name("RenderingMethod"), s_rendering_method_names) };
const ModCombo::Ptr m_synced_afr_method{ ModCombo::create(generate_name("SyncedSequentialMethod"), s_synced_afr_method_names, 1) };
const ModToggle::Ptr m_extreme_compat_mode{ ModToggle::create(generate_name("ExtremeCompatibilityMode"), false, true) };
const ModToggle::Ptr m_uncap_framerate{ ModToggle::create(generate_name("UncapFramerate"), true) };
const ModToggle::Ptr m_disable_blur_widgets{ ModToggle::create(generate_name("DisableBlurWidgets"), true) };
const ModToggle::Ptr m_disable_hdr_compositing{ ModToggle::create(generate_name("DisableHDRCompositing"), true, true) };
const ModToggle::Ptr m_disable_hzbocclusion{ ModToggle::create(generate_name("DisableHZBOcclusion"), true, true) };
const ModToggle::Ptr m_disable_instance_culling{ ModToggle::create(generate_name("DisableInstanceCulling"), true, true) };
const ModToggle::Ptr m_desktop_fix{ ModToggle::create(generate_name("DesktopRecordingFix_V2"), true) };
const ModToggle::Ptr m_enable_gui{ ModToggle::create(generate_name("EnableGUI"), true) };
const ModToggle::Ptr m_enable_depth{ ModToggle::create(generate_name("EnableDepth"), false) };
const ModToggle::Ptr m_decoupled_pitch{ ModToggle::create(generate_name("DecoupledPitch"), false) };
const ModToggle::Ptr m_decoupled_pitch_ui_adjust{ ModToggle::create(generate_name("DecoupledPitchUIAdjust"), true) };
const ModToggle::Ptr m_load_blueprint_code{ ModToggle::create(generate_name("LoadBlueprintCode"), false, true) };
const ModToggle::Ptr m_2d_screen_mode{ ModToggle::create(generate_name("2DScreenMode"), false) };
const ModToggle::Ptr m_roomscale_movement{ ModToggle::create(generate_name("RoomscaleMovement"), false) };
const ModToggle::Ptr m_swap_controllers{ ModToggle::create(generate_name("SwapControllerInputs"), false) };
// Snap turn settings and globals
void gamepad_snapturn(XINPUT_STATE& state);
void process_snapturn();
const ModToggle::Ptr m_snapturn{ ModToggle::create(generate_name("SnapTurn"), false) };
const ModSlider::Ptr m_snapturn_joystick_deadzone{ ModSlider::create(generate_name("SnapturnJoystickDeadzone"), 0.01f, 0.99f, 0.2f) };
const ModInt32::Ptr m_snapturn_angle{ ModSliderInt32::create(generate_name("SnapturnTurnAngle"), 1, 359, 45) };
bool m_snapturn_on_frame{false};
bool m_snapturn_left{false};
bool m_was_snapturn_run_on_input{false};
const ModSlider::Ptr m_controller_pitch_offset{ ModSlider::create(generate_name("ControllerPitchOffset"), -90.0f, 90.0f, 0.0f) };
// Aim method and movement orientation are not the same thing, but they can both have the same options
const ModCombo::Ptr m_aim_method{ ModCombo::create(generate_name("AimMethod"), s_aim_method_names, AimMethod::GAME) };
const ModCombo::Ptr m_movement_orientation{ ModCombo::create(generate_name("MovementOrientation"), s_aim_method_names, AimMethod::GAME) };
AimMethod m_previous_aim_method{ AimMethod::GAME };
const ModToggle::Ptr m_aim_use_pawn_control_rotation{ ModToggle::create(generate_name("AimUsePawnControlRotation"), false) };
const ModToggle::Ptr m_aim_modify_player_control_rotation{ ModToggle::create(generate_name("AimModifyPlayerControlRotation"), false) };
const ModToggle::Ptr m_aim_multiplayer_support{ ModToggle::create(generate_name("AimMPSupport"), false) };
const ModToggle::Ptr m_aim_interp{ ModToggle::create(generate_name("AimInterp"), true, true) };
const ModSlider::Ptr m_aim_speed{ ModSlider::create(generate_name("AimSpeed"), 0.01f, 25.0f, 15.0f) };
const ModToggle::Ptr m_dpad_shifting{ ModToggle::create(generate_name("DPadShifting"), true) };
const ModCombo::Ptr m_dpad_shifting_method{ ModCombo::create(generate_name("DPadShiftingMethod"), s_dpad_method_names, DPadMethod::RIGHT_TOUCH) };
const ModSlider::Ptr m_left_controller_rotation_offset_x{ModSlider::create(generate_name("LeftControllerRotationOffsetX"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_left_controller_rotation_offset_y{ModSlider::create(generate_name("LeftControllerRotationOffsetY"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_left_controller_rotation_offset_z{ModSlider::create(generate_name("LeftControllerRotationOffsetZ"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_rotation_offset_x{ModSlider::create(generate_name("RightControllerRotationOffsetX"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_rotation_offset_y{ModSlider::create(generate_name("RightControllerRotationOffsetY"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_rotation_offset_z{ModSlider::create(generate_name("RightControllerRotationOffsetZ"), -180.0f, 180.0f, 0.0f)};
const ModSlider::Ptr m_left_controller_position_offset_x{ModSlider::create(generate_name("LeftControllerPositionOffsetX"), -1.0f, 1.0f, 0.0f)};
const ModSlider::Ptr m_left_controller_position_offset_y{ModSlider::create(generate_name("LeftControllerPositionOffsetY"), -1.0f, 1.0f, 0.0f)};
const ModSlider::Ptr m_left_controller_position_offset_z{ModSlider::create(generate_name("LeftControllerPositionOffsetZ"), -1.0f, 1.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_position_offset_x{ModSlider::create(generate_name("RightControllerPositionOffsetX"), -1.0f, 1.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_position_offset_y{ModSlider::create(generate_name("RightControllerPositionOffsetY"), -1.0f, 1.0f, 0.0f)};
const ModSlider::Ptr m_right_controller_position_offset_z{ModSlider::create(generate_name("RightControllerPositionOffsetZ"), -1.0f, 1.0f, 0.0f)};
struct DPadGestureState {
std::recursive_mutex mtx{};
enum Direction : uint8_t {
NONE,
UP = 1 << 0,
RIGHT = 1 << 1,
DOWN = 1 << 2,
LEFT = 1 << 3,
};
uint8_t direction{NONE};
} m_dpad_gesture_state{};
//const ModToggle::Ptr m_headlocked_aim{ ModToggle::create(generate_name("HeadLockedAim"), false) };
//const ModToggle::Ptr m_headlocked_aim_controller_based{ ModToggle::create(generate_name("HeadLockedAimControllerBased"), false) };
const ModSlider::Ptr m_motion_controls_inactivity_timer{ ModSlider::create(generate_name("MotionControlsInactivityTimer"), 30.0f, 100.0f, 30.0f) };
const ModSlider::Ptr m_joystick_deadzone{ ModSlider::create(generate_name("JoystickDeadzone"), 0.01f, 0.9f, 0.2f) };
const ModSlider::Ptr m_camera_forward_offset{ ModSlider::create(generate_name("CameraForwardOffset"), -4000.0f, 4000.0f, 0.0f) };
const ModSlider::Ptr m_camera_right_offset{ ModSlider::create(generate_name("CameraRightOffset"), -4000.0f, 4000.0f, 0.0f) };
const ModSlider::Ptr m_camera_up_offset{ ModSlider::create(generate_name("CameraUpOffset"), -4000.0f, 4000.0f, 0.0f) };
const ModSlider::Ptr m_camera_fov_distance_multiplier{ ModSlider::create(generate_name("CameraFOVDistanceMultiplier"), 0.00f, 1000.0f, 0.0f) };
const ModSlider::Ptr m_world_scale{ ModSlider::create(generate_name("WorldScale"), 0.01f, 10.0f, 1.0f) };
const ModSlider::Ptr m_depth_scale{ ModSlider::create(generate_name("DepthScale"), 0.01f, 1.0f, 1.0f) };
const ModToggle::Ptr m_ghosting_fix{ ModToggle::create(generate_name("GhostingFix"), false) };
const ModSlider::Ptr m_custom_z_near{ ModSlider::create(generate_name("CustomZNear"), 0.001f, 100.0f, 0.01f, true) };
const ModToggle::Ptr m_custom_z_near_enabled{ ModToggle::create(generate_name("EnableCustomZNear"), false, true) };
const ModToggle::Ptr m_splitscreen_compatibility_mode{ ModToggle::create(generate_name("Compatibility_SplitScreen"), false, true) };
const ModInt32::Ptr m_splitscreen_view_index{ ModInt32::create(generate_name("SplitscreenViewIndex"), 0, true) };
const ModToggle::Ptr m_sceneview_compatibility_mode{ ModToggle::create(generate_name("Compatibility_SceneView"), false, true) };
const ModToggle::Ptr m_compatibility_skip_pip{ ModToggle::create(generate_name("Compatibility_SkipPostInitProperties"), false, true) };
const ModToggle::Ptr m_compatibility_skip_uobjectarray_init{ ModToggle::create(generate_name("Compatibility_SkipUObjectArrayInit"), false, true) };
const ModToggle::Ptr m_compatibility_ahud{ ModToggle::create(generate_name("Compatibility_AHUD"), false, true) };
// Keybinds
const ModKey::Ptr m_keybind_recenter{ ModKey::create(generate_name("RecenterViewKey")) };
const ModKey::Ptr m_keybind_set_standing_origin{ ModKey::create(generate_name("ResetStandingOriginKey")) };
const ModKey::Ptr m_keybind_load_camera_0{ ModKey::create(generate_name("LoadCamera0Key")) };
const ModKey::Ptr m_keybind_load_camera_1{ ModKey::create(generate_name("LoadCamera1Key")) };
const ModKey::Ptr m_keybind_load_camera_2{ ModKey::create(generate_name("LoadCamera2Key")) };
const ModKey::Ptr m_keybind_toggle_2d_screen{ ModKey::create(generate_name("Toggle2DScreenKey")) };
const ModKey::Ptr m_keybind_disable_vr{ ModKey::create(generate_name("DisableVRKey")) };
bool m_disable_vr{false}; // definitely should not be persistent
const ModKey::Ptr m_keybind_toggle_gui{ ModKey::create(generate_name("ToggleSlateGUIKey")) };
const ModString::Ptr m_requested_runtime_name{ ModString::create("Frontend_RequestedRuntime", "unset") };
struct DecoupledPitchData {
mutable std::shared_mutex mtx{};
glm::quat pre_flattened_rotation{};
} m_decoupled_pitch_data{};
struct CameraFreeze {
glm::vec3 position{};
glm::vec3 rotation{}; // euler
bool position_frozen{false};
bool rotation_frozen{false};
bool position_wants_freeze{false};
bool rotation_wants_freeze{false};
} m_camera_freeze{};
struct CameraData {
glm::vec3 offset{};
float world_scale{1.0f};
bool decoupled_pitch{false};
bool decoupled_pitch_ui_adjust{true};
};
std::array<CameraData, 3> m_camera_datas{};
void save_cameras();
void load_cameras();
void load_camera(int index);
void save_camera(int index);
bool m_stereo_emulation_mode{false}; // not a good config option, just for debugging
bool m_wait_for_present{true};
bool m_controllers_allowed{true};
bool m_controller_test_mode{false};
ValueList m_options{
*m_rendering_method,
*m_synced_afr_method,
*m_extreme_compat_mode,
*m_uncap_framerate,
*m_disable_hdr_compositing,
*m_disable_hzbocclusion,
*m_disable_instance_culling,
*m_desktop_fix,
*m_enable_gui,
*m_enable_depth,
*m_decoupled_pitch,
*m_decoupled_pitch_ui_adjust,
*m_load_blueprint_code,
*m_2d_screen_mode,