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

239 lines
7.3 KiB
C++

/******************************************************************************
* 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 "LeapUtility.h"
#include "Engine/Engine.h" // for GEngine
#include "Engine/World.h"
#include "GameFramework/WorldSettings.h"
#include "IXRTrackingSystem.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/App.h"
#include "UltraleapTrackingData.h"
#include "Runtime/Launch/Resources/Version.h"
#if (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3)
#include "JsonObjectConverter.h"
#else
#include "JsonUtilities/Public/JsonObjectConverter.h"
#endif
DEFINE_LOG_CATEGORY(UltraleapTrackingLog);
// Static vars
#define LEAP_TO_UE_SCALE 0.1f
#define UE_TO_LEAP_SCALE 10.f
FQuat FLeapUtility::LeapRotationOffset;
// Todo: use and verify this for all values
float LeapGetWorldScaleFactor()
{
if (IsInGameThread())
{
if (GEngine != nullptr && GEngine->GetWorld() != nullptr && GEngine->GetWorld()->GetWorldSettings() != nullptr)
{
return (GEngine->GetWorld()->GetWorldSettings()->WorldToMeters) / 100.f;
}
}
return 1.f;
}
void FLeapUtility::LogRotation(const FString& Text, const FRotator& Rotation)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(
-1, 15.0f, FColor::Yellow, FString::Printf(TEXT("%s %f %f %f"), *Text, Rotation.Yaw, Rotation.Pitch, Rotation.Roll));
}
}
FRotator FLeapUtility::CombineRotators(FRotator A, FRotator B)
{
FQuat AQuat = FQuat(A);
FQuat BQuat = FQuat(B);
return FRotator(BQuat * AQuat);
}
// Single point to handle leap conversion
FVector FLeapUtility::ConvertLeapVectorToFVector(const LEAP_VECTOR& LeapVector)
{
// Expects VR Orientation
return FVector(LeapVector.y, -LeapVector.x, -LeapVector.z);
}
FQuat FLeapUtility::ConvertLeapQuatToFQuat(const LEAP_QUATERNION& Quaternion)
{
FQuat Quat;
// it's -Z, X, Y tilted back by 90 degree which is -y,x,z
Quat.X = -Quaternion.y;
Quat.Y = Quaternion.x;
Quat.Z = Quaternion.z;
Quat.W = Quaternion.w;
if (Quat.ContainsNaN())
{
Quat = FQuat::MakeFromEuler(FVector(0, 0, 0));
UE_LOG(
UltraleapTrackingLog, Log, TEXT("FLeapUtility::ConvertLeapQuatToFQuat() Warning - NAN received from tracking device"));
}
return Quat * LeapRotationOffset;
}
FVector FLeapUtility::ConvertAndScaleLeapVectorToFVectorWithHMDOffsets(
const LEAP_VECTOR& LeapVector, const FVector& LeapMountTranslationOffset, const FQuat& LeapMountRotationOffset)
{
if (FLeapUtility::ContainsNaN(LeapVector))
{
return LeapMountRotationOffset.RotateVector(FVector::ForwardVector);
}
// Scale from mm to cm (ue default)
FVector ConvertedVector =
(ConvertLeapVectorToFVector(LeapVector) + LeapMountTranslationOffset) * (LEAP_TO_UE_SCALE * LeapGetWorldScaleFactor());
if (ConvertedVector.ContainsNaN())
{
ConvertedVector = FVector::ZeroVector;
UE_LOG(UltraleapTrackingLog, Log,
TEXT("FLeapUtility::ConvertAndScaleLeapVectorToFVectorWithHMDOffsets Warning - NAN received from tracking device"));
}
// Rotate our vector to adjust for any global rotation offsets
return LeapMountRotationOffset.RotateVector(ConvertedVector);
}
FQuat FLeapUtility::ConvertToFQuatWithHMDOffsets(LEAP_QUATERNION Quaternion, const FQuat& LeapMountRotationOffset)
{
FQuat UEQuat = ConvertLeapQuatToFQuat(Quaternion);
return LeapMountRotationOffset * UEQuat;
}
FMatrix FLeapUtility::SwapLeftHandRuleForRight(const FMatrix& UEMatrix)
{
FMatrix Matrix = UEMatrix;
// Convenience method to swap the axis correctly, already in UE format to swap Y instead of leap Z
FVector InverseVector = -Matrix.GetUnitAxis(EAxis::Y);
Matrix.SetAxes(NULL, &InverseVector, NULL, NULL);
return Matrix;
}
LEAP_VECTOR FLeapUtility::ConvertUEToLeap(FVector UEVector)
{
LEAP_VECTOR vector;
vector.x = UEVector.Y;
vector.y = UEVector.Z;
vector.z = -UEVector.X;
return vector;
}
LEAP_VECTOR FLeapUtility::ConvertAndScaleUEToLeap(FVector UEVector)
{
LEAP_VECTOR vector;
vector.x = UEVector.Y * UE_TO_LEAP_SCALE;
vector.y = UEVector.Z * UE_TO_LEAP_SCALE;
vector.z = -UEVector.X * UE_TO_LEAP_SCALE;
return vector;
}
float FLeapUtility::ScaleLeapFloatToUE(float LeapFloat)
{
return LeapFloat * LEAP_TO_UE_SCALE; // mm->cm
}
float FLeapUtility::ScaleUEToLeap(float UEFloat)
{
return UEFloat * UE_TO_LEAP_SCALE; // mm->cm
}
// static, this has to be done during runtime as the static initialiser
// does not work in shipping builds.
void FLeapUtility::InitLeapStatics()
{
LeapRotationOffset = FQuat(FRotator(90.f, 0.f, 180.f));
}
void FLeapUtility::CleanupConstCharArray(const char** ConstCharArray, int32 Size)
{
// Assume array is filled dynamically
if (ConstCharArray!=nullptr)
{
for (int i = 0; (i <= Size)&&(ConstCharArray[i] != nullptr); ++i)
{
free(const_cast<char*>(ConstCharArray[i]));
}
// Free memory for the const char* array
delete[] ConstCharArray;
ConstCharArray = nullptr;
}
}
void FLeapUtility::ConvertFStringArrayToCharArray(const TArray<FString>& FStringArray, const char*** ConstCharArrayPtr)
{
// Allocate memory for array +1 for the NULL end
*ConstCharArrayPtr = new const char*[FStringArray.Num() + 1];
for (int32 i = 0; i < FStringArray.Num(); ++i)
{
// Convert FString to ANSI const char array
auto ConvertedStr = StringCast<ANSICHAR>(*FStringArray[i]);
const char* ConstCharArray = ConvertedStr.Get();
// String Duplication: Check that string duplications are done correctly
#if PLATFORM_WINDOWS
(*ConstCharArrayPtr)[i] = _strdup(ConstCharArray);
#else
(*ConstCharArrayPtr)[i] = strdup(ConstCharArray);
#endif
}
}
void FLeapUtility::SetLastArrayElemNull(const char*** ConstCharArrayPtr, int32 LastIdx)
{
(*ConstCharArrayPtr)[LastIdx] = NULL;
}
FString FLeapUtility::GetAnalyticsData(size_t& Size)
{
FAnalytics Analytics;
Analytics.telemetry.app_title = FApp::GetProjectName();
#if WITH_EDITOR
Analytics.telemetry.app_type = "editor";
#else
Analytics.telemetry.app_type = "build";
#endif
Analytics.telemetry.engine_name = "Unreal";
FString UnrealVersion = FString::FromInt(ENGINE_MAJOR_VERSION);
UnrealVersion += ".";
UnrealVersion += FString::FromInt(ENGINE_MINOR_VERSION);
Analytics.telemetry.engine_version = UnrealVersion;
Analytics.telemetry.installation_source = "github";
Analytics.telemetry.plugin_version = FString();
TSharedPtr<IPlugin> Plugin = IPluginManager::Get().FindPlugin(FString("UltraleapTracking"));
if (Plugin.IsValid())
{
const FPluginDescriptor& PluginDescriptor = Plugin->GetDescriptor();
Analytics.telemetry.plugin_version = PluginDescriptor.VersionName;
if (Plugin->GetLoadedFrom() == EPluginLoadedFrom::Engine)
{
Analytics.telemetry.installation_source = "EpicGamesLauncher";
}
}
FString SerializedJson;
bool bConverted = FJsonObjectConverter::UStructToFormattedJsonObjectString<TCHAR, TPrettyJsonPrintPolicy>(FAnalytics::StaticStruct(), &Analytics, SerializedJson);
if (!bConverted)
{
UE_LOG(UltraleapTrackingLog, Error, TEXT("FLeapUtility::GetAnalyticsData Failed Json conversion"));
}
Size = SerializedJson.Len() + 1;
return SerializedJson;
}