Add ETC1 compressor
This commit is contained in:
parent
238b6f60fb
commit
bfc02c117d
@ -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()
|
||||
{
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
210
Switch_Toolbox_Library/Texture Decoding/3DS/ETC1_Encoder.cs
Normal file
210
Switch_Toolbox_Library/Texture Decoding/3DS/ETC1_Encoder.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
BIN
Toolbox/Lib/RG_ETC1.dll
Normal file
Binary file not shown.
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user