Add ETC1 compressor

This commit is contained in:
KillzXGaming 2020-02-08 14:06:01 -05:00
parent 238b6f60fb
commit bfc02c117d
8 changed files with 290 additions and 14 deletions

View file

@ -11,7 +11,7 @@ using Toolbox.Library.Forms;
namespace FirstPlugin
{
public class CTXB : TreeNodeFile, IFileFormat, ITextureContainer
public class CTXB : TreeNodeFile, IFileFormat, ITextureContainer, IContextMenuNode
{
public FileType FileType { get; set; } = FileType.Archive;
@ -65,6 +65,73 @@ namespace FirstPlugin
header.Read(new FileReader(stream), this);
}
public ToolStripItem[] GetContextMenuItems()
{
return new ToolStripItem[]
{
new ToolStripMenuItem("Save", null, Save, Keys.Control | Keys.S),
new ToolStripMenuItem("Export All", null, ExportAllAction, Keys.Control | Keys.E),
new ToolStripMenuItem("Import", null, ImportAction, Keys.Control | Keys.I),
};
}
private void Save(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = "ctxb";
sfd.Filter = "Supported Formats|*.ctxb;";
sfd.FileName = FileName;
if (sfd.ShowDialog() == DialogResult.OK)
{
STFileSaver.SaveFileFormat(this, sfd.FileName);
}
}
protected void ExportAllAction(object sender, EventArgs e)
{
if (Nodes.Count <= 0)
return;
string formats = FileFilters.GTX;
string[] forms = formats.Split('|');
List<string> Formats = new List<string>();
for (int i = 0; i < forms.Length; i++)
{
if (i > 1 || i == (forms.Length - 1)) //Skip lines with all extensions
{
if (!forms[i].StartsWith("*"))
Formats.Add(forms[i]);
}
}
FolderSelectDialog sfd = new FolderSelectDialog();
if (sfd.ShowDialog() == DialogResult.OK)
{
string folderPath = sfd.SelectedPath;
BatchFormatExport form = new BatchFormatExport(Formats);
if (form.ShowDialog() == DialogResult.OK)
{
string extension = form.GetSelectedExtension();
extension.Replace(" ", string.Empty);
foreach (STGenericTexture node in Nodes)
{
((STGenericTexture)node).Export($"{folderPath}\\{node.Text}{extension}");
}
}
}
}
private void ImportAction(object sender, EventArgs e)
{
}
public void Unload()
{

View file

@ -109,7 +109,7 @@ In the event that the tool cannot compile, check references. All the libraries u
## Credits
- Smash Forge Devs (SMG, Ploaj, jam1garner, smb123w64gb, etc.) for some code ported over, specifically animation stuff and some rendering.
- Smash Forge Devs (SMG, Ploaj, jam1garner, smb123w64gb, etc.) for some code ported over, specifically animation stuff, ETC1 encoder and some rendering.
- Ploaj for a base on the DAE writer.
- Assimp devs for their massive asset library!
- Wexos (helped figure out a few things, i.e. format list to assign each attribute)

View file

@ -125,7 +125,7 @@ namespace Toolbox.Library.Forms
SelectedTexSettings.IsFinishedCompressing = true;
bitmap = CTR_3DS.DecodeBlockToBitmap(mips[0], (int)SelectedTexSettings.TexWidth, (int)SelectedTexSettings.TexHeight, SelectedTexSettings.Format);
bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
if (pictureBox1.InvokeRequired)
{

View file

@ -0,0 +1,210 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Toolbox.Library.IO;
namespace SmashForge
{
//Ported from https://raw.githubusercontent.com/jam1garner/Smash-Forge/master/Smash%20Forge/Filetypes/Textures/RG_ETC1.cs
//This encoder is pretty good
class RG_ETC1
{
public static byte[] encodeETC(Bitmap b)
{
int width = b.Width;
int height = b.Height;
int[] pixels = new int[width * height];
init();
int i, j;
var mem = new System.IO.MemoryStream();
using (var writer = new FileWriter(mem)) {
writer.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
for (i = 0; i < height; i += 8)
{
for (j = 0; j < width; j += 8)
{
int x, y;
Color[] temp = new Color[16];
int pi = 0;
for (x = i; x < i + 4; x++)
for (y = j; y < j + 4; y++)
temp[pi++] = b.GetPixel(y, x);
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i; x < i + 4; x++)
for (y = j + 4; y < j + 8; y++)
temp[pi++] = b.GetPixel(y, x);
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i + 4; x < i + 8; x++)
for (y = j; y < j + 4; y++)
temp[pi++] = b.GetPixel(y, x);
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i + 4; x < i + 8; x++)
for (y = j + 4; y < j + 8; y++)
temp[pi++] = b.GetPixel(y, x);
writer.Write(GenETC1(temp));
}
}
}
return mem.ToArray();
}
public static byte[] GenETC1(Color[] colors)
{
uint[] pixels = new uint[colors.Length];
for (int i = 0; i < colors.Length; i++)
{
pixels[i] = (uint)((colors[i].A << 24) | (colors[i].B << 16) | (colors[i].G << 8) | colors[i].R);
}
IntPtr ptr = encode_etc1(pixels, (int)ETC1_Quality.med, false);
byte[] result = new byte[8];
Marshal.Copy(ptr, result, 0, 8);
ReleaseMemory(ptr);
byte[] block = result;//pack_etc1_block(pixels);
byte[] ne = new byte[8];
ne[0] = block[7];
ne[1] = block[6];
ne[2] = block[5];
ne[3] = block[4];
ne[4] = block[3];
ne[5] = block[2];
ne[6] = block[1];
ne[7] = block[0];
return ne;
}
public static byte[] encodeETCa4(Bitmap b)
{
int width = b.Width;
int height = b.Height;
int[] pixels = new int[width * height];
init();
int i, j;
var mem = new System.IO.MemoryStream();
using (var writer = new FileWriter(mem))
{
writer.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
for (i = 0; i < height; i += 8)
{
for (j = 0; j < width; j += 8)
{
int x, y;
Color[] temp = new Color[16];
int pi = 0;
for (x = i; x < i + 4; x++)
for (y = j; y < j + 4; y++)
temp[pi++] = b.GetPixel(y, x);
for (int ax = 0; ax < 4; ax++)
for (int ay = 0; ay < 4; ay++)
{
int a = (temp[ax + ay * 4].A >> 4);
ay++;
a |= (temp[ax + ay * 4].A >> 4) << 4;
writer.Write((byte)a);
}
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i; x < i + 4; x++)
for (y = j + 4; y < j + 8; y++)
temp[pi++] = b.GetPixel(y, x);
for (int ax = 0; ax < 4; ax++)
for (int ay = 0; ay < 4; ay++)
{
int a = (temp[ax + ay * 4].A >> 4);
ay++;
a |= (temp[ax + ay * 4].A >> 4) << 4;
writer.Write((byte)a);
}
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i + 4; x < i + 8; x++)
for (y = j; y < j + 4; y++)
temp[pi++] = b.GetPixel(y, x);
for (int ax = 0; ax < 4; ax++)
for (int ay = 0; ay < 4; ay++)
{
int a = (temp[ax + ay * 4].A >> 4);
ay++;
a |= (temp[ax + ay * 4].A >> 4) << 4;
writer.Write((byte)a);
}
writer.Write(GenETC1(temp));
temp = new Color[16];
pi = 0;
for (x = i + 4; x < i + 8; x++)
for (y = j + 4; y < j + 8; y++)
temp[pi++] = b.GetPixel(y, x);
for (int ax = 0; ax < 4; ax++)
for (int ay = 0; ay < 4; ay++)
{
int a = (temp[ax + ay * 4].A >> 4);
ay++;
a |= (temp[ax + ay * 4].A >> 4) << 4;
writer.Write((byte)a);
}
writer.Write(GenETC1(temp));
}
}
}
return mem.ToArray();
}
public enum ETC1_Quality
{
low = 0,
med = 1,
high = 2
}
[DllImport("Lib\\RG_ETC1.dll")]
public static extern void init();
[DllImport("Lib\\RG_ETC1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr encode_etc1(uint[] pSrc_pixels_rgba, int quality, bool dither);
[DllImport("Lib\\RG_ETC1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int ReleaseMemory(IntPtr ptr);
}
}

View file

@ -208,13 +208,10 @@ namespace Toolbox.Library
{
int ImageSize = CalculateLength(Width, Height, PicaFormat);
if (PicaFormat == PICASurfaceFormat.ETC1 ||
PicaFormat == PICASurfaceFormat.ETC1A4)
{
return new byte[ImageSize];
return ETC1.ETC1Encode(Input, Width, Height, PicaFormat == PICASurfaceFormat.ETC1A4);
}
if (PicaFormat == PICASurfaceFormat.ETC1)
return SmashForge.RG_ETC1.encodeETC(BitmapExtension.GetBitmap(Input, Width, Height));
else if (PicaFormat == PICASurfaceFormat.ETC1A4)
return SmashForge.RG_ETC1.encodeETCa4(BitmapExtension.GetBitmap(Input, Width, Height));
var mem = new System.IO.MemoryStream();
using (var writer = new FileWriter(mem))
@ -336,8 +333,8 @@ namespace Toolbox.Library
}
byte[] newOutput = mem.ToArray();
if (newOutput.Length != ImageSize)
throw new Exception($"Invalid image size! Expected {ImageSize} got {newOutput.Length}");
// if (newOutput.Length != ImageSize)
// throw new Exception($"Invalid image size! Expected {ImageSize} got {newOutput.Length}");
if (newOutput.Length > 0)
return newOutput;

View file

@ -934,6 +934,7 @@
<Compile Include="STToolStipMenuItem.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Texture Decoding\3DS\ETC1_Encoder.cs" />
<Compile Include="Texture Decoding\Gamecube\Color32.cs" />
<Compile Include="Texture Decoding\Gamecube\Decode_Gamecube.cs" />
<Compile Include="Texture Decoding\Wii U\GX2TexRegisters.cs" />

BIN
Toolbox/Lib/RG_ETC1.dll Normal file

Binary file not shown.

View file

@ -25,7 +25,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -35,7 +34,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Tool.ico</ApplicationIcon>
@ -491,6 +489,9 @@
<Content Include="Lib\Plugins\Blank.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Lib\RG_ETC1.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Lib\SARCExt.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>