You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
[REVIEW] [at]chris.gagnon #rb none #preflight Fix to the issue spotted by this job. 640393971e7a0f9cfccc78f8 #rnx #localization none #tests Just submitting the fix. So no other testing then just checking if it compile was done. #preferred_allowlister chris.gagnon [CL 24516733 by julien stjean in ue5-main branch]
285 lines
8.2 KiB
C++
285 lines
8.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "TextureSourceDataUtils.h"
|
|
|
|
#if WITH_EDITOR
|
|
|
|
#include "ImageCoreUtils.h"
|
|
#include "Engine/Texture.h"
|
|
#include "HAL/UnrealMemory.h"
|
|
|
|
namespace UE::TextureUtilitiesCommon::Experimental
|
|
{
|
|
|
|
namespace Private
|
|
{
|
|
bool ResizeTexture2D(UTexture* Texture, int32 MaxSize, const ITargetPlatform* TargetPlatform)
|
|
{
|
|
// Protect the code from an async build of the texture
|
|
Texture->PreEditChange(nullptr);
|
|
|
|
// We want to reduce the asset size so ignore the imported mip(s)
|
|
const int32 MipIndex = 0;
|
|
FImage SourceMip0;
|
|
if (!Texture->Source.GetMipImage(SourceMip0, MipIndex))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const int32 LayerIndex = 0;
|
|
Texture->DownsizeImageUsingTextureSettings(TargetPlatform, SourceMip0, MaxSize, LayerIndex);
|
|
FImage ResizedImage = MoveTemp(SourceMip0);
|
|
|
|
UE::Serialization::FEditorBulkData::FSharedBufferWithID ResizedImageBufferWithID = MakeSharedBufferFromArray(MoveTemp(ResizedImage.RawData));
|
|
|
|
const int32 NumMips = 1;
|
|
Texture->Source.Init(ResizedImage.SizeX
|
|
, ResizedImage.SizeY
|
|
, ResizedImage.NumSlices
|
|
, NumMips
|
|
, FImageCoreUtils::ConvertToTextureSourceFormat(ResizedImage.Format)
|
|
, MoveTemp(ResizedImageBufferWithID));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ResizeTextureSlicedBy2DLayers(UTexture* Texture, int32 MaxSize, const ITargetPlatform* TargetPlatform)
|
|
{
|
|
// Protect the code from an async build of the texture
|
|
Texture->PreEditChange(nullptr);
|
|
|
|
FImage ResizedImage;
|
|
{
|
|
TArray<FImage> ResizedSlices;
|
|
ResizedSlices.Reserve(Texture->Source.GetNumSlices());
|
|
|
|
ERawImageFormat::Type FormatUsed;
|
|
EGammaSpace GammaSpaceUsed;
|
|
|
|
{
|
|
// We want to reduce the asset size so ignore the imported mip(s)
|
|
TArray<FImage> Slices;
|
|
Slices.Reserve(Texture->Source.GetNumSlices());
|
|
|
|
{
|
|
// We could probably avoid a copy here but for the simplicity of the code keep it for now.
|
|
FImage SourceMip0;
|
|
if (!Texture->Source.GetMipImage(SourceMip0, 0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FormatUsed = SourceMip0.Format;
|
|
GammaSpaceUsed = SourceMip0.GammaSpace;
|
|
|
|
for (int32 Index = 0; Index < SourceMip0.NumSlices; ++Index)
|
|
{
|
|
FImage& Slice = Slices.AddDefaulted_GetRef();
|
|
FImageView SliceView = SourceMip0.GetSlice(Index);
|
|
|
|
FImageCore::CopyImage(SliceView, Slice);
|
|
}
|
|
}
|
|
|
|
for (FImage& Slice : Slices)
|
|
{
|
|
FImage& ResizedSlice = ResizedSlices.AddDefaulted_GetRef();
|
|
|
|
const int32 LayerIndex = 0;
|
|
Texture->DownsizeImageUsingTextureSettings(TargetPlatform, Slice, MaxSize, LayerIndex);
|
|
ResizedSlice = MoveTemp(Slice);
|
|
}
|
|
}
|
|
|
|
// Move the resized slices into the resized image
|
|
ResizedImage.Init(ResizedSlices[0].SizeX,ResizedSlices[0].SizeY, ResizedSlices.Num(), FormatUsed, GammaSpaceUsed);
|
|
|
|
for (int32 Index = 0; Index < ResizedImage.NumSlices; ++Index)
|
|
{
|
|
FImageCore::CopyImage(ResizedSlices[Index], ResizedImage.GetSlice(Index));
|
|
}
|
|
}
|
|
|
|
|
|
UE::Serialization::FEditorBulkData::FSharedBufferWithID ResizedImageBufferWithID = MakeSharedBufferFromArray(MoveTemp(ResizedImage.RawData));
|
|
|
|
const int32 NumMips = 1;
|
|
Texture->Source.Init(ResizedImage.SizeX
|
|
, ResizedImage.SizeY
|
|
, ResizedImage.NumSlices
|
|
, NumMips
|
|
, FImageCoreUtils::ConvertToTextureSourceFormat(ResizedImage.Format)
|
|
, MoveTemp(ResizedImageBufferWithID));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ResizeTexture2DBlocked(UTexture* Texture, int32 MaxSize, const ITargetPlatform* TargetPlatform)
|
|
{
|
|
// Protect the code from an async build of the texture
|
|
Texture->PreEditChange(nullptr);
|
|
|
|
FIntPoint LogicalSourceSize = Texture->Source.GetLogicalSize();
|
|
double RatioX = double(MaxSize) / LogicalSourceSize.X;
|
|
double RatioY = double(MaxSize) / LogicalSourceSize.Y;
|
|
|
|
TArray<FTextureSourceBlock > ResizedSourceBlocks;
|
|
ResizedSourceBlocks.Reserve(Texture->Source.GetNumBlocks());
|
|
|
|
TArray<FImage> ResizedBlocks;
|
|
ResizedBlocks.Reserve(Texture->Source.GetNumBlocks());
|
|
|
|
for (int32 BlockIndex = 0; BlockIndex < Texture->Source.GetNumBlocks(); ++BlockIndex)
|
|
{
|
|
// We want to reduce the asset size so ignore the imported mip(s)
|
|
FImage SourceMip0;
|
|
const int32 MipIndex = 0;
|
|
const int32 LayerIndex = 0;
|
|
if (!Texture->Source.GetMipImage(SourceMip0, BlockIndex, LayerIndex, MipIndex))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FTextureSourceBlock& ResizedSourceBlock = ResizedSourceBlocks.AddDefaulted_GetRef();
|
|
Texture->Source.GetBlock(BlockIndex, ResizedSourceBlock);
|
|
|
|
FImage& ResizedBlock = ResizedBlocks.AddDefaulted_GetRef();
|
|
|
|
int32 BlockMaxSize = FMath::RoundToInt32(FMath::Min(ResizedSourceBlock.SizeX * RatioX, ResizedSourceBlock.SizeY * RatioY));
|
|
|
|
Texture->DownsizeImageUsingTextureSettings(TargetPlatform, SourceMip0, MaxSize, LayerIndex);
|
|
ResizedBlock = MoveTemp(SourceMip0);
|
|
|
|
ResizedSourceBlock.SizeX = ResizedBlock.SizeX;
|
|
ResizedSourceBlock.SizeY = ResizedBlock.SizeY;
|
|
ResizedSourceBlock.NumSlices = 1;
|
|
}
|
|
|
|
int64 SizeNeededInBytes = 0;
|
|
for (const FImage& Block : ResizedBlocks)
|
|
{
|
|
SizeNeededInBytes += Block.RawData.Num();
|
|
}
|
|
FUniqueBuffer WriteImageBuffer = FUniqueBuffer::Alloc(SizeNeededInBytes);
|
|
|
|
uint8* CurrentAddress = static_cast<uint8*>(WriteImageBuffer.GetData());
|
|
for (FImage& Block : ResizedBlocks)
|
|
{
|
|
FMemory::Memcpy(CurrentAddress, static_cast<uint8*>(Block.RawData.GetData()), Block.RawData.Num());
|
|
CurrentAddress += Block.RawData.Num();
|
|
}
|
|
|
|
UE::Serialization::FEditorBulkData::FSharedBufferWithID ResizedImageBufferWithID = WriteImageBuffer.MoveToShared();
|
|
|
|
const ETextureSourceFormat SourceFormat = Texture->Source.GetFormat();
|
|
int32 NumLayers = 1;
|
|
Texture->Source.InitBlocked(
|
|
&SourceFormat,
|
|
ResizedSourceBlocks.GetData(),
|
|
NumLayers,
|
|
ResizedSourceBlocks.Num(),
|
|
MoveTemp(ResizedImageBufferWithID)
|
|
);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
bool DownsizeTextureSourceData(UTexture* Texture, int32 TargetSizeInGame, const ITargetPlatform* TargetPlatform)
|
|
{
|
|
// Check if we don't know how to resize that texture
|
|
if (Texture->Source.GetNumLayers() != 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!(Texture->Source.GetTextureClass() == ETextureClass::Cube || Texture->Source.GetTextureClass() == ETextureClass::TwoD))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Texture->Source.GetTextureClass() == ETextureClass::TwoD && Texture->Source.GetNumSlices() != 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Texture->Source.GetTextureClass() == ETextureClass::Cube)
|
|
{
|
|
if (Texture->Source.IsLongLatCubemap())
|
|
{
|
|
if (Texture->Source.GetNumSlices() != 1)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (Texture->Source.GetNumSlices() != 6)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int32 TargetSourceSize = TargetSizeInGame;
|
|
if (Texture->Source.IsLongLatCubemap())
|
|
{
|
|
// The function return the max size of the generated cube from the source long lat
|
|
// this should be kept in sync with the implementation details of ComputeLongLatCubemapExtents() or refactored
|
|
TargetSourceSize = (1U << FMath::FloorLog2(TargetSizeInGame)) * 2;
|
|
}
|
|
|
|
FIntPoint SourceSize = Texture->Source.GetLogicalSize();
|
|
if (SourceSize.X <= TargetSourceSize && SourceSize.Y <= TargetSourceSize)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Texture->Source.GetTextureClass() == ETextureClass::TwoD)
|
|
{
|
|
if (Texture->Source.GetNumBlocks() == 1)
|
|
{
|
|
return Private::ResizeTexture2D(Texture, TargetSourceSize, TargetPlatform);
|
|
}
|
|
else
|
|
{
|
|
// UDIM(s)
|
|
return Private::ResizeTexture2DBlocked(Texture, TargetSourceSize, TargetPlatform);
|
|
}
|
|
}
|
|
else if (Texture->Source.GetTextureClass() == ETextureClass::Cube)
|
|
{
|
|
if (Texture->Source.IsLongLatCubemap())
|
|
{
|
|
return Private::ResizeTexture2D(Texture, TargetSourceSize, TargetPlatform);
|
|
}
|
|
else
|
|
{
|
|
return Private::ResizeTextureSlicedBy2DLayers(Texture, TargetSourceSize, TargetPlatform);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DownsizeTexureSourceDataNearRenderingSize(UTexture* Texture, const ITargetPlatform* TargetPlatform)
|
|
{
|
|
int32 SizeX;
|
|
int32 SizeY;
|
|
Texture->GetBuiltTextureSize(TargetPlatform, SizeX, SizeY);
|
|
|
|
int32 TargetSize = FMath::Max(SizeX, SizeY);
|
|
if (DownsizeTextureSourceData(Texture, FMath::Max(SizeX, SizeY), TargetPlatform))
|
|
{
|
|
int32 BiggestSize = FMath::Max(SizeX, SizeY);
|
|
const int32 Bias = FMath::CeilLogTwo(BiggestSize) - FMath::CeilLogTwo(TargetSize);
|
|
Texture->LODBias = FMath::Max(Bias , 0);
|
|
Texture->PostEditChange();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} // End namespace UE::TextureUtilitiesCommon::Experimental
|
|
|
|
#endif //WITH_EDITOR
|