October3d55/M/UltraleapTracking/Source/UltraleapTrackingCore/Private/FUltraleapTrackingPlugin.cpp

278 lines
8.1 KiB
C++
Raw Permalink Normal View History

2025-07-21 10:22:56 +08:00
/******************************************************************************
* 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<IPlugin> 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<FGenericApplicationMessageHandler> 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<FString>& 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<FString>& DeviceSerials)
{
if (bActive)
{
LeapInputDevice->SetLeapPolicy(Flag, Enable, DeviceSerials);
}
}
void FUltraleapTrackingPlugin::SetSwizzles(ELeapQuatSwizzleAxisB ToX, ELeapQuatSwizzleAxisB ToY, ELeapQuatSwizzleAxisB ToZ,
ELeapQuatSwizzleAxisB ToW, const TArray<FString>& DeviceSerials)
{
if (bActive)
{
LeapInputDevice->SetSwizzles(ToX, ToY, ToZ, ToW, DeviceSerials);
}
}
void FUltraleapTrackingPlugin::GetAttachedDevices(TArray<FString>& 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<IPlugin> 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<class IInputDevice> FUltraleapTrackingPlugin::CreateInputDevice(
const TSharedRef<FGenericApplicationMessageHandler>& 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<ISettingsModule>("Settings"))
{
SettingsModule->RegisterSettings("Project", "Plugins", "UltraleapTracking",
LOCTEXT("LeapTrackingSettingsName", "UltraleapTracking"),
LOCTEXT("LeapTrackingSettingsDescription", "Configure the UltraleapTracking plugin"),
GetMutableDefault<ULeapTrackingSettings>());
}
}
void FUltraleapTrackingPlugin::UnregisterSettings()
{
// To avoid hot-reload issues
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
SettingsModule->UnregisterSettings("Project", "Plugins", "UltraleapTracking");
}
}
#endif
IMPLEMENT_MODULE(FUltraleapTrackingPlugin, UltraleapTracking)
#undef LOCTEXT_NAMESPACE