// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "CoreMinimal.h" #if PLATFORM_WINDOWS #include /** * This class is a collection of distant and compressed takes on * OpenExr's ScanLineInputFile and ReadPixel functionality. */ class FExrReader { public: struct FTileDesc { FIntPoint TileResolution; uint32 BufferOffset; // Optimization: align to 128 bit. int32 AlignPadding; }; /** * This is based on Open Exr implementation. * We need to handle all of these in the future. At the moment only INCREASING_Y is * supported. */ enum ELineOrder { INCREASING_Y, DECREASING_Y, RANDOM_Y // Tiled files. }; private: static const int32 STRING_SIZE = 256; static const int32 MAX_LENGTH = STRING_SIZE - 1; public: /*At the beginning of each row of B G R channel planes there is 2x4 byte data that has information*/ static const int32 PLANAR_RGB_SCANLINE_PADDING = 8; /*At the beginning of each tile there is 20 byte data that has information*/ static const int32 TILE_PADDING = 20; public: FExrReader() : FileHandle(nullptr) , FileLength(0) , LineOrTileOffsetsPerLevel() {}; private: static EXRREADERGPU_API bool ReadMagicNumberAndVersionField(FILE* FileHandle); /** * This is just so we can get line offsets. Based on OpenExr implementation with some caveats. * The header in general is discarded, but without reading it - it is impossible to get to the actual pixel data reliably. * Returns false if it has failed reading the file in any way. */ static EXRREADERGPU_API bool ReadHeaderData(FILE* FileHandle); /** Reads Scan line offsets so that we can jump to a position in file. */ static EXRREADERGPU_API bool ReadLineOrTileOffsets(FILE* FileHandle, ELineOrder LineOrder, TArray& LineOrTileOffsets); public: /** Discards the header and fills the buffer with plain pixel data. */ static EXRREADERGPU_API bool GenerateTextureData(uint16* Buffer, int32 BufferSize, FString FilePath, int32 NumberOfScanlines, int32 NumChannels); /** * To be able to read tiles, especially in cases where tiles vary in sizes, we need to calculate offsets manually * for custom exr files, since we don't write out offsets. */ static EXRREADERGPU_API void CalculateTileOffsets ( TArray& OutNumTilesPerLevel , TArray>& OutPartialTileInfo , const FIntPoint& FullTextureResolution , const FIntPoint& TileDimWithBorders , int32 NumMipLevels , int64 PixelSize); /** * This function is used to open file and keep a handle to it so the file can be read in chunks. * Reading in chunks allows the process of reading to be canceled midway through reading. * This function reads and discards the header and keeps the pointers to the scanlines or tiles. */ EXRREADERGPU_API bool OpenExrAndPrepareForPixelReading(FString FilePath, const TArray& NumOffsetsPerLevel); /** * Read a chunk of an Exr file previously open via OpenExrAndPrepareForPixelReading. * The read starts from the last point of file reading. */ EXRREADERGPU_API bool ReadExrImageChunk(void* Buffer, int64 ChunkSize); /** * Moves to the specified tile position in the file in preparation for reading. */ EXRREADERGPU_API bool SeekTileWithinFile(const int32 StartTileIndex, const int32 Level, int64& OutBufferOffset); /** * Gets byte location of the requested tile for the requested mip level. */ EXRREADERGPU_API bool GetByteOffsetForTile(const int32 TileIndex, const int32 Level, int64& OutBufferOffset); /** * After we have finished reading the file that was open via OpenExrAndPrepareForPixelReading * We need to close it to avoid memory leaks */ EXRREADERGPU_API bool CloseExrFile(); private: /** * One approach to reading is to first open a file, read in chunks and then close the file. * It is all done in 3 sepate functions and requires to keep track of Filehandle */ FILE* FileHandle; /** * The length of the file in question. Used to get the last tile. */ int64 FileLength; /** * These are byte offsets pointing to scanlines or tiles from the begining of the file. */ TArray> LineOrTileOffsetsPerLevel; }; #endif