diff --git a/src/ObjCommon/Image/ImageFormat.cpp b/src/ObjCommon/Image/ImageFormat.cpp index 37f742f2..ecc81859 100644 --- a/src/ObjCommon/Image/ImageFormat.cpp +++ b/src/ObjCommon/Image/ImageFormat.cpp @@ -76,6 +76,11 @@ size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, co } const ImageFormatUnsigned ImageFormat::FORMAT_R8G8B8(24, 0, 8, 8, 8, 16, 8, 0, 0, DXGI_FORMAT_UNKNOWN); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(4, 8, DXGI_FORMAT_BC1_UNORM); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(4, 16, DXGI_FORMAT_BC2_UNORM); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(4, 16, DXGI_FORMAT_BC3_UNORM); +const ImageFormatUnsigned ImageFormat::FORMAT_R8G8B8A8(32, 0, 8, 8, 8, 16, 8, 24, 8, DXGI_FORMAT_R8G8B8A8_UNORM); +const ImageFormatUnsigned ImageFormat::FORMAT_A8(8, 0, 0, 0, 0, 0, 0, 0, 8, DXGI_FORMAT_A8_UNORM); +const ImageFormatUnsigned ImageFormat::FORMAT_R16G16B16A16_FLOAT(128, 0, 0, 0, 0, 0, 0, 0, 8, DXGI_FORMAT_R16G16B16A16_FLOAT); +const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(4, 64, DXGI_FORMAT_BC1_UNORM); +const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(4, 128, DXGI_FORMAT_BC2_UNORM); +const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(4, 128, DXGI_FORMAT_BC3_UNORM); +const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(4, 64, DXGI_FORMAT_BC4_UNORM); +const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(4, 128, DXGI_FORMAT_BC5_UNORM); diff --git a/src/ObjCommon/Image/ImageFormat.h b/src/ObjCommon/Image/ImageFormat.h index a955a9ad..43727293 100644 --- a/src/ObjCommon/Image/ImageFormat.h +++ b/src/ObjCommon/Image/ImageFormat.h @@ -53,7 +53,12 @@ public: ImageFormat() = delete; static const ImageFormatUnsigned FORMAT_R8G8B8; + static const ImageFormatUnsigned FORMAT_R8G8B8A8; + static const ImageFormatUnsigned FORMAT_A8; + static const ImageFormatUnsigned FORMAT_R16G16B16A16_FLOAT; //TODO: Float not unsigned static const ImageFormatBlockCompressed FORMAT_BC1; static const ImageFormatBlockCompressed FORMAT_BC2; static const ImageFormatBlockCompressed FORMAT_BC3; + static const ImageFormatBlockCompressed FORMAT_BC4; + static const ImageFormatBlockCompressed FORMAT_BC5; }; diff --git a/src/ObjCommon/Image/IwiTypes.h b/src/ObjCommon/Image/IwiTypes.h new file mode 100644 index 00000000..133d774e --- /dev/null +++ b/src/ObjCommon/Image/IwiTypes.h @@ -0,0 +1,90 @@ +#pragma once + +#include + +struct IwiVersion +{ + char tag[3]; + char version; +}; + +// IW4 +namespace iwi8 +{ + struct IwiHeader + { + uint32_t flags; + int8_t format; + int8_t unused; + uint16_t dimensions[3]; + uint32_t fileSizeForPicmip[4]; + }; +} + +// T5 +namespace iwi13 +{ + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + uint32_t fileSizeForPicmip[8]; + }; +} + +// T6 +namespace iwi27 +{ + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + int8_t maxGlossForMip[16]; + uint32_t fileSizeForPicmip[8]; + }; + + enum class IwiFormat + { + IMG_FORMAT_INVALID = 0x0, + IMG_FORMAT_BITMAP_RGBA = 0x1, + IMG_FORMAT_BITMAP_RGB = 0x2, + IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, + IMG_FORMAT_BITMAP_LUMINANCE = 0x4, + IMG_FORMAT_BITMAP_ALPHA = 0x5, + IMG_FORMAT_WAVELET_RGBA = 0x6, + IMG_FORMAT_WAVELET_RGB = 0x7, + IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, + IMG_FORMAT_WAVELET_LUMINANCE = 0x9, + IMG_FORMAT_WAVELET_ALPHA = 0xA, + IMG_FORMAT_DXT1 = 0xB, + IMG_FORMAT_DXT3 = 0xC, + IMG_FORMAT_DXT5 = 0xD, + IMG_FORMAT_DXN = 0xE, + IMG_FORMAT_BITMAP_RGB565 = 0xF, + IMG_FORMAT_BITMAP_RGB5A3 = 0x10, + IMG_FORMAT_BITMAP_C8 = 0x11, + IMG_FORMAT_BITMAP_RGBA8 = 0x12, + IMG_FORMAT_A16B16G16R16F = 0x13, + IMG_FORMAT_COUNT, + }; + + enum IwiFlags + { + IMG_FLAG_NOPICMIP = 1 << 0, + IMG_FLAG_NOMIPMAPS = 1 << 1, + IMG_FLAG_CUBEMAP = 1 << 2, + IMG_FLAG_VOLMAP = 1 << 3, + IMG_FLAG_STREAMING = 1 << 4, + IMG_FLAG_CLAMP_U = 1 << 6, + IMG_FLAG_CLAMP_V = 1 << 7, + IMG_FLAG_FORCE_SYSTEM = 1 << 8, + IMG_FLAG_DYNAMIC = 1 << 16, + IMG_FLAG_RENDER_TARGET = 1 << 17, + IMG_FLAG_MULTISAMPLE = 1 << 18, + }; + +} diff --git a/src/ObjLoading/Image/IwiLoader.cpp b/src/ObjLoading/Image/IwiLoader.cpp index 400531bd..e162936d 100644 --- a/src/ObjLoading/Image/IwiLoader.cpp +++ b/src/ObjLoading/Image/IwiLoader.cpp @@ -1,24 +1,137 @@ #include "IwiLoader.h" +#include "Image/IwiTypes.h" +#include IwiLoader::IwiLoader(MemoryManager* memoryManager) { m_memory_manager = memoryManager; } -Texture* IwiLoader::LoadIwi(FileAPI::IFile* file) +const IImageFormat* IwiLoader::GetFormat27(int8_t format) { - struct + switch (static_cast(format)) { - char tag[3]; - char version; - } iwiHeaderMeta{}; - - if (file->Read(&iwiHeaderMeta, sizeof iwiHeaderMeta, 1) != 1) - return nullptr; - - printf("Read IWI with version %i\n", iwiHeaderMeta.version); - - // TODO: Read iwi based on version + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8G8B8A8; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi27::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi27::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi27::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi27::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi27::IwiFormat::IMG_FORMAT_A16B16G16R16F: + assert(false); // Unsupported yet + return &ImageFormat::FORMAT_R16G16B16A16_FLOAT; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGBA: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGB: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB565: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB5A3: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_C8: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA8: + printf("Unsupported IWI format: %i\n", format); + break; + default: + printf("Unknown IWI format: %i\n", format); + break; + } return nullptr; } + +Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file) +{ + iwi27::IwiHeader header{}; + + if (file->Read(&header, sizeof header, 1) != 1) + return nullptr; + + const IImageFormat* format = GetFormat27(header.format); + if (format == nullptr) + return nullptr; + + uint16_t width = header.dimensions[0]; + uint16_t height = header.dimensions[1]; + uint16_t depth = header.dimensions[2]; + bool hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS); + + Texture* texture; + if(header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP) + { + texture = m_memory_manager->Create(format, width, height, hasMipMaps); + } + else if(header.flags & iwi27::IwiFlags::IMG_FLAG_VOLMAP) + { + texture = m_memory_manager->Create(format, width, height, depth, hasMipMaps); + } + else + { + texture = m_memory_manager->Create(format, width, height, hasMipMaps); + } + + texture->Allocate(); + + size_t currentFileSize = sizeof iwi27::IwiHeader + sizeof IwiVersion; + const int mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (int currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const size_t sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(_countof(iwi27::IwiHeader::fileSizeForPicmip)) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); + + m_memory_manager->Delete(texture); + return nullptr; + } + + if (file->Read(texture->GetBufferForMipLevel(currentMipLevel), 1, sizeOfMipLevel) != sizeOfMipLevel) + { + printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); + + m_memory_manager->Delete(texture); + return nullptr; + } + } + + return texture; +} + +Texture* IwiLoader::LoadIwi(FileAPI::IFile* file) +{ + IwiVersion iwiVersion{}; + + if (file->Read(&iwiVersion, sizeof iwiVersion, 1) != 1) + return nullptr; + + if (iwiVersion.tag[0] != 'I' + || iwiVersion.tag[1] != 'W' + || iwiVersion.tag[2] != 'i') + { + printf("Invalid IWI magic\n"); + } + + switch (iwiVersion.version) + { + case 27: + return LoadIwi27(file); + + default: + break; + } + + printf("Unknown IWI version %i\n", iwiVersion.version); + return nullptr; +} diff --git a/src/ObjLoading/Image/IwiLoader.h b/src/ObjLoading/Image/IwiLoader.h index 97869e6c..76e3ed7b 100644 --- a/src/ObjLoading/Image/IwiLoader.h +++ b/src/ObjLoading/Image/IwiLoader.h @@ -8,6 +8,9 @@ class IwiLoader { MemoryManager* m_memory_manager; + const IImageFormat* GetFormat27(int8_t format); + Texture* LoadIwi27(FileAPI::IFile* file); + public: explicit IwiLoader(MemoryManager* memoryManager);