diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 359ab2a991372e2a119bc043d26485b5a2e4fa8e..a04763c60e0f5c014a1dc04395d381df66262c53 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ include: - project: '${UNREAL_CI_PROJECT}' - ref: master + ref: master file: '/shared_scripts.yml' # In this file you are able to configure your plugins pipeline. @@ -36,6 +36,11 @@ include: # # You can uncomment the deploy lines to deploy your project to the CAVE/VRDev. This only makes sense, if your plugin works # with a generated project. +# +# Use the UNREAL_VERSION variable to adjust to your preferred Unreal version. + +variables: + UNREAL_VERSION: "5.3" stages: - analyze @@ -58,7 +63,7 @@ clang-format: allow_failure: false script: - clang-format --version - - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME --depth 1 + - git fetch --depth 1 origin $CI_MERGE_REQUEST_DIFF_BASE_SHA - echo $CI_MERGE_REQUEST_DIFF_BASE_SHA - linter_errors=$(unbuffer git-clang-format --commit "$CI_MERGE_REQUEST_DIFF_BASE_SHA" *.h *.cpp -q --diff | grep -v --color=always "no modified files to format" || true) - echo "$linter_errors" @@ -68,10 +73,12 @@ Generate_Project: rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH extends: .Generate_Project_ variables: RUN_SETUP: "false" - GEN_TEMPLATE_BRANCH: "5.3" GEN_DEPENDENCIES: "( [master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git')" @@ -80,6 +87,9 @@ Build_Windows: rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH extends: .Build_Windows_ tags: - windows @@ -97,6 +107,9 @@ Build_Linux: rules: - if: $CI_PIPELINE_SOURCE == "web" - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH extends: .Build_Linux_ tags: - linux @@ -111,6 +124,7 @@ Build_Linux: - job: "Generate_Project" artifacts: true +# Deploys to vrdev Deploy_Windows: rules: - if: $CI_PIPELINE_SOURCE == "web" @@ -120,6 +134,7 @@ Deploy_Windows: - job: "Build_Windows" artifacts: true +# Deploys to vrdemo instead of av006de. Use extends: .Deploy_CAVE_ to deploy to legacy av006de Deploy_CAVE: rules: - if: $CI_PIPELINE_SOURCE == "web" diff --git a/Config/DefaultRWTHVRToolkit.ini b/Config/DefaultRWTHVRToolkit.ini index 29ee91a7aaabc28feebf6357b1672bdd652ff613..13066ebe26e8ab454486f97bbb982275d9b2587c 100644 --- a/Config/DefaultRWTHVRToolkit.ini +++ b/Config/DefaultRWTHVRToolkit.ini @@ -4,4 +4,18 @@ +StructRedirects = (OldName="/Script/RWTHVRToolkit.VRTransformRep",NewName="/Script/RWTHVRToolkit.ReplicatedTransform") +ClassRedirects = (OldName="/Script/RWTHVRToolkit.VRWidgetInteractionComponent",NewName="/Script/RWTHVRToolkit.RWTHVRWidgetInteractionComponent") +PropertyRedirects = (OldName="/Script/RWTHVRToolkit.RWTHVRPawn.PawnMovement",NewName="/Script/RWTHVRToolkit.RWTHVRPawn.CollisionHandlingMovement") -+PropertyRedirects = (OldName="/Script/RWTHVRToolkit.RWTHVRPawn.PawnMovement",NewName="/Script/RWTHVRToolkit.RWTHVRPawn.CollisionHandlingMovement") \ No newline at end of file ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.RWTHVRPawn.PawnMovement",NewName="/Script/RWTHVRToolkit.RWTHVRPawn.CollisionHandlingMovement") ++ClassRedirects = (OldName="/Script/RWTHVRToolkit.RaycastSelectionComponent",NewName="/Script/RWTHVRToolkit.RaycastInteractionComponent") ++ClassRedirects = (OldName="/Script/RWTHVRToolkit.GrabComponent",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent") ++FunctionRedirects = (OldName="/Script/RWTHVRToolkit.RaycastInteractionComponent.OnBeginSelect",NewName="/Script/RWTHVRToolkit.RaycastInteractionComponent.OnBeginInteraction") ++FunctionRedirects = (OldName="/Script/RWTHVRToolkit.RaycastInteractionComponent.OnEndSelect",NewName="/Script/RWTHVRToolkit.RaycastInteractionComponent.OnEndInteraction") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.RaycastInteractionComponent.RayCastSelectInputAction",NewName="/Script/RWTHVRToolkit.RaycastInteractionComponent.RayCastInteractionInputAction") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.RaycastInteractionComponent.RayCastInteractionInputAction",NewName="/Script/RWTHVRToolkit.RaycastInteractionComponent.InteractionInputAction") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousGrabbablesInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousInteractableComponentsInRange") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.GrabInputAction",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.InteractionInputAction") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.GrabSphereRadius",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.InteractionSphereRadius") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.bOnlyGrabClosestActor",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.bOnlyInteractWithClosestActor") ++FunctionRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnBeginGrab",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnBeginInteraction") ++FunctionRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndGrab",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.OnEndInteraction") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.PreviousInteractableComponentsInRange") ++PropertyRedirects = (OldName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentGrabBehavioursInRange",NewName="/Script/RWTHVRToolkit.DirectInteractionComponent.CurrentInteractableComponentsInRange") \ No newline at end of file diff --git a/Content/BP_RWTHVRGameModeBase.uasset b/Content/BP_RWTHVRGameModeBase.uasset index 06db2806ba4271750b06549bc76becfdb32a2ba2..a073a7f7cc247654e724c9d348d57f9bdc55d9ed 100644 Binary files a/Content/BP_RWTHVRGameModeBase.uasset and b/Content/BP_RWTHVRGameModeBase.uasset differ diff --git a/Content/BP_RWTHVRPawn.uasset b/Content/BP_RWTHVRPawn.uasset deleted file mode 100644 index 871461e6ffad1c644424221840b57799c9433fe9..0000000000000000000000000000000000000000 Binary files a/Content/BP_RWTHVRPawn.uasset and /dev/null differ diff --git a/Content/Components/DirectInteraction/BP_DirectInteractionComponent.uasset b/Content/Components/DirectInteraction/BP_DirectInteractionComponent.uasset new file mode 100644 index 0000000000000000000000000000000000000000..840b43fab2eba1c474284e57c0018ec0d7babaaf Binary files /dev/null and b/Content/Components/DirectInteraction/BP_DirectInteractionComponent.uasset differ diff --git a/Content/Components/DirectInteraction/IA_DirectInteractionLeft.uasset b/Content/Components/DirectInteraction/IA_DirectInteractionLeft.uasset new file mode 100644 index 0000000000000000000000000000000000000000..05597e706243b8138bcea4da36fcc87849b6ba51 Binary files /dev/null and b/Content/Components/DirectInteraction/IA_DirectInteractionLeft.uasset differ diff --git a/Content/Components/DirectInteraction/IA_DirectInteractionRight.uasset b/Content/Components/DirectInteraction/IA_DirectInteractionRight.uasset new file mode 100644 index 0000000000000000000000000000000000000000..76128dfe613f4825b57d9a27ac9c93e1829554de Binary files /dev/null and b/Content/Components/DirectInteraction/IA_DirectInteractionRight.uasset differ diff --git a/Content/Components/Grabbing/BP_GrabComponent.uasset b/Content/Components/Grabbing/BP_GrabComponent.uasset deleted file mode 100644 index 5e0430e93aee43918ea62d4465f86e3812efe423..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/BP_GrabComponent.uasset and /dev/null differ diff --git a/Content/Components/Grabbing/BP_GrabbableObjectTest.uasset b/Content/Components/Grabbing/BP_GrabbableObjectTest.uasset deleted file mode 100644 index 6300ab49226dce334df0826293f3d583c7605c07..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/BP_GrabbableObjectTest.uasset and /dev/null differ diff --git a/Content/Components/Grabbing/BP_GrabbableTestObject.uasset b/Content/Components/Grabbing/BP_GrabbableTestObject.uasset deleted file mode 100644 index 9ee3c8f375ef05e90f3c3f8300b6a13f94def5c6..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/BP_GrabbableTestObject.uasset and /dev/null differ diff --git a/Content/Components/Grabbing/IA_GrabLeft.uasset b/Content/Components/Grabbing/IA_GrabLeft.uasset deleted file mode 100644 index bcc873bcdbf823add969db4e7528603617badb84..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/IA_GrabLeft.uasset and /dev/null differ diff --git a/Content/Components/Grabbing/IA_GrabRight.uasset b/Content/Components/Grabbing/IA_GrabRight.uasset deleted file mode 100644 index 9df17caed4d5b4f6e8da91e219ffde3fdb72c21e..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/IA_GrabRight.uasset and /dev/null differ diff --git a/Content/Components/Grabbing/IMC_Grab.uasset b/Content/Components/Grabbing/IMC_Grab.uasset deleted file mode 100644 index 47abc9f0ea07957df2f54c0c80f683d07a14fadc..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/IMC_Grab.uasset and /dev/null differ diff --git a/Content/Components/Movement/ContinuousMovement/BP_ContinuousMovementComponent.uasset b/Content/Components/Movement/ContinuousMovement/BP_ContinuousMovementComponent.uasset index 83b1677640b9495da4155029b2b3f320a66ccb81..6885feec7ec19c1fd7f5771d379225ebd86dd0e1 100644 Binary files a/Content/Components/Movement/ContinuousMovement/BP_ContinuousMovementComponent.uasset and b/Content/Components/Movement/ContinuousMovement/BP_ContinuousMovementComponent.uasset differ diff --git a/Content/Components/Movement/IMC_MovementLeftHand.uasset b/Content/Components/Movement/IMC_MovementLeftHand.uasset deleted file mode 100644 index d871b2eb4545c1acbc81470a80ae950683a574bc..0000000000000000000000000000000000000000 Binary files a/Content/Components/Movement/IMC_MovementLeftHand.uasset and /dev/null differ diff --git a/Content/Components/Movement/IMC_MovementRightHand.uasset b/Content/Components/Movement/IMC_MovementRightHand.uasset deleted file mode 100644 index b1eb664d5e755f86858f40ad6737e87e9dd29a0c..0000000000000000000000000000000000000000 Binary files a/Content/Components/Movement/IMC_MovementRightHand.uasset and /dev/null differ diff --git a/Content/Components/Movement/Teleportation/BP_TeleportationComponent.uasset b/Content/Components/Movement/Teleportation/BP_TeleportationComponent.uasset index d83f23de6da316687028de4c6a45713918bee2f4..724895615850f01d9d665e8b40569d5829fc4574 100644 Binary files a/Content/Components/Movement/Teleportation/BP_TeleportationComponent.uasset and b/Content/Components/Movement/Teleportation/BP_TeleportationComponent.uasset differ diff --git a/Content/Components/Movement/Turn/BP_TurnComponent.uasset b/Content/Components/Movement/Turn/BP_TurnComponent.uasset index e135a8eca226aa6043ca8dcdb87932775aadc93b..a572594744827a04a0a6a6b1912e80ef9be86297 100644 Binary files a/Content/Components/Movement/Turn/BP_TurnComponent.uasset and b/Content/Components/Movement/Turn/BP_TurnComponent.uasset differ diff --git a/Content/Components/Movement/Turn/IMC_DesktopRotation.uasset b/Content/Components/Movement/Turn/IMC_DesktopRotation.uasset deleted file mode 100644 index d68fb4eae4e33f04237249477b5a9994cb6b2721..0000000000000000000000000000000000000000 Binary files a/Content/Components/Movement/Turn/IMC_DesktopRotation.uasset and /dev/null differ diff --git a/Content/Components/Raycast/BP_RaycastSelectionComponent.uasset b/Content/Components/Raycast/BP_RaycastSelectionComponent.uasset deleted file mode 100644 index 4900352dfaa28d6b6f38c595e44bbc889891c947..0000000000000000000000000000000000000000 Binary files a/Content/Components/Raycast/BP_RaycastSelectionComponent.uasset and /dev/null differ diff --git a/Content/Components/Raycast/IA_RaycastSelectLeft.uasset b/Content/Components/Raycast/IA_RaycastSelectLeft.uasset deleted file mode 100644 index 16139611e6a786a71823592bd78c1feb2518862d..0000000000000000000000000000000000000000 Binary files a/Content/Components/Raycast/IA_RaycastSelectLeft.uasset and /dev/null differ diff --git a/Content/Components/Raycast/IA_RaycastSelectRight.uasset b/Content/Components/Raycast/IA_RaycastSelectRight.uasset deleted file mode 100644 index 201c652c77e03a56b9c67e9fcfce356d16e10f3c..0000000000000000000000000000000000000000 Binary files a/Content/Components/Raycast/IA_RaycastSelectRight.uasset and /dev/null differ diff --git a/Content/Components/Raycast/IMC_RaycastSelection.uasset b/Content/Components/Raycast/IMC_RaycastSelection.uasset deleted file mode 100644 index c8107a17d2a2759c51d57c42495245273d290947..0000000000000000000000000000000000000000 Binary files a/Content/Components/Raycast/IMC_RaycastSelection.uasset and /dev/null differ diff --git a/Content/Components/RaycastInteraction/BP_RaycastInteractionComponent.uasset b/Content/Components/RaycastInteraction/BP_RaycastInteractionComponent.uasset new file mode 100644 index 0000000000000000000000000000000000000000..2416ad8fba677355d3d0f1fc8a1708b90bc8fb12 Binary files /dev/null and b/Content/Components/RaycastInteraction/BP_RaycastInteractionComponent.uasset differ diff --git a/Content/Components/RaycastInteraction/IA_RaycastInteractionLeft.uasset b/Content/Components/RaycastInteraction/IA_RaycastInteractionLeft.uasset new file mode 100644 index 0000000000000000000000000000000000000000..13494f735ac48c8c86551b18695f3a0cd064d524 Binary files /dev/null and b/Content/Components/RaycastInteraction/IA_RaycastInteractionLeft.uasset differ diff --git a/Content/Components/RaycastInteraction/IA_RaycastInteractionRight.uasset b/Content/Components/RaycastInteraction/IA_RaycastInteractionRight.uasset new file mode 100644 index 0000000000000000000000000000000000000000..f6ffa30dcc98699d57b19eacfa02bd0701e076e0 Binary files /dev/null and b/Content/Components/RaycastInteraction/IA_RaycastInteractionRight.uasset differ diff --git a/Content/Components/WidgetInteraction/BP_RWTHVRWidgetInteractionComponent.uasset b/Content/Components/WidgetInteraction/BP_RWTHVRWidgetInteractionComponent.uasset index bbbac1fc6516d46209168216f4d8b502e88f0a38..904f5d3363442da0ff916b54041f595a4e023ffc 100644 Binary files a/Content/Components/WidgetInteraction/BP_RWTHVRWidgetInteractionComponent.uasset and b/Content/Components/WidgetInteraction/BP_RWTHVRWidgetInteractionComponent.uasset differ diff --git a/Content/Components/WidgetInteraction/IA_WidgetClick.uasset b/Content/Components/WidgetInteraction/IA_WidgetClick.uasset index 1e8b6c8dbba9ffe7beac263c84b4c800c521e468..a178015abe4a9f945703f46f936b35b97850bc91 100644 Binary files a/Content/Components/WidgetInteraction/IA_WidgetClick.uasset and b/Content/Components/WidgetInteraction/IA_WidgetClick.uasset differ diff --git a/Content/Components/WidgetInteraction/IMC_WidgetInteraction.uasset b/Content/Components/WidgetInteraction/IMC_WidgetInteraction.uasset deleted file mode 100644 index d3751897c41b760e653f74954ff29956897cd671..0000000000000000000000000000000000000000 Binary files a/Content/Components/WidgetInteraction/IMC_WidgetInteraction.uasset and /dev/null differ diff --git a/Content/Examples/ContentExamples/BP_RWTHVRContentExamplesGameModeBase.uasset b/Content/Examples/ContentExamples/BP_RWTHVRContentExamplesGameModeBase.uasset new file mode 100644 index 0000000000000000000000000000000000000000..352e801778bc4dd955b5a1a4fcea0f973b37a1cf Binary files /dev/null and b/Content/Examples/ContentExamples/BP_RWTHVRContentExamplesGameModeBase.uasset differ diff --git a/Content/Examples/ContentExamples/DemoAssets/BP_GrabbableTestObject.uasset b/Content/Examples/ContentExamples/DemoAssets/BP_GrabbableTestObject.uasset new file mode 100644 index 0000000000000000000000000000000000000000..00436a8ef34d22cb949180832fb6717255ed1c98 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoAssets/BP_GrabbableTestObject.uasset differ diff --git a/Content/Examples/ContentExamples/DemoAssets/BP_IntenselectableObject.uasset b/Content/Examples/ContentExamples/DemoAssets/BP_IntenselectableObject.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ad3229202c1db904c6f218802fdbc86d33d8fc44 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoAssets/BP_IntenselectableObject.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/BP_DemoRoom.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/BP_DemoRoom.uasset new file mode 100644 index 0000000000000000000000000000000000000000..8d44e3029f0810051a7b749688b3440afff8e7ed Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/BP_DemoRoom.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/BP_Demostation.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/BP_Demostation.uasset new file mode 100644 index 0000000000000000000000000000000000000000..97a2b6c1fd75976d41f6be2ce09463f72d594432 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/BP_Demostation.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_back_piller.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_back_piller.uasset new file mode 100644 index 0000000000000000000000000000000000000000..5ea4eeae269ac2a5ced17512441e6553f15b3e9d Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_back_piller.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_connector.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_connector.uasset new file mode 100644 index 0000000000000000000000000000000000000000..23da0e9f10b0195e1989f82c36d6823c8a1f1d5f Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_connector.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_floor.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_floor.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ecc96bc983b194433b1ac5d28ae7e9cc66466685 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_floor.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_front_pillar.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_front_pillar.uasset new file mode 100644 index 0000000000000000000000000000000000000000..45afb30f73d17fbb06b17c5094f3b45f53953a20 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_front_pillar.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_long_wall.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_long_wall.uasset new file mode 100644 index 0000000000000000000000000000000000000000..45f4726ee04ed13fa708367db11e51e7a2b3d00a Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_long_wall.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_short_wall.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_short_wall.uasset new file mode 100644 index 0000000000000000000000000000000000000000..41b2612ae5c28c58726de02a01ac0653b9fe1c6b Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_short_wall.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_vertical_end_piller.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_vertical_end_piller.uasset new file mode 100644 index 0000000000000000000000000000000000000000..50a800b203f84ac8d8c20a92c5a52ffdd82e5c94 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomAssets_vertical_end_piller.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomTest.umap b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomTest.umap new file mode 100644 index 0000000000000000000000000000000000000000..6be975361c9574680f74d95ff7bf292077eb7674 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/DemoRoomTest.umap differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Entrance_Pillars.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Entrance_Pillars.uasset new file mode 100644 index 0000000000000000000000000000000000000000..2bbac6b5b367deb14eb705d565330dff3e1e2c73 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Entrance_Pillars.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Floor.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Floor.uasset new file mode 100644 index 0000000000000000000000000000000000000000..2d35c3d3567c1b1d933bd1d6d0856a73c55e0398 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Floor.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Frame.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Frame.uasset new file mode 100644 index 0000000000000000000000000000000000000000..add5d5f739c5dabd1151080881594c4d0457dfb0 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Frame.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Inner_Walls.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Inner_Walls.uasset new file mode 100644 index 0000000000000000000000000000000000000000..536ff38d226d282001023852d0ac859e52f198c7 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Inner_Walls.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Interior.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Interior.uasset new file mode 100644 index 0000000000000000000000000000000000000000..a1416e648a43482d0dddcc8e8db12a5b6bcf9453 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Interior.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Pillars.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Pillars.uasset new file mode 100644 index 0000000000000000000000000000000000000000..3f5d03a620faf69dccb1e197e26733a1f9f4a03d Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Pillars.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Walls.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Walls.uasset new file mode 100644 index 0000000000000000000000000000000000000000..7d4cce614f650980991e92d295cfbd644d629768 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/Outer_Walls.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/S_RoomSettings.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/S_RoomSettings.uasset new file mode 100644 index 0000000000000000000000000000000000000000..8f0d598d8eb1c659cf39951b600768f0b66ba884 Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/S_RoomSettings.uasset differ diff --git a/Content/Examples/ContentExamples/DemoRoomAssets/demostation.uasset b/Content/Examples/ContentExamples/DemoRoomAssets/demostation.uasset new file mode 100644 index 0000000000000000000000000000000000000000..0ca2d2b37cb8d0f3e9d9a5207b87b50db51bbf2d Binary files /dev/null and b/Content/Examples/ContentExamples/DemoRoomAssets/demostation.uasset differ diff --git a/Content/Examples/ContentExamples/Pawns/BP_ContentExamplesPawn.uasset b/Content/Examples/ContentExamples/Pawns/BP_ContentExamplesPawn.uasset new file mode 100644 index 0000000000000000000000000000000000000000..12de4cfc6edddae40e7e026cb9ab082f1e8f4f57 Binary files /dev/null and b/Content/Examples/ContentExamples/Pawns/BP_ContentExamplesPawn.uasset differ diff --git a/Content/Examples/ContentExamples/Pawns/BP_TeleportPawn.uasset b/Content/Examples/ContentExamples/Pawns/BP_TeleportPawn.uasset new file mode 100644 index 0000000000000000000000000000000000000000..df1abb51e6dc3aa7f555518abba1c2af5673e941 Binary files /dev/null and b/Content/Examples/ContentExamples/Pawns/BP_TeleportPawn.uasset differ diff --git a/Content/Examples/ContentExamples/ToolkitExamples.umap b/Content/Examples/ContentExamples/ToolkitExamples.umap new file mode 100644 index 0000000000000000000000000000000000000000..c6e4c2d650345e901032eb8d009b9d65375209a0 Binary files /dev/null and b/Content/Examples/ContentExamples/ToolkitExamples.umap differ diff --git a/Content/Examples/ContentExamples/Trigger/ContinuousNavigationModeTrigger.uasset b/Content/Examples/ContentExamples/Trigger/ContinuousNavigationModeTrigger.uasset new file mode 100644 index 0000000000000000000000000000000000000000..b9a5a2d6c5c3600a9a06c3c61f93fa41d7cd9e1d Binary files /dev/null and b/Content/Examples/ContentExamples/Trigger/ContinuousNavigationModeTrigger.uasset differ diff --git a/Content/Examples/ContentExamples/Trigger/InteractionTechniqueSwapTrigger.uasset b/Content/Examples/ContentExamples/Trigger/InteractionTechniqueSwapTrigger.uasset new file mode 100644 index 0000000000000000000000000000000000000000..befe62fdd1270d6b73eb65b72389135736c48194 Binary files /dev/null and b/Content/Examples/ContentExamples/Trigger/InteractionTechniqueSwapTrigger.uasset differ diff --git a/Content/Examples/ContentExamples/Trigger/InteractionTechniquesEnum.uasset b/Content/Examples/ContentExamples/Trigger/InteractionTechniquesEnum.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e190eb6cdc40f4fa0ebbac9e2df65010861d5175 Binary files /dev/null and b/Content/Examples/ContentExamples/Trigger/InteractionTechniquesEnum.uasset differ diff --git a/Content/Examples/ContentExamples/Trigger/MovementTechniqueSwapTrigger.uasset b/Content/Examples/ContentExamples/Trigger/MovementTechniqueSwapTrigger.uasset new file mode 100644 index 0000000000000000000000000000000000000000..a556443085f9812425130d006a164d2794663286 Binary files /dev/null and b/Content/Examples/ContentExamples/Trigger/MovementTechniqueSwapTrigger.uasset differ diff --git a/Content/Examples/ContentExamples/Widgets/BP_PawnSwapWidgetActor.uasset b/Content/Examples/ContentExamples/Widgets/BP_PawnSwapWidgetActor.uasset new file mode 100644 index 0000000000000000000000000000000000000000..7de08ef1c98e59cc7d62d4bc8164f8b8f7f0064b Binary files /dev/null and b/Content/Examples/ContentExamples/Widgets/BP_PawnSwapWidgetActor.uasset differ diff --git a/Content/Examples/ContentExamples/Widgets/BP_WidgetDemoActor.uasset b/Content/Examples/ContentExamples/Widgets/BP_WidgetDemoActor.uasset new file mode 100644 index 0000000000000000000000000000000000000000..c2b90dabd57345042b7eee882cac86c362263fcf Binary files /dev/null and b/Content/Examples/ContentExamples/Widgets/BP_WidgetDemoActor.uasset differ diff --git a/Content/Examples/ContentExamples/Widgets/ClickMeWidget.uasset b/Content/Examples/ContentExamples/Widgets/ClickMeWidget.uasset new file mode 100644 index 0000000000000000000000000000000000000000..768cccd381e6301ccf231ab4c65a0d58013bd091 Binary files /dev/null and b/Content/Examples/ContentExamples/Widgets/ClickMeWidget.uasset differ diff --git a/Content/Examples/ContentExamples/Widgets/DemostationTextboxWidget.uasset b/Content/Examples/ContentExamples/Widgets/DemostationTextboxWidget.uasset new file mode 100644 index 0000000000000000000000000000000000000000..a7229820c76120bf8512efb6e80774ba9234b7b1 Binary files /dev/null and b/Content/Examples/ContentExamples/Widgets/DemostationTextboxWidget.uasset differ diff --git a/Content/Examples/ContentExamples/Widgets/PawnSwapButtonWidget.uasset b/Content/Examples/ContentExamples/Widgets/PawnSwapButtonWidget.uasset new file mode 100644 index 0000000000000000000000000000000000000000..9cecb1a60ef49a050785e4a8be89b1cecb3f429c Binary files /dev/null and b/Content/Examples/ContentExamples/Widgets/PawnSwapButtonWidget.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_1.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_1.uasset new file mode 100644 index 0000000000000000000000000000000000000000..508ca517427740d74f5e596b0d9e378f48117c33 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_1.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_2.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_2.uasset new file mode 100644 index 0000000000000000000000000000000000000000..420f7e315158df8ef6e4028acbced2bbb51d85ae Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_2.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_3.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_3.uasset new file mode 100644 index 0000000000000000000000000000000000000000..47afecc29c1e3f62b491acc7854bfa1d50db0a8d Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_3.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_4.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_4.uasset new file mode 100644 index 0000000000000000000000000000000000000000..84b8c18241ae1ee4ab4c3f54c6ff62d42d54f712 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_4.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_5.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_5.uasset new file mode 100644 index 0000000000000000000000000000000000000000..671644137e556a38dedb290ab37af6441f07cadc Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_RE_1_5.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_loc_NoReplication.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_loc_NoReplication.uasset new file mode 100644 index 0000000000000000000000000000000000000000..bae3d13ba6cb9a74392e09be4164398703e14b26 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_loc_NoReplication.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_loc_replication.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_loc_replication.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e9cd209b391355e3fb07d6f55955bfd40d56673f Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_loc_replication.uasset differ diff --git a/Content/Examples/ReplicationExamples/Blueprints/BP_locomotive.uasset b/Content/Examples/ReplicationExamples/Blueprints/BP_locomotive.uasset new file mode 100644 index 0000000000000000000000000000000000000000..2724d42266c4cb10acf64f9a487febc5690129eb Binary files /dev/null and b/Content/Examples/ReplicationExamples/Blueprints/BP_locomotive.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/BP_locomotiveAnimation.uasset b/Content/Examples/ReplicationExamples/Models/BP_locomotiveAnimation.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ddcbf601baf38f4f0472d2783f3ab7627b00fc2e Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/BP_locomotiveAnimation.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/Face.uasset b/Content/Examples/ReplicationExamples/Models/Face.uasset new file mode 100644 index 0000000000000000000000000000000000000000..7598f465681158ca6a69a0f28bb0af32ce720374 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/Face.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/Light_Wood.uasset b/Content/Examples/ReplicationExamples/Models/Light_Wood.uasset new file mode 100644 index 0000000000000000000000000000000000000000..863feba2dc1a30b9b4b4561a2e15c9745611e1d6 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/Light_Wood.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/Wood.uasset b/Content/Examples/ReplicationExamples/Models/Wood.uasset new file mode 100644 index 0000000000000000000000000000000000000000..bee85f8a54443363e77fa93bc3d24032e10d1a49 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/Wood.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/locomotive.uasset b/Content/Examples/ReplicationExamples/Models/locomotive.uasset new file mode 100644 index 0000000000000000000000000000000000000000..4a95384c5a33996a5e154071353d894a529fcce1 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/locomotive.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/locomotive_Anim.uasset b/Content/Examples/ReplicationExamples/Models/locomotive_Anim.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e86db372697b2d2055ba03add82b8c44a2df4f35 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/locomotive_Anim.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/locomotive_PhysicsAsset.uasset b/Content/Examples/ReplicationExamples/Models/locomotive_PhysicsAsset.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ec5180e98b5356e1fa56e38aa923bbbf64b3bb57 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/locomotive_PhysicsAsset.uasset differ diff --git a/Content/Examples/ReplicationExamples/Models/locomotive_Skeleton.uasset b/Content/Examples/ReplicationExamples/Models/locomotive_Skeleton.uasset new file mode 100644 index 0000000000000000000000000000000000000000..eb26f1c4e6417620c517b3c9eb8b9b6cb88552d0 Binary files /dev/null and b/Content/Examples/ReplicationExamples/Models/locomotive_Skeleton.uasset differ diff --git a/Content/Examples/ReplicationExamples/ReplicationExamples.umap b/Content/Examples/ReplicationExamples/ReplicationExamples.umap new file mode 100644 index 0000000000000000000000000000000000000000..a1efcfc296c7bad836afe5394bdd832ac53862e5 Binary files /dev/null and b/Content/Examples/ReplicationExamples/ReplicationExamples.umap differ diff --git a/Content/Input/Default_IMC/IMC_General.uasset b/Content/Input/Default_IMC/IMC_General.uasset new file mode 100644 index 0000000000000000000000000000000000000000..cc0bd4ea6d18ace71a9ae2a0b53af84f42689540 Binary files /dev/null and b/Content/Input/Default_IMC/IMC_General.uasset differ diff --git a/Content/Input/Default_IMC/IMC_MovementLeftHand.uasset b/Content/Input/Default_IMC/IMC_MovementLeftHand.uasset new file mode 100644 index 0000000000000000000000000000000000000000..1be9e555bfd0713434a650308d6892ad2e0b7204 Binary files /dev/null and b/Content/Input/Default_IMC/IMC_MovementLeftHand.uasset differ diff --git a/Content/Input/Default_IMC/IMC_MovementRightHand.uasset b/Content/Input/Default_IMC/IMC_MovementRightHand.uasset new file mode 100644 index 0000000000000000000000000000000000000000..4b8151454c391850d9a45ed68fce7babc360c10d Binary files /dev/null and b/Content/Input/Default_IMC/IMC_MovementRightHand.uasset differ diff --git a/Content/IntenSelect/DebugConeMaterial.uasset b/Content/IntenSelect/DebugConeMaterial.uasset new file mode 100644 index 0000000000000000000000000000000000000000..c4dab0863455baa2871fbeb2c871fbe0cc8c7d7c Binary files /dev/null and b/Content/IntenSelect/DebugConeMaterial.uasset differ diff --git a/Content/IntenSelect/DebugConeMesh.uasset b/Content/IntenSelect/DebugConeMesh.uasset new file mode 100644 index 0000000000000000000000000000000000000000..d0980e3b7ff615b970f3cb6e664e21d95a5c8370 Binary files /dev/null and b/Content/IntenSelect/DebugConeMesh.uasset differ diff --git a/Content/IntenSelect/ForwadRayMaterial.uasset b/Content/IntenSelect/ForwadRayMaterial.uasset new file mode 100644 index 0000000000000000000000000000000000000000..a7334c00a1eaffa105f0412bc5c3b64b5b93ed6a Binary files /dev/null and b/Content/IntenSelect/ForwadRayMaterial.uasset differ diff --git a/Content/IntenSelect/ForwardRayParams.uasset b/Content/IntenSelect/ForwardRayParams.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e2d764f568116dd7cc570374e9dbe09fd938afb8 Binary files /dev/null and b/Content/IntenSelect/ForwardRayParams.uasset differ diff --git a/Content/IntenSelect/ForwardRayTransparencyCurve.uasset b/Content/IntenSelect/ForwardRayTransparencyCurve.uasset new file mode 100644 index 0000000000000000000000000000000000000000..f81383ff048dbcce6f1f41662fdc3a80ac78203a Binary files /dev/null and b/Content/IntenSelect/ForwardRayTransparencyCurve.uasset differ diff --git a/Content/IntenSelect/IntenSelectClick.uasset b/Content/IntenSelect/IntenSelectClick.uasset new file mode 100644 index 0000000000000000000000000000000000000000..e14a0945ac964c604bd4ed0e0365e22142de84c3 Binary files /dev/null and b/Content/IntenSelect/IntenSelectClick.uasset differ diff --git a/Content/IntenSelect/OnSelectHapticFeedback.uasset b/Content/IntenSelect/OnSelectHapticFeedback.uasset new file mode 100644 index 0000000000000000000000000000000000000000..92bc614b540e759df6542d31d31c82f88a71ca4d Binary files /dev/null and b/Content/IntenSelect/OnSelectHapticFeedback.uasset differ diff --git a/Content/IntenSelect/OnSelectSound.uasset b/Content/IntenSelect/OnSelectSound.uasset new file mode 100644 index 0000000000000000000000000000000000000000..333e1cbc75a8dbf2b55213abec17152aa0cc16bf Binary files /dev/null and b/Content/IntenSelect/OnSelectSound.uasset differ diff --git a/Content/IntenSelect/RayMesh.uasset b/Content/IntenSelect/RayMesh.uasset new file mode 100644 index 0000000000000000000000000000000000000000..fd84f10b97df7c4733e742fffc20818b1b2d48ae Binary files /dev/null and b/Content/IntenSelect/RayMesh.uasset differ diff --git a/Content/IntenSelect/SelectionSplineMaterial.uasset b/Content/IntenSelect/SelectionSplineMaterial.uasset new file mode 100644 index 0000000000000000000000000000000000000000..51304ee722baefa035343f1a9b6295ef47abc286 Binary files /dev/null and b/Content/IntenSelect/SelectionSplineMaterial.uasset differ diff --git a/Content/IntenSelect/sectionedCubeMesh.uasset b/Content/IntenSelect/sectionedCubeMesh.uasset new file mode 100644 index 0000000000000000000000000000000000000000..536e047dcc5dad08d21ef951d97c71c4887e2b7d Binary files /dev/null and b/Content/IntenSelect/sectionedCubeMesh.uasset differ diff --git a/Content/Pawn/BP_RWTHVRPawn_Default.uasset b/Content/Pawn/BP_RWTHVRPawn_Default.uasset new file mode 100644 index 0000000000000000000000000000000000000000..6171681e8ed6e3a4eae1879d475dac62e33c4c99 Binary files /dev/null and b/Content/Pawn/BP_RWTHVRPawn_Default.uasset differ diff --git a/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset new file mode 100644 index 0000000000000000000000000000000000000000..591070e44ae18b1c035eba19b12492d94c47c7e2 Binary files /dev/null and b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset differ diff --git a/Content/PointingRay/Ray_Mesh.uasset b/Content/PointingRay/Ray_Mesh.uasset index 0da58a602c186aa1ac8d65ba57d2d966a78419b5..e502ceb154ffeb022d651c033f6e0e6ed9b5fbe2 100644 Binary files a/Content/PointingRay/Ray_Mesh.uasset and b/Content/PointingRay/Ray_Mesh.uasset differ diff --git a/Content/RWTHVRCluster/BP_CaveSetup.uasset b/Content/RWTHVRCluster/BP_CaveSetup.uasset index dc92619dc5d235655269978d874ea8e79228b564..fd882f7f9f9860373421e60fafde5f5b0c03a0cb 100644 Binary files a/Content/RWTHVRCluster/BP_CaveSetup.uasset and b/Content/RWTHVRCluster/BP_CaveSetup.uasset differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset b/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset index b98ef4a0d92337e6354a2b13a7b5fe78156bca8e..ab15ee9eb49fa5f0687da7bfff83330b505d4e03 100644 Binary files a/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset and b/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/IMC_Overlay.uasset b/Content/RWTHVRCluster/CAVEOverlay/IMC_Overlay.uasset deleted file mode 100644 index 23003cc697e730b961e3f32adad94eb1c46d8f37..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/IMC_Overlay.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/Config/aixcave_two_player.uasset b/Content/RWTHVRCluster/Config/aixcave_two_player.uasset index ea7cec76836a5ad51207c5b39a5baaebac7a81d9..f55c6f86b133bd41711850009ee28765f435949c 100644 Binary files a/Content/RWTHVRCluster/Config/aixcave_two_player.uasset and b/Content/RWTHVRCluster/Config/aixcave_two_player.uasset differ diff --git a/Content/TestMap.umap b/Content/TestMap.umap deleted file mode 100644 index 7011da4b6ba3919d325f4cce30ec9330e77770df..0000000000000000000000000000000000000000 Binary files a/Content/TestMap.umap and /dev/null differ diff --git a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp b/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp index 157e44d8a64c5d79b5aa6c8a0376838bc2c1842e..08d44b21a4e33283daa9a6a29b556beec0289cfa 100644 --- a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp +++ b/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp @@ -2,7 +2,6 @@ #include "CoreMinimal.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" #include "IDisplayCluster.h" #include "MotionControllerComponent.h" #include "Camera/CameraComponent.h" @@ -165,7 +164,7 @@ void ACAVEOverlayController::BeginPlay() // Input config if (URWTHVRUtilities::IsPrimaryNode()) { - if (CycleDoorTypeInputAction == nullptr || IMCCaveOverlayInputMapping == nullptr) + if (CycleDoorTypeInputAction == nullptr) { UE_LOGFMT(LogCAVEOverlay, Error, "Input action and mapping not set in CaveOverlayController!"); return; @@ -174,15 +173,6 @@ void ACAVEOverlayController::BeginPlay() UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PC->InputComponent); Input->BindAction(CycleDoorTypeInputAction, ETriggerEvent::Triggered, this, &ACAVEOverlayController::CycleDoorType); - - if (const ULocalPlayer* LocalPlayer = PC->GetLocalPlayer()) - { - if (UEnhancedInputLocalPlayerSubsystem* InputSystem = - LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) - { - InputSystem->AddMappingContext(IMCCaveOverlayInputMapping, 0); - } - } } // Bind the cluster events that manage the door state. diff --git a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h index 234344221310b07fe6fe657468100cb4e4e11714..148897a8713c726bc9583de176cf04040b657074 100644 --- a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h +++ b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h @@ -128,9 +128,6 @@ public: UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "CAVEOverlay") UInputAction* CycleDoorTypeInputAction; - UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "CAVEOverlay") - UInputMappingContext* IMCCaveOverlayInputMapping; - UPROPERTY() UDoorOverlayData* Overlay; diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp index 0ff95d0c6fc823faef1016badc7fb8330beb9679..1537243da0b6c92a901decadce793bc8bd819bbb 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp @@ -3,8 +3,9 @@ #include "Interaction/Interactables/GrabBehavior.h" #include "Interaction/Interactables/InteractableComponent.h" -#include "Kismet/GameplayStatics.h" +#include "Logging/StructuredLog.h" #include "Serialization/JsonTypes.h" +#include "Utility/RWTHVRUtilities.h" UPrimitiveComponent* UGrabBehavior::GetFirstComponentSimulatingPhysics(const AActor* TargetActor) { @@ -29,34 +30,42 @@ UPrimitiveComponent* UGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitive { return GetHighestParentSimulatingPhysics(Cast<UPrimitiveComponent>(Comp->GetAttachParent())); } - else - { - return Comp; - } + + return Comp; } void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, const FInputActionValue& Value) { - const APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0); - - USceneComponent* Hand = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); + if (bObjectGrabbed) + { + return; + } + USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); const FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, false); - MyPhysicsComponent = GetFirstComponentSimulatingPhysics(GetOwner()); - - if (MyPhysicsComponent) + if (MyPhysicsComponent = GetFirstComponentSimulatingPhysics(GetOwner()); MyPhysicsComponent != nullptr) { + bWasSimulatingPhysics = MyPhysicsComponent->IsSimulatingPhysics(); MyPhysicsComponent->SetSimulatePhysics(false); - MyPhysicsComponent->AttachToComponent(Hand, Rules); + bObjectGrabbed = MyPhysicsComponent->AttachToComponent(CurrentAttachParent, Rules); } else { - GetOwner()->GetRootComponent()->AttachToComponent(Hand, Rules); + bObjectGrabbed = GetOwner()->GetRootComponent()->AttachToComponent(CurrentAttachParent, Rules); } + if (!bObjectGrabbed) + { + UE_LOGFMT(Toolkit, Warning, "Grab failed! Cannot attach grabbed component to attach parent ({Parent})", + CurrentAttachParent->GetName()); + return; + } + // If we want to restrict other interactions while this component is grabbed we add the component + // that triggered the interaction to the whitelist of all interactables that are attached to the + // affected actor if (bBlockOtherInteractionsWhileGrabbed) { TArray<UInteractableComponent*> Interactables; @@ -66,21 +75,28 @@ void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UIn Interactable->RestrictInteractionToComponent(TriggeredComponent); } } + + OnGrabStartEvent.Broadcast(CurrentAttachParent, MyPhysicsComponent); } void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, const FInputActionValue& Value) { - if (MyPhysicsComponent) - { - MyPhysicsComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); - MyPhysicsComponent->SetSimulatePhysics(true); - } - else + + USceneComponent* CurrentAttachParent = Cast<USceneComponent>(TriggeredComponent->GetAttachParent()); + + // We try to release the attached component. If it is not succesful we log and return. Otherwise, we continue. + if (!TryRelease()) { - GetOwner()->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); + UE_LOGFMT(Toolkit, Display, + "UGrabBehavior::OnActionEnd: TryRelease failed to release with AttachParent {Parent}", + CurrentAttachParent->GetName()); + return; } + OnGrabEndEvent.Broadcast(CurrentAttachParent, MyPhysicsComponent); + + // Release the interation restriction on all component if (bBlockOtherInteractionsWhileGrabbed) { TArray<UInteractableComponent*> Interactables; @@ -91,3 +107,23 @@ void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInpu } } } + +bool UGrabBehavior::TryRelease() +{ + if (!bObjectGrabbed) + { + return false; + } + + if (MyPhysicsComponent) + { + MyPhysicsComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); + MyPhysicsComponent->SetSimulatePhysics(bWasSimulatingPhysics); + } + else + { + GetOwner()->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); + } + bObjectGrabbed = false; + return true; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cd0e3d97f05cd11f45f107103511fa3ec28c48a --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp @@ -0,0 +1,116 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectable.h" + +#include "Interaction/Interactables/IntenSelect/IntenSelectableScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h" +#include "Kismet/KismetSystemLibrary.h" +#include "Misc/MessageDialog.h" +#include "Pawn/IntenSelectComponent.h" + +UIntenSelectable::UIntenSelectable() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> UIntenSelectable::GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, + const float ConeAngle, const float LastValue, + const float DeltaTime) const +{ + checkf(ScoringBehaviour, TEXT("%s"), *GetOwner()->GetName()) return ScoringBehaviour->GetBestPointScorePair( + ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, LastValue, DeltaTime); +} + +void UIntenSelectable::HandleOnSelectStartEvents(const UIntenSelectComponent* IntenSelect, const FHitResult& HitResult) +{ + for (const UHoverBehaviour* b : OnSelectBehaviours) + { + b->OnHoverStartEvent.Broadcast(IntenSelect, HitResult); + } +} + +void UIntenSelectable::HandleOnSelectEndEvents(const UIntenSelectComponent* IntenSelect) +{ + for (const UHoverBehaviour* b : OnSelectBehaviours) + { + b->OnHoverEndEvent.Broadcast(IntenSelect); + } +} + +void UIntenSelectable::HandleOnClickStartEvents(UIntenSelectComponent* IntenSelect) +{ + for (const UActionBehaviour* b : OnClickBehaviours) + { + FInputActionValue v{}; + const UInputAction* a{}; + b->OnActionBeginEvent.Broadcast(IntenSelect, a, v); + } +} + +void UIntenSelectable::HandleOnClickEndEvents(UIntenSelectComponent* IntenSelect, FInputActionValue& InputValue) +{ + for (const UActionBehaviour* b : OnClickBehaviours) + { + const UInputAction* a{}; + b->OnActionEndEvent.Broadcast(IntenSelect, a, InputValue); + } +} + +void UIntenSelectable::InitDefaultBehaviourReferences() +{ + // Scoring + if (UIntenSelectableScoring* AttachedScoring = + Cast<UIntenSelectableScoring>(GetOwner()->GetComponentByClass(UIntenSelectableScoring::StaticClass()))) + { + ScoringBehaviour = AttachedScoring; + } + else + { + ScoringBehaviour = NewObject<UIntenSelectableSinglePointScoring>( + this, UIntenSelectableSinglePointScoring::StaticClass(), "Default Scoring"); + ScoringBehaviour->SetWorldLocation(GetOwner()->GetActorLocation()); + ScoringBehaviour->AttachToComponent(GetOwner()->GetRootComponent(), + FAttachmentTransformRules::SnapToTargetNotIncludingScale); + } + + // Selecting + TInlineComponentArray<UHoverBehaviour*> AttachedSelectionBehaviours; + GetOwner()->GetComponents(AttachedSelectionBehaviours, true); + + this->OnSelectBehaviours = AttachedSelectionBehaviours; + + // Clicking + TInlineComponentArray<UActionBehaviour*> AttachedClickBehaviours; + GetOwner()->GetComponents(AttachedClickBehaviours, true); + + this->OnClickBehaviours = AttachedClickBehaviours; +} + +void UIntenSelectable::ShowErrorAndQuit(const FString& Message) const +{ + UE_LOG(LogTemp, Error, TEXT("%s"), *Message) +#if WITH_EDITOR + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(FString("RUNTIME ERROR"))); +#endif + UKismetSystemLibrary::QuitGame(this, nullptr, EQuitPreference::Quit, false); +} + +void UIntenSelectable::BeginPlay() +{ + Super::BeginPlay(); + + TInlineComponentArray<UIntenSelectable*> AttachedIntenSelectables; + GetOwner()->GetComponents(AttachedIntenSelectables, false); + + if (AttachedIntenSelectables.Num() > 1) + { + if (!ScoringBehaviour) + { + ShowErrorAndQuit( + "Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!"); + } + } + else + { + InitDefaultBehaviourReferences(); + } +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c323f50d1148d8ecb4fc45930a9ca0f00775c69f --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.cpp @@ -0,0 +1,66 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h" + +#include "DrawDebugHelpers.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableCircleScoring::UIntenSelectableCircleScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> +UIntenSelectableCircleScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + const FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = + GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +FVector UIntenSelectableCircleScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const +{ + const FVector CenterWorld = this->GetComponentLocation(); + const FVector CircleNormalWorld = + this->GetComponentTransform().TransformPositionNoScale(FVector::ForwardVector) - CenterWorld; + + float t; + FVector Intersect; + if (!UKismetMathLibrary::LinePlaneIntersection_OriginNormal(Point, Point + Direction * 100000, CenterWorld, + CircleNormalWorld, t, Intersect)) + { + return CenterWorld; + } + + const FVector CenterToPoint = Intersect - CenterWorld; + + FVector Result; + if (OnlyOutline) + { + Result = (CenterToPoint.GetSafeNormal() * Radius) + CenterWorld; + } + else + { + const float DistanceToCenter = CenterToPoint.Size(); + + if (DistanceToCenter >= Radius) + { + Result = (CenterToPoint.GetSafeNormal() * Radius) + CenterWorld; + } + else + { + Result = Intersect; + } + } + + FVector Y = CenterToPoint.GetSafeNormal(); + FVector Z = FVector::CrossProduct(Y, CircleNormalWorld.GetSafeNormal()); + + // Y = FVector(0, 0, 1); + // Z = FVector(1, 0, 0); + DrawDebugCircle(GetWorld(), CenterWorld, Radius, 80, FColor::Green, false, -1, 0, 1, Y, Z, false); + + return Result; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7e8f98116514adc45b63c2b81fa7a66acb95905 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.cpp @@ -0,0 +1,353 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h" + +#include "DrawDebugHelpers.h" +#include "Intersection/IntrRay3AxisAlignedBox3.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableCubeScoring::UIntenSelectableCubeScoring() +{ + PrimaryComponentTick.bCanEverTick = true; + SetRelativeScale3D(FVector::One() * 100); +} + +TPair<FHitResult, float> +UIntenSelectableCubeScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, + LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +FVector UIntenSelectableCubeScoring::GetClosestPointToRectangle(const FVector& StartPoint, const FVector& Direction, + const FVector& Corner00, const FVector& Corner01, + const FVector& Corner10, const FVector& Corner11) const +{ + const float X = FVector::Distance(Corner00, Corner10); + const float Y = FVector::Distance(Corner00, Corner01); + const FVector PlaneNormal = FVector::CrossProduct(Corner10 - Corner00, Corner01 - Corner00).GetSafeNormal(); + + FVector Intersection; + float T; + UKismetMathLibrary::LinePlaneIntersection_OriginNormal(StartPoint, StartPoint + Direction * 10000, Corner00, + PlaneNormal, T, Intersection); + + FVector LocalIntersection = this->GetComponentTransform().InverseTransformPosition(Intersection); + + if (LocalIntersection.Y > X / 2) + { + LocalIntersection.Y = X / 2; + } + else if (LocalIntersection.Y < -X / 2) + { + LocalIntersection.Y = -X / 2; + } + + if (LocalIntersection.Z > Y / 2) + { + LocalIntersection.Z = Y / 2; + } + else if (LocalIntersection.Z < -Y / 2) + { + LocalIntersection.Z = -Y / 2; + } + + /* + if(OnlyOutline) + { + const float DistToBottom = LocalIntersection.Z + (YLength / 2); + const float DistToLeft = LocalIntersection.Y + (XLength / 2); + + if(LocalIntersection.Z < 0) + { + if(LocalIntersection.Y < 0) + { + //Bottom and left + if(DistToLeft < DistToBottom) + { + //snap left + LocalIntersection.Y = -(XLength / 2); + }else + { + //snap bottom + LocalIntersection.Z = -(YLength / 2); + } + }else + { + //bottom and right + if(XLength - DistToLeft < DistToBottom) + { + //snap right + LocalIntersection.Y = XLength / 2; + }else + { + //snap bottom + LocalIntersection.Z = -(YLength / 2); + } + } + }else + { + if(LocalIntersection.Y < 0) + { + //top and left + if(DistToLeft < YLength - DistToBottom) + { + //snap left + LocalIntersection.Y = -(XLength / 2); + }else + { + //snap top + LocalIntersection.Z = (YLength / 2); + } + }else + { + //top and right + if(XLength - DistToLeft < YLength - DistToBottom) + { + //snap right + LocalIntersection.Y = XLength / 2; + }else + { + //snap top + LocalIntersection.Z = (YLength / 2); + } + } + } + } +*/ + + return this->GetComponentTransform().TransformPosition(LocalIntersection); +} + +bool UIntenSelectableCubeScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection) +{ + const FVector Da = ToA - FromA; + const FVector DB = ToB - FromB; + const FVector DC = FromB - FromA; + + const FVector CrossDaDb = FVector::CrossProduct(Da, DB); + const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z; + + const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod); + if (Res >= -0.02f && Res <= 1.02f) + { + OutIntersection = FromA + Da * FVector(Res, Res, Res); + return true; + } + + return false; +} + +FVector UIntenSelectableCubeScoring::GetClosestSelectionPointTo(const FVector& RayOrigin, const FVector& RayDirection) +{ + auto Scale = GetRelativeTransform().GetScale3D(); + const FVector X = this->GetForwardVector() * Scale.X; + const FVector Y = this->GetRightVector() * Scale.Y; + const FVector Z = this->GetUpVector() * Scale.Z; + + TArray<FPlane> CubeSides; + + // bottom + const FVector BottomWorld = this->GetComponentTransform().TransformPositionNoScale(-Z / 2); + CubeSides.Add(FPlane{BottomWorld, -this->GetUpVector()}); + + // top + const FVector TopWorld = this->GetComponentTransform().TransformPositionNoScale(Z / 2); + CubeSides.Add(FPlane{TopWorld, this->GetUpVector()}); + + // left + const FVector LeftWorld = this->GetComponentTransform().TransformPositionNoScale(-Y / 2); + CubeSides.Add(FPlane{LeftWorld, -this->GetRightVector()}); + + // right + const FVector RightWorld = this->GetComponentTransform().TransformPositionNoScale(Y / 2); + CubeSides.Add(FPlane{RightWorld, this->GetRightVector()}); + + // front + const FVector FrontWorld = this->GetComponentTransform().TransformPositionNoScale(-X / 2); + CubeSides.Add(FPlane{FrontWorld, -this->GetForwardVector()}); + + // back + const FVector BackWorld = this->GetComponentTransform().TransformPositionNoScale(X / 2); + CubeSides.Add(FPlane{BackWorld, this->GetForwardVector()}); + + /* + const TRay3<float> Ray{Point, Direction, false}; + const TAxisAlignedBox3<float> Box; + float OutT; + if(TIntrRay3AxisAlignedBox3<float>::FindIntersection(Ray, Box, OutT)) + { + + }*/ + + float MinDistance = TNumericLimits<float>::Max(); + FVector ClosestPoint = GetComponentLocation(); + bool IsSet = false; + for (FPlane Plane : CubeSides) + { + const FVector PlaneToRayOrigin = RayOrigin - Plane.GetOrigin(); + if (FVector::DotProduct(PlaneToRayOrigin.GetSafeNormal(), Plane.GetNormal()) < 0 && BackFaceCulling) + { + if (DrawDebug) + { + DrawDebugSolidPlane(GetWorld(), Plane, GetComponentLocation(), 20, FColor::Red.WithAlpha(9), false, -1, + 0); + } + continue; + } + else + { + if (DrawDebug) + { + DrawDebugSolidPlane(GetWorld(), Plane, GetComponentLocation(), 20, FColor::Green.WithAlpha(9), false, + -1, 0); + } + } + + + FVector CurrentPoint = FMath::RayPlaneIntersection(RayOrigin, RayDirection, Plane); + FVector CurrentPointLocal = GetComponentTransform().InverseTransformPositionNoScale(CurrentPoint); + + Scale = GetRelativeTransform().GetScale3D(); + CurrentPointLocal.X = FMath::Clamp(CurrentPointLocal.X, -Scale.X / 2, Scale.X / 2); + CurrentPointLocal.Y = FMath::Clamp(CurrentPointLocal.Y, -Scale.Y / 2, Scale.Y / 2); + CurrentPointLocal.Z = FMath::Clamp(CurrentPointLocal.Z, -Scale.Z / 2, Scale.Z / 2); + + if (OnlyOutline) + { + const float XSnapDist = (Scale.X / 2) - FMath::Abs(CurrentPointLocal.X); + const float YSnapDist = (Scale.Y / 2) - FMath::Abs(CurrentPointLocal.Y); + const float ZSnapDist = (Scale.Z / 2) - FMath::Abs(CurrentPointLocal.Z); + + bool SnapX = true; + bool SnapY = true; + bool SnapZ = true; + + if (FVector::Parallel(Plane.GetNormal(), GetRightVector())) + { + if (XSnapDist < ZSnapDist) + { + SnapZ = false; + } + else + { + SnapX = false; + } + } + else if (FVector::Parallel(Plane.GetNormal(), GetUpVector())) + { + if (XSnapDist < YSnapDist) + { + SnapY = false; + } + else + { + SnapX = false; + } + } + else if (FVector::Parallel(Plane.GetNormal(), GetForwardVector())) + { + if (YSnapDist < ZSnapDist) + { + SnapZ = false; + } + else + { + SnapY = false; + } + } + + + if (SnapX) + { + if (CurrentPointLocal.X > 0) + { + CurrentPointLocal.X = Scale.X / 2; + } + else + { + CurrentPointLocal.X = -Scale.X / 2; + } + } + if (SnapY) + { + if (CurrentPointLocal.Y > 0) + { + CurrentPointLocal.Y = Scale.Y / 2; + } + else + { + CurrentPointLocal.Y = -Scale.Y / 2; + } + } + if (SnapZ) + { + if (CurrentPointLocal.Z > 0) + { + CurrentPointLocal.Z = Scale.Z / 2; + } + else + { + CurrentPointLocal.Z = -Scale.Z / 2; + } + } + } + + CurrentPoint = GetComponentTransform().TransformPositionNoScale(CurrentPointLocal); + + const float Distance = FMath::PointDistToLine(CurrentPoint, RayDirection, RayOrigin); + + // DrawDebugPoint(GetWorld(), CurrentPoint, 10, FColor::Black.WithAlpha(1), false, -1, 0); + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, -1, FColor::Red, FString::SanitizeFloat(Distance)); + + if (Distance < 0.001) + { + if (MinDistance < 0.001) + { + const float DistToPlayerOld = + IsSet ? FVector::Distance(RayOrigin, ClosestPoint) : TNumericLimits<float>::Max(); + const float DistToPlayerNew = FVector::Distance(RayOrigin, CurrentPoint); + + if (DistToPlayerNew < DistToPlayerOld) + { + MinDistance = Distance; + ClosestPoint = CurrentPoint; + IsSet = true; + } + } + else + { + MinDistance = Distance; + ClosestPoint = CurrentPoint; + IsSet = true; + } + } + else + { + if (Distance < MinDistance) + { + MinDistance = Distance; + ClosestPoint = CurrentPoint; + IsSet = true; + } + } + } + + if (DrawDebug) + DrawDebugBox(GetWorld(), GetComponentLocation(), FVector(Scale.X, Scale.Y, Scale.Z) / 2, + GetComponentRotation().Quaternion(), FColor::Green, false, -1, 0, 2); + return ClosestPoint; +} + +void UIntenSelectableCubeScoring::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4b08696f52712b1ed9dbcc688fda9787c75152c --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.cpp @@ -0,0 +1,110 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h" + +#include "DrawDebugHelpers.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableCylinderScoring::UIntenSelectableCylinderScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> +UIntenSelectableCylinderScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = + GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +bool UIntenSelectableCylinderScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, + const FVector& ToA, const FVector& ToB, + FVector& OutIntersection) +{ + const FVector Da = ToA - FromA; + const FVector DB = ToB - FromB; + const FVector DC = FromB - FromA; + + const FVector CrossDaDb = FVector::CrossProduct(Da, DB); + const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z; + + const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod); + if (Res >= -0.02f && Res <= 1.02f) + { + OutIntersection = FromA + Da * FVector(Res, Res, Res); + return true; + } + + return false; +} + +FVector UIntenSelectableCylinderScoring::GetClosestSelectionPointTo(const FVector& Point, + const FVector& Direction) const +{ + const FVector CylinderStartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]); + const FVector CylinderEndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]); + const FVector CylinderDir = CylinderEndWorld - CylinderStartWorld; + + const FVector CrossProd = UKismetMathLibrary::Cross_VectorVector(CylinderDir, Direction); // v + const FVector LineDifference = CylinderStartWorld - Point; // u + + // Project v onto u => + const FVector Proj = LineDifference.ProjectOnTo(CrossProd); + const float ProjLength = Proj.Size(); + + const FVector OffsetPoint = Point + Proj; + + const FVector FromA = OffsetPoint; + const FVector FromB = CylinderStartWorld; + const FVector ToA = OffsetPoint + Direction * 10000; + const FVector ToB = CylinderEndWorld; + FVector Result; + LineToLineIntersection(FromA, FromB, ToA, ToB, Result); + + const FVector LineDirRes = Result - CylinderStartWorld; + + if (LineDirRes.Size() > CylinderDir.Size()) + { + Result = CylinderEndWorld; + } + + if (!LineDirRes.GetSafeNormal().Equals(CylinderDir.GetSafeNormal())) + { + Result = CylinderStartWorld; + } + + const FVector ToSphere = Result - Point; + const FVector Projection = ToSphere.ProjectOnTo(Direction); + const FVector ProjectionToSphere = ToSphere - Projection; + + if (ProjLength >= Radius) + { + FVector ShiftResult = ProjectionToSphere.GetSafeNormal() * Radius; + ShiftResult -= ShiftResult.ProjectOnTo(CylinderDir); + return Result - ShiftResult; + } + else + { + FVector ShiftResult = ProjectionToSphere.GetSafeNormal() * ProjLength; + ShiftResult -= ShiftResult.ProjectOnTo(CylinderDir); + return Result - ShiftResult; + } +} + +void UIntenSelectableCylinderScoring::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (DrawDebug) + { + const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]); + const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]); + + DrawDebugCylinder(GetWorld(), StartWorld, EndWorld, Radius, 20, FColor::Green, false, 0, 0, 2); + } +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be4cdd9065f3b92f6d640fc78d3c65afa144bcc7 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.cpp @@ -0,0 +1,101 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h" + +#include "DrawDebugHelpers.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableLineScoring::UIntenSelectableLineScoring() +{ + PrimaryComponentTick.bCanEverTick = true; + if (this->LinePoints.Num() == 2) + { + const FVector Average = (this->LinePoints[0] + this->LinePoints[1]) / 2; + + this->SetWorldLocation(this->GetComponentTransform().TransformPositionNoScale(Average)); + this->LinePoints[0] -= Average; + this->LinePoints[1] -= Average; + } +} + +TPair<FHitResult, float> +UIntenSelectableLineScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = + GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +bool UIntenSelectableLineScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection) +{ + const FVector Da = ToA - FromA; + const FVector DB = ToB - FromB; + const FVector DC = FromB - FromA; + + const FVector CrossDaDb = FVector::CrossProduct(Da, DB); + const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z; + + const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod); + if (Res >= -0.02f && Res <= 1.02f) + { + OutIntersection = FromA + Da * FVector(Res, Res, Res); + return true; + } + + return false; +} + +FVector UIntenSelectableLineScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const +{ + const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]); + const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]); + const FVector LineDir = EndWorld - StartWorld; + + + const FVector CrossProd = UKismetMathLibrary::Cross_VectorVector(LineDir, Direction); // v + const FVector LineDifference = StartWorld - Point; // u + + // Project v onto u => + const FVector Proj = LineDifference.ProjectOnTo(CrossProd); + + const FVector OffsetPoint = Point + Proj; + + const FVector FromA = OffsetPoint; + const FVector FromB = StartWorld; + const FVector ToA = OffsetPoint + Direction * 10000; + const FVector ToB = EndWorld; + FVector Result; + LineToLineIntersection(FromA, FromB, ToA, ToB, Result); + + const FVector LineDirRes = Result - StartWorld; + if (LineDirRes.Size() > LineDir.Size()) + { + Result = EndWorld; + } + + if (!LineDirRes.GetSafeNormal().Equals(LineDir.GetSafeNormal())) + { + Result = StartWorld; + } + + return Result; +} + +void UIntenSelectableLineScoring::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (DrawDebug) + { + const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]); + const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]); + DrawDebugLine(GetWorld(), StartWorld, EndWorld, FColor::Green, false, -1, 0, 2); + } +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03b04e32b549450947e0d663c4a5757e1ced9b76 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.cpp @@ -0,0 +1,52 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h" + +#include "Kismet/KismetMathLibrary.h" +#include "Net/Core/PushModel/PushModel.h" + +// Sets default values for this component's properties +UIntenSelectableMultiPointScoring::UIntenSelectableMultiPointScoring() +{ + PrimaryComponentTick.bCanEverTick = true; + PointsToSelect = TArray<FVector>{FVector::UpVector * 100, FVector::DownVector * 100, FVector::RightVector * 100, + FVector::LeftVector * 100}; +} + +TPair<FHitResult, float> +UIntenSelectableMultiPointScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, + LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +void UIntenSelectableMultiPointScoring::UpdatePoints() {} + +FVector UIntenSelectableMultiPointScoring::GetClosestSelectionPointTo(const FVector& Point, + const FVector& Direction) const +{ + if (PointsToSelect.Num() == 0) + { + return this->GetComponentLocation(); + } + + FVector ClosestPoint = this->GetComponentTransform().TransformPositionNoScale(PointsToSelect[0]); + float MinDistance = UKismetMathLibrary::GetPointDistanceToLine(ClosestPoint, Point, Direction); + + for (const FVector P : PointsToSelect) + { + const FVector PointToCheck = this->GetComponentTransform().TransformPositionNoScale(P); + const float Dist = UKismetMathLibrary::GetPointDistanceToLine(PointToCheck, Point, Direction); + if (Dist < MinDistance) + { + MinDistance = Dist; + ClosestPoint = PointToCheck; + } + } + return ClosestPoint; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62737f8d1b07af27317ade5a57fd58a25eb0d92b --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.cpp @@ -0,0 +1,177 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h" + +#include "DrawDebugHelpers.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableRectangleScoring::UIntenSelectableRectangleScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> +UIntenSelectableRectangleScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, + LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +bool UIntenSelectableRectangleScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, + const FVector& ToA, const FVector& ToB, + FVector& OutIntersection) +{ + const FVector Da = ToA - FromA; + const FVector DB = ToB - FromB; + const FVector DC = FromB - FromA; + + const FVector CrossDaDb = FVector::CrossProduct(Da, DB); + const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z; + + const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod); + if (Res >= -0.02f && Res <= 1.02f) + { + OutIntersection = FromA + Da * FVector(Res, Res, Res); + return true; + } + + return false; +} + +FVector UIntenSelectableRectangleScoring::GetClosestSelectionPointTo(const FVector& Point, + const FVector& Direction) const +{ + const FVector X = this->GetRightVector() * XLength; + const FVector Y = this->GetUpVector() * YLength; + + const FVector CornerWorld00 = + this->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2); + const FVector CornerWorld10 = CornerWorld00 + X; + const FVector CornerWorld01 = CornerWorld00 + Y; + const FVector CornerWorld11 = CornerWorld00 + X + Y; + + const FVector PlaneNormal = + FVector::CrossProduct(CornerWorld10 - CornerWorld00, CornerWorld01 - CornerWorld00).GetSafeNormal(); + + FVector Intersection; + float T; + UKismetMathLibrary::LinePlaneIntersection_OriginNormal(Point, Point + Direction * 10000, CornerWorld00, PlaneNormal, + T, Intersection); + + FVector LocalIntersection = this->GetComponentTransform().InverseTransformPosition(Intersection); + + if (LocalIntersection.Y > XLength / 2) + { + LocalIntersection.Y = XLength / 2; + } + else if (LocalIntersection.Y < -XLength / 2) + { + LocalIntersection.Y = -XLength / 2; + } + + if (LocalIntersection.Z > YLength / 2) + { + LocalIntersection.Z = YLength / 2; + } + else if (LocalIntersection.Z < -YLength / 2) + { + LocalIntersection.Z = -YLength / 2; + } + + if (OnlyOutline) + { + const float DistToBottom = LocalIntersection.Z + (YLength / 2); + const float DistToLeft = LocalIntersection.Y + (XLength / 2); + + if (LocalIntersection.Z < 0) + { + if (LocalIntersection.Y < 0) + { + // Bottom and left + if (DistToLeft < DistToBottom) + { + // snap left + LocalIntersection.Y = -(XLength / 2); + } + else + { + // snap bottom + LocalIntersection.Z = -(YLength / 2); + } + } + else + { + // bottom and right + if (XLength - DistToLeft < DistToBottom) + { + // snap right + LocalIntersection.Y = XLength / 2; + } + else + { + // snap bottom + LocalIntersection.Z = -(YLength / 2); + } + } + } + else + { + if (LocalIntersection.Y < 0) + { + // top and left + if (DistToLeft < YLength - DistToBottom) + { + // snap left + LocalIntersection.Y = -(XLength / 2); + } + else + { + // snap top + LocalIntersection.Z = (YLength / 2); + } + } + else + { + // top and right + if (XLength - DistToLeft < YLength - DistToBottom) + { + // snap right + LocalIntersection.Y = XLength / 2; + } + else + { + // snap top + LocalIntersection.Z = (YLength / 2); + } + } + } + } + + return this->GetComponentTransform().TransformPosition(LocalIntersection); +} + +void UIntenSelectableRectangleScoring::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (DrawDebug) + { + const FVector X = this->GetRightVector() * XLength; + const FVector Y = this->GetUpVector() * YLength; + + const FVector CornerWorld00 = + this->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2); + const FVector CornerWorld10 = CornerWorld00 + X; + const FVector CornerWorld01 = CornerWorld00 + Y; + const FVector CornerWorld11 = CornerWorld00 + X + Y; + + DrawDebugLine(GetWorld(), CornerWorld00, CornerWorld01, FColor::Green, false, -1, 0, 2); + DrawDebugLine(GetWorld(), CornerWorld00, CornerWorld10, FColor::Green, false, -1, 0, 2); + DrawDebugLine(GetWorld(), CornerWorld01, CornerWorld11, FColor::Green, false, -1, 0, 2); + DrawDebugLine(GetWorld(), CornerWorld10, CornerWorld11, FColor::Green, false, -1, 0, 2); + } +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82455f7885caea8606e98deb229f0aa51a73cf14 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableScoring.cpp @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactables/IntenSelect/IntenSelectableScoring.h" + +float UIntenSelectableScoring::GetScore(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const FVector& TestPoint, const float LastValue, const float DeltaTime) +{ + const FVector ShiftedConeOrigin = ConeOrigin - (ConeForwardDirection * ConeBackwardShiftDistance); + + const float D_Perspective = FMath::PointDistToLine(TestPoint, ConeForwardDirection, ShiftedConeOrigin); + const float D_Projection = (TestPoint - ShiftedConeOrigin).ProjectOnTo(ConeForwardDirection).Size(); + + const float Angle = FMath::RadiansToDegrees( + FMath::Atan(D_Perspective / (FMath::Pow(D_Projection / 100, CompensationConstant) * 100))); + float S_Contrib = 1 - (Angle / ConeAngle); + if (S_Contrib < 0) + S_Contrib = 0; + + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, GetOwner()->GetName() + " - Contrib: " + + // FString::FromInt(S_Contrib)); + + if (LastValue != 0) + { + constexpr float Interpolate = 0.5; + if (S_Contrib > LastValue) + { + CurrentScore = LastValue + + (((LastValue * Interpolate) + (S_Contrib * (1 - Interpolate))) - LastValue) * DeltaTime * Snappiness; + } + else + { + CurrentScore = LastValue + + (((LastValue * Interpolate) + (S_Contrib * (1 - Interpolate))) - LastValue) * DeltaTime * Stickiness; + } + } + else + { + CurrentScore = S_Contrib * Snappiness * DeltaTime; + } + return CurrentScore; +} + +// Sets default values for this component's properties +UIntenSelectableScoring::UIntenSelectableScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> UIntenSelectableScoring::GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, + const float ConeAngle, const float LastValue, + const float DeltaTime) +{ + return {}; +} + +void UIntenSelectableScoring::BeginPlay() { Super::BeginPlay(); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e42770a89577caa97c2208b2a6905db8ca6bcbba --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.cpp @@ -0,0 +1,16 @@ +#include "Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h" + +UIntenSelectableSinglePointScoring::UIntenSelectableSinglePointScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> UIntenSelectableSinglePointScoring::GetBestPointScorePair( + const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, + const float ConeAngle, const float LastValue, const float DeltaTime) +{ + const FVector Point = this->GetComponentLocation(); + float Score = + GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +void UIntenSelectableSinglePointScoring::BeginPlay() { Super::BeginPlay(); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36ddcbb571c7fe464ed38d9ff6c1cb5b60d40d04 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.cpp @@ -0,0 +1,82 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h" + +#include "DrawDebugHelpers.h" +#include "Algo/IndexOf.h" +#include "Kismet/GameplayStatics.h" +#include "Kismet/KismetMathLibrary.h" + +// Sets default values for this component's properties +UIntenSelectableSphereScoring::UIntenSelectableSphereScoring() { PrimaryComponentTick.bCanEverTick = true; } + +TPair<FHitResult, float> +UIntenSelectableSphereScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) +{ + FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection); + float Score = + GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime); + FHitResult Result = FHitResult{GetOwner(), nullptr, Point, FVector::ForwardVector}; + return TPair<FHitResult, float>{Result, Score}; +} + +FVector UIntenSelectableSphereScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const +{ + const FVector CenterWorld = this->GetComponentLocation(); + + const FVector ToSphere = CenterWorld - Point; + + const FVector Projection = ToSphere.ProjectOnTo(Direction); + const FVector ProjectionToSphere = ToSphere - Projection; + + FVector Result = CenterWorld - ProjectionToSphere.GetSafeNormal() * Radius; + + if (!OnlyOutline) + { + const float t = FVector::DotProduct(ToSphere, Direction.GetSafeNormal()); + const FVector TPoint = Point + Direction.GetSafeNormal() * t; + const float Y = (CenterWorld - TPoint).Size(); + + if (Y <= Radius) + { + const float X = +FMath::Sqrt((Radius * Radius) - (Y * Y)); + + const FVector Result1 = Point + Direction.GetSafeNormal() * (t - X); + const FVector Result2 = Point + Direction.GetSafeNormal() * (t + X); + + if (FVector::Distance(Point, Result1) < FVector::Distance(Point, Result2)) + { + Result = Result1; + } + else + { + Result = Result2; + } + } + + /* + TArray<FHitResult> Out; + const float Dist = FVector::Distance(Point, GetComponentLocation()); + if(GetWorld()->LineTraceMultiByChannel(Out, Point, Point + (Direction.GetSafeNormal() * Dist), + ECollisionChannel::ECC_Visibility)) + { + for(auto Hit : Out) + { + if(Hit.GetActor() == GetOwner()) + { + Result = Hit.ImpactPoint; + break; + } + } + }*/ + } + + if (DrawDebug) + { + DrawDebugSphere(GetWorld(), CenterWorld, Radius, 20, FColor::Green, false, -1, 0, 1); + } + + return Result; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8cf9ce35e45d0bc107cd73da08333ef5ba5b2d9 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp @@ -0,0 +1,185 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactors/DirectInteractionComponent.h" + +#include "EnhancedInputComponent.h" +#include "Interaction/Interactables/InteractableComponent.h" +#include "Interaction/Interactables/InteractionBitSet.h" + +#include "Kismet/GameplayStatics.h" +#include "Logging/StructuredLog.h" +#include "Utility/RWTHVRUtilities.h" + +// Sets default values for this component's properties +UDirectInteractionComponent::UDirectInteractionComponent() +{ + // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these + // features off to improve performance if you don't need them. + PrimaryComponentTick.bCanEverTick = true; + // ... +} + +void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + TArray<UInteractableComponent*> CurrentInteractableCompsInRange; + + TArray<FHitResult> OutHits; + const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); + + auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; + + UKismetSystemLibrary::SphereTraceMulti(GetWorld(), GetAttachParent()->GetComponentLocation(), + GetAttachParent()->GetComponentLocation(), InteractionSphereRadius, + TraceType, true, ActorsToIgnore, DebugTrace, OutHits, true, FColor::Green); + + for (FHitResult Hit : OutHits) + { + AActor* HitActor = Hit.GetActor(); + if (HitActor) + { + UInteractableComponent* InteractableComp = SearchForInteractable(HitActor); + if (InteractableComp && InteractableComp->HasInteractionTypeFlag(EInteractorType::Direct) && + InteractableComp->IsInteractable) + { + InteractableComp->HitResult = Hit; + CurrentInteractableCompsInRange.AddUnique(InteractableComp); + } + } + } + + CurrentInteractableComponentsInRange = CurrentInteractableCompsInRange; + + // Call hover start events on all components that were not in range before + for (UInteractableComponent* CurrentInteractableComp : CurrentInteractableCompsInRange) + { + if (!PreviousInteractableComponentsInRange.Contains(CurrentInteractableComp)) + { + PreviousInteractableComponentsInRange.AddUnique(CurrentInteractableComp); + CurrentInteractableComp->HandleOnHoverStartEvents(this, EInteractorType::Direct); + } + } + + TArray<UInteractableComponent*> ComponentsToRemove; + + // Call hover end events on all components that were previously in range, but not anymore + for (UInteractableComponent* PrevInteractableComp : PreviousInteractableComponentsInRange) + { + if (!CurrentInteractableCompsInRange.Contains(PrevInteractableComp)) + { + ComponentsToRemove.AddUnique(PrevInteractableComp); + PrevInteractableComp->HandleOnHoverEndEvents(this, EInteractorType::Direct); + } + } + + for (UInteractableComponent* CompToRemove : ComponentsToRemove) + { + PreviousInteractableComponentsInRange.Remove(CompToRemove); + } +} + +void UDirectInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) +{ + IInputExtensionInterface::SetupPlayerInput(PlayerInputComponent); + + const APawn* Pawn = Cast<APawn>(GetOwner()); + if (!Pawn) + return; + + // Probably not the best place to add this. + ActorsToIgnore.AddUnique(GetOwner()); + + UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(Pawn->InputComponent); + if (EI == nullptr) + return; + + EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, + &UDirectInteractionComponent::OnBeginInteraction); + EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, + &UDirectInteractionComponent::OnEndInteraction); +} + +void UDirectInteractionComponent::OnBeginInteraction(const FInputActionValue& Value) +{ + const FVector InteractionLocation = GetAttachParent()->GetComponentLocation(); + + if (CurrentInteractableComponentsInRange.IsEmpty()) + return; + + if (bOnlyInteractWithClosestActor) + { + auto MinElement = *Algo::MinElementBy( + CurrentInteractableComponentsInRange, + [&](auto Element) + { return FVector(Element->GetOwner()->GetActorLocation() - InteractionLocation).Size(); }); + MinElement->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + CurrentlyInteractedComponents = {MinElement}; + } + else + { + CurrentlyInteractedComponents.Reserve(CurrentlyInteractedComponents.Num() + + CurrentInteractableComponentsInRange.Num()); + for (UInteractableComponent* InteractableComp : CurrentInteractableComponentsInRange) + { + InteractableComp->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + CurrentlyInteractedComponents.Add(InteractableComp); + } + } +} + +void UDirectInteractionComponent::OnEndInteraction(const FInputActionValue& Value) +{ + for (auto& Component : CurrentlyInteractedComponents) + { + if (Component.IsValid()) + { + Component->HandleOnActionEndEvents(this, InteractionInputAction, Value, EInteractorType::Direct); + } + } +} + +UInteractableComponent* UDirectInteractionComponent::SearchForInteractable(AActor* HitActor) +{ + UInteractableComponent* InteractableComponent = nullptr; + if (!HitActor) + { + UE_LOGFMT(Toolkit, Warning, + "UDirectInteractionComponent::SearchForInteractable: HitActor was nullptr, returning nullptr"); + return nullptr; + } + + if (HitActor->IsChildActor()) + { + // search for UInteractable upwards from hit geometry and return first one found + InteractableComponent = HitActor->FindComponentByClass<UInteractableComponent>(); + // if InteractableComponen is not valid search at parent + if (!InteractableComponent) + { + HitActor = HitActor->GetParentActor(); + if (HitActor) + { + bSearchAtParent = true; + return SearchForInteractable(HitActor); + } + } + } + else if (!HitActor->IsChildActor()) + { + InteractableComponent = HitActor->FindComponentByClass<UInteractableComponent>(); + } + + if (InteractableComponent) + { + // in the case, were we had to iterate up the hierarchy, check if we are allowed + // to interact with the parent via child geometry + if (bSearchAtParent && !InteractableComponent->bAllowInteractionFromChildGeometry) + { + InteractableComponent = nullptr; + } + } + bSearchAtParent = false; + return InteractableComponent; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp deleted file mode 100644 index fcc3abae942e3baa4d1fd01f453dabb6cf9d3b81..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactors/GrabComponent.h" - -#include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" -#include "Interaction/Interactables/InteractableComponent.h" -#include "Interaction/Interactables/InteractionBitSet.h" - -#include "Kismet/GameplayStatics.h" - -// Sets default values for this component's properties -UGrabComponent::UGrabComponent() -{ - // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these - // features off to improve performance if you don't need them. - PrimaryComponentTick.bCanEverTick = true; - - // ... -} - -void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) -{ - Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - - - TArray<UInteractableComponent*> CurrentGrabCompsInRange; - - TArray<AActor*> ActorsToIgnore; - TArray<FHitResult> OutHits; - const ETraceTypeQuery TraceType = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_PhysicsBody); - - auto DebugTrace = bShowDebugTrace ? EDrawDebugTrace::ForOneFrame : EDrawDebugTrace::None; - - UKismetSystemLibrary::SphereTraceMulti(GetWorld(), GetAttachParent()->GetComponentLocation(), - GetAttachParent()->GetComponentLocation(), GrabSphereRadius, TraceType, true, - ActorsToIgnore, DebugTrace, OutHits, true, FColor::Green); - - for (FHitResult Hit : OutHits) - { - AActor* HitActor = Hit.GetActor(); - if (HitActor) - { - UInteractableComponent* Grabbable = HitActor->FindComponentByClass<UInteractableComponent>(); - if (Grabbable && Grabbable->HasInteractionTypeFlag(EInteractorType::Grab) && Grabbable->IsInteractable) - { - Grabbable->HitResult = Hit; - CurrentGrabCompsInRange.Add(Grabbable); - } - } - } - - CurrentGrabbableInRange = CurrentGrabCompsInRange; - - // Call hover start events on all components that were not in range before - for (UInteractableComponent* CurrentGrabbale : CurrentGrabCompsInRange) - { - if (!PreviousGrabbablesInRange.Contains(CurrentGrabbale)) - { - PreviousGrabbablesInRange.Add(CurrentGrabbale); - CurrentGrabbale->HandleOnHoverStartEvents(this, EInteractorType::Grab); - } - } - - TArray<UInteractableComponent*> ComponentsToRemove; - - // Call hover end events on all components that were previously in range, but not anymore - for (UInteractableComponent* PrevGrabbale : PreviousGrabbablesInRange) - { - if (!CurrentGrabCompsInRange.Contains(PrevGrabbale)) - { - ComponentsToRemove.Add(PrevGrabbale); - PrevGrabbale->HandleOnHoverEndEvents(this, EInteractorType::Grab); - } - } - - for (UInteractableComponent* CompToRemove : ComponentsToRemove) - { - PreviousGrabbablesInRange.Remove(CompToRemove); - } -} - -void UGrabComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) -{ - IInputExtensionInterface::SetupPlayerInput(PlayerInputComponent); - - const APawn* Pawn = Cast<APawn>(GetOwner()); - if (!Pawn) - return; - - auto* InputSubsystem = GetEnhancedInputLocalPlayerSubsystem(Pawn); - if (!InputSubsystem) - return; - - // add Input Mapping context - InputSubsystem->AddMappingContext(IMCGrab, 0); - - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(Pawn->InputComponent); - if (EI == nullptr) - return; - - EI->BindAction(GrabInputAction, ETriggerEvent::Started, this, &UGrabComponent::OnBeginGrab); - EI->BindAction(GrabInputAction, ETriggerEvent::Completed, this, &UGrabComponent::OnEndGrab); -} - -void UGrabComponent::OnBeginGrab(const FInputActionValue& Value) -{ - for (UInteractableComponent* Grabbale : CurrentGrabbableInRange) - { - Grabbale->HandleOnActionStartEvents(this, GrabInputAction, Value, EInteractorType::Grab); - } -} - -void UGrabComponent::OnEndGrab(const FInputActionValue& Value) -{ - for (UInteractableComponent* Grabbale : CurrentGrabbableInRange) - { - Grabbale->HandleOnActionEndEvents(this, GrabInputAction, Value, EInteractorType::Grab); - } -} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp index bcbea769743979f8ca91339e038fe2ee0d3d99fd..3a87de65d2cb52a5bce0dd0aa71af9dd3b2f69bb 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp @@ -4,8 +4,7 @@ #include "Interaction/Interactors/RWTHVRWidgetInteractionComponent.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" -#include "Interaction/Interactors/GrabComponent.h" +#include "Interaction/Interactors/DirectInteractionComponent.h" #include "Logging/StructuredLog.h" #include "Misc/Optional.h" #include "Utility/RWTHVRUtilities.h" @@ -35,39 +34,32 @@ void URWTHVRWidgetInteractionComponent::SetupPlayerInput(UInputComponent* Player if (!Pawn) { UE_LOGFMT(Toolkit, Warning, - "URWTHVRWidgetInteractionComponent::SetupPlayerInput requires a Pawn as Owner, which is not the case. Not setting up any input actions.") - ; + "URWTHVRWidgetInteractionComponent::SetupPlayerInput requires a Pawn as Owner, which is not the " + "case. Not setting up any input actions."); return; } - // We can be owned by a pawn, but not be the locally controlled pawn in a MP setting. In that case, just return and - // don't set up any inputs. - auto* InputSubsystem = GetEnhancedInputLocalPlayerSubsystem(Pawn); - if (!InputSubsystem) - return; - // Because we cannot use the regular debug ray (only works in editor), we set up our own (mesh) ray. SetupInteractionRay(); - // add Input Mapping context - InputSubsystem->AddMappingContext(IMCWidgetInteraction, 0); - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(Pawn->InputComponent); if (!EI) { UE_LOGFMT(Toolkit, Warning, - "URWTHVRWidgetInteractionComponent::SetupPlayerInput: Cannot cast Pawn's InputComponent to UEnhancedInputComponent! Not binding any actions!") - ; + "URWTHVRWidgetInteractionComponent::SetupPlayerInput: Cannot cast Pawn's InputComponent to " + "UEnhancedInputComponent! Not binding any actions!"); return; } - EI->BindAction(WidgetClickInputAction, ETriggerEvent::Started, this, &URWTHVRWidgetInteractionComponent::OnBeginClick); - EI->BindAction(WidgetClickInputAction, ETriggerEvent::Completed, this, &URWTHVRWidgetInteractionComponent::OnEndClick); + EI->BindAction(WidgetClickInputAction, ETriggerEvent::Started, this, + &URWTHVRWidgetInteractionComponent::OnBeginClick); + EI->BindAction(WidgetClickInputAction, ETriggerEvent::Completed, this, + &URWTHVRWidgetInteractionComponent::OnEndClick); } // Called every frame void URWTHVRWidgetInteractionComponent::TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) + FActorComponentTickFunction* ThisTickFunction) { // We should only tick on the local owner (the controlling client). Not on the server, not on any other pawn. // In theory, this should never happen as we only activate the component for the local player anyway. @@ -103,7 +95,7 @@ void URWTHVRWidgetInteractionComponent::SetInteractionRayVisibility(EInteraction InteractionRay->SetVisibility(NewVisibility == Visible); else UE_LOGFMT(Toolkit, Error, - "URWTHVRWidgetInteractionComponent::SetInteractionRayVisibility: InteractionRay not set yet!"); + "URWTHVRWidgetInteractionComponent::SetInteractionRayVisibility: InteractionRay not set yet!"); } // Forward the click to the WidgetInteraction @@ -173,7 +165,7 @@ void URWTHVRWidgetInteractionComponent::SetupInteractionRay() // turns off collisions as the InteractionRay is only meant to visualize the ray InteractionRay->SetCollisionProfileName(TEXT("NoCollision")); - //the ray model has a length of 100cm (and is a bit too big in Y/Z dir) + // the ray model has a length of 100cm (and is a bit too big in Y/Z dir) InteractionRay->SetRelativeScale3D(FVector(InteractionDistance / 100.0f, 0.5f, 0.5f)); SetInteractionRayVisibility(InteractionRayVisibility); diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp similarity index 59% rename from Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp rename to Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp index dc88e0375bf44a01c62aa2c91de71e9f18643bca..94afba4b4426fe1b861d787826f0e1cc11d6583b 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp @@ -1,15 +1,14 @@ // Fill out your copyright notice in the Description page of Project Settings. -#include "Interaction/Interactors/RaycastSelectionComponent.h" +#include "Interaction/Interactors/RaycastInteractionComponent.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" #include "Interaction/Interactables/InteractableComponent.h" #include "Kismet/KismetSystemLibrary.h" // Sets default values for this component's properties -URaycastSelectionComponent::URaycastSelectionComponent() +URaycastInteractionComponent::URaycastInteractionComponent() { // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these // features off to improve performance if you don't need them. @@ -19,12 +18,12 @@ URaycastSelectionComponent::URaycastSelectionComponent() } // Called every frame -void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) +void URaycastInteractionComponent::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - UInteractableComponent* CurrentSelectable = nullptr; + UInteractableComponent* NewInteractableComponent = nullptr; TArray<AActor*> ActorsToIgnore; @@ -41,15 +40,15 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT AActor* HitActor = Hit.GetActor(); if (HitActor) { - UInteractableComponent* Selectable = HitActor->FindComponentByClass<UInteractableComponent>(); - if (Selectable && Selectable->IsInteractable) + UInteractableComponent* InteractableComponent = HitActor->FindComponentByClass<UInteractableComponent>(); + if (InteractableComponent && InteractableComponent->IsInteractable) { - CurrentSelectable = Selectable; - Selectable->HitResult = Hit; + NewInteractableComponent = InteractableComponent; + InteractableComponent->HitResult = Hit; } } - CurrentInteractable = CurrentSelectable; + CurrentInteractable = NewInteractableComponent; if (CurrentInteractable != PreviousInteractable) { @@ -62,19 +61,19 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT PreviousInteractable = CurrentInteractable; } -void URaycastSelectionComponent::OnBeginSelect(const FInputActionValue& Value) +void URaycastInteractionComponent::OnBeginInteraction(const FInputActionValue& Value) { if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - CurrentInteractable->HandleOnActionStartEvents(this, RayCastSelectInputAction, Value, EInteractorType::Raycast); + CurrentInteractable->HandleOnActionStartEvents(this, InteractionInputAction, Value, EInteractorType::Raycast); } -void URaycastSelectionComponent::OnEndSelect(const FInputActionValue& Value) +void URaycastInteractionComponent::OnEndInteraction(const FInputActionValue& Value) { if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) - CurrentInteractable->HandleOnActionEndEvents(this, RayCastSelectInputAction, Value, EInteractorType::Raycast); + CurrentInteractable->HandleOnActionEndEvents(this, InteractionInputAction, Value, EInteractorType::Raycast); } -void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) +void URaycastInteractionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) { IInputExtensionInterface::SetupPlayerInput(PlayerInputComponent); @@ -82,17 +81,12 @@ void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputCo if (!Pawn) return; - auto* InputSubsystem = GetEnhancedInputLocalPlayerSubsystem(Pawn); - if (!InputSubsystem) - return; - - // add Input Mapping context - InputSubsystem->AddMappingContext(IMCRaycastSelection, 0); - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(Pawn->InputComponent); if (!EI) return; - EI->BindAction(RayCastSelectInputAction, ETriggerEvent::Started, this, &URaycastSelectionComponent::OnBeginSelect); - EI->BindAction(RayCastSelectInputAction, ETriggerEvent::Completed, this, &URaycastSelectionComponent::OnEndSelect); + EI->BindAction(InteractionInputAction, ETriggerEvent::Started, this, + &URaycastInteractionComponent::OnBeginInteraction); + EI->BindAction(InteractionInputAction, ETriggerEvent::Completed, this, + &URaycastInteractionComponent::OnEndInteraction); } diff --git a/Source/RWTHVRToolkit/Private/Pawn/InputExtensionInterface.cpp b/Source/RWTHVRToolkit/Private/Pawn/InputExtensionInterface.cpp index ddee08706d0f68ad5a5ce1bd4c632642b3bc971f..03ea498fea124f6fe19b947e3cc370dd10295394 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/InputExtensionInterface.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/InputExtensionInterface.cpp @@ -2,12 +2,3 @@ #include "Pawn/InputExtensionInterface.h" - -UEnhancedInputLocalPlayerSubsystem* -IInputExtensionInterface::GetEnhancedInputLocalPlayerSubsystem(const APawn* Pawn) const -{ - const APlayerController* PlayerController = Pawn ? Cast<APlayerController>(Pawn->GetController()) : nullptr; - const ULocalPlayer* LP = PlayerController ? PlayerController->GetLocalPlayer() : nullptr; - - return LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); -} diff --git a/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..644f30c91b22cad8ec4536347912b8791f0d4da8 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp @@ -0,0 +1,792 @@ +#include "Pawn/IntenSelectComponent.h" +#include "EnhancedInputComponent.h" +#include "EnhancedInputSubsystems.h" +#include "Components/WidgetComponent.h" +#include "Haptics/HapticFeedbackEffect_Curve.h" +#include "Kismet/GameplayStatics.h" +#include "Materials/MaterialParameterCollection.h" +#include "Materials/MaterialParameterCollectionInstance.h" +#include "Misc/MessageDialog.h" +#include "Templates/Tuple.h" + + +// INITIALIZATION + +// Sets default values for this component's properties +UIntenSelectComponent::UIntenSelectComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) +{ + PrimaryComponentTick.bCanEverTick = true; + bShowDebug = false; // otherwise the WidgetInteractionComponent debug vis is shown + InteractionSource = EWidgetInteractionSource::Custom; // can also be kept at default (World), this way, however, we + // efficiently reuse the line traces + + ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultConeMesh( + TEXT("StaticMesh'/RWTHVRToolkit/IntenSelect/DebugConeMesh.DebugConeMesh'")); + this->DebugConeMesh = DefaultConeMesh.Object; + + ConstructorHelpers::FObjectFinder<UMaterialInterface> DefaultConeMeshMaterial( + TEXT("Material'/RWTHVRToolkit/IntenSelect/DebugConeMaterial.DebugConeMaterial'")); + this->DebugConeMaterial = DefaultConeMeshMaterial.Object; + + ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultSplineMesh( + TEXT("StaticMesh'/RWTHVRToolkit/IntenSelect/sectionedCubeMesh.sectionedCubeMesh'")); + this->SplineMesh = DefaultSplineMesh.Object; + + ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultForwardRayMesh( + TEXT("StaticMesh'/RWTHVRToolkit/IntenSelect/RayMesh.RayMesh'")); + this->ForwardRayMesh = DefaultForwardRayMesh.Object; + + ConstructorHelpers::FObjectFinder<UMaterialInterface> DefaultSplineMaterial( + TEXT("Material'/RWTHVRToolkit/IntenSelect/SelectionSplineMaterial.SelectionSplineMaterial'")); + this->SplineMaterial = DefaultSplineMaterial.Object; + + ConstructorHelpers::FObjectFinder<UMaterialInterface> DefaultForwardRayMaterial( + TEXT("Material'/RWTHVRToolkit/IntenSelect/ForwadRayMaterial.ForwadRayMaterial'")); + this->ForwardRayMaterial = DefaultForwardRayMaterial.Object; + + ConstructorHelpers::FObjectFinder<UHapticFeedbackEffect_Curve> DefaultSelectionFeedbackHaptic( + TEXT("HapticFeedbackEffect_Curve'/RWTHVRToolkit/IntenSelect/OnSelectHapticFeedback.OnSelectHapticFeedback'")); + this->SelectionFeedbackHaptic = DefaultSelectionFeedbackHaptic.Object; + + ConstructorHelpers::FObjectFinder<USoundBase> DefaultOnSelectSound( + TEXT("SoundWave'/RWTHVRToolkit/IntenSelect/OnSelectSound.OnSelectSound'")); + this->OnSelectSound = DefaultOnSelectSound.Object; + + ConstructorHelpers::FObjectFinder<UMaterialParameterCollection> DefaultMaterialParamCollection( + TEXT("MaterialParameterCollection'/RWTHVRToolkit/IntenSelect/ForwardRayParams.ForwardRayParams'")); + this->MaterialParamCollection = DefaultMaterialParamCollection.Object; + + ConstructorHelpers::FObjectFinder<UCurveFloat> DefaultForwardRayTransparencyCurve( + TEXT("CurveFloat'/RWTHVRToolkit/IntenSelect/ForwardRayTransparencyCurve.ForwardRayTransparencyCurve'")); + this->ForwardRayTransparencyCurve = DefaultForwardRayTransparencyCurve.Object; + + ConstructorHelpers::FObjectFinder<UInputAction> InputActionClick( + TEXT("/Script/EnhancedInput.InputAction'/RWTHVRToolkit/IntenSelect/IntenSelectClick.IntenSelectClick'")); + this->InputClick = InputActionClick.Object; +} + +// Called when the game starts +void UIntenSelectComponent::BeginPlay() +{ + Super::BeginPlay(); + + this->InitSplineComponent(); + this->InitSplineMeshComponent(); + this->InitForwardRayMeshComponent(); + this->InitDebugConeMeshComponent(); + this->InitInputBindings(); + this->InitMaterialParamCollection(); + + this->SphereCastRadius = CalculateSphereCastRadius(); + this->InteractionDistance = this->MaxSelectionDistance; + + this->SetActive(SetActiveOnStart, false); +} + +void UIntenSelectComponent::InitInputBindings() +{ + const APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0); + + UEnhancedInputLocalPlayerSubsystem* Subsystem = + ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()); + + UInputComponent* PlayerInputComponent = PC->InputComponent; + UEnhancedInputComponent* PEI = Cast<UEnhancedInputComponent>(PlayerInputComponent); + + if (!PEI) + { + const FString Message = "Could not get PlayerInputComponent for IntenSelect Input Assignment!"; + +#if WITH_EDITOR + const FText Title = FText::FromString(FString("ERROR")); + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message), Title); +#endif + + UE_LOG(LogTemp, Error, TEXT("%s"), *Message) + UKismetSystemLibrary::QuitGame(this, nullptr, EQuitPreference::Quit, false); + return; + } + + // Bind the actions + PEI->BindAction(InputClick, ETriggerEvent::Started, this, &UIntenSelectComponent::OnFireDown); + PEI->BindAction(InputClick, ETriggerEvent::Completed, this, &UIntenSelectComponent::OnFireUp); +} + +void UIntenSelectComponent::InitSplineComponent() +{ + SplineComponent = NewObject<USplineComponent>(this, TEXT("SplineComponent")); + + if (SplineComponent) + { + SplineComponent->SetupAttachment(this); + SplineComponent->SetMobility(EComponentMobility::Movable); + SplineComponent->RegisterComponent(); + SplineComponent->CreationMethod = EComponentCreationMethod::Instance; + } + else + { + const FString Message = "Error while spawning SplineComponent!"; +#if WITH_EDITOR + const FText Title = FText::FromString(FString("ERROR")); + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message), Title); +#endif + + UE_LOG(LogTemp, Error, TEXT("%s"), *Message) + } +} + +void UIntenSelectComponent::InitSplineMeshComponent() +{ + SplineMeshComponent = + NewObject<USplineMeshComponent>(this, USplineMeshComponent::StaticClass(), TEXT("SplineMeshComponent")); + if (SplineMeshComponent) + { + SplineMeshComponent->SetupAttachment(this); + SplineMeshComponent->SetMobility(EComponentMobility::Movable); + SplineMeshComponent->RegisterComponent(); + SplineMeshComponent->CreationMethod = EComponentCreationMethod::Instance; + + if (SplineMesh) + { + SplineMeshComponent->SetStaticMesh(SplineMesh); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("SplineMesh not set!")); + } + + if (SplineMaterial) + { + SplineMeshComponent->SetMaterial(0, SplineMaterial); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("SplineMesh material not set! Using default material instead.")); + } + + SplineMeshComponent->SetForwardAxis(ESplineMeshAxis::Z); + SplineMeshComponent->CastShadow = false; + } + else + { + UE_LOG(LogTemp, Error, TEXT("Error while spawning SplineMeshComponent!")) + } +} + +void UIntenSelectComponent::InitForwardRayMeshComponent() +{ + ForwardRayMeshComponent = + NewObject<UStaticMeshComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("ForwardRay")); + + if (ForwardRayMeshComponent) + { + ForwardRayMeshComponent->SetupAttachment(this); + ForwardRayMeshComponent->SetMobility((EComponentMobility::Movable)); + ForwardRayMeshComponent->RegisterComponent(); + ForwardRayMeshComponent->CreationMethod = EComponentCreationMethod::Instance; + + ForwardRayMeshComponent->SetCastShadow(false); + ForwardRayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); + + const float MeshLength = MaxSelectionDistance > 1000 ? 1000 : MaxSelectionDistance; + ForwardRayMeshComponent->SetRelativeScale3D(FVector(MeshLength, ForwardRayWidth, ForwardRayWidth)); + ForwardRayMeshComponent->SetRelativeLocation(FVector(MeshLength * 50, 0, 0)); + + // const ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMesh(TEXT("/Engine/BasicShapes/Cube.Cube")); + if (ForwardRayMesh) + { + ForwardRayMeshComponent->SetStaticMesh(ForwardRayMesh); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("Mesh for RayComponent not set!")); + } + + UMaterialInstanceDynamic* DynamicMaterial = + UMaterialInstanceDynamic::Create(ForwardRayMaterial, ForwardRayMeshComponent); + this->ForwardRayMeshComponent->SetMaterial(0, DynamicMaterial); + + ForwardRayMeshComponent->SetHiddenInGame(!bDrawForwardRay); + } + else + { + UE_LOG(LogTemp, Error, TEXT("Error while spawning ForwardRayMesh component!")); + } +} + +void UIntenSelectComponent::InitMaterialParamCollection() +{ + if (MaterialParamCollection) + { + this->ParameterCollectionInstance = GetWorld()->GetParameterCollectionInstance(MaterialParamCollection); + if (this->ParameterCollectionInstance) + { + this->ParameterCollectionInstance->SetScalarParameterValue("Transparency", DebugRayTransparency); + } + else + { + UE_LOG(LogTemp, Warning, + TEXT("MaterialParameterCollection required for rendering of IntenSelect could not be found!")) + } + } + else + { + UE_LOG(LogTemp, Warning, TEXT("MaterialParameterCollection required for InteSelect visualization is not set!")); + } +} + +void UIntenSelectComponent::InitDebugConeMeshComponent() +{ + DebugConeMeshComponent = + NewObject<UStaticMeshComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("DebugCone")); + + if (DebugConeMeshComponent) + { + DebugConeMeshComponent->SetupAttachment(this); + DebugConeMeshComponent->SetMobility(EComponentMobility::Movable); + DebugConeMeshComponent->RegisterComponent(); + DebugConeMeshComponent->CreationMethod = EComponentCreationMethod::Instance; + + + FTransform ConeTransform = DebugConeMeshComponent->GetRelativeTransform(); + const float ConeScale = MaxSelectionDistance / 50 * FMath::Tan(FMath::DegreesToRadians(SelectionConeAngle)); + ConeTransform.SetScale3D(FVector(ConeScale, ConeScale, MaxSelectionDistance / 100)); + + DebugConeMeshComponent->SetRelativeTransform(ConeTransform); + DebugConeMeshComponent->SetRelativeLocation(FVector(MaxSelectionDistance - ConeBackwardShiftDistance, 0, 0), + false); + DebugConeMeshComponent->SetRelativeRotation(DebugConeRotation, false); + DebugConeMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); + + if (DebugConeMesh) + { + DebugConeMeshComponent->SetStaticMesh(DebugConeMesh); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("DebugCone mesh not set!")) + } + if (DebugConeMaterial) + { + DebugConeMeshComponent->SetMaterial(0, DebugConeMaterial); + } + else + { + UE_LOG(LogTemp, Warning, TEXT("DebugCone material not set! Using default material instead.")) + } + + DebugConeMeshComponent->SetVisibility(bDrawDebugCone); + } + else + { + UE_LOG(LogTemp, Error, TEXT("Error while spawning DebugCone component!")) + } +} + + +// SCORING FUNCTIONS + +float UIntenSelectComponent::CalculateSphereCastRadius() const +{ + return FMath::Tan(FMath::DegreesToRadians(SelectionConeAngle)) * MaxSelectionDistance; +} + +bool UIntenSelectComponent::CheckPointInCone(const FVector ConeStartPoint, const FVector ConeForward, + const FVector PointToTest, const float Angle) const +{ + const FVector ShiftedStartOriginPoint = ConeStartPoint - (ConeForward * ConeBackwardShiftDistance); + const FVector DirectionToTestPoint = (PointToTest - ShiftedStartOriginPoint).GetSafeNormal(); + + const float AngleToTestPoint = + FMath::RadiansToDegrees(FMath::Acos((FVector::DotProduct(ConeForward, DirectionToTestPoint)))); + + return AngleToTestPoint <= Angle; +} + +void UIntenSelectComponent::OnNewSelected_Implementation(UIntenSelectable* Selection) +{ + CurrentSelection = Selection; + + if (FeedbackCooldown == 0) + { + // UGameplayStatics::GetPlayerController(GetWorld(), 0)->PlayHapticEffect(SelectionFeedbackHaptic, + // EControllerHand::Right, 0.1, false); + UGameplayStatics::PlaySound2D(GetWorld(), OnSelectSound); + FeedbackCooldown = 0.1; + } +} + +bool UIntenSelectComponent::GetActorsFromSphereCast(const FVector& SphereCastStart, TArray<FHitResult>& OutHits) const +{ + const FVector StartPos = + SphereCastStart + (GetComponentTransform().GetRotation().GetForwardVector() * SphereCastRadius); + const FVector EndPos = + StartPos + (this->GetComponentTransform().GetRotation().GetForwardVector() * (MaxSelectionDistance)); + + const FCollisionQueryParams Params = FCollisionQueryParams(FName(TEXT("SphereTraceMultiForObjects")), false); + // GetWorld()->SweepMultiByChannel(OutHits, StartPos, EndPos, FQuat::Identity, ECC_Visibility, + // FCollisionShape::MakeSphere(SphereCastRadius), Params); + + GetWorld()->SweepMultiByChannel(OutHits, StartPos, EndPos, FQuat::Identity, ECC_Visibility, + FCollisionShape::MakeSphere(SphereCastRadius), Params); + // UKismetSystemLibrary::SphereTraceMulti(GetWorld(),StartPos,EndPos,SphereCastRadius,ETraceTypeQuery::TraceTypeQuery1,false,{},EDrawDebugTrace::ForOneFrame,OutHits,true); + return true; +} + +UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime) +{ + const FVector ConeOrigin = this->GetComponentTransform().GetLocation(); + const FVector ConeForward = this->GetComponentTransform().GetRotation().GetForwardVector(); + + TArray<FHitResult> OutHits; + if (GetActorsFromSphereCast(ConeOrigin, OutHits)) + { + for (const FHitResult& Hit : OutHits) + { + const FVector PointToCheck = Hit.ImpactPoint; + const float DistanceToActor = FVector::Dist(ConeOrigin, PointToCheck); + + const AActor* HitActor = Hit.GetActor(); + if (HitActor) + { + const auto Selectable = HitActor->FindComponentByClass<UIntenSelectable>(); + + if (Selectable && Selectable->IsSelectable && DistanceToActor <= MaxSelectionDistance) + { + ScoreMap.FindOrAdd(Selectable, 0); + } + } + } + } + + UIntenSelectable* MaxScoreSelectable = nullptr; + float MaxScore = TNumericLimits<float>::Min(); + TArray<UIntenSelectable*> RemoveList; + TArray<TPair<UIntenSelectable*, FHitResult>> CandidateList; + + for (TTuple<UIntenSelectable*, float>& OldScoreEntry : ScoreMap) + { + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, OldScoreEntry.Key->GetOwner()->GetName() + " + // - Score: " + FString::SanitizeFloat(OldScoreEntry.Value)); + if (!OldScoreEntry.Key) + { + continue; + } + + TPair<FHitResult, float> NewScorePair = OldScoreEntry.Key->GetBestPointScorePair( + ConeOrigin, ConeForward, ConeBackwardShiftDistance, SelectionConeAngle, OldScoreEntry.Value, DeltaTime); + + ContactPointMap.Add(OldScoreEntry.Key, NewScorePair.Key); + const float DistanceToActor = FVector::Dist(ConeOrigin, NewScorePair.Key.ImpactPoint); + + const float Eps = 0.01; + if (NewScorePair.Value <= 0.01 || DistanceToActor >= MaxSelectionDistance || !OldScoreEntry.Key->IsSelectable) + { + RemoveList.Add(OldScoreEntry.Key); + } + else + { + OldScoreEntry.Value = NewScorePair.Value; + + if (NewScorePair.Value > (1.0 - Eps) && + this->CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle)) + { + CandidateList.Emplace(OldScoreEntry.Key, NewScorePair.Key); + MaxScore = NewScorePair.Value; + MaxScoreSelectable = OldScoreEntry.Key; + } + else if (NewScorePair.Value > MaxScore && + this->CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle)) + { + MaxScore = NewScorePair.Value; + MaxScoreSelectable = OldScoreEntry.Key; + } + } + } + + for (const UIntenSelectable* i : RemoveList) + { + ContactPointMap.Remove(i); + ScoreMap.Remove(i); + } + if (CandidateList.Num() > 0) + { + auto DistanceToMaxScore = + FVector::Distance(MaxScoreSelectable->GetOwner()->GetActorLocation(), GetComponentLocation()); + auto Dist = TNumericLimits<float>::Max(); + for (const TPair<UIntenSelectable*, FHitResult>& Actor : CandidateList) + { + const auto DistanceToCandidate = FVector::Distance(Actor.Value.ImpactPoint, GetComponentLocation()); + if (DistanceToCandidate < Dist) + { + MaxScoreSelectable = Actor.Key; + Dist = DistanceToCandidate; + } + } + } + + return MaxScoreSelectable; +} +// RAYCASTING + + +void UIntenSelectComponent::HandleWidgetInteraction() +{ + const FVector Forward = this->GetComponentTransform().GetRotation().GetForwardVector(); + const FVector Origin = this->GetComponentTransform().GetLocation(); + + TOptional<FHitResult> Hit = RaytraceForFirstHit(Origin, Origin + Forward * MaxSelectionDistance); + + if (!Hit.IsSet()) + { + IsWidgetInFocus = false; + return; + } + + SetCustomHitResult(Hit.GetValue()); + UWidgetComponent* FocusedWidget = Cast<UWidgetComponent>(Hit.GetValue().GetComponent()); + IsWidgetInFocus = (FocusedWidget != nullptr); + + + /* + if(IsWidgetInFocus) + { + if (FocusedWidget != LastFocusedWidget) + { + //We can always execute the enter event as we are sure that a hit occured + if (FocusedWidget->GetOwner()->Implements<UTargetable>()) + { + ITargetable::Execute_OnTargetedEnter(FocusedWidget->GetOwner()); + } + + //Only execute the Leave Event if there was an actor that was focused previously + if (LastFocusedWidget != nullptr && LastFocusedWidget->GetOwner()->Implements<UTargetable>()) + { + ITargetable::Execute_OnTargetedLeave(LastFocusedWidget->GetOwner()); + } + } + + // for now uses the same distance as clicking + if (FocusedWidget->GetOwner()->Implements<UTargetable>()) + { + ITargetable::Execute_OnTargeted(FocusedWidget->GetOwner(), Hit->Location); + } + LastFocusedWidget = FocusedWidget; + + if(FocusedWidget->GetOwner()->GetClass()->ImplementsInterface(UIntenSelectableWidget::StaticClass())) + { + FVector pos = IIntenSelectableWidget::Execute_GetCoordinates(FocusedWidget->GetOwner()); + GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "C++ Pos: " + pos.ToString()); + WidgetFocusPoint = pos; + }else + { + GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "C++ Pos not available"); + } + }*/ +} + +TOptional<FHitResult> UIntenSelectComponent::RaytraceForFirstHit(const FVector& Start, const FVector& End) const +{ + // will be filled by the Line Trace Function + FHitResult Hit; + + FCollisionQueryParams Params; + Params.AddIgnoredActor(GetOwner()->GetUniqueID()); // prevents actor hitting itself + if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_Visibility, Params)) + { + return {Hit}; + } + else + { + return {}; + } +} + + +// VISUALS + +void UIntenSelectComponent::DrawSelectionCurve(const FVector& EndPoint) const +{ + const FVector StartPoint = this->GetComponentTransform().GetLocation(); + const FVector Forward = this->GetComponentTransform().GetRotation().GetForwardVector(); + + SplineComponent->ClearSplinePoints(true); + SplineMeshComponent->SetHiddenInGame(false); + + AddSplinePointsDefault(StartPoint, Forward, EndPoint); + + const FVector StartPosition = SplineComponent->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::Local); + const FVector StartTangent = SplineComponent->GetTangentAtSplinePoint(0, ESplineCoordinateSpace::Local); + const FVector EndPosition = SplineComponent->GetLocationAtSplinePoint(1, ESplineCoordinateSpace::Local); + const FVector EndTangent = SplineComponent->GetTangentAtSplinePoint(1, ESplineCoordinateSpace::Local); + + SplineMeshComponent->SetStartAndEnd(StartPosition, StartTangent, EndPosition, EndTangent, true); +} + +void UIntenSelectComponent::AddSplinePointsDefault(const FVector& StartPoint, const FVector& Forward, + const FVector& EndPoint) const +{ + SplineComponent->AddSplineWorldPoint(StartPoint); + + const FVector StartToEnd = EndPoint - StartPoint; + const FVector ForwardProjection = StartToEnd.ProjectOnTo(Forward); + + SplineComponent->AddSplineWorldPoint(EndPoint); + + SplineComponent->SetSplinePointType(0, ESplinePointType::Curve, true); + SplineComponent->SetSplinePointType(1, ESplinePointType::Curve, true); + + SplineComponent->SetTangentAtSplinePoint(0, Forward * ForwardProjection.Size() * SplineCurvatureStrength, + ESplineCoordinateSpace::World, true); + SplineComponent->SetTangentAtSplinePoint(1, StartToEnd.GetSafeNormal(), ESplineCoordinateSpace::World, true); +} + +void UIntenSelectComponent::UpdateForwardRay(const FVector& ReferencePoint) const +{ + if (ForwardRayTransparencyCurve) + { + const FVector ConeForward = this->GetComponentTransform().GetRotation().GetForwardVector(); + const FVector ConeOrigin = + this->GetComponentTransform().GetLocation() - (ConeForward * ConeBackwardShiftDistance); + + const FVector TestPointVector = (ReferencePoint - ConeOrigin).GetSafeNormal(); + const float AngleToTestPoint = + FMath::RadiansToDegrees(FMath::Acos((FVector::DotProduct(ConeForward, TestPointVector)))); + + const float NewTransparency = + ForwardRayTransparencyCurve->GetFloatValue(AngleToTestPoint / SelectionConeAngle) * DebugRayTransparency; + ParameterCollectionInstance->SetScalarParameterValue("Transparency", NewTransparency); + } +} + +// INPUT-HANDLING + +void UIntenSelectComponent::OnFireDown() +{ + // start interaction of WidgetInteractionComponent + PressPointerKey(EKeys::LeftMouseButton); + + if (!CurrentSelection) + { + return; + } + + if (CurrentSelection) + { + const FHitResult GrabbedPoint = *ContactPointMap.Find(CurrentSelection); + CurrentSelection->HandleOnClickStartEvents(this); + LastKnownSelection = CurrentSelection; + LastKnownGrabPoint = + LastKnownSelection->GetOwner()->GetRootComponent()->GetComponentTransform().InverseTransformPosition( + GrabbedPoint.ImpactPoint); + } + else + { + LastKnownSelection = nullptr; + } + + IsGrabbing = true; + + if (bDrawForwardRay && ParameterCollectionInstance) + { + ParameterCollectionInstance->SetScalarParameterValue("Transparency", 0); + } +} + +void UIntenSelectComponent::OnFireUp() +{ + // end interaction of WidgetInteractionComponent + ReleasePointerKey(EKeys::LeftMouseButton); + + IsGrabbing = false; + + if (LastKnownSelection) + { + FInputActionValue v; + LastKnownSelection->HandleOnClickEndEvents(this, v); + } +} + +// SELECTION-HANDLING + +void UIntenSelectComponent::SelectObject(UIntenSelectable* SelectableComponent, AActor* SelectedBy) +{ + CurrentSelection = SelectableComponent; +} + +void UIntenSelectComponent::Unselect() +{ + IsGrabbing = false; + + SplineMeshComponent->SetHiddenInGame(true); + + CurrentSelection = nullptr; + this->CurrentSelection = nullptr; +} + +void UIntenSelectComponent::SetActive(bool bNewActive, bool bReset) +{ + if (bNewActive) + { + ForwardRayMeshComponent->SetVisibility(true); + SplineMeshComponent->SetVisibility(true); + + Super::SetActive(true, bReset); + } + else + { + if (CurrentSelection) + { + HandleNoActorSelected(); + } + + if (LastKnownSelection) + { + OnFireUp(); + } + + ForwardRayMeshComponent->SetVisibility(false); + SplineMeshComponent->SetVisibility(false); + + Super::SetActive(false, bReset); + } +} + +// TICK + +void UIntenSelectComponent::HandleCooldown(const float DeltaTime) +{ + if (FeedbackCooldown > 0) + { + FeedbackCooldown -= DeltaTime; + } + else + { + FeedbackCooldown = 0; + } +} + +void UIntenSelectComponent::HandleGrabbing(const float DeltaTime) const {} + +void UIntenSelectComponent::HandleActorSelected(UIntenSelectable* NewSelection) +{ + if (NewSelection != CurrentSelection) + { + if (CurrentSelection) + { + CurrentSelection->HandleOnSelectEndEvents(this); + } + + if (NewSelection) + { + UIntenSelectable* NewIntenSelectable = NewSelection; + const FHitResult GrabbedPoint = *ContactPointMap.Find(NewIntenSelectable); + NewIntenSelectable->HandleOnSelectStartEvents(this, GrabbedPoint); + } + + CurrentSelection = NewSelection; + OnNewSelected(NewSelection); + } + + if (CurrentSelection) + { + const UIntenSelectable* NewIntenSelectable = NewSelection; + const auto V_Net = ContactPointMap.Find(NewIntenSelectable)->ImpactPoint; + const FVector PointToDrawTo = ConvertNetVector(V_Net); + + if (bDrawForwardRay) + { + UpdateForwardRay(PointToDrawTo); + } + + DrawSelectionCurve(PointToDrawTo); + } +} + +FVector UIntenSelectComponent::ConvertNetVector(FVector_NetQuantize v) +{ + FVector Result; + Result.X = v.X; + Result.Y = v.Y; + Result.Z = v.Z; + return Result; +} + + +void UIntenSelectComponent::HandleNoActorSelected() +{ + SplineMeshComponent->SetHiddenInGame(true); + + if (CurrentSelection) + { + CurrentSelection->HandleOnSelectEndEvents(this); + } + + if (bDrawForwardRay && ParameterCollectionInstance) + { + ParameterCollectionInstance->SetScalarParameterValue("Transparency", DebugRayTransparency); + } + CurrentSelection = nullptr; +} + +void UIntenSelectComponent::TickComponent(const float DeltaTime, const ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + this->HandleCooldown(DeltaTime); + UIntenSelectable* const NewSelection = GetMaxScoreActor(DeltaTime); + + if (IsGrabbing && LastKnownSelection) + { + const FVector GrabPointWorld = + LastKnownSelection->GetOwner()->GetRootComponent()->GetComponentTransform().TransformPosition( + LastKnownGrabPoint); + DrawSelectionCurve(GrabPointWorld); + + const FVector ConeOrigin = this->GetComponentLocation(); + const FVector ConeForward = this->GetForwardVector().GetSafeNormal(); + + if (!this->CheckPointInCone(ConeOrigin, ConeForward, GrabPointWorld, MaxClickStickAngle)) + { + OnFireUp(); + } + + return; + } + else if (CurrentSelection && ContactPointMap.Contains(CurrentSelection)) + { + const FVector GrabbedPoint = ConvertNetVector(ContactPointMap.Find(CurrentSelection)->ImpactPoint); + DrawSelectionCurve(GrabbedPoint); + } + + // this->HandleWidgetInteraction(); + IsWidgetInFocus = false; + if (IsWidgetInFocus) + { + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "Widget focused"); + HandleNoActorSelected(); + + const FVector PointToDrawTo = WidgetFocusPoint; + + if (bDrawForwardRay) + { + UpdateForwardRay(PointToDrawTo); + } + + DrawSelectionCurve(PointToDrawTo); + } + else + { + if (NewSelection) + { + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "Focused Actor:" + NewSelection->GetName()); + HandleActorSelected(NewSelection); + } + else + { + // GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "No Actor in Focus"); + HandleNoActorSelected(); + } + } +} diff --git a/Source/RWTHVRToolkit/Private/Pawn/Navigation/CollisionHandlingMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/Navigation/CollisionHandlingMovement.cpp index f644f4add3b96e08f66f28a873e57fba8a504dbd..b565b58a43154ece41c681a371434770e5171d60 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/CollisionHandlingMovement.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/CollisionHandlingMovement.cpp @@ -67,13 +67,21 @@ void UCollisionHandlingMovement::TickComponent(float DeltaTime, enum ELevelTick } } + // in case we are in a collision and collision checks are temporarily deactivated, we only allow physical + // movement without any checks, otherwise check collision during physical movement + if (bCollisionChecksTemporarilyDeactivated) + { + ConsumeInputVector(); + } + else + { + // so we add stepping-up (for both walk and fly) + // and gravity for walking only + MoveByGravityOrStepUp(DeltaTime); - // so we add stepping-up (for both walk and fly) - // and gravity for walking only - MoveByGravityOrStepUp(DeltaTime); - - // if we physically (in the tracking space) walked into something, move the world away (by moving the pawn) - CheckForPhysWalkingCollision(); + // if we physically (in the tracking space) walked into something, move the world away (by moving the pawn) + CheckForPhysWalkingCollision(); + } } if (NavigationMode == EVRNavigationModes::NAV_NONE) @@ -150,6 +158,7 @@ void UCollisionHandlingMovement::CheckAndRevertCollisionSinceLastTick() if (!CreateCapsuleTrace(CapsuleLocation, CapsuleLocation).bBlockingHit) { LastCollisionFreeCapsulePosition = CapsuleLocation; + bCollisionChecksTemporarilyDeactivated = false; } return; } @@ -157,8 +166,18 @@ void UCollisionHandlingMovement::CheckAndRevertCollisionSinceLastTick() // check whether we are in a collision at the current position if (CreateCapsuleTrace(CapsuleLocation, CapsuleLocation).bBlockingHit) { - // if so move back to last position - UpdatedComponent->AddWorldOffset(LastCollisionFreeCapsulePosition.GetValue() - CapsuleLocation); + // if so move back to last position, but only if that position is still collision free + // since the user might have moveed physically in between + FVector LastCapsulePos = LastCollisionFreeCapsulePosition.GetValue(); + if (!CreateCapsuleTrace(LastCapsulePos, LastCapsulePos).bBlockingHit) + { + UpdatedComponent->AddWorldOffset(LastCapsulePos - CapsuleLocation); + } + else + { + bCollisionChecksTemporarilyDeactivated = true; + LastCollisionFreeCapsulePosition.Reset(); + } } else { @@ -175,6 +194,13 @@ void UCollisionHandlingMovement::MoveOutOfNewDynamicCollisions() FVector ResolveDirection = 1.5f * ResolveDirectionOptional.GetValue(); // scale it up for security distance UpdatedComponent->AddWorldOffset(ResolveDirection); + // check whether this helped in resolving the collision, and if not deactivate collision checks temporarily + if (CreateCapsuleTrace(UpdatedComponent->GetComponentLocation(), UpdatedComponent->GetComponentLocation()) + .bBlockingHit) + { + bCollisionChecksTemporarilyDeactivated = true; + } + // invalidate the last collision-free position, since apparently something changed so we got into this collision LastCollisionFreeCapsulePosition.Reset(); } @@ -195,8 +221,8 @@ void UCollisionHandlingMovement::CheckForPhysWalkingCollision() if (HitResult.bBlockingHit) { const FVector MoveOutVector = HitResult.Location - CapsuleLocation; - // move it out twice as far, to avoid getting stuck situations - UpdatedComponent->AddWorldOffset(2 * MoveOutVector); + // move it out a bit farther, to avoid getting stuck situations + UpdatedComponent->AddWorldOffset(1.2f * MoveOutVector); } } @@ -316,19 +342,18 @@ TOptional<FVector> UCollisionHandlingMovement::GetOverlapResolveDirection() cons { TArray<UPrimitiveComponent*> OverlappingComponents; TArray<TEnumAsByte<EObjectTypeQuery>> traceObjectTypes; - traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Visibility)); + + // Ideally we would overlap with ECC_Visibility, but there is no object type this can be converted to that I know + // of. This returns everything, even triggers etc that are *not* visible, which is why we further check for a + // visibility trace and blocking hits. + traceObjectTypes.Add(EObjectTypeQuery::ObjectTypeQuery_MAX); + UKismetSystemLibrary::CapsuleOverlapComponents(GetWorld(), CapsuleColliderComponent->GetComponentLocation(), CapsuleColliderComponent->GetScaledCapsuleRadius(), CapsuleColliderComponent->GetScaledCapsuleHalfHeight(), traceObjectTypes, nullptr, ActorsToIgnore, OverlappingComponents); - if (OverlappingComponents.Num() == 0) - { - // return unset optional - return TOptional<FVector>(); - } - - FVector ResolveVector = FVector::ZeroVector; + TOptional<FVector> ResolveVector; // check what to do to move out of these collisions (or nothing if none is there) // we just add the penetrations so in very unfortunate conditions this can become problematic/blocking but for now // and our regular use cases this works @@ -336,7 +361,13 @@ TOptional<FVector> UCollisionHandlingMovement::GetOverlapResolveDirection() cons { FHitResult Hit = CreateCapsuleTrace(CapsuleColliderComponent->GetComponentLocation(), OverlappingComp->GetComponentLocation(), false); - ResolveVector += Hit.ImpactNormal * Hit.PenetrationDepth; + + if (Hit.bBlockingHit) + { + FVector Change = Hit.ImpactNormal * Hit.PenetrationDepth; + ResolveVector = ResolveVector.IsSet() ? ResolveVector.GetValue() + Change : Change; + } } + return ResolveVector; } diff --git a/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp index 9954fc63fe80c2c19602fdd77ee2c52e1bffd848..fa07db5dd9dd15f582728d56ccbd7bff5b81eaf3 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp @@ -3,17 +3,17 @@ #include "Pawn/Navigation/ContinuousMovementComponent.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerController.h" #include "Utility/RWTHVRUtilities.h" #include "MotionControllerComponent.h" +#include "Camera/CameraComponent.h" void UContinuousMovementComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInput(PlayerInputComponent); - if (!VRPawn || !VRPawn->HasLocalNetOwner() || !InputSubsystem) + if (!VRPawn || !VRPawn->HasLocalNetOwner()) { return; } @@ -23,18 +23,13 @@ void UContinuousMovementComponent::SetupPlayerInput(UInputComponent* PlayerInput { MovementHand = VRPawn->RightHand; RotationHand = VRPawn->LeftHand; - IMCMovement = IMCMovementRight; } else { MovementHand = VRPawn->LeftHand; RotationHand = VRPawn->RightHand; - IMCMovement = IMCMovementLeft; } - // add Input Mapping context - InputSubsystem->AddMappingContext(IMCMovement, 0); - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(PlayerInputComponent); if (!EI) { diff --git a/Source/RWTHVRToolkit/Private/Pawn/Navigation/MovementComponentBase.cpp b/Source/RWTHVRToolkit/Private/Pawn/Navigation/MovementComponentBase.cpp index 48562102b52c22c22b8f6f874e451f74d150534e..2020468fb5fcaefc05c91b8d49dd498f42bfedd7 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/MovementComponentBase.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/MovementComponentBase.cpp @@ -3,27 +3,13 @@ #include "Pawn/Navigation/MovementComponentBase.h" -#include "EnhancedInputSubsystems.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerController.h" #include "Pawn/RWTHVRPawn.h" -#include "Utility/RWTHVRUtilities.h" void UMovementComponentBase::SetupPlayerInput(UInputComponent* PlayerInputComponent) { IInputExtensionInterface::SetupPlayerInput(PlayerInputComponent); VRPawn = Cast<ARWTHVRPawn>(GetOwner()); - - if (!VRPawn || !VRPawn->HasLocalNetOwner()) - { - return; - } - - InputSubsystem = GetEnhancedInputLocalPlayerSubsystem(VRPawn); - if (!InputSubsystem) - { - UE_LOG(Toolkit, Error, TEXT("InputSubsystem IS NOT VALID")); - return; - } } diff --git a/Source/RWTHVRToolkit/Private/Pawn/Navigation/TeleportationComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/Navigation/TeleportationComponent.cpp index 3e1e14b8f4ab4bf57ad956550afa9059ff93162a..3a1a7e054daf3e2f3e544313ee8505316ada9ff5 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/TeleportationComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/TeleportationComponent.cpp @@ -4,7 +4,6 @@ #include "Pawn/Navigation/TeleportationComponent.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" #include "NavigationSystem.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerController.h" @@ -19,7 +18,7 @@ void UTeleportationComponent::SetupPlayerInput(UInputComponent* PlayerInputCompo { Super::SetupPlayerInput(PlayerInputComponent); - if (!VRPawn || !VRPawn->HasLocalNetOwner() || !InputSubsystem) + if (!VRPawn || !VRPawn->HasLocalNetOwner()) { return; } @@ -28,14 +27,16 @@ void UTeleportationComponent::SetupPlayerInput(UInputComponent* PlayerInputCompo GetWorld(), TeleportTraceSystem, VRPawn->GetActorLocation(), FRotator(0), FVector(1), true, true, ENCPoolMethod::AutoRelease, true); - FActorSpawnParameters SpawnParameters = FActorSpawnParameters(); - SpawnParameters.Name = "TeleportVisualizer"; - - if (BPTeleportVisualizer) + if (!BPTeleportVisualizer) { - TeleportVisualizer = GetWorld()->SpawnActor<AActor>(BPTeleportVisualizer, VRPawn->GetActorLocation(), - VRPawn->GetActorRotation(), SpawnParameters); + UE_LOG(Toolkit, Error, + TEXT("SetupPlayerInput: BPTeleportVisualizer must be set to an Actor class that can be spawned!")); + return; } + + TeleportVisualizer = + GetWorld()->SpawnActor<AActor>(BPTeleportVisualizer, VRPawn->GetActorLocation(), VRPawn->GetActorRotation()); + TeleportTraceComponent->SetVisibility(false); TeleportVisualizer->SetActorHiddenInGame(true); @@ -44,18 +45,13 @@ void UTeleportationComponent::SetupPlayerInput(UInputComponent* PlayerInputCompo { TeleportationHand = VRPawn->RightHand; RotationHand = VRPawn->LeftHand; - IMCMovement = IMCTeleportRight; } else { TeleportationHand = VRPawn->LeftHand; RotationHand = VRPawn->RightHand; - IMCMovement = IMCTeleportLeft; } - // add Input Mapping context - InputSubsystem->AddMappingContext(IMCMovement, 0); - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(PlayerInputComponent); if (!EI) { diff --git a/Source/RWTHVRToolkit/Private/Pawn/Navigation/TurnComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/Navigation/TurnComponent.cpp index 31e57513a8de14a7f2aab645ef6ec69a497d0bf4..bcf78e6bd57870bc4e3aef0bbeccb3b730aa0f0e 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/TurnComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/TurnComponent.cpp @@ -4,7 +4,6 @@ #include "Pawn/Navigation/TurnComponent.h" #include "EnhancedInputComponent.h" -#include "EnhancedInputSubsystems.h" #include "Pawn/RWTHVRPawn.h" #include "Utility/RWTHVRUtilities.h" @@ -12,7 +11,7 @@ void UTurnComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInput(PlayerInputComponent); - if (!VRPawn || !VRPawn->HasLocalNetOwner() || !InputSubsystem) + if (!VRPawn || !VRPawn->HasLocalNetOwner()) { return; } @@ -21,22 +20,12 @@ void UTurnComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) if (bTurnWithLeftHand) { RotationHand = VRPawn->LeftHand; - // we use the same IMC for movement and turning - // therefore if we move with the right hand, we turn with the left hand - IMCTurn = IMCMovement_Right; } else { RotationHand = VRPawn->RightHand; - // we use the same IMC for movement and turning - // therefore if we move with the left hand, we turn with the right hand - IMCTurn = IMCMovement_Left; } - // add Input Mapping context - InputSubsystem->AddMappingContext(URWTHVRUtilities::IsDesktopMode() ? IMCDesktopRotation : IMCTurn, 0); - - UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(PlayerInputComponent); if (!EI) { diff --git a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp index eee711326be2929cae7f232537c7dc74c37d42c6..56d56cf05728cc0ce2140f47d0b39a19e0dc665c 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp @@ -2,6 +2,7 @@ #include "Pawn/RWTHVRPawn.h" +#include "EnhancedInputSubsystems.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerController.h" #include "ILiveLinkClient.h" @@ -77,9 +78,13 @@ void ARWTHVRPawn::NotifyControllerChanged() // If we are also the authority (standalone or listen server), directly attach it to us. // If we are not (client), ask the server to do it. if (HasAuthority()) + { AttachDCRAtoPawn(); + } else + { ServerAttachDCRAtoPawnRpc(); + } } } } @@ -88,6 +93,8 @@ void ARWTHVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen { Super::SetupPlayerInputComponent(PlayerInputComponent); + ActivePlayerInputComponent = PlayerInputComponent; + APlayerController* PlayerController = Cast<APlayerController>(GetController()); if (!PlayerController) { @@ -132,6 +139,42 @@ void ARWTHVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen { Cast<IInputExtensionInterface>(Comp)->SetupPlayerInput(PlayerInputComponent); } + + // bind the current mapping contexts + for (const auto& Mapping : InputMappingContexts) + { + AddInputMappingContext(PlayerController, Mapping); + } +} + +UInputComponent* ARWTHVRPawn::GetPlayerInputComponent() { return ActivePlayerInputComponent; } + + +void ARWTHVRPawn::AddInputMappingContext(const APlayerController* PC, const UInputMappingContext* Context) const +{ + if (Context) + { + if (const ULocalPlayer* LP = PC->GetLocalPlayer()) + { + if (UEnhancedInputLocalPlayerSubsystem* InputSub = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) + { + InputSub->AddMappingContext(Context, 0); + } + else + { + UE_LOGFMT(Toolkit, Warning, + "ARWTHVRPawn::AddInputMappingContext: UEnhancedInputLocalPlayerSubsystem is nullptr!"); + } + } + else + { + UE_LOGFMT(Toolkit, Warning, "ARWTHVRPawn::AddInputMappingContext: LocalPlayer is nullptr!"); + } + } + else + { + UE_LOGFMT(Toolkit, Warning, "ARWTHVRPawn::AddInputMappingContext: Context is nullptr!"); + } } void ARWTHVRPawn::EvaluateLivelink() const @@ -151,7 +194,9 @@ void ARWTHVRPawn::EvaluateLivelink() const HeadSubjectRepresentation.Role, SubjectData); if (!bHasValidData) + { return; + } // Assume we are using a Transform Role to track the components! This is a slightly dangerous assumption, and // could be further improved. @@ -205,7 +250,6 @@ void ARWTHVRPawn::AttachDCRAtoPawn() { const auto CaveSetupActor = FoundActors[0]; FAttachmentTransformRules AttachmentRules = FAttachmentTransformRules::SnapToTargetNotIncludingScale; - AttachmentRules.RotationRule = EAttachmentRule::KeepWorld; CaveSetupActor->AttachToActor(this, AttachmentRules); UE_LOGFMT(Toolkit, Display, "VirtualRealityPawn: Attaching CaveSetup to our pawn!"); } diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h index 9978823ad96b612d920c6135886d333717a90d7a..d10affdff4aa25e2e4c22818219375580f342c8f 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h @@ -8,6 +8,12 @@ #include "GrabBehavior.generated.h" +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnGrabStart, USceneComponent*, NewAttachParent, UPrimitiveComponent*, + HeldComponent); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnGrabEnd, USceneComponent*, PreviousAttachParent, UPrimitiveComponent*, + HeldComponent); + UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class RWTHVRTOOLKIT_API UGrabBehavior : public UActionBehaviour { @@ -22,6 +28,19 @@ public: virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, const FInputActionValue& Value) override; + + /** + * Called after the object was successfully attached to the hand + */ + UPROPERTY(BlueprintAssignable) + FOnGrabStart OnGrabStartEvent; + + /** + * Called after the object was successfully detached from the hand + */ + UPROPERTY(BlueprintAssignable) + FOnGrabEnd OnGrabEndEvent; + UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor); // recursively goes up the hierarchy and returns the highest parent simulating physics @@ -29,4 +48,20 @@ public: UPROPERTY() UPrimitiveComponent* MyPhysicsComponent; + + UFUNCTION(BlueprintPure) + bool IsObjectGrabbed() const { return bObjectGrabbed; } + +private: + /** + * Try to detach the object from the hand. Keep this private for now as this does not broadcast the GrabEnd Event + * correctly. + * @return true if object was successfully detached. If detachment failed or if object was not grabbed before, + * return false. + */ + bool TryRelease(); + + bool bObjectGrabbed = false; + + bool bWasSimulatingPhysics; }; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectable.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectable.h new file mode 100644 index 0000000000000000000000000000000000000000..ea8fccb95d7a1fad3a1a5e87ed78ea2a50c90861 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectable.h @@ -0,0 +1,53 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "InputActionValue.h" +#include "Components/ActorComponent.h" +#include "IntenSelectable.generated.h" + + +class UIntenSelectableScoring; +class UClickBehaviour; +class USelectionBehaviour; +class UIntenSelectComponent; + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectable : public UActorComponent +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool IsSelectable = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + UIntenSelectableScoring* ScoringBehaviour; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray<UHoverBehaviour*> OnSelectBehaviours; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray<UActionBehaviour*> OnClickBehaviours; + + +public: + UIntenSelectable(); + + TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) const; + + void HandleOnSelectStartEvents(const UIntenSelectComponent* IntenSelect, const FHitResult& HitResult); + void HandleOnSelectEndEvents(const UIntenSelectComponent* IntenSelect); + void HandleOnClickStartEvents(UIntenSelectComponent* IntenSelect); + void HandleOnClickEndEvents(UIntenSelectComponent* IntenSelect, FInputActionValue& InputValue); + + void InitDefaultBehaviourReferences(); + + void ShowErrorAndQuit(const FString& Message) const; + +protected: + virtual void BeginPlay() override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..28046b36670ec03e2f8333b7a46d8d4d50ff6c28 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h @@ -0,0 +1,30 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableCircleScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableCircleScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + +public: + UIntenSelectableCircleScoring(); + + UPROPERTY(EditAnywhere) + bool OnlyOutline = true; + + UPROPERTY(EditAnywhere) + float Radius = 50; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..34d8b637040fbfd282cfaeeea6b4891eb4f50e7d --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h @@ -0,0 +1,49 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableCubeScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableCubeScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection); + + FVector GetClosestSelectionPointTo(const FVector& RayOrigin, const FVector& RayDirection); + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + +public: + UIntenSelectableCubeScoring(); + + UPROPERTY(EditAnywhere) + bool DrawDebug = true; + + UPROPERTY(EditAnywhere) + bool BackFaceCulling = false; + + UPROPERTY(EditAnywhere) + bool OnlyOutline = false; + + // UPROPERTY(EditAnywhere) + // float XLength = 100; + + // UPROPERTY(EditAnywhere) + // float YLength = 100; + + // UPROPERTY(EditAnywhere) + // float ZLength = 100; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; + + FVector GetClosestPointToRectangle(const FVector& StartPoint, const FVector& Direction, const FVector& Corner00, + const FVector& Corner01, const FVector& Corner10, const FVector& Corner11) const; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..d32e6a1ef1bc20489f1d2aa7046b2d2b101ec6b9 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h @@ -0,0 +1,37 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableCylinderScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableCylinderScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection); + + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + +public: + UIntenSelectableCylinderScoring(); + + UPROPERTY(EditAnywhere) + bool DrawDebug = true; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; + + UPROPERTY(EditAnywhere) + TArray<FVector> LinePoints{FVector::UpVector * 50, FVector::DownVector * 50}; + + UPROPERTY(EditAnywhere) + float Radius = 50; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..fab919a87338f3bc4a17892f1024116cf320f9ec --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h @@ -0,0 +1,34 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableLineScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableLineScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection); + + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + +public: + UIntenSelectableLineScoring(); + + UPROPERTY(EditAnywhere) + bool DrawDebug = true; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; + + UPROPERTY(EditAnywhere, meta = (EditFixedSize)) + TArray<FVector> LinePoints{FVector::RightVector * 50, FVector::LeftVector * 50}; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..fa2742e320b50dc7930be04efec380802f6c0e7c --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h @@ -0,0 +1,29 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableMultiPointScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableMultiPointScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + +public: + UIntenSelectableMultiPointScoring(); + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; + + void UpdatePoints(); + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray<FVector> PointsToSelect; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..12eceb0e803def69c1672f676b50c0aa14d88014 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h @@ -0,0 +1,40 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableRectangleScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableRectangleScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, + const FVector& ToB, FVector& OutIntersection); + + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + +public: + UIntenSelectableRectangleScoring(); + + UPROPERTY(EditAnywhere) + bool DrawDebug = true; + + UPROPERTY(EditAnywhere) + bool OnlyOutline = false; + + UPROPERTY(EditAnywhere) + float XLength = 100; + + UPROPERTY(EditAnywhere) + float YLength = 100; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..529fcd36af3cf04393313110b79f5c0f05a7e6cd --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableScoring.h @@ -0,0 +1,40 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Components/SceneComponent.h" +#include "IntenSelectableScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableScoring : public USceneComponent +{ + GENERATED_BODY() + +protected: + float GetScore(const FVector& ConeOrigin, const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, const FVector& TestPoint, + const float LastValue, const float DeltaTime); + +public: + UIntenSelectableScoring(); + + UPROPERTY(BlueprintReadOnly) + float CurrentScore = 0; + UPROPERTY(EditAnywhere) + bool IsSelectable = true; + UPROPERTY(EditAnywhere) + float Stickiness = 10; + UPROPERTY(EditAnywhere) + float Snappiness = 15; + UPROPERTY(EditAnywhere) + float CompensationConstant = 0.8; + + bool bOverwritingContrib = false; + float Contrib = 0; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime); + + virtual void BeginPlay() override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..f8dc22e8d9fa3594d9ac821b155ccc57c3d110c9 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h @@ -0,0 +1,21 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableSinglePointScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableSinglePointScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +public: + UIntenSelectableSinglePointScoring(); + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; + + virtual void BeginPlay() override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h new file mode 100644 index 0000000000000000000000000000000000000000..42100b8d9857b49a5e21bb8062ed99602f532cc7 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h @@ -0,0 +1,34 @@ +#pragma once + +#include "CoreMinimal.h" +#include "IntenSelectableScoring.h" +#include "IntenSelectableSphereScoring.generated.h" + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectableSphereScoring : public UIntenSelectableScoring +{ + GENERATED_BODY() + +protected: + FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const; + +public: + UIntenSelectableSphereScoring(); + + UPROPERTY(EditAnywhere) + UMaterialInstance* DebugMaterial; + + UPROPERTY(EditAnywhere) + bool OnlyOutline = false; + + UPROPERTY(EditAnywhere) + float Radius = 50; + + UPROPERTY(EditAnywhere) + bool DrawDebug = true; + + virtual TPair<FHitResult, float> GetBestPointScorePair(const FVector& ConeOrigin, + const FVector& ConeForwardDirection, + const float ConeBackwardShiftDistance, const float ConeAngle, + const float LastValue, const float DeltaTime) override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h index 8332a897126c46ccb62418b04da0808b6a1bd2b0..da85ad8b003814098fc21e112de423a097a80535 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h @@ -46,6 +46,12 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite) TArray<UActionBehaviour*> OnActionBehaviours; + /** + * If true, allow a grab to be triggered by the geometry of a child actor. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool bAllowInteractionFromChildGeometry = true; + UFUNCTION(BlueprintCallable) FORCEINLINE bool HasInteractionTypeFlag(EInteractorType type) { return type & InteractorFilter; } @@ -76,7 +82,7 @@ public: const FInputActionValue& Value, const EInteractorType Interactor); /** - * @brief If click and grab behaviors are not explicitly specified, load all existing ones + * @brief If hover and action behaviors are not explicitly specified, load all existing ones */ void InitDefaultBehaviourReferences(); @@ -91,7 +97,4 @@ public: TArray<USceneComponent*> AllowedComponents; bool IsComponentAllowed(USceneComponent* Component) const; - -private: - bool bInitOnce = true; }; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h index a317318d9d4af78e1a640c76ce6e7629dbbefae7..f2faaebab1f5288633cf68fba9773a4cd076c952 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h @@ -6,7 +6,7 @@ enum EInteractorType : int None = 0 UMETA(Hidden), Raycast = 1 << 0, Spherecast = 1 << 1, - Grab = 1 << 2, + Direct = 1 << 2, Reserved2 = 1 << 3, Reserved3 = 1 << 4, Reserved4 = 1 << 5, diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..69ef74ff844a727c11a333047a7f011a12d01241 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/DirectInteractionComponent.h @@ -0,0 +1,58 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/SceneComponent.h" +#include "Interaction/Interactables/InteractableComponent.h" +#include "Pawn/InputExtensionInterface.h" +#include "DirectInteractionComponent.generated.h" + +UCLASS(Abstract, Blueprintable) +class RWTHVRTOOLKIT_API UDirectInteractionComponent : public USceneComponent, public IInputExtensionInterface +{ + GENERATED_BODY() + +public: + // Sets default values for this component's properties + UDirectInteractionComponent(); + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + + UPROPERTY(EditAnywhere, Category = "Input") + class UInputAction* InteractionInputAction; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") + float InteractionSphereRadius = 15.0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") + bool bShowDebugTrace = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") + bool bOnlyInteractWithClosestActor = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Direct Interaction") + TArray<AActor*> ActorsToIgnore; + + virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; + +private: + UFUNCTION() + void OnBeginInteraction(const FInputActionValue& Value); + + UFUNCTION() + void OnEndInteraction(const FInputActionValue& Value); + + UPROPERTY() + TArray<UInteractableComponent*> PreviousInteractableComponentsInRange; + + UPROPERTY() + TArray<UInteractableComponent*> CurrentInteractableComponentsInRange; + + TArray<TWeakObjectPtr<UInteractableComponent>> CurrentlyInteractedComponents; + + UInteractableComponent* SearchForInteractable(AActor* HitActor); + + bool bSearchAtParent = false; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h deleted file mode 100644 index 84e1eea6a0eb35fe03519d7eebf39fc93fa0fde0..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h +++ /dev/null @@ -1,51 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Components/SceneComponent.h" -#include "Interaction/Interactables/InteractableComponent.h" -#include "Pawn/InputExtensionInterface.h" -#include "GrabComponent.generated.h" - -class UGrabbableComponent; - -UCLASS(Abstract, Blueprintable) -class RWTHVRTOOLKIT_API UGrabComponent : public USceneComponent, public IInputExtensionInterface -{ - GENERATED_BODY() - -public: - // Sets default values for this component's properties - UGrabComponent(); - - virtual void TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; - - UPROPERTY(EditDefaultsOnly, Category = "Input") - class UInputMappingContext* IMCGrab; - - UPROPERTY(EditAnywhere, Category = "Input") - class UInputAction* GrabInputAction; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - float GrabSphereRadius = 15.0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - bool bShowDebugTrace = false; - - virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; - -private: - UFUNCTION() - void OnBeginGrab(const FInputActionValue& Value); - - UFUNCTION() - void OnEndGrab(const FInputActionValue& Value); - - UPROPERTY() - TArray<UInteractableComponent*> PreviousGrabbablesInRange; - - UPROPERTY() - TArray<UInteractableComponent*> CurrentGrabbableInRange; -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RWTHVRWidgetInteractionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RWTHVRWidgetInteractionComponent.h index 35e32044552e9f84fa5314042b8f926678da5e01..4b1139cf89724faea664f4ac4e2e42f9cf1bb9db 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RWTHVRWidgetInteractionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RWTHVRWidgetInteractionComponent.h @@ -11,16 +11,15 @@ UENUM() enum EInteractionRayVisibility { Visible UMETA(DisplayName = "Interaction ray visible"), - VisibleOnHoverOnly UMETA( - DisplayName = - "Interaction ray only visible when hovering over interactable world UI widgets"), + VisibleOnHoverOnly UMETA(DisplayName = + "Interaction ray only visible when hovering over interactable world UI widgets"), Invisible UMETA(DisplayName = "Interaction ray invisible") }; -UCLASS(Blueprintable, Abstract, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) +UCLASS(Blueprintable, Abstract, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class RWTHVRTOOLKIT_API URWTHVRWidgetInteractionComponent : public UWidgetInteractionComponent, - public IInputExtensionInterface + public IInputExtensionInterface { GENERATED_BODY() @@ -30,7 +29,7 @@ public: virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; + FActorComponentTickFunction* ThisTickFunction) override; UFUNCTION(BlueprintCallable) void SetInteractionRayVisibility(EInteractionRayVisibility NewVisibility); @@ -44,9 +43,6 @@ public: UPROPERTY(EditAnywhere) TEnumAsByte<EInteractionRayVisibility> InteractionRayVisibility = EInteractionRayVisibility::Invisible; - UPROPERTY(EditDefaultsOnly, Category = "Input") - class UInputMappingContext* IMCWidgetInteraction; - UPROPERTY(EditAnywhere, Category = "Input") class UInputAction* WidgetClickInputAction; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h similarity index 68% rename from Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h rename to Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h index 45095c3ac50cc2b81e691e9463d3af2253815173..f5c93123e8ba136e747796825f93309b285109b0 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h @@ -6,28 +6,25 @@ #include "CoreMinimal.h" #include "Components/SceneComponent.h" -#include "RaycastSelectionComponent.generated.h" +#include "Interaction/Interactables/InteractableComponent.h" +#include "RaycastInteractionComponent.generated.h" UCLASS(Abstract, Blueprintable) -class RWTHVRTOOLKIT_API URaycastSelectionComponent : public USceneComponent, public IInputExtensionInterface +class RWTHVRTOOLKIT_API URaycastInteractionComponent : public USceneComponent, public IInputExtensionInterface { GENERATED_BODY() public: // Sets default values for this component's properties - URaycastSelectionComponent(); + URaycastInteractionComponent(); // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - - UPROPERTY(EditDefaultsOnly, Category = "Input") - class UInputMappingContext* IMCRaycastSelection; - UPROPERTY(EditAnywhere, Category = "Input") - class UInputAction* RayCastSelectInputAction; + class UInputAction* InteractionInputAction; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast") float TraceLength = 3000.0; @@ -36,10 +33,10 @@ public: private: UFUNCTION() - void OnBeginSelect(const FInputActionValue& Value); + void OnBeginInteraction(const FInputActionValue& Value); UFUNCTION() - void OnEndSelect(const FInputActionValue& Value); + void OnEndInteraction(const FInputActionValue& Value); public: virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; diff --git a/Source/RWTHVRToolkit/Public/Pawn/InputExtensionInterface.h b/Source/RWTHVRToolkit/Public/Pawn/InputExtensionInterface.h index 51963c0a1514950229a8b8286ad41e407accd362..5d38f4f28172c1053ba3fed15bc0ce0c3c1c8252 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/InputExtensionInterface.h +++ b/Source/RWTHVRToolkit/Public/Pawn/InputExtensionInterface.h @@ -24,7 +24,4 @@ class RWTHVRTOOLKIT_API IInputExtensionInterface public: // Called by VirtualRealityPawn::SetupPlayerInputComponent virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) {} - - // Helper function to get the local player subsystem - virtual UEnhancedInputLocalPlayerSubsystem* GetEnhancedInputLocalPlayerSubsystem(const APawn* Pawn) const; }; diff --git a/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h b/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..ebb11aae55a37e1cd0974a0578c0ea3c712a3715 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h @@ -0,0 +1,201 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#pragma region /** Includes */ +#include "Components/SplineComponent.h" +#include "Components/SplineMeshComponent.h" +#include "CoreMinimal.h" +#include "InputAction.h" +#include "Components/WidgetInteractionComponent.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectable.h" +#include "IntenSelectComponent.generated.h" +#pragma endregion + +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnNewComponent); + +UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UIntenSelectComponent : public UWidgetInteractionComponent +{ + GENERATED_BODY() + + + // VARIABLES + +#pragma region /** INTERNAL VARIABLES */ +private: + float SphereCastRadius; + float FeedbackCooldown; + bool IsGrabbing; + bool IsWidgetInFocus; + FVector WidgetFocusPoint; + + UPROPERTY() + UWidgetComponent* LastFocusedWidget; + UPROPERTY() + TMap<UIntenSelectable*, float> ScoreMap; + UPROPERTY() + TMap<UIntenSelectable*, FHitResult> ContactPointMap; + UPROPERTY() + UIntenSelectable* CurrentSelection; + UPROPERTY() + UIntenSelectable* LastKnownSelection; + UPROPERTY() + FVector LastKnownGrabPoint; + UPROPERTY() + UStaticMeshComponent* DebugConeMeshComponent; + UPROPERTY() + UStaticMeshComponent* ForwardRayMeshComponent; + UPROPERTY() + USplineComponent* SplineComponent; + UPROPERTY() + USplineMeshComponent* SplineMeshComponent; + UPROPERTY() + UMaterialParameterCollectionInstance* ParameterCollectionInstance; + UPROPERTY() + UStaticMesh* DebugConeMesh; + UPROPERTY() + UMaterialInterface* DebugConeMaterial; + UPROPERTY() + UStaticMesh* ForwardRayMesh; +#pragma endregion + +#pragma region /** SETTINGS */ +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + bool SetActiveOnStart = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float MaxSelectionDistance = 5000; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float SelectionConeAngle = 5; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float SplineCurvatureStrength = 1; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float ConeBackwardShiftDistance = 0; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float MaxClickStickAngle = 10; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "IntenSelect|Settings") + float ForwardRayWidth = 0.01; +#pragma endregion + +#pragma region /** REFERENCES */ +public: + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UStaticMesh* SplineMesh; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UMaterialInterface* SplineMaterial; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UMaterialInterface* ForwardRayMaterial; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UHapticFeedbackEffect_Base* SelectionFeedbackHaptic; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + USoundBase* OnSelectSound; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UMaterialParameterCollection* MaterialParamCollection; + UPROPERTY(EditAnywhere, Category = "IntenSelect|References") + UCurveFloat* ForwardRayTransparencyCurve; +#pragma endregion + +#pragma region /** DEBUG */ +public: + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + bool bDrawDebugCone = false; + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + bool bDrawForwardRay = true; + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + FRotator DebugConeRotation = FRotator(90, 0, 0); + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + FVector DebugConeScale = FVector(1, 1, 1); + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + FVector DebugConePosition = FVector(-90, 0, 0); + UPROPERTY(EditAnywhere, Category = "IntenSelect|Debug") + float DebugRayTransparency = 1; +#pragma endregion + + +#pragma region /** Input */ +public: + UPROPERTY(EditAnywhere, Category = "IntenSelect|Input") + UInputAction* InputClick; + +#pragma endregion + +#pragma region /** EVENTS */ +public: + UPROPERTY(BlueprintAssignable) + FOnNewComponent OnNewSelectedEvent; +#pragma endregion + + + // FUNCTIONS + +#pragma region /** INITIALIZATION */ +private: + void InitInputBindings(); + void InitDebugConeMeshComponent(); + void InitSplineMeshComponent(); + void InitSplineComponent(); + void InitForwardRayMeshComponent(); + void InitMaterialParamCollection(); +#pragma endregion + +#pragma region /** SCORING */ +private: + float CalculateSphereCastRadius() const; + bool GetActorsFromSphereCast(const FVector& SphereCastStart, TArray<FHitResult>& OutHits) const; + bool CheckPointInCone(const FVector ConeStartPoint, const FVector ConeForward, const FVector PointToTest, + const float Angle) const; + UIntenSelectable* GetMaxScoreActor(const float DeltaTime); +#pragma endregion + +#pragma region /** VISUALS */ +private: + void DrawSelectionCurve(const FVector& EndPoint) const; + void AddSplinePointsDefault(const FVector& StartPoint, const FVector& Forward, const FVector& EndPoint) const; + void UpdateForwardRay(const FVector& ReferencePoint) const; +#pragma endregion + +#pragma region /** RAYCASTING */ +private: + void HandleWidgetInteraction(); + TOptional<FHitResult> RaytraceForFirstHit(const FVector& Start, const FVector& End) const; +#pragma endregion + +#pragma region /** INPUT-HANDLING */ +private: + UFUNCTION(BlueprintCallable) + void OnFireDown(); + UFUNCTION(BlueprintCallable) + void OnFireUp(); +#pragma endregion + +#pragma region /** OTHER */ +private: + void HandleCooldown(const float DeltaTime); + void HandleGrabbing(const float DeltaTime) const; + void HandleNoActorSelected(); + void HandleActorSelected(UIntenSelectable* NewSelection); + FVector ConvertNetVector(FVector_NetQuantize v); +#pragma endregion + +public: + UIntenSelectComponent(const FObjectInitializer& ObjectInitializer); + +#pragma region /** SELECTION */ + void SelectObject(UIntenSelectable* SelectableComponent, AActor* SelectedBy); + void Unselect(); +#pragma endregion + + virtual void SetActive(bool bNewActive, bool bReset) override; + + UFUNCTION(BlueprintNativeEvent) + void OnNewSelected(UIntenSelectable* Selection); + +protected: + // Called when the game starts + virtual void BeginPlay() override; + + // Called every frame + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; +}; diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/CollisionHandlingMovement.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/CollisionHandlingMovement.h index afa154c74c033ec47ae80862018b441fe113594b..6166c84a1c6f2aee1adfdd2d7b5080ac027d23cd 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/CollisionHandlingMovement.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/CollisionHandlingMovement.h @@ -8,14 +8,14 @@ /* * This Movement component is needed since in VR not only the pawn itself (UpdatedComponent) is moved but also the - * user herself can walk and thereby move the CameraComponent, which can also lead to collisions or e.g. going up steps + * user herself can walk and thereby move the CameraComponent, which can also lead to collisions or e.g. going up steps * * The four modes are: - * None: No controller movement is applied and no corrections regarding steps or collisions with walls are done - * Ghost: The same as above but now the Inputs can be used for unconstrained flying (also through objects) - * Fly: The user can fly but not through walls etc. When the user walks against a wall the scene is moved with her to avoid walking through - * The user can also walk up stairs with a maximum step height of MaxStepHeight - * Walk: Additionally to Fly now gravity keeps the user on the floor + * - None: No controller movement is applied and no corrections regarding steps or collisions with walls are done + * - Ghost: The same as above but now the Inputs can be used for unconstrained flying (also through objects) + * - Fly: The user can fly but not through walls etc. When the user walks against a wall the scene is moved with her to + * avoid walking through The user can also walk up stairs with a maximum step height of MaxStepHeight + * - Walk: Additionally to Fly, now gravity keeps the user on the floor */ UENUM(BlueprintType) @@ -38,14 +38,14 @@ public: void MoveOutOfNewDynamicCollisions(); virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; + FActorComponentTickFunction* ThisTickFunction) override; void SetHeadComponent(USceneComponent* NewHeadComponent); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") EVRNavigationModes NavigationMode = EVRNavigationModes::NAV_WALK; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin="0.0")) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin = "0.0")) float MaxStepHeight = 40.0f; // if the height that the pawn would fall (in walking mode) is higher @@ -53,17 +53,17 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") float MaxFallingDepth = 1000.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMax="0.0")) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMax = "0.0")) float GravityAcceleration = -981.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin="0.0")) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin = "0.0")) float UpSteppingAcceleration = 981.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin="0.0")) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta = (ClampMin = "0.0")) float CapsuleRadius = 40.0f; private: - //check for + // check for FHitResult CreateCapsuleTrace(const FVector& Start, const FVector& End, bool DrawDebug = false) const; TOptional<FVector> GetOverlapResolveDirection() const; void SetCapsuleColliderToUserSize() const; @@ -82,7 +82,11 @@ private: TOptional<FVector> LastCollisionFreeCapsulePosition; FVector LastSteeringCollisionVector; - //just stored for performance gains; + // just stored for performance gains; UPROPERTY(VisibleAnywhere, Transient, DuplicateTransient) TArray<AActor*> ActorsToIgnore; + + // if a collision happens and cannot be resolved (e.g. the user crouched, walked under something and stood up) + // we remporarily deactivate all checks until the user is in a collision free situation again + bool bCollisionChecksTemporarilyDeactivated = false; }; diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/ContinuousMovementComponent.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/ContinuousMovementComponent.h index adbcef6f926e48e57d379423f0b1829f699fe4e3..06e715c52436b903f07978de0ec6508432fedbf1 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/ContinuousMovementComponent.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/ContinuousMovementComponent.h @@ -31,12 +31,6 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") bool bMoveWithRightHand = true; - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - UInputMappingContext* IMCMovementLeft; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - UInputMappingContext* IMCMovementRight; - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input|Actions") UInputAction* Move; @@ -53,9 +47,6 @@ public: virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; private: - UPROPERTY() - class UInputMappingContext* IMCMovement; - UPROPERTY() UMotionControllerComponent* MovementHand; diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h index d2a687130b4f8caf850c25a75b92a4c9364aa66c..ef8548c76182a54a42dca18a62291347b5bbf626 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h @@ -19,12 +19,10 @@ class RWTHVRTOOLKIT_API UMovementComponentBase : public UActorComponent, public public: // Already sets up VRPawn and InputSubsystem properties that can be used by child classes. + UFUNCTION(BlueprintCallable) virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; protected: UPROPERTY() ARWTHVRPawn* VRPawn; - - UPROPERTY() - UEnhancedInputLocalPlayerSubsystem* InputSubsystem; }; diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/TeleportationComponent.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/TeleportationComponent.h index e66968a3b77531ba983d24ad05bcda0451282a8c..308634643f4a0ad6520ab882e384a8bbe8ff8e96 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/TeleportationComponent.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/TeleportationComponent.h @@ -34,12 +34,6 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement|Teleport") float TeleportLaunchSpeed = 800; - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - UInputMappingContext* IMCTeleportLeft; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - UInputMappingContext* IMCTeleportRight; - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input|Actions") UInputAction* Move; @@ -73,9 +67,6 @@ private: UPROPERTY() UMotionControllerComponent* RotationHand; - UPROPERTY() - UInputMappingContext* IMCMovement; - bool bTeleportTraceActive; float TeleportProjectileRadius = 3.6; float RotationArrowRadius = 10.0; diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/TurnComponent.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/TurnComponent.h index de3f274e28caf8f353349798a84c4f2dfc02356d..25576574f32fdbfc5bf095bad2c6d9dfeafee066 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/TurnComponent.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/TurnComponent.h @@ -39,16 +39,6 @@ public: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input|Actions") class UInputAction* DesktopRotation; - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UInputMappingContext* IMCMovement_Left; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UInputMappingContext* IMCMovement_Right; - - /**Input Mapping Context that maps buttons for desktop mode*/ - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UInputMappingContext* IMCDesktopRotation; - /** * Called every tick as long as stick input is received to allow for continuous turning * @param Value Stick input value determines turn direction and turn speed @@ -75,9 +65,6 @@ private: UPROPERTY() UMotionControllerComponent* RotationHand; - UPROPERTY() - class UInputMappingContext* IMCTurn; - /** * If we just use VRPawn->AddControllerYawInput(Yaw), rotation is around tracking origin instead of the actual * player position This function updates the pawns rotation and location to result in a rotation around the users diff --git a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h index 50b98e0e84c1cfb5461c2d5764147fe6de77ca32..490dffdf9445a9578e43cf15f6b062b73b70baf1 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h +++ b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h @@ -31,6 +31,9 @@ public: virtual void NotifyControllerChanged() override; + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Pawn|Input") + TArray<UInputMappingContext*> InputMappingContexts; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|MotionControllers") UMotionControllerComponent* RightHand; @@ -82,6 +85,10 @@ public: protected: virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; + void AddInputMappingContext(const APlayerController* PC, const UInputMappingContext* Context) const; + + UFUNCTION(BlueprintCallable) + UInputComponent* GetPlayerInputComponent(); /* LiveLink helper function called on tick */ void EvaluateLivelink() const; @@ -105,4 +112,7 @@ protected: /* Set device specific motion controller sources (None, L/R, Livelink) */ void SetupMotionControllerSources(); + +private: + UInputComponent* ActivePlayerInputComponent; }; diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCircleScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCircleScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0dc19d143b2f2f2edc95dac79ee2c3f27690ff7 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCircleScoringVisualizer.cpp @@ -0,0 +1,184 @@ +#include "Interaction/IntenSelectableCircleScoringVisualizer.h" + +#include "ActorEditorUtils.h" +#include "SceneManagement.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h" +#include "Kismet/KismetMathLibrary.h" + +IMPLEMENT_HIT_PROXY(FCircleProxy, HComponentVisProxy); + +FIntenSelectableCircleScoringVisualizer::FIntenSelectableCircleScoringVisualizer() +{ + PointsProperty = FindFProperty<FProperty>(UIntenSelectableCircleScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableCircleScoring, Radius)); +} + +FIntenSelectableCircleScoringVisualizer::~FIntenSelectableCircleScoringVisualizer() {} + +FVector FIntenSelectableCircleScoringVisualizer::GetCurrentVectorWorld() const +{ + switch (CurrentSelectionIndex) + { + case 0: + return GetEditedScoringComponent()->GetComponentLocation(); + case 1: + { + const FVector CenterWorld = GetEditedScoringComponent()->GetComponentLocation(); + const FVector NormalWorldPoint = + GetEditedScoringComponent()->GetComponentTransform().TransformPosition(FVector::ForwardVector); + const FVector WorldNormalDir = NormalWorldPoint - CenterWorld; + const FVector Y = + WorldNormalDir.RotateAngleAxis(90, GetEditedScoringComponent()->GetRightVector()).GetSafeNormal() * + GetEditedScoringComponent()->Radius; + return CenterWorld + Y; + } + default: + return FVector::ZeroVector; + } +} + +bool FIntenSelectableCircleScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +UIntenSelectableCircleScoring* FIntenSelectableCircleScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableCircleScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableCircleScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableCircleScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableCircleScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + // UE_LOG(LogTemp, Warning, TEXT("Handling Click")); + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FCircleProxy::StaticGetType())) + { + const UIntenSelectableCircleScoring* T = + Cast<const UIntenSelectableCircleScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FCircleProxy* Proxy = (FCircleProxy*)VisProxy; + CurrentSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableCircleScoringVisualizer::DrawVisualization(const UActorComponent* Component, + const FSceneView* View, FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableCircleScoring* ComponentCasted = Cast<UIntenSelectableCircleScoring>(Component); + + if (ComponentCasted != nullptr) + { + PDI->SetHitProxy(new FCircleProxy(Component, 0)); + + const FVector CenterWorld = ComponentCasted->GetComponentLocation(); + PDI->DrawPoint(CenterWorld, FColor::Green, 20.f, SDPG_Foreground); + PDI->SetHitProxy(nullptr); + + PDI->SetHitProxy(new FCircleProxy(Component, 1)); + const FVector NormalWorldPoint = + ComponentCasted->GetComponentTransform().TransformPosition(FVector::ForwardVector); + const FVector WorldNormalDir = NormalWorldPoint - CenterWorld; + const FVector Y = WorldNormalDir.RotateAngleAxis(90, ComponentCasted->GetRightVector()); + const FVector Z = FVector::CrossProduct(Y.GetSafeNormal(), WorldNormalDir); + DrawCircle(PDI, CenterWorld, Y.GetSafeNormal(), Z.GetSafeNormal(), FColor::Green, ComponentCasted->Radius, 100, + SDPG_Foreground, 2); + + PDI->SetHitProxy(nullptr); + } +} + +void FIntenSelectableCircleScoringVisualizer::EndEditing() {} + +UActorComponent* FIntenSelectableCircleScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +bool FIntenSelectableCircleScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, + FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) +{ + bool bHandled = false; + + if (CurrentSelectionIndex != INDEX_NONE) + { + // UE_LOG(LogTemp, Warning, TEXT("Current Selection! %s"), *DeltaTranslate.ToString()); + + if (CurrentSelectionIndex == 0) + { + const FVector LocalCenter = GetEditedScoringComponent()->GetComponentLocation(); + const FVector NewCenter = LocalCenter + DeltaTranslate; + GetEditedScoringComponent()->SetWorldLocation(NewCenter); + GetEditedScoringComponent()->AddWorldRotation(DeltaRotate); + + bHandled = true; + } + else if (CurrentSelectionIndex == 1) + { + const FVector CenterWorld = GetEditedScoringComponent()->GetComponentLocation(); + const FVector NormalWorldPoint = + GetEditedScoringComponent()->GetComponentTransform().TransformPosition(FVector::ForwardVector); + const FVector WorldNormalDir = NormalWorldPoint - CenterWorld; + const FVector RadiusVector = + WorldNormalDir.RotateAngleAxis(90, GetEditedScoringComponent()->GetRightVector()).GetSafeNormal() * + GetEditedScoringComponent()->Radius; + + const FVector ClampedTranslate = + DeltaTranslate.Size() > 100 ? DeltaTranslate.GetSafeNormal() * 100 : DeltaTranslate; + GetEditedScoringComponent()->Radius = + FVector::Distance(CenterWorld, CenterWorld + RadiusVector + ClampedTranslate); + bHandled = true; + } + + TArray<FProperty*> Properties; + Properties.Add(PointsProperty); + NotifyPropertiesModified(GetEditedScoringComponent(), Properties, EPropertyChangeType::ValueSet); + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return bHandled; +} + +bool FIntenSelectableCircleScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (CurrentSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCubeScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCubeScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..719a5bc4eca4e981730cd047cfff1c21d6a06e39 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCubeScoringVisualizer.cpp @@ -0,0 +1,144 @@ +#include "Interaction/IntenSelectableCubeScoringVisualizer.h" + +#include "ActorEditorUtils.h" +#include "DrawDebugHelpers.h" +#include "SceneManagement.h" +#include "MaterialShared.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h" +#include "Materials/MaterialInstance.h" +#include "Materials/MaterialRenderProxy.h" + +IMPLEMENT_HIT_PROXY(FCubeProxy, HComponentVisProxy); + +FIntenSelectableCubeScoringVisualizer::FIntenSelectableCubeScoringVisualizer() : + DebugMaterial(FColoredMaterialRenderProxy(GEngine->ConstraintLimitMaterial->GetRenderProxy(), FColor::Green)) +{ +} + +FIntenSelectableCubeScoringVisualizer::~FIntenSelectableCubeScoringVisualizer() {} + +FVector FIntenSelectableCubeScoringVisualizer::GetCurrentVectorWorld() const +{ + return GetEditedScoringComponent()->GetComponentLocation(); +} + +bool FIntenSelectableCubeScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +UIntenSelectableCubeScoring* FIntenSelectableCubeScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableCubeScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableCubeScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableCubeScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableCubeScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + // UE_LOG(LogTemp, Warning, TEXT("Handling Click")); + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FCubeProxy::StaticGetType())) + { + const UIntenSelectableCubeScoring* T = Cast<const UIntenSelectableCubeScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FCubeProxy* Proxy = (FCubeProxy*)VisProxy; + CurrentSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableCubeScoringVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableCubeScoring* ComponentCasted = Cast<UIntenSelectableCubeScoring>(Component); + + if (ComponentCasted != nullptr) + { + PDI->SetHitProxy(new FCubeProxy(Component, 0)); + + const auto Scale = ComponentCasted->GetRelativeTransform().GetScale3D(); + const FVector Radii{Scale.X, Scale.Y, Scale.Z}; + DrawBox(PDI, ComponentCasted->GetComponentTransform().ToMatrixNoScale(), Radii / 2, &DebugMaterial, 0); + PDI->DrawPoint(ComponentCasted->GetComponentLocation(), FColor::Green, 20, 0); + + PDI->SetHitProxy(nullptr); + } +} + +void FIntenSelectableCubeScoringVisualizer::EndEditing() {} + +UActorComponent* FIntenSelectableCubeScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +bool FIntenSelectableCubeScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, + FVector& DeltaTranslate, FRotator& DeltaRotate, + FVector& DeltaScale) +{ + bool bHandled = false; + + if (CurrentSelectionIndex != INDEX_NONE) + { + // UE_LOG(LogTemp, Warning, TEXT("Current Selection! %s"), *DeltaTranslate.ToString()); + + const FVector LocalCenter = GetEditedScoringComponent()->GetComponentLocation(); + const FVector NewCenter = LocalCenter + DeltaTranslate; + GetEditedScoringComponent()->SetWorldLocation(NewCenter); + GetEditedScoringComponent()->AddWorldRotation(DeltaRotate); + + auto Scale = GetEditedScoringComponent()->GetRelativeTransform().GetScale3D(); + + Scale.X += DeltaScale.X * 3; + Scale.Y += DeltaScale.Y * 3; + Scale.Z += DeltaScale.Z * 3; + + GetEditedScoringComponent()->GetRelativeTransform().SetScale3D(Scale); + bHandled = true; + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return bHandled; +} + +bool FIntenSelectableCubeScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (CurrentSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCylinderScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCylinderScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..076cf8e42e290a4bfb229c3b19c029f664ecdde8 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableCylinderScoringVisualizer.cpp @@ -0,0 +1,209 @@ +#include "Interaction/IntenSelectableCylinderScoringVisualizer.h" +#include "ActorEditorUtils.h" +#include "SceneManagement.h" + +IMPLEMENT_HIT_PROXY(FCylinderPointProxy, HComponentVisProxy); + +FIntenSelectableCylinderScoringVisualizer::FIntenSelectableCylinderScoringVisualizer() : + DebugMaterial(FColoredMaterialRenderProxy(GEngine->ConstraintLimitMaterial->GetRenderProxy(), FColor::Green)) +{ + RadiusProperty = FindFProperty<FProperty>(UIntenSelectableCylinderScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableCylinderScoring, Radius)); + PointsProperty = FindFProperty<FProperty>(UIntenSelectableCylinderScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableCylinderScoring, LinePoints)); +} + +FIntenSelectableCylinderScoringVisualizer::~FIntenSelectableCylinderScoringVisualizer() {} + +bool FIntenSelectableCylinderScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +FVector FIntenSelectableCylinderScoringVisualizer::GetCurrentVectorWorld() const +{ + if (GetEditedScoringComponent()) + { + if (CurrentCylinderSelectionIndex == INDEX_NONE) + { + return GetEditedScoringComponent()->GetComponentLocation(); + } + return GetEditedScoringComponent()->GetComponentTransform().TransformPositionNoScale( + GetEditedScoringComponent()->LinePoints[CurrentCylinderSelectionIndex]); + } + + return FVector::ZeroVector; +} + +bool FIntenSelectableCylinderScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableCylinderScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableCylinderScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + // UE_LOG(LogTemp, Warning, TEXT("Handling Click")); + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FCylinderPointProxy::StaticGetType())) + { + const UIntenSelectableCylinderScoring* T = + Cast<const UIntenSelectableCylinderScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FCylinderPointProxy* Proxy = (FCylinderPointProxy*)VisProxy; + CurrentCylinderSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentCylinderSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentCylinderSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableCylinderScoringVisualizer::DrawVisualization(const UActorComponent* Component, + const FSceneView* View, FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableCylinderScoring* ComponentCasted = Cast<UIntenSelectableCylinderScoring>(Component); + + if (ComponentCasted != nullptr) + { + for (int i = 0; i < ComponentCasted->LinePoints.Num(); i++) + { + PDI->SetHitProxy(new FCylinderPointProxy(Component, i)); + + FVector PointWorld = + ComponentCasted->GetComponentTransform().TransformPositionNoScale(ComponentCasted->LinePoints[i]); + PDI->DrawPoint(PointWorld, FColor::Green, 20.f, SDPG_Foreground); + + PDI->SetHitProxy(nullptr); + } + + const FVector Start = + ComponentCasted->GetComponentTransform().TransformPositionNoScale(ComponentCasted->LinePoints[0]); + const FVector End = + ComponentCasted->GetComponentTransform().TransformPositionNoScale(ComponentCasted->LinePoints[1]); + PDI->DrawLine(Start, End, FColor::Green, SDPG_World); + + const float Dist = (End - Start).Size(); + DrawCylinder(PDI, Start, End, ComponentCasted->Radius, 20, &DebugMaterial, 0); + } +} + +void FIntenSelectableCylinderScoringVisualizer::EndEditing() +{ + CurrentCylinderSelectionIndex = INDEX_NONE; + // GetEditedScoringComponent()->MarkRenderStateDirty(); + // GEditor->RedrawLevelEditingViewports(true); +} + +UActorComponent* FIntenSelectableCylinderScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +UIntenSelectableCylinderScoring* FIntenSelectableCylinderScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableCylinderScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableCylinderScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, + FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) +{ + bool bHandled = false; + + UIntenSelectableCylinderScoring* ScoringComponent = GetEditedScoringComponent(); + + if (ScoringComponent) + { + if (CurrentCylinderSelectionIndex != INDEX_NONE) + { + ScoringComponent->Modify(); + + const FVector WorldSelection = ScoringComponent->GetComponentTransform().TransformPositionNoScale( + ScoringComponent->LinePoints[CurrentCylinderSelectionIndex]); + const FVector NewWorldPos = ScoringComponent->GetComponentTransform().InverseTransformPositionNoScale( + WorldSelection + DeltaTranslate); + + ScoringComponent->LinePoints[CurrentCylinderSelectionIndex] += DeltaTranslate; + + // UE_LOG(LogTemp, Warning, TEXT("Component: %s"), + // *(ScoringComponent->LinePoints[CurrentCylinderSelectionIndex]).ToString()); + + + TArray<FProperty*> Properties; + Properties.Add(PointsProperty); + Properties.Add(RadiusProperty); + NotifyPropertiesModified(ScoringComponent, Properties, EPropertyChangeType::ValueSet); + + /* + const FVector Average = (ScoringComponent->LinePoints[0] + ScoringComponent->LinePoints[1]) / 2; + + ScoringComponent->SetWorldLocation(ScoringComponent->GetComponentTransform().TransformPositionNoScale(Average)); + ScoringComponent->LinePoints[0] -= Average; + ScoringComponent->LinePoints[1] -= Average; + + ScoringComponent->MarkRenderStateDirty(); + GEditor->RedrawLevelEditingViewports(true); + + ScoringComponent->PostEditChange(); + GEditor->NoteActorMovement(); + + // If you're modifying an actor's component, it might be a good idea to also mark the actor as modified + ScoringComponent->GetOwner()->Modify(); + ScoringComponent->GetOwner()->PostEditChange(); + + // If the component's package might be unsaved, mark it dirty to ensure changes aren't lost + ScoringComponent->GetOuter()->MarkPackageDirty();*/ + + GEditor->RedrawLevelEditingViewports(true); + + bHandled = true; + } + else + { + // ScoringComponent->AddWorldOffset(DeltaTranslate); + // ScoringComponent->AddWorldRotation(DeltaRotate); + + ScoringComponent->Modify(); + ScoringComponent->MarkRenderStateDirty(); + GEditor->RedrawLevelEditingViewports(true); + + // UE_LOG(LogTemp, Warning, TEXT("Cylinder Selected!")); + + return false; + } + } + + return bHandled; +} + +bool FIntenSelectableCylinderScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (GetEditedComponent() && CurrentCylinderSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableLineScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableLineScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59c8e11f79ec3f58b6588e89439f483a096913b1 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableLineScoringVisualizer.cpp @@ -0,0 +1,187 @@ +#include "Interaction/IntenSelectableLineScoringVisualizer.h" + +#include "ActorEditorUtils.h" +#include "SceneManagement.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h" + +IMPLEMENT_HIT_PROXY(FLinePointProxy, HComponentVisProxy); + +FIntenSelectableLineScoringVisualizer::FIntenSelectableLineScoringVisualizer() +{ + PointsProperty = FindFProperty<FProperty>(UIntenSelectableLineScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableLineScoring, LinePoints)); +} + +FIntenSelectableLineScoringVisualizer::~FIntenSelectableLineScoringVisualizer() {} + +FVector FIntenSelectableLineScoringVisualizer::GetCurrentVectorWorld() const +{ + if (CurrentLineSelectionIndex == INDEX_NONE) + { + return FVector::ZeroVector; + } + else if (CurrentLineSelectionIndex == 2) + { + return GetEditedScoringComponent()->GetComponentLocation(); + } + return GetEditedScoringComponent()->GetComponentTransform().TransformPositionNoScale( + GetEditedScoringComponent()->LinePoints[CurrentLineSelectionIndex]); +} + +bool FIntenSelectableLineScoringVisualizer::IsVisualizingArchetype() const +{ + return (GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner())); +} + +bool FIntenSelectableLineScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableLineScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableLineScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + // UE_LOG(LogTemp, Warning, TEXT("Handling Click")); + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FLinePointProxy::StaticGetType())) + { + const UIntenSelectableLineScoring* T = Cast<const UIntenSelectableLineScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FLinePointProxy* Proxy = (FLinePointProxy*)VisProxy; + CurrentLineSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentLineSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentLineSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableLineScoringVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableLineScoring* ComponentCasted = Cast<UIntenSelectableLineScoring>(Component); + + if (ComponentCasted != nullptr && ComponentCasted->LinePoints.Num() == 2) + { + for (int i = 0; i < ComponentCasted->LinePoints.Num() && i <= 2; i++) + { + PDI->SetHitProxy(new FLinePointProxy(Component, i)); + + FVector PointWorld = + ComponentCasted->GetComponentTransform().TransformPosition(ComponentCasted->LinePoints[i]); + PDI->DrawPoint(PointWorld, FColor::Green, 20.f, SDPG_Foreground); + + PDI->SetHitProxy(nullptr); + } + + PDI->SetHitProxy(new FLinePointProxy(Component, 2)); + + const FVector Start = + ComponentCasted->GetComponentTransform().TransformPosition(ComponentCasted->LinePoints[0]); + const FVector End = ComponentCasted->GetComponentTransform().TransformPosition(ComponentCasted->LinePoints[1]); + PDI->DrawLine(Start, End, FColor::Green, SDPG_Foreground, 3); + + PDI->SetHitProxy(nullptr); + } +} + +void FIntenSelectableLineScoringVisualizer::EndEditing() +{ + GetEditedScoringComponent()->MarkRenderStateDirty(); + GEditor->RedrawLevelEditingViewports(true); +} + +UActorComponent* FIntenSelectableLineScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +UIntenSelectableLineScoring* FIntenSelectableLineScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableLineScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableLineScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, + FVector& DeltaTranslate, FRotator& DeltaRotate, + FVector& DeltaScale) +{ + bool bHandled = false; + + if (CurrentLineSelectionIndex != INDEX_NONE) + { + UIntenSelectableLineScoring* ScoringComponent = GetEditedScoringComponent(); + + if (ScoringComponent->LinePoints.Num() == 2) + { + + if (CurrentLineSelectionIndex == 2) + { + ScoringComponent->AddWorldOffset(DeltaTranslate); + ScoringComponent->AddWorldRotation(DeltaRotate); + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("Current Selection! %s"), *DeltaTranslate.ToString()); + + const FVector WorldSelection = ScoringComponent->GetComponentTransform().TransformPositionNoScale( + GetEditedScoringComponent()->LinePoints[CurrentLineSelectionIndex]); + const FVector NewWorldPos = ScoringComponent->GetComponentTransform().InverseTransformPositionNoScale( + WorldSelection + DeltaTranslate); + ScoringComponent->LinePoints[CurrentLineSelectionIndex] = NewWorldPos; + + const FVector Average = (ScoringComponent->LinePoints[0] + ScoringComponent->LinePoints[1]) / 2; + + ScoringComponent->SetWorldLocation( + ScoringComponent->GetComponentTransform().TransformPositionNoScale(Average)); + ScoringComponent->LinePoints[0] -= Average; + ScoringComponent->LinePoints[1] -= Average; + } + + + TArray<FProperty*> Properties; + Properties.Add(PointsProperty); + NotifyPropertiesModified(ScoringComponent, Properties, EPropertyChangeType::ValueSet); + + ScoringComponent->MarkRenderStateDirty(); + GEditor->RedrawLevelEditingViewports(true); + bHandled = true; + } + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return bHandled; +} + +bool FIntenSelectableLineScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (GetEditedScoringComponent() && CurrentLineSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiPointScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiPointScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd6d48ce19f48b35dfbb3524f3204b4fda59516c --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiPointScoringVisualizer.cpp @@ -0,0 +1,156 @@ +#include "Interaction/IntenSelectableMultiPointScoringVisualizer.h" +#include "ActorEditorUtils.h" +#include "SceneManagement.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h" + +IMPLEMENT_HIT_PROXY(FMultiPointProxy, HComponentVisProxy); + +FIntenSelectableMultiPointScoringVisualizer::FIntenSelectableMultiPointScoringVisualizer() +{ + PointsProperty = + FindFProperty<FProperty>(UIntenSelectableMultiPointScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableMultiPointScoring, PointsToSelect)); +} + +FIntenSelectableMultiPointScoringVisualizer::~FIntenSelectableMultiPointScoringVisualizer() {} + +FVector FIntenSelectableMultiPointScoringVisualizer::GetCurrentVectorWorld() const +{ + if (CurrentSelectionIndex == INDEX_NONE) + { + return FVector::ZeroVector; + } + return GetEditedScoringComponent()->GetComponentTransform().TransformPosition( + GetEditedScoringComponent()->PointsToSelect[CurrentSelectionIndex]); +} + +bool FIntenSelectableMultiPointScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +bool FIntenSelectableMultiPointScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableMultiPointScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableMultiPointScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FMultiPointProxy::StaticGetType())) + { + const UIntenSelectableMultiPointScoring* T = + Cast<const UIntenSelectableMultiPointScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FMultiPointProxy* Proxy = (FMultiPointProxy*)VisProxy; + CurrentSelectionIndex = Proxy->TargetIndex; + // UE_LOG(LogTemp, Warning, TEXT("Handling Click %i"), CurrentSelectionIndex); + } + else + { + CurrentSelectionIndex = INDEX_NONE; + // UE_LOG(LogTemp, Warning, TEXT("Handling Click => no selection")); + } + } + else + { + CurrentSelectionIndex = INDEX_NONE; + // UE_LOG(LogTemp, Warning, TEXT("Handling Click => no selection")); + } + + return bEditing; +} + +void FIntenSelectableMultiPointScoringVisualizer::DrawVisualization(const UActorComponent* Component, + const FSceneView* View, + FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableMultiPointScoring* ComponentCasted = Cast<UIntenSelectableMultiPointScoring>(Component); + + if (ComponentCasted != nullptr) + { + for (int i = 0; i < ComponentCasted->PointsToSelect.Num(); i++) + { + PDI->SetHitProxy(new FMultiPointProxy(Component, i)); + + FVector PointWorld = + ComponentCasted->GetComponentTransform().TransformPosition(ComponentCasted->PointsToSelect[i]); + PDI->DrawPoint(PointWorld, FColor::Green, 20.f, SDPG_Foreground); + + PDI->SetHitProxy(nullptr); + } + } +} + +void FIntenSelectableMultiPointScoringVisualizer::EndEditing() {} + +UActorComponent* FIntenSelectableMultiPointScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +bool FIntenSelectableMultiPointScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, + FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) +{ + bool bHandled = false; + + if (CurrentSelectionIndex != INDEX_NONE) + { + UIntenSelectableMultiPointScoring* ScoringComponent = GetEditedScoringComponent(); + ScoringComponent->Modify(); + + const FVector WorldSelection = ScoringComponent->GetComponentTransform().TransformPosition( + GetEditedScoringComponent()->PointsToSelect[CurrentSelectionIndex]); + const FVector NewWorldPos = + ScoringComponent->GetComponentTransform().InverseTransformPosition(WorldSelection + DeltaTranslate); + ScoringComponent->PointsToSelect[CurrentSelectionIndex] = NewWorldPos; + + // UE_LOG(LogTemp, Warning, TEXT("New Pos: %s"), + // *ScoringComponent->PointsToSelect[CurrentSelectionIndex].ToString()); + + ScoringComponent->MarkRenderStateDirty(); + bHandled = true; + + TArray<FProperty*> Properties; + Properties.Add(PointsProperty); + NotifyPropertiesModified(ScoringComponent, Properties, EPropertyChangeType::ValueSet); + + GEditor->RedrawLevelEditingViewports(false); + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return bHandled; +} + +UIntenSelectableMultiPointScoring* FIntenSelectableMultiPointScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableMultiPointScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableMultiPointScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (GetEditedScoringComponent() && CurrentSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiRectangleScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiRectangleScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8096efefa9a261de88bc6cbc0faf101b7d9bd019 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableMultiRectangleScoringVisualizer.cpp @@ -0,0 +1,271 @@ +#include "ActorEditorUtils.h" +#include "Interaction/IntenSelectableRectangleScoringVisualizer.h" +#include "SceneManagement.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h" + +IMPLEMENT_HIT_PROXY(FRectangleProxy, HComponentVisProxy); + +FIntenSelectableRectangleScoringVisualizer::FIntenSelectableRectangleScoringVisualizer() +{ + XLengthProperty = FindFProperty<FProperty>(UIntenSelectableRectangleScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableRectangleScoring, XLength)); + YLengthProperty = FindFProperty<FProperty>(UIntenSelectableRectangleScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableRectangleScoring, YLength)); +} + +FIntenSelectableRectangleScoringVisualizer::~FIntenSelectableRectangleScoringVisualizer() {} + +bool FIntenSelectableRectangleScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +FVector FIntenSelectableRectangleScoringVisualizer::GetCurrentVectorWorld() const +{ + if (CurrentSelectionIndex == INDEX_NONE) + { + return FVector::ZeroVector; + } + + const FVector X = GetEditedScoringComponent()->GetRightVector() * GetEditedScoringComponent()->XLength; + const FVector Y = GetEditedScoringComponent()->GetUpVector() * GetEditedScoringComponent()->YLength; + + const FVector CornerWorld00 = + GetEditedScoringComponent()->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2); + const FVector CornerWorld10 = CornerWorld00 + X; + const FVector CornerWorld01 = CornerWorld00 + Y; + const FVector CornerWorld11 = CornerWorld00 + X + Y; + + + switch (CurrentSelectionIndex) + { + case 0: + // bottom + return CornerWorld00 + (CornerWorld10 - CornerWorld00) * 0.5; + case 1: + // left + return CornerWorld00 + (CornerWorld01 - CornerWorld00) * 0.5; + case 2: + // top + return CornerWorld01 + (CornerWorld11 - CornerWorld01) * 0.5; + case 3: + // right + return CornerWorld11 + (CornerWorld10 - CornerWorld11) * 0.5; + case 4: + // middle + return CornerWorld00 + ((CornerWorld10 - CornerWorld00) * 0.5) - ((CornerWorld10 - CornerWorld11) * 0.5); + default: + return FVector::ZeroVector; + } +} + +bool FIntenSelectableRectangleScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableRectangleScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableRectangleScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FRectangleProxy::StaticGetType())) + { + const UIntenSelectableRectangleScoring* T = + Cast<const UIntenSelectableRectangleScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FRectangleProxy* Proxy = (FRectangleProxy*)VisProxy; + CurrentSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableRectangleScoringVisualizer::DrawVisualization(const UActorComponent* Component, + const FSceneView* View, FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableRectangleScoring* ComponentCasted = Cast<UIntenSelectableRectangleScoring>(Component); + + if (ComponentCasted != nullptr) + { + const FVector X = ComponentCasted->GetRightVector() * ComponentCasted->XLength; + const FVector Y = ComponentCasted->GetUpVector() * ComponentCasted->YLength; + + const FVector CornerWorld00 = + ComponentCasted->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2); + const FVector CornerWorld10 = CornerWorld00 + X; + const FVector CornerWorld01 = CornerWorld00 + Y; + const FVector CornerWorld11 = CornerWorld00 + X + Y; + + // bottom 0 + PDI->SetHitProxy(new FRectangleProxy(Component, 0)); + PDI->DrawLine(CornerWorld00, CornerWorld10, FColor::Green, SDPG_Foreground, 3); + PDI->SetHitProxy(nullptr); + + // left 1 + PDI->SetHitProxy(new FRectangleProxy(Component, 1)); + PDI->DrawLine(CornerWorld00, CornerWorld01, FColor::Green, SDPG_Foreground, 3); + PDI->SetHitProxy(nullptr); + + // up 2 + PDI->SetHitProxy(new FRectangleProxy(Component, 2)); + PDI->DrawLine(CornerWorld01, CornerWorld11, FColor::Green, SDPG_Foreground, 3); + PDI->SetHitProxy(nullptr); + + + // right 3 + PDI->SetHitProxy(new FRectangleProxy(Component, 3)); + PDI->DrawLine(CornerWorld11, CornerWorld10, FColor::Green, SDPG_Foreground, 3); + PDI->SetHitProxy(nullptr); + + // middle + PDI->SetHitProxy(new FRectangleProxy(Component, 4)); + const FVector Middle = + CornerWorld00 + ((CornerWorld10 - CornerWorld00) * 0.5) - ((CornerWorld10 - CornerWorld11) * 0.5); + PDI->DrawPoint(Middle, FColor::Green, 20, SDPG_Foreground); + PDI->SetHitProxy(nullptr); + } +} + +void FIntenSelectableRectangleScoringVisualizer::EndEditing() { GEditor->RedrawLevelEditingViewports(true); } + +UActorComponent* FIntenSelectableRectangleScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +UIntenSelectableRectangleScoring* FIntenSelectableRectangleScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableRectangleScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableRectangleScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, + FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) +{ + bool bHandled = false; + + if (CurrentSelectionIndex != INDEX_NONE) + { + UIntenSelectableRectangleScoring* ScoringComponent = GetEditedScoringComponent(); + ScoringComponent->Modify(); + + switch (CurrentSelectionIndex) + { + case 0: + // bottom + ScoringComponent->YLength -= DeltaTranslate.Z; + if (ScoringComponent->YLength < 0.1) + { + ScoringComponent->YLength = 0.1; + } + else + { + ScoringComponent->AddLocalOffset(FVector::UpVector * DeltaTranslate.Z / 2); + } + bHandled = true; + break; + case 1: + // left + ScoringComponent->XLength -= DeltaTranslate.Y; + if (ScoringComponent->XLength < 0.1) + { + ScoringComponent->XLength = 0.1; + } + else + { + ScoringComponent->AddLocalOffset(FVector::RightVector * DeltaTranslate.Y / 2); + } + bHandled = true; + break; + case 2: + // top + ScoringComponent->YLength += DeltaTranslate.Z; + if (ScoringComponent->YLength < 0.1) + { + ScoringComponent->YLength = 0.1; + } + else + { + ScoringComponent->AddLocalOffset(FVector::UpVector * DeltaTranslate.Z / 2); + } + bHandled = true; + break; + case 3: + // right + ScoringComponent->XLength += DeltaTranslate.Y; + if (ScoringComponent->XLength < 0.1) + { + ScoringComponent->XLength = 0.1; + } + else + { + ScoringComponent->AddLocalOffset(FVector::RightVector * DeltaTranslate.Y / 2); + } + bHandled = true; + break; + case 4: + { + // middle + const FVector WorldCenter = ScoringComponent->GetComponentLocation(); + const FVector NewWorldCenter = WorldCenter + DeltaTranslate; + ScoringComponent->SetWorldLocation(NewWorldCenter); + ScoringComponent->AddWorldRotation(DeltaRotate); + + const FVector LocalScaleDelta = + ScoringComponent->GetComponentTransform().InverseTransformVector(DeltaScale); + ScoringComponent->XLength += LocalScaleDelta.Y * 4; + ScoringComponent->YLength += LocalScaleDelta.Z * 4; + bHandled = true; + break; + } + default: + bHandled = false; + break; + } + + TArray<FProperty*> Properties; + Properties.Add(XLengthProperty); + Properties.Add(YLengthProperty); + NotifyPropertiesModified(ScoringComponent, Properties, EPropertyChangeType::ValueSet); + + return bHandled; + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return false; +} + +bool FIntenSelectableRectangleScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (CurrentSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableSphereScoringVisualizer.cpp b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableSphereScoringVisualizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34657800ad77a3ee67fffb8124fcbae5dea14a7d --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Private/Interaction/IntenSelectableSphereScoringVisualizer.cpp @@ -0,0 +1,167 @@ +#include "Interaction/IntenSelectableSphereScoringVisualizer.h" + +#include "ActorEditorUtils.h" +#include "SceneManagement.h" +#include "MaterialShared.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h" +#include "Kismet/KismetMathLibrary.h" +#include "Materials/MaterialInstance.h" + +IMPLEMENT_HIT_PROXY(FSphereProxy, HComponentVisProxy); + +FIntenSelectableSphereScoringVisualizer::FIntenSelectableSphereScoringVisualizer() : + DebugMaterial(FColoredMaterialRenderProxy(GEngine->ConstraintLimitMaterial->GetRenderProxy(), FColor::Green)) +{ + PointsProperty = FindFProperty<FProperty>(UIntenSelectableSphereScoring::StaticClass(), + GET_MEMBER_NAME_CHECKED(UIntenSelectableSphereScoring, Radius)); +} + +FIntenSelectableSphereScoringVisualizer::~FIntenSelectableSphereScoringVisualizer() {} + +bool FIntenSelectableSphereScoringVisualizer::IsVisualizingArchetype() const +{ + return GetEditedScoringComponent() && GetEditedScoringComponent()->GetOwner() && + FActorEditorUtils::IsAPreviewOrInactiveActor(GetEditedScoringComponent()->GetOwner()); +} + +FVector FIntenSelectableSphereScoringVisualizer::GetCurrentVectorWorld() const +{ + return GetEditedScoringComponent()->GetComponentLocation(); +} + +bool FIntenSelectableSphereScoringVisualizer::ShowWhenSelected() { return false; } + +bool FIntenSelectableSphereScoringVisualizer::ShouldShowForSelectedSubcomponents(const UActorComponent* Component) +{ + return false; +} + +bool FIntenSelectableSphereScoringVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, + HComponentVisProxy* VisProxy, + const FViewportClick& Click) +{ + bool bEditing = false; + + // UE_LOG(LogTemp, Warning, TEXT("Handling Click")); + + if (VisProxy && VisProxy->Component.IsValid()) + { + bEditing = true; + + if (VisProxy->IsA(FSphereProxy::StaticGetType())) + { + const UIntenSelectableSphereScoring* T = + Cast<const UIntenSelectableSphereScoring>(VisProxy->Component.Get()); + ScoringBehaviourPropertyPath = FComponentPropertyPath(T); + + FSphereProxy* Proxy = (FSphereProxy*)VisProxy; + CurrentSelectionIndex = Proxy->TargetIndex; + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + } + else + { + CurrentSelectionIndex = INDEX_NONE; + } + + return bEditing; +} + +void FIntenSelectableSphereScoringVisualizer::DrawVisualization(const UActorComponent* Component, + const FSceneView* View, FPrimitiveDrawInterface* PDI) +{ + const UIntenSelectableSphereScoring* ComponentCasted = Cast<UIntenSelectableSphereScoring>(Component); + + if (ComponentCasted != nullptr) + { + PDI->SetHitProxy(new FSphereProxy(Component, 0)); + + DrawSphere(PDI, ComponentCasted->GetComponentLocation(), FRotator::ZeroRotator, + FVector::OneVector * ComponentCasted->Radius, 50, 50, &DebugMaterial, 0, false); + + PDI->SetHitProxy(nullptr); + } +} + +void FIntenSelectableSphereScoringVisualizer::EndEditing() {} + +UActorComponent* FIntenSelectableSphereScoringVisualizer::GetEditedComponent() const +{ + return GetEditedScoringComponent(); +} + +UIntenSelectableSphereScoring* FIntenSelectableSphereScoringVisualizer::GetEditedScoringComponent() const +{ + return Cast<UIntenSelectableSphereScoring>(ScoringBehaviourPropertyPath.GetComponent()); +} + +bool FIntenSelectableSphereScoringVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, + FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) +{ + bool bHandled = false; + + if (true || CurrentSelectionIndex != INDEX_NONE) + { + // UE_LOG(LogTemp, Warning, TEXT("Current Selection! %s"), *DeltaTranslate.ToString()); + + if ((true || CurrentSelectionIndex == 0) && GetEditedComponent()) + { + UIntenSelectableSphereScoring* ScoringComponent = GetEditedScoringComponent(); + ScoringComponent->Modify(); + + const FVector LocalCenter = ScoringComponent->GetComponentLocation(); + const FVector NewCenter = LocalCenter + DeltaTranslate; + + ScoringComponent->SetWorldLocation(NewCenter); + ScoringComponent->AddWorldRotation(DeltaRotate); + + const float AverageScaleFactor = (DeltaScale.X + DeltaScale.Y + DeltaScale.Z) / 3.0f; + + // Apply the average scale factor to the original radius + float NewRadius; + if (AverageScaleFactor > 0) + { + // Scale up: Increase the radius + NewRadius = ScoringComponent->Radius * (1.0f + FMath::Abs(AverageScaleFactor)); + } + else + { + // Scale down: Decrease the radius, ensuring not to reduce it below a minimum threshold (e.g., not + // making it negative) + NewRadius = ScoringComponent->Radius * FMath::Max(0.1f, 1.0f + AverageScaleFactor); + } + ScoringComponent->Radius = NewRadius; + + TArray<FProperty*> Properties; + Properties.Add(PointsProperty); + NotifyPropertiesModified(ScoringComponent, Properties, EPropertyChangeType::ValueSet); + + ScoringComponent->MarkRenderStateDirty(); + GEditor->RedrawLevelEditingViewports(false); + bHandled = true; + } + } + else + { + // UE_LOG(LogTemp, Warning, TEXT("No Current Selection!")); + } + + return bHandled; +} + +bool FIntenSelectableSphereScoringVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, + FVector& OutLocation) const +{ + if (CurrentSelectionIndex != INDEX_NONE) + { + OutLocation = GetCurrentVectorWorld(); + + return true; + } + + return false; +} diff --git a/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp b/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp index e53695d2b66804e9131f4dccbd5ec9a2856c6d71..a35e9354035fa20e13cf56e54d92ffe2a54d3c28 100644 --- a/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp +++ b/Source/RWTHVRToolkitEditor/Private/RWTHVRToolkitEditor.cpp @@ -1,14 +1,115 @@ #include "RWTHVRToolkitEditor.h" - #include "UnrealEdGlobals.h" #include "Editor/UnrealEdEngine.h" +#include "Interaction/IntenSelectableCylinderScoringVisualizer.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCircleScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCubeScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableLineScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableMultiPointScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableRectangleScoring.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableSphereScoring.h" + +#include "Interaction/IntenSelectableCircleScoringVisualizer.h" +#include "Interaction/IntenSelectableCubeScoringVisualizer.h" +#include "Interaction/IntenSelectableLineScoringVisualizer.h" +#include "Interaction/IntenSelectableMultiPointScoringVisualizer.h" +#include "Interaction/IntenSelectableRectangleScoringVisualizer.h" +#include "Interaction/IntenSelectableSphereScoringVisualizer.h" IMPLEMENT_GAME_MODULE(FRWTHVRToolkitEditorModule, RWTHVRToolkitEditor); #define LOCTEXT_NAMESPACE "RWTHVRToolkitEditor" -void FRWTHVRToolkitEditorModule::StartupModule() {} +void FRWTHVRToolkitEditorModule::StartupModule() +{ + if (GUnrealEd != nullptr) + { + const TSharedPtr<FComponentVisualizer> IntenSelectableLineVisualizer = + MakeShareable(new FIntenSelectableLineScoringVisualizer()); + + if (IntenSelectableLineVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableLineScoring::StaticClass()->GetFName(), + IntenSelectableLineVisualizer); + IntenSelectableLineVisualizer->OnRegister(); + } + + + const TSharedPtr<FComponentVisualizer> IntenSelectableMultipointScoringVisualizer = + MakeShareable(new FIntenSelectableMultiPointScoringVisualizer()); + + if (IntenSelectableMultipointScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableMultiPointScoring::StaticClass()->GetFName(), + IntenSelectableMultipointScoringVisualizer); + IntenSelectableMultipointScoringVisualizer->OnRegister(); + } + + const TSharedPtr<FComponentVisualizer> IntenSelectableCircleScoringVisualizer = + MakeShareable(new FIntenSelectableCircleScoringVisualizer()); + + if (IntenSelectableCircleScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableCircleScoring::StaticClass()->GetFName(), + IntenSelectableCircleScoringVisualizer); + IntenSelectableCircleScoringVisualizer->OnRegister(); + } + + const TSharedPtr<FComponentVisualizer> IntenSelectableRectangleScoringVisualizer = + MakeShareable(new FIntenSelectableRectangleScoringVisualizer()); + + if (IntenSelectableRectangleScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableRectangleScoring::StaticClass()->GetFName(), + IntenSelectableRectangleScoringVisualizer); + IntenSelectableRectangleScoringVisualizer->OnRegister(); + } + + const TSharedPtr<FComponentVisualizer> IntenSelectableSphereScoringVisualizer = + MakeShareable(new FIntenSelectableSphereScoringVisualizer()); + + if (IntenSelectableSphereScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableSphereScoring::StaticClass()->GetFName(), + IntenSelectableSphereScoringVisualizer); + IntenSelectableSphereScoringVisualizer->OnRegister(); + } + + const TSharedPtr<FComponentVisualizer> IntenSelectableCubeScoringVisualizer = + MakeShareable(new FIntenSelectableCubeScoringVisualizer()); + + if (IntenSelectableCubeScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableCubeScoring::StaticClass()->GetFName(), + IntenSelectableCubeScoringVisualizer); + IntenSelectableCubeScoringVisualizer->OnRegister(); + } + + const TSharedPtr<FComponentVisualizer> IntenSelectableCylinderScoringVisualizer = + MakeShareable(new FIntenSelectableCylinderScoringVisualizer()); + + if (IntenSelectableCylinderScoringVisualizer.IsValid()) + { + GUnrealEd->RegisterComponentVisualizer(UIntenSelectableCylinderScoring::StaticClass()->GetFName(), + IntenSelectableCylinderScoringVisualizer); + IntenSelectableCylinderScoringVisualizer->OnRegister(); + } + } +} -void FRWTHVRToolkitEditorModule::ShutdownModule() {} +void FRWTHVRToolkitEditorModule::ShutdownModule() +{ + if (GUnrealEd != nullptr) + { + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableLineScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableMultiPointScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableCircleScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableRectangleScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableSphereScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableCubeScoring::StaticClass()->GetFName()); + GUnrealEd->UnregisterComponentVisualizer(UIntenSelectableCylinderScoring::StaticClass()->GetFName()); + } +} -#undef LOCTEXT_NAMESPACE +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCircleScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCircleScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..42880d84730f4166abedc015739d26369303bef2 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCircleScoringVisualizer.h @@ -0,0 +1,54 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +class UIntenSelectableCircleScoring; +/** + * + */ +class FPrimitiveDrawInterface; +class FSceneView; + +struct FCircleProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FCircleProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableCircleScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentSelectionIndex; + FProperty* PointsProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableCircleScoringVisualizer(); + ~FIntenSelectableCircleScoringVisualizer(); + + FVector GetCurrentVectorWorld() const; + + virtual bool IsVisualizingArchetype() const override; + UIntenSelectableCircleScoring* GetEditedScoringComponent() const; + + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + virtual void EndEditing() override; + virtual UActorComponent* GetEditedComponent() const override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCubeScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCubeScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..6ffffcfbdeaa5eed9e91261ee3ec94b9938928a1 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCubeScoringVisualizer.h @@ -0,0 +1,53 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +#include "Materials/MaterialRenderProxy.h" + +class UIntenSelectableCubeScoring; +class FPrimitiveDrawInterface; +class FSceneView; + +struct FCubeProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FCubeProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableCubeScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentSelectionIndex; + + FColoredMaterialRenderProxy DebugMaterial; + FProperty* PointsProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableCubeScoringVisualizer(); + ~FIntenSelectableCubeScoringVisualizer(); + + FVector GetCurrentVectorWorld() const; + + virtual bool IsVisualizingArchetype() const override; + UIntenSelectableCubeScoring* GetEditedScoringComponent() const; + + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + virtual void EndEditing() override; + virtual UActorComponent* GetEditedComponent() const override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCylinderScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCylinderScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..6e796151b1e75a07b186e71bfbb70aec56ecfa51 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableCylinderScoringVisualizer.h @@ -0,0 +1,78 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +#include "Interaction/Interactables/IntenSelect/IntenSelectableCylinderScoring.h" +#include "Materials/MaterialRenderProxy.h" + +class UIntenSelectableLineScoring; +class FPrimitiveDrawInterface; +class FSceneView; + +/**Base class for clickable targeting editing proxies*/ +struct HTargetingVisProxy : public HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + HTargetingVisProxy(const UActorComponent* InComponent) : HComponentVisProxy(InComponent, HPP_Wireframe) {} +}; + +/**Proxy for target*/ +struct HTargetProxy : public HTargetingVisProxy +{ + DECLARE_HIT_PROXY(); + + HTargetProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HTargetingVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + +struct FCylinderPointProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FCylinderPointProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableCylinderScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentCylinderSelectionIndex; + FColoredMaterialRenderProxy DebugMaterial; + FProperty* RadiusProperty; + FProperty* PointsProperty; + FProperty* LocationProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableCylinderScoringVisualizer(); + ~FIntenSelectableCylinderScoringVisualizer(); + + virtual bool IsVisualizingArchetype() const override; + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + + FVector GetCurrentVectorWorld() const; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; + + virtual UActorComponent* GetEditedComponent() const override; + UIntenSelectableCylinderScoring* GetEditedScoringComponent() const; + + virtual void EndEditing() override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableLineScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableLineScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..1bb024784e513db19713c1f4df74f430c56792a7 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableLineScoringVisualizer.h @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +class UIntenSelectableLineScoring; +/** + * + */ +class FPrimitiveDrawInterface; +class FSceneView; + +struct FLinePointProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FLinePointProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableLineScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentLineSelectionIndex; + FProperty* PointsProperty; + UIntenSelectableLineScoring* LineBehavior; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableLineScoringVisualizer(); + ~FIntenSelectableLineScoringVisualizer(); + + FVector GetCurrentVectorWorld() const; + + virtual bool IsVisualizingArchetype() const override; + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; + virtual UActorComponent* GetEditedComponent() const override; + UIntenSelectableLineScoring* GetEditedScoringComponent() const; + + virtual void EndEditing() override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableMultiPointScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableMultiPointScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..c46253283484cdcffee3bc49c15dda61a4a1190a --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableMultiPointScoringVisualizer.h @@ -0,0 +1,52 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" + +class UIntenSelectableMultiPointScoring; +class FPrimitiveDrawInterface; +class FSceneView; + +struct FMultiPointProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FMultiPointProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableMultiPointScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentSelectionIndex; + FProperty* PointsProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableMultiPointScoringVisualizer(); + ~FIntenSelectableMultiPointScoringVisualizer(); + + virtual bool IsVisualizingArchetype() const override; + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + + FVector GetCurrentVectorWorld() const; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; + + virtual UActorComponent* GetEditedComponent() const override; + UIntenSelectableMultiPointScoring* GetEditedScoringComponent() const; + + virtual void EndEditing() override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableRectangleScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableRectangleScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..983c87788e609d99950e365a457bee455d97cdd6 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableRectangleScoringVisualizer.h @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +class UIntenSelectableRectangleScoring; +/** + * + */ +class FPrimitiveDrawInterface; +class FSceneView; + +struct FRectangleProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FRectangleProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableRectangleScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentSelectionIndex; + FProperty* XLengthProperty; + FProperty* YLengthProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableRectangleScoringVisualizer(); + ~FIntenSelectableRectangleScoringVisualizer(); + + virtual bool IsVisualizingArchetype() const override; + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + + FVector GetCurrentVectorWorld() const; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; + + virtual UActorComponent* GetEditedComponent() const override; + UIntenSelectableRectangleScoring* GetEditedScoringComponent() const; + + virtual void EndEditing() override; +}; diff --git a/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableSphereScoringVisualizer.h b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableSphereScoringVisualizer.h new file mode 100644 index 0000000000000000000000000000000000000000..40e41d1707d63ac812e5e47b6665f43190a4a030 --- /dev/null +++ b/Source/RWTHVRToolkitEditor/Public/Interaction/IntenSelectableSphereScoringVisualizer.h @@ -0,0 +1,55 @@ +#pragma once + +#include "CoreMinimal.h" +#include "ComponentVisualizer.h" +#include "Materials/MaterialRenderProxy.h" + +class UIntenSelectableSphereScoring; +class FPrimitiveDrawInterface; +class FSceneView; + +struct FSphereProxy : HComponentVisProxy +{ + DECLARE_HIT_PROXY(); + + FSphereProxy(const UActorComponent* InComponent, int32 InTargetIndex) : + HComponentVisProxy(InComponent), TargetIndex(InTargetIndex) + { + } + + int32 TargetIndex; +}; + + +class RWTHVRTOOLKITEDITOR_API FIntenSelectableSphereScoringVisualizer : public FComponentVisualizer +{ +private: + int CurrentSelectionIndex; + FColoredMaterialRenderProxy DebugMaterial; + FProperty* PointsProperty; + FComponentPropertyPath ScoringBehaviourPropertyPath; + +public: + FIntenSelectableSphereScoringVisualizer(); + ~FIntenSelectableSphereScoringVisualizer(); + + + virtual bool IsVisualizingArchetype() const override; + virtual bool ShowWhenSelected() override; + virtual bool ShouldShowForSelectedSubcomponents(const UActorComponent* Component) override; + + virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, + const FViewportClick& Click) override; + virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, + FPrimitiveDrawInterface* PDI) override; + virtual bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, + FRotator& DeltaRotate, FVector& DeltaScale) override; + + virtual UActorComponent* GetEditedComponent() const override; + UIntenSelectableSphereScoring* GetEditedScoringComponent() const; + + FVector GetCurrentVectorWorld() const; + virtual bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override; + + virtual void EndEditing() override; +};