|
|
#region License
|
|
|
/* FNA - XNA4 Reimplementation for Desktop Platforms
|
|
|
* Copyright 2009-2020 Ethan Lee and the MonoGame Team
|
|
|
*
|
|
|
* Released under the Microsoft Public License.
|
|
|
* See LICENSE for details.
|
|
|
*/
|
|
|
#endregion
|
|
|
|
|
|
#region Using Statements
|
|
|
using System.IO;
|
|
|
#endregion
|
|
|
|
|
|
namespace Microsoft.Xna.Framework.Graphics
|
|
|
{
|
|
|
internal static class X360TexUtil
|
|
|
{
|
|
|
#region Internal Static Methods
|
|
|
|
|
|
internal static byte[] SwapColor(byte[] imageData)
|
|
|
{
|
|
|
using (MemoryStream imageStream = new MemoryStream(imageData))
|
|
|
{
|
|
|
return SwapColor(imageStream, imageData.Length);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapColor(Stream imageStream, int imageLength)
|
|
|
{
|
|
|
byte[] imageData = new byte[imageLength];
|
|
|
|
|
|
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
|
|
{
|
|
|
for (int i = 0; i < imageLength; i += sizeof(uint))
|
|
|
{
|
|
|
uint data = imageReader.ReadUInt32();
|
|
|
imageData[i + 0] = (byte) ((data >> 24) & 0xFF);
|
|
|
imageData[i + 1] = (byte) ((data >> 16) & 0xFF);
|
|
|
imageData[i + 2] = (byte) ((data >> 8) & 0xFF);
|
|
|
imageData[i + 3] = (byte) ((data >> 0) & 0xFF);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return imageData;
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt1(byte[] imageData, int width, int height)
|
|
|
{
|
|
|
using (MemoryStream imageStream = new MemoryStream(imageData))
|
|
|
{
|
|
|
return SwapDxt1(imageStream, imageData.Length, width, height);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt1(Stream imageStream, int imageLength, int width, int height)
|
|
|
{
|
|
|
byte[] imageData = new byte[imageLength];
|
|
|
using (MemoryStream imageDataStream = new MemoryStream(imageData))
|
|
|
using (BinaryWriter imageWriter = new BinaryWriter(imageDataStream))
|
|
|
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
|
|
{
|
|
|
int blockCountX = (width + 3) / 4;
|
|
|
int blockCountY = (height + 3) / 4;
|
|
|
|
|
|
for (int y = 0; y < blockCountY; y++)
|
|
|
{
|
|
|
for (int x = 0; x < blockCountX; x++)
|
|
|
{
|
|
|
SwapDxt1Block(imageReader, imageWriter);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return imageData;
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt3(byte[] imageData, int width, int height)
|
|
|
{
|
|
|
using (MemoryStream imageStream = new MemoryStream(imageData))
|
|
|
{
|
|
|
return SwapDxt3(imageStream, imageData.Length, width, height);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt3(Stream imageStream, int imageLength, int width, int height)
|
|
|
{
|
|
|
byte[] imageData = new byte[imageLength];
|
|
|
using (MemoryStream imageDataStream = new MemoryStream(imageData))
|
|
|
using (BinaryWriter imageWriter = new BinaryWriter(imageDataStream))
|
|
|
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
|
|
{
|
|
|
int blockCountX = (width + 3) / 4;
|
|
|
int blockCountY = (height + 3) / 4;
|
|
|
|
|
|
for (int y = 0; y < blockCountY; y++)
|
|
|
{
|
|
|
for (int x = 0; x < blockCountX; x++)
|
|
|
{
|
|
|
SwapDxt3Block(imageReader, imageWriter);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return imageData;
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt5(byte[] imageData, int width, int height)
|
|
|
{
|
|
|
using (MemoryStream imageStream = new MemoryStream(imageData))
|
|
|
{
|
|
|
return SwapDxt5(imageStream, imageData.Length, width, height);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
internal static byte[] SwapDxt5(Stream imageStream, int imageLength, int width, int height)
|
|
|
{
|
|
|
byte[] imageData = new byte[imageLength];
|
|
|
using (MemoryStream imageDataStream = new MemoryStream(imageData))
|
|
|
using (BinaryWriter imageWriter = new BinaryWriter(imageDataStream))
|
|
|
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
|
|
{
|
|
|
int blockCountX = (width + 3) / 4;
|
|
|
int blockCountY = (height + 3) / 4;
|
|
|
|
|
|
for (int y = 0; y < blockCountY; y++)
|
|
|
{
|
|
|
for (int x = 0; x < blockCountX; x++)
|
|
|
{
|
|
|
SwapDxt5Block(imageReader, imageWriter);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return imageData;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Private Static Methods
|
|
|
|
|
|
public static ushort SwapEndian(ushort data)
|
|
|
{
|
|
|
return (ushort) (
|
|
|
((ushort) ((data & 0xFF) << 8)) |
|
|
|
((ushort) ((data >> 8) & 0xFF))
|
|
|
);
|
|
|
}
|
|
|
|
|
|
private static void SwapDxt1Block(BinaryReader imageReader, BinaryWriter imageWriter)
|
|
|
{
|
|
|
// Fix the following two big-endian words to litte-endian words.
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
|
|
|
// Two words / 16 bit values instead of a 4 byte / 32 bit table.
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
}
|
|
|
|
|
|
private static void SwapDxt3Block(BinaryReader imageReader, BinaryWriter imageWriter)
|
|
|
{
|
|
|
// Alpha data. 16 4-bit values, but written to / read from as 4 16-bit values.
|
|
|
// Somehow, that one test game I had worked just fine with this unchanged... -ade
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
|
|
|
SwapDxt1Block(imageReader, imageWriter);
|
|
|
}
|
|
|
|
|
|
private static void SwapDxt5Block(BinaryReader imageReader, BinaryWriter imageWriter)
|
|
|
{
|
|
|
// Alpha minimum and maximum. Two bytes, but handled internally as one word.
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
|
|
|
// Alpha indices. 16 3-bit values, but written to / read from as 3 16-bit values.
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
imageWriter.Write(SwapEndian(imageReader.ReadUInt16()));
|
|
|
|
|
|
SwapDxt1Block(imageReader, imageWriter);
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
}
|
|
|
}
|
|
|
|