Skip to content

Commit

Permalink
Added support for R8 and RG88
Browse files Browse the repository at this point in the history
Increased version
  • Loading branch information
notscuffed committed Sep 5, 2019
1 parent 8b9d53f commit ae75037
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 25 deletions.
2 changes: 1 addition & 1 deletion RePKG.Tests/TexDecompilingTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ protected void SetUp()
Directory.CreateDirectory($"{BasePath}\\{ValidatedDirectoryName}\\");
}

protected void Test(string name, bool validateBytes = false, Action<Tex, byte[]> validateTex = null)
protected void Test(string name, bool validateBytes = true, Action<Tex, byte[]> validateTex = null)
{
var texture = TexLoader.LoadTex(LoadTestFile(name));
var bytes = texture.Decompile();
Expand Down
9 changes: 9 additions & 0 deletions RePKG.Tests/Texb2DecompilingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,14 @@ public class Texb2DecompilingTests : TexDecompilingTestsBase

[Test]
public void V2_ARGB8888() => Test(nameof(V2_ARGB8888));

[Test]
public void V2_R8() => Test(nameof(V2_R8));

[Test]
public void V2_RG88() => Test(nameof(V2_RG88));

[Test]
public void V2_ARGB8888N() => Test(nameof(V2_ARGB8888N));
}
}
86 changes: 80 additions & 6 deletions RePKG/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,94 @@ public static IEnumerable<string> GetPropertyKeysForDynamic(dynamic dynamicToGet
var toReturn = new List<string>();
foreach (var key in values.Keys)
{
toReturn.Add(key);
toReturn.Add(key);
}

return toReturn;
}

public static unsafe void CopyRawR8PixelsIntoBitmap(byte[] data, int textureWidth, Bitmap processedBitmap)
{
var dataStride = textureWidth;

var bitmapData = processedBitmap.LockBits(
new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite,
processedBitmap.PixelFormat);

var bytesPerPixel = Image.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
var heightInPixels = bitmapData.Height;
var widthInBytes = bitmapData.Width * bytesPerPixel;
var ptrFirstPixel = (byte*) bitmapData.Scan0;

Parallel.For(0, heightInPixels, y =>
{
var currentLine = ptrFirstPixel + y * bitmapData.Stride;
var currentLineData = y * dataStride;

for (var x = 0; x < widthInBytes; x += bytesPerPixel)
{
var dataX = x / bytesPerPixel;
var p = data[currentLineData + dataX];

currentLine[x] = p;
currentLine[x + 1] = p;
currentLine[x + 2] = p;

currentLine[x + 3] = 0xFF;
}
});

processedBitmap.UnlockBits(bitmapData);
}

public static unsafe void CopyRawRG88PixelsIntoBitmap(byte[] data, int textureWidth, Bitmap processedBitmap)
{
var dataStride = textureWidth * 2;

var bitmapData = processedBitmap.LockBits(
new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite,
processedBitmap.PixelFormat);

var bytesPerPixel = Image.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
var heightInPixels = bitmapData.Height;
var widthInBytes = bitmapData.Width * bytesPerPixel;
var ptrFirstPixel = (byte*) bitmapData.Scan0;

Parallel.For(0, heightInPixels, y =>
{
var currentLine = ptrFirstPixel + y * bitmapData.Stride;
var currentLineData = y * dataStride;

for (var x = 0; x < widthInBytes; x += bytesPerPixel)
{
var dataX = (x / bytesPerPixel) * 2;
var p = data[currentLineData + dataX + 1];

currentLine[x] = p;
currentLine[x + 1] = p;
currentLine[x + 2] = p;

currentLine[x + 3] = 0xFF;
}
});

processedBitmap.UnlockBits(bitmapData);
}

// source: http://csharpexamples.com/fast-image-processing-c/
public static unsafe void CopyRawPixelsIntoBitmap(byte[] data, int dataStride, Bitmap processedBitmap, bool invertedColorOrder)
public static unsafe void CopyRawPixelsIntoBitmap(byte[] data, int textureWidth, Bitmap processedBitmap,
bool invertedColorOrder)
{
var bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);

var dataStride = textureWidth * 4;

var bitmapData = processedBitmap.LockBits(
new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite,
processedBitmap.PixelFormat);

var bytesPerPixel = Image.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
var heightInPixels = bitmapData.Height;
var widthInBytes = bitmapData.Width * bytesPerPixel;
var ptrFirstPixel = (byte*)bitmapData.Scan0;
var ptrFirstPixel = (byte*) bitmapData.Scan0;

if (invertedColorOrder)
{
Expand Down Expand Up @@ -81,4 +155,4 @@ public static string GetExtension(FreeImageFormat format)
return $".{str.ToLower()}";
}
}
}
}
4 changes: 2 additions & 2 deletions RePKG/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.6.0")]
[assembly: AssemblyFileVersion("0.1.6.0")]
[assembly: AssemblyVersion("0.1.7.0")]
[assembly: AssemblyFileVersion("0.1.7.0")]
[assembly: NeutralResourcesLanguage("en")]

50 changes: 34 additions & 16 deletions RePKG/Texture/Tex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Tex
public readonly List<TexMipmap> Mipmaps;

public bool IsGif => (Flags & TexFlags.IsGif) == TexFlags.IsGif;

public Tex()
{
Format = TexFormat.ARGB8888;
Expand All @@ -44,31 +44,44 @@ public byte[] Decompile()

if (ImageFormat != FreeImageFormat.FIF_UNKNOWN)
return bytes;


var width = ImageWidth;
var textureWidth = Mipmaps[0].Width;
var height = ImageHeight;
var bitmap = new Bitmap(width, height);

switch (Format)
{
case TexFormat.DXT5:
bytes = DXT.DecompressImage(Mipmaps[0].Width, Mipmaps[0].Height, bytes, DXT.DXTFlags.DXT5);
Helper.CopyRawPixelsIntoBitmap(bytes, textureWidth, bitmap, true);
break;

case TexFormat.DXT3:
bytes = DXT.DecompressImage(Mipmaps[0].Width, Mipmaps[0].Height, bytes, DXT.DXTFlags.DXT3);
Helper.CopyRawPixelsIntoBitmap(bytes, textureWidth, bitmap, true);
break;

case TexFormat.DXT1:
bytes = DXT.DecompressImage(Mipmaps[0].Width, Mipmaps[0].Height, bytes, DXT.DXTFlags.DXT1);
Helper.CopyRawPixelsIntoBitmap(bytes, textureWidth, bitmap, true);
break;

case TexFormat.R8:
Helper.CopyRawR8PixelsIntoBitmap(bytes, textureWidth, bitmap);
break;

case TexFormat.RG8:
Helper.CopyRawRG88PixelsIntoBitmap(bytes, textureWidth, bitmap);
break;

case TexFormat.ARGB8888:
Helper.CopyRawPixelsIntoBitmap(bytes, textureWidth, bitmap, true);
break;
default:
throw new NotImplementedException($"Format: \"{Format.ToString()}\" ({(int)Format})");
throw new NotImplementedException($"Format: \"{Format.ToString()}\" ({(int) Format})");
}

var width = ImageWidth;
var textureWidth = Mipmaps[0].Width;
var height = ImageHeight;
var bitmap = new Bitmap(width, height);

Helper.CopyRawPixelsIntoBitmap(bytes, textureWidth * 4, bitmap, true);

var stream = new MemoryStream();
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
bitmap.Dispose();
Expand All @@ -81,7 +94,9 @@ public byte[] Decompile()
public void DecompileAndSave(string path, bool overwrite)
{
if (!overwrite && File.Exists(path + Helper.GetExtension(
ImageFormat == FreeImageFormat.FIF_UNKNOWN ? FreeImageFormat.FIF_PNG : ImageFormat)))
ImageFormat == FreeImageFormat.FIF_UNKNOWN
? FreeImageFormat.FIF_PNG
: ImageFormat)))
return;

var bytes = Decompile();
Expand All @@ -100,7 +115,7 @@ public void SaveFormatInfo(string path, bool overwrite)
return;

var format = Format.ToString().Split('.').Last().ToLower();

// ReSharper disable LocalizableElement
File.WriteAllText(path, $"{{\r\n\t\"format\" : \"{format}\"\r\n}}");
}
Expand All @@ -112,27 +127,30 @@ public enum TexMipmapVersion
Version2,
Version1
}

// ReSharper disable InconsistentNaming
public enum TexFormat
{
ARGB8888,
DXT5,
DXT3,
DXT1
DXT1,
R8,
RG8,
}

[Flags]
public enum TexFlags
{
NoInterpolation = 1,
ClampUVs = 2,
IsGif = 4,

// Placeholders
Unk3 = 8,
Unk4 = 16,
Unk5 = 32,
Unk6 = 64,
Unk7 = 128,
}
}
}
6 changes: 6 additions & 0 deletions RePKG/Texture/TexLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public static Tex LoadTex(byte[] bytes, int maxMipmapsToLoad = -1)
case 7:
tex.Format = TexFormat.DXT1;
break;
case 8:
tex.Format = TexFormat.RG8;
break;
case 9:
tex.Format = TexFormat.R8;
break;
default:
throw new Exception(
$"Unknown tex format id: {tex.FormatId} for {tex.TextureContainerMagic}");
Expand Down

0 comments on commit ae75037

Please sign in to comment.