public void ReadNTP3(FileData d) { d.seek(0x4); Version = d.readUShort(); ushort count = d.readUShort(); if (Version == 0x100) { count -= 1; } d.skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.seek(headerPtr); NutTexture tex = new NutTexture(); tex.isDds = true; tex.pixelInternalFormat = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); int dataSize = d.readInt(); int headerSize = d.readUShort(); d.skip(2); //It might seem that mipmapCount and pixelFormat would be shorts, but they're bytes because they stay in the same place regardless of endianness d.skip(1); byte mipmapCount = d.readByte(); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readUShort(); tex.Height = d.readUShort(); d.skip(4); uint caps2 = d.readUInt(); bool isCubemap = false; byte surfaceCount = 1; if ((caps2 & (uint)DDS.DDSCAPS2.CUBEMAP) == (uint)DDS.DDSCAPS2.CUBEMAP) { //Only supporting all six faces if ((caps2 & (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES) == (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES) { isCubemap = true; surfaceCount = 6; } else { throw new NotImplementedException($"Unsupported cubemap face amount for texture {i} with hash 0x{tex.HashId:X}. Six faces are required."); } } int dataOffset = d.readInt() + headerPtr; d.readInt(); d.readInt(); d.readInt(); //The size of a single cubemap face (discounting mipmaps). I don't know why it is repeated. If mipmaps are present, this is also specified in the mipSize section anyway. int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.readInt(); cmapSize2 = d.readInt(); d.skip(8); } int[] mipSizes = new int[mipmapCount]; if (mipmapCount == 1) { if (isCubemap) { mipSizes[0] = cmapSize1; } else { mipSizes[0] = dataSize; } } else { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { mipSizes[mipLevel] = d.readInt(); } d.align(0x10); } d.skip(0x10); //eXt data - always the same d.skip(4); //GIDX d.readInt(); //Always 0x10 tex.HashId = d.readInt(); d.skip(4); // padding align 8 if (Version == 0x100) { dataOffset = d.pos(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { TextureSurface surface = new TextureSurface(); for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { byte[] texArray = d.getSection(dataOffset, mipSizes[mipLevel]); surface.mipmaps.Add(texArray); dataOffset += mipSizes[mipLevel]; } tex.surfaces.Add(surface); } if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { tex.SwapChannelOrderUp(); } headerPtr += headerSize; Nodes.Add(tex); } }
public void ReadNTP3(FileData d) { Version = d.readShort(); int count = d.readShort(); d.skip(0x8); if (Version == 0x100) { count -= 1; } int dataPtr = 0; for (int i = 0; i < count; i++) { //Debug.WriteLine(d.pos().ToString("x")); NutTexture tex = new NutTexture(); tex.type = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); // padding int dataSize = d.readInt(); int headerSize = d.readShort(); d.skip(3); int numMips = d.readByte(); //Debug.WriteLine(numMips); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readShort(); tex.Height = d.readShort(); d.skip(8); // padding? int dataOffset = d.readInt() + dataPtr + 0x10; d.skip(0x0C); int[] mipSizes = new int[numMips]; if (numMips == 1) { mipSizes[0] = dataSize; } else { for (int j = 0; j < numMips; j++) { mipSizes[j] = d.readInt(); } } d.align(16); d.skip(0x18); tex.HASHID = d.readInt(); d.skip(4); // padding align 8 if (Version == 0x100) { dataOffset = d.pos(); } // add mipmap data for (int miplevel = 0; miplevel < numMips; miplevel++) { byte[] texArray = d.getSection(dataOffset, mipSizes[miplevel]); //Debug.WriteLine(texArray.Length.ToString("x")); tex.mipmaps.Add(texArray); dataOffset += mipSizes[miplevel]; } dataPtr += headerSize; if (tex.getNutFormat() == 14 || tex.getNutFormat() == 17) { Console.WriteLine("Endian swap"); // swap foreach (byte[] mip in tex.mipmaps) { for (int t = 0; t < mip.Length; t += 4) { byte t1 = mip[t]; mip[t] = mip[t + 1]; mip[t + 1] = mip[t + 2]; mip[t + 2] = mip[t + 3]; mip[t + 3] = t1; /*byte t1 = mip[t]; * byte t2 = mip[t+1]; * mip[t] = mip[t + 3]; * mip[t + 1] = mip[t + 2]; * mip[t + 2] = t2; * mip[t + 3] = t1;*/ } } } Nodes.Add(tex); /*for (int miplevel = 0; miplevel < numMips; miplevel++) * { * byte[] texArray = d.getSection(dataOffset, mipSizes[miplevel]); * * if (tex.getNutFormat() == 14) * { * byte[] oldArray = texArray; * for (int pos = 0; pos < mipSizes[miplevel]; pos+=4) * { * * for (int p = 0; p < 4; p++) * { * if (p == 0) * texArray[pos + 3] = oldArray[pos]; * else * texArray[pos + p - 1] = oldArray[pos + p]; * } * * } * } * tex.mipmaps.Add(texArray); * dataOffset += mipSizes[miplevel]; * }*/ } foreach (NutTexture tex in Nodes) { if (!draw.ContainsKey(tex.HASHID)) { draw.Add(tex.HASHID, loadImage(tex, true)); } } }