implement the SenseGlove grab/touch sockets one-click-setup ability on any Epic-compliant virtual hand mesh from within the Unreal Editor's Content Browser, Skeleton Editor, or Skeletal Mesh Editor

This commit is contained in:
Mamadou Babaei
2024-08-16 16:37:26 +02:00
parent b33d7a364d
commit 506999f690
43 changed files with 1788 additions and 967 deletions
@@ -145,7 +145,7 @@ public:
FORCEINLINE const FName& GetGrabSocketName() const
{
return GetVirtualHandSettings().GrabSettings.PalmAttachPointSocketName;
return GetVirtualHandSettings().GrabSettings.GrabAttachPointSocketName;
}
FORCEINLINE const FVector& GetDefaultFingertipsGrabColliderSize() const
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,296 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGContentBrowserExtension.h"
#include "Animation/Skeleton.h"
#include "AssetRegistry/AssetData.h"
#include "Containers/UnrealString.h"
#include "ContentBrowserDelegates.h"
#include "ContentBrowserModule.h"
#include "Editor.h"
#include "Engine/SkeletalMesh.h"
#include "Framework/Commands/UIAction.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "GenericPlatform/GenericPlatformMisc.h"
#include "Internationalization/Text.h"
#include "Math/Transform.h"
#include "Misc/MessageDialog.h"
#include "ReferenceSkeleton.h"
#include "UObject/Object.h"
#include "SGEditor/SGAssetUtils.h"
#include "SGEditor/SGPluginStyle.h"
#define LOCTEXT_NAMESPACE "SGContentBrowserExtension"
struct FSGContentBrowserExtension::FImpl
{
/************************
* Static methods
************************/
static void TryAddSenseGloveSockets(const TArray<FAssetData>& SelectedAssets);
static void TryClearExistingSockets(const TArray<FAssetData>& SelectedAssets);
};
void FSGContentBrowserExtension::FImpl::TryAddSenseGloveSockets(const TArray<FAssetData>& SelectedAssets)
{
const FText ConfirmationDialogText{
LOCTEXT("SenseGloveAddSocketsConfirmation",
"Do you want to add the SenseGlove sockets?")
};
const EAppReturnType::Type DialogResult{
FMessageDialog::Open(EAppMsgType::YesNo, ConfirmationDialogText)
};
if (DialogResult != EAppReturnType::Yes)
{
return;
}
bool bAllAssetsSucceeded = true;
for (const FAssetData& Asset: SelectedAssets)
{
USkeletalMesh* SkeletalMesh{Cast<USkeletalMesh>(Asset.GetAsset())};
USkeleton* Skeleton{Cast<USkeleton>(Asset.GetAsset())};
if (!IsValid(SkeletalMesh) && !IsValid(Skeleton))
{
continue;
}
bool bAddedSenseGloveSockets = false;
if (IsValid(SkeletalMesh))
{
bAddedSenseGloveSockets = FSGAssetUtils::AddSenseGloveSockets(SkeletalMesh);
}
else if (IsValid(Skeleton))
{
bAddedSenseGloveSockets = FSGAssetUtils::AddSenseGloveSockets(Skeleton);
}
if (!bAddedSenseGloveSockets)
{
bAllAssetsSucceeded = false;
const FText ResultDialogText{
FText::Format(
LOCTEXT("SenseGloveAddSocketsResultFailedOn",
"Failed to add the SenseGlove sockets to '{0}'!"),
FText::FromString(Asset.GetSoftObjectPath().ToString()))
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
if (!bAddedSenseGloveSockets)
{
break;
}
}
if (bAllAssetsSucceeded)
{
const FText ResultDialogText{
LOCTEXT("SenseGloveAddSocketsResultSuccess",
"Successfully added the SenseGlove grab and touch sockets. If you wish the changes to persist, save"
" the modified asset(s) now!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
}
void FSGContentBrowserExtension::FImpl::TryClearExistingSockets(const TArray<FAssetData>& SelectedAssets)
{
const FText ConfirmationDialogText{
LOCTEXT("SenseGloveClearExistingSocketsConfirmation",
"Are you sure you want to clear all the existing sockets? This cannot be undone!")
};
const EAppReturnType::Type DialogResult{
FMessageDialog::Open(EAppMsgType::YesNo, ConfirmationDialogText)
};
if (DialogResult != EAppReturnType::Yes)
{
return;
}
bool bAllAssetsSucceeded = true;
for (const FAssetData& Asset: SelectedAssets)
{
USkeletalMesh* SkeletalMesh{Cast<USkeletalMesh>(Asset.GetAsset())};
USkeleton* Skeleton{Cast<USkeleton>(Asset.GetAsset())};
if (!IsValid(SkeletalMesh) && !IsValid(Skeleton))
{
continue;
}
bool bClearedExistingSockets = false;
if (IsValid(SkeletalMesh))
{
bClearedExistingSockets = FSGAssetUtils::ClearExistingSockets(SkeletalMesh);
}
else if (IsValid(Skeleton))
{
bClearedExistingSockets = FSGAssetUtils::ClearExistingSockets(Skeleton);
}
if (!bClearedExistingSockets)
{
bAllAssetsSucceeded = false;
const FText ResultDialogText{
FText::Format(
LOCTEXT("SenseGloveClearExistingSocketsResultFailedOn",
"Failed to clear all the existing sockets on '{0}'!"),
FText::FromString(Asset.GetSoftObjectPath().ToString()))
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
if (!bClearedExistingSockets)
{
break;
}
}
if (bAllAssetsSucceeded)
{
const FText ResultDialogText{
LOCTEXT("SenseGloveClearExistingSocketsResultSuccess",
"Successfully cleared all the existing sockets! If you wish the changes to persist, save the"
" modified asset(s) now!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
}
void FSGContentBrowserExtension::Register()
{
FContentBrowserModule& ContentBrowserModule{
FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"))
};
TArray<FContentBrowserMenuExtender_SelectedAssets>& ContextMenuDelegates{
ContentBrowserModule.GetAllAssetViewContextMenuExtenders()
};
ContextMenuDelegates.Add(FContentBrowserMenuExtender_SelectedAssets::CreateStatic(&OnExtendAssetSelectionMenu));
}
TSharedRef<FExtender> FSGContentBrowserExtension::OnExtendAssetSelectionMenu(
const TArray<FAssetData>& SelectedAssets)
{
TSharedRef<FExtender> Extender{MakeShared<FExtender>()};
Extender->AddMenuExtension(
"CommonAssetActions",
EExtensionHook::After,
nullptr,
FMenuExtensionDelegate::CreateStatic(&AssetExtenderCallback, SelectedAssets)
);
return MoveTemp(Extender);
}
void FSGContentBrowserExtension::AssetExtenderCallback(
FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets)
{
bool bShouldExtendTheMenu = true;
for (const FAssetData& Asset: SelectedAssets)
{
if (Asset.IsRedirector()
|| FName{*Asset.AssetClassPath.ToString()} == NAME_Class
|| (Asset.PackageFlags & PKG_FilterEditorOnly))
{
bShouldExtendTheMenu = false;
break;
}
const bool bIsChildOfUSkeletalMesh = Asset.GetClass()->IsChildOf(USkeletalMesh::StaticClass());
const bool bIsChildOfUSkeleton = Asset.GetClass()->IsChildOf(USkeleton::StaticClass());
if (!bIsChildOfUSkeletalMesh && !bIsChildOfUSkeleton)
{
bShouldExtendTheMenu = false;
break;
}
}
if (!bShouldExtendTheMenu)
{
return;
}
MenuBuilder.BeginSection(FName{TEXT("SenseGloveSection")}, LOCTEXT("SenseGloveHeading", "SenseGlove"));
MenuBuilder.AddMenuEntry(
LOCTEXT("SenseGloveAddSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT("SenseGloveAddSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
FUIAction{
FExecuteAction::CreateLambda([SelectedAssets]()-> void
{
FImpl::TryAddSenseGloveSockets(SelectedAssets);
})
},
NAME_None,
EUserInterfaceActionType::Button,
NAME_None);
MenuBuilder.AddMenuEntry(
LOCTEXT("SenseGloveClearExistingSocketsLabel", "Clear Existing Sockets"),
LOCTEXT("SenseGloveClearExistingSocketsToolTip",
"Clears all the existing sockets; SenseGlove or otherwise"),
FSGPluginStyle::GetStyleSetIcon(),
FUIAction{
FExecuteAction::CreateLambda([SelectedAssets]()-> void
{
FImpl::TryClearExistingSockets(SelectedAssets);
})
},
NAME_None,
EUserInterfaceActionType::Button,
NAME_None);
MenuBuilder.EndSection();
}
#undef LOCTEXT_NAMESPACE
@@ -1,178 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGContentBrowserExtension_SkeletalMesh.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "ContentBrowserDelegates.h"
#include "ContentBrowserModule.h"
#include "Editor.h"
#include "Engine/SkeletalMeshSocket.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "Math/Transform.h"
#include "ReferenceSkeleton.h"
#include "SGEditor/SGPluginStyle.h"
#include "SGLog/SGLog.h"
#define LOCTEXT_NAMESPACE "SGContentBrowserExtension_SkeletalMesh"
void FSGContentBrowserExtension_SkeletalMesh::Register()
{
FContentBrowserModule& ContentBrowserModule{
FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"))
};
TArray<FContentBrowserMenuExtender_SelectedAssets>& ContextMenuDelegates{
ContentBrowserModule.GetAllAssetViewContextMenuExtenders()
};
ContextMenuDelegates.Add(FContentBrowserMenuExtender_SelectedAssets::CreateStatic(&OnExtendAssetSelectionMenu));
}
TSharedRef<FExtender> FSGContentBrowserExtension_SkeletalMesh::OnExtendAssetSelectionMenu(
const TArray<FAssetData>& SelectedAssets)
{
TSharedRef<FExtender> Extender{MakeShared<FExtender>()};
Extender->AddMenuExtension(
"CommonAssetActions",
EExtensionHook::After,
nullptr,
FMenuExtensionDelegate::CreateStatic(&AssetExtenderCallback, SelectedAssets)
);
return MoveTemp(Extender);
}
void FSGContentBrowserExtension_SkeletalMesh::AssetExtenderCallback(
FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets)
{
MenuBuilder.BeginSection(FName{TEXT("SenseGloveSection")}, LOCTEXT("SenseGloveHeading", "SenseGlove"));
{
for (const FAssetData& Asset: SelectedAssets)
{
if (!Asset.IsRedirector()
&& FName{*Asset.AssetClassPath.ToString()} != NAME_Class
&& !(Asset.PackageFlags & PKG_FilterEditorOnly))
{
if (Asset.GetClass()->IsChildOf(USkeletalMesh::StaticClass()))
{
MenuBuilder.AddMenuEntry(
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
FUIAction{
FExecuteAction::CreateLambda([SelectedAssets]()-> void
{
for (const FAssetData& Asset: SelectedAssets)
{
USkeletalMesh* SkeletalMesh{Cast<USkeletalMesh>(Asset.GetAsset())};
if (!IsValid(SkeletalMesh))
{
continue;
}
AddSenseGloveSockets(SkeletalMesh);
}
})
},
NAME_None,
EUserInterfaceActionType::Button,
NAME_None);
}
}
}
}
MenuBuilder.EndSection();
}
void FSGContentBrowserExtension_SkeletalMesh::AddSenseGloveSockets(USkeletalMesh* SkeletalMesh)
{
if (!ensureAlwaysMsgf(IsValid(SkeletalMesh), TEXT("Invalid SkeletalMesh!")))
{
return;
}
const USkeleton* Skeleton{SkeletalMesh->GetSkeleton()};
if (!ensureAlwaysMsgf(IsValid(Skeleton), TEXT("Invalid Skeleton!")))
{
return;
}
USkeletalMeshSocket* GrabSocket{NewObject<USkeletalMeshSocket>()};
if (!IsValid(GrabSocket))
{
// show proper messages
SGLOG("Failed to create new socket!");
}
GrabSocket->SocketName = FName(TEXT("CodeGrabSocket"));
GrabSocket->BoneName = FName(TEXT("hand_l"));
GrabSocket->RelativeLocation = FVector(0.0f, 0.0f, 0.0f);
GrabSocket->RelativeRotation = FRotator(0.0f, 0.0f, 0.0f);
GrabSocket->RelativeScale = FVector(1.0f, 1.0f, 1.0f);
SkeletalMesh->AddSocket(GrabSocket, true);
const bool bMarkedSkeletalMeshPackageDirty = SkeletalMesh->MarkPackageDirty();
const bool bMarkedSkeletonPackageDirty = Skeleton->MarkPackageDirty();
SGLOG("Socket added to hand_l?", bMarkedSkeletalMeshPackageDirty, bMarkedSkeletonPackageDirty);
if (bMarkedSkeletalMeshPackageDirty && bMarkedSkeletonPackageDirty)
{
FAssetRegistryModule::AssetCreated(GrabSocket);
FEditorDelegates::RefreshEditor.Broadcast();
// Log success
SGLOG("Create new socket!");
}
else
{
// Log errors
SGLOG("Failed to create new socket 2!");
}
// Maybe we try to add them to this?
FReferenceSkeleton ReferenceSkeleton{Skeleton->GetReferenceSkeleton()};
FReferenceSkeletonModifier SkeletonModifier{ReferenceSkeleton, Skeleton};
}
#undef LOCTEXT_NAMESPACE
@@ -1,131 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGContentBrowserExtension_Skeleton.h"
#include "AssetRegistry/AssetData.h"
#include "ContentBrowserDelegates.h"
#include "ContentBrowserModule.h"
#include "Engine/SkeletalMeshSocket.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "Math/Transform.h"
#include "ReferenceSkeleton.h"
#include "SGEditor/SGPluginStyle.h"
#include "SGLog/SGLog.h"
#define LOCTEXT_NAMESPACE "SGContentBrowserExtension_Skeleton"
void FSGContentBrowserExtension_Skeleton::Register()
{
FContentBrowserModule& ContentBrowserModule{
FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"))
};
TArray<FContentBrowserMenuExtender_SelectedAssets>& ContextMenuDelegates{
ContentBrowserModule.GetAllAssetViewContextMenuExtenders()
};
ContextMenuDelegates.Add(FContentBrowserMenuExtender_SelectedAssets::CreateStatic(&OnExtendAssetSelectionMenu));
}
TSharedRef<FExtender> FSGContentBrowserExtension_Skeleton::OnExtendAssetSelectionMenu(
const TArray<FAssetData>& SelectedAssets)
{
TSharedRef<FExtender> Extender{MakeShared<FExtender>()};
Extender->AddMenuExtension(
"CommonAssetActions",
EExtensionHook::After,
nullptr,
FMenuExtensionDelegate::CreateStatic(&AssetExtenderCallback, SelectedAssets)
);
return MoveTemp(Extender);
}
void FSGContentBrowserExtension_Skeleton::AssetExtenderCallback(
FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets)
{
MenuBuilder.BeginSection(FName{TEXT("SenseGlove")}, LOCTEXT("SenseGloveHeading", "SenseGlove"));
{
for (const FAssetData& Asset: SelectedAssets)
{
if (!Asset.IsRedirector()
&& FName{*Asset.AssetClassPath.ToString()} != NAME_Class
&& !(Asset.PackageFlags & PKG_FilterEditorOnly))
{
if (Asset.GetClass()->IsChildOf(USkeleton::StaticClass()))
{
MenuBuilder.AddMenuEntry(
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
FUIAction{
FExecuteAction::CreateLambda([SelectedAssets]()-> void
{
for (const FAssetData& Asset: SelectedAssets)
{
USkeleton* Skeleton{Cast<USkeleton>(Asset.GetAsset())};
if (!IsValid(Skeleton))
{
continue;
}
AddSenseGloveSockets(Skeleton);
}
})
},
NAME_None,
EUserInterfaceActionType::Button,
NAME_None);
}
}
}
}
MenuBuilder.EndSection();
}
void FSGContentBrowserExtension_Skeleton::AddSenseGloveSockets(USkeleton* Skeleton)
{
if (!ensureAlwaysMsgf(IsValid(Skeleton), TEXT("Invalid Skeleton!")))
{
return;
}
}
#undef LOCTEXT_NAMESPACE
@@ -1,239 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGSkeletalMeshEditor.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "ISkeletalMeshEditor.h"
#include "ISkeletalMeshEditorModule.h"
#include "Modules/ModuleManager.h"
#include "SGEditor/SGAssetTypeActions_SkeletalMesh.h"
#include "SGEditor/SGPluginStyle.h"
#include "SGEditor/SGSkeletalMeshEditorCommands.h"
#define LOCTEXT_NAMESPACE "SkeletalMeshEditor"
struct FSGSkeletalMeshEditor::FImpl
{
/************************
* Member variables
************************/
TSharedPtr<FSGAssetTypeActions_SkeletalMesh> AssetActions;
TSharedPtr<FSGSkeletalMeshEditorCommands> EditorCommands;
TSharedPtr<FExtender> MenuExtender;
TSharedPtr<FExtender> ToolbarExtender;
/************************
* Owner object
************************/
FSGSkeletalMeshEditor* Owner;
/************************
* Constructor / Destructor
************************/
explicit FImpl(FSGSkeletalMeshEditor* InOwner);
~FImpl();
/************************
* Default copy constructor & copy assignment operator
************************/
FImpl(const FImpl& Rhs) = default;
FImpl& operator=(const FImpl& Rhs) = default;
};
TSharedRef<FSGSkeletalMeshEditor> FSGSkeletalMeshEditor::GetInstance()
{
static TSharedPtr<FSGSkeletalMeshEditor> Instance{MakeShared<FSGSkeletalMeshEditor>()};
return Instance.ToSharedRef();
}
FSGSkeletalMeshEditor::FSGSkeletalMeshEditor()
: Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
{
}
FSGSkeletalMeshEditor::~FSGSkeletalMeshEditor() = default;
void FSGSkeletalMeshEditor::Initialize() const
{
//RegisterAssetTypeActions();
RegisterCommands();
ExtendMenu();
ExtendToolbar();
}
void FSGSkeletalMeshEditor::Deinitialize() const
{
UnregisterCommands();
}
void FSGSkeletalMeshEditor::RegisterAssetTypeActions() const
{
if (Pimpl->AssetActions.IsValid())
{
Pimpl->AssetActions.Reset();
}
Pimpl->AssetActions = MakeShared<FSGAssetTypeActions_SkeletalMesh>();
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
AssetTools.RegisterAssetTypeActions(Pimpl->AssetActions.ToSharedRef());
}
void FSGSkeletalMeshEditor::RegisterCommands() const
{
if (Pimpl->EditorCommands.IsValid())
{
Pimpl->EditorCommands.Reset();
}
Pimpl->EditorCommands = MakeShared<FSGSkeletalMeshEditorCommands>();
Pimpl->EditorCommands->RegisterCommands();
}
void FSGSkeletalMeshEditor::UnregisterCommands() const
{
if (!Pimpl->EditorCommands.IsValid())
{
return;
}
Pimpl->EditorCommands->Unregister();
}
void FSGSkeletalMeshEditor::ExtendMenu() const
{
if (Pimpl->MenuExtender.IsValid())
{
Pimpl->MenuExtender.Reset();
}
Pimpl->MenuExtender = MakeShared<FExtender>();
ISkeletalMeshEditorModule& SkeletonEditorModule{
FModuleManager::LoadModuleChecked<ISkeletalMeshEditorModule>("SkeletalMeshEditor")
};
const TSharedPtr<FExtensibilityManager> ExtensibilityManager{
SkeletonEditorModule.GetMenuExtensibilityManager()
};
if (!ensureAlwaysMsgf(ExtensibilityManager.IsValid(), TEXT("Invalid ExtensibilityManager!")))
{
return;
}
Pimpl->MenuExtender->AddMenuExtension(
FName{TEXT("AssetEditorActions")},
EExtensionHook::After,
Pimpl->EditorCommands->CommandList,
FMenuExtensionDelegate::CreateLambda([&](FMenuBuilder MenuBuilder)-> void
{
MenuBuilder.BeginSection(FName{TEXT("SenseGlove")}, LOCTEXT("SenseGloveHeading", "SenseGlove"));
{
MenuBuilder.AddMenuEntry(
Pimpl->EditorCommands->AddSenseGloveSockets,
NAME_None,
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSlateIcon{FSGPluginStyle::GetStyleSetIcon()},
NAME_None);
}
MenuBuilder.EndSection();
}));
ExtensibilityManager->AddExtender(Pimpl->MenuExtender);
}
void FSGSkeletalMeshEditor::ExtendToolbar() const
{
if (Pimpl->ToolbarExtender.IsValid())
{
Pimpl->ToolbarExtender.Reset();
}
Pimpl->ToolbarExtender = MakeShared<FExtender>();
ISkeletalMeshEditorModule& SkeletalMeshEditorModule{
FModuleManager::LoadModuleChecked<ISkeletalMeshEditorModule>("SkeletalMeshEditor")
};
const TSharedPtr<FExtensibilityManager> ExtensibilityManager{
SkeletalMeshEditorModule.GetToolBarExtensibilityManager()
};
if (!ensureAlwaysMsgf(ExtensibilityManager.IsValid(), TEXT("Invalid ExtensibilityManager!")))
{
return;
}
Pimpl->ToolbarExtender->AddToolBarExtension(
FName{TEXT("SkeletalMesh")},
EExtensionHook::After,
Pimpl->EditorCommands->CommandList,
FToolBarExtensionDelegate::CreateLambda([&](FToolBarBuilder& ToolbarBuilder)-> void
{
ToolbarBuilder.BeginSection(FName{TEXT("SenseGlove")});
{
ToolbarBuilder.AddToolBarButton(
Pimpl->EditorCommands->AddSenseGloveSockets,
NAME_None,
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
NAME_None,
FNewMenuDelegate{}
);
}
ToolbarBuilder.EndSection();
}));
ExtensibilityManager->AddExtender(Pimpl->ToolbarExtender);
}
FSGSkeletalMeshEditor::FImpl::FImpl(FSGSkeletalMeshEditor* InOwner)
: Owner(InOwner)
{
}
FSGSkeletalMeshEditor::FImpl::~FImpl() = default;
void FSGSkeletalMeshEditor::FImplDeleter::operator()(const FImpl* P) const
{
delete P;
}
#undef LOCTEXT_NAMESPACE
@@ -1,91 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGSkeletalMeshEditorCommands.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "SGEditor/SGPluginStyle.h"
#define LOCTEXT_NAMESPACE "SkeletalMeshEditorCommands"
FSGSkeletalMeshEditorCommands::FSGSkeletalMeshEditorCommands()
: TCommands<FSGSkeletalMeshEditorCommands>{
TEXT("SGSkeletalMeshEditor"),
NSLOCTEXT("Contexts", "SGSkeletalMeshEditor", "SenseGlove SkeletalMesh Editor"),
NAME_None,
FSGPluginStyle::GetInstance()->GetStyleSetName()
}
{
}
FSGSkeletalMeshEditorCommands::~FSGSkeletalMeshEditorCommands() = default;
void FSGSkeletalMeshEditorCommands::RegisterCommands()
{
if (AddSenseGloveSockets.IsValid())
{
AddSenseGloveSockets.Reset();
}
UI_COMMAND(AddSenseGloveSockets,
"Add SenseGlove Sockets",
"Adds and sets up the SenseGlove grab and touch sockets",
EUserInterfaceActionType::Button,
FInputChord{});
if (CommandList.IsValid())
{
CommandList.Reset();
}
CommandList = MakeShared<FUICommandList>();
CommandList->MapAction(AddSenseGloveSockets,
FExecuteAction::CreateLambda([&]()-> void
{
FMessageDialog::Open(
EAppMsgType::Ok, FText::FromString(
FString{
"The SenseGlove grab and touch sockets have been added."
" If you wish the changes to persist, save the asset now!"
}));
}),
FCanExecuteAction::CreateLambda([&]()-> bool
{
return true;
}),
EUIActionRepeatMode::RepeatDisabled);
}
#undef LOCTEXT_NAMESPACE
@@ -1,91 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGSkeletonEditorCommands.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "SGEditor/SGPluginStyle.h"
#define LOCTEXT_NAMESPACE "SkeletonEditorCommands"
FSGSkeletonEditorCommands::FSGSkeletonEditorCommands()
: TCommands<FSGSkeletonEditorCommands>{
TEXT("SGSkeletonEditor"),
NSLOCTEXT("Contexts", "SGSkeletonEditor", "SenseGlove Skeleton Editor"),
NAME_None,
FSGPluginStyle::GetInstance()->GetStyleSetName()
}
{
}
FSGSkeletonEditorCommands::~FSGSkeletonEditorCommands() = default;
void FSGSkeletonEditorCommands::RegisterCommands()
{
if (AddSenseGloveSockets.IsValid())
{
AddSenseGloveSockets.Reset();
}
UI_COMMAND(AddSenseGloveSockets,
"Add SenseGlove Sockets",
"Adds and sets up the SenseGlove grab and touch sockets",
EUserInterfaceActionType::Button,
FInputChord{});
if (CommandList.IsValid())
{
CommandList.Reset();
}
CommandList = MakeShared<FUICommandList>();
CommandList->MapAction(AddSenseGloveSockets,
FExecuteAction::CreateLambda([&]()-> void
{
FMessageDialog::Open(
EAppMsgType::Ok, FText::FromString(
FString{
"The SenseGlove grab and touch sockets have been added."
" If you wish the changes to persist, save the asset now!"
}));
}),
FCanExecuteAction::CreateLambda([&]()-> bool
{
return true;
}),
EUIActionRepeatMode::RepeatDisabled);
}
#undef LOCTEXT_NAMESPACE
@@ -33,27 +33,26 @@
*/
#include "SGEditor/SGSkeletonEditor.h"
#include "SGEditor/SGSocketsEditor.h"
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "ISkeletonEditor.h"
#include "ISkeletonEditorModule.h"
#include "Modules/ModuleManager.h"
#include "SGEditor/SGAssetTypeActions_Skeleton.h"
// #include "SGEditor/SGAssetTypeActions_Skeleton.h"
#include "SGEditor/SGPluginStyle.h"
#include "SGEditor/SGSkeletonEditorCommands.h"
#include "SGEditor/SGSocketsEditorCommands.h"
#define LOCTEXT_NAMESPACE "SkeletonEditor"
#define LOCTEXT_NAMESPACE "SocketsEditor"
struct FSGSkeletonEditor::FImpl
struct FSGSocketsEditor::FImpl
{
/************************
* Member variables
************************/
TSharedPtr<FSGAssetTypeActions_Skeleton> AssetActions;
TSharedPtr<FSGSkeletonEditorCommands> EditorCommands;
// TSharedPtr<FSGAssetTypeActions_Skeleton> AssetActions;
TSharedPtr<FSGSocketsEditorCommands> EditorCommands;
TSharedPtr<FExtender> MenuExtender;
TSharedPtr<FExtender> ToolbarExtender;
@@ -61,13 +60,13 @@ struct FSGSkeletonEditor::FImpl
* Owner object
************************/
FSGSkeletonEditor* Owner;
FSGSocketsEditor* Owner;
/************************
* Constructor / Destructor
************************/
explicit FImpl(FSGSkeletonEditor* InOwner);
explicit FImpl(FSGSocketsEditor* InOwner);
~FImpl();
/************************
@@ -78,20 +77,20 @@ struct FSGSkeletonEditor::FImpl
FImpl& operator=(const FImpl& Rhs) = default;
};
TSharedRef<FSGSkeletonEditor> FSGSkeletonEditor::GetInstance()
TSharedRef<FSGSocketsEditor> FSGSocketsEditor::GetInstance()
{
static TSharedPtr<FSGSkeletonEditor> Instance{MakeShared<FSGSkeletonEditor>()};
static TSharedPtr<FSGSocketsEditor> Instance{MakeShared<FSGSocketsEditor>()};
return Instance.ToSharedRef();
}
FSGSkeletonEditor::FSGSkeletonEditor()
FSGSocketsEditor::FSGSocketsEditor()
: Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
{
}
FSGSkeletonEditor::~FSGSkeletonEditor() = default;
FSGSocketsEditor::~FSGSocketsEditor() = default;
void FSGSkeletonEditor::Initialize() const
void FSGSocketsEditor::Initialize() const
{
//RegisterAssetTypeActions();
RegisterCommands();
@@ -99,35 +98,35 @@ void FSGSkeletonEditor::Initialize() const
ExtendToolbar();
}
void FSGSkeletonEditor::Deinitialize() const
void FSGSocketsEditor::Deinitialize() const
{
UnregisterCommands();
}
void FSGSkeletonEditor::RegisterAssetTypeActions() const
void FSGSocketsEditor::RegisterAssetTypeActions() const
{
if (Pimpl->AssetActions.IsValid())
{
Pimpl->AssetActions.Reset();
}
Pimpl->AssetActions = MakeShared<FSGAssetTypeActions_Skeleton>();
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
AssetTools.RegisterAssetTypeActions(Pimpl->AssetActions.ToSharedRef());
// if (Pimpl->AssetActions.IsValid())
// {
// Pimpl->AssetActions.Reset();
// }
// Pimpl->AssetActions = MakeShared<FSGAssetTypeActions_Skeleton>();
//
// IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
//
// AssetTools.RegisterAssetTypeActions(Pimpl->AssetActions.ToSharedRef());
}
void FSGSkeletonEditor::RegisterCommands() const
void FSGSocketsEditor::RegisterCommands() const
{
if (Pimpl->EditorCommands.IsValid())
{
Pimpl->EditorCommands.Reset();
}
Pimpl->EditorCommands = MakeShared<FSGSkeletonEditorCommands>();
Pimpl->EditorCommands = MakeShared<FSGSocketsEditorCommands>();
Pimpl->EditorCommands->RegisterCommands();
}
void FSGSkeletonEditor::UnregisterCommands() const
void FSGSocketsEditor::UnregisterCommands() const
{
if (!Pimpl->EditorCommands.IsValid())
{
@@ -136,7 +135,7 @@ void FSGSkeletonEditor::UnregisterCommands() const
Pimpl->EditorCommands->Unregister();
}
void FSGSkeletonEditor::ExtendMenu() const
void FSGSocketsEditor::ExtendMenu() const
{
if (Pimpl->MenuExtender.IsValid())
{
@@ -144,14 +143,30 @@ void FSGSkeletonEditor::ExtendMenu() const
}
Pimpl->MenuExtender = MakeShared<FExtender>();
ISkeletonEditorModule& SkeletalMeshEditorModule{
FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletalMeshEditor")
};
ISkeletonEditorModule& SkeletonEditorModule{
FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor")
};
const TSharedPtr<FExtensibilityManager> ExtensibilityManager{
const TSharedPtr<FExtensibilityManager> SkeletalMeshExtensibilityManager{
SkeletalMeshEditorModule.GetMenuExtensibilityManager()
};
const TSharedPtr<FExtensibilityManager> SkeletonExtensibilityManager{
SkeletonEditorModule.GetMenuExtensibilityManager()
};
if (!ensureAlwaysMsgf(ExtensibilityManager.IsValid(), TEXT("Invalid ExtensibilityManager!")))
if (!ensureAlwaysMsgf(SkeletonExtensibilityManager.IsValid(),
TEXT("Invalid SkeletonExtensibilityManager!")))
{
return;
}
if (!ensureAlwaysMsgf(SkeletalMeshExtensibilityManager.IsValid(),
TEXT("Invalid SkeletalMeshExtensibilityManager!")))
{
return;
}
@@ -165,21 +180,31 @@ void FSGSkeletonEditor::ExtendMenu() const
MenuBuilder.BeginSection(FName{TEXT("SenseGlove")}, LOCTEXT("SenseGloveHeading", "SenseGlove"));
{
MenuBuilder.AddMenuEntry(
Pimpl->EditorCommands->AddSenseGloveSockets,
Pimpl->EditorCommands->SenseGloveAddSockets,
NAME_None,
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT("SenseGloveAddSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
"SenseGloveAddSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
NAME_None);
MenuBuilder.AddMenuEntry(
Pimpl->EditorCommands->SenseGloveClearExistingSockets,
NAME_None,
LOCTEXT("SenseGloveClearExistingSocketsLabel", "Clear Existing Sockets"),
LOCTEXT(
"SenseGloveClearSocketsToolTip", "Clears all sockets; SenseGlove or otherwise"),
FSlateIcon{FSGPluginStyle::GetStyleSetIcon()},
NAME_None);
}
MenuBuilder.EndSection();
}));
ExtensibilityManager->AddExtender(Pimpl->MenuExtender);
SkeletalMeshExtensibilityManager->AddExtender(Pimpl->MenuExtender);
SkeletonExtensibilityManager->AddExtender(Pimpl->MenuExtender);
}
void FSGSkeletonEditor::ExtendToolbar() const
void FSGSocketsEditor::ExtendToolbar() const
{
if (Pimpl->ToolbarExtender.IsValid())
{
@@ -187,20 +212,36 @@ void FSGSkeletonEditor::ExtendToolbar() const
}
Pimpl->ToolbarExtender = MakeShared<FExtender>();
ISkeletonEditorModule& SkeletalMeshEditorModule{
FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletalMeshEditor")
};
ISkeletonEditorModule& SkeletonEditorModule{
FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor")
};
const TSharedPtr<FExtensibilityManager> ExtensibilityManager{
const TSharedPtr<FExtensibilityManager> SkeletalMeshExtensibilityManager{
SkeletalMeshEditorModule.GetToolBarExtensibilityManager()
};
const TSharedPtr<FExtensibilityManager> SkeletonExtensibilityManager{
SkeletonEditorModule.GetToolBarExtensibilityManager()
};
if (!ensureAlwaysMsgf(ExtensibilityManager.IsValid(), TEXT("Invalid ExtensibilityManager!")))
if (!ensureAlwaysMsgf(SkeletonExtensibilityManager.IsValid(),
TEXT("Invalid SkeletonExtensibilityManager!")))
{
return;
}
if (!ensureAlwaysMsgf(SkeletalMeshExtensibilityManager.IsValid(),
TEXT("Invalid SkeletalMeshExtensibilityManager!")))
{
return;
}
Pimpl->ToolbarExtender->AddToolBarExtension(
FName{TEXT("Skeleton")},
FName{TEXT("SkeletalMesh")},
EExtensionHook::After,
Pimpl->EditorCommands->CommandList,
FToolBarExtensionDelegate::CreateLambda([&](FToolBarBuilder& ToolbarBuilder)-> void
@@ -208,11 +249,22 @@ void FSGSkeletonEditor::ExtendToolbar() const
ToolbarBuilder.BeginSection(FName{TEXT("SenseGlove")});
{
ToolbarBuilder.AddToolBarButton(
Pimpl->EditorCommands->AddSenseGloveSockets,
Pimpl->EditorCommands->SenseGloveAddSockets,
NAME_None,
LOCTEXT("AddSenseGloveSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT("SenseGloveAddSocketsLabel", "Add SenseGlove Sockets"),
LOCTEXT(
"AddSenseGloveSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
"SenseGloveAddSocketsToolTip", "Adds and sets up the SenseGlove grab and touch sockets"),
FSGPluginStyle::GetStyleSetIcon(),
NAME_None,
FNewMenuDelegate{}
);
ToolbarBuilder.AddToolBarButton(
Pimpl->EditorCommands->SenseGloveClearExistingSockets,
NAME_None,
LOCTEXT("SenseGloveClearExistingSocketsLabel", "Clear Existing Sockets"),
LOCTEXT(
"SenseGloveClearSocketsToolTip", "Clears all sockets; SenseGlove or otherwise"),
FSGPluginStyle::GetStyleSetIcon(),
NAME_None,
FNewMenuDelegate{}
@@ -221,17 +273,18 @@ void FSGSkeletonEditor::ExtendToolbar() const
ToolbarBuilder.EndSection();
}));
ExtensibilityManager->AddExtender(Pimpl->ToolbarExtender);
SkeletalMeshExtensibilityManager->AddExtender(Pimpl->ToolbarExtender);
SkeletonExtensibilityManager->AddExtender(Pimpl->ToolbarExtender);
}
FSGSkeletonEditor::FImpl::FImpl(FSGSkeletonEditor* InOwner)
FSGSocketsEditor::FImpl::FImpl(FSGSocketsEditor* InOwner)
: Owner(InOwner)
{
}
FSGSkeletonEditor::FImpl::~FImpl() = default;
FSGSocketsEditor::FImpl::~FImpl() = default;
void FSGSkeletonEditor::FImplDeleter::operator()(const FImpl* P) const
void FSGSocketsEditor::FImplDeleter::operator()(const FImpl* P) const
{
delete P;
}
@@ -0,0 +1,224 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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 "SGEditor/SGSocketsEditorCommands.h"
#include "Animation/Skeleton.h"
#include "Containers/UnrealString.h"
#include "Engine/SkeletalMesh.h"
#include "Framework/Commands/UIAction.h"
#include "GenericPlatform/GenericPlatformMisc.h"
#include "Internationalization/Text.h"
#include "Misc/MessageDialog.h"
#include "UObject/Object.h"
#include "SGEditor/SGAssetUtils.h"
#include "SGEditor/SGPluginStyle.h"
#define LOCTEXT_NAMESPACE "SocketsEditorCommands"
struct FSGSocketsEditorCommands::FImpl
{
/************************
* Static methods
************************/
static void TryAddSenseGloveSockets();
static void TryClearExistingSockets();
};
void FSGSocketsEditorCommands::FImpl::TryAddSenseGloveSockets()
{
const FText ConfirmationDialogText{
LOCTEXT("SenseGloveAddSocketsConfirmation",
"Do you want to add the SenseGlove sockets?")
};
const EAppReturnType::Type DialogResult{
FMessageDialog::Open(EAppMsgType::YesNo, ConfirmationDialogText)
};
if (DialogResult != EAppReturnType::Yes)
{
return;
}
UObject* EditedAsset{FSGAssetUtils::GetEditedAsset()};
USkeletalMesh* EditedSkeletalMesh{Cast<USkeletalMesh>(EditedAsset)};
USkeleton* EditedSkeleton{Cast<USkeleton>(EditedAsset)};
bool bAddedSenseGloveSockets = false;
if (IsValid(EditedSkeletalMesh))
{
bAddedSenseGloveSockets = FSGAssetUtils::AddSenseGloveSockets(EditedSkeletalMesh);
}
else if (IsValid(EditedSkeleton))
{
bAddedSenseGloveSockets = FSGAssetUtils::AddSenseGloveSockets(EditedSkeleton);
}
if (bAddedSenseGloveSockets)
{
const FText ResultDialogText{
LOCTEXT("SenseGloveAddSocketsResultSuccess",
"Successfully added the SenseGlove grab and touch sockets. If you wish the changes to persist, save"
" the modified asset(s) now!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
else
{
const FText ResultDialogText{
LOCTEXT("SenseGloveAddSocketsResultSuccessFailed",
"Failed to add the SenseGlove sockets!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
}
void FSGSocketsEditorCommands::FImpl::TryClearExistingSockets()
{
const FText ConfirmationDialogText{
LOCTEXT("SenseGloveClearExistingSocketsConfirmation",
"Are you sure you want to clear all the existing sockets? This cannot be undone!")
};
const EAppReturnType::Type DialogResult{
FMessageDialog::Open(EAppMsgType::YesNo, ConfirmationDialogText)
};
if (DialogResult != EAppReturnType::Yes)
{
return;
}
UObject* EditedAsset{FSGAssetUtils::GetEditedAsset()};
USkeletalMesh* EditedSkeletalMesh{Cast<USkeletalMesh>(EditedAsset)};
USkeleton* EditedSkeleton{Cast<USkeleton>(EditedAsset)};
bool bClearedExistingSockets = false;
if (IsValid(EditedSkeletalMesh))
{
bClearedExistingSockets = FSGAssetUtils::ClearExistingSockets(EditedSkeletalMesh);
}
else if (IsValid(EditedSkeleton))
{
bClearedExistingSockets = FSGAssetUtils::ClearExistingSockets(EditedSkeleton);
}
if (bClearedExistingSockets)
{
const FText ResultDialogText{
LOCTEXT("SenseGloveClearExistingSocketsResultSuccess",
"Successfully cleared all the existing sockets! If you wish the changes to persist, save the"
" modified asset(s) now!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
else
{
const FText ResultDialogText{
LOCTEXT("SenseGloveClearExistingSocketsResultSuccessFailed",
"Failed to clear all the existing sockets!")
};
FMessageDialog::Open(EAppMsgType::Ok, ResultDialogText);
}
}
FSGSocketsEditorCommands::FSGSocketsEditorCommands()
: TCommands<FSGSocketsEditorCommands>{
TEXT("SGSocketsEditor"),
NSLOCTEXT("Contexts", "SGSocketsEditor", "SenseGlove Sockets Editor"),
NAME_None,
FSGPluginStyle::GetInstance()->GetStyleSetName()
}
{
}
FSGSocketsEditorCommands::~FSGSocketsEditorCommands() = default;
void FSGSocketsEditorCommands::RegisterCommands()
{
if (CommandList.IsValid())
{
CommandList.Reset();
}
CommandList = MakeShared<FUICommandList>();
if (SenseGloveAddSockets.IsValid())
{
SenseGloveAddSockets.Reset();
}
if (SenseGloveClearExistingSockets.IsValid())
{
SenseGloveClearExistingSockets.Reset();
}
UI_COMMAND(SenseGloveAddSockets,
"Add SenseGlove Sockets",
"Adds and sets up the SenseGlove grab and touch sockets",
EUserInterfaceActionType::Button,
FInputChord{});
UI_COMMAND(SenseGloveClearExistingSockets,
"Clear Existing Sockets",
"Clears all the existing sockets; SenseGlove or otherwise",
EUserInterfaceActionType::Button,
FInputChord{});
CommandList->MapAction(SenseGloveAddSockets,
FExecuteAction::CreateLambda([&]()-> void
{
FImpl::TryAddSenseGloveSockets();
}),
FCanExecuteAction::CreateLambda([&]()-> bool
{
return true;
}),
EUIActionRepeatMode::RepeatDisabled);
CommandList->MapAction(SenseGloveClearExistingSockets,
FExecuteAction::CreateLambda([&]()-> void
{
FImpl::TryClearExistingSockets();
}),
FCanExecuteAction::CreateLambda([&]()-> bool
{
return true;
}),
EUIActionRepeatMode::RepeatDisabled);
}
#undef LOCTEXT_NAMESPACE
@@ -35,11 +35,9 @@
#include "SenseGloveEditorModule.h"
#include "SGEditor/SGContentBrowserExtension_SkeletalMesh.h"
#include "SGEditor/SGContentBrowserExtension_Skeleton.h"
#include "SGEditor/SGContentBrowserExtension.h"
#include "SGEditor/SGPluginStyle.h"
#include "SGEditor/SGSkeletalMeshEditor.h"
#include "SGEditor/SGSkeletonEditor.h"
#include "SGEditor/SGSocketsEditor.h"
#include "SGLog/SGLog.h"
#define LOCTEXT_NAMESPACE "FSenseGloveEditorModule"
@@ -49,10 +47,8 @@ void FSenseGloveEditorModule::StartupModule()
SGLOG("Starting up SenseGloveEditor module...");
FSGPluginStyle::GetInstance()->Initialize();
FSGContentBrowserExtension_SkeletalMesh::Register();
FSGContentBrowserExtension_Skeleton::Register();
FSGSkeletalMeshEditor::GetInstance()->Initialize();
FSGSkeletonEditor::GetInstance()->Initialize();
FSGContentBrowserExtension::Register();
FSGSocketsEditor::GetInstance()->Initialize();
}
void FSenseGloveEditorModule::PreUnloadCallback()
@@ -69,8 +65,7 @@ void FSenseGloveEditorModule::ShutdownModule()
{
SGLOG("Shutting down SenseGloveEditor module...");
FSGSkeletalMeshEditor::GetInstance()->Deinitialize();
FSGSkeletonEditor::GetInstance()->Deinitialize();
FSGSocketsEditor::GetInstance()->Deinitialize();
FSGPluginStyle::GetInstance()->Deinitialize();
}
@@ -50,7 +50,7 @@ class IToolkitHost;
class UClass;
class UObject;
class FSGAssetTypeActions_SkeletalMesh : public FAssetTypeActions_Base
class SENSEGLOVEEDITOR_API FSGAssetTypeActions_SkeletalMesh : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override;
@@ -50,7 +50,7 @@ class IToolkitHost;
class UClass;
class UObject;
class FSGAssetTypeActions_Skeleton : public FAssetTypeActions_Base
class SENSEGLOVEEDITOR_API FSGAssetTypeActions_Skeleton : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override;
@@ -36,23 +36,37 @@
#pragma once
#include "Containers/Array.h"
#include "HAL/Platform.h"
#include "Templates/SharedPointer.h"
struct FAssetData;
class FMenuBuilder;
class IAssetEditorInstance;
class UAssetEditorSubsystem;
class USkeletalMesh;
class USkeleton;
class UObject;
class FSGContentBrowserExtension_SkeletalMesh
class SENSEGLOVEEDITOR_API FSGAssetUtils final
{
public:
static void Register();
static UAssetEditorSubsystem* GetAssetEditorSubsystem();
static TSharedRef<FExtender> OnExtendAssetSelectionMenu(const TArray<FAssetData>& SelectedAssets);
static void AssetExtenderCallback(FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets);
static UObject* GetEditedAsset();
static void AddSenseGloveSockets(USkeletalMesh* SkeletalMesh);
static bool IsAssetEditorOpenForAsset(UObject* Asset);
static TArray<IAssetEditorInstance*> FindEditorsForAsset(UObject* Asset);
static bool OpenEditorForAsset(UObject* Asset);
static int32 CloseAllEditorsForAsset(UObject* Asset);
static bool AddSenseGloveSockets(USkeletalMesh* SkeletalMesh);
static bool AddSenseGloveSockets(USkeleton* Skeleton);
static bool ClearExistingSockets(USkeletalMesh* SkeletalMesh);
static bool ClearExistingSockets(USkeleton* Skeleton);
private:
FSGContentBrowserExtension_SkeletalMesh() = delete;
virtual ~FSGContentBrowserExtension_SkeletalMesh() = delete;
struct FImpl;
private:
FSGAssetUtils() = delete;
virtual ~FSGAssetUtils() = delete;
};
@@ -40,19 +40,21 @@
struct FAssetData;
class FMenuBuilder;
class USkeleton;
class USkeletalMesh;
class FSGContentBrowserExtension_Skeleton
class SENSEGLOVEEDITOR_API FSGContentBrowserExtension
{
public:
static void Register();
protected:
static TSharedRef<FExtender> OnExtendAssetSelectionMenu(const TArray<FAssetData>& SelectedAssets);
static void AssetExtenderCallback(FMenuBuilder& MenuBuilder, const TArray<FAssetData> SelectedAssets);
static void AddSenseGloveSockets(USkeleton* Skeleton);
private:
struct FImpl;
private:
FSGContentBrowserExtension_Skeleton() = delete;
virtual ~FSGContentBrowserExtension_Skeleton() = delete;
FSGContentBrowserExtension() = delete;
virtual ~FSGContentBrowserExtension() = delete;
};
@@ -40,7 +40,7 @@
class ISlateStyle;
class FSGPluginStyle final : public FSlateStyleSet
class SENSEGLOVEEDITOR_API FSGPluginStyle final : public FSlateStyleSet
{
public:
FORCEINLINE static TSharedRef<FSGPluginStyle> GetInstance()
@@ -49,12 +49,6 @@ public:
return Instance.ToSharedRef();
}
FORCEINLINE static const FSlateStyleSet& GetStyleSet()
{
const FSlateStyleSet& StyleSet{GetInstance()->GetStyleSet()};
return StyleSet;
}
FORCEINLINE static const FName& GetStyleSetIconName()
{
static const FName IconName{TEXT("SenseGlove.Icon")};
@@ -1,73 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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
*
*
*/
#pragma once
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "Templates/SharedPointer.h"
class FSGSkeletalMeshEditor
{
public:
static TSharedRef<FSGSkeletalMeshEditor> GetInstance();
private:
struct FImpl;
struct FImplDeleter
{
void operator()(const FImpl* P) const;
};
TUniquePtr<FImpl, FImplDeleter> Pimpl;
FImplDeleter PimplDeleter;
public:
FSGSkeletalMeshEditor();
virtual ~FSGSkeletalMeshEditor();
public:
void Initialize() const;
void Deinitialize() const;
void RegisterAssetTypeActions() const;
void RegisterCommands() const;
void UnregisterCommands() const;
void ExtendMenu() const;
void ExtendToolbar() const;
};
@@ -1,54 +0,0 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2024 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
*
*
*/
#pragma once
#include "Framework/Commands/Commands.h"
#include "Framework/Commands/UICommandList.h"
#include "Templates/SharedPointer.h"
class FSGSkeletonEditorCommands final : public TCommands<FSGSkeletonEditorCommands>
{
public:
TSharedPtr<FUICommandList> CommandList;
TSharedPtr<FUICommandInfo> AddSenseGloveSockets;
public:
FSGSkeletonEditorCommands();
virtual ~FSGSkeletonEditorCommands() override;
public:
virtual void RegisterCommands() override;
};
@@ -38,10 +38,10 @@
#include "Framework/MultiBox/MultiBoxExtender.h"
#include "Templates/SharedPointer.h"
class FSGSkeletonEditor
class SENSEGLOVEEDITOR_API FSGSocketsEditor
{
public:
static TSharedRef<FSGSkeletonEditor> GetInstance();
static TSharedRef<FSGSocketsEditor> GetInstance();
private:
struct FImpl;
@@ -55,8 +55,8 @@ private:
FImplDeleter PimplDeleter;
public:
FSGSkeletonEditor();
virtual ~FSGSkeletonEditor();
FSGSocketsEditor();
virtual ~FSGSocketsEditor();
public:
void Initialize() const;
@@ -39,15 +39,19 @@
#include "Framework/Commands/UICommandList.h"
#include "Templates/SharedPointer.h"
class FSGSkeletalMeshEditorCommands final : public TCommands<FSGSkeletalMeshEditorCommands>
class SENSEGLOVEEDITOR_API FSGSocketsEditorCommands final : public TCommands<FSGSocketsEditorCommands>
{
public:
TSharedPtr<FUICommandList> CommandList;
TSharedPtr<FUICommandInfo> AddSenseGloveSockets;
TSharedPtr<FUICommandInfo> SenseGloveAddSockets;
TSharedPtr<FUICommandInfo> SenseGloveClearExistingSockets;
private:
struct FImpl;
public:
FSGSkeletalMeshEditorCommands();
virtual ~FSGSkeletalMeshEditorCommands() override;
FSGSocketsEditorCommands();
virtual ~FSGSocketsEditorCommands() override;
public:
virtual void RegisterCommands() override;
@@ -56,7 +56,15 @@ public class SenseGloveEditor : ModuleRules
"Slate",
"SlateCore",
"UnrealEd",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"SenseGloveLog",
"SenseGloveSettings",
"SenseGloveTypes",
}
);
}
@@ -37,7 +37,8 @@
FSGVirtualHandGrabSettings::FSGVirtualHandGrabSettings()
: FSGVirtualHandGrabSettings{
FName{TEXT("GrabPalmAttachPoint")},
FName{TEXT("GrabAttachPoint")},
FTransform{FQuat::Identity, FVector{0.0f, 5.0f, -6.61557f}},
FVector{0.04f, 0.04f, 0.04f},
FName{TEXT("GrabThumbCollider")},
FName{TEXT("GrabIndexCollider")},
@@ -47,12 +48,14 @@ FSGVirtualHandGrabSettings::FSGVirtualHandGrabSettings()
}
FSGVirtualHandGrabSettings::FSGVirtualHandGrabSettings(
const FName& InPalmAttachPointSocketName,
const FName& InGrabAttachPointSocketName,
const FTransform& InGrabAttachPointSocketTransform,
const FVector& InDefaultColliderSize,
const FName& InThumbColliderSocketName,
const FName& InIndexColliderSocketName,
const FName& InMiddleColliderSocketName)
: PalmAttachPointSocketName{InPalmAttachPointSocketName},
: GrabAttachPointSocketName{InGrabAttachPointSocketName},
GrabAttachPointSocketTransform{InGrabAttachPointSocketTransform},
DefaultColliderSize{InDefaultColliderSize},
ThumbColliderSocketName{InThumbColliderSocketName},
IndexColliderSocketName{InIndexColliderSocketName},
@@ -35,6 +35,8 @@
#include "SGSettings/SGVirtualHandMeshSettings.h"
#include "UObject/UnrealNames.h"
#include "Engine/SkeletalMesh.h"
FSGVirtualHandMeshSettings::FSGVirtualHandMeshSettings()
@@ -35,6 +35,8 @@
#pragma once
#include "HAL/Platform.h"
#include "Math/Color.h"
#include "UObject/ObjectMacros.h"
#include "SGDebugGizmoSettings.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
#include "SGHandTrackingSettings.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
#include "SGInitializationSettings.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
#include "SGSettings/SGGloveTrackingSettings.h"
@@ -35,6 +35,8 @@
#pragma once
#include "HAL/Platform.h"
#include "Math/Rotator.h"
#include "UObject/ObjectMacros.h"
#include "UObject/SoftObjectPtr.h"
@@ -35,6 +35,9 @@
#pragma once
#include "HAL/Platform.h"
#include "Math/Color.h"
#include "Math/Vector.h"
#include "UObject/ObjectMacros.h"
#include "SGTypes/SGDebugTypes.h"
@@ -35,6 +35,9 @@
#pragma once
#include "Math/Transform.h"
#include "Math/Vector.h"
#include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/SoftObjectPtr.h"
@@ -52,7 +55,10 @@ struct SENSEGLOVESETTINGS_API FSGVirtualHandGrabSettings
public:
UPROPERTY(Config, EditDefaultsOnly, Category="Grab")
FName PalmAttachPointSocketName;
FName GrabAttachPointSocketName;
UPROPERTY(Config, EditDefaultsOnly, Category="Grab")
FTransform GrabAttachPointSocketTransform;
UPROPERTY(Config, EditDefaultsOnly, Category="Grab")
FVector DefaultColliderSize;
@@ -70,7 +76,8 @@ public:
FSGVirtualHandGrabSettings();
FSGVirtualHandGrabSettings(
const FName& InPalmAttachPointSocketName,
const FName& InGrabAttachPointSocketName,
const FTransform& InGrabAttachPointSocketTransform,
const FVector& InDefaultColliderSize,
const FName& InThumbColliderSocketName,
const FName& InIndexColliderSocketName,
@@ -35,6 +35,12 @@
#pragma once
#include "Containers/Array.h"
#include "Containers/Map.h"
#include "Engine/SkeletalMesh.h"
#include "Math/Rotator.h"
#include "Math/Transform.h"
#include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/SoftObjectPtr.h"
@@ -35,6 +35,8 @@
#pragma once
#include "Math/Vector.h"
#include "UObject/NameTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/SoftObjectPtr.h"
@@ -36,6 +36,8 @@
#pragma once
#include "InputCoreTypes.h"
#include "Math/Rotator.h"
#include "Math/Vector.h"
#include "UObject/ObjectMacros.h"
#include "SGSettings/SGDebugGizmoSettings.h"
@@ -899,10 +899,12 @@ USGHandPose* FSGXRTracker::FImpl::GetHandPose(const bool bRight)
FTransform FSGXRTracker::FImpl::GetMeshRawBoneRefTransform(const bool bRight, const FName& BoneName)
{
const FSGVirtualHandMeshSettings& MeshSettings{GetVirtualHandSettings().MeshSettings};
const TSoftObjectPtr<USkeletalMesh>& HandMesh{
bRight
? GetVirtualHandSettings().MeshSettings.LeftHandReferenceMesh
: GetVirtualHandSettings().MeshSettings.RightHandReferenceMesh
? MeshSettings.LeftHandReferenceMesh
: MeshSettings.RightHandReferenceMesh
};
if (HandMesh.IsValid())
@@ -924,26 +926,24 @@ FTransform FSGXRTracker::FImpl::GetMeshRawBoneRefTransform(const bool bRight, co
return Transform;
}
const FSGVirtualHandMeshSettings& Settings{GetVirtualHandSettings().MeshSettings};
ensureAlwaysMsgf(
bRight
? Settings.RightHandDefaultReferenceBoneTransforms.Contains(BoneName)
: Settings.LeftHandDefaultReferenceBoneTransforms.Contains(BoneName),
? MeshSettings.RightHandDefaultReferenceBoneTransforms.Contains(BoneName)
: MeshSettings.LeftHandDefaultReferenceBoneTransforms.Contains(BoneName),
TEXT("Invalid bone name '%s'!"), *BoneName.ToString());
const FTransform& Transform{
bRight
? Settings.RightHandDefaultReferenceBoneTransforms[BoneName]
: Settings.LeftHandDefaultReferenceBoneTransforms[BoneName]
? MeshSettings.RightHandDefaultReferenceBoneTransforms[BoneName]
: MeshSettings.LeftHandDefaultReferenceBoneTransforms[BoneName]
};
return Transform;
}
FTransform FSGXRTracker::FImpl::GetMeshWristChildBoneRefTransform(const bool bRight, const FName& BoneName)
{
FQuat RootRotationCorrection{
GetVirtualHandSettings().MeshSettings.RootBoneRotationCorrection
};
const FSGVirtualHandMeshSettings& MeshSettings{GetVirtualHandSettings().MeshSettings};
FQuat RootRotationCorrection{MeshSettings.RootBoneRotationCorrection};
const FTransform& RootBoneRefTransform{GetMeshRawBoneRefTransform(bRight, EHandKeypoint::Wrist)};
const FTransform& RawTransform{GetMeshRawBoneRefTransform(bRight, BoneName)};
FQuat CorrectedRootBoneRefRotation{MoveTemp(RootRotationCorrection) * RootBoneRefTransform.GetRotation()};
@@ -956,9 +956,8 @@ FTransform FSGXRTracker::FImpl::GetMeshWristChildBoneRefTransform(const bool bRi
FTransform FSGXRTracker::FImpl::GetMeshFingerStartBoneRefTransform(
const bool bRight, const EHandKeypoint Parent, const FName& BoneName)
{
FQuat RootRotationCorrection{
GetVirtualHandSettings().MeshSettings.RootBoneRotationCorrection
};
const FSGVirtualHandMeshSettings& MeshSettings{GetVirtualHandSettings().MeshSettings};
FQuat RootRotationCorrection{MeshSettings.RootBoneRotationCorrection};
const FTransform& RootBoneRefTransform{GetMeshRawBoneRefTransform(bRight, EHandKeypoint::Wrist)};
FQuat CorrectedRootBoneRefRotation{MoveTemp(RootRotationCorrection) * RootBoneRefTransform.GetRotation()};
FTransform CorrectedRootBoneRefTransform{
@@ -35,7 +35,7 @@
#pragma once
#include "CoreTypes.h"
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
UENUM(BlueprintType)
@@ -36,6 +36,7 @@
#pragma once
#include "CoreTypes.h"
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
/**
@@ -35,6 +35,7 @@
#pragma once
#include "Containers/Array.h"
#include "UObject/ObjectMacros.h"
#include "SGFloatArray.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "Containers/Array.h"
#include "UObject/NameTypes.h"
#include "SGNameArray.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "Containers/Array.h"
#include "Math/Quat.h"
#include "SGQuatArray.generated.h"
@@ -35,6 +35,7 @@
#pragma once
#include "Containers/Array.h"
#include "Math/Rotator.h"
#include "SGRotatorArray.generated.h"
@@ -35,7 +35,7 @@
#pragma once
#include "CoreTypes.h"
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
/**
@@ -35,7 +35,7 @@
#pragma once
#include "CoreTypes.h"
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
/**
@@ -35,6 +35,7 @@
#pragma once
#include "HAL/Platform.h"
#include "Math/Vector.h"
#include "SGVectorArray.generated.h"