// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Internationalization/Internationalization.h" #include "Internationalization/Text.h" #include "LandscapeImageFileCache.h" #include "LandscapeFileFormatInterface.h" #include "LandscapeDataAccess.h" template class LandscapeImageTraits { public: static T DefaultValue() { return 0; } }; template<> class LandscapeImageTraits { public: static uint16 DefaultValue() { return static_cast(LandscapeDataAccess::MidValue); } }; class FLandscapeTiledImage { public: FLandscapeTiledImage(); template FLandscapeFileInfo Load(const TCHAR* Filename); FIntPoint GetTileResolution() const { return TileResolution; } FIntPoint GetSizeInTiles() const { return SizeInTiles; } FIntPoint GetResolution() const { return FIntPoint(TileResolution.X * SizeInTiles.X, TileResolution.Y * SizeInTiles.Y); } static void FindFiles(const TCHAR* FilenamePattern, TArray& OutPaths); template void Read(TArray& OutImageData, bool bFlipYAxis = false) const { const FIntPoint Resolution = GetResolution(); ReadRegion(FIntRect(0, 0, Resolution.X, Resolution.Y), OutImageData, bFlipYAxis); } static bool CheckTiledNamePath(const FString& Filename, FString& OutTiledFilenamePattern); template FLandscapeFileInfo ReadRegion(const FIntRect& Region, TArray& OutImageData, bool bFlipYAxis = false, T DefaultValue = LandscapeImageTraits::DefaultValue()) const { OutImageData.Init(DefaultValue, Region.Height() * Region.Width()); int32 MinTileX = Region.Min.X / TileResolution.X; int32 MinTileY = Region.Min.Y / TileResolution.Y; int32 MaxTileX = Region.Max.X / TileResolution.X; int32 MaxTileY = Region.Max.Y / TileResolution.Y; for (int32 TileY = MinTileY; TileY <= MaxTileY; ++TileY) { for (int32 TileX = MinTileX; TileX <= MaxTileX; ++TileX) { const FIntPoint TileMin(TileX * TileResolution.X, TileY * TileResolution.Y); const FString* TileFilename = TileFilenames.Find(FIntPoint(TileX, TileY)); if (TileFilename) { FLandscapeImageDataRef ImageData; FLandscapeImageFileCache& LandscapeImageFileCache = FModuleManager::GetModuleChecked("LandscapeEditor").GetImageFileCache(); FLandscapeFileInfo TileResult = LandscapeImageFileCache.FindImage(**TileFilename, ImageData); if (TileResult.ResultCode == ELandscapeImportResult::Error) { return TileResult; } const uint8* TileData = ImageData.Data->GetData(); FIntRect TileRegion = Region; TileRegion -= TileMin; TileRegion.Clip(FIntRect(0, 0, TileResolution.X, TileResolution.Y)); for (int32 Y = 0; Y < TileRegion.Height(); ++Y) { for (int32 X = 0; X < TileRegion.Width(); ++X) { const FIntPoint TileCoord = FIntPoint(X, Y) + TileRegion.Min; const FIntPoint OutCoord = TileCoord + TileMin - Region.Min; const int32 SrcY = bFlipYAxis ? TileResolution.Y - TileCoord.Y - 1 : TileCoord.Y; T& Dest = OutImageData[OutCoord.Y * Region.Width() + OutCoord.X]; const uint8* Src = &TileData[ImageData.BytesPerPixel * (SrcY * TileResolution.X + TileCoord.X)]; if (sizeof(T) == ImageData.BytesPerPixel) { Dest = *(reinterpret_cast(Src)); } else if (ImageData.BytesPerPixel == 2 && sizeof(T) == 1) { Dest = *(reinterpret_cast(Src)) >> 8; } else { Dest = *Src; } } } } } } return FLandscapeFileInfo(); } private: static TMap Tokens; static FString GetTokenRegex(const FString& Prefix); TMap TileFilenames; FIntPoint TileResolution = FIntPoint::NoneValue; FIntPoint SizeInTiles = FIntPoint::NoneValue; };