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 @@ + +