CoD4 Material

CoD4 Material File Format

Each file has a header, an array of MapInfoBlocks, and strings for the image file names.
Some also have StringInfoBlocks, function unknown.

typedef struct tagMapInfoBlock
    DWORD    dwMapTypeOffset;
    // The start of a string for the type of image map.
    BYTE         Unk0[4];                     
// Unk[1] looks like a type enumeration where "colorMap" = 2.
    DWORD    dwMapNameOffset; 
// The start of a string for the image file name.

typedef struct tagStringInfoBlock
    DWORD dwMapTypeOffset;
// The start of an info string.
    float Unk1[4];                           // Four floats, function unknown.

Note1: All offsets are from the beginning of the file.
Note2: All strings are C style, zero terminated.

typedef struct tagHeader
    DWORD    dwMaterialNameOffset;            
// Not very useful since it always seems to be same as material filename.
    DWORD    dwColorMapFilenameOffset;     // A shortcut to the most important map, the mesh's skin.
    BYTE         Unk2[0x28];                           
    WORD       nNumMapInfoBlocks;               
// See above.
    WORD       nNumMapInfoStrings;               
// Not sure of their function.
    DWORD    dwMaterialTypeOffset;
    DWORD    dwMapInfoBlockOffset;            
// Always 0x44; Offset to the first MapInfoBlock
    DWORD    dwStringInfoBlockOffset;           // Offset to the first StringInfoBlock;

CString CXmodelCoD4::MaterialToMap(CString &sMaterialFileName, CString sMapType)
    // Valid MapTypes are:
     //     "colorMap",
     //     "detailMap",'
     //     "normalMap",
     //     "specularMap"
     // These are the names in the material file.
    // Returns the requested filename or "" if not found.

    CString    sRet("");
    CFile       file;
    char        buffer[255];

    if(file.Open(sMaterialFileName, CFile::modeRead))
        MaterialHeader    header;
        file.Read(&header, sizeof(MaterialHeader));
        MapInfoBlock* pBlocks = new MapInfoBlock[header.wNumMapInfoBlocks];
        // Move to first MapInfoBlock and read them all in.
        file.Seek(header.dwInfoBlockOffset, CFile::begin);
        file.Read(pBlocks, sizeof(MapInfoBlock)):
        // If interested in them, the file pointer is now pointing to the InfoStringBlocks
        for(WORD i = 0; i < header.wNumMapInfoBlocks; i++)
            file.Seek(pBlocks[i].dwMapTypeOffset,  CFile::begin);
            file.Read(buffer, 255);    // Just grab a bunch;
            CString sTemp(buffer);
            if(sTemp == sMapType)
                file.Seek(pBlocks[i].dwMapNameOffset, CFile::begin);
                file.Read(buffer, 255);
                sRet = buffer;
                sRet += ".iwi";

        delete[] pBlocks;

    return sRet;

Note 3: This code was typed from memory.  If it compiles, I wrote it. If not, then Anonymous wrote it.

CoD2 Material File Format