/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ #pragma once #include "Components/ActorComponent.h" #include "LeapWrapper.h" #include "UltraleapTrackingData.h" #include "IUltraleapTrackingPlugin.h" #if WITH_EDITOR #include "DetailLayoutBuilder.h" #endif #include "LeapComponent.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE(FLeapEventSignature); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapDeviceSignature, FString, DeviceName); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapVisibilityBoolSignature, bool, bIsVisible); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapFrameSignature, const FLeapFrameData&, Frame); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapHandSignature, const FLeapHandData&, Hand); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapPolicySignature, TArray>, Flags); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FLeapImageEventSignature, UTexture2D*, Texture, ELeapImageType, ImageType); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLeapTrackingModeSignature, ELeapMode, Flag); UCLASS(ClassGroup = "Input Controller", meta = (BlueprintSpawnableComponent)) class ULTRALEAPTRACKING_API ULeapComponent : public UActorComponent, public ILeapConnectorCallbacks { GENERATED_UCLASS_BODY() public: ~ULeapComponent(); /** Called when a device connects to the leap service, this may happen before the game starts and you may not get the call*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapDeviceSignature OnLeapDeviceAttached; /** Called when a device disconnects from the leap service*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapDeviceSignature OnLeapDeviceDetached; /** Event called when new tracking data is available, typically every game tick. */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapFrameSignature OnLeapTrackingData; /** Event called when a leap hand grab gesture is detected */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandGrabbed; /** Event called when a leap hand release gesture is detected */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandReleased; /** Event called when a leap hand pinch gesture is detected */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandPinched; /** Event called when a leap hand unpinch gesture is detected */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandUnpinched; /** Event called when a leap hand enters the field of view and begins tracking */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandBeginTracking; /** Event called when a leap hand exits the field of view and stops tracking */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapHandSignature OnHandEndTracking; /** Event called when the left hand tracking changes*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapVisibilityBoolSignature OnLeftHandVisibilityChanged; /** Event called when the right hand begins tracking */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapVisibilityBoolSignature OnRightHandVisibilityChanged; /** Event called when leap policies have changed */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapPolicySignature OnLeapPoliciesUpdated; /** Event called when a device image is ready. Requires setting image policy first*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapImageEventSignature OnImageEvent; /** Event called when the leap service connects. Will likely be called before game begin play so some component won't receive * this call.*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapEventSignature OnLeapServiceConnected; /** Event called if leap service connection gets lost. Track won't work if this event gets called.*/ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapEventSignature OnLeapServiceDisconnected; /** Tracking mode optimization */ UPROPERTY(BlueprintReadOnly, Category = "Leap Properties") TEnumAsByte TrackingMode; /** Event called when leap policies have changed */ UPROPERTY(BlueprintAssignable, Category = "Leap Events") FLeapTrackingModeSignature OnLeapTrackingModeUpdated; // By default in vr mode the first/primary device has this set to true UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Leap Properties") bool bAddHmdOrigin; UFUNCTION(BlueprintCallable, Category = "Leap Functions") void SetShouldAddHmdOrigin(bool& bShouldAdd); /** Utility function to check if a hand is visible and tracked at this moment */ UFUNCTION(BlueprintCallable, Category = "Leap Functions") void AreHandsVisible(bool& LeftIsVisible, bool& RightIsVisible); /** Polling function to get latest data */ UFUNCTION(BlueprintCallable, Category = "Leap Functions") void GetLatestFrameData(FLeapFrameData& OutData, const bool ApplyDeviceOrigin = false); UFUNCTION(BlueprintCallable, Category = "Leap Functions") void SetSwizzles(ELeapQuatSwizzleAxisB ToX, ELeapQuatSwizzleAxisB ToY, ELeapQuatSwizzleAxisB ToZ, ELeapQuatSwizzleAxisB ToW); UFUNCTION(BlueprintCallable, Category = "Leap Functions") void SetTrackingMode(ELeapMode Mode); UFUNCTION(BlueprintCallable, Category = "Leap Functions") void SetLeapPolicy(ELeapPolicyFlag Flag, bool Enable); UFUNCTION(BlueprintCallable, Category = "Leap Functions") bool GetLeapOptions(FLeapOptions& Options); /** * Get the hand size, by default it will get the left hand size * In this method that we measure the middle finger length + palm position * to start of finger as an indication of the hand size * @param OutHandSize - returns the hand size */ UFUNCTION(BlueprintCallable, Category = "Leap Functions") void GetHandSize(float& OutHandSize); /** * Get the grab strength for both hands * @param GrabStrength - returns the grab strength as an array * Index 0 of the array is for the left hand * Index 1 of the array is for the right hand */ UFUNCTION(BlueprintCallable, Category = "Leap Functions") void GetLRGrabStrength(TArray &GrabStrength); /** * Checks if the hand type can grab, but checking the pinch or grab strength * @param GrabStrength - the grab strength * @param Type - the hand type * @return bool, if we can grab with this hand type (left or right) */ UFUNCTION(BlueprintCallable, Category = "Leap Functions") bool DoesCurrentGrabStrengthExceedTarget(const float GrabStrength, uint8 TargetHand); /** Multidevice configuration, Singular subscribes to a single device. Combined subscribes to multiple devices combined into one device */ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Leap Devices", meta = ( EditCondition = "DisableEditMultiDeviceMode == false")) TEnumAsByte MultiDeviceMode; /** Available device list */ UPROPERTY(BlueprintReadOnly, Category = "Leap Devices") TArray AvailableDeviceSerials; /** Active Device (Singular mode only) */ UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Leap Devices", meta = (GetOptions = "GetSerialOptions", EditCondition = "MultiDeviceMode == ELeapMultiDeviceMode::LEAP_MULTI_DEVICE_SINGULAR")) FString ActiveDeviceSerial; UFUNCTION(CallInEditor) TArray GetSerialOptions() const { TArray Ret(AvailableDeviceSerials); Ret.Insert(NameConstantNone, 0); return Ret; } /** Combined device list */ UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Leap Devices", meta = (GetOptions = "GetSerialOptions", EditCondition = "MultiDeviceMode == ELeapMultiDeviceMode::LEAP_MULTI_DEVICE_COMBINED")) TArray CombinedDeviceSerials; UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Leap Devices", meta = (GetOptions = "GetSerialOptions" , EditCondition = "MultiDeviceMode == ELeapMultiDeviceMode::LEAP_MULTI_DEVICE_COMBINED")) TEnumAsByte DeviceCombinerClass; UFUNCTION(CallInEditor, BlueprintCallable, Category = "Leap Devices") ELeapDeviceType GetDeviceTypeFromSerial(const FString& DeviceSerial); UFUNCTION(CallInEditor, BlueprintCallable, Category = "Leap Devices") void UpdateDeviceOrigin(const FTransform& DeviceOriginIn); // Setup multidevice programmatically in one call UFUNCTION(CallInEditor, BlueprintCallable, Category = "Leap Devices") void SetupMultidevice( const TArray& DeviceSerials, const ELeapMultiDeviceMode MultiDeviceModeIn, const ELeapDeviceCombinerClass CombinerClass); /** Disable/Grey out setting the multidevice mode.*/ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Leap Devices") bool DisableEditMultiDeviceMode; #if WITH_EDITOR // property change handlers virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; void SetCustomDetailsPanel(IDetailLayoutBuilder* DetailBuilder); #endif // ILeapConnectorCallbacks implementation virtual void OnDeviceAdded(IHandTrackingWrapper* DeviceWrapper) override; virtual void OnDeviceRemoved(IHandTrackingWrapper* DeviceWrapper) override; UFUNCTION(BlueprintCallable, Category = "Leap Functions") bool IsActiveDevicePluggedIn(); UFUNCTION(BlueprintCallable, Category = "Leap Functions") void GetMultiDeviceDebugInfo(int32& NumLeftTracked, int32& NumRightTracked); class IHandTrackingDevice* GetCombinedDeviceBySerials(const TArray& DeviceSerials); UFUNCTION() bool GetDeviceOrigin(FTransform& DeviceOrigin); protected: virtual void InitializeComponent() override; virtual void UninitializeComponent() override; UFUNCTION(BlueprintCallable, Category = "Leap Functions") bool UpdateMultiDeviceMode(const ELeapMultiDeviceMode DeviceMode); UFUNCTION(BlueprintCallable, Category = "Leap Functions") bool UpdateActiveDevice(const FString& DeviceSerial); private: void RefreshDeviceList(const bool NotifyChangeToUI = false); bool SubscribeToDevice(); bool UnsubscribeFromCurrentDevice(); #if WITH_EDITOR // custom detail panel interface IDetailLayoutBuilder* DetailBuilder; #endif void ConnectToInputEvents(); bool IsConnectedToInputEvents; /** * Converts IEHandType enum (as a uint8) to EHandType * @param Type - the hand type * @return EHandType */ EHandType FromIEHandTypeToEHandType(uint8 Type); IHandTrackingWrapper* CurrentHandTrackingDevice = nullptr; static const FString NameConstantNone; };