/** * @file * * @author Mamadou Babaei * * @section LICENSE * * (The MIT License) * * Copyright (c) 2020 - 2025 SenseGlove * * 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. * * @section DESCRIPTION * * */ #include "SGCoreImpl/SGHapticGloveImpl.h" #include #include #include "Containers/StringConv.h" #include "SGBuildHacks/SGInclude_Core_BasicHandModel.h" #include "SGBuildHacks/SGInclude_Core_CustomWaveform.h" #include "SGBuildHacks/SGInclude_Core_HandPose.h" #include "SGBuildHacks/SGInclude_Core_HapticGlove.h" #include "SGBuildHacks/SGInclude_Core_Quat.h" #include "SGBuildHacks/SGInclude_Core_Vect3D.h" #include "SGCoreImpl/SGBasicHandModelImpl.h" #include "SGCoreImpl/SGCoreEnumCast.h" #include "SGCoreImpl/SGCustomWaveformImpl.h" #include "SGCoreImpl/SGHandPoseImpl.h" #include "SGCoreImpl/SGQuatImpl.h" #include "SGCoreImpl/SGVect3DImpl.h" #include "SGUtils/SGArrayUtils.h" struct FSGHapticGloveImpl::FImpl { /************************ * Owner object ************************/ FSGHapticGloveImpl* Owner; /************************ * Constructor / Destructor ************************/ explicit FImpl(FSGHapticGloveImpl* InOwner); ~FImpl(); /************************ * Default copy constructor & copy assignment operator ************************/ FImpl(const FImpl& Rhs) = default; FImpl& operator=(const FImpl& Rhs) = default; }; TArray> FSGHapticGloveImpl::GetHapticGloves(const bool bConnectedOnly) { const FHapticGlovePtrVectorType HapticGloves{FHapticGloveType::GetHapticGloves(bConnectedOnly)}; TArray> HapticGloveImpls; for (FHapticGlovePtrType HapticGlove: HapticGloves) { TSharedRef HapticGloveImpl{MakeShared(MoveTemp(HapticGlove))}; HapticGloveImpls.Push(MoveTemp(HapticGloveImpl)); } return HapticGloveImpls; } bool FSGHapticGloveImpl::GetGlove(TSharedPtr& OutGlove) { FHapticGlovePtrType Glove; const bool bReturn = FHapticGloveType::GetGlove(Glove); if (bReturn) { OutGlove = MakeShared(MoveTemp(Glove)); } return bReturn; } bool FSGHapticGloveImpl::GetGlove(const bool bRightHanded, TSharedPtr& OutGlove) { FHapticGlovePtrType Glove; const bool bReturn = FHapticGloveType::GetGlove(bRightHanded, Glove); if (bReturn) { OutGlove = MakeShared(MoveTemp(Glove)); } return bReturn; } FString FSGHapticGloveImpl::ToString(ESGHapticGloveCalibrationState State) { const FString String{ UTF8_TO_TCHAR(FHapticGloveType::ToString(FSGCoreEnumCast::ToEHapticGloveCalibrationState(State)).c_str()) }; return String; } FString FSGHapticGloveImpl::ToString(ESGHapticLocation Location) { const FString String{ UTF8_TO_TCHAR(FHapticGloveType::ToString(FSGCoreEnumCast::ToEHapticLocation(Location)).c_str()) }; return String; } FSGHapticGloveImpl::FSGHapticGloveImpl() : FSGDeviceImpl(), Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) { } FSGHapticGloveImpl::FSGHapticGloveImpl(const FHapticGlovePtrType HapticGlove) : FSGDeviceImpl(std::static_pointer_cast(HapticGlove)), Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) { } FSGHapticGloveImpl::FSGHapticGloveImpl(const FSGHapticGloveImpl& Rhs) : FSGDeviceImpl(Rhs), Pimpl(TUniquePtr(new FImpl{*Rhs.Pimpl}, PimplDeleter)) { Pimpl->Owner = this; } FSGHapticGloveImpl::FSGHapticGloveImpl(FSGHapticGloveImpl&& Rhs) SG_NOEXCEPT = default; FSGHapticGloveImpl::~FSGHapticGloveImpl() = default; FSGHapticGloveImpl& FSGHapticGloveImpl::operator=(const FSGHapticGloveImpl& Rhs) { FSGDeviceImpl::operator=(Rhs); *Pimpl = *Rhs.Pimpl; Pimpl->Owner = this; return *this; } FSGHapticGloveImpl& FSGHapticGloveImpl::operator=(FSGHapticGloveImpl&& Rhs) SG_NOEXCEPT = default; FSGHapticGloveImpl::FHapticGlovePtrType FSGHapticGloveImpl::ToHapticGlovePtr() const { return std::static_pointer_cast(ToSGDevicePtr()); } FSGHapticGloveImpl::FHapticGlovePtrType FSGHapticGloveImpl::ToHapticGlovePtrChecked() const { FHapticGlovePtrType HapticGlove = std::static_pointer_cast(ToSGDevicePtr()); ensureAlwaysMsgf(HapticGlove.get(), TEXT("Invalid HapticGlove")); return HapticGlove; } ESGDeviceType FSGHapticGloveImpl::GetDeviceType() const { return FSGCoreEnumCast::ToESGDeviceType(ToHapticGlovePtrChecked()->GetDeviceType()); } FString FSGHapticGloveImpl::GetDeviceId() const { const FString Id{UTF8_TO_TCHAR(ToHapticGlovePtrChecked()->GetDeviceId().c_str())}; return Id; } FString FSGHapticGloveImpl::GetHardwareVersion() const { const FString Version{UTF8_TO_TCHAR(ToHapticGlovePtrChecked()->GetHardwareVersion().c_str())}; return Version; } int32 FSGHapticGloveImpl::GetFirmwareVersion() const { return ToHapticGlovePtrChecked()->GetFirmwareVersion(); } int32 FSGHapticGloveImpl::GetSubFirmwareVersion() const { return ToHapticGlovePtrChecked()->GetSubFirmwareVersion(); } bool FSGHapticGloveImpl::IsRight() const { return ToHapticGlovePtrChecked()->IsRight(); } bool FSGHapticGloveImpl::GetImuRotation(FQuat& OutImu) { FSGQuatImpl::FQuatType Imu; const bool bResult = ToHapticGlovePtrChecked()->GetImuRotation(Imu); OutImu = FSGQuatImpl{MoveTemp(Imu)}.ToFQuat(); return bResult; } bool FSGHapticGloveImpl::GetHandPose(const FSGBasicHandModelImpl& HandGeometry, FSGHandPoseImpl& OutHandPose) const { FSGHandPoseImpl::FHandPoseType HandPose; const bool bResult = ToHapticGlovePtrChecked()->GetHandPose(HandGeometry.ToBasicHandModel(), HandPose); OutHandPose = FSGHandPoseImpl{MoveTemp(HandPose)}; return bResult; } bool FSGHapticGloveImpl::GetHandPose(FSGHandPoseImpl& OutHandPose) { FSGHandPoseImpl::FHandPoseType HandPose; const bool bResult = ToHapticGlovePtrChecked()->GetHandPose(HandPose); OutHandPose = FSGHandPoseImpl{MoveTemp(HandPose)}; return bResult; } bool FSGHapticGloveImpl::GetHandAngles(TArray>& OutHandAngles) const { std::vector> HandAngles; const bool bResult = ToHapticGlovePtrChecked()->GetHandAngles(HandAngles); OutHandAngles = FSGArrayUtils::FromSenseGloveAngles(HandAngles); return bResult; } FSGBasicHandModelImpl FSGHapticGloveImpl::GetHandGeometry() const { FSGBasicHandModelImpl::FBasicHandModelType Geometry{ToHapticGlovePtrChecked()->GetHandGeometry()}; return FSGBasicHandModelImpl{MoveTemp(Geometry)}; } void FSGHapticGloveImpl::SetHandGeometry(const FSGBasicHandModelImpl& HandGeometry) { ToHapticGlovePtrChecked()->SetHandGeometry(HandGeometry.ToBasicHandModel()); } ESGHapticGloveCalibrationState FSGHapticGloveImpl::GetCalibrationState() const { return FSGCoreEnumCast::ToESGHapticGloveCalibrationState(ToHapticGlovePtrChecked()->GetCalibrationState()); } void FSGHapticGloveImpl::EndCalibration() { ToHapticGlovePtrChecked()->EndCalibration(); } void FSGHapticGloveImpl::ResetCalibration() { ToHapticGlovePtrChecked()->ResetCalibration(); } FString FSGHapticGloveImpl::GetCalibrationInstruction() const { const FString Instruction{UTF8_TO_TCHAR(ToHapticGlovePtrChecked()->GetCalibrationInstruction().c_str())}; return Instruction; } void FSGHapticGloveImpl::StopHaptics() { ToHapticGlovePtrChecked()->StopHaptics(); } void FSGHapticGloveImpl::StopVibrations() { ToHapticGlovePtrChecked()->StopVibrations(); } bool FSGHapticGloveImpl::SendHaptics() { return ToHapticGlovePtrChecked()->SendHaptics(); } bool FSGHapticGloveImpl::SupportsCustomWaveform(const ESGHapticLocation AtLocation) const { return ToHapticGlovePtrChecked()->SupportsCustomWaveform(FSGCoreEnumCast::ToEHapticLocation(AtLocation)); } bool FSGHapticGloveImpl::SendCustomWaveform(FSGCustomWaveformImpl& OutWaveform, const ESGHapticLocation Location) { return ToHapticGlovePtrChecked()->SendCustomWaveform( OutWaveform.ToCustomWaveform(), FSGCoreEnumCast::ToEHapticLocation(Location)); } bool FSGHapticGloveImpl::QueueForceFeedbackLevels(const TArray& Levels01) { std::vector Levels01Vector{FSGArrayUtils::ToStdVector(Levels01)}; return ToHapticGlovePtrChecked()->QueueForceFeedbackLevels(MoveTemp(Levels01Vector)); } bool FSGHapticGloveImpl::QueueForceFeedbackLevel(const int32 Finger, const float Level01) { return ToHapticGlovePtrChecked()->QueueForceFeedbackLevel(Finger, Level01); } bool FSGHapticGloveImpl::QueueVibroLevels(const TArray& Levels01) { std::vector Levels01Vector{FSGArrayUtils::ToStdVector(Levels01)}; return ToHapticGlovePtrChecked()->QueueVibroLevels(MoveTemp(Levels01Vector)); } bool FSGHapticGloveImpl::QueueVibroLevel(const ESGHapticLocation Location, const float Level01) { return ToHapticGlovePtrChecked()->QueueVibroLevel(FSGCoreEnumCast::ToEHapticLocation(Location), Level01); } void FSGHapticGloveImpl::GetWristLocation(const FVector& ReferencePosition, const FQuat& ReferenceRotation, const ESGPositionalTrackingHardware TrackingHardware, FVector& OutWristPosition, FQuat& OutWristRotation) const { FSGVect3DImpl::FVect3DType WristPosition; FSGQuatImpl::FQuatType WristRotation; ToHapticGlovePtrChecked()->GetWristLocation( FSGUnits::CentimetersToMillimeters(ReferencePosition), FSGQuatImpl(ReferenceRotation).ToQuat(), FSGCoreEnumCast::ToEPositionalTrackingHardware(TrackingHardware), WristPosition, WristRotation); OutWristPosition = FSGUnits::MillimetersToCentimeters( MoveTemp(WristPosition)); OutWristRotation = FSGQuatImpl(MoveTemp(WristRotation)).ToFQuat(); } void FSGHapticGloveImpl::GetGloveLocation(const FVector& ReferencePosition, const FQuat& ReferenceRotation, const ESGPositionalTrackingHardware TrackingHardware, FVector& OutGlovePosition, FQuat& OutGloveRotation) const { FSGVect3DImpl::FVect3DType GlovePosition; FSGQuatImpl::FQuatType GloveRotation; ToHapticGlovePtrChecked()->GetGloveLocation( FSGUnits::CentimetersToMillimeters(ReferencePosition), FSGQuatImpl(ReferenceRotation).ToQuat(), FSGCoreEnumCast::ToEPositionalTrackingHardware(TrackingHardware), GlovePosition, GloveRotation); OutGlovePosition = FSGUnits::MillimetersToCentimeters( MoveTemp(GlovePosition)); OutGloveRotation = FSGQuatImpl(MoveTemp(GloveRotation)).ToFQuat(); } FString FSGHapticGloveImpl::ToString() const { const FString String{UTF8_TO_TCHAR(ToHapticGlovePtrChecked()->ToString().c_str())}; return String; } FSGHapticGloveImpl::FImpl::FImpl(FSGHapticGloveImpl* InOwner) : Owner(InOwner) { } FSGHapticGloveImpl::FImpl::~FImpl() = default; void FSGHapticGloveImpl::FImplDeleter::operator()(const FImpl* P) const { delete P; }