public void ReadFTEX(Texture tex) { ImageKey = "texture"; SelectedImageKey = "texture"; reserve = tex.Data; texture.width = (int)tex.Width; texture.height = (int)tex.Height; format = (int)tex.Format; int swizzle = (int)tex.Swizzle; int pitch = (int)tex.Pitch; texture.data = GTX.swizzleBC(tex.Data, texture.width, texture.height, format, (int)tex.TileMode, pitch, swizzle); Text = tex.Name; //Setup variables for treenode data width = texture.width; height = texture.height; texture.mipMapCount = (int)tex.MipCount; FileData f = new FileData(tex.MipData); for (int level = 0; level < tex.MipCount; level++) { if (level != 0) { } // byte[] mip = f.getSection((int)tex.MipOffsets[level - 1], (int)tex.MipOffsets[level + 1]); // texture.mipMapData.Add(mip); } switch (format) { case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB): texture.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_UNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_SRGB): texture.pixelInternalFormat = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB): texture.pixelInternalFormat = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedSignedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM): texture.pixelInternalFormat = PixelInternalFormat.CompressedRgRgtc2; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM): //OpenTK doesn't load BC5 SNORM textures right so I'll use the same decompress method bntx has byte[] fixBC5 = DDS_Decompress.DecompressBC5(texture.data, texture.width, texture.height, true); texture.data = fixBC5; texture.pixelInternalFormat = PixelInternalFormat.Rgba; texture.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM): texture.pixelInternalFormat = PixelInternalFormat.Rgba; texture.pixelFormat = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; } }
public void ReadFTEX(Texture tex) { ImageKey = "texture"; SelectedImageKey = "texture"; reserve = tex.Data; texture.width = (int)tex.Width; texture.height = (int)tex.Height; format = (int)tex.Format; int swizzle = (int)tex.Swizzle; int pitch = (int)tex.Pitch; texture.data = GTX.swizzleBC(tex.Data, texture.width, texture.height, format, (int)tex.TileMode, pitch, swizzle); Text = tex.Name; //Setup variables for treenode data width = texture.width; height = texture.height; switch (format) { case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_UNORM): texture.type = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC1_SRGB): texture.type = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt1Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_UNORM): texture.type = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC2_SRGB): texture.type = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt3Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_UNORM): texture.type = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC3_SRGB): texture.type = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_UNORM): texture.type = PixelInternalFormat.CompressedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC4_SNORM): texture.type = PixelInternalFormat.CompressedSignedRedRgtc1; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_UNORM): texture.type = PixelInternalFormat.CompressedRgRgtc2; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_T_BC5_SNORM): //OpenTK doesn't load BC5 SNORM textures right so I'll use the same decompress method bntx has byte[] fixBC5 = DDS_Decompress.DecompressBC5(texture.data, texture.width, texture.height, true); texture.data = fixBC5; texture.type = PixelInternalFormat.Rgba; texture.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; case ((int)GTX.GX2SurfaceFormat.GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM): texture.type = PixelInternalFormat.Rgba; texture.utype = OpenTK.Graphics.OpenGL.PixelFormat.Rgba; break; } texture.display = loadImage(texture); display = texture.display; }
public void ReadNTWU(FileData d) { d.skip(0x02); int count = d.readShort(); d.skip(0x10); int headerPtr = d.pos(); int dataPtr = 0; int gtxHeaderOffset = 0; for (int i = 0; i < count; i++) { NUD_Texture tex = new NUD_Texture(); tex.type = PixelInternalFormat.Rgba32ui; d.seek(headerPtr); int totalSize = d.readInt(); int headerSize = d.readShort(); int numMips = d.readInt(); tex.setPixelFormatFromNutFormat(d.readShort()); tex.width = d.readShort(); tex.height = d.readShort(); d.skip(8); // mipmaps and padding int dataOffset = d.readInt() + dataPtr + 0x10; headerPtr += headerSize; dataPtr += headerSize; d.skip(0x04); if (i == 0) { gtxHeaderOffset = d.readInt() + 0x10; } else { gtxHeaderOffset += 0x80; d.skip(0x04); } d.skip(0x04); d.skip(headerSize - 0x50); d.skip(0x18); tex.id = d.readInt(); d.seek(gtxHeaderOffset); d.skip(0x04); // dim d.skip(0x04); // width d.skip(0x04); // height d.skip(0x04); // depth d.skip(0x04); // numMips int format = d.readInt(); d.skip(0x04); // aa d.skip(0x04); // use int imageSize = d.readInt(); d.skip(0x04); // imagePtr d.skip(0x04); // mipSize d.skip(0x04); // mipPtr int tileMode = d.readInt(); int swizzle = d.readInt(); d.skip(0x04); // alignment int pitch = d.readInt(); for (int mipLevel = 0; mipLevel < numMips; mipLevel++) { // Maybe this is the problem? int mipSize = imageSize >> (mipLevel * 2); //if (mipLevel == 0) { tex.mipmaps.Add(GTX.swizzleBC( d.getSection(dataOffset, mipSize), (tex.width >> mipLevel), (tex.height >> mipLevel), format, tileMode, pitch, swizzle )); } dataOffset += mipSize; } textures.Add(tex); } foreach (var tex in textures) { if (!draw.ContainsKey(tex.id)) { draw.Add(tex.id, loadImage(tex)); } } }
public void ReadNTWU(FileData d) { d.skip(0x02); int count = d.readShort(); d.skip(0x10); int headerPtr = d.pos(); int dataPtr = 0; int gtxHeaderOffset = 0; for (int i = 0; i < count; i++) { NUD_Texture tex = new NUD_Texture(); tex.type = PixelInternalFormat.Rgba32ui; d.seek(headerPtr); int totalSize = d.readInt(); int headerSize = d.readShort(); int numMips = d.readInt(); tex.setPixelFormatFromNutFormat(d.readShort()); tex.width = d.readShort(); tex.height = d.readShort(); d.skip(8); // mipmaps and padding int dataOffset = d.readInt() + dataPtr + 0x10; headerPtr += headerSize; dataPtr += headerSize; d.skip(0x04); if (i == 0) { gtxHeaderOffset = d.readInt() + 0x10; } else { gtxHeaderOffset += 0x80; d.skip(0x04); } d.skip(0x04); // check for cubemap bool cmap = (d.readInt() == d.readInt()); d.seek(d.pos() - 8); if (cmap) { Console.WriteLine("cubemap detected"); } d.skip(headerSize - 0x50); d.skip(0x18); tex.id = d.readInt(); d.seek(gtxHeaderOffset); d.skip(0x04); // dim d.skip(0x04); // width d.skip(0x04); // height d.skip(0x04); // depth d.skip(0x04); // numMips int format = d.readInt(); d.skip(0x04); // aa d.skip(0x04); // use int imageSize = d.readInt(); d.skip(0x04); // imagePtr d.skip(0x04); // mipSize d.skip(0x04); // mipPtr int tileMode = d.readInt(); int swizzle = d.readInt(); d.skip(0x04); // alignment int pitch = d.readInt(); for (int mipLevel = 0; mipLevel < numMips; mipLevel++) { // Maybe this is the problem? int mipSize = imageSize >> (mipLevel * 2); int p = pitch >> mipLevel; //Console.WriteLine(tex.id.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + swizzle); //Console.WriteLine((tex.width >> mipLevel) + " " + (tex.height >> mipLevel)); //if (cmap) tex.height *= 2; int w = (tex.width >> mipLevel); int h = (tex.height >> mipLevel); //if (mipSize % 0x10 != 0) mipSize += mipSize % 0x10; //if (cmap) mipSize /= 6; //if (p <= 16) p = 64; { tex.mipmaps.Add(GTX.swizzleBC( d.getSection(dataOffset, mipSize), w, h, format, tileMode, p, swizzle )); } dataOffset += mipSize; /*if (cmap) * { * for(int k = 0; k < 5; k++) * { * p = pitch >> (mipLevel + k + 1); * tex.mipmaps.Add(GTX.swizzleBC( * d.getSection(dataOffset, mipSize), * w, * h, * format, * tileMode, * p, * swizzle * )); * * dataOffset += mipSize; * } * }*/ //while (dataOffset % 1024 != 0) dataOffset++; //if (mipSize == 0x4000) dataOffset += 0x400; } // fix mipmap swizzle for rgba types 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]; * byte t2 = mip[t+1]; * mip[t] = mip[t + 3]; * mip[t + 1] = mip[t + 2]; * mip[t + 2] = t2; * mip[t + 3] = t1;*/ } } } textures.Add(tex); } foreach (var tex in textures) { if (!draw.ContainsKey(tex.id)) { draw.Add(tex.id, loadImage(tex)); } } }
public void ReadNTWU(FileData d) { d.seek(0x4); Version = d.readUShort(); ushort count = d.readUShort(); d.skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.seek(headerPtr); NutTexture tex = new NutTexture(); tex.pixelInternalFormat = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); int dataSize = d.readInt(); int headerSize = d.readUShort(); d.skip(2); d.skip(1); byte mipmapCount = d.readByte(); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readUShort(); tex.Height = d.readUShort(); d.readInt(); //Always 1? 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; int mipDataOffset = d.readInt() + headerPtr; int gtxHeaderOffset = d.readInt() + headerPtr; d.readInt(); int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.readInt(); cmapSize2 = d.readInt(); d.skip(8); } int imageSize = 0; //Total size of first mipmap of every surface int mipSize = 0; //Total size of mipmaps other than the first of every surface if (mipmapCount == 1) { if (isCubemap) { imageSize = cmapSize1; } else { imageSize = dataSize; } } else { imageSize = d.readInt(); mipSize = d.readInt(); d.skip((mipmapCount - 2) * 4); 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 d.seek(gtxHeaderOffset); GTX.GX2Surface gtxHeader = new GTX.GX2Surface(); gtxHeader.dim = d.readInt(); gtxHeader.width = d.readInt(); gtxHeader.height = d.readInt(); gtxHeader.depth = d.readInt(); gtxHeader.numMips = d.readInt(); gtxHeader.format = d.readInt(); gtxHeader.aa = d.readInt(); gtxHeader.use = d.readInt(); gtxHeader.imageSize = d.readInt(); gtxHeader.imagePtr = d.readInt(); gtxHeader.mipSize = d.readInt(); gtxHeader.mipPtr = d.readInt(); gtxHeader.tileMode = d.readInt(); gtxHeader.swizzle = d.readInt(); gtxHeader.alignment = d.readInt(); gtxHeader.pitch = d.readInt(); //mipOffsets[0] is not in this list and is simply the start of the data (dataOffset) //mipOffsets[1] is relative to the start of the data (dataOffset + mipOffsets[1]) //Other mipOffsets are relative to mipOffset[1] (dataOffset + mipOffsets[1] + mipOffsets[i]) int[] mipOffsets = new int[mipmapCount]; mipOffsets[0] = 0; for (byte mipLevel = 1; mipLevel < mipmapCount; ++mipLevel) { mipOffsets[mipLevel] = 0; mipOffsets[mipLevel] = mipOffsets[1] + d.readInt(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { tex.surfaces.Add(new TextureSurface()); } int w = tex.Width, h = tex.Height; for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { int p = gtxHeader.pitch / (gtxHeader.width / w); int size; if (mipmapCount == 1) { size = imageSize; } else if (mipLevel + 1 == mipmapCount) { size = (mipSize + mipOffsets[1]) - mipOffsets[mipLevel]; } else { size = mipOffsets[mipLevel + 1] - mipOffsets[mipLevel]; } size /= surfaceCount; for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { gtxHeader.data = d.getSection(dataOffset + mipOffsets[mipLevel] + (size * surfaceLevel), size); //Real size //Leave the below line commented for now because it breaks RGBA textures //size = ((w + 3) >> 2) * ((h + 3) >> 2) * (GTX.getBPP(gtxHeader.format) / 8); if (size < (GTX.getBPP(gtxHeader.format) / 8)) { size = (GTX.getBPP(gtxHeader.format) / 8); } byte[] deswiz = GTX.swizzleBC( gtxHeader.data, w, h, gtxHeader.format, gtxHeader.tileMode, p, gtxHeader.swizzle ); tex.surfaces[surfaceLevel].mipmaps.Add(new FileData(deswiz).getSection(0, size)); } w /= 2; h /= 2; if (w < 1) { w = 1; } if (h < 1) { h = 1; } } headerPtr += headerSize; Nodes.Add(tex); } }
public void ReadNTWU(FileData d) { d.skip(0x02); int count = d.readShort(); d.skip(0x10); int headerPtr = d.pos(); int dataPtr = 0; int gtxHeaderOffset = 0; for (int i = 0; i < count; i++) { NutTexture tex = new NutTexture(); tex.type = PixelInternalFormat.Rgba32ui; d.seek(headerPtr); int totalSize = d.readInt(); int headerSize = d.readShort(); int numMips = d.readInt(); tex.setPixelFormatFromNutFormat(d.readShort()); tex.Width = d.readShort(); tex.Height = d.readShort(); d.skip(8); // mipmaps and padding int dataOffset = d.readInt() + dataPtr + 0x10; headerPtr += headerSize; dataPtr += headerSize; d.skip(0x04); if (i == 0) { gtxHeaderOffset = d.readInt() + 0x10; } else { gtxHeaderOffset += 0x80; d.skip(0x04); } d.skip(0x04); // check for cubemap bool cmap = (d.readInt() == d.readInt()); d.seek(d.pos() - 8); if (cmap) { Console.WriteLine("cubemap detected"); } d.skip(headerSize - 0x50); d.skip(0x18); tex.HASHID = d.readInt(); Console.WriteLine(gtxHeaderOffset.ToString("x")); d.seek(gtxHeaderOffset); d.skip(0x04); // dim d.skip(0x04); // width d.skip(0x04); // height d.skip(0x04); // depth d.skip(0x04); // numMips int format = d.readInt(); d.skip(0x04); // aa d.skip(0x04); // use int imageSize = d.readInt(); d.skip(0x04); // imagePtr int maxSize = d.readInt(); // mipSize d.skip(0x04); // mipPtr int tileMode = d.readInt(); int swizzle = d.readInt(); d.skip(0x04); // alignment int pitch = d.readInt(); int ds = dataOffset; int s1 = 0; int size = 0; Console.WriteLine(totalSize.ToString("x")); for (int mipLevel = 0; mipLevel < numMips; mipLevel++) { // Maybe this is the problem? int mipSize = imageSize >> (mipLevel * 2); int p = pitch >> mipLevel; size = d.readInt(); //Console.WriteLine("\tMIP: " + size.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + (size == 0 ? ds + totalSize - dataOffset : size)); //Console.WriteLine(tex.id.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + swizzle); //Console.WriteLine((tex.width >> mipLevel) + " " + (tex.height >> mipLevel)); //if (cmap) tex.height *= 2; int w = (tex.Width >> mipLevel); int h = (tex.Height >> mipLevel); { byte[] deswiz = GTX.swizzleBC( d.getSection(dataOffset, d.size() - dataOffset), w, h, format, tileMode, p, swizzle ); tex.mipmaps.Add(new FileData(deswiz).getSection(0, mipSize)); } if (mipLevel == 0) { s1 = size; dataOffset = ds + size; } else { dataOffset = ds + s1 + size; } //dataOffset += mipSize; /*if (cmap) * { * for(int k = 0; k < 5; k++) * { * p = pitch >> (mipLevel + k + 1); * tex.mipmaps.Add(GTX.swizzleBC( * d.getSection(dataOffset, mipSize), * w, * h, * format, * tileMode, * p, * swizzle * )); * * dataOffset += mipSize; * } * }*/ //while (dataOffset % 1024 != 0) dataOffset++; //if (mipSize == 0x4000) dataOffset += 0x400; } Nodes.Add(tex); } foreach (NutTexture tex in Nodes) { if (!draw.ContainsKey(tex.HASHID)) { draw.Add(tex.HASHID, loadImage(tex, false)); } // redo mipmaps /*GL.BindTexture(TextureTarget.Texture2D, draw[tex.id]); * for (int k = 1; k < tex.mipmaps.Count; k++) * { * tex.mipmaps[k] = new byte[tex.mipmaps[k].Length]; * GCHandle pinnedArray = GCHandle.Alloc(tex.mipmaps[k], GCHandleType.Pinned); * IntPtr pointer = pinnedArray.AddrOfPinnedObject(); * GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, pointer); * pinnedArray.Free(); * }*/ } //File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\mip1.bin", bytearray); //Console.WriteLine(GL.GetError()); /*int j = 0; * foreach(byte[] b in textures[0].mipmaps) * { * if (j == 3) * { * for(int w = 3; w < 8; w++) * { * for (int p = 3; p < 6; p++) * { * byte[] deswiz = GTX.swizzleBC( * b, * (int)Math.Pow(2, w), * 64, * 51, * 4, * (int)Math.Pow(2, p), * 197632 * ); * File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\chunk_" + (int)Math.Pow(2, p) + "_" + (int)Math.Pow(2, w), deswiz); * } * } * * } * j++; * }*/ }
public void ReadNTWU(FileData d) { d.seek(0x4); Version = d.readUShort(); ushort count = d.readUShort(); d.skip(0x8); int headerPtr = 0x10; for (ushort i = 0; i < count; ++i) { d.seek(headerPtr); NutTexture tex = new NutTexture(); tex.type = PixelInternalFormat.Rgba32ui; int totalSize = d.readInt(); d.skip(4); int dataSize = d.readInt(); int headerSize = d.readUShort(); d.skip(2); d.skip(1); byte mipMapCount = d.readByte(); d.skip(1); tex.setPixelFormatFromNutFormat(d.readByte()); tex.Width = d.readUShort(); tex.Height = d.readUShort(); d.readInt(); //Always 1? 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; int mipDataOffset = d.readInt() + headerPtr; int gtxHeaderOffset = d.readInt() + headerPtr; d.readInt(); int cmapSize1 = 0; int cmapSize2 = 0; if (isCubemap) { cmapSize1 = d.readInt(); cmapSize2 = d.readInt(); d.skip(8); } int imageSize = 0; //Total size of first mipmap of every surface int mipSize = 0; //Total size of mipmaps other than the first of every surface if (mipMapCount == 1) { if (isCubemap) { imageSize = cmapSize1; } else { imageSize = dataSize; } } else { imageSize = d.readInt(); mipSize = d.readInt(); d.skip((mipMapCount - 2) * 4); 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 d.seek(gtxHeaderOffset); GTX.GX2Surface gtxHeader = new GTX.GX2Surface(); gtxHeader.dim = d.readInt(); gtxHeader.width = d.readInt(); gtxHeader.height = d.readInt(); gtxHeader.depth = d.readInt(); gtxHeader.numMips = d.readInt(); gtxHeader.format = d.readInt(); gtxHeader.aa = d.readInt(); gtxHeader.use = d.readInt(); gtxHeader.imageSize = d.readInt(); gtxHeader.imagePtr = d.readInt(); gtxHeader.mipSize = d.readInt(); gtxHeader.mipPtr = d.readInt(); gtxHeader.tileMode = d.readInt(); gtxHeader.swizzle = d.readInt(); gtxHeader.alignment = d.readInt(); gtxHeader.pitch = d.readInt(); //mipOffsets[0] is not in this list and is simply the start of the data (dataOffset) //mipOffsets[1] is relative to the start of the data (dataOffset + mipOffsets[1]) //Other mipOffsets are relative to mipOffset[1] (dataOffset + mipOffsets[1] + mipOffsets[i]) int[] mipOffsets = new int[mipMapCount]; mipOffsets[0] = 0; for (byte mipLevel = 1; mipLevel < mipMapCount; ++mipLevel) { mipOffsets[mipLevel] = 0; mipOffsets[mipLevel] = mipOffsets[1] + d.readInt(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { tex.surfaces.Add(new TextureSurface()); } int w = tex.Width, h = tex.Height; for (byte mipLevel = 0; mipLevel < mipMapCount; ++mipLevel) { int p = gtxHeader.pitch / (gtxHeader.width / w); int size; if (mipMapCount == 1) { size = imageSize; } else if (mipLevel + 1 == mipMapCount) { size = (mipSize + mipOffsets[1]) - mipOffsets[mipLevel]; } else { size = mipOffsets[mipLevel + 1] - mipOffsets[mipLevel]; } size /= surfaceCount; for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { gtxHeader.data = d.getSection(dataOffset + mipOffsets[mipLevel] + (size * surfaceLevel), size); //Real size //Leave the below line commented for now because it breaks RGBA textures //size = ((w + 3) >> 2) * ((h + 3) >> 2) * (GTX.getBPP(gtxHeader.format) / 8); if (size < (GTX.getBPP(gtxHeader.format) / 8)) { size = (GTX.getBPP(gtxHeader.format) / 8); } byte[] deswiz = GTX.swizzleBC( gtxHeader.data, w, h, gtxHeader.format, gtxHeader.tileMode, p, gtxHeader.swizzle ); tex.surfaces[surfaceLevel].mipmaps.Add(new FileData(deswiz).getSection(0, size)); } w /= 2; h /= 2; if (w < 1) { w = 1; } if (h < 1) { h = 1; } } headerPtr += headerSize; Nodes.Add(tex); } RefreshGlTexturesByHashId(); //Console.WriteLine("\tMIP: " + size.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + (size == 0 ? ds + dataSize - dataOffset : size)); //Console.WriteLine(tex.id.ToString("x") + " " + dataOffset.ToString("x") + " " + mipSize.ToString("x") + " " + p + " " + swizzle); //Console.WriteLine((tex.width >> mipLevel) + " " + (tex.height >> mipLevel)); //File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\mip1.bin", bytearray); //Console.WriteLine(GL.GetError()); /*int j = 0; * foreach(byte[] b in textures[0].mipmaps) * { * if (j == 3) * { * for(int w = 3; w < 8; w++) * { * for (int p = 3; p < 6; p++) * { * byte[] deswiz = GTX.swizzleBC( * b, * (int)Math.Pow(2, w), * 64, * 51, * 4, * (int)Math.Pow(2, p), * 197632 * ); * File.WriteAllBytes("C:\\s\\Smash\\extract\\data\\fighter\\duckhunt\\model\\body\\chunk_" + (int)Math.Pow(2, p) + "_" + (int)Math.Pow(2, w), deswiz); * } * } * * } * j++; * }*/ }