mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-10 07:04:36 +00:00
Start to implement 3ds texture encoding. (Todo ETC1 and L4/A4)
This commit is contained in:
parent
c11389fb4f
commit
9db860f0b8
18 changed files with 572 additions and 291 deletions
|
@ -13,7 +13,6 @@ using Toolbox.Library.IO;
|
|||
using Toolbox.Library.Forms;
|
||||
using GL_EditorFramework.EditorDrawables;
|
||||
using FirstPlugin.Forms;
|
||||
using static GL_EditorFramework.EditorDrawables.EditorSceneBase;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
|
@ -314,7 +313,7 @@ namespace FirstPlugin
|
|||
}
|
||||
}
|
||||
|
||||
public KCLRendering Renderer;
|
||||
public KCLRendering Renderer = null ;
|
||||
bool DrawablesLoaded = false;
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
|
@ -457,8 +456,8 @@ namespace FirstPlugin
|
|||
protected bool Selected = false;
|
||||
protected bool Hovered = false;
|
||||
|
||||
// public override bool IsSelected() => Selected;
|
||||
// public override bool IsSelected(int partIndex) => Selected;
|
||||
// public override bool IsSelected() => Selected;
|
||||
// public override bool IsSelected(int partIndex) => Selected;
|
||||
|
||||
public bool IsHovered() => Selected;
|
||||
|
||||
|
@ -587,7 +586,7 @@ namespace FirstPlugin
|
|||
|
||||
public override void Prepare(GL_ControlLegacy control)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void CheckBuffers()
|
||||
|
@ -747,103 +746,103 @@ namespace FirstPlugin
|
|||
GL.Uniform1(shader["colorOverride"], 0);
|
||||
}
|
||||
|
||||
/* public override BoundingBox GetSelectionBox()
|
||||
{
|
||||
Vector3 Min = new Vector3(0);
|
||||
Vector3 Max = new Vector3(0);
|
||||
/* public override BoundingBox GetSelectionBox()
|
||||
{
|
||||
Vector3 Min = new Vector3(0);
|
||||
Vector3 Max = new Vector3(0);
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
foreach (var vertex in model.vertices)
|
||||
{
|
||||
Min.X = Math.Min(Min.X, vertex.pos.X);
|
||||
Min.Y = Math.Min(Min.Y, vertex.pos.Y);
|
||||
Min.Z = Math.Min(Min.Z, vertex.pos.Z);
|
||||
Max.X = Math.Max(Max.X, vertex.pos.X);
|
||||
Max.Y = Math.Max(Max.Y, vertex.pos.Y);
|
||||
Max.Z = Math.Max(Max.Z, vertex.pos.Z);
|
||||
}
|
||||
}
|
||||
foreach (var model in models)
|
||||
{
|
||||
foreach (var vertex in model.vertices)
|
||||
{
|
||||
Min.X = Math.Min(Min.X, vertex.pos.X);
|
||||
Min.Y = Math.Min(Min.Y, vertex.pos.Y);
|
||||
Min.Z = Math.Min(Min.Z, vertex.pos.Z);
|
||||
Max.X = Math.Max(Max.X, vertex.pos.X);
|
||||
Max.Y = Math.Max(Max.Y, vertex.pos.Y);
|
||||
Max.Z = Math.Max(Max.Z, vertex.pos.Z);
|
||||
}
|
||||
}
|
||||
|
||||
return new BoundingBox()
|
||||
{
|
||||
minX = Min.X,
|
||||
minY = Min.Y,
|
||||
minZ = Min.Z,
|
||||
maxX = Max.X,
|
||||
maxY = Max.Y,
|
||||
maxZ = Max.Z,
|
||||
};
|
||||
}
|
||||
return new BoundingBox()
|
||||
{
|
||||
minX = Min.X,
|
||||
minY = Min.Y,
|
||||
minZ = Min.Z,
|
||||
maxX = Max.X,
|
||||
maxY = Max.Y,
|
||||
maxZ = Max.Z,
|
||||
};
|
||||
}
|
||||
|
||||
public override LocalOrientation GetLocalOrientation(int partIndex)
|
||||
{
|
||||
return new LocalOrientation(position);
|
||||
}
|
||||
public override LocalOrientation GetLocalOrientation(int partIndex)
|
||||
{
|
||||
return new LocalOrientation(position);
|
||||
}
|
||||
|
||||
public override bool TryStartDragging(DragActionType actionType, int hoveredPart, out LocalOrientation localOrientation, out bool dragExclusively)
|
||||
{
|
||||
localOrientation = new LocalOrientation(position);
|
||||
dragExclusively = false;
|
||||
return Selected;
|
||||
}
|
||||
public override bool TryStartDragging(DragActionType actionType, int hoveredPart, out LocalOrientation localOrientation, out bool dragExclusively)
|
||||
{
|
||||
localOrientation = new LocalOrientation(position);
|
||||
dragExclusively = false;
|
||||
return Selected;
|
||||
}
|
||||
|
||||
public override bool IsInRange(float range, float rangeSquared, Vector3 pos)
|
||||
{
|
||||
range = 20000; //Make the range large for now. Todo go back to this
|
||||
public override bool IsInRange(float range, float rangeSquared, Vector3 pos)
|
||||
{
|
||||
range = 20000; //Make the range large for now. Todo go back to this
|
||||
|
||||
BoundingBox box = GetSelectionBox();
|
||||
BoundingBox box = GetSelectionBox();
|
||||
|
||||
if (pos.X < box.maxX + range && pos.X > box.minX - range &&
|
||||
pos.Y < box.maxY + range && pos.Y > box.minY - range &&
|
||||
pos.Z < box.maxZ + range && pos.Z > box.minZ - range)
|
||||
return true;
|
||||
if (pos.X < box.maxX + range && pos.X > box.minX - range &&
|
||||
pos.Y < box.maxY + range && pos.Y > box.minY - range &&
|
||||
pos.Z < box.maxZ + range && pos.Z > box.minZ - range)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override uint SelectAll(GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
public override uint SelectAll(GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
|
||||
public override uint SelectDefault(GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
public override uint SelectDefault(GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
|
||||
public override uint Select(int partIndex, GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
public override uint Select(int partIndex, GL_ControlBase control)
|
||||
{
|
||||
Selected = true;
|
||||
return REDRAW;
|
||||
}
|
||||
|
||||
public override uint Deselect(int partIndex, GL_ControlBase control)
|
||||
{
|
||||
Selected = false;
|
||||
return REDRAW;
|
||||
}
|
||||
public override uint Deselect(int partIndex, GL_ControlBase control)
|
||||
{
|
||||
Selected = false;
|
||||
return REDRAW;
|
||||
}
|
||||
|
||||
public override uint DeselectAll(GL_ControlBase control)
|
||||
{
|
||||
Selected = false;
|
||||
return REDRAW;
|
||||
}
|
||||
public override uint DeselectAll(GL_ControlBase control)
|
||||
{
|
||||
Selected = false;
|
||||
return REDRAW;
|
||||
}
|
||||
|
||||
public override Vector3 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
position = value;
|
||||
}
|
||||
}*/
|
||||
public override Vector3 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
position = value;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
//Convert KCL lib vec3 to opentk one so i can use the cross and dot methods
|
||||
|
@ -962,4 +961,4 @@ namespace FirstPlugin
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ using Toolbox.Library.IO;
|
|||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class TEX3DS : STGenericTexture, IEditor<ImageEditorBase>, IFileFormat
|
||||
public class TEX3DS : STGenericTexture, IFileFormat, IContextMenuNode
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Image;
|
||||
|
||||
|
@ -62,28 +62,44 @@ namespace FirstPlugin
|
|||
|
||||
public byte[] ImageData;
|
||||
|
||||
public ImageEditorBase OpenForm()
|
||||
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
bool IsDialog = IFileInfo != null && IFileInfo.InArchive;
|
||||
UpdateEditor();
|
||||
}
|
||||
|
||||
Properties prop = new Properties();
|
||||
prop.Width = Width;
|
||||
prop.Height = Height;
|
||||
prop.Depth = Depth;
|
||||
prop.MipCount = MipCount;
|
||||
prop.ArrayCount = ArrayCount;
|
||||
prop.ImageSize = (uint)ImageData.Length;
|
||||
prop.Format = Format;
|
||||
private void UpdateEditor()
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
ImageEditorBase form = new ImageEditorBase();
|
||||
form.Text = Text;
|
||||
form.Dock = DockStyle.Fill;
|
||||
// form.editorBase.AddFileContextEvent("Save", Save);
|
||||
// form.editorBase.AddFileContextEvent("Replace", Replace);
|
||||
form.LoadProperties(prop);
|
||||
form.LoadImage(this);
|
||||
editor.LoadProperties(GenericProperties);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
return form;
|
||||
public ToolStripItem[] GetContextMenuItems()
|
||||
{
|
||||
List<ToolStripItem> Items = new List<ToolStripItem>();
|
||||
Items.Add(new ToolStripMenuItem("Save", null, SaveAction, Keys.Control | Keys.S));
|
||||
Items.AddRange(base.GetContextMenuItems());
|
||||
return Items.ToArray();
|
||||
}
|
||||
|
||||
private void SaveAction(object sender, EventArgs args)
|
||||
{
|
||||
SaveFileDialog sfd = new SaveFileDialog();
|
||||
sfd.Filter = Utils.GetAllFilters(this);
|
||||
sfd.FileName = FileName;
|
||||
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
STFileSaver.SaveFileFormat(this, sfd.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
public void FillEditor(UserControl control)
|
||||
|
@ -105,6 +121,7 @@ namespace FirstPlugin
|
|||
{
|
||||
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
|
||||
CanSave = true;
|
||||
CanReplace = true;
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
|
@ -137,6 +154,50 @@ namespace FirstPlugin
|
|||
}
|
||||
}
|
||||
|
||||
public override void Replace(string FileName)
|
||||
{
|
||||
CTR_3DSTextureImporter importer = new CTR_3DSTextureImporter();
|
||||
CTR_3DSImporterSettings settings = new CTR_3DSImporterSettings();
|
||||
|
||||
if (Utils.GetExtension(FileName) == ".dds" ||
|
||||
Utils.GetExtension(FileName) == ".dds2")
|
||||
{
|
||||
settings.LoadDDS(FileName);
|
||||
importer.LoadSettings(new List<CTR_3DSImporterSettings>() { settings, });
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.LoadBitMap(FileName);
|
||||
importer.LoadSettings(new List<CTR_3DSImporterSettings>() { settings, });
|
||||
|
||||
if (importer.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (settings.GenerateMipmaps && !settings.IsFinishedCompressing)
|
||||
{
|
||||
settings.DataBlockOutput.Clear();
|
||||
settings.DataBlockOutput.Add(settings.GenerateMips());
|
||||
}
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettings(CTR_3DSImporterSettings settings)
|
||||
{
|
||||
this.ImageData = settings.DataBlockOutput[0];
|
||||
this.Width = settings.TexWidth;
|
||||
this.Height = settings.TexHeight;
|
||||
this.Format = settings.GenericFormat;
|
||||
this.MipCount = settings.MipCount;
|
||||
this.Depth = settings.Depth;
|
||||
this.ArrayCount = (uint)settings.DataBlockOutput.Count;
|
||||
}
|
||||
|
||||
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
|
||||
{
|
||||
|
||||
|
|
|
@ -370,6 +370,18 @@
|
|||
<Compile Include="GUI\BFRES\SmoothNormalsMultiMeshForm.Designer.cs">
|
||||
<DependentUpon>SmoothNormalsMultiMeshForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\BinaryTextureImporterList.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\BinaryTextureImporterList.Designer.cs">
|
||||
<DependentUpon>BinaryTextureImporterList.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\TextureImporterSettings.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\CreateGx2Texture.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\GTXImporterSettings.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\GTXTextureImporter.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Scenes\SMO\CustomClasses.cs" />
|
||||
<Compile Include="Scenes\SMO\Level.cs" />
|
||||
<Compile Include="Scenes\SMO\LevelObj.cs" />
|
||||
|
@ -570,10 +582,6 @@
|
|||
<Compile Include="GUI\SMO\OdysseyCostumeLoader.Designer.cs">
|
||||
<DependentUpon>OdysseyCostumeLoader.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\3DS\CTR_3DSImporterSettings.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\3DS\CTR_3DSTextureImporter.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GUI\SMO\MarioCostumeEditor.cs" />
|
||||
<Compile Include="GUI\AAMP\AampV1Editor.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
|
@ -930,10 +938,6 @@
|
|||
<Compile Include="GUI\TextureLoader.Designer.cs">
|
||||
<DependentUpon>TextureLoader.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\GTXImporterSettings.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\GTXTextureImporter.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GUI\Byaml\ByamlEditor.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -971,14 +975,6 @@
|
|||
<Compile Include="GUI\BFRES\Materials\Texture Selector.Designer.cs">
|
||||
<DependentUpon>Texture Selector.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\BinaryTextureImporterList.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\BinaryTextureImporterList.Designer.cs">
|
||||
<DependentUpon>BinaryTextureImporterList.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUI\TextureUI\Importers\GX2\CreateGx2Texture.cs" />
|
||||
<Compile Include="GUI\TextureUI\Importers\BNTX\TextureImporterSettings.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="MaterialPresetConfig.cs" />
|
||||
<Compile Include="NodeWrappers\Archives\BFRESWrapper.cs" />
|
||||
|
@ -1273,9 +1269,6 @@
|
|||
<EmbeddedResource Include="GUI\TextureLoader.resx">
|
||||
<DependentUpon>TextureLoader.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="GUI\TextureUI\Importers\3DS\CTR_3DSTextureImporter.resx">
|
||||
<DependentUpon>CTR_3DSTextureImporter.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="GUI\TextureUI\Importers\BNTX\BinaryTextureImporterList.resx">
|
||||
<DependentUpon>BinaryTextureImporterList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Toolbox.Library.Animations
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a class for animating a skeleton
|
||||
/// </summary>
|
||||
public class STSkeletonAnimation
|
||||
{
|
||||
/// <summary>
|
||||
/// The total amount of frames to play in the animation
|
||||
/// </summary>
|
||||
public uint FrameCount { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,22 +6,19 @@ using System.Drawing;
|
|||
using System.Threading.Tasks;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
using Syroot.NintenTools.Bfres.GX2;
|
||||
using Bfres.Structs;
|
||||
|
||||
namespace FirstPlugin
|
||||
namespace Toolbox.Library.Forms
|
||||
{
|
||||
public class CTR_3DSImporterSettings
|
||||
{
|
||||
public string TexName;
|
||||
public uint TexWidth;
|
||||
public uint TexHeight;
|
||||
public uint MipCount;
|
||||
public uint Depth = 1;
|
||||
public uint arrayLength = 1;
|
||||
public List<byte[]> DataBlockOutput = new List<byte[]>();
|
||||
public List<byte[]> DecompressedData = new List<byte[]>();
|
||||
public CTR_3DS.PICASurfaceFormat Format;
|
||||
|
||||
public bool GenerateMipmaps;
|
||||
public bool IsSRGB;
|
||||
public uint tileMode = 4;
|
||||
|
@ -32,6 +29,52 @@ namespace FirstPlugin
|
|||
|
||||
public float alphaRef = 0.5f;
|
||||
|
||||
//Round 3DS width/height by power of 2
|
||||
private uint _width;
|
||||
public uint TexWidth
|
||||
{
|
||||
get { return _width; }
|
||||
set { _width = Pow2RoundDown(value); }
|
||||
}
|
||||
|
||||
private uint _height;
|
||||
public uint TexHeight
|
||||
{
|
||||
get { return _height; }
|
||||
set { _height = Pow2RoundDown(value); }
|
||||
}
|
||||
|
||||
public TEX_FORMAT GenericFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
return CTR_3DS.ConvertPICAToGenericFormat(Format);
|
||||
}
|
||||
}
|
||||
|
||||
static uint Pow2RoundDown(uint Value) {
|
||||
return IsPow2(Value) ? Value : Pow2RoundUp(Value) >> 1;
|
||||
}
|
||||
|
||||
static bool IsPow2(uint Value) {
|
||||
return Value != 0 && (Value & (Value - 1)) == 0;
|
||||
}
|
||||
|
||||
static uint Pow2RoundUp(uint Value)
|
||||
{
|
||||
Value--;
|
||||
|
||||
Value |= (Value >> 1);
|
||||
Value |= (Value >> 2);
|
||||
Value |= (Value >> 4);
|
||||
Value |= (Value >> 8);
|
||||
Value |= (Value >> 16);
|
||||
|
||||
return ++Value;
|
||||
}
|
||||
|
||||
public bool IsFinishedCompressing = false;
|
||||
|
||||
public void LoadDDS(string FileName, byte[] FileData = null)
|
||||
{
|
||||
TexName = STGenericTexture.SetNameFromPath(FileName);
|
||||
|
@ -61,7 +104,7 @@ namespace FirstPlugin
|
|||
|
||||
TexName = STGenericTexture.SetNameFromPath(FileName);
|
||||
|
||||
Format = CTR_3DS.ConvertToPICAFormat(Runtime.PreferredTexFormat);
|
||||
Format = CTR_3DS.PICASurfaceFormat.RGBA8;
|
||||
|
||||
GenerateMipmaps = true;
|
||||
LoadImage(new Bitmap(Image));
|
||||
|
@ -73,7 +116,7 @@ namespace FirstPlugin
|
|||
|
||||
TexName = STGenericTexture.SetNameFromPath(FileName);
|
||||
|
||||
Format = CTR_3DS.ConvertToPICAFormat(Runtime.PreferredTexFormat);
|
||||
Format = CTR_3DS.PICASurfaceFormat.RGBA8;
|
||||
GenerateMipmaps = true;
|
||||
|
||||
//If a texture is .tga, we need to convert it
|
||||
|
@ -98,6 +141,9 @@ namespace FirstPlugin
|
|||
TexHeight = (uint)Image.Height;
|
||||
MipCount = (uint)GetTotalMipCount();
|
||||
|
||||
if (TexWidth != Image.Width || TexHeight != Image.Height)
|
||||
Image = BitmapExtension.Resize(Image, TexWidth, TexHeight);
|
||||
|
||||
DecompressedData.Add(BitmapExtension.ImageToByte(Image));
|
||||
|
||||
Image.Dispose();
|
||||
|
@ -112,8 +158,8 @@ namespace FirstPlugin
|
|||
int MipmapNum = 0;
|
||||
uint num = Math.Max(TexHeight, TexWidth);
|
||||
|
||||
int width = (int)TexWidth;
|
||||
int height = (int)TexHeight;
|
||||
uint width = TexWidth;
|
||||
uint height = TexHeight;
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -121,6 +167,10 @@ namespace FirstPlugin
|
|||
|
||||
width = width / 2;
|
||||
height = height / 2;
|
||||
|
||||
width = Pow2RoundDown(width);
|
||||
height = Pow2RoundDown(height);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
break;
|
||||
|
||||
|
@ -132,25 +182,35 @@ namespace FirstPlugin
|
|||
|
||||
return MipmapNum;
|
||||
}
|
||||
|
||||
public byte[] GenerateMips(int SurfaceLevel = 0)
|
||||
{
|
||||
return Utils.CombineByteArray(GenerateMipList().ToArray());
|
||||
}
|
||||
|
||||
public List<byte[]> GenerateMipList(int SurfaceLevel = 0)
|
||||
{
|
||||
MipCount = 1;
|
||||
|
||||
Bitmap Image = BitmapExtension.GetBitmap(DecompressedData[SurfaceLevel], (int)TexWidth, (int)TexHeight);
|
||||
|
||||
Console.WriteLine("generating mips CTR");
|
||||
|
||||
List<byte[]> mipmaps = new List<byte[]>();
|
||||
mipmaps.Add(STGenericTexture.CompressBlock(DecompressedData[SurfaceLevel],
|
||||
(int)TexWidth, (int)TexHeight, FTEX.ConvertFromGx2Format((GX2SurfaceFormat)Format), alphaRef));
|
||||
mipmaps.Add(CTR_3DS.EncodeBlock(DecompressedData[SurfaceLevel],
|
||||
(int)TexWidth, (int)TexHeight, Format));
|
||||
|
||||
//while (Image.Width / 2 > 0 && Image.Height / 2 > 0)
|
||||
// for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
|
||||
for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
|
||||
{
|
||||
Image = BitmapExtension.Resize(Image, Image.Width / 2, Image.Height / 2);
|
||||
mipmaps.Add(STGenericTexture.CompressBlock(BitmapExtension.ImageToByte(Image),
|
||||
Image.Width, Image.Height, FTEX.ConvertFromGx2Format((GX2SurfaceFormat)Format), alphaRef));
|
||||
}
|
||||
mipmaps.Add(CTR_3DS.EncodeBlock(BitmapExtension.ImageToByte(Image),
|
||||
Image.Width, Image.Height, Format));
|
||||
}
|
||||
Image.Dispose();
|
||||
|
||||
return Utils.CombineByteArray(mipmaps.ToArray());
|
||||
return mipmaps;
|
||||
}
|
||||
public void Compress()
|
||||
{
|
|
@ -6,9 +6,8 @@ using System.Drawing;
|
|||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.Forms;
|
||||
using Bfres.Structs;
|
||||
|
||||
namespace FirstPlugin
|
||||
namespace Toolbox.Library.Forms
|
||||
{
|
||||
public partial class CTR_3DSTextureImporter : STForm
|
||||
{
|
||||
|
@ -28,40 +27,22 @@ namespace FirstPlugin
|
|||
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.A4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.A8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.ETC1);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.ETC1A4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.HiLo8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.L4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.LA4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.L8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.LA4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.LA8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.LA4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.LA8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGB565);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGB8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGBA4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGBA5551);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGBA8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGB8);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGBA5551);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGBA4);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.RGB565);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.ETC1);
|
||||
formatComboBox.Items.Add(CTR_3DS.PICASurfaceFormat.ETC1A4);
|
||||
|
||||
IsLoaded = true;
|
||||
}
|
||||
|
||||
public bool ReadOnlySwizzle
|
||||
{
|
||||
set
|
||||
{
|
||||
SwizzleNum.ReadOnly = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadOnlyTileMode
|
||||
{
|
||||
set
|
||||
{
|
||||
tileModeCB.ReadOnly = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadOnlyFormat
|
||||
{
|
||||
set
|
||||
|
@ -111,7 +92,7 @@ namespace FirstPlugin
|
|||
private Thread Thread;
|
||||
public void SetupSettings()
|
||||
{
|
||||
if (SelectedTexSettings.Format == 0 || SelectedIndex == -1)
|
||||
if (SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
if (Thread != null && Thread.IsAlive)
|
||||
|
@ -120,35 +101,54 @@ namespace FirstPlugin
|
|||
if (formatComboBox.SelectedItem is CTR_3DS.PICASurfaceFormat)
|
||||
{
|
||||
SelectedTexSettings.Format = (CTR_3DS.PICASurfaceFormat)formatComboBox.SelectedItem;
|
||||
listViewCustom1.SelectedItems[0].SubItems[1].Text = SelectedTexSettings.Format.ToString();
|
||||
listViewCustom1.Items[SelectedIndex].SubItems[1].Text = SelectedTexSettings.Format.ToString();
|
||||
}
|
||||
|
||||
HeightLabel.Text = $"Height: {SelectedTexSettings.TexHeight}";
|
||||
WidthLabel.Text = $"Width: {SelectedTexSettings.TexWidth}";
|
||||
|
||||
Bitmap bitmap = Toolbox.Library.Imaging.GetLoadingImage();
|
||||
|
||||
pictureBox1.Image = bitmap;
|
||||
|
||||
Thread = new Thread((ThreadStart)(() =>
|
||||
{
|
||||
pictureBox1.Image = bitmap;
|
||||
SelectedTexSettings.Compress();
|
||||
SelectedTexSettings.IsFinishedCompressing = false;
|
||||
ToggleOkButton(false);
|
||||
|
||||
pictureBox1.Image = bitmap;
|
||||
var mips = SelectedTexSettings.GenerateMipList();
|
||||
|
||||
SelectedTexSettings.DataBlockOutput.Clear();
|
||||
SelectedTexSettings.DataBlockOutput.Add(Utils.CombineByteArray(mips.ToArray()));
|
||||
|
||||
ToggleOkButton(true);
|
||||
SelectedTexSettings.IsFinishedCompressing = true;
|
||||
|
||||
bitmap = CTR_3DS.DecodeBlockToBitmap(mips[0], (int)SelectedTexSettings.TexWidth, (int)SelectedTexSettings.TexHeight, SelectedTexSettings.Format);
|
||||
|
||||
mips.Clear();
|
||||
|
||||
if (pictureBox1.InvokeRequired)
|
||||
{
|
||||
pictureBox1.Invoke((MethodInvoker)delegate {
|
||||
pictureBox1.Image = bitmap;
|
||||
pictureBox1.Refresh();
|
||||
});
|
||||
}
|
||||
}));
|
||||
Thread.Start();
|
||||
}
|
||||
|
||||
private void tileModeCB_SelectedIndexChanged(object sender, EventArgs e)
|
||||
private void ToggleOkButton(bool Enable)
|
||||
{
|
||||
if (tileModeCB.SelectedIndex > -1 && SelectedTexSettings != null)
|
||||
SelectedTexSettings.tileMode = (uint)(GX2.GX2TileMode)tileModeCB.SelectedItem;
|
||||
|
||||
if (tileModeCB.SelectedIndex != 0 && IsLoaded)
|
||||
if (button1.InvokeRequired)
|
||||
{
|
||||
var result = MessageBox.Show("Warning! Only change the tile mode unless you know what you are doing!", "Texture Importer", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
|
||||
if (result == DialogResult.Cancel)
|
||||
tileModeCB.SelectedIndex = 0;
|
||||
button1.Invoke((MethodInvoker)delegate {
|
||||
button1.Enabled = Enable;
|
||||
});
|
||||
}
|
||||
else
|
||||
button1.Enabled = Enable;
|
||||
}
|
||||
|
||||
bool DialogShown = false;
|
||||
|
@ -182,16 +182,9 @@ namespace FirstPlugin
|
|||
}
|
||||
|
||||
MipmapNum.Value = SelectedTexSettings.MipCount;
|
||||
|
||||
SwizzleNum.Value = (SelectedTexSettings.Swizzle >> 8) & 7;
|
||||
}
|
||||
}
|
||||
|
||||
private void SwizzleNum_ValueChanged(object sender, EventArgs e) {
|
||||
SelectedTexSettings.Swizzle &= GX2.SwizzleMask;
|
||||
SelectedTexSettings.Swizzle |= (uint)SwizzleNum.Value << 8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
|
@ -218,11 +211,7 @@ namespace FirstPlugin
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GTXTextureImporter));
|
||||
this.SwizzleNum = new Toolbox.Library.Forms.STNumbericUpDown();
|
||||
this.label5 = new Toolbox.Library.Forms.STLabel();
|
||||
this.tileModeCB = new Toolbox.Library.Forms.STComboBox();
|
||||
this.label4 = new Toolbox.Library.Forms.STLabel();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CTR_3DSTextureImporter));
|
||||
this.ImgDimComb = new Toolbox.Library.Forms.STComboBox();
|
||||
this.label3 = new Toolbox.Library.Forms.STLabel();
|
||||
this.label2 = new Toolbox.Library.Forms.STLabel();
|
||||
|
@ -238,17 +227,12 @@ namespace FirstPlugin
|
|||
this.button1 = new Toolbox.Library.Forms.STButton();
|
||||
this.pictureBox1 = new Toolbox.Library.Forms.PictureBoxCustom();
|
||||
this.contentContainer.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SwizzleNum)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.MipmapNum)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// contentContainer
|
||||
//
|
||||
this.contentContainer.Controls.Add(this.SwizzleNum);
|
||||
this.contentContainer.Controls.Add(this.label5);
|
||||
this.contentContainer.Controls.Add(this.tileModeCB);
|
||||
this.contentContainer.Controls.Add(this.label4);
|
||||
this.contentContainer.Controls.Add(this.ImgDimComb);
|
||||
this.contentContainer.Controls.Add(this.label3);
|
||||
this.contentContainer.Controls.Add(this.label2);
|
||||
|
@ -274,54 +258,6 @@ namespace FirstPlugin
|
|||
this.contentContainer.Controls.SetChildIndex(this.label2, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.label3, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.ImgDimComb, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.label4, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.tileModeCB, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.label5, 0);
|
||||
this.contentContainer.Controls.SetChildIndex(this.SwizzleNum, 0);
|
||||
//
|
||||
// SwizzleNum
|
||||
//
|
||||
this.SwizzleNum.Location = new System.Drawing.Point(774, 167);
|
||||
this.SwizzleNum.Maximum = new decimal(new int[] {
|
||||
7,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.SwizzleNum.Name = "SwizzleNum";
|
||||
this.SwizzleNum.Size = new System.Drawing.Size(130, 20);
|
||||
this.SwizzleNum.TabIndex = 44;
|
||||
this.SwizzleNum.ValueChanged += new System.EventHandler(this.SwizzleNum_ValueChanged);
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(666, 167);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(82, 13);
|
||||
this.label5.TabIndex = 43;
|
||||
this.label5.Text = "Swizzle Pattern:";
|
||||
//
|
||||
// tileModeCB
|
||||
//
|
||||
this.tileModeCB.BorderColor = System.Drawing.Color.Empty;
|
||||
this.tileModeCB.BorderStyle = System.Windows.Forms.ButtonBorderStyle.Solid;
|
||||
this.tileModeCB.ButtonColor = System.Drawing.Color.Empty;
|
||||
this.tileModeCB.FormattingEnabled = true;
|
||||
this.tileModeCB.Location = new System.Drawing.Point(774, 94);
|
||||
this.tileModeCB.Name = "tileModeCB";
|
||||
this.tileModeCB.ReadOnly = true;
|
||||
this.tileModeCB.Size = new System.Drawing.Size(172, 21);
|
||||
this.tileModeCB.TabIndex = 42;
|
||||
this.tileModeCB.SelectedIndexChanged += new System.EventHandler(this.tileModeCB_SelectedIndexChanged);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(666, 97);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(54, 13);
|
||||
this.label4.TabIndex = 41;
|
||||
this.label4.Text = "Tile Mode";
|
||||
//
|
||||
// ImgDimComb
|
||||
//
|
||||
|
@ -356,7 +292,7 @@ namespace FirstPlugin
|
|||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(666, 132);
|
||||
this.label1.Location = new System.Drawing.Point(664, 99);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(90, 13);
|
||||
this.label1.TabIndex = 37;
|
||||
|
@ -364,7 +300,7 @@ namespace FirstPlugin
|
|||
//
|
||||
// MipmapNum
|
||||
//
|
||||
this.MipmapNum.Location = new System.Drawing.Point(774, 130);
|
||||
this.MipmapNum.Location = new System.Drawing.Point(772, 97);
|
||||
this.MipmapNum.Maximum = new decimal(new int[] {
|
||||
13,
|
||||
0,
|
||||
|
@ -378,7 +314,7 @@ namespace FirstPlugin
|
|||
// WidthLabel
|
||||
//
|
||||
this.WidthLabel.AutoSize = true;
|
||||
this.WidthLabel.Location = new System.Drawing.Point(666, 235);
|
||||
this.WidthLabel.Location = new System.Drawing.Point(667, 178);
|
||||
this.WidthLabel.Name = "WidthLabel";
|
||||
this.WidthLabel.Size = new System.Drawing.Size(35, 13);
|
||||
this.WidthLabel.TabIndex = 35;
|
||||
|
@ -387,7 +323,7 @@ namespace FirstPlugin
|
|||
// HeightLabel
|
||||
//
|
||||
this.HeightLabel.AutoSize = true;
|
||||
this.HeightLabel.Location = new System.Drawing.Point(666, 200);
|
||||
this.HeightLabel.Location = new System.Drawing.Point(667, 143);
|
||||
this.HeightLabel.Name = "HeightLabel";
|
||||
this.HeightLabel.Size = new System.Drawing.Size(38, 13);
|
||||
this.HeightLabel.TabIndex = 34;
|
||||
|
@ -466,15 +402,14 @@ namespace FirstPlugin
|
|||
this.pictureBox1.TabIndex = 33;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
// GTXTextureImporter
|
||||
// CTR_3DSTextureImporter
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(986, 516);
|
||||
this.Text = "GTXTextureImporter";
|
||||
this.Text = "CTR Texture Importer";
|
||||
this.contentContainer.ResumeLayout(false);
|
||||
this.contentContainer.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.SwizzleNum)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.MipmapNum)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
@ -482,11 +417,6 @@ namespace FirstPlugin
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Toolbox.Library.Forms.STNumbericUpDown SwizzleNum;
|
||||
private Toolbox.Library.Forms.STLabel label5;
|
||||
private Toolbox.Library.Forms.STComboBox tileModeCB;
|
||||
private Toolbox.Library.Forms.STLabel label4;
|
||||
private Toolbox.Library.Forms.STComboBox ImgDimComb;
|
||||
private Toolbox.Library.Forms.STLabel label3;
|
||||
private Toolbox.Library.Forms.STLabel label2;
|
|
@ -35,7 +35,7 @@ namespace Toolbox.Library
|
|||
|
||||
public override void Prepare(GL_ControlModern control)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public override void Prepare(GL_ControlLegacy control)
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ namespace Toolbox.Library
|
|||
shader.SetFloat("scale", Runtime.bonePointSize * BonePointScale);
|
||||
shader.SetMatrix4x4("ModelMatrix", ref bn.ModelMatrix);
|
||||
|
||||
|
||||
|
||||
Matrix4 transform = bn.Transform;
|
||||
|
||||
shader.SetMatrix4x4("bone", ref transform);
|
||||
|
|
Binary file not shown.
|
@ -42,13 +42,15 @@ namespace Toolbox.Library
|
|||
return datas;
|
||||
}
|
||||
|
||||
public static Bitmap Resize(Image original, Size size)
|
||||
{
|
||||
public static Bitmap Resize(Image original, Size size) {
|
||||
return ResizeImage(original, size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static Bitmap Resize(Image original, int width, int height)
|
||||
{
|
||||
public static Bitmap Resize(Image original, uint width, uint height) {
|
||||
return ResizeImage(original, (int)width, (int)height);
|
||||
}
|
||||
|
||||
public static Bitmap Resize(Image original, int width, int height) {
|
||||
return ResizeImage(original, width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace Toolbox.Library
|
||||
{
|
||||
|
@ -68,6 +69,39 @@ namespace Toolbox.Library
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] ETC1Encode(byte[] Input, int Width, int Height, bool Alpha)
|
||||
{
|
||||
long OOffset = 0;
|
||||
int IOffset = 0;
|
||||
|
||||
var mem = new System.IO.MemoryStream();
|
||||
using (var writer = new FileWriter(mem))
|
||||
{
|
||||
for (int TY = 0; TY < Height; TY += 8)
|
||||
{
|
||||
for (int TX = 0; TX < Width; TX += 8)
|
||||
{
|
||||
for (int i = 0; i < 8; i += 4)
|
||||
{
|
||||
for (int j = 0; j < 8; j += 4)
|
||||
{
|
||||
EncodeETC1Block(writer, TX + j, TY + i, Input, IOffset, OOffset, Alpha);
|
||||
OOffset += Alpha ? 16 : 8;
|
||||
IOffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mem.ToArray();
|
||||
}
|
||||
|
||||
public static void EncodeETC1Block(FileWriter writer, int blockX, int blockY, byte[] Input, long IOffset, long OOffset, bool Alpha)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static byte[] ETC1Tile(ulong Block)
|
||||
{
|
||||
uint BlockLow = (uint)(Block >> 32);
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace Toolbox.Library
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace Toolbox.Library
|
|||
|
||||
public static TEX_FORMAT ConvertPICAToGenericFormat(PICASurfaceFormat format)
|
||||
{
|
||||
switch (format)
|
||||
switch (format)
|
||||
{
|
||||
case PICASurfaceFormat.RGB565: return TEX_FORMAT.B5G6R5_UNORM;
|
||||
case PICASurfaceFormat.RGB8: return TEX_FORMAT.R8G8_UNORM;
|
||||
|
@ -65,6 +66,7 @@ namespace Toolbox.Library
|
|||
case TEX_FORMAT.L8: return PICASurfaceFormat.L8;
|
||||
case TEX_FORMAT.A8_UNORM: return PICASurfaceFormat.A8;
|
||||
case TEX_FORMAT.LA4: return PICASurfaceFormat.LA4;
|
||||
case TEX_FORMAT.L4: return PICASurfaceFormat.L4;
|
||||
case TEX_FORMAT.A4: return PICASurfaceFormat.A4;
|
||||
case TEX_FORMAT.ETC1_UNORM: return PICASurfaceFormat.ETC1;
|
||||
case TEX_FORMAT.ETC1_A4: return PICASurfaceFormat.ETC1A4;
|
||||
|
@ -87,14 +89,24 @@ namespace Toolbox.Library
|
|||
52, 53, 60, 61, 54, 55, 62, 63
|
||||
};
|
||||
|
||||
public static byte[] DecodeBlock(byte[] Input, int Width, int Height, TEX_FORMAT Format)
|
||||
public static System.Drawing.Bitmap DecodeBlockToBitmap(byte[] Input, int Width, int Height, PICASurfaceFormat picaFormat)
|
||||
{
|
||||
if (Format == TEX_FORMAT.ETC1_UNORM || Format == TEX_FORMAT.ETC1_A4)
|
||||
return ETC1.ETC1Decompress(Input, Width, Height, Format == TEX_FORMAT.ETC1_A4);
|
||||
return BitmapExtension.GetBitmap(DecodeBlock(Input, Width, Height, picaFormat),
|
||||
Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
|
||||
}
|
||||
|
||||
public static byte[] DecodeBlock(byte[] Input, int Width, int Height, TEX_FORMAT Format) {
|
||||
return DecodeBlock(Input, Width, Height, ConvertToPICAFormat(Format));
|
||||
}
|
||||
|
||||
public static byte[] DecodeBlock(byte[] Input, int Width, int Height, PICASurfaceFormat picaFormat)
|
||||
{
|
||||
if (picaFormat == PICASurfaceFormat.ETC1 || picaFormat == PICASurfaceFormat.ETC1A4)
|
||||
return ETC1.ETC1Decompress(Input, Width, Height, picaFormat == PICASurfaceFormat.ETC1A4);
|
||||
|
||||
byte[] Output = new byte[Width * Height * 4];
|
||||
|
||||
int Increment = FmtBPP[(int)ConvertToPICAFormat(Format)] / 8;
|
||||
int Increment = FmtBPP[(int)picaFormat] / 8;
|
||||
if (Increment == 0) Increment = 1;
|
||||
|
||||
int IOffset = 0;
|
||||
|
@ -110,83 +122,75 @@ namespace Toolbox.Library
|
|||
|
||||
int OOffet = (TX + X + ((Height - 1 - (TY + Y)) * Width)) * 4;
|
||||
|
||||
switch (Format)
|
||||
switch (picaFormat)
|
||||
{
|
||||
case TEX_FORMAT.R8G8_UNORM:
|
||||
case PICASurfaceFormat.RGBA8:
|
||||
Output[OOffet + 0] = Input[IOffset + 3];
|
||||
Output[OOffet + 1] = Input[IOffset + 2];
|
||||
Output[OOffet + 2] = Input[IOffset + 1];
|
||||
Output[OOffet + 3] = Input[IOffset + 0];
|
||||
break;
|
||||
case TEX_FORMAT.R8G8B8A8_UNORM:
|
||||
case PICASurfaceFormat.RGB8:
|
||||
Output[OOffet + 0] = Input[IOffset + 2];
|
||||
Output[OOffet + 1] = Input[IOffset + 1];
|
||||
Output[OOffet + 2] = Input[IOffset + 0];
|
||||
Output[OOffet + 3] = 0xff;
|
||||
break;
|
||||
case TEX_FORMAT.B5G5R5A1_UNORM:
|
||||
case PICASurfaceFormat.RGBA5551:
|
||||
DecodeRGBA5551(Output, OOffet, GetUShort(Input, IOffset));
|
||||
break;
|
||||
case TEX_FORMAT.B5G6R5_UNORM:
|
||||
case PICASurfaceFormat.RGB565:
|
||||
DecodeRGB565(Output, OOffet, GetUShort(Input, IOffset));
|
||||
break;
|
||||
case TEX_FORMAT.B4G4R4A4_UNORM:
|
||||
case PICASurfaceFormat.RGBA4:
|
||||
DecodeRGBA4(Output, OOffet, GetUShort(Input, IOffset));
|
||||
break;
|
||||
case TEX_FORMAT.LA8:
|
||||
case PICASurfaceFormat.LA8:
|
||||
Output[OOffet + 0] = Input[IOffset + 1];
|
||||
Output[OOffet + 1] = Input[IOffset + 1];
|
||||
Output[OOffet + 2] = Input[IOffset + 1];
|
||||
Output[OOffet + 3] = Input[IOffset + 0];
|
||||
break;
|
||||
case TEX_FORMAT.HIL08:
|
||||
case PICASurfaceFormat.HiLo8:
|
||||
Output[OOffet + 0] = Input[IOffset + 1];
|
||||
Output[OOffet + 1] = Input[IOffset + 0];
|
||||
Output[OOffet + 2] = 0;
|
||||
Output[OOffet + 3] = 0xff;
|
||||
break;
|
||||
case TEX_FORMAT.L8:
|
||||
case PICASurfaceFormat.L8:
|
||||
Output[OOffet + 0] = Input[IOffset];
|
||||
Output[OOffet + 1] = Input[IOffset];
|
||||
Output[OOffet + 2] = Input[IOffset];
|
||||
Output[OOffet + 3] = 0xff;
|
||||
break;
|
||||
|
||||
case TEX_FORMAT.A8_UNORM:
|
||||
case PICASurfaceFormat.A8:
|
||||
Output[OOffet + 0] = 0xff;
|
||||
Output[OOffet + 1] = 0xff;
|
||||
Output[OOffet + 2] = 0xff;
|
||||
Output[OOffet + 3] = Input[IOffset];
|
||||
break;
|
||||
case TEX_FORMAT.LA4:
|
||||
case PICASurfaceFormat.LA4:
|
||||
Output[OOffet + 0] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0));
|
||||
Output[OOffet + 1] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0));
|
||||
Output[OOffet + 2] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0));
|
||||
Output[OOffet + 3] = (byte)((Input[IOffset] << 4) | (Input[IOffset] & 0x0f));
|
||||
break;
|
||||
case TEX_FORMAT.L4:
|
||||
case PICASurfaceFormat.L4:
|
||||
int L = (Input[IOffset >> 1] >> ((IOffset & 1) << 2)) & 0xf;
|
||||
Output[OOffet + 0] = (byte)((L << 4) | L);
|
||||
Output[OOffet + 1] = (byte)((L << 4) | L);
|
||||
Output[OOffet + 2] = (byte)((L << 4) | L);
|
||||
Output[OOffet + 3] = 0xff;
|
||||
break;
|
||||
case TEX_FORMAT.A4:
|
||||
case PICASurfaceFormat.A4:
|
||||
int A = (Input[IOffset >> 1] >> ((IOffset & 1) << 2)) & 0xf;
|
||||
|
||||
Output[OOffet + 0] = 0xff;
|
||||
Output[OOffet + 1] = 0xff;
|
||||
Output[OOffet + 2] = 0xff;
|
||||
Output[OOffet + 3] = (byte)((A << 4) | A);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Output[OOffet + 0] = 0xff;
|
||||
Output[OOffet + 1] = 0xff;
|
||||
Output[OOffet + 2] = 0xff;
|
||||
Output[OOffet + 3] = Input[IOffset];
|
||||
|
||||
IOffset += Increment;
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +199,166 @@ namespace Toolbox.Library
|
|||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] EncodeBlock(byte[] Input, int Width, int Height, TEX_FORMAT Format) {
|
||||
return EncodeBlock(Input, Width, Height, ConvertToPICAFormat(Format));
|
||||
}
|
||||
|
||||
|
||||
//Much help from encoding thanks to this
|
||||
// https://github.com/Cruel/3dstex/blob/master/src/Encoder.cpp
|
||||
public static byte[] EncodeBlock(byte[] Input, int Width, int Height, PICASurfaceFormat PicaFormat)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
var mem = new System.IO.MemoryStream();
|
||||
using (var writer = new FileWriter(mem))
|
||||
{
|
||||
for (int TY = 0; TY < Height; TY += 8)
|
||||
{
|
||||
for (int TX = 0; TX < Width; TX += 8)
|
||||
{
|
||||
for (int Px = 0; Px < 64; Px++)
|
||||
{
|
||||
int X = SwizzleLUT[Px] & 7;
|
||||
int Y = (SwizzleLUT[Px] - X) >> 3;
|
||||
|
||||
int IOffs = (TX + X + ((TY + Y) * Width)) * 4;
|
||||
if (PicaFormat == PICASurfaceFormat.RGBA8)
|
||||
{
|
||||
writer.Write(Input[IOffs + 3]);
|
||||
writer.Write(Input[IOffs + 0]);
|
||||
writer.Write(Input[IOffs + 1]);
|
||||
writer.Write(Input[IOffs + 2]);
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.RGB8)
|
||||
{
|
||||
writer.Write(Input[IOffs + 0]);
|
||||
writer.Write(Input[IOffs + 1]);
|
||||
writer.Write(Input[IOffs + 2]);
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.A8)
|
||||
{
|
||||
writer.Write(Input[IOffs]);
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.L8)
|
||||
{
|
||||
writer.Write(ConvertBRG8ToL(
|
||||
new byte[]
|
||||
{
|
||||
Input[IOffs + 0],
|
||||
Input[IOffs + 1],
|
||||
Input[IOffs + 2]
|
||||
}));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.LA8)
|
||||
{
|
||||
writer.Write(Input[IOffs + 3]);
|
||||
writer.Write(ConvertBRG8ToL(
|
||||
new byte[]
|
||||
{
|
||||
Input[IOffs + 0],
|
||||
Input[IOffs + 1],
|
||||
Input[IOffs + 2]
|
||||
}));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.RGB565)
|
||||
{
|
||||
ushort R = (ushort)(Convert8To5(Input[IOffs + 0]));
|
||||
ushort G = (ushort)(Convert8To6(Input[IOffs + 1]) << 5);
|
||||
ushort B = (ushort)(Convert8To5(Input[IOffs + 2]) << 11);
|
||||
|
||||
writer.Write((ushort)(R | G | B));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.RGBA4)
|
||||
{
|
||||
ushort R = (ushort)(Convert8To4(Input[IOffs]) << 4);
|
||||
ushort G = (ushort)(Convert8To4(Input[IOffs + 1]) << 8);
|
||||
ushort B = (ushort)(Convert8To4(Input[IOffs + 2]) << 12);
|
||||
ushort A = (ushort)(Convert8To4(Input[IOffs + 3]));
|
||||
|
||||
writer.Write((ushort)(R | G | B | A));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.RGBA5551)
|
||||
{
|
||||
ushort R = (ushort)(Convert8To5(Input[IOffs + 0]) << 1);
|
||||
ushort G = (ushort)(Convert8To5(Input[IOffs + 1]) << 6);
|
||||
ushort B = (ushort)(Convert8To5(Input[IOffs + 2]) << 11);
|
||||
ushort A = (ushort)(Convert8To1(Input[IOffs + 3]));
|
||||
|
||||
writer.Write((ushort)(R | G | B | A));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.LA4)
|
||||
{
|
||||
byte A = Input[IOffs + 3];
|
||||
byte L = ConvertBRG8ToL(
|
||||
new byte[]
|
||||
{
|
||||
Input[IOffs + 0],
|
||||
Input[IOffs + 1],
|
||||
Input[IOffs + 2]
|
||||
});
|
||||
writer.Write((byte)((A >> 4) | (L & 0xF0)));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.L4)
|
||||
{
|
||||
//Todo this has issues
|
||||
byte L1 = ConvertBRG8ToL(
|
||||
new byte[]
|
||||
{
|
||||
Input[IOffs + 0],
|
||||
Input[IOffs + 1],
|
||||
Input[IOffs + 2]
|
||||
});
|
||||
|
||||
writer.Write((byte)(L1 >> 4));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.A4)
|
||||
{
|
||||
//Todo this has issues
|
||||
byte A1 = (byte)(Input[IOffs] >> 4);
|
||||
byte A2 = (byte)(Input[IOffs + 3] & 0xF0);
|
||||
writer.Write((byte)(A1 | A2));
|
||||
}
|
||||
else if (PicaFormat == PICASurfaceFormat.HiLo8)
|
||||
{
|
||||
writer.Write(Input[IOffs]);
|
||||
writer.Write(Input[IOffs + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] newOutput = mem.ToArray();
|
||||
if (newOutput.Length > 0)
|
||||
return newOutput;
|
||||
else
|
||||
return new byte[CalculateLength(Width, Height, PicaFormat)];
|
||||
}
|
||||
|
||||
// Convert helpers from Citra Emulator (citra/src/common/color.h)
|
||||
private static byte Convert8To1(byte val) { return (byte)(val == 0 ? 0 : 1); }
|
||||
private static byte Convert8To4(byte val) { return (byte)(val >> 4); }
|
||||
private static byte Convert8To5(byte val) { return (byte)(val >> 3); }
|
||||
private static byte Convert8To6(byte val) { return (byte)(val >> 2); }
|
||||
|
||||
private static byte ConvertBRG8ToL(byte[] bytes)
|
||||
{
|
||||
byte L = (byte)(bytes[0] * 0.0722f);
|
||||
L += (byte)(bytes[1] * 0.7152f);
|
||||
L += (byte)(bytes[2] * 0.2126f);
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
private static void DecodeRGB565(byte[] Buffer, int Address, ushort Value)
|
||||
{
|
||||
int R = ((Value >> 0) & 0x1f) << 3;
|
||||
|
@ -245,5 +409,17 @@ namespace Toolbox.Library
|
|||
Buffer[Address + 0] << 0 |
|
||||
Buffer[Address + 1] << 8);
|
||||
}
|
||||
|
||||
public static int CalculateLength(int Width, int Height, PICASurfaceFormat Format)
|
||||
{
|
||||
int Length = (Width * Height * FmtBPP[(int)Format]) / 8;
|
||||
|
||||
if ((Length & 0x7f) != 0) {
|
||||
Length = (Length & ~0x7f) + 0x80;
|
||||
}
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -199,6 +199,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Animations\Animation.cs" />
|
||||
<Compile Include="Animations\AnimationGroupNode.cs" />
|
||||
<Compile Include="Animations\AnimationRewrite\STAnimation.cs" />
|
||||
<Compile Include="Animations\ImageKeyFrame.cs" />
|
||||
<Compile Include="Animations\VisibilityAnimation.cs" />
|
||||
<Compile Include="Animations\BooleanKeyFrame.cs" />
|
||||
|
@ -242,6 +243,10 @@
|
|||
<Compile Include="Forms\Editors\Object Editor\SearchNodeForm.Designer.cs">
|
||||
<DependentUpon>SearchNodeForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\Editors\TextureImport\3DS\CTR_3DSImporterSettings.cs" />
|
||||
<Compile Include="Forms\Editors\TextureImport\3DS\CTR_3DSTextureImporter.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\Editors\TextureImport\GenericTextureImporterList.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -954,6 +959,9 @@
|
|||
<EmbeddedResource Include="Forms\Editors\Animation\TimeLine.resx">
|
||||
<DependentUpon>TimeLine.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\Editors\TextureImport\3DS\CTR_3DSTextureImporter.resx">
|
||||
<DependentUpon>CTR_3DSTextureImporter.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\Editors\TextureImport\GenericTextureImporterList.resx">
|
||||
<DependentUpon>GenericTextureImporterList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
Binary file not shown.
1
Toolbox/MainForm.Designer.cs
generated
1
Toolbox/MainForm.Designer.cs
generated
|
@ -522,4 +522,3 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem tutorialToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Loading…
Reference in a new issue