/****************************************************************************** * 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. * ******************************************************************************/ #include "FUltraleapTrackingPlugin.h" #include "BodyStateBPLibrary.h" #include "BodyStateDeviceConfig.h" #include "FUltraleapTrackingInputDevice.h" #include "IInputDeviceModule.h" #include "Interfaces/IPluginManager.h" #include "Modules/ModuleManager.h" #include "LeapTrackingSettings.h" #if WITH_EDITOR #include "ISettingsModule.h" #endif #if (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4) #include "Misc/Paths.h" #endif #define LOCTEXT_NAMESPACE "LeapPlugin" // this forces the assembly context to use the LeapC.dll in the Plugin // without this, if OpenXR is enabled, the LeapC.dll in the OpenXR distribution will be loaded instead as it's // loaded earlier on in the boot process // This only works in the editor as Windows side by side expects the dll to be in either the same folder as the loading dll/exe // or a direct sub folder, the folder structure for packaged apps means that this is not possible without breaking Unreal's folder // structure. #if PLATFORM_WINDOWS #if WITH_EDITOR #pragma comment(linker, \ "\"/manifestdependency:type='win32' name='LeapC.dll' version='5.3.0.0' \ processorArchitecture='*' publicKeyToken='0000000000000000' language='*'\"") #endif #endif // PLATFORM_WINDOWS void FUltraleapTrackingPlugin::StartupModule() { // This code will execute after your module is loaded into memory (but after global variables are initialized, of course.) // Custom module-specific init can go here. // IMPORTANT: This line registers our input device module with the engine. // If we do not register the input device module with the engine, // the engine won't know about our existence. Which means // CreateInputDevice never gets called, which means the engine // will never try to poll for events from our custom input device. // Load the dll from appropriate location LeapDLLHandle = GetLeapHandle(); IModularFeatures::Get().RegisterModularFeature(IInputDeviceModule::GetModularFeatureName(), this); // Get and display our plugin version in the log for debugging TSharedPtr Plugin = IPluginManager::Get().FindPlugin(FString("UltraleapTracking")); const FPluginDescriptor& PluginDescriptor = Plugin->GetDescriptor(); UE_LOG(UltraleapTrackingLog, Log, TEXT("Leap Plugin started v%s"), *PluginDescriptor.VersionName); // early initialising works around device/input startup after begin play TSharedPtr DummyMessageHandler(new FGenericApplicationMessageHandler()); CreateInputDevice(DummyMessageHandler.ToSharedRef()); #if WITH_EDITOR if (!IsRunningGame()) { RegisterSettings(); } #endif } void FUltraleapTrackingPlugin::ShutdownModule() { UE_LOG(UltraleapTrackingLog, Log, TEXT("Leap Plugin shutdown.")); if (LeapDLLHandle) { FPlatformProcess::FreeDllHandle(LeapDLLHandle); LeapDLLHandle = nullptr; } // Unregister our input device module IModularFeatures::Get().UnregisterModularFeature(IInputDeviceModule::GetModularFeatureName(), this); #if WITH_EDITOR if (!IsRunningGame()) { UnregisterSettings(); } #endif } void FUltraleapTrackingPlugin::AddEventDelegate(const ULeapComponent* EventDelegate) { if (bActive) { LeapInputDevice->AddEventDelegate(EventDelegate); } else { // Delay load it until it is ready DeferredComponentList.Add((ULeapComponent*) EventDelegate); } } void FUltraleapTrackingPlugin::RemoveEventDelegate(const ULeapComponent* EventDelegate) { if (bActive) { LeapInputDevice->RemoveEventDelegate(EventDelegate); } } FLeapStats FUltraleapTrackingPlugin::GetLeapStats(const FString& DeviceSerial) { if (bActive) { return LeapInputDevice->GetStats(DeviceSerial); } else { return IUltraleapTrackingPlugin::GetLeapStats(DeviceSerial); } } void FUltraleapTrackingPlugin::SetOptions(const FLeapOptions& Options, const TArray& DeviceSerials) { if (bActive) { LeapInputDevice->SetOptions(Options, DeviceSerials); } } FLeapOptions FUltraleapTrackingPlugin::GetOptions(const FString& DeviceSerial) { if (bActive) { return LeapInputDevice->GetOptions(DeviceSerial); } else { return IUltraleapTrackingPlugin::GetOptions(DeviceSerial); } } void FUltraleapTrackingPlugin::AreHandsVisible(bool& LeftHandIsVisible, bool& RightHandIsVisible,const FString& DeviceSerial) { if (bActive) { LeapInputDevice->AreHandsVisible(LeftHandIsVisible, RightHandIsVisible, DeviceSerial); } } void FUltraleapTrackingPlugin::GetLatestFrameData(FLeapFrameData& OutData, const FString& DeviceSerial) { // Copies data if (bActive) { LeapInputDevice->LatestFrame(OutData, DeviceSerial); } } void FUltraleapTrackingPlugin::SetLeapPolicy(ELeapPolicyFlag Flag, bool Enable, const TArray& DeviceSerials) { if (bActive) { LeapInputDevice->SetLeapPolicy(Flag, Enable, DeviceSerials); } } void FUltraleapTrackingPlugin::SetSwizzles(ELeapQuatSwizzleAxisB ToX, ELeapQuatSwizzleAxisB ToY, ELeapQuatSwizzleAxisB ToZ, ELeapQuatSwizzleAxisB ToW, const TArray& DeviceSerials) { if (bActive) { LeapInputDevice->SetSwizzles(ToX, ToY, ToZ, ToW, DeviceSerials); } } void FUltraleapTrackingPlugin::GetAttachedDevices(TArray& Devices) { if (bActive) { Devices = LeapInputDevice->GetAttachedDevices(); } } void FUltraleapTrackingPlugin::ShutdownLeap() { if (bActive) { UE_LOG(UltraleapTrackingLog, Log, TEXT("Shutting down leap from command.")); LeapInputDevice->ShutdownLeap(); } } ILeapConnector* FUltraleapTrackingPlugin::GetConnector() { return LeapInputDevice->GetConnector(); } void* FUltraleapTrackingPlugin::GetLeapHandle() { void* NewLeapDLLHandle = nullptr; // Load LeapC DLL FString LeapCLibraryPath; #if PLATFORM_WINDOWS TSharedPtr Plugin = IPluginManager::Get().FindPlugin(FString("UltraleapTracking")); if (Plugin != nullptr) { FString BaseDir = Plugin->GetBaseDir(); LeapCLibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/Win64/LeapC.dll")); NewLeapDLLHandle = !LeapCLibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*LeapCLibraryPath) : nullptr; } #endif // PLATFORM_WINDOWS if (NewLeapDLLHandle != nullptr) { UE_LOG( UltraleapTrackingLog, Log, TEXT("Engine plugin DLL found at %s"), *FPaths::ConvertRelativePathToFull(LeapCLibraryPath)); } return NewLeapDLLHandle; } TSharedPtr FUltraleapTrackingPlugin::CreateInputDevice( const TSharedRef& InMessageHandler) { if (!LeapInputDevice.IsValid()) { LeapInputDevice = MakeShareable(new FUltraleapTrackingInputDevice(InMessageHandler)); } else { LeapInputDevice.Get()->SetMessageHandler(InMessageHandler); LeapInputDevice->PostEarlyInit(); } bActive = true; // Add all the deferred components and empty it for (int i = 0; i < DeferredComponentList.Num(); i++) { AddEventDelegate(DeferredComponentList[i]); } DeferredComponentList.Empty(); return LeapInputDevice; } #if WITH_EDITOR void FUltraleapTrackingPlugin::RegisterSettings() { // This will show the plugin settings if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) { SettingsModule->RegisterSettings("Project", "Plugins", "UltraleapTracking", LOCTEXT("LeapTrackingSettingsName", "UltraleapTracking"), LOCTEXT("LeapTrackingSettingsDescription", "Configure the UltraleapTracking plugin"), GetMutableDefault()); } } void FUltraleapTrackingPlugin::UnregisterSettings() { // To avoid hot-reload issues if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) { SettingsModule->UnregisterSettings("Project", "Plugins", "UltraleapTracking"); } } #endif IMPLEMENT_MODULE(FUltraleapTrackingPlugin, UltraleapTracking) #undef LOCTEXT_NAMESPACE