Advertisement
Guest User

Untitled

a guest
Nov 14th, 2018
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.82 KB | None | 0 0
  1. // Module loading is not allowed outside of the main thread, so we load the ImageWrapper module ahead of time. static IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(TEXT("ImageWrapper"));
  2.  
  3. UImageLoader* UImageLoader::LoadImageFromDiskAsync(UObject* Outer, const FString& ImagePath) { // This simply creates a new ImageLoader object and starts an asynchronous load. UImageLoader* Loader = NewObject<UImageLoader>(); Loader->LoadImageAsync(Outer, ImagePath); return Loader; }
  4.  
  5. void UImageLoader::LoadImageAsync(UObject* Outer, const FString& ImagePath) { // The asynchronous loading operation is represented by a Future, which will contain the result value once the operation is done. // We store the Future in this object, so we can retrieve the result value in the completion callback below. Future = LoadImageFromDiskAsync(Outer, ImagePath, [this]() { // This is the same Future object that we assigned above, but later in time. // At this point, loading is done and the Future contains a value. if (Future.IsValid()) { // Notify listeners about the loaded texture on the game thread. AsyncTask(ENamedThreads::GameThread, [this]() { LoadCompleted.Broadcast(Future.Get()); }); } }); }
  6.  
  7. TFuture<UTexture2D*> UImageLoader::LoadImageFromDiskAsync(UObject* Outer, const FString& ImagePath, TFunction<void()> CompletionCallback) { // Run the image loading function asynchronously through a lambda expression, capturing the ImagePath string by value. // Run it on the thread pool, so we can load multiple images simultaneously without interrupting other tasks. return Async<UTexture2D*>(EAsyncExecution::ThreadPool, [=]() { return LoadImageFromDisk(Outer, ImagePath); }, CompletionCallback); }
  8.  
  9. UTexture2D* UImageLoader::LoadImageFromDisk(UObject* Outer, const FString& ImagePath) { // Check if the file exists first if (!FPaths::FileExists(ImagePath)) { UIL_LOG(Error, TEXT("File not found: %s"), *ImagePath); return nullptr; }
  10.  
  11. // Load the compressed byte data from the file TArray<uint8> FileData; if (!FFileHelper::LoadFileToArray(FileData, *ImagePath)) { UIL_LOG(Error, TEXT("Failed to load file: %s"), *ImagePath); return nullptr; }
  12.  
  13. // Detect the image type using the ImageWrapper module EImageFormat::Type ImageFormat = ImageWrapperModule.DetectImageFormat(FileData.GetData(), FileData.Num()); if (ImageFormat == EImageFormat::Invalid) { UIL_LOG(Error, TEXT("Unrecognized image file format: %s"), *ImagePath); return nullptr; }
  14.  
  15. // Create an image wrapper for the detected image format IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(ImageFormat); if (!ImageWrapper.IsValid()) { UIL_LOG(Error, TEXT("Failed to create image wrapper for file: %s"), *ImagePath); return nullptr; }
  16.  
  17. // Decompress the image data const TArray<uint8>* RawData = nullptr; ImageWrapper->SetCompressed(FileData.GetData(), FileData.Num()); ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, RawData); if (RawData == nullptr) { UIL_LOG(Error, TEXT("Failed to decompress image file: %s"), *ImagePath); return nullptr; }
  18.  
  19. // Create the texture and upload the uncompressed image data FString TextureBaseName = TEXT("Texture_") + FPaths::GetBaseFilename(ImagePath); return CreateTexture(Outer, *RawData, ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), EPixelFormat::PF_B8G8R8A8, FName(*TextureBaseName)); }
  20.  
  21. UTexture2D* UImageLoader::CreateTexture(UObject* Outer, const TArray<uint8>& PixelData, int32 InSizeX, int32 InSizeY, EPixelFormat InFormat, FName BaseName) { // Shamelessly copied from UTexture2D::CreateTransient with a few modifications if (InSizeX <= 0 || InSizeY <= 0 || (InSizeX % GPixelFormats[InFormat].BlockSizeX) != 0 || (InSizeY % GPixelFormats[InFormat].BlockSizeY) != 0) { UIL_LOG(Warning, TEXT("Invalid parameters specified for UImageLoader::CreateTexture()")); return nullptr; }
  22.  
  23. // Most important difference with UTexture2D::CreateTransient: we provide the new texture with a name and an owner FName TextureName = MakeUniqueObjectName(Outer, UTexture2D::StaticClass(), BaseName); UTexture2D* NewTexture = NewObject<UTexture2D>(Outer, TextureName, RF_Transient);
  24.  
  25. NewTexture->PlatformData = new FTexturePlatformData(); NewTexture->PlatformData->SizeX = InSizeX; NewTexture->PlatformData->SizeY = InSizeY; NewTexture->PlatformData->PixelFormat = InFormat;
  26.  
  27. // Allocate first mipmap and upload the pixel data int32 NumBlocksX = InSizeX / GPixelFormats[InFormat].BlockSizeX; int32 NumBlocksY = InSizeY / GPixelFormats[InFormat].BlockSizeY; FTexture2DMipMap* Mip = new(NewTexture->PlatformData->Mips) FTexture2DMipMap(); Mip->SizeX = InSizeX; Mip->SizeY = InSizeY; Mip->BulkData.Lock(LOCK_READ_WRITE); void* TextureData = Mip->BulkData.Realloc(NumBlocksX * NumBlocksY * GPixelFormats[InFormat].BlockBytes); FMemory::Memcpy(TextureData, PixelData.GetData(), PixelData.Num()); Mip->BulkData.Unlock();
  28.  
  29. NewTexture->UpdateResource(); return NewTexture; }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement