mirror of
https://github.com/Eragon-Brisingr/UShaderLab.git
synced 2026-09-15 23:04:37 +00:00
Support SL_INTERPOLATOR and local function
This commit is contained in:
133
Source/UShaderLabEditor/Private/ShaderLabVSCodeButton.cpp
Normal file
133
Source/UShaderLabEditor/Private/ShaderLabVSCodeButton.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright UShaderLab. All Rights Reserved.
|
||||
|
||||
#include "ShaderLabVSCodeButton.h"
|
||||
|
||||
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
||||
#include "Framework/MultiBox/MultiBoxExtender.h"
|
||||
#include "HAL/PlatformProcess.h"
|
||||
#include "MaterialEditorModule.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "ShaderCore.h"
|
||||
#include "ShaderLabMaterialInstanceConstant.h"
|
||||
#include "Styling/AppStyle.h"
|
||||
#include "Textures/SlateIcon.h"
|
||||
#include "Toolkits/AssetEditorToolkit.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "ShaderLabVSCode"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogShaderLabVSCode, Log, All);
|
||||
|
||||
namespace ShaderLabVSCodeButton
|
||||
{
|
||||
static FDelegateHandle GExtenderDelegateHandle;
|
||||
|
||||
/** Reverse the ShaderLabPath virtual path (e.g. "/Project/Examples/Basic.usl") to a disk path via the
|
||||
* registered shader mappings (generic — /Project, /Plugin/<any>, /Engine). Empty if unresolved. */
|
||||
static FString ResolveVirtualToDisk(const FString& VirtualPath)
|
||||
{
|
||||
int32 BestKeyLen = -1;
|
||||
FString BestDisk;
|
||||
for (const TPair<FString, FString>& Mapping : AllShaderSourceDirectoryMappings())
|
||||
{
|
||||
if (VirtualPath.StartsWith(Mapping.Key + TEXT("/"), ESearchCase::IgnoreCase) && Mapping.Key.Len() > BestKeyLen)
|
||||
{
|
||||
BestKeyLen = Mapping.Key.Len();
|
||||
BestDisk = Mapping.Value / VirtualPath.RightChop(Mapping.Key.Len() + 1);
|
||||
}
|
||||
}
|
||||
return (BestKeyLen >= 0) ? FPaths::ConvertRelativePathToFull(BestDisk) : FString();
|
||||
}
|
||||
|
||||
static void OpenInVSCode(TWeakObjectPtr<UShaderLabMaterialInstanceConstant> MICWeak)
|
||||
{
|
||||
UShaderLabMaterialInstanceConstant* MIC = MICWeak.Get();
|
||||
if (!MIC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const FString VirtualPath = UShaderLabMaterialInstanceConstant::GetShaderLabPath(MIC);
|
||||
if (VirtualPath.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogShaderLabVSCode, Warning, TEXT("'%s' has no ShaderLabPath."), *MIC->GetName());
|
||||
return;
|
||||
}
|
||||
const FString DiskPath = ResolveVirtualToDisk(VirtualPath);
|
||||
if (DiskPath.IsEmpty() || !FPaths::FileExists(DiskPath))
|
||||
{
|
||||
UE_LOG(LogShaderLabVSCode, Warning, TEXT("Cannot resolve '%s' to an existing file (got '%s')."), *VirtualPath, *DiskPath);
|
||||
return;
|
||||
}
|
||||
|
||||
// `code` is a .cmd on Windows, so launch it through the command interpreter; it opens/reuses VSCode.
|
||||
#if PLATFORM_WINDOWS
|
||||
const FString Exe = TEXT("cmd.exe");
|
||||
const FString Args = FString::Printf(TEXT("/c code \"%s\""), *DiskPath);
|
||||
#else
|
||||
const FString Exe = TEXT("code");
|
||||
const FString Args = FString::Printf(TEXT("\"%s\""), *DiskPath);
|
||||
#endif
|
||||
FProcHandle Proc = FPlatformProcess::CreateProc(*Exe, *Args, /*bLaunchDetached*/ true,
|
||||
/*bLaunchHidden*/ true, /*bLaunchReallyHidden*/ true, nullptr, 0, nullptr, nullptr);
|
||||
if (Proc.IsValid())
|
||||
{
|
||||
FPlatformProcess::CloseProc(Proc);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogShaderLabVSCode, Warning, TEXT("Failed to launch VSCode ('code' on PATH?) for '%s'."), *DiskPath);
|
||||
}
|
||||
}
|
||||
|
||||
/** Context-aware extender: add the button only when a ShaderLab MIC is being edited. */
|
||||
static TSharedRef<FExtender> OnExtendToolbar(const TSharedRef<FUICommandList> Commands, const TArray<UObject*> EditedObjects)
|
||||
{
|
||||
TSharedRef<FExtender> Extender = MakeShared<FExtender>();
|
||||
|
||||
UShaderLabMaterialInstanceConstant* MIC = nullptr;
|
||||
for (UObject* Object : EditedObjects)
|
||||
{
|
||||
if (UShaderLabMaterialInstanceConstant* Found = Cast<UShaderLabMaterialInstanceConstant>(Object))
|
||||
{
|
||||
MIC = Found;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!MIC || UShaderLabMaterialInstanceConstant::GetShaderLabPath(MIC).IsEmpty())
|
||||
{
|
||||
return Extender;
|
||||
}
|
||||
|
||||
TWeakObjectPtr<UShaderLabMaterialInstanceConstant> MICWeak(MIC);
|
||||
Extender->AddToolBarExtension("Asset", EExtensionHook::After, Commands,
|
||||
FToolBarExtensionDelegate::CreateLambda([MICWeak](FToolBarBuilder& Builder)
|
||||
{
|
||||
Builder.AddToolBarButton(
|
||||
FUIAction(FExecuteAction::CreateStatic(&OpenInVSCode, MICWeak)),
|
||||
NAME_None,
|
||||
LOCTEXT("OpenSourceLabel", "Open .usl"),
|
||||
LOCTEXT("OpenSourceTooltip", "Open this ShaderLab material's source .usl in VSCode"),
|
||||
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Edit"));
|
||||
}));
|
||||
return Extender;
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
IMaterialEditorModule& MaterialEditor = FModuleManager::LoadModuleChecked<IMaterialEditorModule>("MaterialEditor");
|
||||
TArray<FAssetEditorExtender>& Delegates = MaterialEditor.GetToolBarExtensibilityManager()->GetExtenderDelegates();
|
||||
Delegates.Add(FAssetEditorExtender::CreateStatic(&OnExtendToolbar));
|
||||
GExtenderDelegateHandle = Delegates.Last().GetHandle();
|
||||
}
|
||||
|
||||
void Unregister()
|
||||
{
|
||||
if (IMaterialEditorModule* MaterialEditor = FModuleManager::GetModulePtr<IMaterialEditorModule>("MaterialEditor"))
|
||||
{
|
||||
MaterialEditor->GetToolBarExtensibilityManager()->GetExtenderDelegates().RemoveAll(
|
||||
[](const FAssetEditorExtender& Delegate) { return Delegate.GetHandle() == GExtenderDelegateHandle; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
Reference in New Issue
Block a user