ExtAssetThumbnail.cpp 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796
  1. // Copyright 2017-2021 marynate. All Rights Reserved.
  2. #include "ExtAssetThumbnail.h"
  3. #include "ExtContentBrowser.h"
  4. #include "ExtPackageUtils.h"
  5. #include "ExtContentBrowserSingleton.h"
  6. #include "ExtContentBrowserSettings.h"
  7. #include "ExtContentBrowserStyle.h"
  8. #include "Engine/Blueprint.h"
  9. #include "GameFramework/Actor.h"
  10. #include "Layout/Margin.h"
  11. #include "Widgets/DeclarativeSyntaxSupport.h"
  12. #include "Widgets/SOverlay.h"
  13. #include "Engine/GameViewportClient.h"
  14. #include "Interfaces/Interface_AsyncCompilation.h"
  15. #include "Modules/ModuleManager.h"
  16. #include "Animation/CurveHandle.h"
  17. #include "Animation/CurveSequence.h"
  18. #include "Textures/SlateTextureData.h"
  19. #include "Fonts/SlateFontInfo.h"
  20. #include "Application/ThrottleManager.h"
  21. #include "Widgets/SCompoundWidget.h"
  22. #include "Widgets/Layout/SBorder.h"
  23. #include "Widgets/Images/SImage.h"
  24. #include "Widgets/Text/STextBlock.h"
  25. #include "Widgets/SViewport.h"
  26. #include "EditorStyleSet.h"
  27. #include "RenderingThread.h"
  28. #include "Settings/ContentBrowserSettings.h"
  29. #include "RenderUtils.h"
  30. #include "Editor/UnrealEdEngine.h"
  31. #include "ThumbnailRendering/ThumbnailManager.h"
  32. #include "Editor.h"
  33. #include "UnrealEdGlobals.h"
  34. #include "Slate/SlateTextures.h"
  35. #include "ObjectTools.h"
  36. #include "ShaderCompiler.h"
  37. #include "AssetCompilingManager.h"
  38. #include "IAssetTools.h"
  39. #include "AssetTypeActions_Base.h"
  40. #include "AssetToolsModule.h"
  41. #include "Styling/SlateIconFinder.h"
  42. #include "ClassIconFinder.h"
  43. #include "IVREditorModule.h"
  44. #include "Framework/Application/SlateApplication.h"
  45. //-------------------------------------------------------------------------------------
  46. // SExtAssetThumbnail - Thumbnail widget for display thumbnail of .uasset file
  47. //
  48. class SExtAssetThumbnail : public SCompoundWidget
  49. {
  50. public:
  51. SLATE_BEGIN_ARGS( SExtAssetThumbnail )
  52. : _Style("AssetThumbnail")
  53. , _ThumbnailPool(NULL)
  54. , _AllowFadeIn(false)
  55. , _ForceGenericThumbnail(false)
  56. , _AllowHintText(true)
  57. , _AllowAssetSpecificThumbnailOverlay(false)
  58. , _Label(EThumbnailLabel::ClassName)
  59. , _HighlightedText(FText::GetEmpty())
  60. , _HintColorAndOpacity(FLinearColor(0.0f, 0.0f, 0.0f, 0.0f))
  61. , _ClassThumbnailBrushOverride(NAME_None)
  62. , _AssetTypeColorOverride()
  63. , _Padding(0)
  64. , _GenericThumbnailSize(64)
  65. {}
  66. SLATE_ARGUMENT(FName, Style)
  67. SLATE_ARGUMENT(TSharedPtr<FExtAssetThumbnail>, AssetThumbnail)
  68. SLATE_ARGUMENT(TSharedPtr<FExtAssetThumbnailPool>, ThumbnailPool)
  69. SLATE_ARGUMENT(bool, AllowFadeIn)
  70. SLATE_ARGUMENT(bool, ForceGenericThumbnail)
  71. SLATE_ARGUMENT(bool, AllowHintText)
  72. SLATE_ARGUMENT(bool, AllowAssetSpecificThumbnailOverlay)
  73. //SLATE_ARGUMENT(bool, AllowRealTimeOnHovered)
  74. SLATE_ARGUMENT(EThumbnailLabel::Type, Label)
  75. SLATE_ATTRIBUTE(FText, HighlightedText)
  76. SLATE_ATTRIBUTE(FLinearColor, HintColorAndOpacity)
  77. SLATE_ARGUMENT(FName, ClassThumbnailBrushOverride)
  78. SLATE_ARGUMENT(TOptional<FLinearColor>, AssetTypeColorOverride)
  79. SLATE_ARGUMENT(FMargin, Padding)
  80. SLATE_ATTRIBUTE(int32, GenericThumbnailSize)
  81. SLATE_END_ARGS()
  82. /** Constructs this widget with InArgs */
  83. void Construct( const FArguments& InArgs )
  84. {
  85. Style = InArgs._Style;
  86. HighlightedText = InArgs._HighlightedText;
  87. Label = InArgs._Label;
  88. HintColorAndOpacity = InArgs._HintColorAndOpacity;
  89. bAllowHintText = InArgs._AllowHintText;
  90. ThumbnailBrush = nullptr;
  91. ClassIconBrush = nullptr;
  92. AssetThumbnail = InArgs._AssetThumbnail;
  93. bHasRenderedThumbnail = false;
  94. WidthLastFrame = 0;
  95. GenericThumbnailBorderPadding = 2.f;
  96. GenericThumbnailSize = InArgs._GenericThumbnailSize;
  97. AssetThumbnail->OnAssetDataChanged().AddSP(this, &SExtAssetThumbnail::OnAssetDataChanged);
  98. const FExtAssetData& AssetData = AssetThumbnail->GetAssetData();
  99. const bool bInvalidUAsset = !AssetData.IsValid() && AssetData.IsUAsset();
  100. UClass* Class = bInvalidUAsset ? nullptr : FindObjectSafe<UClass>(nullptr, *AssetData.AssetClass.ToString());
  101. static FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
  102. TSharedPtr<IAssetTypeActions> AssetTypeActions;
  103. if ( Class != NULL )
  104. {
  105. AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Class).Pin();
  106. }
  107. AssetColor = bInvalidUAsset ? FLinearColor::Red : FLinearColor::White;
  108. if( InArgs._AssetTypeColorOverride.IsSet() )
  109. {
  110. AssetColor = InArgs._AssetTypeColorOverride.GetValue();
  111. }
  112. else if ( AssetTypeActions.IsValid() )
  113. {
  114. AssetColor = AssetTypeActions->GetTypeColor();
  115. }
  116. TSharedRef<SOverlay> OverlayWidget = SNew(SOverlay);
  117. UpdateThumbnailClass();
  118. ClassThumbnailBrushOverride = InArgs._ClassThumbnailBrushOverride;
  119. AssetBackgroundBrushName = *(Style.ToString() + TEXT(".AssetBackground"));
  120. ClassBackgroundBrushName = *(Style.ToString() + TEXT(".ClassBackground"));
  121. // The generic representation of the thumbnail, for use before the rendered version, if it exists
  122. OverlayWidget->AddSlot()
  123. .Padding(InArgs._Padding)
  124. [
  125. SAssignNew(AssetBackgroundWidget, SBorder)
  126. .BorderImage(GetAssetBackgroundBrush())
  127. .Padding(GenericThumbnailBorderPadding)
  128. .VAlign(VAlign_Center)
  129. .HAlign(HAlign_Center)
  130. .Visibility(this, &SExtAssetThumbnail::GetGenericThumbnailVisibility)
  131. [
  132. SNew(SOverlay)
  133. +SOverlay::Slot()
  134. [
  135. SAssignNew(GenericLabelTextBlock, STextBlock)
  136. .Text(GetLabelText())
  137. .Font(GetTextFont())
  138. .Justification(ETextJustify::Center)
  139. .ColorAndOpacity(FAppStyle::GetColor(Style, ".ColorAndOpacity"))
  140. .HighlightText(HighlightedText)
  141. ]
  142. +SOverlay::Slot()
  143. [
  144. SAssignNew(GenericThumbnailImage, SImage)
  145. .DesiredSizeOverride(this, &SExtAssetThumbnail::GetGenericThumbnailDesiredSize)
  146. .Image(this, &SExtAssetThumbnail::GetClassThumbnailBrush)
  147. ]
  148. ]
  149. ];
  150. if ( InArgs._ThumbnailPool.IsValid() && !InArgs._ForceGenericThumbnail )
  151. {
  152. ViewportFadeAnimation = FCurveSequence();
  153. ViewportFadeCurve = ViewportFadeAnimation.AddCurve(0.f, 0.25f, ECurveEaseFunction::QuadOut);
  154. TSharedPtr<SViewport> Viewport =
  155. SNew( SViewport )
  156. .EnableGammaCorrection(false)
  157. // In VR editor every widget is in the world and gamma corrected by the scene renderer. Thumbnails will have already been gamma
  158. // corrected and so they need to be reversed
  159. .ReverseGammaCorrection(IVREditorModule::Get().IsVREditorModeActive())
  160. .EnableBlending(true);
  161. Viewport->SetViewportInterface( AssetThumbnail.ToSharedRef() );
  162. AssetThumbnail->GetViewportRenderTargetTexture(); // Access the render texture to push it on the stack if it isn't already rendered
  163. InArgs._ThumbnailPool->OnThumbnailRendered().AddSP(this, &SExtAssetThumbnail::OnThumbnailRendered);
  164. InArgs._ThumbnailPool->OnThumbnailRenderFailed().AddSP(this, &SExtAssetThumbnail::OnThumbnailRenderFailed);
  165. if ( ShouldRender() && (!InArgs._AllowFadeIn || InArgs._ThumbnailPool->IsRendered(AssetThumbnail)) )
  166. {
  167. bHasRenderedThumbnail = true;
  168. ViewportFadeAnimation.JumpToEnd();
  169. }
  170. // The viewport for the rendered thumbnail, if it exists
  171. OverlayWidget->AddSlot()
  172. [
  173. SAssignNew(RenderedThumbnailWidget, SBorder)
  174. .Padding(InArgs._Padding)
  175. .BorderImage(FStyleDefaults::GetNoBrush())
  176. .ColorAndOpacity(this, &SExtAssetThumbnail::GetViewportColorAndOpacity)
  177. .HAlign(HAlign_Center)
  178. .VAlign(VAlign_Center)
  179. [
  180. Viewport.ToSharedRef()
  181. ]
  182. ];
  183. }
  184. if( ThumbnailClass.Get() && bIsClassType)
  185. {
  186. OverlayWidget->AddSlot()
  187. .VAlign(VAlign_Bottom)
  188. .HAlign(HAlign_Right)
  189. .Padding(TAttribute<FMargin>(this, &SExtAssetThumbnail::GetClassIconPadding))
  190. [
  191. SAssignNew(ClassIconWidget, SBorder)
  192. .BorderImage(FAppStyle::GetNoBrush())
  193. [
  194. SNew(SImage)
  195. .Image(this, &SExtAssetThumbnail::GetClassIconBrush)
  196. ]
  197. ];
  198. }
  199. if( bAllowHintText )
  200. {
  201. OverlayWidget->AddSlot()
  202. .HAlign(HAlign_Center)
  203. .VAlign(VAlign_Top)
  204. .Padding(FMargin(2, 2, 2, 2))
  205. [
  206. SNew(SBorder)
  207. .BorderImage(FAppStyle::GetBrush(Style, ".HintBackground"))
  208. .BorderBackgroundColor(this, &SExtAssetThumbnail::GetHintBackgroundColor) //Adjust the opacity of the border itself
  209. .ColorAndOpacity(HintColorAndOpacity) //adjusts the opacity of the contents of the border
  210. .Visibility(this, &SExtAssetThumbnail::GetHintTextVisibility)
  211. .Padding(0)
  212. [
  213. SAssignNew(HintTextBlock, STextBlock)
  214. .Text(GetLabelText())
  215. .Font(GetHintTextFont())
  216. .ColorAndOpacity(FAppStyle::GetColor(Style, ".HintColorAndOpacity"))
  217. .HighlightText(HighlightedText)
  218. ]
  219. ];
  220. }
  221. // The asset color strip
  222. OverlayWidget->AddSlot()
  223. .HAlign(HAlign_Fill)
  224. .VAlign(VAlign_Bottom)
  225. [
  226. SAssignNew(AssetColorStripWidget, SBorder)
  227. .BorderImage(FAppStyle::GetBrush("WhiteBrush"))
  228. .BorderBackgroundColor(AssetColor)
  229. .Padding(this, &SExtAssetThumbnail::GetAssetColorStripPadding)
  230. ];
  231. #if ECB_LEGACY
  232. if( InArgs._AllowAssetSpecificThumbnailOverlay && AssetTypeActions.IsValid() )
  233. {
  234. // Does the asset provide an additional thumbnail overlay?
  235. TSharedPtr<SWidget> AssetSpecificThumbnailOverlay = AssetTypeActions->GetThumbnailOverlay(AssetData.AssetData);
  236. if( AssetSpecificThumbnailOverlay.IsValid() )
  237. {
  238. OverlayWidget->AddSlot()
  239. [
  240. AssetSpecificThumbnailOverlay.ToSharedRef()
  241. ];
  242. }
  243. }
  244. #endif
  245. if (InArgs._AllowAssetSpecificThumbnailOverlay)
  246. {
  247. // Does the asset provide an additional thumbnail overlay?
  248. TSharedPtr<SWidget> AssetSpecificThumbnailOverlay = AssetThumbnail->GetSpecificThumbnailOverlay();
  249. if (AssetSpecificThumbnailOverlay.IsValid())
  250. {
  251. OverlayWidget->AddSlot()
  252. [
  253. AssetSpecificThumbnailOverlay.ToSharedRef()
  254. ];
  255. }
  256. }
  257. ChildSlot
  258. [
  259. OverlayWidget
  260. ];
  261. UpdateThumbnailVisibilities();
  262. }
  263. void UpdateThumbnailClass()
  264. {
  265. const FExtAssetData& AssetData = AssetThumbnail->GetAssetData();
  266. ThumbnailClass = MakeWeakObjectPtr(const_cast<UClass*>(AssetData.GetIconClass(&bIsClassType)));
  267. // For non-class types, use the default based upon the actual asset class
  268. // This has the side effect of not showing a class icon for assets that don't have a proper thumbnail image available
  269. const FName DefaultThumbnail = (bIsClassType) ? NAME_None : FName(*FString::Printf(TEXT("ClassThumbnail.%s"), *AssetThumbnail->GetAssetData().AssetClass.ToString()));
  270. ThumbnailBrush = FClassIconFinder::FindThumbnailForClass(ThumbnailClass.Get(), DefaultThumbnail);
  271. ClassIconBrush = FSlateIconFinder::FindIconBrushForClass(ThumbnailClass.Get());
  272. }
  273. FSlateColor GetHintBackgroundColor() const
  274. {
  275. const FLinearColor Color = HintColorAndOpacity.Get();
  276. return FSlateColor( FLinearColor( Color.R, Color.G, Color.B, FMath::Lerp( 0.0f, 0.5f, Color.A ) ) );
  277. }
  278. // SWidget implementation
  279. virtual void OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override
  280. {
  281. SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent);
  282. #if ECB_LEGACY
  283. if (!GetDefault<UExtContentBrowserSettings>()->RealTimeThumbnails )
  284. {
  285. // Update hovered thumbnails if we are not already updating them in real-time
  286. AssetThumbnail->RefreshThumbnail();
  287. }
  288. #endif
  289. }
  290. virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override
  291. {
  292. if ( WidthLastFrame != AllottedGeometry.Size.X )
  293. {
  294. WidthLastFrame = AllottedGeometry.Size.X;
  295. // The width changed, update the font
  296. if ( GenericLabelTextBlock.IsValid() )
  297. {
  298. GenericLabelTextBlock->SetFont( GetTextFont() );
  299. GenericLabelTextBlock->SetWrapTextAt( GetTextWrapWidth() );
  300. }
  301. if ( HintTextBlock.IsValid() )
  302. {
  303. HintTextBlock->SetFont( GetHintTextFont() );
  304. HintTextBlock->SetWrapTextAt( GetTextWrapWidth() );
  305. }
  306. }
  307. }
  308. private:
  309. void OnAssetDataChanged()
  310. {
  311. if ( GenericLabelTextBlock.IsValid() )
  312. {
  313. GenericLabelTextBlock->SetText( GetLabelText() );
  314. }
  315. if ( HintTextBlock.IsValid() )
  316. {
  317. HintTextBlock->SetText( GetLabelText() );
  318. }
  319. // Check if the asset has a thumbnail.
  320. const FObjectThumbnail* ObjectThumbnail = NULL;
  321. FThumbnailMap ThumbnailMap;
  322. if( AssetThumbnail->GetAsset() )
  323. {
  324. FName FullAssetName = FName( *(AssetThumbnail->GetAssetData().GetFullName()) );
  325. TArray<FName> ObjectNames;
  326. ObjectNames.Add( FullAssetName );
  327. ThumbnailTools::ConditionallyLoadThumbnailsForObjects(ObjectNames, ThumbnailMap);
  328. ObjectThumbnail = ThumbnailMap.Find( FullAssetName );
  329. }
  330. bHasRenderedThumbnail = ObjectThumbnail && !ObjectThumbnail->IsEmpty();
  331. ViewportFadeAnimation.JumpToEnd();
  332. AssetThumbnail->GetViewportRenderTargetTexture(); // Access the render texture to push it on the stack if it isnt already rendered
  333. const FExtAssetData& AssetData = AssetThumbnail->GetAssetData();
  334. UClass* Class = FindObject<UClass>(nullptr, *AssetData.AssetClass.ToString());
  335. FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
  336. TWeakPtr<IAssetTypeActions> AssetTypeActions;
  337. if ( Class != NULL )
  338. {
  339. AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Class);
  340. }
  341. UpdateThumbnailClass();
  342. AssetColor = FLinearColor::White;
  343. if ( AssetTypeActions.IsValid() )
  344. {
  345. AssetColor = AssetTypeActions.Pin()->GetTypeColor();
  346. AssetBackgroundWidget->SetBorderBackgroundColor(AssetColor.CopyWithNewOpacity(0.3f));
  347. AssetColorStripWidget->SetBorderBackgroundColor(AssetColor);
  348. }
  349. UpdateThumbnailVisibilities();
  350. }
  351. FSlateFontInfo GetTextFont() const
  352. {
  353. return FAppStyle::GetFontStyle( WidthLastFrame <= 64 ? FAppStyle::Join(Style, ".FontSmall") : FAppStyle::Join(Style, ".Font") );
  354. }
  355. FSlateFontInfo GetHintTextFont() const
  356. {
  357. return FAppStyle::GetFontStyle( WidthLastFrame <= 64 ? FAppStyle::Join(Style, ".HintFontSmall") : FAppStyle::Join(Style, ".HintFont") );
  358. }
  359. float GetTextWrapWidth() const
  360. {
  361. return WidthLastFrame - GenericThumbnailBorderPadding * 2.f;
  362. }
  363. const FSlateBrush* GetAssetBackgroundBrush() const
  364. {
  365. return FAppStyle::GetBrush(AssetBackgroundBrushName);
  366. }
  367. const FSlateBrush* GetClassBackgroundBrush() const
  368. {
  369. return FAppStyle::GetBrush(ClassBackgroundBrushName);
  370. }
  371. FSlateColor GetViewportBorderColorAndOpacity() const
  372. {
  373. return FLinearColor(AssetColor.R, AssetColor.G, AssetColor.B, ViewportFadeCurve.GetLerp());
  374. }
  375. FLinearColor GetViewportColorAndOpacity() const
  376. {
  377. return FLinearColor(1, 1, 1, ViewportFadeCurve.GetLerp());
  378. }
  379. EVisibility GetViewportVisibility() const
  380. {
  381. return bHasRenderedThumbnail ? EVisibility::Visible : EVisibility::Collapsed;
  382. }
  383. float GetAssetColorStripHeight() const
  384. {
  385. return 2.0f;
  386. }
  387. FMargin GetAssetColorStripPadding() const
  388. {
  389. const float Height = GetAssetColorStripHeight();
  390. return FMargin(0,Height,0,0);
  391. }
  392. const FSlateBrush* GetClassThumbnailBrush() const
  393. {
  394. if (ClassThumbnailBrushOverride.IsNone())
  395. {
  396. return ThumbnailBrush;
  397. }
  398. else
  399. {
  400. // Instead of getting the override thumbnail directly from the editor style here get it from the
  401. // ClassIconFinder since it may have additional styles registered which can be searched by passing
  402. // it as a default with no class to search for.
  403. return FClassIconFinder::FindThumbnailForClass(nullptr, ClassThumbnailBrushOverride);
  404. }
  405. }
  406. EVisibility GetClassThumbnailVisibility() const
  407. {
  408. if(!bHasRenderedThumbnail)
  409. {
  410. const FSlateBrush* ClassThumbnailBrush = GetClassThumbnailBrush();
  411. if( ClassThumbnailBrush && ThumbnailClass.Get() )
  412. {
  413. return EVisibility::Visible;
  414. }
  415. }
  416. return EVisibility::Collapsed;
  417. }
  418. EVisibility GetGenericThumbnailVisibility() const
  419. {
  420. return (bHasRenderedThumbnail && ViewportFadeAnimation.IsAtEnd()) ? EVisibility::Collapsed : EVisibility::Visible;
  421. }
  422. const FSlateBrush* GetClassIconBrush() const
  423. {
  424. return ClassIconBrush;
  425. }
  426. FMargin GetClassIconPadding() const
  427. {
  428. const float Height = GetAssetColorStripHeight();
  429. return FMargin(0,0,0,Height);
  430. }
  431. EVisibility GetHintTextVisibility() const
  432. {
  433. if ( bAllowHintText && ( bHasRenderedThumbnail || !GenericLabelTextBlock.IsValid() ) && HintColorAndOpacity.Get().A > 0 )
  434. {
  435. return EVisibility::Visible;
  436. }
  437. return EVisibility::Collapsed;
  438. }
  439. void OnThumbnailRendered(const FExtAssetData& AssetData)
  440. {
  441. if ( !bHasRenderedThumbnail && AssetData == AssetThumbnail->GetAssetData() && ShouldRender() )
  442. {
  443. OnRenderedThumbnailChanged( true );
  444. ViewportFadeAnimation.Play( this->AsShared() );
  445. }
  446. }
  447. void OnThumbnailRenderFailed(const FExtAssetData& AssetData)
  448. {
  449. if ( bHasRenderedThumbnail && AssetData == AssetThumbnail->GetAssetData() )
  450. {
  451. OnRenderedThumbnailChanged( false );
  452. }
  453. }
  454. bool ShouldRender() const
  455. {
  456. const FExtAssetData& AssetData = AssetThumbnail->GetAssetData();
  457. #if ECB_FEA_SHOW_INVALID
  458. if ( !AssetData.IsValid() )
  459. {
  460. return false;
  461. }
  462. #endif
  463. if( AssetData.IsAssetLoaded() )
  464. {
  465. // Loaded asset, return true if there is a rendering info for it
  466. UObject* Asset = AssetData.GetAsset();
  467. FThumbnailRenderingInfo* RenderInfo = GUnrealEd->GetThumbnailManager()->GetRenderingInfo( Asset );
  468. if ( RenderInfo != NULL && RenderInfo->Renderer != NULL )
  469. {
  470. return true;
  471. }
  472. }
  473. const FObjectThumbnail* CachedThumbnail = ThumbnailTools::FindCachedThumbnail(AssetData.GetFullName());
  474. if ( CachedThumbnail != NULL )
  475. {
  476. // There is a cached thumbnail for this asset, we should render it
  477. return !CachedThumbnail->IsEmpty();
  478. }
  479. // Unloaded blueprint or asset that may have a custom thumbnail, check to see if there is a thumbnail in the package to render
  480. if (AssetData.HasThumbnail())
  481. {
  482. return true;
  483. }
  484. if ( AssetData.AssetClass != UBlueprint::StaticClass()->GetFName() )
  485. {
  486. // If we are not a blueprint, see if the CDO of the asset's class has a rendering info
  487. // Blueprints can't do this because the rendering info is based on the generated class
  488. UClass* AssetClass = FindObject<UClass>(nullptr, *AssetData.AssetClass.ToString());
  489. if ( AssetClass )
  490. {
  491. FThumbnailRenderingInfo* RenderInfo = GUnrealEd->GetThumbnailManager()->GetRenderingInfo( AssetClass->GetDefaultObject() );
  492. if ( RenderInfo != NULL && RenderInfo->Renderer != NULL )
  493. {
  494. return true;
  495. }
  496. }
  497. }
  498. // Unloaded blueprint or asset that may have a custom thumbnail, check to see if there is a thumbnail in the package to render
  499. FString PackageFilename;
  500. if ( FPackageName::DoesPackageExist(AssetData.PackageName.ToString(), &PackageFilename) )
  501. {
  502. TSet<FName> ObjectFullNames;
  503. FThumbnailMap ThumbnailMap;
  504. FName ObjectFullName = FName(*AssetData.GetFullName());
  505. ObjectFullNames.Add(ObjectFullName);
  506. ThumbnailTools::LoadThumbnailsFromPackage(PackageFilename, ObjectFullNames, ThumbnailMap);
  507. const FObjectThumbnail* ThumbnailPtr = ThumbnailMap.Find(ObjectFullName);
  508. if (ThumbnailPtr)
  509. {
  510. const FObjectThumbnail& ObjectThumbnail = *ThumbnailPtr;
  511. return ObjectThumbnail.GetImageWidth() > 0 && ObjectThumbnail.GetImageHeight() > 0 && ObjectThumbnail.GetCompressedDataSize() > 0;
  512. }
  513. }
  514. return false;
  515. }
  516. FText GetLabelText() const
  517. {
  518. if( Label != EThumbnailLabel::NoLabel )
  519. {
  520. if ( Label == EThumbnailLabel::ClassName )
  521. {
  522. return GetAssetClassDisplayName();
  523. }
  524. else if ( Label == EThumbnailLabel::AssetName )
  525. {
  526. return GetAssetDisplayName();
  527. }
  528. }
  529. return FText::GetEmpty();
  530. }
  531. FText GetDisplayNameForClass( UClass* Class, const FExtAssetData* InExtAssetData = nullptr) const
  532. {
  533. FText ClassDisplayName;
  534. if ( Class )
  535. {
  536. FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
  537. TWeakPtr<IAssetTypeActions> AssetTypeActions = AssetToolsModule.Get().GetAssetTypeActionsForClass(Class);
  538. if ( AssetTypeActions.IsValid() )
  539. {
  540. if (InExtAssetData != nullptr)
  541. {
  542. FAssetTypeActions_Base* BaseAssetTypeAction = static_cast<FAssetTypeActions_Base*>(AssetTypeActions.Pin().Get());
  543. if (BaseAssetTypeAction != nullptr)
  544. {
  545. ClassDisplayName = BaseAssetTypeAction->GetDisplayNameFromAssetData(InExtAssetData->AssetData);
  546. }
  547. }
  548. if (ClassDisplayName.IsEmpty())
  549. {
  550. ClassDisplayName = AssetTypeActions.Pin()->GetName();
  551. }
  552. }
  553. if ( ClassDisplayName.IsEmpty() )
  554. {
  555. ClassDisplayName = FText::FromString( FName::NameToDisplayString(*Class->GetName(), false) );
  556. }
  557. }
  558. return ClassDisplayName;
  559. }
  560. FText GetAssetClassDisplayName() const
  561. {
  562. const FExtAssetData& AssetData = AssetThumbnail->GetAssetData();
  563. /*
  564. FName(TEXT("Code"));
  565. FName(TEXT("Code Missing"));
  566. FName(TEXT("Map Missing"));
  567. FName(TEXT("Package Missing"));
  568. */
  569. FString AssetClass = AssetData.AssetClass.ToString();
  570. const bool bInvalidUAsset = !AssetData.IsValid() && AssetData.IsUAsset();
  571. if (bInvalidUAsset)
  572. {
  573. AssetClass = TEXT("");
  574. }
  575. UClass* Class = FindObjectSafe<UClass>(nullptr, *AssetClass);
  576. if ( Class )
  577. {
  578. return GetDisplayNameForClass( Class, &AssetData );
  579. }
  580. if (bInvalidUAsset)
  581. {
  582. return FText::FromString(AssetData.GetInvalidReason());
  583. }
  584. else
  585. {
  586. return FText::FromString(AssetClass);
  587. }
  588. }
  589. FText GetAssetDisplayName() const
  590. {
  591. const FExtAssetData& ExtAssetData = AssetThumbnail->GetAssetData();
  592. if ( ExtAssetData.GetClass() == UClass::StaticClass() )
  593. {
  594. UClass* Class = Cast<UClass>( ExtAssetData.GetAsset() );
  595. return GetDisplayNameForClass( Class );
  596. }
  597. return FText::FromName(ExtAssetData.AssetName);
  598. }
  599. void OnRenderedThumbnailChanged( bool bInHasRenderedThumbnail )
  600. {
  601. bHasRenderedThumbnail = bInHasRenderedThumbnail;
  602. UpdateThumbnailVisibilities();
  603. }
  604. void UpdateThumbnailVisibilities()
  605. {
  606. // Either the generic label or thumbnail should be shown, but not both at once
  607. const EVisibility ClassThumbnailVisibility = GetClassThumbnailVisibility();
  608. if( GenericThumbnailImage.IsValid() )
  609. {
  610. GenericThumbnailImage->SetVisibility( ClassThumbnailVisibility );
  611. }
  612. if( GenericLabelTextBlock.IsValid() )
  613. {
  614. GenericLabelTextBlock->SetVisibility( (ClassThumbnailVisibility == EVisibility::Visible) ? EVisibility::Collapsed : EVisibility::Visible );
  615. }
  616. const EVisibility ViewportVisibility = GetViewportVisibility();
  617. if( RenderedThumbnailWidget.IsValid() )
  618. {
  619. RenderedThumbnailWidget->SetVisibility( ViewportVisibility );
  620. if( ClassIconWidget.IsValid() )
  621. {
  622. ClassIconWidget->SetVisibility( ViewportVisibility );
  623. }
  624. }
  625. }
  626. TOptional<FVector2D> GetGenericThumbnailDesiredSize() const
  627. {
  628. const int32 Size = GenericThumbnailSize.Get();
  629. return FVector2D(Size, Size);
  630. }
  631. private:
  632. TSharedPtr<STextBlock> GenericLabelTextBlock;
  633. TSharedPtr<STextBlock> HintTextBlock;
  634. TSharedPtr<SImage> GenericThumbnailImage;
  635. TSharedPtr<SBorder> ClassIconWidget;
  636. TSharedPtr<SBorder> RenderedThumbnailWidget;
  637. TSharedPtr<SBorder> AssetBackgroundWidget;
  638. TSharedPtr<SBorder> AssetColorStripWidget;
  639. TSharedPtr<FExtAssetThumbnail> AssetThumbnail;
  640. FCurveSequence ViewportFadeAnimation;
  641. FCurveHandle ViewportFadeCurve;
  642. FLinearColor AssetColor;
  643. TOptional<FLinearColor> AssetTypeColorOverride;
  644. float WidthLastFrame;
  645. float GenericThumbnailBorderPadding;
  646. bool bHasRenderedThumbnail;
  647. FName Style;
  648. TAttribute< FText > HighlightedText;
  649. EThumbnailLabel::Type Label;
  650. TAttribute< FLinearColor > HintColorAndOpacity;
  651. TAttribute<int32> GenericThumbnailSize;
  652. bool bAllowHintText;
  653. /** The name of the thumbnail which should be used instead of the class thumbnail. */
  654. FName ClassThumbnailBrushOverride;
  655. FName AssetBackgroundBrushName;
  656. FName ClassBackgroundBrushName;
  657. const FSlateBrush* ThumbnailBrush;
  658. const FSlateBrush* ClassIconBrush;
  659. /** The class to use when finding the thumbnail. */
  660. TWeakObjectPtr<UClass> ThumbnailClass;
  661. /** Are we showing a class type? (UClass, UBlueprint) */
  662. bool bIsClassType;
  663. };
  664. //-------------------------------------------------------------------------------------
  665. // FExtAssetThumbnail implementation
  666. //
  667. FExtAssetThumbnail::FExtAssetThumbnail( UObject* InAsset, uint32 InWidth, uint32 InHeight, const TSharedPtr<class FExtAssetThumbnailPool>& InThumbnailPool )
  668. : ThumbnailPool(InThumbnailPool)
  669. , AssetData(InAsset ? FExtAssetData(InAsset) : FExtAssetData())
  670. , Width( InWidth )
  671. , Height( InHeight )
  672. {
  673. if ( InThumbnailPool.IsValid() )
  674. {
  675. InThumbnailPool->AddReferencer(*this);
  676. }
  677. }
  678. FExtAssetThumbnail::FExtAssetThumbnail( const FExtAssetData& InAssetData , uint32 InWidth, uint32 InHeight, const TSharedPtr<class FExtAssetThumbnailPool>& InThumbnailPool )
  679. : ThumbnailPool( InThumbnailPool )
  680. , AssetData ( InAssetData )
  681. , Width( InWidth )
  682. , Height( InHeight )
  683. {
  684. if ( InThumbnailPool.IsValid() )
  685. {
  686. InThumbnailPool->AddReferencer(*this);
  687. }
  688. }
  689. FExtAssetThumbnail::~FExtAssetThumbnail()
  690. {
  691. if ( ThumbnailPool.IsValid() )
  692. {
  693. ThumbnailPool.Pin()->RemoveReferencer(*this);
  694. }
  695. }
  696. FIntPoint FExtAssetThumbnail::GetSize() const
  697. {
  698. return FIntPoint( Width, Height );
  699. }
  700. FSlateShaderResource* FExtAssetThumbnail::GetViewportRenderTargetTexture() const
  701. {
  702. FSlateTexture2DRHIRef* Texture = NULL;
  703. if ( ThumbnailPool.IsValid() )
  704. {
  705. Texture = ThumbnailPool.Pin()->AccessTexture( AssetData, Width, Height );
  706. }
  707. if( !Texture || !Texture->IsValid() )
  708. {
  709. return NULL;
  710. }
  711. return Texture;
  712. }
  713. UObject* FExtAssetThumbnail::GetAsset() const
  714. {
  715. if ( AssetData.ObjectPath != NAME_None )
  716. {
  717. return FindObject<UObject>(NULL, *AssetData.ObjectPath.ToString());
  718. }
  719. else
  720. {
  721. return NULL;
  722. }
  723. }
  724. const FExtAssetData& FExtAssetThumbnail::GetAssetData() const
  725. {
  726. return AssetData;
  727. }
  728. void FExtAssetThumbnail::SetAsset( const UObject* InAsset )
  729. {
  730. SetAsset( FExtAssetData(InAsset) );
  731. }
  732. void FExtAssetThumbnail::SetAsset( const FExtAssetData& InAssetData )
  733. {
  734. if ( ThumbnailPool.IsValid() )
  735. {
  736. ThumbnailPool.Pin()->RemoveReferencer(*this);
  737. }
  738. // if ( InAssetData.IsValid() ) // Even Invalid Asset can provide value information
  739. {
  740. AssetData = InAssetData;
  741. if ( ThumbnailPool.IsValid() )
  742. {
  743. ThumbnailPool.Pin()->AddReferencer(*this);
  744. }
  745. }
  746. // else
  747. // {
  748. // AssetData = FExtAssetData();
  749. // }
  750. AssetDataChangedEvent.Broadcast();
  751. }
  752. TSharedRef<SWidget> FExtAssetThumbnail::MakeThumbnailWidget( const FExtAssetThumbnailConfig& InConfig )
  753. {
  754. return
  755. SNew(SExtAssetThumbnail)
  756. .AssetThumbnail( SharedThis(this) )
  757. .ThumbnailPool( ThumbnailPool.Pin() )
  758. .AllowFadeIn( InConfig.bAllowFadeIn )
  759. .ForceGenericThumbnail( InConfig.bForceGenericThumbnail )
  760. .Label( InConfig.ThumbnailLabel )
  761. .HighlightedText( InConfig.HighlightedText )
  762. .HintColorAndOpacity( InConfig.HintColorAndOpacity )
  763. .AllowHintText( InConfig.bAllowHintText )
  764. .ClassThumbnailBrushOverride( InConfig.ClassThumbnailBrushOverride )
  765. .AllowAssetSpecificThumbnailOverlay( InConfig.bAllowAssetSpecificThumbnailOverlay )
  766. .AssetTypeColorOverride( InConfig.AssetTypeColorOverride )
  767. .Padding(InConfig.Padding)
  768. .GenericThumbnailSize(InConfig.GenericThumbnailSize);
  769. }
  770. void FExtAssetThumbnail::RefreshThumbnail()
  771. {
  772. if ( ThumbnailPool.IsValid() && /*AssetData.IsValid()*/AssetData.HasThumbnail() )
  773. {
  774. ThumbnailPool.Pin()->RefreshThumbnail( SharedThis(this) );
  775. }
  776. }
  777. TSharedPtr<SWidget> FExtAssetThumbnail::GetSpecificThumbnailOverlay() const
  778. {
  779. TSharedRef<SOverlay> ThumbnailOverlayWidget = SNew(SOverlay);
  780. const bool bDisplayEngineVersionOverlay = GetDefault<UExtContentBrowserSettings>()->DisplayEngineVersionOverlay;
  781. if (bDisplayEngineVersionOverlay)
  782. {
  783. //FText OverlayText = FText::FromString(AssetData.GetSavedEngineVersionForDisplay());
  784. ThumbnailOverlayWidget->AddSlot()
  785. [
  786. SNew(SBorder)
  787. .BorderImage(FAppStyle::GetNoBrush())
  788. //.Visibility(TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&FExtAssetThumbnailOverlayManager::GetSpecificThumbnailOverlayVisibility, InAssetData.AssetClass)))
  789. .Padding(FMargin(1.0f, 1.0f, 1.0f, 1.0f))
  790. .HAlign(HAlign_Left)
  791. .VAlign(VAlign_Top)
  792. [
  793. SNew(STextBlock)
  794. //.Text(OverlayText)
  795. .Text_Lambda([this]()
  796. {
  797. return FText::FromString(this->GetAssetData().GetSavedEngineVersionForDisplay());
  798. })
  799. .TextStyle(FExtContentBrowserStyle::Get(), "UAssetBrowser.AssetThumbnail.EngineOverlay")
  800. .Justification(ETextJustify::Center)
  801. ]
  802. ];
  803. }
  804. #if ECB_FEA_VALIDATE_OVERLAY
  805. const bool bDisplayValidationOverlay = GetDefault<UExtContentBrowserSettings>()->DisplayValidationStatusOverlay;
  806. if (bDisplayValidationOverlay)
  807. {
  808. ThumbnailOverlayWidget->AddSlot()
  809. [
  810. SNew(SBorder)
  811. .BorderImage(FAppStyle::GetNoBrush())
  812. .Padding(FMargin(2.0f, 1.0f, 1.0f, 8.0f))
  813. .HAlign(HAlign_Left)
  814. .VAlign(VAlign_Bottom)
  815. [
  816. SNew(SImage)
  817. .Image(this, &FExtAssetThumbnail::GetValidationIconBrush)
  818. ]
  819. ];
  820. }
  821. #endif
  822. #if ECB_WIP_CONTENT_TYPE_OVERLAY
  823. const bool bDisplayContentTypeOverlay = GetDefault<UExtContentBrowserSettings>()->DisplayContentTypeOverlay;
  824. if (bDisplayContentTypeOverlay)
  825. {
  826. ThumbnailOverlayWidget->AddSlot()
  827. [
  828. SNew(SBorder)
  829. .BorderImage(FAppStyle::GetNoBrush())
  830. .Visibility(this, &FExtAssetThumbnail::GetContentTypeOverlayVisibility)
  831. .Padding(FMargin(1.0f, 1.0f, 1.0f, 1.0f))
  832. .HAlign(HAlign_Right)
  833. .VAlign(VAlign_Top)
  834. [
  835. SNew(STextBlock)
  836. //.Text(OverlayText)
  837. .Text_Lambda([this]()
  838. {
  839. return FText::FromString(this->GetAssetData().GetAssetContentTypeForDisplay());
  840. })
  841. .TextStyle(FExtContentBrowserStyle::Get(), "UAssetBrowser.AssetThumbnail.EngineOverlay")
  842. .Justification(ETextJustify::Center)
  843. ]
  844. ];
  845. }
  846. #endif
  847. return ThumbnailOverlayWidget;
  848. }
  849. const FSlateBrush* FExtAssetThumbnail::GetValidationIconBrush() const
  850. {
  851. #if ECB_FEA_VALIDATE_OVERLAY
  852. if (!AssetData.IsValid())
  853. {
  854. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationInValid");
  855. }
  856. if (const FExtAssetDependencyInfo* DependencyInfoPtr = FExtContentBrowserSingleton::GetAssetRegistry().GetCachedAssetDependencyInfo(AssetData))
  857. {
  858. const FExtAssetDependencyInfo& DependencyInfo = *DependencyInfoPtr;
  859. if (DependencyInfo.AssetStatus == EDependencyNodeStatus::Invalid || DependencyInfo.AssetStatus == EDependencyNodeStatus::Missing)
  860. {
  861. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationInValid");
  862. }
  863. else if (DependencyInfo.AssetStatus == EDependencyNodeStatus::Valid)
  864. {
  865. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationValid");
  866. }
  867. else if (DependencyInfo.AssetStatus == EDependencyNodeStatus::ValidWithSoftReferenceIssue)
  868. {
  869. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationIssue");
  870. }
  871. else
  872. {
  873. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationUknown");
  874. }
  875. }
  876. return FExtContentBrowserStyle::Get().GetBrush("UAssetBrowser.ValidationUknown");
  877. #endif
  878. return nullptr;
  879. }
  880. EVisibility FExtAssetThumbnail::GetContentTypeOverlayVisibility() const
  881. {
  882. //return EVisibility::Collapsed;
  883. return EVisibility::Visible;
  884. }
  885. //-------------------------------------------------------------------------------------
  886. // FExtAssetThumbnailPool implementation
  887. //
  888. FExtAssetThumbnailPool::FExtAssetThumbnailPool( uint32 InNumInPool, const TAttribute<bool>& InAreRealTimeThumbnailsAllowed, double InMaxFrameTimeAllowance, uint32 InMaxRealTimeThumbnailsPerFrame )
  889. : AreRealTimeThumbnailsAllowed( InAreRealTimeThumbnailsAllowed )
  890. , NumInPool( InNumInPool )
  891. , MaxRealTimeThumbnailsPerFrame( InMaxRealTimeThumbnailsPerFrame )
  892. , MaxFrameTimeAllowance( InMaxFrameTimeAllowance )
  893. {
  894. FCoreUObjectDelegates::OnObjectPropertyChanged.AddRaw(this, &FExtAssetThumbnailPool::OnObjectPropertyChanged);
  895. FCoreUObjectDelegates::OnAssetLoaded.AddRaw(this, &FExtAssetThumbnailPool::OnAssetLoaded);
  896. if ( GEditor )
  897. {
  898. GEditor->OnActorMoved().AddRaw( this, &FExtAssetThumbnailPool::OnActorPostEditMove );
  899. }
  900. }
  901. FExtAssetThumbnailPool::~FExtAssetThumbnailPool()
  902. {
  903. FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this);
  904. FCoreUObjectDelegates::OnAssetLoaded.RemoveAll(this);
  905. if ( GEditor )
  906. {
  907. GEditor->OnActorMoved().RemoveAll(this);
  908. }
  909. // Release all the texture resources
  910. ReleaseResources();
  911. }
  912. FExtAssetThumbnailPool::FThumbnailInfo::~FThumbnailInfo()
  913. {
  914. if( ThumbnailTexture )
  915. {
  916. delete ThumbnailTexture;
  917. ThumbnailTexture = NULL;
  918. }
  919. if( ThumbnailRenderTarget )
  920. {
  921. delete ThumbnailRenderTarget;
  922. ThumbnailRenderTarget = NULL;
  923. }
  924. }
  925. void FExtAssetThumbnailPool::ReleaseResources()
  926. {
  927. // Clear all pending render requests
  928. ThumbnailsToRenderStack.Empty();
  929. RealTimeThumbnails.Empty();
  930. RealTimeThumbnailsToRender.Empty();
  931. TArray< TSharedRef<FThumbnailInfo> > ThumbnailsToRelease;
  932. for( auto ThumbIt = ThumbnailToTextureMap.CreateConstIterator(); ThumbIt; ++ThumbIt )
  933. {
  934. ThumbnailsToRelease.Add(ThumbIt.Value());
  935. }
  936. ThumbnailToTextureMap.Empty();
  937. for( auto ThumbIt = FreeThumbnails.CreateConstIterator(); ThumbIt; ++ThumbIt )
  938. {
  939. ThumbnailsToRelease.Add(*ThumbIt);
  940. }
  941. FreeThumbnails.Empty();
  942. for ( auto ThumbIt = ThumbnailsToRelease.CreateConstIterator(); ThumbIt; ++ThumbIt )
  943. {
  944. const TSharedRef<FThumbnailInfo>& Thumb = *ThumbIt;
  945. // Release rendering resources
  946. FThumbnailInfo_RenderThread ThumbInfo = Thumb.Get();
  947. ENQUEUE_RENDER_COMMAND(ReleaseThumbnailResources)(
  948. [ThumbInfo](FRHICommandListImmediate& RHICmdList)
  949. {
  950. ThumbInfo.ThumbnailTexture->ClearTextureData();
  951. ThumbInfo.ThumbnailTexture->ReleaseResource();
  952. ThumbInfo.ThumbnailRenderTarget->ReleaseResource();
  953. });
  954. }
  955. // Wait for all resources to be released
  956. FlushRenderingCommands();
  957. // Make sure there are no more references to any of our thumbnails now that rendering commands have been flushed
  958. for ( auto ThumbIt = ThumbnailsToRelease.CreateConstIterator(); ThumbIt; ++ThumbIt )
  959. {
  960. const TSharedRef<FThumbnailInfo>& Thumb = *ThumbIt;
  961. if ( !Thumb.IsUnique() )
  962. {
  963. ensureMsgf(0, TEXT("Thumbnail info for '%s' is still referenced by '%d' other objects"), *Thumb->AssetData.ObjectPath.ToString(), Thumb.GetSharedReferenceCount());
  964. }
  965. }
  966. }
  967. TStatId FExtAssetThumbnailPool::GetStatId() const
  968. {
  969. RETURN_QUICK_DECLARE_CYCLE_STAT( FExtAssetThumbnailPool, STATGROUP_Tickables );
  970. }
  971. bool FExtAssetThumbnailPool::IsTickable() const
  972. {
  973. return RecentlyLoadedAssets.Num() > 0 || ThumbnailsToRenderStack.Num() > 0 || RealTimeThumbnails.Num() > 0 || bWereShadersCompilingLastFrame || (GShaderCompilingManager && GShaderCompilingManager->IsCompiling());
  974. }
  975. void FExtAssetThumbnailPool::Tick( float DeltaTime )
  976. {
  977. // If throttling do not tick unless drag dropping which could have a thumbnail as the cursor decorator
  978. if (!FSlateApplication::Get().IsDragDropping() && !FSlateThrottleManager::Get().IsAllowingExpensiveTasks() && !FSlateApplication::Get().AnyMenusVisible())
  979. {
  980. return;
  981. }
  982. const bool bAreShadersCompiling = (GShaderCompilingManager && GShaderCompilingManager->IsCompiling());
  983. if (bWereShadersCompilingLastFrame && !bAreShadersCompiling)
  984. {
  985. ThumbnailsToRenderStack.Reset();
  986. // Reschedule visible thumbnails to be rerendered now that shaders are finished compiling
  987. for (auto ThumbIt = ThumbnailToTextureMap.CreateIterator(); ThumbIt; ++ThumbIt)
  988. {
  989. ThumbnailsToRenderStack.Push(ThumbIt.Value());
  990. }
  991. }
  992. bWereShadersCompilingLastFrame = bAreShadersCompiling;
  993. // If there were any assets loaded since last frame that we are currently displaying thumbnails for, push them on the render stack now.
  994. if ( RecentlyLoadedAssets.Num() > 0 )
  995. {
  996. for ( int32 LoadedAssetIdx = 0; LoadedAssetIdx < RecentlyLoadedAssets.Num(); ++LoadedAssetIdx )
  997. {
  998. RefreshThumbnailsFor(RecentlyLoadedAssets[LoadedAssetIdx]);
  999. }
  1000. RecentlyLoadedAssets.Empty();
  1001. }
  1002. // If we have dynamic thumbnails are we are done rendering the last batch of dynamic thumbnails, start a new batch as long as real-time thumbnails are enabled
  1003. const bool bIsInPIEOrSimulate = GEditor->PlayWorld != NULL || GEditor->bIsSimulatingInEditor;
  1004. #if ECB_LEGACY
  1005. const bool bShouldUseRealtimeThumbnails = AreRealTimeThumbnailsAllowed.Get() && GetDefault<UExtContentBrowserSettings>()->RealTimeThumbnails && !bIsInPIEOrSimulate;
  1006. #else
  1007. const bool bShouldUseRealtimeThumbnails = false;
  1008. #endif
  1009. if ( bShouldUseRealtimeThumbnails && RealTimeThumbnails.Num() > 0 && RealTimeThumbnailsToRender.Num() == 0 )
  1010. {
  1011. double CurrentTime = FPlatformTime::Seconds();
  1012. for ( int32 ThumbIdx = RealTimeThumbnails.Num() - 1; ThumbIdx >= 0; --ThumbIdx )
  1013. {
  1014. const TSharedRef<FThumbnailInfo>& Thumb = RealTimeThumbnails[ThumbIdx];
  1015. if ( Thumb->AssetData.IsAssetLoaded() )
  1016. {
  1017. // Only render thumbnails that have been requested recently
  1018. if ( (CurrentTime - Thumb->LastAccessTime) < 1.f )
  1019. {
  1020. RealTimeThumbnailsToRender.Add(Thumb);
  1021. }
  1022. }
  1023. else
  1024. {
  1025. RealTimeThumbnails.RemoveAt(ThumbIdx);
  1026. }
  1027. }
  1028. }
  1029. uint32 NumRealTimeThumbnailsRenderedThisFrame = 0;
  1030. // If there are any thumbnails to render, pop one off the stack and render it.
  1031. if( ThumbnailsToRenderStack.Num() + RealTimeThumbnailsToRender.Num() > 0 )
  1032. {
  1033. double FrameStartTime = FPlatformTime::Seconds();
  1034. // Render as many thumbnails as we are allowed to
  1035. while( ThumbnailsToRenderStack.Num() + RealTimeThumbnailsToRender.Num() > 0 && FPlatformTime::Seconds() - FrameStartTime < MaxFrameTimeAllowance )
  1036. {
  1037. TSharedPtr<FThumbnailInfo> Info;
  1038. if ( ThumbnailsToRenderStack.Num() > 0 )
  1039. {
  1040. Info = ThumbnailsToRenderStack.Pop();
  1041. }
  1042. else if (RealTimeThumbnailsToRender.Num() > 0 && NumRealTimeThumbnailsRenderedThisFrame < MaxRealTimeThumbnailsPerFrame )
  1043. {
  1044. Info = RealTimeThumbnailsToRender.Pop();
  1045. NumRealTimeThumbnailsRenderedThisFrame++;
  1046. }
  1047. else
  1048. {
  1049. // No thumbnails left to render or we don't want to render any more
  1050. break;
  1051. }
  1052. if( Info.IsValid() )
  1053. {
  1054. TSharedRef<FThumbnailInfo> InfoRef = Info.ToSharedRef();
  1055. /*if ( InfoRef->AssetData.IsValid() )*/
  1056. if (InfoRef->AssetData.HasThumbnail())
  1057. {
  1058. bool bLoadedThumbnail = false;
  1059. // If this is a loaded asset and we have a rendering info for it, render a fresh thumbnail here
  1060. if( InfoRef->AssetData.IsAssetLoaded() )
  1061. {
  1062. UObject* Asset = InfoRef->AssetData.GetAsset();
  1063. FThumbnailRenderingInfo* RenderInfo = GUnrealEd->GetThumbnailManager()->GetRenderingInfo( Asset );
  1064. if ( RenderInfo != NULL && RenderInfo->Renderer != NULL )
  1065. {
  1066. FThumbnailInfo_RenderThread ThumbInfo = InfoRef.Get();
  1067. ENQUEUE_RENDER_COMMAND(SyncSlateTextureCommand)(
  1068. [ThumbInfo](FRHICommandListImmediate& RHICmdList)
  1069. {
  1070. if ( ThumbInfo.ThumbnailTexture->GetTypedResource() != ThumbInfo.ThumbnailRenderTarget->GetTextureRHI() )
  1071. {
  1072. ThumbInfo.ThumbnailTexture->ClearTextureData();
  1073. ThumbInfo.ThumbnailTexture->ReleaseRHI();
  1074. ThumbInfo.ThumbnailTexture->SetRHIRef(ThumbInfo.ThumbnailRenderTarget->GetTextureRHI(), ThumbInfo.Width, ThumbInfo.Height);
  1075. }
  1076. });
  1077. if (InfoRef->LastUpdateTime <= 0.0f/* || RenderInfo->Renderer->AllowsRealtimeThumbnails(Asset)*/)
  1078. {
  1079. //@todo: this should be done on the GPU only but it is not supported by thumbnail tools yet
  1080. ThumbnailTools::RenderThumbnail(
  1081. Asset,
  1082. InfoRef->Width,
  1083. InfoRef->Height,
  1084. ThumbnailTools::EThumbnailTextureFlushMode::NeverFlush,
  1085. InfoRef->ThumbnailRenderTarget
  1086. );
  1087. }
  1088. bLoadedThumbnail = true;
  1089. // Since this was rendered, add it to the list of thumbnails that can be rendered in real-time
  1090. RealTimeThumbnails.AddUnique(InfoRef);
  1091. }
  1092. }
  1093. const FObjectThumbnail* ObjectThumbnailPtr = NULL;
  1094. FObjectThumbnail ObjectThumbnail;
  1095. // If we could not render a fresh thumbnail, see if we already have a cached one to load
  1096. if ( !bLoadedThumbnail )
  1097. {
  1098. // Unloaded asset
  1099. const bool bUseThumbnailPool = GetDefault<UExtContentBrowserSettings>()->bUseThumbnailPool;
  1100. #if ECB_WIP_THUMB_CACHE
  1101. const FObjectThumbnail* FoundThumbnail = FExtContentBrowserSingleton::GetAssetRegistry().FindCachedThumbnail(InfoRef->AssetData.PackageFilePath);
  1102. #else
  1103. #if ECB_WIP_OBJECT_THUMB_POOL
  1104. const FObjectThumbnail* FoundThumbnail = bUseThumbnailPool
  1105. ? FExtContentBrowserSingleton::GetThumbnailPool().FindCachedThumbnail(InfoRef->AssetData.GetFullName())
  1106. : ThumbnailTools::FindCachedThumbnail(InfoRef->AssetData.GetFullName());
  1107. #else
  1108. const FObjectThumbnail* FoundThumbnail = ThumbnailTools::FindCachedThumbnail(InfoRef->AssetData.GetFullName());
  1109. #endif
  1110. #endif
  1111. if ( FoundThumbnail )
  1112. {
  1113. //ECB_LOG(Display, TEXT("Found cached thumbnail for %s"), *InfoRef->AssetData.PackageFilePath.ToString());
  1114. ObjectThumbnailPtr = FoundThumbnail;
  1115. }
  1116. else
  1117. {
  1118. #if ECB_WIP_OBJECT_THUMB_POOL
  1119. FObjectThumbnail& ObjectThumbnailRef = bUseThumbnailPool
  1120. ? FExtContentBrowserSingleton::GetThumbnailPool().AddToPool(InfoRef->AssetData.GetFullName())
  1121. : ObjectThumbnail;
  1122. if (InfoRef->AssetData.LoadThumbnail(ObjectThumbnailRef))
  1123. {
  1124. ObjectThumbnailPtr = &ObjectThumbnailRef;
  1125. }
  1126. #else
  1127. // If we don't have a cached thumbnail, try to find it on disk
  1128. if (InfoRef->AssetData.LoadThumbnail(ObjectThumbnail))
  1129. {
  1130. ObjectThumbnailPtr = &ObjectThumbnail;
  1131. }
  1132. #endif
  1133. }
  1134. }
  1135. if ( ObjectThumbnailPtr )
  1136. {
  1137. if ( ObjectThumbnailPtr->GetImageWidth() > 0 && ObjectThumbnailPtr->GetImageHeight() > 0 && ObjectThumbnailPtr->GetUncompressedImageData().Num() > 0 )
  1138. {
  1139. // Make bulk data for updating the texture memory later
  1140. FSlateTextureData* BulkData = new FSlateTextureData(ObjectThumbnailPtr->GetImageWidth(),ObjectThumbnailPtr->GetImageHeight(),GPixelFormats[PF_B8G8R8A8].BlockBytes, ObjectThumbnailPtr->AccessImageData() );
  1141. // Update the texture RHI
  1142. FThumbnailInfo_RenderThread ThumbInfo = InfoRef.Get();
  1143. ENQUEUE_RENDER_COMMAND(ClearSlateTextureCommand)(
  1144. [ThumbInfo, BulkData](FRHICommandListImmediate& RHICmdList)
  1145. {
  1146. if (ThumbInfo.ThumbnailTexture->GetTypedResource() == ThumbInfo.ThumbnailRenderTarget->GetTextureRHI())
  1147. {
  1148. ThumbInfo.ThumbnailTexture->SetRHIRef(NULL, ThumbInfo.Width, ThumbInfo.Height);
  1149. }
  1150. ThumbInfo.ThumbnailTexture->SetTextureData(MakeShareable(BulkData));
  1151. ThumbInfo.ThumbnailTexture->UpdateRHI(RHICmdList);
  1152. });
  1153. bLoadedThumbnail = true;
  1154. }
  1155. else
  1156. {
  1157. bLoadedThumbnail = false;
  1158. }
  1159. }
  1160. if ( bLoadedThumbnail )
  1161. {
  1162. // Mark it as updated
  1163. InfoRef->LastUpdateTime = FPlatformTime::Seconds();
  1164. // Notify listeners that a thumbnail has been rendered
  1165. ThumbnailRenderedEvent.Broadcast(InfoRef->AssetData);
  1166. }
  1167. else
  1168. {
  1169. // Notify listeners that a thumbnail has been rendered
  1170. ThumbnailRenderFailedEvent.Broadcast(InfoRef->AssetData);
  1171. }
  1172. }
  1173. }
  1174. }
  1175. }
  1176. }
  1177. FSlateTexture2DRHIRef* FExtAssetThumbnailPool::AccessTexture( const FExtAssetData& AssetData, uint32 Width, uint32 Height )
  1178. {
  1179. if(AssetData.ObjectPath == NAME_None || Width == 0 || Height == 0)
  1180. {
  1181. return NULL;
  1182. }
  1183. else
  1184. {
  1185. FThumbId ThumbId( AssetData.ObjectPath, Width, Height ) ;
  1186. // Check to see if a thumbnail for this asset exists. If so we don't need to render it
  1187. const TSharedRef<FThumbnailInfo>* ThumbnailInfoPtr = ThumbnailToTextureMap.Find( ThumbId );
  1188. TSharedPtr<FThumbnailInfo> ThumbnailInfo;
  1189. if( ThumbnailInfoPtr )
  1190. {
  1191. ThumbnailInfo = *ThumbnailInfoPtr;
  1192. }
  1193. else
  1194. {
  1195. // If a the max number of thumbnails allowed by the pool exists then reuse its rendering resource for the new thumbnail
  1196. if( FreeThumbnails.Num() == 0 && ThumbnailToTextureMap.Num() == NumInPool )
  1197. {
  1198. // Find the thumbnail which was accessed last and use it for the new thumbnail
  1199. float LastAccessTime = FLT_MAX;
  1200. const FThumbId* AssetToRemove = NULL;
  1201. for( TMap< FThumbId, TSharedRef<FThumbnailInfo> >::TConstIterator It(ThumbnailToTextureMap); It; ++It )
  1202. {
  1203. if( It.Value()->LastAccessTime < LastAccessTime )
  1204. {
  1205. LastAccessTime = It.Value()->LastAccessTime;
  1206. AssetToRemove = &It.Key();
  1207. }
  1208. }
  1209. check( AssetToRemove );
  1210. // Remove the old mapping
  1211. ThumbnailInfo = ThumbnailToTextureMap.FindAndRemoveChecked( *AssetToRemove );
  1212. }
  1213. else if( FreeThumbnails.Num() > 0 )
  1214. {
  1215. ThumbnailInfo = FreeThumbnails.Pop();
  1216. FSlateTextureRenderTarget2DResource* ThumbnailRenderTarget = ThumbnailInfo->ThumbnailRenderTarget;
  1217. ENQUEUE_RENDER_COMMAND(SlateUpdateThumbSizeCommand)(
  1218. [ThumbnailRenderTarget, Width, Height](FRHICommandListImmediate& RHICmdList)
  1219. {
  1220. ThumbnailRenderTarget->SetSize(Width, Height);
  1221. });
  1222. }
  1223. else
  1224. {
  1225. // There are no free thumbnail resources
  1226. check( (uint32)ThumbnailToTextureMap.Num() <= NumInPool );
  1227. check( !ThumbnailInfo.IsValid() );
  1228. // The pool isn't used up so just make a new texture
  1229. // Make new thumbnail info if it doesn't exist
  1230. // This happens when the pool is not yet full
  1231. ThumbnailInfo = MakeShareable( new FThumbnailInfo );
  1232. // Set the thumbnail and asset on the info. It is NOT safe to change or NULL these pointers until ReleaseResources.
  1233. ThumbnailInfo->ThumbnailTexture = new FSlateTexture2DRHIRef( Width, Height, PF_B8G8R8A8, NULL, TexCreate_Dynamic );
  1234. ThumbnailInfo->ThumbnailRenderTarget = new FSlateTextureRenderTarget2DResource(FLinearColor::Black, Width, Height, PF_B8G8R8A8, SF_Point, TA_Wrap, TA_Wrap, 0.0f);
  1235. BeginInitResource( ThumbnailInfo->ThumbnailTexture );
  1236. BeginInitResource( ThumbnailInfo->ThumbnailRenderTarget );
  1237. }
  1238. check( ThumbnailInfo.IsValid() );
  1239. TSharedRef<FThumbnailInfo> ThumbnailRef = ThumbnailInfo.ToSharedRef();
  1240. // Map the object to its thumbnail info
  1241. ThumbnailToTextureMap.Add( ThumbId, ThumbnailRef );
  1242. ThumbnailInfo->AssetData = AssetData;
  1243. ThumbnailInfo->Width = Width;
  1244. ThumbnailInfo->Height = Height;
  1245. // Mark this thumbnail as needing to be updated
  1246. ThumbnailInfo->LastUpdateTime = -1.f;
  1247. // Request that the thumbnail be rendered as soon as possible
  1248. ThumbnailsToRenderStack.Push( ThumbnailRef );
  1249. }
  1250. // This thumbnail was accessed, update its last time to the current time
  1251. // We'll use LastAccessTime to determine the order to recycle thumbnails if the pool is full
  1252. ThumbnailInfo->LastAccessTime = FPlatformTime::Seconds();
  1253. return ThumbnailInfo->ThumbnailTexture;
  1254. }
  1255. }
  1256. void FExtAssetThumbnailPool::AddReferencer( const FExtAssetThumbnail& AssetThumbnail )
  1257. {
  1258. FIntPoint Size = AssetThumbnail.GetSize();
  1259. if ( AssetThumbnail.GetAssetData().ObjectPath == NAME_None || Size.X == 0 || Size.Y == 0 )
  1260. {
  1261. // Invalid referencer
  1262. return;
  1263. }
  1264. // Generate a key and look up the number of references in the RefCountMap
  1265. FThumbId ThumbId( AssetThumbnail.GetAssetData().ObjectPath, Size.X, Size.Y ) ;
  1266. int32* RefCountPtr = RefCountMap.Find(ThumbId);
  1267. if ( RefCountPtr )
  1268. {
  1269. // Already in the map, increment a reference
  1270. (*RefCountPtr)++;
  1271. }
  1272. else
  1273. {
  1274. // New referencer, add it to the map with a RefCount of 1
  1275. RefCountMap.Add(ThumbId, 1);
  1276. }
  1277. }
  1278. void FExtAssetThumbnailPool::RemoveReferencer( const FExtAssetThumbnail& AssetThumbnail )
  1279. {
  1280. FIntPoint Size = AssetThumbnail.GetSize();
  1281. const FName ObjectPath = AssetThumbnail.GetAssetData().ObjectPath;
  1282. if ( ObjectPath == NAME_None || Size.X == 0 || Size.Y == 0 )
  1283. {
  1284. // Invalid referencer
  1285. return;
  1286. }
  1287. // Generate a key and look up the number of references in the RefCountMap
  1288. FThumbId ThumbId( ObjectPath, Size.X, Size.Y ) ;
  1289. int32* RefCountPtr = RefCountMap.Find(ThumbId);
  1290. // This should complement an AddReferencer so this entry should be in the map
  1291. if ( RefCountPtr )
  1292. {
  1293. // Decrement the RefCount
  1294. (*RefCountPtr)--;
  1295. // If we reached zero, free the thumbnail and remove it from the map.
  1296. if ( (*RefCountPtr) <= 0 )
  1297. {
  1298. RefCountMap.Remove(ThumbId);
  1299. FreeThumbnail(ObjectPath, Size.X, Size.Y);
  1300. }
  1301. }
  1302. else
  1303. {
  1304. // This FExtAssetThumbnail did not reference anything or was deleted after the pool was deleted.
  1305. }
  1306. }
  1307. bool FExtAssetThumbnailPool::IsInRenderStack( const TSharedPtr<FExtAssetThumbnail>& Thumbnail ) const
  1308. {
  1309. const FExtAssetData& AssetData = Thumbnail->GetAssetData();
  1310. const uint32 Width = Thumbnail->GetSize().X;
  1311. const uint32 Height = Thumbnail->GetSize().Y;
  1312. if ( ensure(AssetData.ObjectPath != NAME_None) && ensure(Width > 0) && ensure(Height > 0) )
  1313. {
  1314. FThumbId ThumbId( AssetData.ObjectPath, Width, Height ) ;
  1315. const TSharedRef<FThumbnailInfo>* ThumbnailInfoPtr = ThumbnailToTextureMap.Find( ThumbId );
  1316. if ( ThumbnailInfoPtr )
  1317. {
  1318. return ThumbnailsToRenderStack.Contains(*ThumbnailInfoPtr);
  1319. }
  1320. }
  1321. return false;
  1322. }
  1323. bool FExtAssetThumbnailPool::IsRendered(const TSharedPtr<FExtAssetThumbnail>& Thumbnail) const
  1324. {
  1325. const FExtAssetData& AssetData = Thumbnail->GetAssetData();
  1326. const uint32 Width = Thumbnail->GetSize().X;
  1327. const uint32 Height = Thumbnail->GetSize().Y;
  1328. if (ensure(AssetData.ObjectPath != NAME_None) && ensure(Width > 0) && ensure(Height > 0))
  1329. {
  1330. FThumbId ThumbId(AssetData.ObjectPath, Width, Height);
  1331. const TSharedRef<FThumbnailInfo>* ThumbnailInfoPtr = ThumbnailToTextureMap.Find(ThumbId);
  1332. if (ThumbnailInfoPtr)
  1333. {
  1334. return (*ThumbnailInfoPtr).Get().LastUpdateTime >= 0.f;
  1335. }
  1336. }
  1337. return false;
  1338. }
  1339. void FExtAssetThumbnailPool::PrioritizeThumbnails( const TArray< TSharedPtr<FExtAssetThumbnail> >& ThumbnailsToPrioritize, uint32 Width, uint32 Height )
  1340. {
  1341. if ( ensure(Width > 0) && ensure(Height > 0) )
  1342. {
  1343. TSet<FName> ObjectPathList;
  1344. for ( int32 ThumbIdx = 0; ThumbIdx < ThumbnailsToPrioritize.Num(); ++ThumbIdx )
  1345. {
  1346. ObjectPathList.Add(ThumbnailsToPrioritize[ThumbIdx]->GetAssetData().ObjectPath);
  1347. }
  1348. TArray< TSharedRef<FThumbnailInfo> > FoundThumbnails;
  1349. for ( int32 ThumbIdx = ThumbnailsToRenderStack.Num() - 1; ThumbIdx >= 0; --ThumbIdx )
  1350. {
  1351. const TSharedRef<FThumbnailInfo>& ThumbnailInfo = ThumbnailsToRenderStack[ThumbIdx];
  1352. if ( ThumbnailInfo->Width == Width && ThumbnailInfo->Height == Height && ObjectPathList.Contains(ThumbnailInfo->AssetData.ObjectPath) )
  1353. {
  1354. FoundThumbnails.Add(ThumbnailInfo);
  1355. ThumbnailsToRenderStack.RemoveAt(ThumbIdx);
  1356. }
  1357. }
  1358. for ( int32 ThumbIdx = 0; ThumbIdx < FoundThumbnails.Num(); ++ThumbIdx )
  1359. {
  1360. ThumbnailsToRenderStack.Push(FoundThumbnails[ThumbIdx]);
  1361. }
  1362. }
  1363. }
  1364. void FExtAssetThumbnailPool::RefreshThumbnail( const TSharedPtr<FExtAssetThumbnail>& ThumbnailToRefresh )
  1365. {
  1366. const FExtAssetData& AssetData = ThumbnailToRefresh->GetAssetData();
  1367. const uint32 Width = ThumbnailToRefresh->GetSize().X;
  1368. const uint32 Height = ThumbnailToRefresh->GetSize().Y;
  1369. if ( ensure(AssetData.ObjectPath != NAME_None) && ensure(Width > 0) && ensure(Height > 0) )
  1370. {
  1371. FThumbId ThumbId( AssetData.ObjectPath, Width, Height ) ;
  1372. const TSharedRef<FThumbnailInfo>* ThumbnailInfoPtr = ThumbnailToTextureMap.Find( ThumbId );
  1373. if ( ThumbnailInfoPtr )
  1374. {
  1375. ThumbnailsToRenderStack.AddUnique(*ThumbnailInfoPtr);
  1376. }
  1377. }
  1378. }
  1379. void FExtAssetThumbnailPool::FreeThumbnail( const FName& ObjectPath, uint32 Width, uint32 Height )
  1380. {
  1381. if(ObjectPath != NAME_None && Width != 0 && Height != 0)
  1382. {
  1383. FThumbId ThumbId( ObjectPath, Width, Height ) ;
  1384. const TSharedRef<FThumbnailInfo>* ThumbnailInfoPtr = ThumbnailToTextureMap.Find(ThumbId);
  1385. if( ThumbnailInfoPtr )
  1386. {
  1387. TSharedRef<FThumbnailInfo> ThumbnailInfo = *ThumbnailInfoPtr;
  1388. ThumbnailToTextureMap.Remove(ThumbId);
  1389. ThumbnailsToRenderStack.Remove(ThumbnailInfo);
  1390. RealTimeThumbnails.Remove(ThumbnailInfo);
  1391. RealTimeThumbnailsToRender.Remove(ThumbnailInfo);
  1392. FSlateTexture2DRHIRef* ThumbnailTexture = ThumbnailInfo->ThumbnailTexture;
  1393. ENQUEUE_RENDER_COMMAND(ReleaseThumbnailTextureData)(
  1394. [ThumbnailTexture](FRHICommandListImmediate& RHICmdList)
  1395. {
  1396. ThumbnailTexture->ClearTextureData();
  1397. });
  1398. FreeThumbnails.Add( ThumbnailInfo );
  1399. }
  1400. }
  1401. }
  1402. void FExtAssetThumbnailPool::RefreshThumbnailsFor( FName ObjectPath )
  1403. {
  1404. for ( auto ThumbIt = ThumbnailToTextureMap.CreateIterator(); ThumbIt; ++ThumbIt)
  1405. {
  1406. if ( ThumbIt.Key().ObjectPath == ObjectPath )
  1407. {
  1408. ThumbnailsToRenderStack.Push( ThumbIt.Value() );
  1409. }
  1410. }
  1411. }
  1412. void FExtAssetThumbnailPool::OnAssetLoaded( UObject* Asset )
  1413. {
  1414. if ( Asset != NULL )
  1415. {
  1416. RecentlyLoadedAssets.Add( FName(*Asset->GetPathName()) );
  1417. }
  1418. }
  1419. void FExtAssetThumbnailPool::OnActorPostEditMove( AActor* Actor )
  1420. {
  1421. DirtyThumbnailForObject(Actor);
  1422. }
  1423. void FExtAssetThumbnailPool::OnObjectPropertyChanged( UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent )
  1424. {
  1425. DirtyThumbnailForObject(ObjectBeingModified);
  1426. }
  1427. void FExtAssetThumbnailPool::DirtyThumbnailForObject(UObject* ObjectBeingModified)
  1428. {
  1429. if (!ObjectBeingModified)
  1430. {
  1431. return;
  1432. }
  1433. if (ObjectBeingModified->HasAnyFlags(RF_ClassDefaultObject))
  1434. {
  1435. if (ObjectBeingModified->GetClass()->ClassGeneratedBy != NULL)
  1436. {
  1437. // This is a blueprint modification. Check to see if this thumbnail is the blueprint of the modified CDO
  1438. ObjectBeingModified = ObjectBeingModified->GetClass()->ClassGeneratedBy;
  1439. }
  1440. }
  1441. else if (AActor* ActorBeingModified = Cast<AActor>(ObjectBeingModified))
  1442. {
  1443. // This is a non CDO actor getting modified. Update the actor's world's thumbnail.
  1444. ObjectBeingModified = ActorBeingModified->GetWorld();
  1445. }
  1446. if (ObjectBeingModified && ObjectBeingModified->IsAsset())
  1447. {
  1448. // An object in memory was modified. We'll mark it's thumbnail as dirty so that it'll be
  1449. // regenerated on demand later. (Before being displayed in the browser, or package saves, etc.)
  1450. FObjectThumbnail* Thumbnail = ThumbnailTools::GetThumbnailForObject(ObjectBeingModified);
  1451. // Don't try loading thumbnails for package that have never been saved
  1452. if (Thumbnail == NULL && !IsGarbageCollecting() && !ObjectBeingModified->GetOutermost()->HasAnyPackageFlags(PKG_NewlyCreated))
  1453. {
  1454. // If we don't yet have a thumbnail map, load one from disk if possible
  1455. // Don't attempt to do this while garbage collecting since loading or finding objects during GC is illegal
  1456. FName ObjectFullName = FName(*ObjectBeingModified->GetFullName());
  1457. TArray<FName> ObjectFullNames;
  1458. FThumbnailMap LoadedThumbnails;
  1459. ObjectFullNames.Add(ObjectFullName);
  1460. if (ThumbnailTools::ConditionallyLoadThumbnailsForObjects(ObjectFullNames, LoadedThumbnails))
  1461. {
  1462. Thumbnail = LoadedThumbnails.Find(ObjectFullName);
  1463. if (Thumbnail != NULL)
  1464. {
  1465. Thumbnail = ThumbnailTools::CacheThumbnail(ObjectBeingModified->GetFullName(), Thumbnail, ObjectBeingModified->GetOutermost());
  1466. }
  1467. }
  1468. }
  1469. if (Thumbnail != NULL)
  1470. {
  1471. // Mark the thumbnail as dirty
  1472. Thumbnail->MarkAsDirty();
  1473. }
  1474. RefreshThumbnailsFor( FName(*ObjectBeingModified->GetPathName()) );
  1475. }
  1476. }
  1477. /////////////////////////////////////////////////////////////////////
  1478. const FObjectThumbnail* FExtObjectThumbnailPool::FindCachedThumbnail(const FString& InFullName)
  1479. {
  1480. FObjectThumbnail* FoundThumbnail = Pool.Find(InFullName);
  1481. if (FoundThumbnail)
  1482. {
  1483. ECB_LOG(Display, TEXT("Found ThumbPool: %s"), *InFullName);
  1484. }
  1485. return FoundThumbnail;
  1486. }
  1487. FObjectThumbnail& FExtObjectThumbnailPool::AddToPool(const FString& InFullName)
  1488. {
  1489. if (Pool.Num() > NumInPool)
  1490. {
  1491. FString FirstKey;
  1492. for (auto ThumbIt = Pool.CreateConstIterator(); ThumbIt; ++ThumbIt)
  1493. {
  1494. FirstKey = ThumbIt->Key;
  1495. break;
  1496. }
  1497. Pool.Remove(FirstKey);
  1498. }
  1499. // Todo: Free if Pool is Full
  1500. ECB_LOG(Warning, TEXT("Addto ThumbPool: %s"), *InFullName);
  1501. return Pool.FindOrAdd(InFullName);
  1502. }
  1503. void FExtObjectThumbnailPool::Reserve(int32 InSize)
  1504. {
  1505. NumInPool = InSize;
  1506. Pool.Reserve(InSize);
  1507. }
  1508. void FExtObjectThumbnailPool::Resize(int32 InSize)
  1509. {
  1510. NumInPool = InSize;
  1511. if (NumInPool <= 0)
  1512. {
  1513. Free();
  1514. return;
  1515. }
  1516. if (NumInPool < Pool.Num())
  1517. {
  1518. int32 NumToRemove = Pool.Num() - NumInPool;
  1519. int32 Index = 0;
  1520. for (auto ThumbIt = Pool.CreateIterator(); ThumbIt; ++ThumbIt)
  1521. {
  1522. if (Index >= NumToRemove)
  1523. break;
  1524. ThumbIt.RemoveCurrent();
  1525. ++Index;
  1526. }
  1527. }
  1528. else
  1529. {
  1530. Pool.Reserve(NumInPool);
  1531. }
  1532. }
  1533. void FExtObjectThumbnailPool::Free()
  1534. {
  1535. Pool.Empty();
  1536. }
  1537. uint32 FExtObjectThumbnailPool::GetAllocatedSize() const
  1538. {
  1539. uint32 MapMemory = Pool.GetAllocatedSize();
  1540. uint32 MapArrayMemory = 0;
  1541. auto SubArray =
  1542. [&MapArrayMemory](const auto& A)
  1543. {
  1544. for (auto& Pair : A)
  1545. {
  1546. MapArrayMemory += Pair.Value.GetCompressedDataSize();
  1547. }
  1548. };
  1549. SubArray(Pool);
  1550. return MapMemory + MapArrayMemory;
  1551. }