diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 798c4c4355db910eea9185312727d7253dbcb542..506e29189f52fd71b16e128653e04092b06de27d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,8 @@ 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" @@ -130,12 +132,14 @@ Build_Linux: - job: "Generate_Project" artifacts: true -Build_Linux_Without_Cluster: + +# Builds for linux without the cluster pluginBuild_Linux_Without_Cluster: extends: Build_Linux needs: - job: "Generate_Project_Without_Cluster" artifacts: true +# Deploys to vrdev Deploy_Windows: rules: - if: $CI_PIPELINE_SOURCE == "web" @@ -145,6 +149,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/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..777321ddbb5e3586fe3bb2132495977c4798417e 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..9a06001e6ecb2c86136df84977087b4713bb6b70 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 7eed29647f76056e5a3dc778cb24273cfafae8ad..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/BP_GrabComponent.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 3f54fd0dfe08390ecbcfa2a9c48bf391f5b6de69..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 2ed1023f48272c1eb2b8a621788c6e83723c344f..0000000000000000000000000000000000000000 Binary files a/Content/Components/Grabbing/IA_GrabRight.uasset and /dev/null differ diff --git a/Content/Components/Movement/IA_Move.uasset b/Content/Components/Movement/IA_Move.uasset index 7bf4d3cd0a05eeeb8b9aa02f350ab9fcc682ae52..3bc9a527ec86673e8f8e988f755708a4f1ba6dbc 100644 Binary files a/Content/Components/Movement/IA_Move.uasset and b/Content/Components/Movement/IA_Move.uasset differ diff --git a/Content/Components/Movement/IA_MoveUp.uasset b/Content/Components/Movement/IA_MoveUp.uasset index f7bbb39f3acad97936a42f6f25f3617c66b55318..a85002e5cc20b787cc6930a835affdf9b0e0302e 100644 Binary files a/Content/Components/Movement/IA_MoveUp.uasset and b/Content/Components/Movement/IA_MoveUp.uasset differ diff --git a/Content/Components/Movement/Turn/IA_DesktopRotation.uasset b/Content/Components/Movement/Turn/IA_DesktopRotation.uasset index e6914976fcea9e1344011c1964c0d4ab5b1b253e..9a780d7a9679fdf2a68a1fca575200140e057a73 100644 Binary files a/Content/Components/Movement/Turn/IA_DesktopRotation.uasset and b/Content/Components/Movement/Turn/IA_DesktopRotation.uasset differ diff --git a/Content/Components/Movement/Turn/IA_Turn.uasset b/Content/Components/Movement/Turn/IA_Turn.uasset index ad57154a7d3dc116f1d77aab7f7880a308170504..eb14d702537bd15f6d2e6ae3badcd935bc4126c0 100644 Binary files a/Content/Components/Movement/Turn/IA_Turn.uasset and b/Content/Components/Movement/Turn/IA_Turn.uasset differ diff --git a/Content/Components/Raycast/BP_RaycastSelectionComponent.uasset b/Content/Components/Raycast/BP_RaycastSelectionComponent.uasset deleted file mode 100644 index d9aefe54fa14a1c85bd368f83a6891bc214baa4d..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 fd2f5223badfaeff7375cb8fc824bdff2dc54530..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 22b37d92edb64871071257de46a99cfa9df19f41..0000000000000000000000000000000000000000 Binary files a/Content/Components/Raycast/IA_RaycastSelectRight.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..d97225cf998fc828f5d8d4b0d75efa45c9107e4a 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..3b8c855173d49cb285e76e7167012ac521b594c7 Binary files /dev/null and b/Content/Components/RaycastInteraction/IA_RaycastInteractionRight.uasset differ diff --git a/Content/Components/WidgetInteraction/IA_WidgetClick.uasset b/Content/Components/WidgetInteraction/IA_WidgetClick.uasset index 56b77a57f41451865903267d5d9875960996e1db..470e02e6edeec5b128dd66f602fc5680e3fb9dbe 100644 Binary files a/Content/Components/WidgetInteraction/IA_WidgetClick.uasset and b/Content/Components/WidgetInteraction/IA_WidgetClick.uasset 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/TestContent/BP_GrabbableTestObject.uasset b/Content/Examples/ContentExamples/DemoAssets/BP_GrabbableTestObject.uasset similarity index 73% rename from Content/TestContent/BP_GrabbableTestObject.uasset rename to Content/Examples/ContentExamples/DemoAssets/BP_GrabbableTestObject.uasset index 82bdd72c12940a1996273946b7c7de3a0a2d5125..00436a8ef34d22cb949180832fb6717255ed1c98 100644 Binary files a/Content/TestContent/BP_GrabbableTestObject.uasset 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 index 8de5bc1e14890320eb9d9781c7f5c683ee22b42f..cc0bd4ea6d18ace71a9ae2a0b53af84f42689540 100644 Binary files a/Content/Input/Default_IMC/IMC_General.uasset 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 index 0f7b20de8195f512a52c942cce354d1d5539149e..1be9e555bfd0713434a650308d6892ad2e0b7204 100644 Binary files a/Content/Input/Default_IMC/IMC_MovementLeftHand.uasset 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 index 95b5df42372d7c15d12716c51ea4aab4a69b5ba7..4b8151454c391850d9a45ed68fce7babc360c10d 100644 Binary files a/Content/Input/Default_IMC/IMC_MovementRightHand.uasset 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..a6f1bea361671c714db945ffff629342cb6f104d 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 index 9c343e66bc3f56b53758efe957b5156a818efc73..6171681e8ed6e3a4eae1879d475dac62e33c4c99 100644 Binary files a/Content/Pawn/BP_RWTHVRPawn_Default.uasset and b/Content/Pawn/BP_RWTHVRPawn_Default.uasset differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/IA_ToggleOverlay.uasset b/Content/RWTHVRCluster/CAVEOverlay/IA_ToggleOverlay.uasset new file mode 100644 index 0000000000000000000000000000000000000000..77af01f0b1f00c791d5b4baf06ac3136355776fe Binary files /dev/null and b/Content/RWTHVRCluster/CAVEOverlay/IA_ToggleOverlay.uasset differ diff --git a/Content/TestContent/TestMap.umap b/Content/TestContent/TestMap.umap deleted file mode 100644 index cc2ea71d4215b96055b6a5acfde5c18285a21fc6..0000000000000000000000000000000000000000 Binary files a/Content/TestContent/TestMap.umap and /dev/null differ diff --git a/README.md b/README.md index 5bf9cb5d5ba5063753341a7f47a37c0853287d34..04552d2fc64b72f062ac763a4c1685cd825e3506 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,7 @@ The **RWTH VR Toolkit** contains a collection of extensions which are used in ma The contents of this plugin are constantly extended and improved to reflect changes in the Unreal nDisplay Plugin that we use to support our aixCAVE with Unreal. [Check out the repository's wiki page for installation, usage and documentation](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit/-/wikis/home). + +## Citation + +If you need to reference the toolkit in your scientific work, please use https://zenodo.org/records/10817754 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..9352bc3f8e0c1e734579c94bf7326175af7089f3 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp @@ -0,0 +1,136 @@ +// 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(ScoringBehaviours.Num() > 0, TEXT("%s"), *GetOwner()->GetName()); + + float MaxScore = -1; + FHitResult MaxResult; + + for (UIntenSelectableScoring* s : ScoringBehaviours) + { + const TPair<FHitResult, float> Score_Pair = s->GetBestPointScorePair( + ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, LastValue, DeltaTime); + + if (Score_Pair.Value >= MaxScore) + { + MaxResult = Score_Pair.Key; + MaxScore = Score_Pair.Value; + } + } + return TPair<FHitResult, float>{MaxResult, MaxScore}; +} + +void UIntenSelectable::BeginPlay() +{ + Super::BeginPlay(); + + TInlineComponentArray<UIntenSelectable*> AttachedIntenSelectables; + GetOwner()->GetComponents(AttachedIntenSelectables, false); + + if (AttachedIntenSelectables.Num() > 1) + { + if (ScoringBehaviours.Num() == 0) + { + ShowErrorAndQuit( + "Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!"); + } + } + else + { + InitDefaultBehaviourReferences(); + } +} + +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 + + for (TSet<UActorComponent*> AllComponents = GetOwner()->GetComponents(); UActorComponent * c : AllComponents) + { + if (UIntenSelectableScoring* TryToGetScoring = Cast<UIntenSelectableScoring>(c)) + { + ScoringBehaviours.Add(TryToGetScoring); + } + } + + if (ScoringBehaviours.Num() == 0) + { + const auto InitScoringBehaviour = NewObject<UIntenSelectableSinglePointScoring>( + this, UIntenSelectableSinglePointScoring::StaticClass(), "Default Scoring"); + InitScoringBehaviour->SetWorldLocation(GetOwner()->GetActorLocation()); + InitScoringBehaviour->AttachToComponent(GetOwner()->GetRootComponent(), + FAttachmentTransformRules::SnapToTargetNotIncludingScale); + + ScoringBehaviours.Add(InitScoringBehaviour); + } + + // 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); +} 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 7429a615013b4fa35b77171cb82e58ff9e738075..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactors/GrabComponent.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 -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<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 = SearchForInteractable(HitActor); - if (Grabbable && Grabbable->HasInteractionTypeFlag(EInteractorType::Grab) && Grabbable->IsInteractable) - { - Grabbable->HitResult = Hit; - CurrentGrabCompsInRange.AddUnique(Grabbable); - } - } - } - - CurrentGrabBehavioursInRange = CurrentGrabCompsInRange; - - // Call hover start events on all components that were not in range before - for (UInteractableComponent* CurrentGrabbable : CurrentGrabCompsInRange) - { - if (!PreviousGrabBehavioursInRange.Contains(CurrentGrabbable)) - { - PreviousGrabBehavioursInRange.AddUnique(CurrentGrabbable); - CurrentGrabbable->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 : PreviousGrabBehavioursInRange) - { - if (!CurrentGrabCompsInRange.Contains(PrevGrabbale)) - { - ComponentsToRemove.AddUnique(PrevGrabbale); - PrevGrabbale->HandleOnHoverEndEvents(this, EInteractorType::Grab); - } - } - - for (UInteractableComponent* CompToRemove : ComponentsToRemove) - { - PreviousGrabBehavioursInRange.Remove(CompToRemove); - } -} - -void UGrabComponent::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(GrabInputAction, ETriggerEvent::Started, this, &UGrabComponent::OnBeginGrab); - EI->BindAction(GrabInputAction, ETriggerEvent::Completed, this, &UGrabComponent::OnEndGrab); -} - -void UGrabComponent::OnBeginGrab(const FInputActionValue& Value) -{ - const FVector GrabLocation = GetAttachParent()->GetComponentLocation(); - - if (CurrentGrabBehavioursInRange.IsEmpty()) - return; - - if (bOnlyGrabClosestActor) - { - auto MinElement = *Algo::MinElementBy( - CurrentGrabBehavioursInRange, - [&](auto Element) { return FVector(Element->GetOwner()->GetActorLocation() - GrabLocation).Size(); }); - MinElement->HandleOnActionStartEvents(this, GrabInputAction, Value, EInteractorType::Grab); - CurrentlyGrabbedComponents = {MinElement}; - } - else - { - CurrentlyGrabbedComponents.Reserve(CurrentlyGrabbedComponents.Num() + CurrentGrabBehavioursInRange.Num()); - for (UInteractableComponent* Grabbable : CurrentGrabBehavioursInRange) - { - Grabbable->HandleOnActionStartEvents(this, GrabInputAction, Value, EInteractorType::Grab); - CurrentlyGrabbedComponents.Add(Grabbable); - } - } -} - -void UGrabComponent::OnEndGrab(const FInputActionValue& Value) -{ - for (auto& Component : CurrentlyGrabbedComponents) - { - if (Component.IsValid()) - { - Component->HandleOnActionEndEvents(this, GrabInputAction, Value, EInteractorType::Grab); - } - } -} - -UInteractableComponent* UGrabComponent::SearchForInteractable(AActor* HitActor) -{ - UInteractableComponent* Grabbable = nullptr; - if (!HitActor) - { - UE_LOGFMT(Toolkit, Warning, "UGrabComponent::SearchForInteractable: HitActor was nullptr, returning nullptr"); - return nullptr; - } - - if (HitActor->IsChildActor()) - { - // search for UInteractable upwards from hit geometry and return first one found - Grabbable = HitActor->FindComponentByClass<UInteractableComponent>(); - // if Grabbable is not valid search at parent - if (!Grabbable) - { - HitActor = HitActor->GetParentActor(); - if (HitActor) - { - bSearchAtParent = true; - return SearchForInteractable(HitActor); - } - } - } - else if (!HitActor->IsChildActor()) - { - Grabbable = HitActor->FindComponentByClass<UInteractableComponent>(); - } - - if (Grabbable) - { - // in the case, were we had to iterate up the hierarchy, check if we are allowed - // to grab the parent via child geometry - if (bSearchAtParent && !Grabbable->bAllowInteractionFromChildGeometry) - { - Grabbable = nullptr; - } - } - bSearchAtParent = false; - return Grabbable; -} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp index 020ae40bff8e17f164d2e7d895ae5860aab93de9..3a87de65d2cb52a5bce0dd0aa71af9dd3b2f69bb 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RWTHVRWidgetInteractionComponent.cpp @@ -4,7 +4,7 @@ #include "Interaction/Interactors/RWTHVRWidgetInteractionComponent.h" #include "EnhancedInputComponent.h" -#include "Interaction/Interactors/GrabComponent.h" +#include "Interaction/Interactors/DirectInteractionComponent.h" #include "Logging/StructuredLog.h" #include "Misc/Optional.h" #include "Utility/RWTHVRUtilities.h" diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp similarity index 60% rename from Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp rename to Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp index e10a44b0053726512f1ed80e98e853e411675377..94afba4b4426fe1b861d787826f0e1cc11d6583b 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastInteractionComponent.cpp @@ -1,14 +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 "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. @@ -18,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; @@ -40,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) { @@ -61,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); @@ -85,6 +85,8 @@ void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputCo 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/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 988d1618a5ec3a80c6016c027bf0c3b89aeaaa0b..fa07db5dd9dd15f582728d56ccbd7bff5b81eaf3 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/Navigation/ContinuousMovementComponent.cpp @@ -7,6 +7,7 @@ #include "GameFramework/PlayerController.h" #include "Utility/RWTHVRUtilities.h" #include "MotionControllerComponent.h" +#include "Camera/CameraComponent.h" void UContinuousMovementComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) { diff --git a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp index ea27c0ebab4a765daf2055bad92d6b68bb9211ea..9801f83893cb31dec6b04d71c4f26e3696c2234b 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp @@ -104,6 +104,8 @@ void ARWTHVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen { Super::SetupPlayerInputComponent(PlayerInputComponent); + ActivePlayerInputComponent = PlayerInputComponent; + APlayerController* PlayerController = Cast<APlayerController>(GetController()); if (!PlayerController) { @@ -156,6 +158,9 @@ void ARWTHVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen } } +UInputComponent* ARWTHVRPawn::GetPlayerInputComponent() { return ActivePlayerInputComponent; } + + void ARWTHVRPawn::AddInputMappingContext(const APlayerController* PC, const UInputMappingContext* Context) const { if (Context) 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..45e6a7726227e26c299399ba733a143909ae32b7 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/IntenSelect/IntenSelectable.h @@ -0,0 +1,55 @@ +// 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 "Interaction/Interactables/ActionBehaviour.h" +#include "Interaction/Interactables/HoverBehaviour.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) + TArray<UIntenSelectableScoring*> ScoringBehaviours; + + 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/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 4e18d911a41ad79fbcb4cf4d6d1e914d11f74b5f..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h +++ /dev/null @@ -1,60 +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(EditAnywhere, Category = "Input") - class UInputAction* GrabInputAction; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - float GrabSphereRadius = 15.0; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - bool bShowDebugTrace = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - bool bOnlyGrabClosestActor = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grabbing") - TArray<AActor*> ActorsToIgnore; - - virtual void SetupPlayerInput(UInputComponent* PlayerInputComponent) override; - -private: - UFUNCTION() - void OnBeginGrab(const FInputActionValue& Value); - - UFUNCTION() - void OnEndGrab(const FInputActionValue& Value); - - UPROPERTY() - TArray<UInteractableComponent*> PreviousGrabBehavioursInRange; - - UPROPERTY() - TArray<UInteractableComponent*> CurrentGrabBehavioursInRange; - - TArray<TWeakObjectPtr<UInteractableComponent>> CurrentlyGrabbedComponents; - - UInteractableComponent* SearchForInteractable(AActor* HitActor); - - bool bSearchAtParent = false; -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h similarity index 70% rename from Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h rename to Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h index b77f9ca80f6b66bdce3d47771bfab14d9daa39b8..f5c93123e8ba136e747796825f93309b285109b0 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastInteractionComponent.h @@ -6,24 +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(EditAnywhere, Category = "Input") - class UInputAction* RayCastSelectInputAction; + class UInputAction* InteractionInputAction; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Raycast") float TraceLength = 3000.0; @@ -32,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/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/MovementComponentBase.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h index f9d03b513f1e7f1c4da813240436982063f9ab24..ef8548c76182a54a42dca18a62291347b5bbf626 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/MovementComponentBase.h @@ -19,6 +19,7 @@ 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: diff --git a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h index 5b67bd31bd46e4187a17f1849187df5aae059beb..abe9255dd701b20595c5ee56caff2702f1d60a36 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h +++ b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h @@ -87,6 +87,9 @@ 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; @@ -109,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; +};