From 05303313be427df1f4c48d11b721f47574ddcc6a Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 2 Apr 2021 18:15:33 +0200 Subject: [PATCH] Load iwis of version 6 (cod4) --- src/Common/Image/IwiTypes.h | 48 ++++++++++++++ src/ObjLoading/Image/IwiLoader.cpp | 103 +++++++++++++++++++++++++++++ src/ObjLoading/Image/IwiLoader.h | 3 + 3 files changed, 154 insertions(+) diff --git a/src/Common/Image/IwiTypes.h b/src/Common/Image/IwiTypes.h index 6e854b13..10a38894 100644 --- a/src/Common/Image/IwiTypes.h +++ b/src/Common/Image/IwiTypes.h @@ -8,6 +8,54 @@ struct IwiVersion char version; }; +// IW3 +namespace iwi6 +{ + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + uint32_t fileSizeForPicmip[4]; + }; + + 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_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_LEGACY_NORMALS = 1 << 5, + IMG_FLAG_CLAMP_U = 1 << 6, + IMG_FLAG_CLAMP_V = 1 << 7, + IMG_FLAG_DYNAMIC = 1 << 16, + IMG_FLAG_RENDER_TARGET = 1 << 17, + IMG_FLAG_SYSTEMMEM = 1 << 18 + }; +} + // IW4 namespace iwi8 { diff --git a/src/ObjLoading/Image/IwiLoader.cpp b/src/ObjLoading/Image/IwiLoader.cpp index 38a9d8e0..051447fd 100644 --- a/src/ObjLoading/Image/IwiLoader.cpp +++ b/src/ObjLoading/Image/IwiLoader.cpp @@ -10,6 +10,106 @@ IwiLoader::IwiLoader(MemoryManager* memoryManager) m_memory_manager = memoryManager; } +const ImageFormat* IwiLoader::GetFormat6(int8_t format) +{ + switch (static_cast(format)) + { + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8_G8_B8_A8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGB: + return &ImageFormat::FORMAT_R8_G8_B8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi6::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi6::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi6::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi6::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + return &ImageFormat::FORMAT_R8_A8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + return &ImageFormat::FORMAT_R8; + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + printf("Unsupported IWI format: %i\n", format); + break; + default: + printf("Unknown IWI format: %i\n", format); + break; + } + + return nullptr; +} + +Texture* IwiLoader::LoadIwi6(std::istream& stream) const +{ + iwi6::IwiHeader header{}; + + stream.read(reinterpret_cast(&header), sizeof(header)); + if (stream.gcount() != sizeof(header)) + return nullptr; + + const auto* format = GetFormat6(header.format); + if (format == nullptr) + return nullptr; + + auto width = header.dimensions[0]; + auto height = header.dimensions[1]; + auto depth = header.dimensions[2]; + auto hasMipMaps = !(header.flags & iwi6::IwiFlags::IMG_FLAG_NOMIPMAPS); + + Texture* texture; + if (header.flags & iwi6::IwiFlags::IMG_FLAG_CUBEMAP) + { + texture = m_memory_manager->Create(format, width, height, hasMipMaps); + } + else if (header.flags & iwi6::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(); + + auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersion); + const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(std::extent::value) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); + + m_memory_manager->Delete(texture); + return nullptr; + } + + stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); + if (stream.gcount() != sizeOfMipLevel) + { + printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); + + m_memory_manager->Delete(texture); + return nullptr; + } + } + + return texture; +} + const ImageFormat* IwiLoader::GetFormat8(int8_t format) { switch (static_cast(format)) @@ -252,6 +352,9 @@ Texture* IwiLoader::LoadIwi(std::istream& stream) switch (iwiVersion.version) { + case 6: + return LoadIwi6(stream); + case 8: return LoadIwi8(stream); diff --git a/src/ObjLoading/Image/IwiLoader.h b/src/ObjLoading/Image/IwiLoader.h index 18940009..8063617d 100644 --- a/src/ObjLoading/Image/IwiLoader.h +++ b/src/ObjLoading/Image/IwiLoader.h @@ -8,6 +8,9 @@ class IwiLoader { MemoryManager* m_memory_manager; + static const ImageFormat* GetFormat6(int8_t format); + Texture* LoadIwi6(std::istream& stream) const; + static const ImageFormat* GetFormat8(int8_t format); Texture* LoadIwi8(std::istream& stream) const;