// Extract the sprites based on SpriteExtractSettings->Mode void SPaperExtractSpritesDialog::PreviewExtractedSprites() { FScopedSlowTask SlowTask(2, NSLOCTEXT("Paper2D", "Paper2D_ExtractingSprites", "Extracting Sprites")); SlowTask.MakeDialog(false); SlowTask.EnterProgressFrame(); const FString DefaultSuffix = TEXT("Sprite"); if (ExtractSpriteSettings->Mode == ESpriteExtractMode::Auto) { ExtractedSprites.Empty(); // First extract the rects from the texture TArray<FIntRect> ExtractedRects; UPaperSprite::ExtractRectsFromTexture(SourceTexture, /*out*/ ExtractedRects); // Sort the rectangles by approximate row struct FRectangleSortHelper { FRectangleSortHelper(TArray<FIntRect>& InOutSprites) { // Sort by Y, then by X (top left corner), descending order (so we can use it as a stack from the top row down) TArray<FIntRect> SpritesLeft = InOutSprites; SpritesLeft.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.Y == B.Min.Y) ? (A.Min.X > B.Min.X) : (A.Min.Y > B.Min.Y); }); InOutSprites.Reset(); // Start pulling sprites out, the first one in each row will dominate remaining ones and cause them to get labeled TArray<FIntRect> DominatedSprites; DominatedSprites.Empty(SpritesLeft.Num()); while (SpritesLeft.Num()) { FIntRect DominatingSprite = SpritesLeft.Pop(); DominatedSprites.Add(DominatingSprite); // Find the sprites that are dominated (intersect the infinite horizontal band described by the dominating sprite) for (int32 Index = 0; Index < SpritesLeft.Num();) { const FIntRect& CurElement = SpritesLeft[Index]; if ((CurElement.Min.Y <= DominatingSprite.Max.Y) && (CurElement.Max.Y >= DominatingSprite.Min.Y)) { DominatedSprites.Add(CurElement); SpritesLeft.RemoveAt(Index, /*Count=*/ 1, /*bAllowShrinking=*/ false); } else { ++Index; } } // Sort the sprites in the band by X and add them to the result DominatedSprites.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.X < B.Min.X); }); InOutSprites.Append(DominatedSprites); DominatedSprites.Reset(); } } }; FRectangleSortHelper RectSorter(ExtractedRects); int32 ExtractedRectIndex = 0; for (FIntRect Rect : ExtractedRects) { FPaperExtractedSprite* Sprite = new(ExtractedSprites)FPaperExtractedSprite(); Sprite->Rect = Rect; Sprite->Name = FString::Printf(TEXT("%s_%d"), *DefaultSuffix, ExtractedRectIndex); ExtractedRectIndex++; } } else { // Calculate rects ExtractedSprites.Empty(); if (SourceTexture != nullptr) { int32 ExtractedRectIndex = 0; int32 TextureWidth = SourceTexture->GetSizeX(); int32 TextureHeight = SourceTexture->GetSizeY(); for (int32 Y = ExtractSpriteSettings->Margin; Y + ExtractSpriteSettings->GridHeight <= TextureHeight; Y += ExtractSpriteSettings->GridHeight + ExtractSpriteSettings->Spacing) { for (int32 X = ExtractSpriteSettings->Margin; X + ExtractSpriteSettings->GridWidth <= TextureWidth; X += ExtractSpriteSettings->GridWidth + ExtractSpriteSettings->Spacing) { FPaperExtractedSprite* Sprite = new(ExtractedSprites)FPaperExtractedSprite(); Sprite->Rect = FIntRect(X, Y, X + ExtractSpriteSettings->GridWidth, Y + ExtractSpriteSettings->GridHeight); Sprite->Name = FString::Printf(TEXT("%s_%d"), *DefaultSuffix, ExtractedRectIndex); ExtractedRectIndex++; } } } } }
void CreateSpritesFromTextures(TArray<UTexture2D*>& Textures) { const FString DefaultSuffix = TEXT("_Sprite"); FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools"); FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser"); TArray<UObject*> ObjectsToSync; for (auto TextureIt = Textures.CreateConstIterator(); TextureIt; ++TextureIt) { UTexture2D* Texture = *TextureIt; // Create the factory used to generate the sprite UPaperSpriteFactory* SpriteFactory = ConstructObject<UPaperSpriteFactory>(UPaperSpriteFactory::StaticClass()); SpriteFactory->InitialTexture = Texture; // Create the sprite FString Name; FString PackageName; if (!bExtractSprites) { // Get a unique name for the sprite AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), DefaultSuffix, /*out*/ PackageName, /*out*/ Name); const FString PackagePath = FPackageName::GetLongPackagePath(PackageName); if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory)) { ObjectsToSync.Add(NewAsset); } } else { FScopedSlowTask Feedback(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture")); Feedback.MakeDialog(true); // First extract the rects from the texture TArray<FIntRect> ExtractedRects; UPaperSprite::ExtractRectsFromTexture(Texture, /*out*/ ExtractedRects); // Sort the rectangles by approximate row struct FRectangleSortHelper { FRectangleSortHelper(TArray<FIntRect>& InOutSprites) { // Sort by Y, then by X (top left corner), descending order (so we can use it as a stack from the top row down) TArray<FIntRect> SpritesLeft = InOutSprites; SpritesLeft.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.Y == B.Min.Y) ? (A.Min.X > B.Min.X) : (A.Min.Y > B.Min.Y); }); InOutSprites.Reset(); // Start pulling sprites out, the first one in each row will dominate remaining ones and cause them to get labeled TArray<FIntRect> DominatedSprites; DominatedSprites.Empty(SpritesLeft.Num()); while (SpritesLeft.Num()) { FIntRect DominatingSprite = SpritesLeft.Pop(); DominatedSprites.Add(DominatingSprite); // Find the sprites that are dominated (intersect the infinite horizontal band described by the dominating sprite) for (int32 Index = 0; Index < SpritesLeft.Num();) { const FIntRect& CurElement = SpritesLeft[Index]; if ((CurElement.Min.Y <= DominatingSprite.Max.Y) && (CurElement.Max.Y >= DominatingSprite.Min.Y)) { DominatedSprites.Add(CurElement); SpritesLeft.RemoveAt(Index, /*Count=*/ 1, /*bAllowShrinking=*/ false); } else { ++Index; } } // Sort the sprites in the band by X and add them to the result DominatedSprites.Sort([](const FIntRect& A, const FIntRect& B) { return (A.Min.X < B.Min.X); }); InOutSprites.Append(DominatedSprites); DominatedSprites.Reset(); } } }; FRectangleSortHelper RectSorter(ExtractedRects); Feedback.TotalAmountOfWork = ExtractedRects.Num(); for (int ExtractedRectIndex = 0; ExtractedRectIndex < ExtractedRects.Num(); ++ExtractedRectIndex) { Feedback.EnterProgressFrame(1, NSLOCTEXT("Paper2D", "Paper2D_ExtractSpritesFromTexture", "Extracting Sprites From Texture")); FIntRect& ExtractedRect = ExtractedRects[ExtractedRectIndex]; SpriteFactory->bUseSourceRegion = true; SpriteFactory->InitialSourceUV = FVector2D(ExtractedRect.Min.X, ExtractedRect.Min.Y); SpriteFactory->InitialSourceDimension = FVector2D(ExtractedRect.Width(), ExtractedRect.Height()); // Get a unique name for the sprite const FString Suffix = FString::Printf(TEXT("%s_%d"), *DefaultSuffix, ExtractedRectIndex); AssetToolsModule.Get().CreateUniqueAssetName(Texture->GetOutermost()->GetName(), Suffix, /*out*/ PackageName, /*out*/ Name); const FString PackagePath = FPackageName::GetLongPackagePath(PackageName); if (UObject* NewAsset = AssetToolsModule.Get().CreateAsset(Name, PackagePath, UPaperSprite::StaticClass(), SpriteFactory)) { ObjectsToSync.Add(NewAsset); } if (GWarn->ReceivedUserCancel()) { break; } } } } if (ObjectsToSync.Num() > 0) { ContentBrowserModule.Get().SyncBrowserToAssets(ObjectsToSync); } }