diff --git a/LibEveryFileExplorer/GFX/DTX.cs b/LibEveryFileExplorer/GFX/DTX.cs
new file mode 100644
index 0000000..653164b
--- /dev/null
+++ b/LibEveryFileExplorer/GFX/DTX.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+
+namespace LibEveryFileExplorer.GFX
+{
+ public class DTX
+ {
+ public static uint[] DecodeDTX1(ushort Color0, ushort Color1, uint Data)
+ {
+ uint[] Palette = new uint[4];
+ Palette[0] = GFXUtil.ConvertColorFormat(Color0, ColorFormat.RGB565, ColorFormat.ARGB8888);
+ Palette[1] = GFXUtil.ConvertColorFormat(Color1, ColorFormat.RGB565, ColorFormat.ARGB8888);
+ Color a = Color.FromArgb((int)Palette[0]);
+ Color b = Color.FromArgb((int)Palette[1]);
+ if (Color0 > Color1)//1/3 and 2/3
+ {
+ Palette[2] = GFXUtil.ToColorFormat((a.R * 2 + b.R * 1) / 3, (a.G * 2 + b.G * 1) / 3, (a.B * 2 + b.B * 1) / 3, ColorFormat.ARGB8888);
+ Palette[3] = GFXUtil.ToColorFormat((a.R * 1 + b.R * 2) / 3, (a.G * 1 + b.G * 2) / 3, (a.B * 1 + b.B * 2) / 3, ColorFormat.ARGB8888);
+ }
+ else//1/2 and transparent
+ {
+ Palette[2] = GFXUtil.ToColorFormat((a.R + b.R) / 2, (a.G + b.G) / 2, (a.B + b.B) / 2, ColorFormat.ARGB8888);
+ Palette[3] = 0;
+ }
+
+ uint[] Result = new uint[4 * 4];
+
+ int q = 30;
+ for (int y = 0; y < 4; y++)
+ {
+ for (int x = 0; x < 4; x++)
+ {
+ Result[y * 4 + x] = Palette[(Data >> q) & 3];
+ q -= 2;
+ }
+ }
+ return Result;
+ }
+
+ public static uint[] DecodeDTX5(ushort Color0, ushort Color1, uint Data, ulong AData)
+ {
+ uint[] Result = DecodeDTX1(Color0, Color1, Data);
+ byte[] AlphaPalette = new byte[8];
+ AlphaPalette[0] = (byte)(AData & 0xFF);
+ AlphaPalette[1] = (byte)((AData >> 8) & 0xFF);
+ AData >>= 16;
+ if (AlphaPalette[0] > AlphaPalette[1])
+ {
+ AlphaPalette[2] = (byte)((6 * AlphaPalette[0] + 1 * AlphaPalette[1]) / 7);
+ AlphaPalette[3] = (byte)((5 * AlphaPalette[0] + 2 * AlphaPalette[1]) / 7);
+ AlphaPalette[4] = (byte)((4 * AlphaPalette[0] + 3 * AlphaPalette[1]) / 7);
+ AlphaPalette[5] = (byte)((3 * AlphaPalette[0] + 4 * AlphaPalette[1]) / 7);
+ AlphaPalette[6] = (byte)((2 * AlphaPalette[0] + 5 * AlphaPalette[1]) / 7);
+ AlphaPalette[7] = (byte)((1 * AlphaPalette[0] + 6 * AlphaPalette[1]) / 7);
+ }
+ else
+ {
+ AlphaPalette[2] = (byte)((4 * AlphaPalette[0] + 1 * AlphaPalette[1]) / 5);
+ AlphaPalette[3] = (byte)((3 * AlphaPalette[0] + 2 * AlphaPalette[1]) / 5);
+ AlphaPalette[4] = (byte)((2 * AlphaPalette[0] + 3 * AlphaPalette[1]) / 5);
+ AlphaPalette[5] = (byte)((1 * AlphaPalette[0] + 4 * AlphaPalette[1]) / 5);
+ AlphaPalette[6] = 0;
+ AlphaPalette[7] = 255;
+ }
+ int aq = 45;
+ for (int i = 0; i < 16; i++)
+ {
+ Result[i] = (Result[i] & 0xFFFFFF) | ((uint)AlphaPalette[(AData >> aq) & 7] << 24);
+ aq -= 3;
+ }
+ return Result;
+ }
+ }
+}
diff --git a/LibEveryFileExplorer/IO/IOUtil.cs b/LibEveryFileExplorer/IO/IOUtil.cs
index e72490b..5cca080 100644
--- a/LibEveryFileExplorer/IO/IOUtil.cs
+++ b/LibEveryFileExplorer/IO/IOUtil.cs
@@ -82,6 +82,11 @@ namespace LibEveryFileExplorer.IO
return (ulong)Data[Offset] | ((ulong)Data[Offset + 1] << 8) | ((ulong)Data[Offset + 2] << 16) | ((ulong)Data[Offset + 3] << 24) | ((ulong)Data[Offset + 4] << 32) | ((ulong)Data[Offset + 5] << 40) | ((ulong)Data[Offset + 6] << 48) | ((ulong)Data[Offset + 7] << 56);
}
+ public static ulong ReadU64BE(byte[] Data, int Offset)
+ {
+ return ((ulong)Data[Offset] << 56) | ((ulong)Data[Offset + 1] << 48) | ((ulong)Data[Offset + 2] << 40) | ((ulong)Data[Offset + 3] << 32) | ((ulong)Data[Offset + 4] << 24) | ((ulong)Data[Offset + 5] << 16) | ((ulong)Data[Offset + 6] << 8) | ((ulong)Data[Offset + 7] << 0);
+ }
+
public static void WriteU64LE(byte[] Data, int Offset, ulong Value)
{
Data[Offset] = (byte)(Value & 0xFF);
diff --git a/LibEveryFileExplorer/LibEveryFileExplorer.csproj b/LibEveryFileExplorer/LibEveryFileExplorer.csproj
index 4ab4e32..3f293ea 100644
--- a/LibEveryFileExplorer/LibEveryFileExplorer.csproj
+++ b/LibEveryFileExplorer/LibEveryFileExplorer.csproj
@@ -58,6 +58,7 @@
+
diff --git a/LibEveryFileExplorer/UI/GameDataSectionViewer.cs b/LibEveryFileExplorer/UI/GameDataSectionViewer.cs
index 5ab2c94..5770e9f 100644
--- a/LibEveryFileExplorer/UI/GameDataSectionViewer.cs
+++ b/LibEveryFileExplorer/UI/GameDataSectionViewer.cs
@@ -48,14 +48,15 @@ namespace LibEveryFileExplorer.UI
}
if (listViewNF1.SelectedIndices.Count != 0) buttonRemove.Enabled = buttonUp.Enabled = buttonDown.Enabled = true;
else buttonRemove.Enabled = buttonUp.Enabled = buttonDown.Enabled = false;
- if (!RemovingSelection && listViewNF1.SelectedIndices.Count == 0 && OnSelected != null) OnSelected(null, null);
+ //if (!RemovingSelection && listViewNF1.SelectedIndices.Count == 0 && OnSelected != null) OnSelected(null, null);
}
Timer t;
void listViewNF1_SelectedIndexChanged(object sender, EventArgs e)
{
- t.Interval = 100;
+ if (!RemovingSelection && listViewNF1.SelectedIndices.Count == 0 && OnSelected != null) OnSelected(null, null);
+ t.Interval = 10;//100;
t.Enabled = true;
}
@@ -164,6 +165,7 @@ namespace LibEveryFileExplorer.UI
bool RemovingSelection = false;
public void RemoveSelection()
{
+ if (listViewNF1.SelectedIndices.Count == 0) return;
RemovingSelection = true;
listViewNF1.SelectedItems.Clear();
RemovingSelection = false;
diff --git a/MarioKart/MarioKart.csproj b/MarioKart/MarioKart.csproj
index addcfa8..3bdb27b 100644
--- a/MarioKart/MarioKart.csproj
+++ b/MarioKart/MarioKart.csproj
@@ -124,6 +124,12 @@
+
+ UserControl
+
+
+ MKDSRouteViewer.cs
+
Form
@@ -178,6 +184,9 @@
CDMDViewer.cs
+
+ MKDSRouteViewer.cs
+
NKMDViewer2.cs
diff --git a/MarioKart/UI/MKDSRouteViewer.Designer.cs b/MarioKart/UI/MKDSRouteViewer.Designer.cs
new file mode 100644
index 0000000..fdb91f3
--- /dev/null
+++ b/MarioKart/UI/MKDSRouteViewer.Designer.cs
@@ -0,0 +1,252 @@
+namespace MarioKart.UI
+{
+ partial class MKDSRouteViewer
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MKDSRouteViewer));
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ this.listViewNF1 = new LibEveryFileExplorer.UI.ListViewNF();
+ this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+ this.toolStrip2 = new System.Windows.Forms.ToolStrip();
+ this.listViewNF2 = new LibEveryFileExplorer.UI.ListViewNF();
+ this.buttonAdd = new System.Windows.Forms.ToolStripButton();
+ this.buttonRemove = new System.Windows.Forms.ToolStripButton();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.buttonUp = new System.Windows.Forms.ToolStripButton();
+ this.buttonDown = new System.Windows.Forms.ToolStripButton();
+ this.buttonRouteAdd = new System.Windows.Forms.ToolStripButton();
+ this.buttonRouteRemove = new System.Windows.Forms.ToolStripButton();
+ this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.buttonRouteUp = new System.Windows.Forms.ToolStripButton();
+ this.buttonRouteDown = new System.Windows.Forms.ToolStripButton();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ this.toolStrip1.SuspendLayout();
+ this.toolStrip2.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // splitContainer1
+ //
+ this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+ this.splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ this.splitContainer1.Panel1.Controls.Add(this.listViewNF2);
+ this.splitContainer1.Panel1.Controls.Add(this.toolStrip1);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.Controls.Add(this.listViewNF1);
+ this.splitContainer1.Panel2.Controls.Add(this.toolStrip2);
+ this.splitContainer1.Size = new System.Drawing.Size(474, 369);
+ this.splitContainer1.SplitterDistance = 173;
+ this.splitContainer1.TabIndex = 0;
+ //
+ // listViewNF1
+ //
+ this.listViewNF1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.listViewNF1.FullRowSelect = true;
+ this.listViewNF1.GridLines = true;
+ this.listViewNF1.HideSelection = false;
+ this.listViewNF1.Location = new System.Drawing.Point(0, 25);
+ this.listViewNF1.Name = "listViewNF1";
+ this.listViewNF1.Size = new System.Drawing.Size(297, 344);
+ this.listViewNF1.TabIndex = 0;
+ this.listViewNF1.UseCompatibleStateImageBehavior = false;
+ this.listViewNF1.View = System.Windows.Forms.View.Details;
+ //
+ // toolStrip1
+ //
+ this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.buttonRouteAdd,
+ this.buttonRouteRemove,
+ this.toolStripSeparator2,
+ this.buttonRouteUp,
+ this.buttonRouteDown});
+ this.toolStrip1.Location = new System.Drawing.Point(0, 0);
+ this.toolStrip1.Name = "toolStrip1";
+ this.toolStrip1.Size = new System.Drawing.Size(173, 25);
+ this.toolStrip1.TabIndex = 0;
+ this.toolStrip1.Text = "toolStrip1";
+ //
+ // toolStrip2
+ //
+ this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.buttonAdd,
+ this.buttonRemove,
+ this.toolStripSeparator1,
+ this.buttonUp,
+ this.buttonDown});
+ this.toolStrip2.Location = new System.Drawing.Point(0, 0);
+ this.toolStrip2.Name = "toolStrip2";
+ this.toolStrip2.Size = new System.Drawing.Size(297, 25);
+ this.toolStrip2.TabIndex = 1;
+ this.toolStrip2.Text = "toolStrip2";
+ //
+ // listViewNF2
+ //
+ this.listViewNF2.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.listViewNF2.FullRowSelect = true;
+ this.listViewNF2.GridLines = true;
+ this.listViewNF2.HideSelection = false;
+ this.listViewNF2.Location = new System.Drawing.Point(0, 25);
+ this.listViewNF2.MultiSelect = false;
+ this.listViewNF2.Name = "listViewNF2";
+ this.listViewNF2.Size = new System.Drawing.Size(173, 344);
+ this.listViewNF2.TabIndex = 1;
+ this.listViewNF2.UseCompatibleStateImageBehavior = false;
+ this.listViewNF2.View = System.Windows.Forms.View.Details;
+ this.listViewNF2.SelectedIndexChanged += new System.EventHandler(this.listViewNF2_SelectedIndexChanged);
+ //
+ // buttonAdd
+ //
+ this.buttonAdd.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonAdd.Image = ((System.Drawing.Image)(resources.GetObject("buttonAdd.Image")));
+ this.buttonAdd.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonAdd.Name = "buttonAdd";
+ this.buttonAdd.Size = new System.Drawing.Size(23, 22);
+ this.buttonAdd.Text = "Add";
+ //
+ // buttonRemove
+ //
+ this.buttonRemove.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonRemove.Image = ((System.Drawing.Image)(resources.GetObject("buttonRemove.Image")));
+ this.buttonRemove.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonRemove.Name = "buttonRemove";
+ this.buttonRemove.Size = new System.Drawing.Size(23, 22);
+ this.buttonRemove.Text = "Remove";
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
+ //
+ // buttonUp
+ //
+ this.buttonUp.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonUp.Image = ((System.Drawing.Image)(resources.GetObject("buttonUp.Image")));
+ this.buttonUp.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonUp.Name = "buttonUp";
+ this.buttonUp.Size = new System.Drawing.Size(23, 22);
+ this.buttonUp.Text = "Up";
+ //
+ // buttonDown
+ //
+ this.buttonDown.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonDown.Image = ((System.Drawing.Image)(resources.GetObject("buttonDown.Image")));
+ this.buttonDown.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonDown.Name = "buttonDown";
+ this.buttonDown.Size = new System.Drawing.Size(23, 22);
+ this.buttonDown.Text = "Down";
+ //
+ // buttonRouteAdd
+ //
+ this.buttonRouteAdd.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonRouteAdd.Image = ((System.Drawing.Image)(resources.GetObject("buttonRouteAdd.Image")));
+ this.buttonRouteAdd.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonRouteAdd.Name = "buttonRouteAdd";
+ this.buttonRouteAdd.Size = new System.Drawing.Size(23, 22);
+ this.buttonRouteAdd.Text = "Add";
+ //
+ // buttonRouteRemove
+ //
+ this.buttonRouteRemove.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonRouteRemove.Image = ((System.Drawing.Image)(resources.GetObject("buttonRouteRemove.Image")));
+ this.buttonRouteRemove.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonRouteRemove.Name = "buttonRouteRemove";
+ this.buttonRouteRemove.Size = new System.Drawing.Size(23, 22);
+ this.buttonRouteRemove.Text = "Remove";
+ //
+ // toolStripSeparator2
+ //
+ this.toolStripSeparator2.Name = "toolStripSeparator2";
+ this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25);
+ //
+ // buttonRouteUp
+ //
+ this.buttonRouteUp.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonRouteUp.Image = ((System.Drawing.Image)(resources.GetObject("buttonRouteUp.Image")));
+ this.buttonRouteUp.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonRouteUp.Name = "buttonRouteUp";
+ this.buttonRouteUp.Size = new System.Drawing.Size(23, 22);
+ this.buttonRouteUp.Text = "Up";
+ //
+ // buttonRouteDown
+ //
+ this.buttonRouteDown.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+ this.buttonRouteDown.Image = ((System.Drawing.Image)(resources.GetObject("buttonRouteDown.Image")));
+ this.buttonRouteDown.ImageTransparentColor = System.Drawing.Color.Magenta;
+ this.buttonRouteDown.Name = "buttonRouteDown";
+ this.buttonRouteDown.Size = new System.Drawing.Size(23, 22);
+ this.buttonRouteDown.Text = "Down";
+ //
+ // MKDSRouteViewer
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.splitContainer1);
+ this.Name = "MKDSRouteViewer";
+ this.Size = new System.Drawing.Size(474, 369);
+ this.Load += new System.EventHandler(this.MKDSRouteViewer_Load);
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel1.PerformLayout();
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ this.splitContainer1.Panel2.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+ this.splitContainer1.ResumeLayout(false);
+ this.toolStrip1.ResumeLayout(false);
+ this.toolStrip1.PerformLayout();
+ this.toolStrip2.ResumeLayout(false);
+ this.toolStrip2.PerformLayout();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ private LibEveryFileExplorer.UI.ListViewNF listViewNF2;
+ private System.Windows.Forms.ToolStrip toolStrip1;
+ private LibEveryFileExplorer.UI.ListViewNF listViewNF1;
+ private System.Windows.Forms.ToolStrip toolStrip2;
+ internal System.Windows.Forms.ToolStripButton buttonRouteAdd;
+ internal System.Windows.Forms.ToolStripButton buttonRouteRemove;
+ internal System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+ internal System.Windows.Forms.ToolStripButton buttonRouteUp;
+ internal System.Windows.Forms.ToolStripButton buttonRouteDown;
+ internal System.Windows.Forms.ToolStripButton buttonAdd;
+ internal System.Windows.Forms.ToolStripButton buttonRemove;
+ internal System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+ internal System.Windows.Forms.ToolStripButton buttonUp;
+ internal System.Windows.Forms.ToolStripButton buttonDown;
+ }
+}
diff --git a/MarioKart/UI/MKDSRouteViewer.cs b/MarioKart/UI/MKDSRouteViewer.cs
new file mode 100644
index 0000000..5d7c4c3
--- /dev/null
+++ b/MarioKart/UI/MKDSRouteViewer.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using LibEveryFileExplorer.UI;
+using MarioKart.MKDS.NKM;
+
+namespace MarioKart.UI
+{
+ public partial class MKDSRouteViewer : UserControl, IGameDataSectionViewer
+ {
+ PATH Routes;
+ POIT Points;
+ public MKDSRouteViewer(PATH Routes, POIT Points)
+ {
+ this.Routes = Routes;
+ this.Points = Points;
+ InitializeComponent();
+ }
+
+ private void listViewNF2_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ RefreshPoints();
+ }
+
+ public event SelectedEventHandler OnSelected;
+
+ public void RefreshListView()
+ {
+ int[] sel = null;
+ if (listViewNF2.SelectedIndices.Count != 0)
+ {
+ sel = new int[listViewNF2.SelectedIndices.Count];
+ listViewNF2.SelectedIndices.CopyTo(sel, 0);
+ }
+ listViewNF2.BeginUpdate();
+ listViewNF2.Items.Clear();
+ listViewNF2.Items.AddRange(Routes.GetListViewItems());
+ listViewNF2.EndUpdate();
+ if (sel != null)
+ {
+ foreach (int i in sel)
+ {
+ if (i < Routes.Entries.Count) listViewNF2.SelectedIndices.Add(i);
+ }
+ }
+ RefreshPoints();
+ }
+
+ private void RefreshPoints()
+ {
+ if (listViewNF2.SelectedIndices.Count != 0)
+ {
+ listViewNF1.BeginUpdate();
+ listViewNF1.Items.Clear();
+ int idx = 0;
+ int q = 0;
+ foreach (var o in Routes.Entries)
+ {
+ if (Points.NrEntries < o.NrPoit + idx) break;
+ if (q == listViewNF2.SelectedIndices[0])
+ {
+ for (int i = 0; i < o.NrPoit; i++)
+ {
+ var v = Points[idx + i].GetListViewItem();
+ v.Text = (idx + i).ToString();
+ listViewNF1.Items.Add(v);
+ }
+ break;
+ }
+ idx += o.NrPoit;
+ q++;
+ }
+ listViewNF1.EndUpdate();
+ }
+ else
+ {
+ listViewNF1.BeginUpdate();
+ listViewNF1.Items.Clear();
+ listViewNF1.EndUpdate();
+ }
+ }
+
+ private void MKDSRouteViewer_Load(object sender, EventArgs e)
+ {
+ listViewNF1.BeginUpdate();
+ listViewNF1.Columns.Clear();
+ foreach (String s in Points.GetColumnNames()) listViewNF1.Columns.Add(s);
+ listViewNF1.EndUpdate();
+
+ listViewNF2.BeginUpdate();
+ listViewNF2.Columns.Clear();
+ foreach (String s in Routes.GetColumnNames()) listViewNF2.Columns.Add(s);
+ listViewNF2.EndUpdate();
+ RefreshListView();
+ }
+
+ public void UpdateListViewEntry(params object[] Entries)
+ {
+ //throw new NotImplementedException();
+ }
+
+ public void Select(params object[] Entries)
+ {
+ //throw new NotImplementedException();
+ }
+
+ public void RemoveSelection()
+ {
+ //throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MarioKart/UI/MKDSRouteViewer.resx b/MarioKart/UI/MKDSRouteViewer.resx
new file mode 100644
index 0000000..0243de7
--- /dev/null
+++ b/MarioKart/UI/MKDSRouteViewer.resx
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 122, 17
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFVSURBVDhPtY67L8NRGIaPSzpI0R+tVNuEFBGqiaYTdYlL
+ xK3ULUFE1CYmdpvF0MUgOlhI3WMh5roHR8Igqc3IX/H6vpMTQ7VNfoMneZI373fe5Ij/49ARF8cOqeRs
+ mgO7jH6vYuFrBZx1a4KEXU5/LoHlrFsT7Bpy7GMRkVQUnHVrgh1DDrzNov91Bpx1m4W4LS626VGaPc+T
+ 6HocR6ab2vyyZZPh93n0yinwqPtpQg1br4fQcjWIjvtRtN+NoO02jNDNsMq80Wtis1TyVzsfIkoe8LDx
+ PITqo4DSnWiCa88HT8IP70kQvNFrIlYcFzGrTNdz5ofr1IdMN7XJyYZVOi8bUHFRD866NcG6VdqTdShP
+ 1oKzbk2wViTLXmpgSC8469YEyxZppLxgOes2J4Wkm2wmg6Ivb1/M5UslZ+6ECJBVpIX8Qz5ZQjpJVxYr
+ SRtZQBJC/ADGtKxvV2OcbwAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACtSURBVDhPYxgFgwUsY2CYuZyB4QwpGKQHqp2BYS5Q4F1a
+ 2v/H0dH/74aG/r/u7///kpfX/7Ourv9POzv/P+no+P+Eg8P/4/b2/4/Z2YHZID1Q7QwMfUDO8/j4/7eC
+ gv5f8fH5f87NDawJpPiore3/IzY2/w9bW/8/ZGX1/6ClJZgG6YFqZ5CJZmBYVAEUIAWD9ID0ggzgA2Ih
+ IBYHYikiMUgtSA9I7yigDDAwAADO52St0AETFQAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGESURBVDhPtYtNKMNhHMdneSmkSBMHciCUKCuRl4sclIOD
+ KH9J5CInB9luLuLgLcawixWx1hrZxsFF4/I4kJSXzctMpO2g1iT29fzyeMmG/8WnPj19f9/vo/g3qg23
+ UpXhltErTvKpmLuRKmc8TO8F6KUsqr8pn7qQynSXbNoDaHcfobsCKNNdTH5GPXYiqUeO2dRlCD0bDx+O
+ u15Ad+rFNJyiwQOpaOiQTbhf0LXqD3P46AnU0058+SR/YE8qGNhjo6fP0OwE0O8MoNvuQ5PxHC1LbnRY
+ LtBmcqFv+x60o734+kaudkefo3Gyr7abXagZY2hdPsP3jvbia2SyerdYs8mNqsl9NC67QFlU8kjvtrE6
+ sxfFs2eoXbkGZVHJI7XTwkqtfmQa71Bi8YGyqOSRKC2xnPUgkkwBZK8FQVlU8ohvWmAqRwhKawgp9hAo
+ i0oeMQ3zTLUJJNqAZAdAWVS/EsfN45ZElfcuKutn2LuU6c4t5CZwIxLNTeVm/GIaN5YrUCheAR5z8efG
+ /ZWxAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGISURBVDhPtYtJKMRhGManYUrWlGRkqSklF+tFGAeccFC2
+ w5+yxAEHIcVBnLigSEY4GKUx2TPCZCscfA6KgyxDJsyF0GTUNI/vzWfJ+r/41a+v53ueV/EvpA7bdNqh
+ a/YqZVHJI6X/gvWeAV1HLvRYAMqikkdi3znrOHCieduB9n0nKItKHgmdh6x114GaxXu07DyCsqjkEd2x
+ z5q37aiYvUHTlh2URSWPqLZd1rB+hwK9BZVzVlAWlTwimjZZycQJ0rsZigzHoCyq7wmpNevC61bYRwuN
+ p9D27iHPcILPHe3F6QtB1SZJXWVi1Zt3yJq+QubUJVJGzxEzcIwk/RkyjFakj1uRO28D7WgvTt8JLJuU
+ AsqnWP7GA8L0ti+mLdyCetqJk6/4FBskb2mMadee4Gu0vxm75AD9Uy+mP+NVqJc8C0ZY5KoLyhkXNGYX
+ KNO/mPyNMrlRUuUMsuBlgF7KovoVFTeUG8eNV8aV1iuz+xm9lIUargf3W9y4flw1N/gH/bnuXIFC8QzC
+ r+rkeChKNQAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFVSURBVDhPtY67L8NRGIaPSzpI0R+tVNuEFBGqiaYTdYlL
+ xK3ULUFE1CYmdpvF0MUgOlhI3WMh5roHR8Igqc3IX/H6vpMTQ7VNfoMneZI373fe5Ij/49ARF8cOqeRs
+ mgO7jH6vYuFrBZx1a4KEXU5/LoHlrFsT7Bpy7GMRkVQUnHVrgh1DDrzNov91Bpx1m4W4LS626VGaPc+T
+ 6HocR6ab2vyyZZPh93n0yinwqPtpQg1br4fQcjWIjvtRtN+NoO02jNDNsMq80Wtis1TyVzsfIkoe8LDx
+ PITqo4DSnWiCa88HT8IP70kQvNFrIlYcFzGrTNdz5ofr1IdMN7XJyYZVOi8bUHFRD866NcG6VdqTdShP
+ 1oKzbk2wViTLXmpgSC8469YEyxZppLxgOes2J4Wkm2wmg6Ivb1/M5UslZ+6ECJBVpIX8Qz5ZQjpJVxYr
+ SRtZQBJC/ADGtKxvV2OcbwAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACtSURBVDhPYxgFgwUsY2CYuZyB4QwpGKQHqp2BYS5Q4F1a
+ 2v/H0dH/74aG/r/u7///kpfX/7Ourv9POzv/P+no+P+Eg8P/4/b2/4/Z2YHZID1Q7QwMfUDO8/j4/7eC
+ gv5f8fH5f87NDawJpPiore3/IzY2/w9bW/8/ZGX1/6ClJZgG6YFqZ5CJZmBYVAEUIAWD9ID0ggzgA2Ih
+ IBYHYikiMUgtSA9I7yigDDAwAADO52St0AETFQAAAABJRU5ErkJggg==
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGESURBVDhPtYtNKMNhHMdneSmkSBMHciCUKCuRl4sclIOD
+ KH9J5CInB9luLuLgLcawixWx1hrZxsFF4/I4kJSXzctMpO2g1iT29fzyeMmG/8WnPj19f9/vo/g3qg23
+ UpXhltErTvKpmLuRKmc8TO8F6KUsqr8pn7qQynSXbNoDaHcfobsCKNNdTH5GPXYiqUeO2dRlCD0bDx+O
+ u15Ad+rFNJyiwQOpaOiQTbhf0LXqD3P46AnU0058+SR/YE8qGNhjo6fP0OwE0O8MoNvuQ5PxHC1LbnRY
+ LtBmcqFv+x60o734+kaudkefo3Gyr7abXagZY2hdPsP3jvbia2SyerdYs8mNqsl9NC67QFlU8kjvtrE6
+ sxfFs2eoXbkGZVHJI7XTwkqtfmQa71Bi8YGyqOSRKC2xnPUgkkwBZK8FQVlU8ohvWmAqRwhKawgp9hAo
+ i0oeMQ3zTLUJJNqAZAdAWVS/EsfN45ZElfcuKutn2LuU6c4t5CZwIxLNTeVm/GIaN5YrUCheAR5z8efG
+ /ZWxAAAAAElFTkSuQmCC
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGISURBVDhPtYtJKMRhGManYUrWlGRkqSklF+tFGAeccFC2
+ w5+yxAEHIcVBnLigSEY4GKUx2TPCZCscfA6KgyxDJsyF0GTUNI/vzWfJ+r/41a+v53ueV/EvpA7bdNqh
+ a/YqZVHJI6X/gvWeAV1HLvRYAMqikkdi3znrOHCieduB9n0nKItKHgmdh6x114GaxXu07DyCsqjkEd2x
+ z5q37aiYvUHTlh2URSWPqLZd1rB+hwK9BZVzVlAWlTwimjZZycQJ0rsZigzHoCyq7wmpNevC61bYRwuN
+ p9D27iHPcILPHe3F6QtB1SZJXWVi1Zt3yJq+QubUJVJGzxEzcIwk/RkyjFakj1uRO28D7WgvTt8JLJuU
+ AsqnWP7GA8L0ti+mLdyCetqJk6/4FBskb2mMadee4Gu0vxm75AD9Uy+mP+NVqJc8C0ZY5KoLyhkXNGYX
+ KNO/mPyNMrlRUuUMsuBlgF7KovoVFTeUG8eNV8aV1iuz+xm9lIUargf3W9y4flw1N/gH/bnuXIFC8QzC
+ r+rkeChKNQAAAABJRU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/MarioKart/UI/NKMDViewer2.cs b/MarioKart/UI/NKMDViewer2.cs
index f6fe6b5..93f9346 100644
--- a/MarioKart/UI/NKMDViewer2.cs
+++ b/MarioKart/UI/NKMDViewer2.cs
@@ -49,6 +49,15 @@ namespace MarioKart.UI
if (NKMD.ObjectInformation != null) AddTab("OBJI", NKMD.ObjectInformation);
if (NKMD.Path != null) AddTab("PATH", NKMD.Path);
if (NKMD.Point != null) AddTab("POIT", NKMD.Point);
+ if (NKMD.Path != null && NKMD.Point != null)
+ {
+ TabPage p = new TabPage("Routes");
+ var vv = new MKDSRouteViewer(NKMD.Path, NKMD.Point) { Dock = DockStyle.Fill };
+ vv.OnSelected += new SelectedEventHandler(GameDataSectionViewer_OnSelected);
+ SectionViewers.Add(vv);
+ p.Controls.Add(vv);
+ tabControl1.TabPages.Add(p);
+ }
if (NKMD.KartPointStart != null) AddTab("KTPS", NKMD.KartPointStart);
if (NKMD.KartPointJugem != null) AddTab("KTPJ", NKMD.KartPointJugem);
if (NKMD.KartPointSecond != null) AddTab("KTP2", NKMD.KartPointSecond);
diff --git a/WiiU/GPU/R600Tiling.cs b/WiiU/GPU/R600Tiling.cs
new file mode 100644
index 0000000..9b4f08b
--- /dev/null
+++ b/WiiU/GPU/R600Tiling.cs
@@ -0,0 +1,731 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WiiU.GPU
+{
+ public class R600Tiling
+ {
+ private static readonly uint[] bankSwapOrder = { 0, 1, 3, 2, 6, 7, 5, 4 };
+
+ uint m_class = 6;
+ uint m_chipFamily = 0;
+ uint m_chipRevision = 0;
+ uint m_version = 502;
+ uint m_pElemLib = 0;
+ uint m_pipes = 2;//0;
+ uint m_banks = 8;//0;
+ uint m_pipeInterleaveBytes = 256;
+ uint m_rowSize = 2048;//0;
+ uint m_backendDisables = 0;
+ uint m_configFlags = 0;
+
+ uint m_swapSize = 256;//0;
+ uint m_splitSize = 2048;//0;
+
+ public struct _ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT
+ {
+ public uint size; //dd ?
+ public uint x; // dd ?
+ public uint y; //dd ?
+ public uint slice; //dd ?
+ public uint sample; //dd ?
+ public uint bpp; //dd ?
+ public uint pitch; //dd ?
+ public uint height; //dd ?
+ public uint numSlices; //dd ?
+ public uint numSamples; //dd ?
+ public int tileMode; // dd ? ; enum _AddrTileMode
+ public bool isDepth; //dd ?
+ public uint tileBase; //dd ?
+ public uint compBits; // dd ?
+ public uint pipeSwizzle; //dd ?
+ public uint bankSwizzle; //dd ?
+ public uint numFrags; //dd ?
+ public int tileType; //dd ? ; enum _AddrTileType
+ public uint _bf72; //dd ?
+ public uint pTileInfo; //dd ? ; offset
+ public uint tileIndex; //dd ?
+ }
+
+ public struct _ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT
+ {
+ public uint size; // dd ?
+ //byte db ? ; undefined
+ //byte db ? ; undefined
+ //byte db ? ; undefined
+ //byte db ? ; undefined
+ public ulong addr; // dq ?
+ public uint bitPosition; // dd ?
+ //byte _padding db 4 dup(?)
+ }
+
+ public ulong ComputeSurfaceAddrFromCoord(/*R600AddrLib *this, */ref _ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT pIn, ref _ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT pOut)
+ {
+ /* _AddrTileMode*/
+ int v3; // ecx@4
+ ulong v4 = 0; // qax@5
+ ulong result; // qax@9
+ /*_AddrTileMode*/
+ int v6; // [sp+4h] [bp-4Ch]@1
+ uint v7; // [sp+8h] [bp-48h]@2
+ //uint /***/pBitPosition; // [sp+Ch] [bp-44h]@4
+ uint bankSwizzle; // [sp+10h] [bp-40h]@4
+ uint pipeSwizzle; // [sp+14h] [bp-3Ch]@4
+ uint compBits; // [sp+18h] [bp-38h]@4
+ uint tileBase; // [sp+1Ch] [bp-34h]@4
+ bool isDepth; // [sp+20h] [bp-30h]@4
+ /*_AddrTileMode*/
+ int tileMode; // [sp+24h] [bp-2Ch]@4
+ uint numSamples; // [sp+28h] [bp-28h]@4
+ uint numSlices; // [sp+2Ch] [bp-24h]@1
+ uint height; // [sp+30h] [bp-20h]@1
+ uint pitch; // [sp+34h] [bp-1Ch]@1
+ uint bpp; // [sp+38h] [bp-18h]@1
+ uint sample; // [sp+3Ch] [bp-14h]@1
+ uint slice; // [sp+40h] [bp-10h]@1
+ uint y; // [sp+44h] [bp-Ch]@1
+ uint x; // [sp+48h] [bp-8h]@1
+ // AddrLib *thisa; // [sp+4Ch] [bp-4h]@1
+
+ //memset(&v6, -858993460, 0x4Cu);
+ // thisa = (AddrLib *)this;
+ x = pIn.x;
+ y = pIn.y;
+ slice = pIn.slice;
+ sample = pIn.sample;
+ bpp = pIn.bpp;
+ pitch = pIn.pitch;
+ height = pIn.height;
+ numSlices = pIn.numSlices;
+ if (pIn.numSamples != 0)
+ v7 = pIn.numSamples;
+ else
+ v7 = 1;
+ numSamples = v7;
+ tileMode = pIn.tileMode;
+ isDepth = pIn.isDepth;
+ tileBase = pIn.tileBase;
+ compBits = pIn.compBits;
+ pipeSwizzle = pIn.pipeSwizzle;
+ bankSwizzle = pIn.bankSwizzle;
+ //pBitPosition = &pOut->bitPosition;
+ v6 = tileMode;
+ v3 = tileMode;
+ switch (tileMode)
+ {
+ case 0:
+ case 1:
+ /*v4 = ComputeSurfaceAddrFromCoordLinear(
+ thisa,
+ x,
+ y,
+ slice,
+ sample,
+ bpp,
+ pitch,
+ height,
+ numSlices,
+ pBitPosition);*/
+ break;
+ case 2:
+ case 3:
+ /* v4 = ComputeSurfaceAddrFromCoordMicroTiled(
+ (R600AddrLib *)thisa,
+ x,
+ y,
+ slice,
+ bpp,
+ pitch,
+ height,
+ tileMode,
+ isDepth,
+ tileBase,
+ compBits,
+ pBitPosition);*/
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ v4 = ComputeSurfaceAddrFromCoordMacroTiled(
+ //(R600AddrLib *)thisa,
+ x,
+ y,
+ slice,
+ sample,
+ bpp,
+ pitch,
+ height,
+ numSamples,
+ tileMode,
+ isDepth,
+ tileBase,
+ compBits,
+ pipeSwizzle,
+ bankSwizzle,
+ out pOut.bitPosition);// pBitPosition);
+ break;
+ default:
+ v4 = 0;
+ //HIDWORD(v4) = 0;
+ break;
+ }
+ //LODWORD(result) = _RTC_CheckEsp(v3, HIDWORD(v4));
+ //return result;
+ return v4;
+ }
+
+ private static uint Log2_0(uint x)
+ {
+ uint y; // [sp+0h] [bp-4h]@1
+
+ y = 0;
+ while (x > 1)
+ {
+ x >>= 1;
+ ++y;
+ }
+ return y;
+ }
+
+ private ulong ComputeSurfaceAddrFromCoordMacroTiled(/*R600AddrLib *this, */uint x, uint y, uint slice, uint sample, uint bpp, uint pitch, uint height, uint numSamples, /*_AddrTileMode*/int tileMode, bool isDepth, uint tileBase, uint compBits, uint pipeSwizzle, uint bankSwizzle, /*unsigned int **/out uint pBitPosition)
+ {
+ /*_AddrTileType*/
+ int v16; // eax@1
+ ulong v17; // qax@24
+ ulong result; // qax@24
+ int v19; // [sp+8h] [bp-C8h]@1
+ uint swapIndex; // [sp+Ch] [bp-C4h]@23
+ uint bankSwapWidth; // [sp+10h] [bp-C0h]@23
+ uint sliceIn; // [sp+14h] [bp-BCh]@12
+ uint bankPipe; // [sp+18h] [bp-B8h]@12
+ uint swizzle; // [sp+1Ch] [bp-B4h]@12
+ uint rotation; // [sp+20h] [bp-B0h]@12
+ uint tileSliceBits; // [sp+24h] [bp-ACh]@10
+ uint bytesPerSample; // [sp+28h] [bp-A8h]@8
+ uint numBanks; // [sp+2Ch] [bp-A4h]@1
+ uint numPipes; // [sp+30h] [bp-A0h]@1
+ ulong groupMask; // [sp+34h] [bp-9Ch]@24
+ uint elemOffset; // [sp+54h] [bp-7Ch]@8
+ uint pixelOffset; // [sp+58h] [bp-78h]@4
+ uint sampleOffset; // [sp+5Ch] [bp-74h]@4
+ uint pixelIndex; // [sp+60h] [bp-70h]@1
+ ulong macroTileOffset; // [sp+64h] [bp-6Ch]@17
+ uint macroTileIndexY; // [sp+6Ch] [bp-64h]@17
+ uint macroTileIndexX; // [sp+70h] [bp-60h]@17
+ long macroTileBytes; // [sp+74h] [bp-5Ch]@17
+ uint macroTilesPerRow; // [sp+7Ch] [bp-54h]@17
+ uint macroTileHeight; // [sp+80h] [bp-50h]@14
+ uint macroTilePitch; // [sp+84h] [bp-4Ch]@14
+ ulong sliceOffset; // [sp+88h] [bp-48h]@14
+ ulong sliceBytes; // [sp+90h] [bp-40h]@14
+ uint microTileThickness; // [sp+98h] [bp-38h]@1
+ uint bank; // [sp+9Ch] [bp-34h]@12
+ uint pipe; // [sp+A0h] [bp-30h]@12
+ uint sampleSlice; // [sp+A4h] [bp-2Ch]@10
+ uint numSampleSplits; // [sp+A8h] [bp-28h]@10
+ uint samplesPerSlice; // [sp+ACh] [bp-24h]@10
+ uint microTileBits; // [sp+B0h] [bp-20h]@1
+ uint microTileBytes; // [sp+B4h] [bp-1Ch]@1
+ uint numBankBits; // [sp+B8h] [bp-18h]@1
+ uint numPipeBits; // [sp+BCh] [bp-14h]@1
+ uint numGroupBits; // [sp+C0h] [bp-10h]@1
+ //R600AddrLib *thisa; // [sp+CCh] [bp-4h]@1
+
+ numPipes = this/*->baseclass_0*/.m_pipes;
+ numBanks = this/*->baseclass_0*/.m_banks;
+ numGroupBits = Log2_0(this/*->baseclass_0*/.m_pipeInterleaveBytes);
+ numPipeBits = Log2_0(this/*a->baseclass_0*/.m_pipes);
+ numBankBits = Log2_0(this/*a->baseclass_0*/.m_banks);
+ microTileThickness = ComputeSurfaceThickness(tileMode);
+ microTileBits = numSamples * bpp * (microTileThickness << 6);
+ microTileBytes = numSamples * bpp * (microTileThickness << 6) >> 3;
+ v16 = GetTileType(isDepth);
+ pixelIndex = ComputePixelIndexWithinMicroTile(/*&thisa->baseclass_0,*/ x, y, slice, bpp, tileMode, v16);
+ if (isDepth)
+ {
+ if (compBits != 0 && compBits != bpp)
+ {
+ sampleOffset = tileBase + compBits * sample;
+ pixelOffset = numSamples * compBits * pixelIndex;
+ }
+ else
+ {
+ sampleOffset = bpp * sample;
+ pixelOffset = numSamples * bpp * pixelIndex;
+ }
+ }
+ else
+ {
+ sampleOffset = sample * microTileBits / numSamples;
+ pixelOffset = bpp * pixelIndex;
+ }
+ elemOffset = pixelOffset + sampleOffset;
+ pBitPosition = (pixelOffset + sampleOffset) % 8;//*pBitPosition = (pixelOffset + sampleOffset) % 8;
+ bytesPerSample = microTileBytes / numSamples;
+ if (numSamples <= 1 || microTileBytes <= this/*a->*/.m_splitSize)
+ {
+ samplesPerSlice = numSamples;
+ numSampleSplits = 1;
+ sampleSlice = 0;
+ }
+ else
+ {
+ samplesPerSlice = this/*a->*/.m_splitSize / bytesPerSample;
+ numSampleSplits = numSamples / samplesPerSlice;
+ numSamples = samplesPerSlice;
+ tileSliceBits = microTileBits / numSampleSplits;
+ sampleSlice = elemOffset / (microTileBits / numSampleSplits);
+ elemOffset %= microTileBits / numSampleSplits;
+ }
+ elemOffset >>= 3;
+ pipe = ComputePipeFromCoordWoRotation(/*thisa, */x, y);
+ bank = ComputeBankFromCoordWoRotation(/*thisa, */x, y);
+ bankPipe = pipe + numPipes * bank;
+ rotation = ComputeSurfaceRotationFromTileMode(/*thisa, */tileMode);
+ swizzle = pipeSwizzle + numPipes * bankSwizzle;
+ sliceIn = slice;
+ if (IsThickMacroTiled(tileMode))
+ sliceIn >>= 2;
+ bankPipe ^= numPipes * sampleSlice * ((numBanks >> 1) + 1) ^ (swizzle + sliceIn * rotation);
+ bankPipe %= numPipes * numBanks;
+ pipe = bankPipe % numPipes;
+ bank = bankPipe / numPipes;
+ sliceBytes = (height * (ulong)pitch * microTileThickness * bpp * numSamples + 7) / 8;
+ sliceOffset = sliceBytes * (sampleSlice + numSampleSplits * slice) / microTileThickness;
+ macroTilePitch = 8 * this/*a->baseclass_0*/.m_banks;
+ macroTileHeight = 8 * this/*a->baseclass_0*/.m_pipes;
+ v19 = tileMode - 5;
+ switch (tileMode)
+ {
+ case 5:
+ case 9:
+ macroTilePitch >>= 1;
+ macroTileHeight *= 2;
+ break;
+ case 6:
+ case 10:
+ macroTilePitch >>= 2;
+ macroTileHeight *= 4;
+ break;
+ default:
+ break;
+ }
+ macroTilesPerRow = pitch / macroTilePitch;
+ macroTileBytes = (numSamples * microTileThickness * bpp * macroTileHeight * macroTilePitch + 7) >> 3;
+ macroTileIndexX = x / macroTilePitch;
+ macroTileIndexY = y / macroTileHeight;
+ macroTileOffset = (x / macroTilePitch + pitch / macroTilePitch * y / macroTileHeight)
+ * (ulong)((numSamples * microTileThickness * bpp * macroTileHeight * macroTilePitch + 7) >> 3);
+ if (tileMode == 8 || tileMode == 9 || tileMode == 10 || tileMode == 11 || tileMode == 14 || tileMode == 15)
+ {
+ uint nop;
+ bankSwapWidth = ComputeSurfaceBankSwappedWidth(/*thisa,*/ tileMode, bpp, numSamples, pitch, out nop);//0);
+ swapIndex = macroTilePitch * macroTileIndexX / bankSwapWidth;
+ bank ^= bankSwapOrder[swapIndex & (this/*a->baseclass_0*/.m_banks - 1)];
+ }
+ v17 = elemOffset + ((macroTileOffset + sliceOffset) >> ((byte)numBankBits + (byte)numPipeBits));
+ groupMask = (1u << (int)numGroupBits) - 1;
+ ulong addr = ((v17 & (ulong)~(long)((1 << (int)numGroupBits) - 1)) << ((byte)numBankBits
+ + (byte)numPipeBits)) | groupMask & v17 | (pipe << (int)numGroupBits);
+ addr = addr | (bank << (int)(numPipeBits + numGroupBits));
+ return addr;
+ }
+
+ private static bool IsBankSwappedTileMode(/*_AddrTileMode*/ int tileMode)
+ {
+ bool bankSwapped; // [sp+4h] [bp-4h]@1
+
+ bankSwapped = false;
+ switch (tileMode)
+ {
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 14:
+ case 15:
+ bankSwapped = true;
+ break;
+ default:
+ return bankSwapped;
+ }
+ return bankSwapped;
+ }
+
+ private static uint ComputeMacroTileAspectRatio(/*_AddrTileMode*/int tileMode)
+ {
+ uint ratio; // [sp+4h] [bp-4h]@1
+
+ ratio = 1;
+ switch (tileMode)
+ {
+ case 8:
+ case 12:
+ case 14:
+ ratio = 1;
+ break;
+ case 5:
+ case 9:
+ ratio = 2;
+ break;
+ case 6:
+ case 10:
+ ratio = 4;
+ break;
+ default:
+ return ratio;
+ }
+ return ratio;
+ }
+
+ private uint ComputeSurfaceBankSwappedWidth(/*R600AddrLib *this, *//*_AddrTileMode*/int tileMode, uint bpp, uint numSamples, uint pitch, out uint /***/pSlicesPerTile)
+ {
+ uint v6; // edx@6
+ uint v7; // ecx@6
+ uint v9; // [sp+4h] [bp-54h]@1
+ uint v10; // [sp+8h] [bp-50h]@11
+ uint v11; // [sp+Ch] [bp-4Ch]@8
+ uint swapMin; // [sp+10h] [bp-48h]@10
+ uint swapMax; // [sp+14h] [bp-44h]@10
+ uint heightBytes; // [sp+18h] [bp-40h]@10
+ uint swapWidth; // [sp+1Ch] [bp-3Ch]@10
+ uint swapTiles; // [sp+20h] [bp-38h]@7
+ uint factor; // [sp+24h] [bp-34h]@7
+ uint bytesPerTileSlice; // [sp+28h] [bp-30h]@6
+ uint samplesPerTile; // [sp+2Ch] [bp-2Ch]@1
+ uint bytesPerSample; // [sp+30h] [bp-28h]@1
+ int slicesPerTile; // [sp+34h] [bp-24h]@1
+ uint groupSize; // [sp+38h] [bp-20h]@1
+ uint splitSize; // [sp+3Ch] [bp-1Ch]@1
+ uint rowSize; // [sp+40h] [bp-18h]@1
+ uint swapSize; // [sp+44h] [bp-14h]@1
+ uint numPipes; // [sp+48h] [bp-10h]@1
+ uint numBanks; // [sp+4Ch] [bp-Ch]@1
+ uint bankSwapWidth; // [sp+50h] [bp-8h]@1
+ /*R600AddrLib *thisa;*/
+ // [sp+54h] [bp-4h]@1
+
+ //memset(&v9, -858993460, 0x54u);
+ //thisa = this;
+ bankSwapWidth = 0;
+ numBanks = this/*->baseclass_0*/.m_banks;
+ numPipes = this/*->baseclass_0*/.m_pipes;
+ swapSize = this/*->*/.m_swapSize;
+ rowSize = this/*->baseclass_0*/.m_rowSize;
+ splitSize = this/*->*/.m_splitSize;
+ groupSize = this/*->baseclass_0*/.m_pipeInterleaveBytes;
+ slicesPerTile = 1;
+ bytesPerSample = 8 * bpp & 0x1FFFFFFF;
+ samplesPerTile = splitSize / bytesPerSample;
+ if ((splitSize / bytesPerSample) != 0)
+ {
+ slicesPerTile = (int)(numSamples / samplesPerTile);
+ if ((numSamples / samplesPerTile) == 0)
+ slicesPerTile = 1;
+ }
+ pSlicesPerTile = (uint)slicesPerTile;
+ //SafeAssign_2(pSlicesPerTile, slicesPerTile);
+ if (IsThickMacroTiled(tileMode))
+ numSamples = 4;
+ bytesPerTileSlice = (uint)(numSamples * bytesPerSample / slicesPerTile);
+ if (IsBankSwappedTileMode(tileMode))
+ {
+ factor = ComputeMacroTileAspectRatio(tileMode);
+ swapTiles = (swapSize >> 1) / bpp;
+ if (swapTiles != 0)
+ v11 = swapTiles;
+ else
+ v11 = 1;
+ v7 = v11 * 8 * numBanks;
+ swapWidth = v11 * 8 * numBanks;
+ heightBytes = (uint)(numSamples * factor * numPipes * bpp / slicesPerTile);
+ swapMax = numPipes * numBanks * rowSize / heightBytes;
+ swapMin = groupSize * 8 * numBanks / bytesPerTileSlice;
+ if (numPipes * numBanks * rowSize / heightBytes >= swapWidth)
+ {
+ if (swapMin <= swapWidth)
+ v9 = swapWidth;
+ else
+ v9 = swapMin;
+ v7 = v9;
+ v10 = v9;
+ }
+ else
+ {
+ v10 = swapMax;
+ }
+ v6 = v10;
+ for (bankSwapWidth = v10; bankSwapWidth >= 2 * pitch; bankSwapWidth >>= 1)
+ v7 = bankSwapWidth >> 1;
+ }
+ return bankSwapWidth;//_RTC_CheckEsp(v7, v6);
+ }
+
+ private static bool IsThickMacroTiled(/*_AddrTileMode*/int tileMode)
+ {
+ bool thickMacroTiled; // [sp+4h] [bp-4h]@1
+
+ thickMacroTiled = false;
+ switch (tileMode)
+ {
+ case 7:
+ case 11:
+ case 13:
+ case 15:
+ thickMacroTiled = true;
+ break;
+ default:
+ return thickMacroTiled;
+ }
+ return thickMacroTiled;
+ }
+
+ private uint ComputeSurfaceRotationFromTileMode(/*R600AddrLib *this, *//*_AddrTileMode*/int tileMode)
+ {
+ uint result; // eax@2
+ uint v3; // [sp+0h] [bp-14h]@4
+ uint pipes; // [sp+Ch] [bp-8h]@1
+
+ pipes = this/*->baseclass_0*/.m_pipes;
+ switch (tileMode)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ result = pipes * ((this/*->baseclass_0*/.m_banks >> 1) - 1);
+ break;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if (pipes >= 4)
+ v3 = (pipes >> 1) - 1;
+ else
+ v3 = 1;
+ result = v3;
+ break;
+ default:
+ result = 0;
+ break;
+ }
+ return result;
+ }
+
+ private uint ComputePipeFromCoordWoRotation(/*R600AddrLib *this, */uint x, uint y)
+ {
+ int pipe; // [sp+14h] [bp-8h]@2
+
+ switch (this/*->baseclass_0*/.m_pipes)
+ {
+ case 1u:
+ pipe = 0;
+ break;
+ case 2u:
+ pipe = ((byte)(y >> 3) ^ (byte)(x >> 3)) & 1;
+ break;
+ case 4u:
+ pipe = ((byte)(y >> 3) ^ (byte)(x >> 4)) & 1 | 2
+ * (((byte)(y >> 4) ^ (byte)(x >> 3)) & 1);
+ break;
+ case 8u:
+ pipe = ((byte)(y >> 3) ^ (byte)(x >> 5)) & 1 | 2
+ * (((byte)(y >> 4) ^ (byte)((x >> 5) ^ (x >> 4))) & 1) | 4 * (((byte)(y >> 5) ^ (byte)(x >> 3)) & 1);
+ break;
+ default:
+ pipe = 0;
+ break;
+ }
+ return (uint)pipe;
+ }
+
+ private uint ComputeBankFromCoordWoRotation(/*R600AddrLib *this, */uint x, uint y)
+ {
+ uint bankOpt; // [sp+8h] [bp-20h]@1
+ uint numBanks; // [sp+Ch] [bp-1Ch]@1
+ uint numPipes; // [sp+10h] [bp-18h]@1
+ uint bankBit0; // [sp+1Ch] [bp-Ch]@4
+ uint bankBit0a; // [sp+1Ch] [bp-Ch]@8
+ uint bank; // [sp+20h] [bp-8h]@3
+
+ numPipes = this/*->baseclass_0*/.m_pipes;
+ numBanks = this/*->baseclass_0*/.m_banks;
+ bankOpt = (this/*->baseclass_0*/.m_configFlags/*.value*/ >> 1) & 1;
+ if (numBanks == 4)
+ {
+ bankBit0 = (y / (16 * numPipes) ^ (byte)(x >> 3)) & 1;
+ if (bankOpt == 1 && numPipes == 8)
+ bankBit0 ^= x / 0x20 & 1;
+ bank = bankBit0 | 2 * ((y / (8 * numPipes) ^ (byte)(x >> 4)) & 1);
+ }
+ else
+ {
+ if (this/*->baseclass_0*/.m_banks == 8)
+ {
+ bankBit0a = (y / (32 * numPipes) ^ (byte)(x >> 3)) & 1;
+ if (bankOpt == 1 && numPipes == 8)
+ bankBit0a ^= x / (8 * numBanks) & 1;
+ bank = bankBit0a | 2 * ((y / (32 * numPipes) ^ (byte)(y / (16 * numPipes) ^ (x >> 4))) & 1) | 4 * ((y / (8 * numPipes) ^ (byte)(x >> 5)) & 1);
+ }
+ else
+ {
+ bank = 0;
+ }
+ }
+ return bank;
+ }
+
+ private static int GetTileType(bool isDepth)
+ {
+ return (isDepth) ? 1 : 0;
+ }
+
+ private uint ComputePixelIndexWithinMicroTile(/*AddrLib *this,*/ uint x, uint y, uint z, uint bpp, /*_AddrTileMode*/int tileMode, /*_AddrTileType*/int microTileType)
+ {
+ uint v8; // [sp+4h] [bp-34h]@1
+ uint thickness; // [sp+8h] [bp-30h]@1
+ uint pixelBit8; // [sp+10h] [bp-28h]@1
+ uint pixelBit7; // [sp+14h] [bp-24h]@1
+ uint pixelBit6; // [sp+18h] [bp-20h]@1
+ uint pixelBit5; // [sp+1Ch] [bp-1Ch]@4
+ uint pixelBit4; // [sp+20h] [bp-18h]@4
+ uint pixelBit3; // [sp+24h] [bp-14h]@4
+ uint pixelBit2; // [sp+28h] [bp-10h]@4
+ uint pixelBit1; // [sp+2Ch] [bp-Ch]@4
+ uint pixelBit0; // [sp+30h] [bp-8h]@4
+ // AddrLib *thisa; // [sp+34h] [bp-4h]@1
+
+ // memset(&v8, -858993460, 0x34u);
+ //thisa = this;
+ pixelBit6 = 0;
+ pixelBit7 = 0;
+ pixelBit8 = 0;
+ thickness = ComputeSurfaceThickness(tileMode);
+ if (microTileType == 3)
+ {
+ pixelBit0 = x & 1;
+ pixelBit1 = y & 1;
+ pixelBit2 = z & 1;
+ pixelBit3 = (x & 2) >> 1;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (z & 2) >> 1;
+ pixelBit6 = (x & 4) >> 2;
+ pixelBit7 = (y & 4) >> 2;
+ }
+ else
+ {
+ if (microTileType != 0)
+ {
+ pixelBit0 = x & 1;
+ pixelBit1 = y & 1;
+ pixelBit2 = (x & 2) >> 1;
+ pixelBit3 = (y & 2) >> 1;
+ pixelBit4 = (x & 4) >> 2;
+ pixelBit5 = (y & 4) >> 2;
+ }
+ else
+ {
+ v8 = bpp - 8;
+ switch (bpp)
+ {
+ case 8u:
+ pixelBit0 = x & 1;
+ pixelBit1 = (x & 2) >> 1;
+ pixelBit2 = (x & 4) >> 2;
+ pixelBit3 = (y & 2) >> 1;
+ pixelBit4 = y & 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ case 0x10u:
+ pixelBit0 = x & 1;
+ pixelBit1 = (x & 2) >> 1;
+ pixelBit2 = (x & 4) >> 2;
+ pixelBit3 = y & 1;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ case 0x20u:
+ case 0x60u:
+ pixelBit0 = x & 1;
+ pixelBit1 = (x & 2) >> 1;
+ pixelBit2 = y & 1;
+ pixelBit3 = (x & 4) >> 2;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ case 0x40u:
+ pixelBit0 = x & 1;
+ pixelBit1 = y & 1;
+ pixelBit2 = (x & 2) >> 1;
+ pixelBit3 = (x & 4) >> 2;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ case 0x80u:
+ pixelBit0 = y & 1;
+ pixelBit1 = x & 1;
+ pixelBit2 = (x & 2) >> 1;
+ pixelBit3 = (x & 4) >> 2;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ default:
+ pixelBit0 = x & 1;
+ pixelBit1 = (x & 2) >> 1;
+ pixelBit2 = y & 1;
+ pixelBit3 = (x & 4) >> 2;
+ pixelBit4 = (y & 2) >> 1;
+ pixelBit5 = (y & 4) >> 2;
+ break;
+ }
+ }
+ if (thickness > 1)
+ {
+ pixelBit6 = z & 1;
+ pixelBit7 = (z & 2) >> 1;
+ }
+ }
+ if (thickness == 8) pixelBit8 = (z & 4) >> 2;
+ return (pixelBit8 << 8) | (pixelBit7 << 7) | (pixelBit6 << 6) | 32 * pixelBit5 | 16 * pixelBit4 | 8 * pixelBit3 | 4 * pixelBit2 | pixelBit0 | 2 * pixelBit1;
+ }
+
+ private static uint ComputeSurfaceThickness(/*_AddrTileMode*/int tileMode)
+ {
+ uint thickness; // [sp+4h] [bp-4h]@2
+
+ switch (tileMode)
+ {
+ case 3:
+ case 7:
+ case 11:
+ case 13:
+ case 15:
+ thickness = 4;
+ break;
+ case 16:
+ case 17:
+ thickness = 8;
+ break;
+ default:
+ thickness = 1;
+ break;
+ }
+ return thickness;
+ }
+ }
+}
diff --git a/WiiU/GPU/Textures.cs b/WiiU/GPU/Textures.cs
new file mode 100644
index 0000000..03d52a7
--- /dev/null
+++ b/WiiU/GPU/Textures.cs
@@ -0,0 +1,436 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using LibEveryFileExplorer.IO;
+using LibEveryFileExplorer.GFX;
+
+namespace WiiU.GPU
+{
+ public class Textures
+ {
+ public enum TileMode : uint
+ {
+ Default = 0,
+ LinearAligned = 1,
+ Tiled1DThin1 = 2,
+ Tiled1DThick = 3,
+ Tiled2DThin1 = 4,
+ Tiled2DThin2 = 5,
+ Tiled2DThin4 = 6,
+ Tiled2DThick = 7,
+ Tiled2BThin1 = 8,
+ Tiled2BThin2 = 9,
+ Tiled2BThin4 = 10,
+ Tiled2BThick = 11,
+ Tiled3DThin1 = 12,
+ Tiled3DThick = 13,
+ Tiled3BThin1 = 14,
+ Tiled3BThick = 15,
+ LinearSpecial = 16
+ }
+
+ public enum ImageFormat : uint
+ {
+ RGB565,
+ DXT5
+ //ETC1,
+ //ETC1A4
+ }
+
+ //private static readonly int[] Bpp = { 32, 24, 16, 16, 16, 16, 16, 8, 8, 8, 4, 4, 4, 8 };
+
+ private static readonly int[] TileOrder =
+ {
+ 0, 1, 4, 5,
+ 2, 3, 6, 7,
+
+ 8, 9, 12, 13,
+ 10, 11, 14, 15
+ };
+ //1. Swap column 1 and 2, 4 and 5 etc.
+ //2. Put back 8x8 tiles in 16x16 blocks in the order 0, 3
+ // 1, 2
+
+ private static readonly int[,] ETC1Modifiers =
+ {
+ { 2, 8 },
+ { 5, 17 },
+ { 9, 29 },
+ { 13, 42 },
+ { 18, 60 },
+ { 24, 80 },
+ { 33, 106 },
+ { 47, 183 }
+ };
+
+ //public static int GetBpp(ImageFormat Format) { return Bpp[(uint)Format]; }
+
+ public static Bitmap ToBitmap(byte[] Data, int Width, int Height, ImageFormat Format, TileMode TileMode, uint SwizzleMode, bool ExactSize = false)
+ {
+ return ToBitmap(Data, 0, Width, Height, Format, TileMode, SwizzleMode, ExactSize);
+ }
+
+ public static unsafe Bitmap ToBitmap(byte[] Data, int Offset, int Width, int Height, ImageFormat Format, TileMode TileMode, uint SwizzleMode, bool ExactSize = false)
+ {
+ if (Data == null || Data.Length < 1 || Offset < 0 || Offset >= Data.Length || Width < 1 || Height < 1) return null;
+ if (ExactSize && ((Width % 8) != 0 || (Height % 8) != 0)) return null;
+ int physicalwidth = Width;
+ int physicalheight = Height;
+ if (!ExactSize)
+ {
+ Width = 1 << (int)Math.Ceiling(Math.Log(Width, 2));
+ Height = 1 << (int)Math.Ceiling(Math.Log(Height, 2));
+ }
+ Bitmap bitm = new Bitmap(Width, Height);//physicalwidth, physicalheight);
+ BitmapData d = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
+ uint* res = (uint*)d.Scan0;
+ int offs = Offset;//0;
+ int stride = d.Stride / 4;
+ switch (Format)
+ {
+ case ImageFormat.RGB565:
+ for (int y = 0; y < Height; y++)
+ {
+ for (int x = 0; x < Width; x++)
+ {
+ //if (x >= physicalwidth) continue;
+ if (y >= physicalheight) continue;
+ res[y * stride + x] =
+ GFXUtil.ConvertColorFormat(
+ IOUtil.ReadU16LE(Data, offs),
+ ColorFormat.RGB565,
+ ColorFormat.ARGB8888);
+ offs += 2;
+ }
+ }
+ break;
+ case ImageFormat.DXT5:
+ for (int y2 = 0; y2 < Height; y2 += 4)
+ {
+ for (int x2 = 0; x2 < Width; x2 += 4)
+ {
+ ulong a_data = IOUtil.ReadU64LE(Data, offs);
+ byte[] AlphaPalette = new byte[8];
+ AlphaPalette[0] = (byte)(a_data & 0xFF);
+ AlphaPalette[1] = (byte)((a_data >> 8) & 0xFF);
+ a_data >>= 16;
+ if (AlphaPalette[0] > AlphaPalette[1])
+ {
+ AlphaPalette[2] = (byte)((6 * AlphaPalette[0] + 1 * AlphaPalette[1]) / 7);
+ AlphaPalette[3] = (byte)((5 * AlphaPalette[0] + 2 * AlphaPalette[1]) / 7);
+ AlphaPalette[4] = (byte)((4 * AlphaPalette[0] + 3 * AlphaPalette[1]) / 7);
+ AlphaPalette[5] = (byte)((3 * AlphaPalette[0] + 4 * AlphaPalette[1]) / 7);
+ AlphaPalette[6] = (byte)((2 * AlphaPalette[0] + 5 * AlphaPalette[1]) / 7);
+ AlphaPalette[7] = (byte)((1 * AlphaPalette[0] + 6 * AlphaPalette[1]) / 7);
+ }
+ else
+ {
+ AlphaPalette[2] = (byte)((4 * AlphaPalette[0] + 1 * AlphaPalette[1]) / 5);
+ AlphaPalette[3] = (byte)((3 * AlphaPalette[0] + 2 * AlphaPalette[1]) / 5);
+ AlphaPalette[4] = (byte)((2 * AlphaPalette[0] + 3 * AlphaPalette[1]) / 5);
+ AlphaPalette[5] = (byte)((1 * AlphaPalette[0] + 4 * AlphaPalette[1]) / 5);
+ AlphaPalette[6] = 0;
+ AlphaPalette[7] = 255;
+ }
+ offs += 8;
+ ushort color0 = IOUtil.ReadU16LE(Data, offs);
+ ushort color1 = IOUtil.ReadU16LE(Data, offs + 2);
+ uint data = IOUtil.ReadU32LE(Data, offs + 4);
+ uint[] Palette = new uint[4];
+ Palette[0] = GFXUtil.ConvertColorFormat(color0, ColorFormat.RGB565, ColorFormat.ARGB8888);
+ Palette[1] = GFXUtil.ConvertColorFormat(color1, ColorFormat.RGB565, ColorFormat.ARGB8888);
+ Color a = System.Drawing.Color.FromArgb((int)Palette[0]);
+ Color b = System.Drawing.Color.FromArgb((int)Palette[1]);
+ if (color0 > color1)//1/3 and 2/3
+ {
+ Palette[2] = GFXUtil.ToColorFormat((a.R * 2 + b.R * 1) / 3, (a.G * 2 + b.G * 1) / 3, (a.B * 2 + b.B * 1) / 3, ColorFormat.ARGB8888);
+ Palette[3] = GFXUtil.ToColorFormat((a.R * 1 + b.R * 2) / 3, (a.G * 1 + b.G * 2) / 3, (a.B * 1 + b.B * 2) / 3, ColorFormat.ARGB8888);
+ }
+ else//1/2 and transparent
+ {
+ Palette[2] = GFXUtil.ToColorFormat((a.R + b.R) / 2, (a.G + b.G) / 2, (a.B + b.B) / 2, ColorFormat.ARGB8888);
+ Palette[3] = 0;
+ }
+
+ int q = 30;
+ int aq = 45;
+ for (int y3 = 0; y3 < 4; y3++)
+ {
+ for (int x3 = 0; x3 < 4; x3++)
+ {
+ //if (x2 + x3 >= physicalwidth) continue;
+ if (y2 + y3 >= physicalheight) continue;
+ res[(y2 + y3) * stride + x2 + x3] = (Palette[(data >> q) & 3] & 0xFFFFFF) | ((uint)AlphaPalette[(a_data >> aq) & 7] << 24);
+ q -= 2;
+ aq -= 3;
+ }
+ }
+ offs += 8;
+ }
+ // }
+ //}
+ }
+ break;
+ /*case ImageFormat.ETC1://Some reference: http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
+ case ImageFormat.ETC1A4:
+ {
+ for (int y = 0; y < Height; y += 8)
+ {
+ for (int x = 0; x < Width; x += 8)
+ {
+ for (int i = 0; i < 8; i += 4)
+ {
+ for (int j = 0; j < 8; j += 4)
+ {
+ ulong alpha = 0xFFFFFFFFFFFFFFFF;
+ ulong data = IOUtil.ReadU64BE(Data, offs);
+ if (Format == ImageFormat.ETC1A4)
+ {
+ offs += 8;
+ alpha = IOUtil.ReadU64BE(Data, offs);
+ }
+ bool diffbit = ((data >> 33) & 1) == 1;
+ bool flipbit = ((data >> 32) & 1) == 1; //0: |||, 1: |-|
+ int r1, r2, g1, g2, b1, b2;
+ if (diffbit) //'differential' mode
+ {
+ int r = (int)((data >> 59) & 0x1F);
+ int g = (int)((data >> 51) & 0x1F);
+ int b = (int)((data >> 43) & 0x1F);
+ r1 = (r << 3) | ((r & 0x1C) >> 2);
+ g1 = (g << 3) | ((g & 0x1C) >> 2);
+ b1 = (b << 3) | ((b & 0x1C) >> 2);
+ r += (int)((data >> 56) & 0x7) << 29 >> 29;
+ g += (int)((data >> 48) & 0x7) << 29 >> 29;
+ b += (int)((data >> 40) & 0x7) << 29 >> 29;
+ r2 = (r << 3) | ((r & 0x1C) >> 2);
+ g2 = (g << 3) | ((g & 0x1C) >> 2);
+ b2 = (b << 3) | ((b & 0x1C) >> 2);
+ }
+ else //'individual' mode
+ {
+ r1 = (int)((data >> 60) & 0xF) * 0x11;
+ g1 = (int)((data >> 52) & 0xF) * 0x11;
+ b1 = (int)((data >> 44) & 0xF) * 0x11;
+ r2 = (int)((data >> 56) & 0xF) * 0x11;
+ g2 = (int)((data >> 48) & 0xF) * 0x11;
+ b2 = (int)((data >> 40) & 0xF) * 0x11;
+ }
+ int Table1 = (int)((data >> 37) & 0x7);
+ int Table2 = (int)((data >> 34) & 0x7);
+ for (int y3 = 0; y3 < 4; y3++)
+ {
+ for (int x3 = 0; x3 < 4; x3++)
+ {
+ if (x + j + x3 >= physicalwidth) continue;
+ if (y + i + y3 >= physicalheight) continue;
+
+ int val = (int)((data >> (x3 * 4 + y3)) & 0x1);
+ bool neg = ((data >> (x3 * 4 + y3 + 16)) & 0x1) == 1;
+ uint c;
+ if ((flipbit && y3 < 2) || (!flipbit && x3 < 2))
+ {
+ int add = ETC1Modifiers[Table1, val] * (neg ? -1 : 1);
+ c = GFXUtil.ToColorFormat((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add), ColorFormat.ARGB8888);
+ }
+ else
+ {
+ int add = ETC1Modifiers[Table2, val] * (neg ? -1 : 1);
+ c = GFXUtil.ToColorFormat((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add), ColorFormat.ARGB8888);
+ }
+ res[(i + y3) * stride + x + j + x3] = c;
+ }
+ }
+ offs += 8;
+ }
+ }
+ }
+ res += stride * 8;
+ }
+ }
+ break;
+ * */
+ }
+ Detile(res, stride, Width, Height, physicalwidth, physicalheight, TileMode);
+ bitm.UnlockBits(d);
+ return bitm;
+ }
+
+ private static unsafe void Detile(uint* res, int stride, int width, int height, int physicalwidth, int physicalheight, TileMode Mode)
+ {
+ switch (Mode)
+ {
+ case Textures.TileMode.Tiled2DThin1:
+ DetileTiled2DThin1(res, stride, width, height, physicalwidth, physicalheight);
+ return;
+ default:
+ throw new Exception("Unsupported Tilemode!");
+ }
+ }
+
+ //private static readonly int[] Tiled2DThin1OrderA = { 0, 1, 3, 2 };
+ //private static readonly int[] Tiled2DThin1OrderB = { 0, 2, 3, 1 };
+ private static readonly int[] Tiled2DThin1Order = { 2, 0, 1, 3 };
+
+ private static unsafe void DetileTiled2DThin1(uint* res, int stride, int width, int height, int physicalwidth, int physicalheight)
+ {
+ uint[] Result = new uint[width * height];
+ int px = 0;
+ int py = 0;
+ for (int y = 0; y < height; y += 64)
+ {
+ for (int x = 0; x < width; x += 64)
+ {
+ for (int i = 0; i < 64; i++)//y2 = 0; y2 < 64; y2 += 8)
+ {
+ int tile = i;
+ int q = Tiled2DThin1Order[(tile / 2) % 4];
+ int p = tile & ~7;
+ int xx = (p % 16) * 2 + (q % 2) * 8;
+ //if ((i / 0x20) == 1)
+ //{
+ //xx += (i % 2) * 8;
+ //}
+ /*else */xx += (i % 2) * 32;
+ int yy = p / 16 * 16 + (q / 2) * 8;
+ for (int y3 = 0; y3 < 8; y3++)
+ {
+ for (int x3 = 0; x3 < 8; x3++)
+ {
+ //if (x + x2 + x3 >= physicalwidth) continue;
+ //if (y + y3 + yy >= physicalheight) continue;
+ Result[(y + y3 + yy) * width + x + x3 + xx] = ReadPixel(res, stride, width, height, ref px, ref py);
+ }
+ }
+ }
+ }
+ }
+ /*R600Tiling t = new R600Tiling();
+ R600Tiling._ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT r = new R600Tiling._ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_INPUT();
+ r.bpp = 32;
+ r.tileMode = 4;
+ r.tileType = 0;
+ r.pitch = (uint)stride;
+ r.height = (uint)height;
+ r.numSlices = 1;
+ r.numSamples = (uint)(height * width);
+ R600Tiling._ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT o = new R600Tiling._ADDR_COMPUTE_SURFACE_ADDRFROMCOORD_OUTPUT();
+ int i = 0;
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ r.x = (uint)x;
+ r.y = (uint)y;
+ r.sample = (uint)i;
+ int pixel_number = (int)t.ComputeSurfaceAddrFromCoord(ref r, ref o);
+ /*int pixel_number = 0;
+ pixel_number |= ((x >> 0) & 1) << 0; // pn[0] = x[0]
+ pixel_number |= ((x >> 1) & 1) << 1; // pn[1] = x[1]
+ pixel_number |= ((x >> 2) & 1) << 2; // pn[2] = x[2]
+ pixel_number |= ((y >> 1) & 1) << 3; // pn[3] = y[1]
+ pixel_number |= ((y >> 0) & 1) << 4; // pn[4] = y[0]
+ pixel_number |= ((y >> 2) & 1) << 5; // pn[5] = y[2]/
+
+ Result[y * width + x] = res[(pixel_number & 0xFFF) / 4];
+ i++;
+ }
+ }*/
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ //if (x >= physicalwidth) continue;
+ if (y >= physicalheight) continue;
+ res[y * stride + x] = Result[y * width + x];
+ }
+ }
+ /*
+ //Swap columns first!
+ for (int c = 0; c < width; c += 16)
+ {
+ //Swap c + 4 and c + 8
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < 4; x++)
+ {
+ if (c + x >= physicalwidth) continue;
+ if (y >= physicalheight) continue;
+ uint a = res[y * stride + c + x + 4];
+ uint b = res[y * stride + c + x + 8];
+ res[y * stride + c + x + 4] = b;
+ res[y * stride + c + x + 8] = a;
+ }
+ }
+ }
+ uint[] Result = new uint[width * height];
+ //work in 16x16 and then in 8x8 tiles
+ int px = 0;
+ int py = 0;
+ for (int y = 0; y < height; y += 32)
+ {
+ for (int x = 0; x < width; x += 32)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ int x4 = (Tiled2DThin1OrderA[j] % 2) * 16;
+ int y4 = ((Tiled2DThin1OrderA[j] & 2) >> 1) * 16;
+ //Read out the 256 pixels needed!
+ uint[] Pixels = new uint[256];
+ for (int i = 0; i < 256; i++) Pixels[i] = ReadPixel(res, stride, width, height, ref px, ref py);
+ int idx = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ int x2 = (Tiled2DThin1OrderB[i] % 2) * 8;
+ int y2 = ((Tiled2DThin1OrderB[i] & 2) >> 1) * 8;
+ for (int y3 = 0; y3 < 8; y3++)
+ {
+ for (int x3 = 0; x3 < 8; x3++)
+ {
+ Result[(y + y2 + y3 + y4) * width + x + x2 + x3 + x4] = Pixels[idx++];
+ //res[(y + y2 + y3) * stride + x + x2 + x3] = Pixels[idx++];
+ }
+ }
+ }
+ }
+ }
+ }
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ if (x >= physicalwidth) continue;
+ if (y >= physicalheight) continue;
+ res[y * stride + x] = Result[y * width + x];
+ }
+ }
+ */
+ }
+
+ private static unsafe uint ReadPixel(uint* res, int stride, int width, int height, ref int px, ref int py)
+ {
+ if (px >= width || py >= height || px < 0 || py < 0)
+ return 0;//throw new ArgumentException("ReadPixel fail!");
+ uint result = res[py * stride + px];
+ px++;
+ if (px == width)
+ {
+ px = 0;
+ py++;
+ }
+ return result;
+ }
+
+ private static int ColorClamp(int Color)
+ {
+ if (Color > 255) Color = 255;
+ if (Color < 0) Color = 0;
+ return Color;
+ }
+
+ }
+}
diff --git a/WiiU/NintendoWare/LYT2/FLIM.cs b/WiiU/NintendoWare/LYT2/FLIM.cs
index 19a5cfa..a4a1851 100644
--- a/WiiU/NintendoWare/LYT2/FLIM.cs
+++ b/WiiU/NintendoWare/LYT2/FLIM.cs
@@ -116,7 +116,7 @@ namespace WiiU.NintendoWare.LYT2
public Byte Unknown;
//Tempoarly use 3ds stuff!
- public _3DS.GPU.Textures.ImageFormat GetGPUTextureFormat()
+ /*public _3DS.GPU.Textures.ImageFormat GetGPUTextureFormat()
{
switch (Format)
{
@@ -134,17 +134,65 @@ namespace WiiU.NintendoWare.LYT2
case 11: return _3DS.GPU.Textures.ImageFormat.ETC1A4;
case 0x12: return _3DS.GPU.Textures.ImageFormat.L4;
case 0x13: return _3DS.GPU.Textures.ImageFormat.A4;
+ //Wii U Formats:
+ case 0x17: return WiiU.GPU.Textures.ImageFormat.ETC1A4;
}
throw new Exception("Unknown Image Format!");
- }
+ }*/
}
public UInt32 DataLength;
//Tempoarly use 3ds stuff!
public Bitmap ToBitmap()
{
- if (Image.Unknown == 0) return _3DS.GPU.Textures.ToBitmap(Data, Image.Width, Image.Height, Image.GetGPUTextureFormat());
- return _3DS.GPU.Textures.ToBitmap(Data, Image.Height, Image.Width, Image.GetGPUTextureFormat());
+ if (Header.Endianness == 0xFFFE)//3ds
+ {
+ _3DS.GPU.Textures.ImageFormat f3 = 0;
+ switch (Image.Format)
+ {
+ case 0: f3 = _3DS.GPU.Textures.ImageFormat.L8; break;
+ case 1: f3 = _3DS.GPU.Textures.ImageFormat.A8; break;
+ case 2: f3 = _3DS.GPU.Textures.ImageFormat.LA4; break;
+ case 3: f3 = _3DS.GPU.Textures.ImageFormat.LA8; break;
+ case 4: f3 = _3DS.GPU.Textures.ImageFormat.HILO8; break;
+ case 5: f3 = _3DS.GPU.Textures.ImageFormat.RGB565; break;
+ case 6: f3 = _3DS.GPU.Textures.ImageFormat.RGB8; break;
+ case 7: f3 = _3DS.GPU.Textures.ImageFormat.RGBA5551; break;
+ case 8: f3 = _3DS.GPU.Textures.ImageFormat.RGBA4; break;
+ case 9: f3 = _3DS.GPU.Textures.ImageFormat.RGBA8; break;
+ case 10: f3 = _3DS.GPU.Textures.ImageFormat.ETC1; break;
+ case 11: f3 = _3DS.GPU.Textures.ImageFormat.ETC1A4; break;
+ case 0x12: f3 = _3DS.GPU.Textures.ImageFormat.L4; break;
+ case 0x13: f3 = _3DS.GPU.Textures.ImageFormat.A4; break;
+ default: throw new Exception("Unknown Image Format!");
+ }
+ if (Image.Unknown == 0) return _3DS.GPU.Textures.ToBitmap(Data, Image.Width, Image.Height, f3);
+ return _3DS.GPU.Textures.ToBitmap(Data, Image.Height, Image.Width, f3);
+ }
+ else
+ {
+ GPU.Textures.ImageFormat fu = 0;
+ switch (Image.Format)
+ {
+ //case 0: f3 = _3DS.GPU.Textures.ImageFormat.L8; break;
+ //case 1: f3 = _3DS.GPU.Textures.ImageFormat.A8; break;
+ //case 2: f3 = _3DS.GPU.Textures.ImageFormat.LA4; break;
+ //case 3: f3 = _3DS.GPU.Textures.ImageFormat.LA8; break;
+ //case 4: f3 = _3DS.GPU.Textures.ImageFormat.HILO8; break;
+ case 5: fu = GPU.Textures.ImageFormat.RGB565; break;
+ //case 6: f3 = _3DS.GPU.Textures.ImageFormat.RGB8; break;
+ //case 7: f3 = _3DS.GPU.Textures.ImageFormat.RGBA5551; break;
+ //case 8: f3 = _3DS.GPU.Textures.ImageFormat.RGBA4; break;
+ //case 9: f3 = _3DS.GPU.Textures.ImageFormat.RGBA8; break;
+ //case 10: f3 = _3DS.GPU.Textures.ImageFormat.ETC1; break;
+ //case 11: f3 = _3DS.GPU.Textures.ImageFormat.ETC1A4; break;
+ //case 0x12: f3 = _3DS.GPU.Textures.ImageFormat.L4; break;
+ //case 0x13: f3 = _3DS.GPU.Textures.ImageFormat.A4; break;
+ case 0x17: fu = GPU.Textures.ImageFormat.DXT5; break;
+ default: throw new Exception("Unknown Image Format!");
+ }
+ return GPU.Textures.ToBitmap(Data, Image.Width, Image.Height, fu, (GPU.Textures.TileMode)(Image.Unknown & 0x1F), (uint)Image.Unknown >> 5);
+ }
}
public class FLIMIdentifier : FileFormatIdentifier
diff --git a/WiiU/WiiU.csproj b/WiiU/WiiU.csproj
index 2ffdb3e..6c46a8f 100644
--- a/WiiU/WiiU.csproj
+++ b/WiiU/WiiU.csproj
@@ -21,6 +21,7 @@
DEBUG;TRACE
prompt
4
+ true
pdbonly
@@ -42,6 +43,8 @@
+
+