#include "iwifile.h" IWIFile::IWIFile() : fileStem(), header(), info(), mipmaps() { } IWIFile::IWIFile(const QString &aFilePath) : fileStem(aFilePath.split('.').first().split('/').last()) { QFile file(aFilePath); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Error: Unable to open IWI file" << aFilePath; return; } QDataStream in(&file); in.setByteOrder(QDataStream::LittleEndian); // Read header in.readRawData(reinterpret_cast(&header), sizeof(IWIHeader)); if (!header.isSupported()) { qDebug() << "Error: Unsupported IWI version!"; return; } // Adjust seek position for MW2/MW3 if (header.Version == 0x08) { file.seek(0x08); } // Read info in.readRawData(reinterpret_cast(&info), sizeof(IWIInfo)); // Determine offset array size QVector offsets((header.Version == 0x1B) ? 8 : 4); if (header.Version == 0x0D || header.Version == 0x1B) { file.seek(header.Version == 0x1B ? 0x20 : 0x10); } // Read offsets for (qint32 &offset : offsets) { in >> offset; } // Compute mipmaps qint64 currentPos = file.pos(); qint64 fileSize = file.size(); QVector positions = QVector(); for (int i = 0; i < offsets.size(); i++) { IWIMipmap m; if (i == 0) { m.offset = offsets[i]; m.size = fileSize - offsets[i]; } else if (i == offsets.size() - 1) { m.offset = currentPos; m.size = offsets[i] - currentPos; } else { m.offset = offsets[i]; m.size = offsets[i - 1] - offsets[i]; } quint64 pos = file.pos(); // Read mipmap file.seek(m.offset); m.data = file.read(m.size); file.seek(pos); mipmaps.append(m); } // Close file file.close(); } // IWIFile::IWIFile(const DDSFile &aDDSFile) { // // Ensure the DDS file has mipmaps // if (aDDSFile.mipmaps.isEmpty()) { // qDebug() << "Error: No mipmaps found in DDS file!"; // return; // } // // Create IWIFile object // fileStem = aDDSFile.fileStem; // // Set header (Magic & Version) // memcpy(header.Magic, "IWi", 3); // header.Version = 0x06; // Default to CoD4/CoD5 version // // Set IWI Texture Info // info.Format = static_cast(aDDSFile.header.pixelFormat.format); // info.Width = aDDSFile.header.width; // info.Height = aDDSFile.header.height; // info.Depth = 1; // Default depth for 2D textures // info.Usage = 0; // No specific usage // // Convert DDS mipmaps to IWI mipmaps // int offset = 28; // Standard offset start // for (const auto& ddsMipmap : aDDSFile.mipmaps) { // IWIMipmap iwiMipmap; // iwiMipmap.offset = offset; // iwiMipmap.size = ddsMipmap.data.size(); // iwiMipmap.data = ddsMipmap.data; // offset += iwiMipmap.size; // mipmaps.append(iwiMipmap); // } // } IWIFile::IWIFile(const IWIFile &iwiFile) { fileStem = iwiFile.fileStem; header = iwiFile.header; info = iwiFile.info; mipmaps = iwiFile.mipmaps; } IWIFile &IWIFile::operator=(const IWIFile &other) { if (this != &other) { fileStem = other.fileStem; header = other.header; info = other.info; mipmaps = other.mipmaps; } return *this; } IWIFile::~IWIFile() { } void IWIFile::SetupExportDirs() const { QDir dir = QDir::currentPath(); if (!dir.exists("exports/")) { dir.mkdir("exports/"); } if (!dir.exists("exports/iwi/")) { dir.mkdir("exports/iwi/"); } if (!dir.exists("exports/dds/")) { dir.mkdir("exports/dds/"); } if (!dir.exists("exports/png/")) { dir.mkdir("exports/png/"); } if (!dir.exists("exports/jpg/")) { dir.mkdir("exports/jpg/"); } } bool IWIFile::SaveIWI() const { SetupExportDirs(); QFile file("exports/iwi/" + fileStem + ".iwi"); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "Error: Unable to write IWI file " << fileStem + ".iwi"; return false; } QDataStream out(&file); out.setByteOrder(QDataStream::LittleEndian); // Write IWI Header out.writeRawData(reinterpret_cast(&header), sizeof(IWIHeader)); // Adjust seek position for MW2/MW3 if (header.Version == 0x08) { file.seek(0x08); } // Write IWI Texture Info out.writeRawData(reinterpret_cast(&info), sizeof(IWIInfo)); // Determine number of mipmaps based on version QVector offsets((header.Version == 0x1B) ? 8 : 4); size_t currentOffset = file.pos() + (offsets.size() * sizeof(qint32)); // Compute offsets for (int i = 0; i < offsets.size(); i++) { offsets[i] = static_cast(currentOffset); if (mipmaps.size() && i < mipmaps.size()) { currentOffset += mipmaps[i].size; } } // Seek and write offsets if (header.Version == 0x0D || header.Version == 0x1B) { file.seek(header.Version == 0x1B ? 0x20 : 0x10); } for (const qint32 &offset : offsets) { out << offset; } for (auto mipmap : mipmaps) { file.seek(mipmap.offset); file.write(mipmap.data); } file.close(); qDebug() << "Successfully wrote IWI file: " << fileStem + ".iwi"; return true; } // bool IWIFile::SaveDDS() const { // SetupExportDirs(); // QFile file("exports/dds/" + fileStem + ".dds"); // if (!file.open(QIODevice::WriteOnly)) { // qDebug() << "Error: Unable to write DDS file " << fileStem + ".dds"; // return false; // } // DDSHeader ddsHeader = {}; // ddsHeader.magic = 0x20534444; // 'DDS ' // ddsHeader.size = 124; // ddsHeader.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; // ddsHeader.height = info.Height; // ddsHeader.width = info.Width; // ddsHeader.depth = 0; // ddsHeader.mipMapCount = mipmaps.size(); // DDSPixelFormat ddsPixelFormat = DDSFile::CalculatePixelFormat(info.Format); // if (ddsPixelFormat.flags & DDPF_FOURCC) { // ddsHeader.flags |= DDSD_LINEARSIZE; // } else { // ddsHeader.flags |= DDSD_PITCH; // } // ddsHeader.pixelFormat = ddsPixelFormat; // // Calculate pitch/linear size // if (ddsPixelFormat.flags & DDPF_FOURCC) { // int blockSize = (ddsPixelFormat.format == 0x31545844) ? 8 : 16; // ddsHeader.pitchOrLinearSize = fmax(1, (ddsHeader.width + 3) / 4) * blockSize * (ddsHeader.height / 4); // } else { // ddsHeader.pitchOrLinearSize = ddsHeader.width * (ddsPixelFormat.rgbBitCount / 8); // } // DDSCaps ddsCaps = {}; // ddsCaps.caps1 = DDSCAPS_TEXTURE; // ddsCaps.caps2 = 0; // ddsCaps.dDSX = 0; // ddsCaps.reserved = 0; // ddsHeader.caps = ddsCaps; // QDataStream out(&file); // out.setByteOrder(QDataStream::LittleEndian); // // Write DDS header // out.writeRawData(reinterpret_cast(&ddsHeader), sizeof(DDSHeader)); // for (auto mipmap : mipmaps) { // if (!mipmap.data.size()) { continue; } // // Write mipmap data // out.writeRawData(reinterpret_cast(mipmap.data.constData()), mipmap.data.size()); // } // file.close(); // return true; // } bool IWIFile::SavePNG() const { // DDSFile ddsFile(*this); // if (!ddsFile.SavePNG()) { // qDebug() << "Error: Failed to save PNG file: " << fileStem + ".png"; // return false; // } // return true; return false; } bool IWIFile::SaveJPG() const { // DDSFile ddsFile(*this); // if (!ddsFile.SavePNG()) { // qDebug() << "Error: Failed to save JPG file: " << fileStem + ".jpg"; // return false; // } // return true; return false; } // Check if the IWI version is supported bool IWIHeader::isSupported() const { return (Magic[0] == 'I' && Magic[1] == 'W' && Magic[2] == 'i') && supportedVersions.contains(Version); }