October3d55/M/UltraleapTracking/Source/ThirdParty/BodyState/Private/BodyStateSkeletonStorage.cpp

238 lines
7.0 KiB
C++

/*************************************************************************************************************************************
*The MIT License(MIT)
*
*Copyright(c) 2016 Jan Kaniewski(Getnamo)
*Modified work Copyright(C) 2019 - 2021 Ultraleap, Inc.
*
*Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
*files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
*merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions :
*
*The above copyright notice and this permission notice shall be included in all copies or
*substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
*FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
*CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*************************************************************************************************************************************/
#include "BodyStateSkeletonStorage.h"
#include "BodyStateUtility.h"
#include "CoreMinimal.h"
#include "Misc/App.h"
#include "Skeleton/BodyStateSkeleton.h"
FBodyStateSkeletonStorage::FBodyStateSkeletonStorage()
{
PrivateMergedSkeleton = nullptr;
DeviceIndex = 0;
MergingFunctionIndexCount = 0;
}
FBodyStateSkeletonStorage::~FBodyStateSkeletonStorage()
{
// Allow merge skeleton to be removed
if (PrivateMergedSkeleton && PrivateMergedSkeleton->IsValidLowLevel())
{
PrivateMergedSkeleton->ReleaseRefs();
PrivateMergedSkeleton->RemoveFromRoot();
PrivateMergedSkeleton = nullptr;
}
}
int32 FBodyStateSkeletonStorage::AddDevice(const FBodyStateDevice& InDevice)
{
// Ensure we have a merged skeleton first
MergedSkeleton();
FBodyStateDevice Device = InDevice;
DeviceIndex++;
Device.DeviceId = DeviceIndex;
Device.Skeleton = NewObject<UBodyStateSkeleton>();
Device.Skeleton->Name = Device.Config.DeviceName;
Device.Skeleton->SkeletonId = Device.DeviceId;
Device.Skeleton->TrackingTags = Device.Config.TrackingTags;
Device.Skeleton->AddToRoot();
Devices.Add(Device.InputCallbackDelegate, Device);
DeviceKeyMap.Add(Device.DeviceId, Device.InputCallbackDelegate);
UE_LOG(BodyStateLog, Log, TEXT("BodyState::DeviceAttached: %s (%d)"), *Device.Config.DeviceName, Devices.Num());
return Device.DeviceId;
}
bool FBodyStateSkeletonStorage::RemoveDevice(int32 DeviceId)
{
UE_LOG(BodyStateLog, Log, TEXT("Id: %d"), DeviceId);
if (DeviceId < 0)
{
UE_LOG(BodyStateLog, Log, TEXT("BodyState::RemoveDevice attempted to remove invalid index: (%d)"), DeviceId);
return false; // couldn't find
}
bool HasKey = DeviceKeyMap.Contains(DeviceId);
if (!HasKey)
{
UE_LOG(BodyStateLog, Log, TEXT("BodyState::RemoveDevice already removed (%d)"), DeviceId);
return false; // already removed
}
IBodyStateInputRawInterface* DelegatePtr = DeviceKeyMap[DeviceId];
const FBodyStateDevice& Device = Devices[DelegatePtr];
const FString DeviceName = Device.Config.DeviceName;
if (Device.Skeleton->IsValidLowLevel())
{
Device.Skeleton->RemoveFromRoot();
}
DeviceKeyMap.Remove(DeviceId);
Devices.Remove(DelegatePtr);
UE_LOG(BodyStateLog, Log, TEXT("BodyState::Device Detached: %s (%d)"), *DeviceName, Devices.Num());
return true;
}
void FBodyStateSkeletonStorage::RemoveAllDevices()
{
// We need to make a copy of our devices as remove will change the size of devices
TArray<FBodyStateDevice> AllDevices;
Devices.GenerateValueArray(AllDevices);
for (auto& Device : AllDevices)
{
if (Device.InputCallbackDelegate != nullptr)
{
RemoveDevice(Device.DeviceId);
}
}
}
UBodyStateSkeleton* FBodyStateSkeletonStorage::SkeletonForDevice(int32 DeviceId)
{
// Return merged/only skeleton
if (DeviceId == 0)
{
return PrivateMergedSkeleton;
}
// Return specific skeleton
else if (!DeviceKeyMap.Contains(DeviceId))
{
UE_LOG(BodyStateLog, Warning, TEXT("DeviceID: %d is invalid, returning nullptr skeleton."), DeviceId);
return nullptr;
}
else
{
return Devices[DeviceKeyMap[DeviceId]].Skeleton;
}
}
UBodyStateSkeleton* FBodyStateSkeletonStorage::MergedSkeleton()
{
// create as needed
if (!PrivateMergedSkeleton || !PrivateMergedSkeleton->IsValidLowLevel())
{
PrivateMergedSkeleton = NewObject<UBodyStateSkeleton>();
PrivateMergedSkeleton->Name = TEXT("Merged");
PrivateMergedSkeleton->SkeletonId = 0;
PrivateMergedSkeleton->AddToRoot();
}
return PrivateMergedSkeleton;
}
void FBodyStateSkeletonStorage::UpdateMergeSkeletonData()
{
double Now = FApp::GetCurrentTime();
DeltaTime = (Now - LastFrameTime);
// Basic merge of skeleton data
MergedSkeleton();
if (!PrivateMergedSkeleton->bTrackingActive)
{
return;
}
// Reset our confidence
PrivateMergedSkeleton->ClearConfidence();
PrivateMergedSkeleton->TrackingTags.Empty();
// Merges all skeleton data
{
FScopeLock ScopeLock(&PrivateMergedSkeleton->BoneDataLock);
for (auto& Elem : Devices)
{
UBodyStateSkeleton* Skeleton = Elem.Value.Skeleton;
PrivateMergedSkeleton->MergeFromOtherSkeleton(Skeleton);
}
}
// Dispatch estimator function lambdas which give merge skeleton and expect further updated values
CallMergingFunctions();
LastFrameTime = Now;
}
void FBodyStateSkeletonStorage::CallMergingFunctions()
{
// Call all merging functions on our private merged skeleton
for (auto& Pair : MergingFunctions)
{
FScopeLock ScopeLock(&PrivateMergedSkeleton->BoneDataLock);
Pair.Value(PrivateMergedSkeleton, DeltaTime);
}
}
int32 FBodyStateSkeletonStorage::AddMergingFunction(TFunction<void(UBodyStateSkeleton*, float)> InFunction)
{
MergingFunctions.Add(MergingFunctionIndexCount, InFunction);
MergingFunctionIndexCount++;
return MergingFunctionIndexCount - 1;
}
bool FBodyStateSkeletonStorage::RemoveMergingFunction(int32 MergingFunctionId)
{
int32 ValueCount = MergingFunctions.Remove(MergingFunctionId);
return ValueCount > 0;
}
void FBodyStateSkeletonStorage::ClearMergingFunctions()
{
MergingFunctions.Empty();
MergingFunctionIndexCount = 0;
}
void FBodyStateSkeletonStorage::CallFunctionOnDevices(TFunction<void(const FBodyStateDevice&)> InFunction)
{
TMap<IBodyStateInputRawInterface*, FBodyStateDevice> DevicesCopy = Devices;
for (auto& Elem : DevicesCopy)
{
auto& Device = Elem.Value;
if (Device.InputCallbackDelegate != nullptr)
{
InFunction(Device);
}
}
}
bool FBodyStateSkeletonStorage::GetAvailableDevices(TArray<FString>& DeviceSerials, TArray<int32>& DeviceIDs)
{
DeviceSerials.Empty();
DeviceIDs.Empty();
int Index = 0;
for (auto& Elem : Devices)
{
auto& Device = Elem.Value;
if (!Device.Config.DeviceSerial.IsEmpty())
{
DeviceSerials.Add(Device.Config.DeviceSerial);
DeviceIDs.Add(Device.DeviceId);
}
}
return true;
}