You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Removing texture build metadata due to ddc complexities. It will be added to the metadata system in the new build flow SoonTM. Additionally, the alpha information for the source mips is no longer necessary as that is computed elsewhere now. #rb fabian.giesen #jira UE-183750 [CL 30895383 by dan thompson in 5.4 branch]
3330 lines
110 KiB
C++
3330 lines
110 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "TextureEditorToolkit.h"
|
|
#include "UObject/UObjectIterator.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Engine/Texture.h"
|
|
#include "Engine/Texture2D.h"
|
|
#include "Editor.h"
|
|
#include "Widgets/Layout/SBorder.h"
|
|
#include "Misc/FeedbackContext.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "SlateOptMacros.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Widgets/Input/SCheckBox.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "EditorReimportHandler.h"
|
|
#include "DeviceProfiles/DeviceProfileManager.h"
|
|
#include "Engine/LightMapTexture2D.h"
|
|
#include "Engine/ShadowMapTexture2D.h"
|
|
#include "Engine/Texture2DDynamic.h"
|
|
#include "Engine/TextureCube.h"
|
|
#include "Engine/Texture2DArray.h"
|
|
#include "Engine/TextureCubeArray.h"
|
|
#include "Engine/VolumeTexture.h"
|
|
#include "TextureEncodingSettings.h"
|
|
#include "Engine/TextureRenderTarget.h"
|
|
#include "Engine/TextureRenderTarget2D.h"
|
|
#include "Engine/TextureRenderTarget2DArray.h"
|
|
#include "Engine/TextureRenderTargetCube.h"
|
|
#include "Engine/TextureRenderTargetVolume.h"
|
|
#include "Interfaces/ITextureEditorModule.h"
|
|
#include "TextureEditor.h"
|
|
#include "Slate/SceneViewport.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "TextureEditorConstants.h"
|
|
#include "Models/TextureEditorCommands.h"
|
|
#include "Widgets/STextureEditorViewport.h"
|
|
#include "ISettingsModule.h"
|
|
#include "Widgets/Docking/SDockTab.h"
|
|
#include "Widgets/Input/SNumericEntryBox.h"
|
|
#include "DeviceProfiles/DeviceProfile.h"
|
|
#include "Curves/CurveLinearColorAtlas.h"
|
|
#include "TextureEditorSettings.h"
|
|
#include "Widgets/Input/SSlider.h"
|
|
#include "Widgets/Input/STextComboBox.h"
|
|
#include "Widgets/Layout/SSpacer.h"
|
|
#include "Menus/TextureEditorViewOptionsMenu.h"
|
|
#include "MediaTexture.h"
|
|
#include "TextureEncodingSettings.h"
|
|
#include "SEnumCombo.h"
|
|
#include "Widgets/Layout/SHeader.h"
|
|
#include "DerivedDataCacheKey.h"
|
|
#include "Settings/ProjectPackagingSettings.h"
|
|
#include "Compression/OodleDataCompressionUtil.h"
|
|
#include "Components/SceneCaptureComponent2D.h"
|
|
#include "TextureResource.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "FTextureEditorToolkit"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogTextureEditor, Log, All);
|
|
|
|
#define MIPLEVEL_MIN 0
|
|
#define MIPLEVEL_MAX 15
|
|
#define EXPOSURE_MIN -10
|
|
#define EXPOSURE_MAX 10
|
|
|
|
|
|
const FName FTextureEditorToolkit::ViewportTabId(TEXT("TextureEditor_Viewport"));
|
|
const FName FTextureEditorToolkit::PropertiesTabId(TEXT("TextureEditor_Properties"));
|
|
const FName FTextureEditorToolkit::OodleTabId(TEXT("TextureEditor_Oodle"));
|
|
|
|
UNREALED_API void GetBestFitForNumberOfTiles(int32 InSize, int32& OutRatioX, int32& OutRatioY);
|
|
|
|
EPixelFormatChannelFlags GetPixelFormatChannelFlagForButton(ETextureChannelButton InButton)
|
|
{
|
|
switch (InButton)
|
|
{
|
|
case ETextureChannelButton::Red:
|
|
{
|
|
return EPixelFormatChannelFlags::R;
|
|
}
|
|
case ETextureChannelButton::Green:
|
|
{
|
|
return EPixelFormatChannelFlags::G;
|
|
}
|
|
case ETextureChannelButton::Blue:
|
|
{
|
|
return EPixelFormatChannelFlags::B;
|
|
}
|
|
case ETextureChannelButton::Alpha:
|
|
{
|
|
return EPixelFormatChannelFlags::A;
|
|
}
|
|
default:
|
|
{
|
|
check(false);
|
|
}
|
|
}
|
|
|
|
return EPixelFormatChannelFlags::None;
|
|
}
|
|
|
|
void FTextureEditorToolkit::PostTextureRecode()
|
|
{
|
|
// Each time we change a custom encode setting we want to re-encode the texture
|
|
// as though we changed a compression setting on the actual texture, so we just
|
|
// post a CompressionSettings property changed event to handle all of that for
|
|
// us.
|
|
FProperty* Property = FindFProperty<FProperty>(UTexture::StaticClass(), "CompressionSettings");
|
|
FPropertyChangedEvent PropertyChangedEvent(Property);
|
|
Texture->PostEditChangeProperty(PropertyChangedEvent);
|
|
|
|
// Clear the key we have so we know when we have new data
|
|
OodleCompressedPreviewDDCKey.Set<FString>(FString());
|
|
}
|
|
|
|
|
|
/* FTextureEditorToolkit structors
|
|
*****************************************************************************/
|
|
|
|
FTextureEditorToolkit::FTextureEditorToolkit()
|
|
: Texture(nullptr)
|
|
, VolumeOpacity(1.f)
|
|
{
|
|
}
|
|
|
|
FTextureEditorToolkit::~FTextureEditorToolkit( )
|
|
{
|
|
// Release the VT page table allocation used to display this texture
|
|
UTexture2D* Texture2D = Cast<UTexture2D>(Texture);
|
|
if (Texture2D && Texture2D->IsCurrentlyVirtualTextured())
|
|
{
|
|
FVirtualTexture2DResource* Resource = (FVirtualTexture2DResource*)Texture2D->GetResource();
|
|
if (Resource)
|
|
{
|
|
Resource->ReleaseAllocatedVT();
|
|
}
|
|
}
|
|
|
|
FReimportManager::Instance()->OnPreReimport().RemoveAll(this);
|
|
FReimportManager::Instance()->OnPostReimport().RemoveAll(this);
|
|
GEditor->GetEditorSubsystem<UImportSubsystem>()->OnAssetPostImport.RemoveAll(this);
|
|
|
|
GEditor->UnregisterForUndo(this);
|
|
|
|
if (CustomEncoding->bUseCustomEncode)
|
|
{
|
|
// reencode the texture with normal settings.
|
|
CustomEncoding->bUseCustomEncode = false;
|
|
PostTextureRecode();
|
|
}
|
|
}
|
|
|
|
|
|
/* FAssetEditorToolkit interface
|
|
*****************************************************************************/
|
|
|
|
FString FTextureEditorToolkit::GetDocumentationLink( ) const
|
|
{
|
|
return FString(TEXT("Engine/Content/Types/Textures/Properties/Interface"));
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::RegisterTabSpawners( const TSharedRef<class FTabManager>& InTabManager )
|
|
{
|
|
WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_TextureEditor", "Texture Editor"));
|
|
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
|
|
|
|
FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
|
|
|
|
InTabManager->RegisterTabSpawner(ViewportTabId, FOnSpawnTab::CreateSP(this, &FTextureEditorToolkit::HandleTabSpawnerSpawnViewport))
|
|
.SetDisplayName(LOCTEXT("ViewportTab", "Viewport"))
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Viewports"))
|
|
.SetReadOnlyBehavior(ETabReadOnlyBehavior::Custom);
|
|
|
|
InTabManager->RegisterTabSpawner(PropertiesTabId, FOnSpawnTab::CreateSP(this, &FTextureEditorToolkit::HandleTabSpawnerSpawnProperties))
|
|
.SetDisplayName(LOCTEXT("PropertiesTab", "Details") )
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"))
|
|
.SetReadOnlyBehavior(ETabReadOnlyBehavior::Custom);
|
|
|
|
InTabManager->RegisterTabSpawner(OodleTabId, FOnSpawnTab::CreateSP(this, &FTextureEditorToolkit::HandleTabSpawnerSpawnOodle))
|
|
.SetDisplayName(LOCTEXT("OodleTab", "Oodle"))
|
|
.SetGroup(WorkspaceMenuCategoryRef)
|
|
.SetIcon(FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tabs.Details"));
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::UnregisterTabSpawners( const TSharedRef<class FTabManager>& InTabManager )
|
|
{
|
|
FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);
|
|
|
|
InTabManager->UnregisterTabSpawner(ViewportTabId);
|
|
InTabManager->UnregisterTabSpawner(PropertiesTabId);
|
|
InTabManager->UnregisterTabSpawner(OodleTabId);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::InitTextureEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UObject* ObjectToEdit )
|
|
{
|
|
FReimportManager::Instance()->OnPreReimport().AddRaw(this, &FTextureEditorToolkit::HandleReimportManagerPreReimport);
|
|
FReimportManager::Instance()->OnPostReimport().AddRaw(this, &FTextureEditorToolkit::HandleReimportManagerPostReimport);
|
|
GEditor->GetEditorSubsystem<UImportSubsystem>()->OnAssetPostImport.AddRaw(this, &FTextureEditorToolkit::HandleAssetPostImport);
|
|
|
|
Texture = CastChecked<UTexture>(ObjectToEdit);
|
|
|
|
// The texture being edited might still be compiling, wait till it finishes then.
|
|
// FinishCompilation is nice enough to provide a progress for us while we're waiting.
|
|
Texture->BlockOnAnyAsyncBuild();
|
|
|
|
// Support undo/redo
|
|
Texture->SetFlags(RF_Transactional);
|
|
GEditor->RegisterForUndo(this);
|
|
|
|
CustomEncoding = MakeShared<FTextureEditorCustomEncode>(FTextureEditorCustomEncode());
|
|
|
|
// initialize view options
|
|
bIsRedChannel = true;
|
|
bIsGreenChannel = true;
|
|
bIsBlueChannel = true;
|
|
bIsAlphaChannel = false;
|
|
|
|
ExposureBias = 0;
|
|
|
|
bIsVolumeTexture = IsVolumeTexture();
|
|
|
|
switch (Texture->CompressionSettings)
|
|
{
|
|
default:
|
|
bIsAlphaChannel = !Texture->CompressionNoAlpha;
|
|
break;
|
|
case TC_Normalmap:
|
|
case TC_Grayscale:
|
|
case TC_Displacementmap:
|
|
case TC_VectorDisplacementmap:
|
|
case TC_DistanceFieldFont:
|
|
bIsAlphaChannel = false;
|
|
break;
|
|
}
|
|
|
|
// Start out with alpha channel unchecked for render targets. Scene capture render targets have a depth mask
|
|
// in the alpha channel, which causes them to appear as fully transparent (checkerboard), and it isn't easily
|
|
// discoverable that toggling off the alpha channel would solve the issue, so it's helpful to start out with
|
|
// it disabled.
|
|
if (Texture->GetTextureClass() == ETextureClass::RenderTarget)
|
|
{
|
|
bIsAlphaChannel = false;
|
|
}
|
|
|
|
bIsDesaturation = false;
|
|
|
|
PreviewEffectiveTextureWidth = 0;
|
|
PreviewEffectiveTextureHeight = 0;
|
|
|
|
SpecifiedMipLevel = 0;
|
|
bUseSpecifiedMipLevel = false;
|
|
|
|
SpecifiedLayer = 0;
|
|
|
|
SpecifiedSlice = 0;
|
|
bUseSpecifiedSlice = false;
|
|
|
|
SpecifiedFace = 0;
|
|
bUseSpecifiedFace = false;
|
|
|
|
// Start at whatever the last used values of the following settings were
|
|
const UTextureEditorSettings& Settings = *GetDefault<UTextureEditorSettings>();
|
|
ZoomMode = Settings.ZoomMode;
|
|
VolumeViewMode = Settings.VolumeViewMode;
|
|
CubemapViewMode = Settings.CubemapViewMode;
|
|
Sampling = Settings.Sampling;
|
|
|
|
ResetOrientation();
|
|
Zoom = 1.0f;
|
|
|
|
// Register our commands. This will only register them if not previously registered
|
|
FTextureEditorCommands::Register();
|
|
|
|
BindCommands();
|
|
CreateInternalWidgets();
|
|
|
|
const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout("Standalone_TextureEditor_Layout_v5")
|
|
->AddArea
|
|
(
|
|
FTabManager::NewPrimaryArea()
|
|
->SetOrientation(Orient_Horizontal)
|
|
->Split
|
|
(
|
|
FTabManager::NewSplitter()
|
|
->SetOrientation(Orient_Vertical)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack()
|
|
->AddTab(ViewportTabId, ETabState::OpenedTab)
|
|
->SetHideTabWell(true)
|
|
->SetSizeCoefficient(0.9f)
|
|
)
|
|
)
|
|
->Split
|
|
(
|
|
FTabManager::NewStack()
|
|
->AddTab(PropertiesTabId, ETabState::OpenedTab)
|
|
->AddTab(OodleTabId, ETabState::OpenedTab)
|
|
->SetForegroundTab(PropertiesTabId)
|
|
->SetSizeCoefficient(0.33f)
|
|
)
|
|
);
|
|
|
|
const bool bCreateDefaultStandaloneMenu = true;
|
|
const bool bCreateDefaultToolbar = true;
|
|
|
|
FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, TextureEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit);
|
|
|
|
ITextureEditorModule* TextureEditorModule = &FModuleManager::LoadModuleChecked<ITextureEditorModule>("TextureEditor");
|
|
AddMenuExtender(TextureEditorModule->GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
|
|
|
|
TexturePropertiesWidget->SetIsPropertyEditingEnabledDelegate(FIsPropertyEditingEnabled::CreateLambda([this]
|
|
{
|
|
return GetOpenMethod() == EAssetOpenMethod::Edit;
|
|
}));
|
|
|
|
ExtendToolBar();
|
|
|
|
RegenerateMenusAndToolbars();
|
|
|
|
// If we're opening the texture editor then we likely want to see the Final
|
|
// texture quality for evaluation and parameter adjustment. This ends up latching
|
|
// for the current editor session, but since it's already getting built this is
|
|
// fine. This doesn't need the normal Modify() / PreEditChange/PostEditChange incantations
|
|
// because it's transient, and any async build was completed above.
|
|
if ( Texture->Source.IsValid() && ( (int64)Texture->Source.GetSizeX() * Texture->Source.GetSizeY() <= 4096*4096 ) )
|
|
{
|
|
Texture->CompressFinal = true;
|
|
}
|
|
|
|
// We don't want to post recodes for render targets because that clears them to black and
|
|
// we don't care about CompressFinal for them anyway as they aren't encoded. While we are
|
|
// here, don't bother with other dynamic textures as well.
|
|
ETextureClass TextureClass = Texture->GetTextureClass();
|
|
if (TextureClass != ETextureClass::RenderTarget &&
|
|
TextureClass != ETextureClass::Other2DNoSource &&
|
|
TextureClass != ETextureClass::TwoDDynamic)
|
|
{
|
|
PostTextureRecode();
|
|
}
|
|
|
|
// @todo toolkit world centric editing
|
|
/*if(IsWorldCentricAssetEditor())
|
|
{
|
|
SpawnToolkitTab(GetToolbarTabId(), FString(), EToolkitTabSpot::ToolBar);
|
|
SpawnToolkitTab(ViewportTabId, FString(), EToolkitTabSpot::Viewport);
|
|
SpawnToolkitTab(PropertiesTabId, FString(), EToolkitTabSpot::Details);
|
|
}*/
|
|
}
|
|
|
|
|
|
/* ITextureEditorToolkit interface
|
|
*****************************************************************************/
|
|
|
|
void FTextureEditorToolkit::CalculateTextureDimensions(int32& OutWidth, int32& OutHeight, int32& OutDepth, int32& OutArraySize, bool bInIncludeBorderSize) const
|
|
{
|
|
OutWidth = static_cast<int32>(Texture->GetSurfaceWidth());
|
|
OutHeight = static_cast<int32>(Texture->GetSurfaceHeight());
|
|
OutDepth = static_cast<int32>(Texture->GetSurfaceDepth());
|
|
OutArraySize = IsArrayTexture() ? (IsCubeTexture() ? Texture->GetSurfaceArraySize() / 6 : Texture->GetSurfaceArraySize()) : 0;
|
|
const int32 BorderSize = GetDefault<UTextureEditorSettings>()->TextureBorderEnabled ? 1 : 0;
|
|
|
|
|
|
if (UTexture2D* Texture2D = Cast<UTexture2D>(Texture))
|
|
{
|
|
if (UTexture2D* CpuTexture = Texture2D->GetCPUCopyTexture())
|
|
{
|
|
OutWidth = CpuTexture->GetSurfaceWidth();
|
|
OutHeight = CpuTexture->GetSurfaceHeight();
|
|
OutDepth = 1;
|
|
OutArraySize = 0;
|
|
}
|
|
}
|
|
|
|
if (!PreviewEffectiveTextureWidth || !PreviewEffectiveTextureHeight)
|
|
{
|
|
OutWidth = 0;
|
|
OutHeight = 0;
|
|
OutDepth = 0;
|
|
OutArraySize = 0;
|
|
return;
|
|
}
|
|
|
|
// Fit is the same as fill, but doesn't scale up past 100%
|
|
const ETextureEditorZoomMode CurrentZoomMode = GetZoomMode();
|
|
if (CurrentZoomMode == ETextureEditorZoomMode::Fit || CurrentZoomMode == ETextureEditorZoomMode::Fill)
|
|
{
|
|
const int32 MaxWidth = FMath::Max(TextureViewport->GetViewport()->GetSizeXY().X - 2 * BorderSize, 0);
|
|
const int32 MaxHeight = FMath::Max(TextureViewport->GetViewport()->GetSizeXY().Y - 2 * BorderSize, 0);
|
|
|
|
if (IsVolumeTexture() && GetVolumeViewMode() == ETextureEditorVolumeViewMode::TextureEditorVolumeViewMode_VolumeTrace)
|
|
{
|
|
OutWidth = OutHeight = FMath::Min(MaxWidth, MaxHeight);
|
|
}
|
|
else if (MaxWidth * PreviewEffectiveTextureHeight < MaxHeight * PreviewEffectiveTextureWidth)
|
|
{
|
|
OutWidth = MaxWidth;
|
|
OutHeight = FMath::DivideAndRoundNearest(OutWidth * PreviewEffectiveTextureHeight, PreviewEffectiveTextureWidth);
|
|
}
|
|
else
|
|
{
|
|
OutHeight = MaxHeight;
|
|
OutWidth = FMath::DivideAndRoundNearest(OutHeight * PreviewEffectiveTextureWidth, PreviewEffectiveTextureHeight);
|
|
}
|
|
|
|
// If fit, then we only want to scale down
|
|
// So if our natural dimensions are smaller than the viewport, we can just use those
|
|
if (CurrentZoomMode == ETextureEditorZoomMode::Fit && (PreviewEffectiveTextureWidth < OutWidth || PreviewEffectiveTextureHeight < OutHeight))
|
|
{
|
|
OutWidth = PreviewEffectiveTextureWidth;
|
|
OutHeight = PreviewEffectiveTextureHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OutWidth = static_cast<int32>(PreviewEffectiveTextureWidth * Zoom);
|
|
OutHeight = static_cast<int32>(PreviewEffectiveTextureHeight * Zoom);
|
|
}
|
|
|
|
if (bInIncludeBorderSize)
|
|
{
|
|
OutWidth += 2 * BorderSize;
|
|
OutHeight += 2 * BorderSize;
|
|
}
|
|
}
|
|
|
|
|
|
ESimpleElementBlendMode FTextureEditorToolkit::GetColourChannelBlendMode( ) const
|
|
{
|
|
if (Texture && (Texture->CompressionSettings == TC_Grayscale || Texture->CompressionSettings == TC_Alpha))
|
|
{
|
|
return SE_BLEND_Opaque;
|
|
}
|
|
|
|
// Add the red, green, blue, alpha and desaturation flags to the enum to identify the chosen filters
|
|
uint32 Result = (uint32)SE_BLEND_RGBA_MASK_START;
|
|
Result += bIsRedChannel ? (1 << 0) : 0;
|
|
Result += bIsGreenChannel ? (1 << 1) : 0;
|
|
Result += bIsBlueChannel ? (1 << 2) : 0;
|
|
Result += bIsAlphaChannel ? (1 << 3) : 0;
|
|
|
|
// If we only have one color channel active, enable color desaturation by default
|
|
const int32 NumColorChannelsActive = (bIsRedChannel ? 1 : 0) + (bIsGreenChannel ? 1 : 0) + (bIsBlueChannel ? 1 : 0);
|
|
const bool bIsDesaturationLocal = bIsDesaturation ? true : (NumColorChannelsActive==1);
|
|
Result += bIsDesaturationLocal ? (1 << 4) : 0;
|
|
|
|
return (ESimpleElementBlendMode)Result;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsFitToViewport() const
|
|
{
|
|
return IsCurrentZoomMode(ETextureEditorZoomMode::Fit);
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsFillToViewport() const
|
|
{
|
|
return IsCurrentZoomMode(ETextureEditorZoomMode::Fill);
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetMipLevel( ) const
|
|
{
|
|
return GetUseSpecifiedMip() ? SpecifiedMipLevel : -1;
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetLayer() const
|
|
{
|
|
return SpecifiedLayer;
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetSlice() const
|
|
{
|
|
return GetUseSpecifiedSlice() ? HandleSliceEntryBoxValue().Get(-1) : -1;
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetFace() const
|
|
{
|
|
return GetUseSpecifiedFace() ? SpecifiedFace : -1;
|
|
}
|
|
|
|
UTexture* FTextureEditorToolkit::GetTexture( ) const
|
|
{
|
|
return Texture;
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HasValidTextureResource( ) const
|
|
{
|
|
return Texture != nullptr && Texture->GetResource() != nullptr;
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::GetUseSpecifiedMip( ) const
|
|
{
|
|
if (GetMaxMipLevel().Get(MIPLEVEL_MAX) > 0)
|
|
{
|
|
if (HandleMipLevelCheckBoxIsEnabled())
|
|
{
|
|
return bUseSpecifiedMipLevel;
|
|
}
|
|
|
|
// by default this is on
|
|
return true;
|
|
}
|
|
|
|
// disable the widgets if we have no mip maps
|
|
return false;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::GetUseSpecifiedSlice() const
|
|
{
|
|
return HandleSliceCheckBoxIsEnabled() && bUseSpecifiedSlice;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::GetUseSpecifiedFace() const
|
|
{
|
|
return bUseSpecifiedFace;
|
|
}
|
|
|
|
double FTextureEditorToolkit::GetCustomZoomLevel( ) const
|
|
{
|
|
return Zoom;
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::PopulateQuickInfo( )
|
|
{
|
|
if (Texture->IsDefaultTexture())
|
|
{
|
|
ImportedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Imported_NA", "Imported: Computing..."));
|
|
CurrentText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Displayed_NA", "Displayed: Computing..."));
|
|
MaxInGameText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_MaxInGame_NA", "Max In-Game: Computing..."));
|
|
SizeText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_ResourceSize_NA", "Resource Size: Computing..."));
|
|
MethodText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Method_NA", "Method: Computing..."));
|
|
LODBiasText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_LODBias_NA", "Combined LOD Bias: Computing..."));
|
|
FormatText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Format_NA", "Format: Computing..."));
|
|
NumMipsText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_NumMips_NA", "Number of Mips: Computing..."));
|
|
HasAlphaChannelText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_HasAlphaChannel_NA", "Has Alpha Channel: Computing..."));
|
|
EncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_Computing", "Encode Speed: Computing..."));
|
|
SceneCaptureSizeText->SetText(FText());
|
|
SceneCaptureNameText->SetText(FText());
|
|
return;
|
|
}
|
|
|
|
FTexturePlatformData** PlatformDataPtr = Texture->GetRunningPlatformData();
|
|
if (PlatformDataPtr && PlatformDataPtr[0]) // Can be null if we haven't had a chance to call CachePlatformData on the texture (brand new)
|
|
{
|
|
FTexturePlatformData* PlatformData = PlatformDataPtr[0];
|
|
FTexturePlatformData::FTextureEncodeResultMetadata const& ResultMetadata = PlatformData->ResultMetadata;
|
|
if (ResultMetadata.bIsValid == false)
|
|
{
|
|
EncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_NA", "Encode Speed: N/A"));
|
|
|
|
FText OodleInfoMissing = NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_Missing", "<Metadata Missing>");
|
|
OodleEncoderText->SetText(OodleInfoMissing);
|
|
OodleEncodeSpeedText->SetText(OodleInfoMissing);
|
|
OodleRDOText->SetText(OodleInfoMissing);
|
|
OodleEffortText->SetText(OodleInfoMissing);
|
|
OodleTilingText->SetText(OodleInfoMissing);
|
|
OodleRDOSourceText->SetText(OodleInfoMissing);
|
|
|
|
OodleRDOText->SetVisibility(EVisibility::Hidden);
|
|
OodleEffortText->SetVisibility(EVisibility::Hidden);
|
|
OodleTilingText->SetVisibility(EVisibility::Hidden);
|
|
OodleRDOSourceText->SetVisibility(EVisibility::Hidden);
|
|
|
|
OodleRDOEnabledLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleRDOSourceLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleEffortLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleTilingLabel->SetVisibility(EVisibility::Hidden);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check if we need to compress new Oodle preview once we know we have
|
|
// valid results.
|
|
//
|
|
bool AlreadyHaveResults = false;
|
|
if (PlatformData->DerivedDataKey.GetIndex() == OodleCompressedPreviewDDCKey.GetIndex())
|
|
{
|
|
if (PlatformData->DerivedDataKey.IsType<FString>())
|
|
{
|
|
if (PlatformData->DerivedDataKey.Get<FString>() == OodleCompressedPreviewDDCKey.Get<FString>())
|
|
{
|
|
AlreadyHaveResults = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (*PlatformData->DerivedDataKey.Get<UE::DerivedData::FCacheKeyProxy>().AsCacheKey() == *OodleCompressedPreviewDDCKey.Get<UE::DerivedData::FCacheKeyProxy>().AsCacheKey())
|
|
{
|
|
AlreadyHaveResults = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AlreadyHaveResults == false)
|
|
{
|
|
if (bEstimateCompressionEnabled)
|
|
{
|
|
OutstandingEstimation = PlatformData->LaunchEstimateOnDiskSizeTask(OodleCompressor, OodleCompressionLevel, CompressionBlockSize, Texture->GetPathName());
|
|
}
|
|
|
|
OodleCompressedPreviewDDCKey = PlatformDataPtr[0]->DerivedDataKey;
|
|
}
|
|
|
|
// If we have an outstanding estimation task, update UI when complete.
|
|
if (OutstandingEstimation.IsValid())
|
|
{
|
|
if (OutstandingEstimation.IsReady())
|
|
{
|
|
TTuple<uint64, uint64> Result = OutstandingEstimation.Get();
|
|
|
|
OodleEstimateRaw->SetText(FText::AsMemory(Result.Get<1>()));
|
|
OodleEstimateCompressed->SetText(FText::AsMemory(Result.Get<0>()));
|
|
|
|
OutstandingEstimation = TFuture<TTuple<uint64, uint64>>();
|
|
}
|
|
else
|
|
{
|
|
OodleEstimateRaw->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_Working", "Working..."));
|
|
OodleEstimateCompressed->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_Working", "Working..."));
|
|
}
|
|
}
|
|
|
|
OodleEncoderText->SetText(FText::FromName(ResultMetadata.Encoder));
|
|
|
|
if (ResultMetadata.bSupportsEncodeSpeed == false)
|
|
{
|
|
EncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_Unsup", "Encode Speed: Unsupported"));
|
|
OodleEncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_SpeedUnsup", "Unsupported"));
|
|
|
|
FText OodleInfoNA = NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_NA", "N/A");
|
|
OodleRDOText->SetText(OodleInfoNA);
|
|
OodleEffortText->SetText(OodleInfoNA);
|
|
OodleTilingText->SetText(OodleInfoNA);
|
|
OodleRDOSourceText->SetText(OodleInfoNA);
|
|
|
|
OodleRDOText->SetVisibility(EVisibility::Hidden);
|
|
OodleEffortText->SetVisibility(EVisibility::Hidden);
|
|
OodleTilingText->SetVisibility(EVisibility::Hidden);
|
|
OodleRDOSourceText->SetVisibility(EVisibility::Hidden);
|
|
|
|
OodleRDOEnabledLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleRDOSourceLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleEffortLabel->SetVisibility(EVisibility::Hidden);
|
|
OodleTilingLabel->SetVisibility(EVisibility::Hidden);
|
|
|
|
}
|
|
else
|
|
{
|
|
OodleRDOText->SetVisibility(EVisibility::Visible);
|
|
OodleEffortText->SetVisibility(EVisibility::Visible);
|
|
OodleTilingText->SetVisibility(EVisibility::Visible);
|
|
OodleRDOSourceText->SetVisibility(EVisibility::Visible);
|
|
|
|
OodleRDOEnabledLabel->SetVisibility(EVisibility::Visible);
|
|
OodleRDOSourceLabel->SetVisibility(EVisibility::Visible);
|
|
OodleEffortLabel->SetVisibility(EVisibility::Visible);
|
|
OodleTilingLabel->SetVisibility(EVisibility::Visible);
|
|
|
|
if (ResultMetadata.bWasEditorCustomEncoding)
|
|
{
|
|
EncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_Custom", "Encode Speed: Custom"));
|
|
OodleEncodeSpeedText->SetText(NSLOCTEXT("TextureEditor", "QuickInfoDetails_EncodeSpeed_Custom", "Custom"));
|
|
}
|
|
else
|
|
{
|
|
EncodeSpeedText->SetText(
|
|
ResultMetadata.EncodeSpeed == (uint8)ETextureEncodeSpeed::Fast ?
|
|
NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_Fast", "Encode Speed: Fast") :
|
|
NSLOCTEXT("TextureEditor", "QuickInfo_EncodeSpeed_Final", "Encode Speed: Final")
|
|
);
|
|
OodleEncodeSpeedText->SetText(
|
|
ResultMetadata.EncodeSpeed == (uint8)ETextureEncodeSpeed::Fast ?
|
|
NSLOCTEXT("TextureEditor", "QuickInfoDetails_EncodeSpeed_Fast", "Fast") :
|
|
NSLOCTEXT("TextureEditor", "QuickInfoDetails_EncodeSpeed_Final", "Final")
|
|
);
|
|
}
|
|
|
|
if (ResultMetadata.OodleRDO == 0)
|
|
{
|
|
const FResolvedTextureEncodingSettings& Settings = FResolvedTextureEncodingSettings::Get();
|
|
const bool bDisabledGlobally = ResultMetadata.EncodeSpeed == (uint8)ETextureEncodeSpeed::Fast ? !Settings.Project.bFastUsesRDO : !Settings.Project.bFinalUsesRDO;
|
|
|
|
OodleRDOText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDODisable", "Disabled"));
|
|
if (ResultMetadata.bWasEditorCustomEncoding)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSource_Custom", "Custom"));
|
|
}
|
|
else if (bDisabledGlobally)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSourceDisableSettings", "Disabled By Project Settings"));
|
|
}
|
|
else
|
|
{
|
|
if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::Default)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSourceDisableLCA_Default", "Disabled By Project (Lossy Compression Amount)"));
|
|
}
|
|
else if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::Texture)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSourceDisableLCA_Texture", "Disabled By Texture (Lossy Compression Amount)"));
|
|
}
|
|
else if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::LODGroup)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSourceDisableLCA_LODGroup", "Disabled By LODGroup (Lossy Compression Amount)"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OodleRDOText->SetText(FText::AsNumber(ResultMetadata.OodleRDO));
|
|
|
|
if (ResultMetadata.bWasEditorCustomEncoding)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSource_Custom", "Custom"));
|
|
}
|
|
else if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::Default)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSource_Default", "Project (Lambda)"));
|
|
}
|
|
else if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::Texture)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSource_Texture", "Texture (Lossy Compression Amount)"));
|
|
}
|
|
else if (ResultMetadata.RDOSource == FTexturePlatformData::FTextureEncodeResultMetadata::OodleRDOSource::LODGroup)
|
|
{
|
|
OodleRDOSourceText->SetText(NSLOCTEXT("TextureEditor", "QuickInfo_Oodle_RDOSource_LODGroup", "LODGroup (Lossy Compression Amount)"));
|
|
}
|
|
}
|
|
|
|
UEnum* EncodeEffortEnum = StaticEnum<ETextureEncodeEffort>();
|
|
OodleEffortText->SetText(FText::AsCultureInvariant(EncodeEffortEnum->GetNameStringByValue(ResultMetadata.OodleEncodeEffort)));
|
|
|
|
UEnum* UniversalTilingEnum = StaticEnum<ETextureUniversalTiling>();
|
|
OodleTilingText->SetText(FText::AsCultureInvariant(UniversalTilingEnum->GetNameStringByValue(ResultMetadata.OodleUniversalTiling)));
|
|
} // end if encode speed supported
|
|
} // end if results metadata valid
|
|
|
|
if (Texture->Source.IsValid() &&
|
|
Texture->Source.GetLayerColorInfo().Num())
|
|
{
|
|
// Make a 1x1 image with our max colors to use for alpha detection.
|
|
FImageView View(&Texture->Source.GetLayerColorInfo()[0].ColorMin, 1, 1);
|
|
|
|
bool bSourceAlphaDetected = FImageCore::DetectAlphaChannel(View);
|
|
SourceMipsAlphaDetectedText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_SourceAlphaDetected", "Source Alpha Detected: {0}"),
|
|
bSourceAlphaDetected ? NSLOCTEXT("TextureEditor", "True", "True") : NSLOCTEXT("TextureEditor", "False", "False")));
|
|
}
|
|
else
|
|
{
|
|
SourceMipsAlphaDetectedText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_SourceAlphaDetected", "Source Alpha Detected: {0}"),
|
|
NSLOCTEXT("TextureEditor", "Unknown", "Unknown")));
|
|
}
|
|
} // end if valid platform data
|
|
|
|
UTexture2D* Texture2D = Cast<UTexture2D>(Texture);
|
|
|
|
|
|
const bool bIsVolume = IsVolumeTexture();
|
|
const bool bIsArray = IsArrayTexture();
|
|
const bool bIsCube = IsCubeTexture();
|
|
|
|
const int32 SurfaceWidth = static_cast<int32>(Texture->GetSurfaceWidth());
|
|
const int32 SurfaceHeight = static_cast<int32>(Texture->GetSurfaceHeight());
|
|
const int32 SurfaceDepth = static_cast<int32>(Texture->GetSurfaceDepth());
|
|
const int32 NumSurfaces = Texture->GetSurfaceArraySize();
|
|
const int32 ArraySize = bIsArray ? (bIsCube ? NumSurfaces / 6 : NumSurfaces) : 0;
|
|
|
|
// this is the size of just one block :
|
|
// use GetLogicalSize for all blocks
|
|
const int32 ImportedWidth = Texture->Source.IsValid() ? Texture->Source.GetSizeX() : SurfaceWidth;
|
|
const int32 ImportedHeight = Texture->Source.IsValid() ? Texture->Source.GetSizeY() : SurfaceHeight;
|
|
const int32 ImportedDepth = Texture->Source.IsValid() ? (bIsVolume ? Texture->Source.GetNumSlices() : 0) : SurfaceDepth;
|
|
|
|
const int32 ImportedNumBlocks = Texture->Source.GetNumBlocks();
|
|
const FIntPoint ImportedSizeInBlocks = Texture->Source.GetSizeInBlocks();
|
|
|
|
const FStreamableRenderResourceState SRRState = Texture->GetStreamableResourceState();
|
|
const int32 ActualMipBias = SRRState.IsValid() ? (SRRState.ResidentFirstLODIdx() + SRRState.AssetLODBias) : Texture->GetCachedLODBias();
|
|
// Editor dimensions (takes user specified mip setting into account)
|
|
const int32 MipLevel = ActualMipBias + FMath::Max(GetMipLevel(), 0);
|
|
PreviewEffectiveTextureWidth = SurfaceWidth ? FMath::Max(SurfaceWidth >> MipLevel, 1) : 0;
|
|
PreviewEffectiveTextureHeight = SurfaceHeight ? FMath::Max(SurfaceHeight >> MipLevel, 1) : 0;
|
|
const int32 PreviewEffectiveTextureDepth = SurfaceDepth ? FMath::Max(SurfaceDepth >> MipLevel, 1) : 0;
|
|
|
|
// In game max bias and dimensions
|
|
const int32 MaxResMipBias = Texture2D ? (Texture2D->GetNumMips() - Texture2D->GetNumMipsAllowed(true)) : Texture->GetCachedLODBias();
|
|
const int32 MaxInGameWidth = SurfaceWidth ? FMath::Max(SurfaceWidth >> MaxResMipBias, 1) : 0;
|
|
const int32 MaxInGameHeight = SurfaceHeight ? FMath::Max(SurfaceHeight >> MaxResMipBias, 1) : 0;
|
|
const int32 MaxInGameDepth = SurfaceDepth ? FMath::Max(SurfaceDepth >> MaxResMipBias, 1) : 0;
|
|
|
|
// Texture asset size
|
|
const int64 ResourceSize = PlatformDataPtr && *PlatformDataPtr ? (*PlatformDataPtr)->GetPayloadSize(ActualMipBias) : Texture->GetResourceSizeBytes(EResourceSizeMode::Exclusive);
|
|
|
|
FText ImportedCubemapInfo;
|
|
FText DisplayedCubemapInfo;
|
|
FText InGameCubemapInfo;
|
|
if (bIsCube)
|
|
{
|
|
InGameCubemapInfo = NSLOCTEXT("TextureEditor", "QuickInfo_PerCubeSide", "*6 (Cubemap)");
|
|
ImportedCubemapInfo = Texture->Source.IsLongLatCubemap() ? NSLOCTEXT("TextureEditor", "QuickInfo_LongLat", " (LongLat)") : InGameCubemapInfo;
|
|
if (GetFace() >= 0)
|
|
{
|
|
DisplayedCubemapInfo = NSLOCTEXT("TextureEditor", "QuickInfo_CubemapFace", " (Cubemap face)");
|
|
}
|
|
else if (GetCubemapViewMode() == TextureEditorCubemapViewMode_2DView)
|
|
{
|
|
// when using 2D view mode and face index is not specified, cubemaps are previewed as longlat unwraps, which have double width of a cube face
|
|
PreviewEffectiveTextureWidth *= 2;
|
|
DisplayedCubemapInfo = NSLOCTEXT("TextureEditor", "QuickInfo_LongLat", " (LongLat)");
|
|
}
|
|
else
|
|
{
|
|
DisplayedCubemapInfo = InGameCubemapInfo;
|
|
}
|
|
}
|
|
|
|
FNumberFormattingOptions FormatOptions;
|
|
FormatOptions.UseGrouping = false;
|
|
|
|
if (bIsVolume)
|
|
{
|
|
ImportedText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_Imported_3x", "Imported: {0}x{1}x{2}"), FText::AsNumber(ImportedWidth, &FormatOptions), FText::AsNumber(ImportedHeight, &FormatOptions), FText::AsNumber(ImportedDepth, &FormatOptions)));
|
|
CurrentText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_Displayed_3x", "Displayed: {0}x{1}x{2}"), FText::AsNumber(PreviewEffectiveTextureWidth, &FormatOptions ), FText::AsNumber(PreviewEffectiveTextureHeight, &FormatOptions), FText::AsNumber(PreviewEffectiveTextureDepth, &FormatOptions)));
|
|
MaxInGameText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_MaxInGame_3x_v1", "Max In-Game: {0}x{1}x{2}"), FText::AsNumber(MaxInGameWidth, &FormatOptions), FText::AsNumber(MaxInGameHeight, &FormatOptions), FText::AsNumber(MaxInGameDepth, &FormatOptions)));
|
|
|
|
if (GetVolumeViewMode() == ETextureEditorVolumeViewMode::TextureEditorVolumeViewMode_VolumeTrace)
|
|
{
|
|
PreviewEffectiveTextureWidth = PreviewEffectiveTextureHeight = FMath::Max(PreviewEffectiveTextureWidth, PreviewEffectiveTextureHeight);
|
|
}
|
|
else
|
|
{
|
|
int32 NumTilesX = 0;
|
|
int32 NumTilesY = 0;
|
|
GetBestFitForNumberOfTiles(PreviewEffectiveTextureDepth, NumTilesX, NumTilesY);
|
|
PreviewEffectiveTextureWidth *= NumTilesX;
|
|
PreviewEffectiveTextureHeight *= NumTilesY;
|
|
}
|
|
}
|
|
else if (bIsArray)
|
|
{
|
|
ImportedText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_Imported_3x_v2", "Imported: {0}x{1}{2}*{3}"), FText::AsNumber(ImportedWidth, &FormatOptions), FText::AsNumber(ImportedHeight, &FormatOptions), ImportedCubemapInfo, FText::AsNumber(ArraySize, &FormatOptions)));
|
|
CurrentText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_Displayed_3x_v2", "Displayed: {0}x{1}{2}*{3}"), FText::AsNumber(PreviewEffectiveTextureWidth, &FormatOptions), FText::AsNumber(PreviewEffectiveTextureHeight, &FormatOptions), DisplayedCubemapInfo, FText::AsNumber(ArraySize, &FormatOptions)));
|
|
MaxInGameText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_MaxInGame_3x_v2", "Max In-Game: {0}x{1}{2}*{3}"), FText::AsNumber(MaxInGameWidth, &FormatOptions), FText::AsNumber(MaxInGameHeight, &FormatOptions), InGameCubemapInfo, FText::AsNumber(ArraySize, &FormatOptions)));
|
|
}
|
|
else
|
|
{
|
|
if ( ImportedNumBlocks > 1 )
|
|
{
|
|
ImportedText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_Imported_Blocks", "Imported: {0}x{1}x{2}x{3}"),
|
|
FText::AsNumber(ImportedWidth, &FormatOptions), FText::AsNumber(ImportedHeight, &FormatOptions),
|
|
FText::AsNumber(ImportedSizeInBlocks.X, &FormatOptions), FText::AsNumber(ImportedSizeInBlocks.Y, &FormatOptions)));
|
|
}
|
|
else
|
|
{
|
|
ImportedText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_Imported_2x", "Imported: {0}x{1}{2}"), FText::AsNumber(ImportedWidth, &FormatOptions), FText::AsNumber(ImportedHeight, &FormatOptions), ImportedCubemapInfo));
|
|
}
|
|
|
|
CurrentText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_Displayed_2x", "Displayed: {0}x{1}{2}"), FText::AsNumber(PreviewEffectiveTextureWidth, &FormatOptions ), FText::AsNumber(PreviewEffectiveTextureHeight, &FormatOptions), DisplayedCubemapInfo));
|
|
MaxInGameText->SetText(FText::Format( NSLOCTEXT("TextureEditor", "QuickInfo_MaxInGame_2x", "Max In-Game: {0}x{1}{2}"), FText::AsNumber(MaxInGameWidth, &FormatOptions), FText::AsNumber(MaxInGameHeight, &FormatOptions), InGameCubemapInfo));
|
|
}
|
|
|
|
if (Texture2D)
|
|
{
|
|
if (UTexture2D* CpuTexture = Texture2D->GetCPUCopyTexture(); CpuTexture)
|
|
{
|
|
PreviewEffectiveTextureWidth = CpuTexture->GetSurfaceWidth();
|
|
PreviewEffectiveTextureHeight = CpuTexture->GetSurfaceHeight();
|
|
}
|
|
}
|
|
|
|
SizeText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_ResourceSize", "Resource Size: {0} KB"), FText::AsNumber(FMath::DivideAndRoundNearest(ResourceSize, (int64)1024), &FormatOptions)));
|
|
|
|
FText Method = Texture->IsCurrentlyVirtualTextured() ? NSLOCTEXT("TextureEditor", "QuickInfo_MethodVirtualStreamed", "Virtual Streamed")
|
|
: (!Texture->IsStreamable() ? NSLOCTEXT("TextureEditor", "QuickInfo_MethodNotStreamed", "Not Streamed")
|
|
: NSLOCTEXT("TextureEditor", "QuickInfo_MethodStreamed", "Streamed") );
|
|
|
|
MethodText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_Method", "Method: {0}"), Method));
|
|
LODBiasText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_LODBias", "Combined LOD Bias: {0}"), FText::AsNumber(Texture->GetCachedLODBias())));
|
|
|
|
EPixelFormat TextureFormat = GetPixelFormat();
|
|
if (TextureFormat != PF_MAX)
|
|
{
|
|
FormatText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_Format", "Format: {0}"), FText::FromString(GPixelFormats[(uint8)TextureFormat].Name)));
|
|
}
|
|
|
|
// This "Has Alpha Channel" is whether the GPU format can represent alpha in the format (eg. is it DXT1 vs DXT5)
|
|
// it does not tell you if the texture actually has non-opaque alpha
|
|
EPixelFormatChannelFlags ValidTextureChannels = GetPixelFormatValidChannels(TextureFormat);
|
|
HasAlphaChannelText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_HasAlphaChannel", "Has Alpha Channel: {0}"),
|
|
EnumHasAnyFlags(ValidTextureChannels, EPixelFormatChannelFlags::A) ? NSLOCTEXT("TextureEditor", "True", "True") : NSLOCTEXT("TextureEditor", "False", "False")));
|
|
HasAlphaChannelText->SetVisibility((ValidTextureChannels != EPixelFormatChannelFlags::None) ? EVisibility::Visible : EVisibility::Collapsed);
|
|
|
|
int32 NumMips = GetNumMips();
|
|
NumMipsText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_NumMips", "Number of Mips: {0}"), FText::AsNumber(NumMips)));
|
|
|
|
uint64 CaptureSize = 0;
|
|
FName CaptureName;
|
|
if (Texture->GetTextureClass() == ETextureClass::RenderTarget)
|
|
{
|
|
for (TObjectIterator<USceneCaptureComponent2D> It; It; ++It)
|
|
{
|
|
USceneCaptureComponent2D* SceneCaptureComponent = *It;
|
|
if (SceneCaptureComponent->TextureTarget == Texture && SceneCaptureComponent->CaptureMemorySize.IsValid())
|
|
{
|
|
// Could have multiple scene captures blending to the same render target -- add them all up, but only show the name of the last one...
|
|
CaptureSize += SceneCaptureComponent->CaptureMemorySize->Size;
|
|
CaptureName = SceneCaptureComponent->GetOwner()->GetFName();
|
|
}
|
|
}
|
|
}
|
|
if (CaptureSize)
|
|
{
|
|
SceneCaptureSizeText->SetText(FText::Format(NSLOCTEXT("TextureEditor", "QuickInfo_SceneCaptureSize", "Scene Capture: {0} KB"), FText::AsNumber(FMath::DivideAndRoundNearest(CaptureSize, (uint64)1024), &FormatOptions)));
|
|
SceneCaptureNameText->SetText(FText::Format(FText::FromString(TEXT("({0})")), FText::FromName(CaptureName)));
|
|
}
|
|
else
|
|
{
|
|
SceneCaptureSizeText->SetText(FText());
|
|
SceneCaptureNameText->SetText(FText());
|
|
}
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::SetZoomMode( const ETextureEditorZoomMode InZoomMode )
|
|
{
|
|
// Update our own zoom mode
|
|
ZoomMode = InZoomMode;
|
|
|
|
// And also save it so it's used for new texture editors
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.ZoomMode = ZoomMode;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
ETextureEditorZoomMode FTextureEditorToolkit::GetZoomMode() const
|
|
{
|
|
// Each texture editors keeps a local zoom mode so that it can be changed without affecting other open editors
|
|
return ZoomMode;
|
|
}
|
|
|
|
double FTextureEditorToolkit::CalculateDisplayedZoomLevel() const
|
|
{
|
|
// Avoid calculating dimensions if we're custom anyway
|
|
if (GetZoomMode() == ETextureEditorZoomMode::Custom)
|
|
{
|
|
return Zoom;
|
|
}
|
|
|
|
int32 DisplayWidth, DisplayHeight, DisplayDepth, DisplayArraySize;
|
|
CalculateTextureDimensions(DisplayWidth, DisplayHeight, DisplayDepth, DisplayArraySize, false);
|
|
if (PreviewEffectiveTextureHeight != 0)
|
|
{
|
|
return (double)DisplayHeight / PreviewEffectiveTextureHeight;
|
|
}
|
|
else if (PreviewEffectiveTextureWidth != 0)
|
|
{
|
|
return (double)DisplayWidth / PreviewEffectiveTextureWidth;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void FTextureEditorToolkit::SetCustomZoomLevel( double ZoomValue )
|
|
{
|
|
// snap to discrete steps so that if we are nearly at 1.0 or 2.0, we hit them exactly:
|
|
//ZoomValue = FMath::GridSnap(ZoomValue, MinZoom/4.0);
|
|
|
|
double LogZoom = log2(ZoomValue);
|
|
// the mouse wheel zoom is quantized on ZoomFactorLogSteps
|
|
// but that's too chunky for the drag slider, give it more steps, but on the same quantization grid
|
|
double QuantizationSteps = ZoomFactorLogSteps*2.0;
|
|
double LogZoomQuantized = (1.0/QuantizationSteps) * (double)FMath::RoundToInt( QuantizationSteps * LogZoom );
|
|
ZoomValue = pow(2.0,LogZoomQuantized);
|
|
|
|
ZoomValue = FMath::Clamp(ZoomValue, MinZoom, MaxZoom);
|
|
|
|
// set member variable "Zoom"
|
|
Zoom = ZoomValue;
|
|
|
|
// For now we also want to be in custom mode whenever this is changed
|
|
SetZoomMode(ETextureEditorZoomMode::Custom);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::ZoomIn( )
|
|
{
|
|
// mouse wheel zoom
|
|
const double CurrentZoom = CalculateDisplayedZoomLevel();
|
|
SetCustomZoomLevel(CurrentZoom * ZoomFactor);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::ZoomOut( )
|
|
{
|
|
const double CurrentZoom = CalculateDisplayedZoomLevel();
|
|
SetCustomZoomLevel(CurrentZoom / ZoomFactor);
|
|
}
|
|
|
|
float FTextureEditorToolkit::GetVolumeOpacity() const
|
|
{
|
|
return VolumeOpacity;
|
|
}
|
|
|
|
void FTextureEditorToolkit::SetVolumeOpacity(float InVolumeOpacity)
|
|
{
|
|
VolumeOpacity = FMath::Clamp(InVolumeOpacity, 0.f, 1.f);
|
|
}
|
|
|
|
ETextureEditorVolumeViewMode FTextureEditorToolkit::GetVolumeViewMode() const
|
|
{
|
|
// Each texture editor keeps a local volume view mode so that it can be changed without affecting other open editors
|
|
return VolumeViewMode;
|
|
}
|
|
|
|
void FTextureEditorToolkit::SetVolumeViewMode(const ETextureEditorVolumeViewMode InVolumeViewMode)
|
|
{
|
|
// Update our own volume view mode
|
|
VolumeViewMode = InVolumeViewMode;
|
|
|
|
// And also save it so it's used for new texture editors
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.VolumeViewMode = VolumeViewMode;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
ETextureEditorCubemapViewMode FTextureEditorToolkit::GetCubemapViewMode() const
|
|
{
|
|
// Each texture editor keeps a local cubemap view mode so that it can be changed without affecting other open editors
|
|
return CubemapViewMode;
|
|
}
|
|
|
|
void FTextureEditorToolkit::SetCubemapViewMode(const ETextureEditorCubemapViewMode InCubemapViewMode)
|
|
{
|
|
// Update our own cubemap view mode
|
|
CubemapViewMode = InCubemapViewMode;
|
|
|
|
// And also save it so it's used for new texture editors
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.CubemapViewMode = CubemapViewMode;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsUsingOrientation() const
|
|
{
|
|
return (IsVolumeTexture() && GetVolumeViewMode() == TextureEditorVolumeViewMode_VolumeTrace) ||
|
|
(IsCubeTexture() && GetCubemapViewMode() == TextureEditorCubemapViewMode_3DView && GetFace() < 0);
|
|
}
|
|
|
|
const FRotator& FTextureEditorToolkit::GetOrientation() const
|
|
{
|
|
return Orientation;
|
|
}
|
|
|
|
void FTextureEditorToolkit::SetOrientation(const FRotator& InOrientation)
|
|
{
|
|
Orientation = InOrientation;
|
|
}
|
|
|
|
void FTextureEditorToolkit::ResetOrientation()
|
|
{
|
|
SetOrientation(IsVolumeTexture() ? FRotator(90, 0, -90) : FRotator(0, 0, 0));
|
|
}
|
|
|
|
ETextureEditorSampling FTextureEditorToolkit::GetSampling() const
|
|
{
|
|
return Sampling;
|
|
}
|
|
|
|
/* IToolkit interface
|
|
*****************************************************************************/
|
|
|
|
FText FTextureEditorToolkit::GetBaseToolkitName( ) const
|
|
{
|
|
return LOCTEXT("AppLabel", "Texture Editor");
|
|
}
|
|
|
|
|
|
FName FTextureEditorToolkit::GetToolkitFName( ) const
|
|
{
|
|
return FName("TextureEditor");
|
|
}
|
|
|
|
|
|
FLinearColor FTextureEditorToolkit::GetWorldCentricTabColorScale( ) const
|
|
{
|
|
return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f);
|
|
}
|
|
|
|
|
|
FString FTextureEditorToolkit::GetWorldCentricTabPrefix( ) const
|
|
{
|
|
return LOCTEXT("WorldCentricTabPrefix", "Texture ").ToString();
|
|
}
|
|
|
|
|
|
/* FGCObject interface
|
|
*****************************************************************************/
|
|
|
|
void FTextureEditorToolkit::AddReferencedObjects( FReferenceCollector& Collector )
|
|
{
|
|
Collector.AddReferencedObject(Texture);
|
|
TextureViewport->AddReferencedObjects(Collector);
|
|
}
|
|
|
|
|
|
/* FEditorUndoClient interface
|
|
*****************************************************************************/
|
|
|
|
void FTextureEditorToolkit::PostUndo( bool bSuccess )
|
|
{
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::PostRedo( bool bSuccess )
|
|
{
|
|
PostUndo(bSuccess);
|
|
}
|
|
|
|
|
|
/* FTextureEditorToolkit implementation
|
|
*****************************************************************************/
|
|
|
|
void FTextureEditorToolkit::BindCommands( )
|
|
{
|
|
const FTextureEditorCommands& Commands = FTextureEditorCommands::Get();
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.RedChannel,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::OnChannelButtonCheckStateChanged, ETextureChannelButton::Red),
|
|
FCanExecuteAction());
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.GreenChannel,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::OnChannelButtonCheckStateChanged, ETextureChannelButton::Green),
|
|
FCanExecuteAction());
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.BlueChannel,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::OnChannelButtonCheckStateChanged, ETextureChannelButton::Blue),
|
|
FCanExecuteAction());
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.AlphaChannel,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::OnChannelButtonCheckStateChanged, ETextureChannelButton::Alpha),
|
|
FCanExecuteAction());
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.Desaturation,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleDesaturationChannelActionExecute),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleDesaturationChannelActionIsChecked));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.FillToViewport,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleFillToViewportActionExecute));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.FitToViewport,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleFitToViewportActionExecute));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.ZoomToNatural,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomToNaturalActionExecute));
|
|
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.CheckeredBackground,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionExecute, TextureEditorBackground_Checkered),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionIsChecked, TextureEditorBackground_Checkered));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.CheckeredBackgroundFill,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionExecute, TextureEditorBackground_CheckeredFill),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionIsChecked, TextureEditorBackground_CheckeredFill));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.SolidBackground,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionExecute, TextureEditorBackground_SolidColor),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleCheckeredBackgroundActionIsChecked, TextureEditorBackground_SolidColor));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.TextureBorder,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleTextureBorderActionExecute),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleTextureBorderActionIsChecked));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.DefaultSampling,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleSamplingActionExecute, TextureEditorSampling_Default),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleSamplingActionIsChecked, TextureEditorSampling_Default));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.PointSampling,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleSamplingActionExecute, TextureEditorSampling_Point),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::HandleSamplingActionIsChecked, TextureEditorSampling_Point));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.CompressNow,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleCompressNowActionExecute),
|
|
FCanExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleCompressNowActionCanExecute));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.Reimport,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleReimportActionExecute),
|
|
FCanExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleReimportActionCanExecute));
|
|
|
|
ToolkitCommands->MapAction(
|
|
Commands.Settings,
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleSettingsActionExecute));
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::BuildTexturePropertiesWidget( )
|
|
{
|
|
FDetailsViewArgs Args;
|
|
Args.bHideSelectionTip = true;
|
|
|
|
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
TexturePropertiesWidget = PropertyModule.CreateDetailView(Args);
|
|
TexturePropertiesWidget->SetObject(Texture);
|
|
|
|
// todo, maybe :
|
|
// check cvar "r.VT.MenuRestricted"
|
|
// if set, hide the "VirtualTextureStreaming" property
|
|
// TexturePropertiesWidget->SetIsPropertyVisibleDelegate(FIsPropertyVisible::CreateSP(this, &FTextureEditorToolkit::ShowTextureProperty));
|
|
|
|
return TexturePropertiesWidget.ToSharedRef();
|
|
}
|
|
|
|
void FTextureEditorToolkit::CreateInternalWidgets()
|
|
{
|
|
//
|
|
// Convert the packaging settings names into enums we can use.
|
|
//
|
|
UProjectPackagingSettings const* ProjectSettings = GetDefault<UProjectPackagingSettings>();
|
|
|
|
PackagingSettingsNames.Add(MakeShared<FString>(TEXT("DebugDevelopment")));
|
|
PackagingSettingsNames.Add(MakeShared<FString>(TEXT("TestShipping")));
|
|
PackagingSettingsNames.Add(MakeShared<FString>(TEXT("Distribution")));
|
|
|
|
// Default to Distribution
|
|
TSharedPtr<FString> InitialPackagingSetting = PackagingSettingsNames[2];
|
|
|
|
// Determine which oodle compressor they are using.
|
|
const TCHAR* CompressorName = 0;
|
|
{
|
|
// Validity check the string by trying to convert to enum.
|
|
const FString& LookupCompressor = ProjectSettings->PackageCompressionMethod;
|
|
FOodleDataCompression::ECompressor PackageCompressor = FOodleDataCompression::ECompressor::Kraken;
|
|
if (FOodleDataCompression::ECompressorFromString(LookupCompressor, PackageCompressor))
|
|
{
|
|
OodleCompressor = PackageCompressor;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTextureEditor, Warning, TEXT("Project packaging settings not using Oodle? Failed to recognize compression: %s - using Kraken for estimation."), *LookupCompressor);
|
|
OodleCompressor = FOodleDataCompression::ECompressor::Kraken;
|
|
}
|
|
|
|
FOodleDataCompression::ECompressorToString(OodleCompressor, &CompressorName);
|
|
}
|
|
|
|
OodleCompressionLevel = FOodleDataCompression::ECompressionLevel::Optimal3;
|
|
const TCHAR* LevelName;
|
|
{
|
|
int8 PackageCompressionLevel_Distribution8 = 0;
|
|
if (IntFitsIn<int8>(ProjectSettings->PackageCompressionLevel_Distribution))
|
|
{
|
|
PackageCompressionLevel_Distribution8 = static_cast<int8>(ProjectSettings->PackageCompressionLevel_Distribution);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTextureEditor, Warning, TEXT("PackageCompressionLevel_Distribution in Project Settings is an invalid value = %d, must be [-128, 127]"), ProjectSettings->PackageCompressionLevel_Distribution);
|
|
}
|
|
FOodleDataCompression::ECompressionLevelFromValue(PackageCompressionLevel_Distribution8, OodleCompressionLevel);
|
|
FOodleDataCompression::ECompressionLevelToString(OodleCompressionLevel, &LevelName);
|
|
}
|
|
|
|
// Grab the compression block size in the settings.
|
|
{
|
|
FString CompBlockSizeString;
|
|
if (FParse::Value(*ProjectSettings->PackageAdditionalCompressionOptions, TEXT("-compressionblocksize="), CompBlockSizeString) &&
|
|
FParse::Value(*ProjectSettings->PackageAdditionalCompressionOptions, TEXT("-compressionblocksize="), CompressionBlockSize))
|
|
{
|
|
if (CompBlockSizeString.EndsWith(TEXT("MB")))
|
|
{
|
|
CompressionBlockSize *= 1024 * 1024;
|
|
}
|
|
else if (CompBlockSizeString.EndsWith(TEXT("KB")))
|
|
{
|
|
CompressionBlockSize *= 1024;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTextureEditor, Verbose, TEXT("No compression block size found in settings - using 64KB"));
|
|
CompressionBlockSize = 64*1024;
|
|
}
|
|
}
|
|
|
|
TextureViewport = SNew(STextureEditorViewport, SharedThis(this));
|
|
|
|
OodleTabContainer = SNew(SVerticalBox)
|
|
|
|
//
|
|
// Oodle relevant details container
|
|
//
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(4.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
|
|
//
|
|
// Details label container
|
|
//
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_Encoder", "Encoder:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_Tooltip_Encoder", "Which texture encoder was used to encode the texture."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EncodeSpeed", "Encode Speed:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_Tooltip_EncodeSpeed", "Which of the encode speeds was used for this texture encode, if the encoder supports encode speed."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleRDOEnabledLabel, STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_RDOEnabled", "RDO Lambda:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_Tooltip_RDOEnabled", "Whether or not the texture was encoded with RDO enabled. If enabled, shows the lambda used to encode. Excludes any global ini specific adjustments (e.g. GlobalLambdaMultiplier)"))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleRDOSourceLabel, STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_RDOSource", "RDO Lambda Source:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_Tooltip_RDOSource", "This is where the build system found the lambda to use, due to defaults and fallbacks. (Lambda) means a direct lambda value (Lossy Compression Amount) means it was converted from that property."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleEffortLabel, STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_Effort", "Effort:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_Effort", "Which effort value was used when encoding this texture. Pulled from the encode speed options. Effort represents how much CPU time was spent finding better results."))
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleTilingLabel, STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_UniversalTiling", "Universal Tiling:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_UniversalTiling", "Which universal tiling setting was used when encoding this texture. Specified with encode speed. Universal Tiling is a technique to save on-disk space for platforms that expect tiled textures."))
|
|
]
|
|
]
|
|
|
|
//
|
|
// Details controls container
|
|
//
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleEncoderText, STextBlock)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleEncodeSpeedText, STextBlock)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleRDOText, STextBlock)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleRDOSourceText, STextBlock)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleEffortText, STextBlock)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(OodleTilingText, STextBlock)
|
|
]
|
|
]
|
|
] // end oodle details.
|
|
|
|
//
|
|
// Header for oodle rdo experiments
|
|
//
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SHeader)
|
|
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_TryHeader", "Try Encodings"))
|
|
]
|
|
]
|
|
|
|
//
|
|
// Container for oodle rdo experiments labels/controls
|
|
//
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(4.0f)
|
|
[
|
|
//
|
|
// Labels for oodle rdo experiments.
|
|
//
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_OverrideCompression", "Enabled:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_OverrideEncoding", "If checked, allows you to experiment with Oodle RDO encoder settings to visualize results."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_OverrideRDO", "RDO Lambda:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_OverrideRDO", "The RDO lambda to encode with for experimentation. 0 disables RDO entirely. 1 is largest filesize, 100 is smallest."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_OverrideEffort", "Effort:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_OverrideEffort", "The encoding effort to try. Effort controls how much CPU time spent on finding better results. See the Oodle Texture documentation for detailed information."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_OverrideTiling", "Universal Tiling:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_OverrideTiling", "The universal tiling to try. See the Oodle Texture documentation for detailed information."))
|
|
]
|
|
]
|
|
|
|
//
|
|
// Controls for oodle rdo experiments
|
|
//
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SAssignNew(OodleOverrideCheck, SCheckBox)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::OnUseEditorOodleSettingsChanged)
|
|
.IsChecked(this, &FTextureEditorToolkit::UseEditorOodleSettingsChecked)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SNew(SNumericEntryBox<int32>)
|
|
.Value(this, &FTextureEditorToolkit::GetEditorOodleSettingsRDO)
|
|
.OnValueCommitted(this, &FTextureEditorToolkit::EditorOodleSettingsRDOCommitted)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EditorOodleSettingsEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SNew(SEnumComboBox, StaticEnum< ETextureEncodeEffort >())
|
|
.CurrentValue(this, &FTextureEditorToolkit::GetEditorOodleSettingsEffort)
|
|
.OnEnumSelectionChanged(this, &FTextureEditorToolkit::EditorOodleSettingsEffortChanged)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EditorOodleSettingsEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SNew(SEnumComboBox, StaticEnum< ETextureUniversalTiling >())
|
|
.CurrentValue(this, &FTextureEditorToolkit::GetEditorOodleSettingsTiling)
|
|
.OnEnumSelectionChanged(this, &FTextureEditorToolkit::EditorOodleSettingsTilingChanged)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EditorOodleSettingsEnabled)
|
|
]
|
|
] // end controls
|
|
] // end oodle rdo experiment labels/controls
|
|
|
|
//
|
|
// Header for the on disk estimates
|
|
//
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SHeader)
|
|
.HAlign(EHorizontalAlignment::HAlign_Fill)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimatesHeader", "On-disk Sizes"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimatesHeader", "RDO encoding only helps on-disk texture sizes when package compression is enabled. It does not affect runtime memory usage."))
|
|
]
|
|
]
|
|
//
|
|
// Container for the on disk estimate labels/controls.
|
|
//
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(4.0f)
|
|
[
|
|
//
|
|
// Labels for the on disk estimates
|
|
//
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimatesEnabled", "Enabled:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimatesEnabled", "If checked, texture data will be compressed in the same manner as project packaging in order to estimate the benefits of RDO encoding of the texture."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EncoderSettings", "Packaging Configuration:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_CompressorSettings", "Which packaging configuration to pull from for determining which Oodle compressor and compression level to use."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimateCompressor", "Oodle Compressor:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimateCompressor", "The oodle compressor to use for estimating. Pulled from the packaging configuration specified above."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimateLevel", "Oodle Compression Level:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimateLevel", "The compression level. Pulled from the packaging configuration specified above."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_BlockSize", "Compression Block Size:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_BlockSize", "The size of chunks used when compressing. Pulled from the packaging configuration 'Package Compression Commandline Options'."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimateRaw", "Uncompressed size:"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimateRaw", "The size of the mip or virtual texture data for the texture."))
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OodleTab_Label_EstimateCompressed", "Compressed size (estimate):"))
|
|
.ToolTipText(LOCTEXT("OodleTab_ToolTip_EstimateCompressed", "The size of the compressed mip or virtual texture data for the texture."))
|
|
]
|
|
]
|
|
|
|
//
|
|
// Controls for the on disk estimates
|
|
//
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SAssignNew(OodleEstimateCheck, SCheckBox)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::OnEstimateCompressionChanged)
|
|
.IsChecked(this, &FTextureEditorToolkit::EstimateCompressionChecked)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2)
|
|
[
|
|
SNew(STextComboBox)
|
|
.OptionsSource(&PackagingSettingsNames)
|
|
.OnSelectionChanged(this, &FTextureEditorToolkit::PackagingSettingsChanged)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
.InitiallySelectedItem(InitialPackagingSetting)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(8)
|
|
[
|
|
SAssignNew(OodleCompressorUsed, STextBlock)
|
|
.Text(FText::AsCultureInvariant(CompressorName))
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SAssignNew(OodleLevelUsed, STextBlock)
|
|
.Text(FText::FromString(FString::Printf(TEXT("%s (%d)"), LevelName, (int8)OodleCompressionLevel)))
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SAssignNew(OodleCompressionBlockUsed, STextBlock)
|
|
.Text(FText::AsMemory(CompressionBlockSize))
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SAssignNew(OodleEstimateRaw, STextBlock)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
]
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(6)
|
|
[
|
|
SAssignNew(OodleEstimateCompressed, STextBlock)
|
|
.IsEnabled(this, &FTextureEditorToolkit::EstimateCompressionEnabled)
|
|
]
|
|
]
|
|
]; // end on disk estimates controls
|
|
|
|
|
|
TextureProperties = SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(2.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(ImportedText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(CurrentText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(MaxInGameText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(SizeText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(HasAlphaChannelText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(SourceMipsAlphaDetectedText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(SceneCaptureSizeText, STextBlock)
|
|
]
|
|
]
|
|
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(0.5f)
|
|
[
|
|
SNew(SVerticalBox)
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(MethodText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(FormatText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(LODBiasText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(NumMipsText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(EncodeSpeedText, STextBlock)
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SAssignNew(SceneCaptureNameText, STextBlock)
|
|
]
|
|
]
|
|
]
|
|
|
|
+ SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
.Padding(2.0f)
|
|
[
|
|
BuildTexturePropertiesWidget()
|
|
];
|
|
}
|
|
|
|
void FTextureEditorToolkit::ExtendToolBar()
|
|
{
|
|
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
|
|
|
|
ToolbarExtender->AddToolBarExtension(
|
|
"Asset",
|
|
EExtensionHook::After,
|
|
GetToolkitCommands(),
|
|
FToolBarExtensionDelegate::CreateSP(this, &FTextureEditorToolkit::FillToolbar)
|
|
);
|
|
|
|
AddToolbarExtender(ToolbarExtender);
|
|
|
|
// Extensions are currently disabled in read-only mode, if they are desired to be added in the future we should move this code to the individual extensions
|
|
if(GetOpenMethod() == EAssetOpenMethod::Edit)
|
|
{
|
|
ITextureEditorModule* TextureEditorModule = &FModuleManager::LoadModuleChecked<ITextureEditorModule>("TextureEditor");
|
|
AddToolbarExtender(TextureEditorModule->GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
|
|
}
|
|
}
|
|
|
|
void FTextureEditorToolkit::FillToolbar(FToolBarBuilder& ToolbarBuilder)
|
|
{
|
|
TSharedRef<SWidget> ChannelControl = MakeChannelControlWidget();
|
|
TSharedRef<SWidget> LODControl = MakeLODControlWidget();
|
|
TSharedRef<SWidget> LayerControl = MakeLayerControlWidget();
|
|
TSharedRef<SWidget> SliceControl = MakeSliceControlWidget();
|
|
TSharedRef<SWidget> FaceControl = MakeFaceControlWidget();
|
|
TSharedRef<SWidget> ExposureControl = MakeExposureContolWidget();
|
|
TSharedPtr<SWidget> OptionalOpacityControl = IsVolumeTexture() ? TSharedPtr<SWidget>(MakeOpacityControlWidget()) : nullptr;
|
|
TSharedRef<SWidget> ZoomControl = MakeZoomControlWidget();
|
|
TSharedRef<SWidget> View3DControl = MakeView3DControlWidget();
|
|
|
|
UCurveLinearColorAtlas* Atlas = Cast<UCurveLinearColorAtlas>(GetTexture());
|
|
if (!Atlas)
|
|
{
|
|
// These actions don't make sense in read-only mode
|
|
if(GetOpenMethod() == EAssetOpenMethod::Edit)
|
|
{
|
|
ToolbarBuilder.BeginSection("TextureMisc");
|
|
{
|
|
ToolbarBuilder.AddToolBarButton(FTextureEditorCommands::Get().CompressNow);
|
|
ToolbarBuilder.AddToolBarButton(FTextureEditorCommands::Get().Reimport);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
|
|
ToolbarBuilder.BeginSection("Channels");
|
|
{
|
|
ToolbarBuilder.AddWidget(ChannelControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
|
|
ToolbarBuilder.BeginSection("TextureMipAndExposure");
|
|
{
|
|
ToolbarBuilder.AddWidget(LODControl);
|
|
ToolbarBuilder.AddWidget(ExposureControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
|
|
if (HasLayers())
|
|
{
|
|
ToolbarBuilder.BeginSection("Layers");
|
|
{
|
|
ToolbarBuilder.AddWidget(LayerControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
if (HasSlices())
|
|
{
|
|
ToolbarBuilder.BeginSection("Slices");
|
|
{
|
|
ToolbarBuilder.AddWidget(SliceControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
if (IsCubeTexture())
|
|
{
|
|
ToolbarBuilder.BeginSection("Faces");
|
|
{
|
|
ToolbarBuilder.AddWidget(FaceControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
if (OptionalOpacityControl.IsValid())
|
|
{
|
|
ToolbarBuilder.BeginSection("Opacity");
|
|
{
|
|
ToolbarBuilder.AddWidget(OptionalOpacityControl.ToSharedRef());
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
if (IsCubeTexture() || IsVolumeTexture())
|
|
{
|
|
ToolbarBuilder.BeginSection("View3D");
|
|
{
|
|
ToolbarBuilder.AddWidget(View3DControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
|
|
ToolbarBuilder.BeginSection("Zoom");
|
|
{
|
|
ToolbarBuilder.AddWidget(ZoomControl);
|
|
}
|
|
ToolbarBuilder.EndSection();
|
|
|
|
ToolbarBuilder.BeginSection("Settings");
|
|
ToolbarBuilder.BeginStyleOverride("CalloutToolbar");
|
|
{
|
|
ToolbarBuilder.AddWidget(SNew(SSpacer), NAME_None, false, HAlign_Right);
|
|
ToolbarBuilder.AddComboButton(
|
|
FUIAction(),
|
|
FOnGetContent::CreateSP(this, &FTextureEditorToolkit::OnGenerateSettingsMenu),
|
|
LOCTEXT("SettingsMenu", "View Settings"),
|
|
FText::GetEmpty(),
|
|
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Settings")
|
|
);
|
|
}
|
|
ToolbarBuilder.EndStyleOverride();
|
|
ToolbarBuilder.EndSection();
|
|
}
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::GetMaxMipLevel() const
|
|
{
|
|
TOptional<int32> MaxMipLevel;
|
|
int32 NumMips = GetNumMips();
|
|
if (NumMips > 0)
|
|
{
|
|
MaxMipLevel = NumMips - 1;
|
|
}
|
|
return MaxMipLevel;
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetNumMips( ) const
|
|
{
|
|
if (const UTexture2D* Texture2D = Cast<UTexture2D>(Texture))
|
|
{
|
|
return Texture2D->GetNumMips();
|
|
}
|
|
else if (const UTextureCube* TextureCube = Cast<UTextureCube>(Texture))
|
|
{
|
|
return TextureCube->GetNumMips();
|
|
}
|
|
else if (const UTextureCubeArray* TextureCubeArray = Cast<UTextureCubeArray>(Texture))
|
|
{
|
|
return TextureCubeArray->GetNumMips();
|
|
}
|
|
else if (const UTexture2DArray* Texture2DArray = Cast<UTexture2DArray>(Texture))
|
|
{
|
|
return Texture2DArray->GetNumMips();
|
|
}
|
|
else if (const UVolumeTexture* VolumeTexture = Cast<UVolumeTexture>(Texture))
|
|
{
|
|
return VolumeTexture->GetNumMips();
|
|
}
|
|
else if (const UTextureRenderTarget2D* Texture2DRT = Cast<UTextureRenderTarget2D>(Texture))
|
|
{
|
|
return Texture2DRT->GetNumMips();
|
|
}
|
|
else if (const UTextureRenderTargetCube* TextureCubeRT = Cast<UTextureRenderTargetCube>(Texture))
|
|
{
|
|
return TextureCubeRT->GetNumMips();
|
|
}
|
|
else if (const UTextureRenderTarget2DArray* Texture2DArrayRT = Cast<UTextureRenderTarget2DArray>(Texture))
|
|
{
|
|
return Texture2DArrayRT->GetNumMips();
|
|
}
|
|
else if (const UTextureRenderTargetVolume* VolumeTextureRT = Cast<UTextureRenderTargetVolume>(Texture))
|
|
{
|
|
return VolumeTextureRT->GetNumMips();
|
|
}
|
|
else if (const UTexture2DDynamic* Texture2DDynamic = Cast<UTexture2DDynamic>(Texture))
|
|
{
|
|
return Texture2DDynamic->NumMips;
|
|
}
|
|
else if (const UMediaTexture* MediaTexture = Cast<UMediaTexture>(Texture))
|
|
{
|
|
return MediaTexture->GetTextureNumMips();
|
|
}
|
|
|
|
return MIPLEVEL_MAX;
|
|
}
|
|
|
|
EPixelFormat FTextureEditorToolkit::GetPixelFormat() const
|
|
{
|
|
if (const UTexture2D* Texture2D = Cast<UTexture2D>(Texture))
|
|
{
|
|
return Texture2D->GetPixelFormat(SpecifiedLayer);
|
|
}
|
|
else if (const UTextureCube* TextureCube = Cast<UTextureCube>(Texture))
|
|
{
|
|
return TextureCube->GetPixelFormat();
|
|
}
|
|
else if (const UTexture2DArray* Texture2DArray = Cast<UTexture2DArray>(Texture))
|
|
{
|
|
return Texture2DArray->GetPixelFormat();
|
|
}
|
|
else if (const UTextureCubeArray* TextureCubeArray = Cast<UTextureCubeArray>(Texture))
|
|
{
|
|
return TextureCubeArray->GetPixelFormat();
|
|
}
|
|
else if (const UVolumeTexture* VolumeTexture = Cast<UVolumeTexture>(Texture))
|
|
{
|
|
return VolumeTexture->GetPixelFormat();
|
|
}
|
|
else if (const UTextureRenderTarget2D* Texture2DRT = Cast<UTextureRenderTarget2D>(Texture))
|
|
{
|
|
return Texture2DRT->GetFormat();
|
|
}
|
|
else if (const UTextureRenderTargetCube* TextureCubeRT = Cast<UTextureRenderTargetCube>(Texture))
|
|
{
|
|
return TextureCubeRT->GetFormat();
|
|
}
|
|
else if (const UTextureRenderTarget2DArray* Texture2DArrayRT = Cast<UTextureRenderTarget2DArray>(Texture))
|
|
{
|
|
return Texture2DArrayRT->GetFormat();
|
|
}
|
|
else if (const UTextureRenderTargetVolume* VolumeTextureRT = Cast<UTextureRenderTargetVolume>(Texture))
|
|
{
|
|
return VolumeTextureRT->GetFormat();
|
|
}
|
|
else if (const UTexture2DDynamic* Texture2DDynamic = Cast<UTexture2DDynamic>(Texture))
|
|
{
|
|
return Texture2DDynamic->Format;
|
|
}
|
|
//else if (const UMediaTexture* MediaTexture = Cast<UMediaTexture>(Texture))
|
|
//{
|
|
// UMediaTexture::GetDesc() suggests PF_B8G8R8A8, maybe?
|
|
//}
|
|
|
|
return PF_MAX;
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::GetMaxLayer() const
|
|
{
|
|
return FMath::Max(Texture->Source.GetNumLayers() - 1, 1);
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::GetMaxSlice() const
|
|
{
|
|
return FMath::Max(0, GetNumSlices() - 1);
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsCubeTexture( ) const
|
|
{
|
|
return (Texture->IsA(UTextureCube::StaticClass()) || Texture->IsA(UTextureCubeArray::StaticClass()) || Texture->IsA(UTextureRenderTargetCube::StaticClass()));
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsVolumeTexture() const
|
|
{
|
|
return (Texture->IsA(UVolumeTexture::StaticClass()) || Texture->IsA(UTextureRenderTargetVolume::StaticClass()));
|
|
}
|
|
|
|
bool FTextureEditorToolkit::Is2DArrayTexture() const
|
|
{
|
|
return (Texture->IsA(UTexture2DArray::StaticClass()) || Texture->IsA(UTextureRenderTarget2DArray::StaticClass()));
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsArrayTexture() const
|
|
{
|
|
return Is2DArrayTexture() || Texture->IsA(UTextureCubeArray::StaticClass());
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::OnGenerateMipMapLevelMenu()
|
|
{
|
|
FMenuBuilder MenuBuilder(true, nullptr);
|
|
|
|
for (int32 MipLevel = MIPLEVEL_MIN; MipLevel <= GetMaxMipLevel().Get(MIPLEVEL_MAX); ++MipLevel)
|
|
{
|
|
FText MipNumberText = FText::AsNumber(MipLevel);
|
|
|
|
MenuBuilder.AddMenuEntry(
|
|
FText::Format(LOCTEXT("MipLevel", "Mip Level {0}"), MipNumberText),
|
|
FText::Format(LOCTEXT("MipLevel_Tooltip", "Display Mip Level {0}"), MipNumberText),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleMipLevelChanged, MipLevel),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateLambda([this, MipLevel]() {return SpecifiedMipLevel == MipLevel; })
|
|
)
|
|
);
|
|
}
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::OnGenerateSettingsMenu()
|
|
{
|
|
FMenuBuilder MenuBuilder(true, ToolkitCommands);
|
|
FTextureEditorViewOptionsMenu::MakeMenu(MenuBuilder);
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
/* FTextureEditorToolkit callbacks
|
|
*****************************************************************************/
|
|
bool FTextureEditorToolkit::IsChannelButtonEnabled(ETextureChannelButton Button) const
|
|
{
|
|
EPixelFormatChannelFlags ValidTextureChannels = GetPixelFormatValidChannels(GetPixelFormat());
|
|
return EnumHasAnyFlags(ValidTextureChannels, GetPixelFormatChannelFlagForButton(Button));
|
|
}
|
|
|
|
FSlateColor FTextureEditorToolkit::GetChannelButtonBackgroundColor(ETextureChannelButton Button) const
|
|
{
|
|
FSlateColor Dropdown = FAppStyle::Get().GetSlateColor("Colors.Dropdown");
|
|
|
|
switch (Button)
|
|
{
|
|
case ETextureChannelButton::Red:
|
|
return bIsRedChannel ? FLinearColor::Red : FLinearColor::White;
|
|
case ETextureChannelButton::Green:
|
|
return bIsGreenChannel ? FLinearColor::Green : FLinearColor::White;
|
|
case ETextureChannelButton::Blue:
|
|
return bIsBlueChannel ? FLinearColor::Blue : FLinearColor::White;
|
|
case ETextureChannelButton::Alpha:
|
|
return FLinearColor::White;
|
|
default:
|
|
check(false);
|
|
return FSlateColor();
|
|
}
|
|
}
|
|
|
|
FSlateColor FTextureEditorToolkit::GetChannelButtonForegroundColor(ETextureChannelButton Button) const
|
|
{
|
|
FSlateColor DefaultForeground = FAppStyle::Get().GetSlateColor("Colors.Foreground");
|
|
|
|
switch (Button)
|
|
{
|
|
case ETextureChannelButton::Red:
|
|
return bIsRedChannel ? FLinearColor::Black : DefaultForeground;
|
|
case ETextureChannelButton::Green:
|
|
return bIsGreenChannel ? FLinearColor::Black : DefaultForeground;
|
|
case ETextureChannelButton::Blue:
|
|
return bIsBlueChannel ? FLinearColor::Black : DefaultForeground;
|
|
case ETextureChannelButton::Alpha:
|
|
return bIsAlphaChannel ? FLinearColor::Black : DefaultForeground;
|
|
default:
|
|
check(false);
|
|
return FSlateColor::UseForeground();
|
|
}
|
|
}
|
|
|
|
void FTextureEditorToolkit::OnChannelButtonCheckStateChanged(ETextureChannelButton Button)
|
|
{
|
|
switch (Button)
|
|
{
|
|
case ETextureChannelButton::Red:
|
|
bIsRedChannel = !bIsRedChannel;
|
|
break;
|
|
case ETextureChannelButton::Green:
|
|
bIsGreenChannel = !bIsGreenChannel;
|
|
break;
|
|
case ETextureChannelButton::Blue:
|
|
bIsBlueChannel = !bIsBlueChannel;
|
|
break;
|
|
case ETextureChannelButton::Alpha:
|
|
bIsAlphaChannel = !bIsAlphaChannel;
|
|
break;
|
|
default:
|
|
check(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ECheckBoxState FTextureEditorToolkit::OnGetChannelButtonCheckState(ETextureChannelButton Button) const
|
|
{
|
|
switch (Button)
|
|
{
|
|
case ETextureChannelButton::Red:
|
|
return bIsRedChannel ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
break;
|
|
case ETextureChannelButton::Green:
|
|
return bIsGreenChannel ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
break;
|
|
case ETextureChannelButton::Blue:
|
|
return bIsBlueChannel ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
break;
|
|
case ETextureChannelButton::Alpha:
|
|
return bIsAlphaChannel ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
break;
|
|
default:
|
|
check(false);
|
|
return ECheckBoxState::Unchecked;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleCheckeredBackgroundActionExecute( ETextureEditorBackgrounds Background )
|
|
{
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.Background = Background;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleCheckeredBackgroundActionIsChecked( ETextureEditorBackgrounds Background )
|
|
{
|
|
const UTextureEditorSettings& Settings = *GetDefault<UTextureEditorSettings>();
|
|
|
|
return (Background == Settings.Background);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleSamplingActionExecute(ETextureEditorSampling InSampling)
|
|
{
|
|
// Update our own sampling
|
|
Sampling = InSampling;
|
|
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.Sampling = InSampling;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleSamplingActionIsChecked(ETextureEditorSampling InSampling)
|
|
{
|
|
return InSampling == Sampling;
|
|
}
|
|
|
|
// Callback for toggling the volume view action.
|
|
void FTextureEditorToolkit::HandleVolumeViewModeActionExecute(ETextureEditorVolumeViewMode InViewMode)
|
|
{
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.VolumeViewMode = InViewMode;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
// Callback for getting the checked state of the volume view action.
|
|
bool FTextureEditorToolkit::HandleVolumeViewModeActionIsChecked(ETextureEditorVolumeViewMode InViewMode)
|
|
{
|
|
const UTextureEditorSettings& Settings = *GetDefault<UTextureEditorSettings>();
|
|
|
|
return (InViewMode == Settings.VolumeViewMode);
|
|
}
|
|
|
|
// Callback for toggling the cubemap view action.
|
|
void FTextureEditorToolkit::HandleCubemapViewModeActionExecute(ETextureEditorCubemapViewMode InViewMode)
|
|
{
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.CubemapViewMode = InViewMode;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
// Callback for getting the checked state of the cubemap view action.
|
|
bool FTextureEditorToolkit::HandleCubemapViewModeActionIsChecked(ETextureEditorCubemapViewMode InViewMode)
|
|
{
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
return Settings.CubemapViewMode == InViewMode;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleCompressNowActionExecute( )
|
|
{
|
|
GWarn->BeginSlowTask(NSLOCTEXT("TextureEditor", "CompressNow", "Compressing 1 Textures that have Defer Compression set"), true);
|
|
|
|
if (Texture->DeferCompression)
|
|
{
|
|
// turn off deferred compression and compress the texture
|
|
Texture->DeferCompression = false;
|
|
Texture->Source.Compress();
|
|
Texture->PostEditChange();
|
|
|
|
PopulateQuickInfo();
|
|
}
|
|
|
|
GWarn->EndSlowTask();
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleCompressNowActionCanExecute( ) const
|
|
{
|
|
return (Texture->DeferCompression != 0);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleFitToViewportActionExecute( )
|
|
{
|
|
SetZoomMode(ETextureEditorZoomMode::Fit);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleFillToViewportActionExecute()
|
|
{
|
|
SetZoomMode(ETextureEditorZoomMode::Fill);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleZoomToNaturalActionExecute()
|
|
{
|
|
SetCustomZoomLevel(1);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleMipLevelCheckBoxCheckedStateChanged( ECheckBoxState InNewState )
|
|
{
|
|
bUseSpecifiedMipLevel = InNewState == ECheckBoxState::Checked;
|
|
}
|
|
|
|
|
|
ECheckBoxState FTextureEditorToolkit::HandleMipLevelCheckBoxIsChecked( ) const
|
|
{
|
|
return GetUseSpecifiedMip() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleMipLevelCheckBoxIsEnabled( ) const
|
|
{
|
|
return GetMaxMipLevel().Get(MIPLEVEL_MAX) > 0;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleMipLevelChanged(int32 NewMipLevel)
|
|
{
|
|
SpecifiedMipLevel = FMath::Clamp<int32>(NewMipLevel, MIPLEVEL_MIN, GetMaxMipLevel().Get(MIPLEVEL_MAX));
|
|
|
|
MipLevelTextBlock->SetText(FText::Format(LOCTEXT("MipLevel", "Mip Level {0}"), SpecifiedMipLevel));
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::HandleMipLevelEntryBoxValue( ) const
|
|
{
|
|
return SpecifiedMipLevel;
|
|
}
|
|
|
|
FReply FTextureEditorToolkit::HandleMipMapMinusButtonClicked()
|
|
{
|
|
HandleMipLevelChanged(--SpecifiedMipLevel);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
FReply FTextureEditorToolkit::HandleMipMapPlusButtonClicked()
|
|
{
|
|
HandleMipLevelChanged(++SpecifiedMipLevel);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleLayerEntryBoxChanged(int32 NewLayer)
|
|
{
|
|
SpecifiedLayer = FMath::Clamp<int32>(NewLayer, 0, Texture->Source.GetNumLayers() - 1);
|
|
PopulateQuickInfo();
|
|
}
|
|
|
|
|
|
TOptional<int32> FTextureEditorToolkit::HandleLayerEntryBoxValue() const
|
|
{
|
|
return SpecifiedLayer;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::HasLayers() const
|
|
{
|
|
return Texture->Source.GetNumLayers() > 1;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::HasSlices() const
|
|
{
|
|
// slice selection should be supported even for a texture array with less than two elements, because array elements can be added dynamically
|
|
return IsArrayTexture();
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetNumSlices() const
|
|
{
|
|
if (Texture->IsA(UTexture2DArray::StaticClass()))
|
|
{
|
|
return Cast<UTexture2DArray>(Texture)->GetArraySize();
|
|
}
|
|
else if (Texture->IsA(UTextureRenderTarget2DArray::StaticClass()))
|
|
{
|
|
return Cast<UTextureRenderTarget2DArray>(Texture)->GetSurfaceArraySize();
|
|
}
|
|
else if (Texture->IsA(UTextureCubeArray::StaticClass()))
|
|
{
|
|
// for a TextureCube array SliceIndex represents an index of a cubemap in the array
|
|
return Cast<UTextureCubeArray>(Texture)->GetSurfaceArraySize() / 6;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
bool FTextureEditorToolkit::HandleSliceCheckBoxIsEnabled() const
|
|
{
|
|
return GetNumSlices() > 1;
|
|
}
|
|
|
|
ECheckBoxState FTextureEditorToolkit::HandleSliceCheckBoxIsChecked() const
|
|
{
|
|
return GetUseSpecifiedSlice() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleSliceCheckBoxCheckedStateChanged(ECheckBoxState InNewState)
|
|
{
|
|
bUseSpecifiedSlice = InNewState == ECheckBoxState::Checked;
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::HandleSliceEntryBoxValue() const
|
|
{
|
|
return FMath::Clamp<int32>(SpecifiedSlice, 0, GetMaxSlice().Get(0));
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleSliceEntryBoxChanged(int32 NewSlice)
|
|
{
|
|
SpecifiedSlice = FMath::Clamp<int32>(NewSlice, 0, GetMaxSlice().Get(0));
|
|
PopulateQuickInfo();
|
|
}
|
|
|
|
ECheckBoxState FTextureEditorToolkit::HandleFaceCheckBoxIsChecked() const
|
|
{
|
|
return GetUseSpecifiedFace() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleFaceCheckBoxCheckedStateChanged(ECheckBoxState InNewState)
|
|
{
|
|
bUseSpecifiedFace = InNewState == ECheckBoxState::Checked;
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::HandleFaceEntryBoxValue() const
|
|
{
|
|
return FMath::Clamp<int32>(SpecifiedFace, 0, 5);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleFaceEntryBoxChanged(int32 NewFace)
|
|
{
|
|
SpecifiedFace = FMath::Clamp<int32>(NewFace, 0, 5);
|
|
PopulateQuickInfo();
|
|
}
|
|
|
|
ECheckBoxState FTextureEditorToolkit::HandleView3DCheckBoxIsChecked() const
|
|
{
|
|
if (IsVolumeTexture())
|
|
{
|
|
return GetVolumeViewMode() == TextureEditorVolumeViewMode_VolumeTrace ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
else
|
|
{
|
|
check(IsCubeTexture());
|
|
return GetCubemapViewMode() == TextureEditorCubemapViewMode_3DView ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleView3DCheckBoxCheckedStateChanged(ECheckBoxState InNewState)
|
|
{
|
|
if (IsVolumeTexture())
|
|
{
|
|
SetVolumeViewMode(InNewState == ECheckBoxState::Checked ? TextureEditorVolumeViewMode_VolumeTrace : TextureEditorVolumeViewMode_DepthSlices);
|
|
}
|
|
else
|
|
{
|
|
check(IsCubeTexture());
|
|
SetCubemapViewMode(InNewState == ECheckBoxState::Checked ? TextureEditorCubemapViewMode_3DView : TextureEditorCubemapViewMode_2DView);
|
|
}
|
|
}
|
|
|
|
bool FTextureEditorToolkit::HandleReimportActionCanExecute( ) const
|
|
{
|
|
if (Texture->IsA<ULightMapTexture2D>() || Texture->IsA<UShadowMapTexture2D>() || Texture->IsA<UTexture2DDynamic>() || Texture->IsA<UTextureRenderTarget>() || Texture->IsA<UCurveLinearColorAtlas>())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleReimportActionExecute( )
|
|
{
|
|
FReimportManager::Instance()->ReimportAsync(Texture, /*bAskForNewFileIfMissing=*/true);
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleReimportManagerPostReimport( UObject* InObject, bool bSuccess )
|
|
{
|
|
// Ignore if this is regarding a different object
|
|
if (InObject != Texture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Re-enable viewport rendering now that the texture should be in a known state again
|
|
TextureViewport->EnableRendering();
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleReimportManagerPreReimport( UObject* InObject )
|
|
{
|
|
// Ignore if this is regarding a different object
|
|
if (InObject != Texture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Disable viewport rendering until the texture has finished re-importing
|
|
TextureViewport->DisableRendering();
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleAssetPostImport(UFactory* InFactory, UObject* InObject)
|
|
{
|
|
if (Cast<UTexture>(InObject) != nullptr && InObject == Texture && TexturePropertiesWidget != nullptr )
|
|
{
|
|
// Refresh this object within the details panel
|
|
TexturePropertiesWidget->SetObject(InObject);
|
|
}
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleDesaturationChannelActionExecute( )
|
|
{
|
|
bIsDesaturation = !bIsDesaturation;
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleDesaturationChannelActionIsChecked( ) const
|
|
{
|
|
return bIsDesaturation;
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleSettingsActionExecute( )
|
|
{
|
|
FModuleManager::LoadModuleChecked<ISettingsModule>("Settings").ShowViewer("Editor", "ContentEditors", "TextureEditor");
|
|
}
|
|
|
|
TSharedRef<SDockTab> FTextureEditorToolkit::HandleTabSpawnerSpawnOodle(const FSpawnTabArgs& Args)
|
|
{
|
|
check(Args.GetTabId() == OodleTabId);
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("TextureOodleTitle", "Oodle"))
|
|
[
|
|
OodleTabContainer.ToSharedRef()
|
|
];
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
TSharedRef<SDockTab> FTextureEditorToolkit::HandleTabSpawnerSpawnProperties( const FSpawnTabArgs& Args )
|
|
{
|
|
check(Args.GetTabId() == PropertiesTabId);
|
|
|
|
TSharedRef<SDockTab> SpawnedTab = SNew(SDockTab)
|
|
.Label(LOCTEXT("TexturePropertiesTitle", "Details"))
|
|
[
|
|
TextureProperties.ToSharedRef()
|
|
];
|
|
|
|
PopulateQuickInfo();
|
|
|
|
return SpawnedTab;
|
|
}
|
|
|
|
|
|
TSharedRef<SDockTab> FTextureEditorToolkit::HandleTabSpawnerSpawnViewport( const FSpawnTabArgs& Args )
|
|
{
|
|
check(Args.GetTabId() == ViewportTabId);
|
|
|
|
return SNew(SDockTab)
|
|
.Label(LOCTEXT("TextureViewportTitle", "Viewport"))
|
|
[
|
|
TextureViewport.ToSharedRef()
|
|
];
|
|
}
|
|
|
|
|
|
void FTextureEditorToolkit::HandleTextureBorderActionExecute( )
|
|
{
|
|
UTextureEditorSettings& Settings = *GetMutableDefault<UTextureEditorSettings>();
|
|
Settings.TextureBorderEnabled = !Settings.TextureBorderEnabled;
|
|
Settings.PostEditChange();
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::HandleTextureBorderActionIsChecked( ) const
|
|
{
|
|
const UTextureEditorSettings& Settings = *GetDefault<UTextureEditorSettings>();
|
|
|
|
return Settings.TextureBorderEnabled;
|
|
}
|
|
|
|
EVisibility FTextureEditorToolkit::HandleExposureBiasWidgetVisibility() const
|
|
{
|
|
if (Texture)
|
|
{
|
|
FTexturePlatformData** RunningPlatformDataPtr = Texture->GetRunningPlatformData();
|
|
if (RunningPlatformDataPtr && *RunningPlatformDataPtr && IsHDR((*RunningPlatformDataPtr)->PixelFormat))
|
|
{
|
|
return EVisibility::Visible;
|
|
}
|
|
}
|
|
return EVisibility::Collapsed;
|
|
}
|
|
|
|
|
|
TOptional<int32> FTextureEditorToolkit::HandleExposureBiasBoxValue() const
|
|
{
|
|
return GetExposureBias();
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleExposureBiasBoxValueChanged(int32 NewExposure)
|
|
{
|
|
ExposureBias = NewExposure;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleOpacitySliderChanged(float NewValue)
|
|
{
|
|
SetVolumeOpacity(NewValue);
|
|
}
|
|
|
|
TOptional<float> FTextureEditorToolkit::HandleOpacitySliderValue() const
|
|
{
|
|
return GetVolumeOpacity();
|
|
}
|
|
|
|
|
|
FReply FTextureEditorToolkit::HandleViewOptionsMenuButtonClicked()
|
|
{
|
|
if (ViewOptionsMenuAnchor->ShouldOpenDueToClick())
|
|
{
|
|
ViewOptionsMenuAnchor->SetIsOpen(true);
|
|
}
|
|
else
|
|
{
|
|
ViewOptionsMenuAnchor->SetIsOpen(false);
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleZoomMenuEntryClicked(double ZoomValue)
|
|
{
|
|
SetCustomZoomLevel(ZoomValue);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleZoomMenuFillClicked()
|
|
{
|
|
SetZoomMode(ETextureEditorZoomMode::Fill);
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleZoomMenuFitClicked()
|
|
{
|
|
SetZoomMode(ETextureEditorZoomMode::Fit);
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsZoomMenuFillChecked() const
|
|
{
|
|
return IsCurrentZoomMode(ETextureEditorZoomMode::Fill);
|
|
}
|
|
|
|
bool FTextureEditorToolkit::IsZoomMenuFitChecked() const
|
|
{
|
|
return IsCurrentZoomMode(ETextureEditorZoomMode::Fit);
|
|
}
|
|
|
|
FText FTextureEditorToolkit::HandleZoomPercentageText() const
|
|
{
|
|
double DisplayedZoomLevel = CalculateDisplayedZoomLevel();
|
|
FText ZoomLevelPercent = FText::AsPercent(DisplayedZoomLevel);
|
|
|
|
// For fit and fill, show the effective zoom level in parenthesis - eg. "Fill (220%)"
|
|
static const FText ZoomModeWithPercentFormat = LOCTEXT("ZoomModeWithPercentFormat", "{ZoomMode} ({ZoomPercent})");
|
|
if (GetZoomMode() == ETextureEditorZoomMode::Fit)
|
|
{
|
|
static const FText ZoomModeFit = LOCTEXT("ZoomModeFit", "Fit");
|
|
return FText::FormatNamed(ZoomModeWithPercentFormat, TEXT("ZoomMode"), ZoomModeFit, TEXT("ZoomPercent"), ZoomLevelPercent);
|
|
}
|
|
|
|
if (GetZoomMode() == ETextureEditorZoomMode::Fill)
|
|
{
|
|
static const FText ZoomModeFill = LOCTEXT("ZoomModeFill", "Fill");
|
|
return FText::FormatNamed(ZoomModeWithPercentFormat, TEXT("ZoomMode"), ZoomModeFill, TEXT("ZoomPercent"), ZoomLevelPercent);
|
|
}
|
|
|
|
// If custom, then just the percent is enough
|
|
return ZoomLevelPercent;
|
|
}
|
|
|
|
void FTextureEditorToolkit::HandleZoomSliderChanged(float SliderValue)
|
|
{
|
|
// zoom slider is log scale, SliderValue in [0,1] between MinZoom and MaxZoom
|
|
double Octaves = log2( MaxZoom/MinZoom );
|
|
double ZoomValue = pow(2.0,SliderValue * Octaves) * MinZoom;
|
|
|
|
SetCustomZoomLevel((float)ZoomValue);
|
|
}
|
|
|
|
float FTextureEditorToolkit::HandleZoomSliderValue() const
|
|
{
|
|
double ZoomValue = CalculateDisplayedZoomLevel();
|
|
double Octaves = log2( MaxZoom/MinZoom );
|
|
double SliderValue = log2( ZoomValue/MinZoom ) / Octaves;
|
|
|
|
return (float)SliderValue;
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetEditorOodleSettingsEffort() const
|
|
{
|
|
return CustomEncoding->OodleEncodeEffort;
|
|
}
|
|
|
|
void FTextureEditorToolkit::EditorOodleSettingsEffortChanged(int32 NewValue, ESelectInfo::Type SelectionType)
|
|
{
|
|
bool bChanged = CustomEncoding->OodleEncodeEffort != NewValue;
|
|
|
|
CustomEncoding->OodleEncodeEffort = IntCastChecked<uint8>(NewValue);
|
|
|
|
if (CustomEncoding->bUseCustomEncode || bChanged)
|
|
{
|
|
PostTextureRecode();
|
|
}
|
|
}
|
|
|
|
int32 FTextureEditorToolkit::GetEditorOodleSettingsTiling() const
|
|
{
|
|
return CustomEncoding->OodleUniversalTiling;
|
|
}
|
|
|
|
void FTextureEditorToolkit::EditorOodleSettingsTilingChanged(int32 NewValue, ESelectInfo::Type SelectionType)
|
|
{
|
|
bool bChanged = CustomEncoding->OodleUniversalTiling != NewValue;
|
|
CustomEncoding->OodleUniversalTiling = IntCastChecked<uint8>(NewValue);
|
|
|
|
if (CustomEncoding->bUseCustomEncode && bChanged)
|
|
{
|
|
PostTextureRecode();
|
|
}
|
|
}
|
|
|
|
TOptional<int32> FTextureEditorToolkit::GetEditorOodleSettingsRDO() const
|
|
{
|
|
return CustomEncoding->OodleRDOLambda;
|
|
}
|
|
|
|
void FTextureEditorToolkit::EditorOodleSettingsRDOCommitted(int32 NewValue, ETextCommit::Type CommitType)
|
|
{
|
|
if (NewValue > 100)
|
|
{
|
|
NewValue = 100;
|
|
}
|
|
if (NewValue < 0)
|
|
{
|
|
NewValue = 0;
|
|
}
|
|
|
|
bool bChanged = CustomEncoding->OodleRDOLambda != (int8)NewValue;
|
|
|
|
CustomEncoding->OodleRDOLambda = (int8)NewValue;
|
|
|
|
if (CustomEncoding->bUseCustomEncode && bChanged)
|
|
{
|
|
PostTextureRecode();
|
|
}
|
|
}
|
|
|
|
|
|
bool FTextureEditorToolkit::EditorOodleSettingsEnabled() const
|
|
{
|
|
return CustomEncoding->bUseCustomEncode;
|
|
}
|
|
|
|
ECheckBoxState FTextureEditorToolkit::UseEditorOodleSettingsChecked() const
|
|
{
|
|
return CustomEncoding->bUseCustomEncode ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void FTextureEditorToolkit::OnUseEditorOodleSettingsChanged(ECheckBoxState NewState)
|
|
{
|
|
// We need to convince the texture to recompress and signal all its users
|
|
// that they need to update, so we do this by faking a compression method property change.
|
|
CustomEncoding->bUseCustomEncode = NewState == ECheckBoxState::Checked ? true : false;
|
|
|
|
PostTextureRecode();
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeChannelControlWidget()
|
|
{
|
|
auto OnChannelCheckStateChanged = [this](ECheckBoxState NewState, ETextureChannelButton Button)
|
|
{
|
|
OnChannelButtonCheckStateChanged(Button);
|
|
};
|
|
|
|
TSharedRef<SWidget> ChannelControl =
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FAppStyle::Get(), "TextureEditor.ChannelButtonStyle")
|
|
.BorderBackgroundColor(this, &FTextureEditorToolkit::GetChannelButtonBackgroundColor, ETextureChannelButton::Red)
|
|
.ForegroundColor(this, &FTextureEditorToolkit::GetChannelButtonForegroundColor, ETextureChannelButton::Red)
|
|
.OnCheckStateChanged_Lambda(OnChannelCheckStateChanged, ETextureChannelButton::Red)
|
|
.IsChecked(this, &FTextureEditorToolkit::OnGetChannelButtonCheckState, ETextureChannelButton::Red)
|
|
.IsEnabled(this, &FTextureEditorToolkit::IsChannelButtonEnabled, ETextureChannelButton::Red)
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("TextureEditor.ChannelButtonFont"))
|
|
.Text(FText::FromString("R"))
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FAppStyle::Get(), "TextureEditor.ChannelButtonStyle")
|
|
.BorderBackgroundColor(this, &FTextureEditorToolkit::GetChannelButtonBackgroundColor, ETextureChannelButton::Green)
|
|
.ForegroundColor(this, &FTextureEditorToolkit::GetChannelButtonForegroundColor, ETextureChannelButton::Green)
|
|
.OnCheckStateChanged_Lambda(OnChannelCheckStateChanged, ETextureChannelButton::Green)
|
|
.IsChecked(this, &FTextureEditorToolkit::OnGetChannelButtonCheckState, ETextureChannelButton::Green)
|
|
.IsEnabled(this, &FTextureEditorToolkit::IsChannelButtonEnabled, ETextureChannelButton::Green)
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("TextureEditor.ChannelButtonFont"))
|
|
.Text(FText::FromString("G"))
|
|
]
|
|
]
|
|
|
|
+SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FAppStyle::Get(), "TextureEditor.ChannelButtonStyle")
|
|
.BorderBackgroundColor(this, &FTextureEditorToolkit::GetChannelButtonBackgroundColor, ETextureChannelButton::Blue)
|
|
.ForegroundColor(this, &FTextureEditorToolkit::GetChannelButtonForegroundColor, ETextureChannelButton::Blue)
|
|
.OnCheckStateChanged_Lambda(OnChannelCheckStateChanged, ETextureChannelButton::Blue)
|
|
.IsChecked(this, &FTextureEditorToolkit::OnGetChannelButtonCheckState, ETextureChannelButton::Blue)
|
|
.IsEnabled(this, &FTextureEditorToolkit::IsChannelButtonEnabled, ETextureChannelButton::Blue)
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("TextureEditor.ChannelButtonFont"))
|
|
.Text(FText::FromString("B"))
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.Style(FAppStyle::Get(), "TextureEditor.ChannelButtonStyle")
|
|
.BorderBackgroundColor(this, &FTextureEditorToolkit::GetChannelButtonBackgroundColor, ETextureChannelButton::Alpha)
|
|
.ForegroundColor(this, &FTextureEditorToolkit::GetChannelButtonForegroundColor, ETextureChannelButton::Alpha)
|
|
.OnCheckStateChanged_Lambda(OnChannelCheckStateChanged, ETextureChannelButton::Alpha)
|
|
.IsChecked(this, &FTextureEditorToolkit::OnGetChannelButtonCheckState, ETextureChannelButton::Alpha)
|
|
.IsEnabled(this, &FTextureEditorToolkit::IsChannelButtonEnabled, ETextureChannelButton::Alpha)
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(FAppStyle::Get().GetFontStyle("TextureEditor.ChannelButtonFont"))
|
|
.Text(FText::FromString("A"))
|
|
]
|
|
];
|
|
|
|
return ChannelControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeLODControlWidget()
|
|
{
|
|
TSharedRef<SWidget> LODControl = SNew(SBox)
|
|
.WidthOverride(212.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.IsEnabled(this, &FTextureEditorToolkit::HandleMipLevelCheckBoxIsEnabled)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 2.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &FTextureEditorToolkit::HandleMipLevelCheckBoxIsChecked)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::HandleMipLevelCheckBoxCheckedStateChanged)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2.0f, 0.0f, 4.0f, 0.0f)
|
|
[
|
|
SNew(SComboButton)
|
|
.IsEnabled(this, &FTextureEditorToolkit::GetUseSpecifiedMip)
|
|
.OnGetMenuContent(this, &FTextureEditorToolkit::OnGenerateMipMapLevelMenu)
|
|
.ButtonContent()
|
|
[
|
|
SAssignNew(MipLevelTextBlock, STextBlock)
|
|
.Text(FText::Format(LOCTEXT("MipLevel", "Mip Level {0}"), SpecifiedMipLevel))
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "TextureEditor.MipmapButtonStyle")
|
|
.OnClicked(this, &FTextureEditorToolkit::HandleMipMapPlusButtonClicked)
|
|
.IsEnabled(this, &FTextureEditorToolkit::GetUseSpecifiedMip)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FAppStyle::Get().GetBrush("Icons.Plus"))
|
|
.ColorAndOpacity(FSlateColor::UseForeground())
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(4.0f)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "TextureEditor.MipmapButtonStyle")
|
|
.OnClicked(this, &FTextureEditorToolkit::HandleMipMapMinusButtonClicked)
|
|
.IsEnabled(this, &FTextureEditorToolkit::GetUseSpecifiedMip)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FAppStyle::Get().GetBrush("Icons.Minus"))
|
|
.ColorAndOpacity(FSlateColor::UseForeground())
|
|
]
|
|
]
|
|
];
|
|
|
|
return LODControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeLayerControlWidget()
|
|
{
|
|
TSharedRef<SWidget> LayerControl = SNew(SBox)
|
|
.WidthOverride(160.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("TextureEditor", "Layer", "Layer"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SNumericEntryBox<int32>)
|
|
.AllowSpin(true)
|
|
.MinSliderValue(0)
|
|
.MaxSliderValue(this, &FTextureEditorToolkit::GetMaxLayer)
|
|
.Value(this, &FTextureEditorToolkit::HandleLayerEntryBoxValue)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleLayerEntryBoxChanged)
|
|
]
|
|
];
|
|
|
|
return LayerControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeSliceControlWidget()
|
|
{
|
|
TSharedRef<SWidget> SliceControl = SNew(SBox)
|
|
.WidthOverride(212.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.IsEnabled(this, &FTextureEditorToolkit::HandleSliceCheckBoxIsEnabled)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("TextureEditor", "Slice", "Slice"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 2.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &FTextureEditorToolkit::HandleSliceCheckBoxIsChecked)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::HandleSliceCheckBoxCheckedStateChanged)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SNumericEntryBox<int32>)
|
|
.IsEnabled(this, &FTextureEditorToolkit::GetUseSpecifiedSlice)
|
|
.AllowSpin(true)
|
|
.MinSliderValue(0)
|
|
.MaxSliderValue(this, &FTextureEditorToolkit::GetMaxSlice)
|
|
.Value(this, &FTextureEditorToolkit::HandleSliceEntryBoxValue)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleSliceEntryBoxChanged)
|
|
]
|
|
];
|
|
|
|
return SliceControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeFaceControlWidget()
|
|
{
|
|
TSharedRef<SWidget> FaceControl = SNew(SBox)
|
|
.WidthOverride(212.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("TextureEditor", "Face", "Face"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 2.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &FTextureEditorToolkit::HandleFaceCheckBoxIsChecked)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::HandleFaceCheckBoxCheckedStateChanged)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SNumericEntryBox<int32>)
|
|
.IsEnabled(this, &FTextureEditorToolkit::GetUseSpecifiedFace)
|
|
.AllowSpin(true)
|
|
.MinSliderValue(0)
|
|
.MaxSliderValue(5)
|
|
.Value(this, &FTextureEditorToolkit::HandleFaceEntryBoxValue)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleFaceEntryBoxChanged)
|
|
]
|
|
];
|
|
|
|
return FaceControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeExposureContolWidget()
|
|
{
|
|
TSharedRef<SWidget> ExposureControl = SNew(SBox)
|
|
.WidthOverride(160.0f)
|
|
.Visibility(this, &FTextureEditorToolkit::HandleExposureBiasWidgetVisibility)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(8.0f, 0.0f, 4.0f, 0.0f)
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("ExposureBiasLabel", "Exposure Bias"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SNumericEntryBox<int32>)
|
|
.AllowSpin(true)
|
|
.MinSliderValue(MinExposure)
|
|
.MaxSliderValue(MaxExposure)
|
|
.Value(this, &FTextureEditorToolkit::HandleExposureBiasBoxValue)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleExposureBiasBoxValueChanged)
|
|
]
|
|
]
|
|
];
|
|
return ExposureControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeOpacityControlWidget()
|
|
{
|
|
TSharedRef<SWidget> OpacityControl = SNew(SBox)
|
|
.WidthOverride(160.0f)
|
|
[
|
|
// opacity slider
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("OpacityLabel", "Opacity"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SNumericEntryBox<float>)
|
|
.AllowSpin(true)
|
|
.MinSliderValue(0.0f)
|
|
.MaxSliderValue(1.0f)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleOpacitySliderChanged)
|
|
.Value(this, &FTextureEditorToolkit::HandleOpacitySliderValue)
|
|
]
|
|
];
|
|
|
|
return OpacityControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeZoomControlWidget()
|
|
{
|
|
const FMargin ToolbarSlotPadding(4.0f, 1.0f);
|
|
const FMargin ToolbarButtonPadding(4.0f, 0.0f);
|
|
|
|
FMenuBuilder ZoomMenuBuilder(true, NULL);
|
|
{
|
|
FUIAction Zoom25Action(FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuEntryClicked, 0.25));
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("Zoom25Action", "25%"), LOCTEXT("Zoom25ActionHint", "Show the texture at a quarter of its size."), FSlateIcon(), Zoom25Action);
|
|
|
|
FUIAction Zoom50Action(FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuEntryClicked, 0.5));
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("Zoom50Action", "50%"), LOCTEXT("Zoom50ActionHint", "Show the texture at half its size."), FSlateIcon(), Zoom50Action);
|
|
|
|
FUIAction Zoom100Action(FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuEntryClicked, 1.0));
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("Zoom100Action", "100%"), LOCTEXT("Zoom100ActionHint", "Show the texture in its original size."), FSlateIcon(), Zoom100Action);
|
|
|
|
FUIAction Zoom200Action(FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuEntryClicked, 2.0));
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("Zoom200Action", "200%"), LOCTEXT("Zoom200ActionHint", "Show the texture at twice its size."), FSlateIcon(), Zoom200Action);
|
|
|
|
FUIAction Zoom400Action(FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuEntryClicked, 4.0));
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("Zoom400Action", "400%"), LOCTEXT("Zoom400ActionHint", "Show the texture at four times its size."), FSlateIcon(), Zoom400Action);
|
|
|
|
ZoomMenuBuilder.AddMenuSeparator();
|
|
|
|
FUIAction ZoomFitAction(
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuFitClicked),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::IsZoomMenuFitChecked)
|
|
);
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("ZoomFitAction", "Scale To Fit"), LOCTEXT("ZoomFitActionHint", "Scales the texture down to fit within the viewport if needed."), FSlateIcon(), ZoomFitAction, NAME_None, EUserInterfaceActionType::RadioButton);
|
|
|
|
FUIAction ZoomFillAction(
|
|
FExecuteAction::CreateSP(this, &FTextureEditorToolkit::HandleZoomMenuFillClicked),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateSP(this, &FTextureEditorToolkit::IsZoomMenuFillChecked)
|
|
);
|
|
ZoomMenuBuilder.AddMenuEntry(LOCTEXT("ZoomFillAction", "Scale To Fill"), LOCTEXT("ZoomFillActionHint", "Scales the texture up and down to fill the viewport."), FSlateIcon(), ZoomFillAction, NAME_None, EUserInterfaceActionType::RadioButton);
|
|
}
|
|
|
|
// zoom slider
|
|
TSharedRef<SWidget> ZoomControl =
|
|
SNew(SBox)
|
|
.WidthOverride(250.f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(LOCTEXT("ZoomLabel", "Zoom"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SBox)
|
|
.WidthOverride(200.f)
|
|
[
|
|
SNew(SSlider)
|
|
.OnValueChanged(this, &FTextureEditorToolkit::HandleZoomSliderChanged)
|
|
.Value(this, &FTextureEditorToolkit::HandleZoomSliderValue)
|
|
]
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
.Padding(4.0f, 0.0f, 0.0f, 0.0f)
|
|
[
|
|
|
|
SNew(SComboButton)
|
|
.ComboButtonStyle(FAppStyle::Get(), "SimpleComboButton")
|
|
.ButtonContent()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &FTextureEditorToolkit::HandleZoomPercentageText)
|
|
]
|
|
.MenuContent()
|
|
[
|
|
ZoomMenuBuilder.MakeWidget()
|
|
]
|
|
]
|
|
];
|
|
|
|
return ZoomControl;
|
|
}
|
|
|
|
TSharedRef<SWidget> FTextureEditorToolkit::MakeView3DControlWidget()
|
|
{
|
|
// currently both volume textures and cubemaps have only 2 view modes, one of which can be described as "3D View"
|
|
// ("Trace Into Volume" for volume textures and "3D View" for cubemaps),
|
|
// therefore view mode for both volume textures and cubemaps can be controlled using the same "3D View" checkbox widget.
|
|
TSharedRef<SWidget> View3DControl = SNew(SBox)
|
|
.WidthOverride(80.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 4.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("TextureEditor", "3D View", "3D View"))
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(4.0f, 0.0f, 2.0f, 0.0f)
|
|
.VAlign(VAlign_Center)
|
|
.AutoWidth()
|
|
[
|
|
SNew(SCheckBox)
|
|
.IsChecked(this, &FTextureEditorToolkit::HandleView3DCheckBoxIsChecked)
|
|
.OnCheckStateChanged(this, &FTextureEditorToolkit::HandleView3DCheckBoxCheckedStateChanged)
|
|
]
|
|
];
|
|
|
|
return View3DControl;
|
|
}
|
|
|
|
void FTextureEditorToolkit::OnEstimateCompressionChanged(ECheckBoxState NewState)
|
|
{
|
|
OodleCompressedPreviewDDCKey.Set<FString>(FString());
|
|
bEstimateCompressionEnabled = NewState == ECheckBoxState::Checked;
|
|
}
|
|
ECheckBoxState FTextureEditorToolkit::EstimateCompressionChecked() const
|
|
{
|
|
return bEstimateCompressionEnabled ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
void FTextureEditorToolkit::PackagingSettingsChanged(TSharedPtr<FString> Selection, ESelectInfo::Type SelectInfo)
|
|
{
|
|
if (Selection.IsValid())
|
|
{
|
|
UProjectPackagingSettings const* ProjectSettings = GetDefault<UProjectPackagingSettings>();
|
|
int32 CompressionLevelFromSettings = (int32)FOodleDataCompression::ECompressionLevel::Optimal3;
|
|
if (*Selection == TEXT("DebugDevelopment"))
|
|
{
|
|
CompressionLevelFromSettings = ProjectSettings->PackageCompressionLevel_DebugDevelopment;
|
|
}
|
|
else if (*Selection == TEXT("TestShipping"))
|
|
{
|
|
CompressionLevelFromSettings = ProjectSettings->PackageCompressionLevel_TestShipping;
|
|
}
|
|
else if (*Selection == TEXT("Distribution"))
|
|
{
|
|
CompressionLevelFromSettings = ProjectSettings->PackageCompressionLevel_Distribution;
|
|
}
|
|
|
|
if (IntFitsIn<int8>(CompressionLevelFromSettings) == false)
|
|
{
|
|
UE_LOG(LogTextureEditor, Warning, TEXT("PackageCompressionLevel_%s in Project Settings is an invalid value = %d, must be [-128, 127]"), **Selection, CompressionLevelFromSettings);
|
|
CompressionLevelFromSettings = (int32)FOodleDataCompression::ECompressionLevel::Optimal3;
|
|
}
|
|
|
|
FOodleDataCompression::ECompressionLevel OldLevel = OodleCompressionLevel;
|
|
FOodleDataCompression::ECompressionLevelFromValue(static_cast<int8>(CompressionLevelFromSettings), OodleCompressionLevel);
|
|
|
|
const TCHAR* LevelName;
|
|
FOodleDataCompression::ECompressionLevelToString(OodleCompressionLevel, &LevelName);
|
|
OodleLevelUsed->SetText(FText::FromString(FString::Printf(TEXT("%s (%d)"), LevelName, CompressionLevelFromSettings)));
|
|
|
|
if (OldLevel != OodleCompressionLevel)
|
|
{
|
|
OodleCompressedPreviewDDCKey.Set<FString>(FString());
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|