2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "ThumbnailRendering/ThumbnailManager.h"
# include "HAL/FileManager.h"
# include "Misc/FileHelper.h"
# include "Misc/Paths.h"
# include "UObject/ConstructorHelpers.h"
# include "Materials/Material.h"
# include "ISourceControlOperation.h"
# include "SourceControlOperations.h"
# include "ISourceControlProvider.h"
2014-03-14 14:13:41 -04:00
# include "ISourceControlModule.h"
2014-11-12 04:43:54 -05:00
# include "Engine/StaticMesh.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "UnrealClient.h"
2014-11-12 04:43:54 -05:00
# include "Engine/TextureCube.h"
2019-09-14 09:45:25 -04:00
# include "Engine/Texture2DArray.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "ImageUtils.h"
2021-01-26 17:20:04 -04:00
# include "AssetThumbnail.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogThumbnailManager , Log , All ) ;
//////////////////////////////////////////////////////////////////////////
UThumbnailManager * UThumbnailManager : : ThumbnailManagerSingleton = nullptr ;
2014-10-14 10:29:11 -04:00
UThumbnailManager : : UThumbnailManager ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
if ( ! IsRunningCommandlet ( ) )
{
// Structure to hold one-time initialization
struct FConstructorStatics
{
ConstructorHelpers : : FObjectFinder < UStaticMesh > EditorCubeMesh ;
ConstructorHelpers : : FObjectFinder < UStaticMesh > EditorSphereMesh ;
ConstructorHelpers : : FObjectFinder < UStaticMesh > EditorCylinderMesh ;
ConstructorHelpers : : FObjectFinder < UStaticMesh > EditorPlaneMesh ;
ConstructorHelpers : : FObjectFinder < UStaticMesh > EditorSkySphereMesh ;
ConstructorHelpers : : FObjectFinder < UMaterial > FloorPlaneMaterial ;
ConstructorHelpers : : FObjectFinder < UTextureCube > DaylightAmbientCubemap ;
2019-09-14 09:45:25 -04:00
2014-03-14 14:13:41 -04:00
FConstructorStatics ( )
: EditorCubeMesh ( TEXT ( " /Engine/EditorMeshes/EditorCube " ) )
, EditorSphereMesh ( TEXT ( " /Engine/EditorMeshes/EditorSphere " ) )
, EditorCylinderMesh ( TEXT ( " /Engine/EditorMeshes/EditorCylinder " ) )
, EditorPlaneMesh ( TEXT ( " /Engine/EditorMeshes/EditorPlane " ) )
, EditorSkySphereMesh ( TEXT ( " /Engine/EditorMeshes/EditorSkySphere " ) )
, FloorPlaneMaterial ( TEXT ( " /Engine/EditorMaterials/Thumbnails/FloorPlaneMaterial " ) )
, DaylightAmbientCubemap ( TEXT ( " /Engine/MapTemplates/Sky/DaylightAmbientCubemap " ) )
{
}
} ;
static FConstructorStatics ConstructorStatics ;
EditorCube = ConstructorStatics . EditorCubeMesh . Object ;
EditorSphere = ConstructorStatics . EditorSphereMesh . Object ;
EditorCylinder = ConstructorStatics . EditorCylinderMesh . Object ;
EditorPlane = ConstructorStatics . EditorPlaneMesh . Object ;
EditorSkySphere = ConstructorStatics . EditorSkySphereMesh . Object ;
FloorPlaneMaterial = ConstructorStatics . FloorPlaneMaterial . Object ;
AmbientCubemap = ConstructorStatics . DaylightAmbientCubemap . Object ;
2015-06-22 13:58:40 -04:00
SetupCheckerboardTexture ( ) ;
}
2014-03-14 14:13:41 -04:00
}
void UThumbnailManager : : Initialize ( void )
{
if ( bIsInitialized = = false )
{
InitializeRenderTypeArray ( RenderableThumbnailTypes ) ;
2021-01-26 17:20:04 -04:00
SharedThumbnailPool = MakeShared < FAssetThumbnailPool > ( 100 ) ;
2014-03-14 14:13:41 -04:00
bIsInitialized = true ;
}
}
void UThumbnailManager : : InitializeRenderTypeArray ( TArray < FThumbnailRenderingInfo > & ThumbnailRendererTypes )
{
// Loop through setting up each thumbnail entry
for ( int32 Index = 0 ; Index < ThumbnailRendererTypes . Num ( ) ; Index + + )
{
FThumbnailRenderingInfo & RenderInfo = ThumbnailRendererTypes [ Index ] ;
// Load the class that this is for
if ( RenderInfo . ClassNeedingThumbnailName . Len ( ) > 0 )
{
// Try to load the specified class
RenderInfo . ClassNeedingThumbnail = LoadObject < UClass > ( nullptr , * RenderInfo . ClassNeedingThumbnailName , nullptr , LOAD_None , nullptr ) ;
}
if ( RenderInfo . RendererClassName . Len ( ) > 0 )
{
// Try to create the renderer object by loading its class and
// constructing one
UClass * RenderClass = LoadObject < UClass > ( nullptr , * RenderInfo . RendererClassName , nullptr , LOAD_None , nullptr ) ;
if ( RenderClass ! = nullptr )
{
2015-02-03 05:40:57 -05:00
RenderInfo . Renderer = NewObject < UThumbnailRenderer > ( GetTransientPackage ( ) , RenderClass ) ;
2014-03-14 14:13:41 -04:00
}
}
// Add this to the map if it created the renderer component
if ( RenderInfo . Renderer ! = nullptr )
{
RenderInfoMap . Add ( RenderInfo . ClassNeedingThumbnail , & RenderInfo ) ;
}
}
}
FThumbnailRenderingInfo * UThumbnailManager : : GetRenderingInfo ( UObject * Object )
{
// If something may have been GCed, empty the map so we don't crash
if ( bMapNeedsUpdate = = true )
{
RenderInfoMap . Empty ( ) ;
bMapNeedsUpdate = false ;
}
check ( Object ) ;
TArray < FThumbnailRenderingInfo > & ThumbnailTypes = RenderableThumbnailTypes ;
// Get the class to check against.
2021-01-13 09:12:49 -04:00
UClass * ClassToCheck = Object - > GetClass ( ) ;
2014-03-14 14:13:41 -04:00
// Search for the cached entry and do the slower if not found
FThumbnailRenderingInfo * RenderInfo = RenderInfoMap . FindRef ( ClassToCheck ) ;
if ( RenderInfo = = nullptr )
{
// Loop through searching for the right thumbnail entry
for ( int32 Index = ThumbnailTypes . Num ( ) - 1 ; ( Index > = 0 ) & & ( RenderInfo = = nullptr ) ; Index - - )
{
RenderInfo = & ThumbnailTypes [ Index ] ;
// See if this thumbnail renderer will work for the specified class or
// if there is some data reason not to render the thumbnail
if ( ( ClassToCheck - > IsChildOf ( RenderInfo - > ClassNeedingThumbnail ) = = false ) | | ( RenderInfo - > Renderer = = nullptr ) )
{
RenderInfo = nullptr ;
}
}
// Make sure to add it to the cache if it is missing
RenderInfoMap . Add ( ClassToCheck , ( RenderInfo ! = nullptr ) ? RenderInfo : & NotSupported ) ;
}
2018-02-22 11:25:06 -05:00
if ( RenderInfo & & RenderInfo - > Renderer & & ! RenderInfo - > Renderer - > CanVisualizeAsset ( Object ) )
2014-03-14 14:13:41 -04:00
{
2018-02-22 11:25:06 -05:00
// This is an asset with a thumbnail renderer, but it can't visualized (i.e it is something like a blueprint that doesn't contain any visible primitive components)
RenderInfo = nullptr ;
2014-03-14 14:13:41 -04:00
}
// Check to see if this object is the "not supported" type or not
if ( RenderInfo = = & NotSupported )
{
RenderInfo = nullptr ;
}
return RenderInfo ;
}
void UThumbnailManager : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
// Just mark us as dirty so that the cache is rebuilt
bMapNeedsUpdate = true ;
}
void UThumbnailManager : : RegisterCustomRenderer ( UClass * Class , TSubclassOf < UThumbnailRenderer > RendererClass )
{
check ( Class ! = nullptr ) ;
check ( * RendererClass ! = nullptr ) ;
const FString NewClassPathName = Class - > GetPathName ( ) ;
// Verify that this class isn't already registered
for ( int32 Index = 0 ; Index < RenderableThumbnailTypes . Num ( ) ; + + Index )
{
if ( ensure ( RenderableThumbnailTypes [ Index ] . ClassNeedingThumbnailName ! = NewClassPathName ) )
{
}
else
{
return ;
}
}
// Register the new class
FThumbnailRenderingInfo & Info = * ( new ( RenderableThumbnailTypes ) FThumbnailRenderingInfo ( ) ) ;
Info . ClassNeedingThumbnailName = NewClassPathName ;
Info . ClassNeedingThumbnail = Class ;
2020-09-01 14:07:48 -04:00
if ( FApp : : CanEverRender ( ) )
{
Info . Renderer = NewObject < UThumbnailRenderer > ( GetTransientPackage ( ) , RendererClass ) ;
}
else
{
Info . Renderer = nullptr ;
}
2014-03-14 14:13:41 -04:00
Info . RendererClassName = RendererClass - > GetPathName ( ) ;
bMapNeedsUpdate = true ;
}
void UThumbnailManager : : UnregisterCustomRenderer ( UClass * Class )
{
check ( Class ! = nullptr ) ;
const FString OldClassPathName = Class - > GetPathName ( ) ;
for ( int32 Index = 0 ; Index < RenderableThumbnailTypes . Num ( ) ; )
{
if ( RenderableThumbnailTypes [ Index ] . ClassNeedingThumbnailName = = OldClassPathName )
{
RenderableThumbnailTypes . RemoveAtSwap ( Index ) ;
}
else
{
+ + Index ;
}
}
bMapNeedsUpdate = true ;
}
UThumbnailManager & UThumbnailManager : : Get ( )
{
// Create it if we need to
if ( ThumbnailManagerSingleton = = nullptr )
{
FString ClassName = GetDefault < UThumbnailManager > ( ) - > ThumbnailManagerClassName ;
if ( ! ClassName . IsEmpty ( ) )
{
// Try to load the specified class
UClass * Class = LoadObject < UClass > ( nullptr , * ClassName , nullptr , LOAD_None , nullptr ) ;
if ( Class ! = nullptr )
{
// Create an instance of this class
2015-02-03 05:40:57 -05:00
ThumbnailManagerSingleton = NewObject < UThumbnailManager > ( GetTransientPackage ( ) , Class ) ;
2014-03-14 14:13:41 -04:00
}
}
// If the class couldn't be loaded or is the wrong type, fallback to the default
if ( ThumbnailManagerSingleton = = nullptr )
{
2015-02-03 05:40:57 -05:00
ThumbnailManagerSingleton = NewObject < UThumbnailManager > ( ) ;
2014-03-14 14:13:41 -04:00
}
// Keep the singleton alive
ThumbnailManagerSingleton - > AddToRoot ( ) ;
// Tell it to load all of its classes
ThumbnailManagerSingleton - > Initialize ( ) ;
}
return * ThumbnailManagerSingleton ;
}
void UThumbnailManager : : SetupCheckerboardTexture ( )
{
if ( CheckerboardTexture )
{
return ;
}
2015-05-21 18:01:52 -04:00
CheckerboardTexture = FImageUtils : : CreateCheckerboardTexture ( FColor ( 128 , 128 , 128 ) , FColor ( 64 , 64 , 64 ) , 32 ) ;
2014-03-14 14:13:41 -04:00
}
bool UThumbnailManager : : CaptureProjectThumbnail ( FViewport * Viewport , const FString & OutputFilename , bool bUseSCCIfPossible )
{
const uint32 AutoScreenshotSize = 192 ;
//capture the thumbnail
uint32 SrcWidth = Viewport - > GetSizeXY ( ) . X ;
uint32 SrcHeight = Viewport - > GetSizeXY ( ) . Y ;
// Read the contents of the viewport into an array.
TArray < FColor > OrigBitmap ;
if ( Viewport - > ReadPixels ( OrigBitmap ) )
{
check ( OrigBitmap . Num ( ) = = SrcWidth * SrcHeight ) ;
//pin to smallest value
int32 CropSize = FMath : : Min < uint32 > ( SrcWidth , SrcHeight ) ;
//pin to max size
int32 ScaledSize = FMath : : Min < uint32 > ( AutoScreenshotSize , CropSize ) ;
//calculations for cropping
TArray < FColor > CroppedBitmap ;
CroppedBitmap . AddUninitialized ( CropSize * CropSize ) ;
//Crop the image
int32 CroppedSrcTop = ( SrcHeight - CropSize ) / 2 ;
int32 CroppedSrcLeft = ( SrcWidth - CropSize ) / 2 ;
for ( int32 Row = 0 ; Row < CropSize ; + + Row )
{
//Row*Side of a row*byte per color
int32 SrcPixelIndex = ( CroppedSrcTop + Row ) * SrcWidth + CroppedSrcLeft ;
const void * SrcPtr = & ( OrigBitmap [ SrcPixelIndex ] ) ;
void * DstPtr = & ( CroppedBitmap [ Row * CropSize ] ) ;
FMemory : : Memcpy ( DstPtr , SrcPtr , CropSize * 4 ) ;
}
//Scale image down if needed
TArray < FColor > ScaledBitmap ;
if ( ScaledSize < CropSize )
{
FImageUtils : : ImageResize ( CropSize , CropSize , CroppedBitmap , ScaledSize , ScaledSize , ScaledBitmap , true ) ;
}
else
{
//just copy the data over. sizes are the same
ScaledBitmap = CroppedBitmap ;
}
// Compress the scaled image
TArray < uint8 > ScaledPng ;
2022-03-03 12:33:29 -05:00
FImageUtils : : ThumbnailCompressImageArray ( ScaledSize , ScaledSize , ScaledBitmap , ScaledPng ) ;
2014-03-14 14:13:41 -04:00
// Save to file
const FString ScreenShotPath = FPaths : : GetPath ( OutputFilename ) ;
if ( IFileManager : : Get ( ) . MakeDirectory ( * ScreenShotPath , true ) )
{
// If source control is available, try to check out the file if necessary.
// If not, silently continue. This is just a courtesy.
bool bMarkFileForAdd = false ;
FString AbsoluteFilename = FPaths : : ConvertRelativePathToFull ( OutputFilename ) ;
TArray < FString > FilesToBeCheckedOut ;
FilesToBeCheckedOut . Add ( AbsoluteFilename ) ;
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
if ( bUseSCCIfPossible & & ISourceControlModule : : Get ( ) . IsEnabled ( ) & & SourceControlProvider . IsAvailable ( ) )
{
FSourceControlStatePtr SourceControlState = SourceControlProvider . GetState ( AbsoluteFilename , EStateCacheUsage : : ForceUpdate ) ;
if ( SourceControlState . IsValid ( ) )
{
if ( SourceControlState - > CanCheckout ( ) )
{
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FCheckOut > ( ) , FilesToBeCheckedOut ) ;
}
else if ( ! SourceControlState - > IsSourceControlled ( ) )
{
bMarkFileForAdd = true ;
}
}
}
if ( FFileHelper : : SaveArrayToFile ( ScaledPng , * OutputFilename ) )
{
if ( bMarkFileForAdd )
{
SourceControlProvider . Execute ( ISourceControlOperation : : Create < FMarkForAdd > ( ) , FilesToBeCheckedOut ) ;
}
return true ;
}
}
}
return false ;
}