diff --git a/.gitignore b/.gitignore
index 3c4efe2..3a8542d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
+*.rsuser
*.suo
*.user
*.userosscache
@@ -10,6 +13,9 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# Mono auto generated files
+mono_crash.*
+
# Build results
[Dd]ebug/
[Dd]ebugPublic/
@@ -17,42 +23,62 @@
[Rr]eleases/
x64/
x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
+[Ll]ogs/
-# Visual Studio 2015 cache/options directory
+# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
-# NUNIT
+# NUnit
*.VisualState.xml
TestResult.xml
+nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
-# DNX
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
*_i.c
*_p.c
-*_i.h
+*_h.h
*.ilk
*.meta
*.obj
+*.iobj
*.pch
*.pdb
+*.ipdb
*.pgc
*.pgd
*.rsp
@@ -62,6 +88,7 @@ artifacts/
*.tlh
*.tmp
*.tmp_proj
+*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
@@ -90,6 +117,9 @@ ipch/
*.vspx
*.sap
+# Visual Studio Trace Files
+*.e2e
+
# TFS 2012 Local Workspace
$tf/
@@ -101,15 +131,25 @@ _ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
-# JustCode is a .NET coding add-in
-.JustCode
-
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
# NCrunch
_NCrunch_*
.*crunch*.local.xml
@@ -141,9 +181,9 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
+# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
-#*.pubxml
+*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
@@ -153,13 +193,15 @@ PublishScripts/
# NuGet Packages
*.nupkg
+# NuGet Symbol Packages
+*.snupkg
# The packages folder can be ignored because of Package Restore
-**/packages/*
+**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
-!**/packages/build/
+!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@@ -176,12 +218,15 @@ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
-!*.[Cc]ache/
+!?*.[Cc]ache/
# Others
ClientBin/
@@ -192,9 +237,12 @@ ClientBin/
*.jfm
*.pfx
*.publishsettings
-node_modules/
orleans.codegen.cs
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
@@ -209,15 +257,22 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
+*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
@@ -227,6 +282,7 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
+node_modules/
# Visual Studio 6 build log
*.plg
@@ -234,6 +290,9 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@@ -249,13 +308,55 @@ paket-files/
# FAKE - F# Make
.fake/
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-# CodeRush
-.cr/
+# CodeRush personal settings
+.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
-*.pyc
\ No newline at end of file
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
\ No newline at end of file
diff --git a/DS_Map.sln b/DS_Map.sln
new file mode 100644
index 0000000..b5c31b4
--- /dev/null
+++ b/DS_Map.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS Map", "DS_Map\DS Map.csproj", "{E3C66521-EE89-4406-92C4-FC1D40DC4200}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E3C66521-EE89-4406-92C4-FC1D40DC4200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E3C66521-EE89-4406-92C4-FC1D40DC4200}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E3C66521-EE89-4406-92C4-FC1D40DC4200}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E3C66521-EE89-4406-92C4-FC1D40DC4200}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/DS_Map/AB.cs b/DS_Map/AB.cs
new file mode 100644
index 0000000..b4c79f8
--- /dev/null
+++ b/DS_Map/AB.cs
@@ -0,0 +1,111 @@
+using System;
+using System.IO;
+
+namespace AB_API
+{
+ public class AB
+ {
+ public static void Extract(string filePath, string folderPath)
+ {
+ BinaryReader read = new BinaryReader(File.OpenRead(filePath));
+ if (read.ReadUInt16() != 0x4241)
+ {
+ read.Close();
+ return;
+ }
+ int fileCount = read.ReadUInt16();
+ int[] offsets = new int[fileCount];
+ for (int i = 0; i < fileCount; i++)
+ {
+ offsets[i] = read.ReadInt32();
+ }
+ FileStream file;
+ byte[] buffer;
+ if (Directory.Exists(folderPath + "\\" + "header"))
+ {
+ Directory.Delete(folderPath + "\\" + "header", true);
+ }
+ if (Directory.Exists(folderPath + "\\" + "model"))
+ {
+ Directory.Delete(folderPath + "\\" + "model", true);
+ }
+ Directory.CreateDirectory(folderPath + "\\" + "header");
+ Directory.CreateDirectory(folderPath + "\\" + "model");
+ for (int i = 0; i < fileCount / 2; i++)
+ {
+ read.BaseStream.Position = offsets[i] + 19;
+ int count = read.ReadByte();
+ if (count == 0)
+ {
+ file = File.Create(folderPath + "\\" + "header" + "\\" + i.ToString("D4"));
+ read.BaseStream.Position = offsets[i];
+ buffer = new byte[0x24];
+ read.Read(buffer, 0, 0x24);
+ file.Write(buffer, 0, 0x24);
+ file.Close();
+ }
+ else
+ {
+ BinaryWriter write = new BinaryWriter(File.Create(folderPath + "\\" + "header" + "\\" + i.ToString("D4")));
+ if (count == 2) read.BaseStream.Position += 4;
+ if (count == 3) read.BaseStream.Position += 8;
+ if (count == 4) read.BaseStream.Position += 12;
+ int offset = read.ReadInt32();
+ read.BaseStream.Position = offsets[i] + 0x18 + offset;
+ int size = read.ReadInt32();
+ read.BaseStream.Position = offsets[i];
+ for (int j = 0; j < 0x10 + offset + size; j++)
+ {
+ write.Write((byte)read.ReadByte());
+ }
+ write.Close();
+ }
+ }
+ for (int i = fileCount / 2; i < fileCount; i++)
+ {
+ read.BaseStream.Position = offsets[i] + 8;
+ BinaryWriter write = new BinaryWriter(File.Create(folderPath + "\\" + "model" + "\\" + (i - fileCount / 2).ToString("D4")));
+ int size = read.ReadInt32();
+ read.BaseStream.Position = offsets[i];
+ for (int j = 0; j < size; j++)
+ {
+ write.Write((byte)read.ReadByte());
+ }
+ write.Close();
+ }
+ read.Close();
+ }
+
+ public static void Pack(string folderPath, string filePath)
+ {
+ BinaryWriter write = new BinaryWriter(File.Create(filePath));
+ int count = Directory.GetFiles(folderPath + "\\" + "header").Length;
+ write.Write((Int16)0x4241);
+ write.Write((Int16)(count * 2));
+ int offset = 0x4 + (count * 2) * 4;
+ for (int i = 0; i < count; i++)
+ {
+ write.Write((UInt32)offset);
+ offset += (int)new FileInfo(folderPath + "\\" + "header" + "\\" + i.ToString("D4")).Length;
+ }
+ for (int i = 0; i < count; i++)
+ {
+ write.Write((UInt32)offset);
+ offset += (int)new FileInfo(folderPath + "\\" + "model" + "\\" + i.ToString("D4")).Length;
+ }
+ for (int i = 0; i < count; i++)
+ {
+ BinaryReader read = new BinaryReader(File.OpenRead(folderPath + "\\" + "header" + "\\" + i.ToString("D4")));
+ write.Write(read.ReadBytes((int)new FileInfo(folderPath + "\\" + "header" + "\\" + i.ToString("D4")).Length));
+ read.Close();
+ }
+ for (int i = 0; i < count; i++)
+ {
+ BinaryReader read = new BinaryReader(File.OpenRead(folderPath + "\\" + "model" + "\\" + i.ToString("D4")));
+ write.Write(read.ReadBytes((int)new FileInfo(folderPath + "\\" + "model" + "\\" + i.ToString("D4")).Length));
+ read.Close();
+ }
+ write.Close();
+ }
+ }
+}
diff --git a/DS_Map/ASMHacksDialog.Designer.cs b/DS_Map/ASMHacksDialog.Designer.cs
new file mode 100644
index 0000000..4906cab
--- /dev/null
+++ b/DS_Map/ASMHacksDialog.Designer.cs
@@ -0,0 +1,128 @@
+namespace DS_Map
+{
+ partial class ASMHacksDialog
+ {
+ ///
+ /// 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 Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.applyItemStandardizeButton = new System.Windows.Forms.Button();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.applyARM9ExpansionButton = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // applyItemStandardizeButton
+ //
+ this.applyItemStandardizeButton.Location = new System.Drawing.Point(330, 107);
+ this.applyItemStandardizeButton.Name = "applyItemStandardizeButton";
+ this.applyItemStandardizeButton.Size = new System.Drawing.Size(100, 31);
+ this.applyItemStandardizeButton.TabIndex = 0;
+ this.applyItemStandardizeButton.Text = "Apply";
+ this.applyItemStandardizeButton.UseVisualStyleBackColor = true;
+ this.applyItemStandardizeButton.Click += new System.EventHandler(this.applyItemStandardizeButton_Click);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.Location = new System.Drawing.Point(15, 92);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(155, 13);
+ this.label1.TabIndex = 1;
+ this.label1.Text = "Standardize Item Numbers";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(15, 107);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(305, 26);
+ this.label2.TabIndex = 2;
+ this.label2.Text = "Makes it so that PokéBall item scripts follow the order of items\r\nas indexed in t" +
+ "he ROM. Needed for \'Item\' option in Event Editor\r\n";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(15, 32);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(309, 39);
+ this.label3.TabIndex = 5;
+ this.label3.Text = "Expands ARM9 by repointing the Map Headers table to another \r\nmemory region, leav" +
+ "ing free space in the original location. \r\nNeeded to add new Headers and for oth" +
+ "er ASM hacks.";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label4.Location = new System.Drawing.Point(15, 17);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(187, 13);
+ this.label4.TabIndex = 4;
+ this.label4.Text = "ARM9 Expansion (Experimental)";
+ //
+ // applyARM9ExpansionButton
+ //
+ this.applyARM9ExpansionButton.Enabled = false;
+ this.applyARM9ExpansionButton.Location = new System.Drawing.Point(330, 30);
+ this.applyARM9ExpansionButton.Name = "applyARM9ExpansionButton";
+ this.applyARM9ExpansionButton.Size = new System.Drawing.Size(100, 31);
+ this.applyARM9ExpansionButton.TabIndex = 3;
+ this.applyARM9ExpansionButton.Text = "Work in progress";
+ this.applyARM9ExpansionButton.UseVisualStyleBackColor = true;
+ this.applyARM9ExpansionButton.Click += new System.EventHandler(this.applyARM9ExpansionButton_Click);
+ //
+ // ASMHacksDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(442, 156);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.applyARM9ExpansionButton);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.applyItemStandardizeButton);
+ this.Name = "ASMHacksDialog";
+ this.Text = "ASM Hacks";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button applyItemStandardizeButton;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Button applyARM9ExpansionButton;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/ASMHacksDialog.cs b/DS_Map/ASMHacksDialog.cs
new file mode 100644
index 0000000..c8df8f5
--- /dev/null
+++ b/DS_Map/ASMHacksDialog.cs
@@ -0,0 +1,39 @@
+using System;
+using System.IO;
+using System.Windows.Forms;
+
+namespace DS_Map
+{
+ public partial class ASMHacksDialog : Form
+ {
+ RomInfo info;
+
+ public bool standardizedItems = new bool();
+
+ public ASMHacksDialog(RomInfo romInfo)
+ {
+ InitializeComponent();
+ info = romInfo;
+ }
+
+ private void applyItemStandardizeButton_Click(object sender, EventArgs e)
+ {
+ string path = info.GetScriptFolderPath() + "\\" + info.GetItemScriptFileNumber().ToString("D4");
+
+ ScriptFile file = new ScriptFile(new FileStream(path, FileMode.Open), info.GetVersion());
+ for (int i = 0; i < file.scripts.Count - 1; i++)
+ {
+ file.scripts[i].commands[0].parameters[1] = BitConverter.GetBytes((ushort)i); // Fix item index
+ file.scripts[i].commands[1].parameters[1] = BitConverter.GetBytes((ushort)1); // Fix item quantity
+ }
+ using (BinaryWriter writer = new BinaryWriter(new FileStream(path, FileMode.Create))) writer.Write(file.Save());
+
+ standardizedItems = true;
+ }
+
+ private void applyARM9ExpansionButton_Click(object sender, EventArgs e)
+ {
+
+ }
+ }
+}
diff --git a/DS_Map/ASMHacksDialog.resx b/DS_Map/ASMHacksDialog.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/ASMHacksDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
\ No newline at end of file
diff --git a/DS_Map/App.config b/DS_Map/App.config
new file mode 100644
index 0000000..88fa402
--- /dev/null
+++ b/DS_Map/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DS_Map/AreaData.cs b/DS_Map/AreaData.cs
new file mode 100644
index 0000000..d69f188
--- /dev/null
+++ b/DS_Map/AreaData.cs
@@ -0,0 +1,66 @@
+using System.IO;
+namespace DS_Map
+{
+ ///
+ /// Class to store area data in Pokmon NDS games
+ ///
+ public class AreaData
+ {
+ #regionFields(2)
+ public ushort buildingsTileset;
+ public ushort mapTileset;
+ public ushort dynamicTextureType;
+ public ushort unknown1;
+ public byte areaType;
+ public byte lightType;
+ #endregion
+
+ #regionConstructors(1)
+ public AreaData(Stream data, string version)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ buildingsTileset = reader.ReadUInt16();
+ mapTileset = reader.ReadUInt16();
+
+ if (version == "HeartGold" || version == "SoulSilver")
+ {
+ dynamicTextureType = reader.ReadUInt16();
+ areaType = reader.ReadByte();
+ lightType = reader.ReadByte();
+ }
+ else
+ {
+ unknown1 = reader.ReadUInt16();
+ lightType = reader.ReadByte();
+ }
+ }
+ }
+ #endregion
+
+ #regionMethods(1)
+ public byte[] SaveAreaData(string version)
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ writer.Write(buildingsTileset);
+ writer.Write(mapTileset);
+
+ if (version == "HeartGold" || version == "SoulSilver")
+ {
+ writer.Write(dynamicTextureType);
+ writer.Write(areaType);
+ writer.Write(lightType);
+ }
+ else
+ {
+ writer.Write(unknown1);
+ writer.Write(lightType);
+ }
+ }
+ return newData.ToArray();
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/BuildingEditor.Designer.cs b/DS_Map/BuildingEditor.Designer.cs
new file mode 100644
index 0000000..daf9e8b
--- /dev/null
+++ b/DS_Map/BuildingEditor.Designer.cs
@@ -0,0 +1,149 @@
+namespace DS_Map
+{
+ partial class BuildingEditor
+ {
+ ///
+ /// 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 Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.textureComboBox = new System.Windows.Forms.ComboBox();
+ this.importButton = new System.Windows.Forms.Button();
+ this.exportButton = new System.Windows.Forms.Button();
+ this.buildingOpenGLControl = new Tao.Platform.Windows.SimpleOpenGlControl();
+ this.interiorCheckBox = new System.Windows.Forms.CheckBox();
+ this.buildingsListBox = new System.Windows.Forms.ListBox();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.panel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // textureComboBox
+ //
+ this.textureComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.textureComboBox.FormattingEnabled = true;
+ this.textureComboBox.Location = new System.Drawing.Point(120, 465);
+ this.textureComboBox.Name = "textureComboBox";
+ this.textureComboBox.Size = new System.Drawing.Size(140, 21);
+ this.textureComboBox.TabIndex = 25;
+ this.textureComboBox.SelectedIndexChanged += new System.EventHandler(this.textureComboBox_SelectedIndexChanged);
+ //
+ // importButton
+ //
+ this.importButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+ this.importButton.Location = new System.Drawing.Point(12, 492);
+ this.importButton.Name = "importButton";
+ this.importButton.Size = new System.Drawing.Size(93, 23);
+ this.importButton.TabIndex = 23;
+ this.importButton.Text = "Import NSBMD";
+ this.importButton.UseVisualStyleBackColor = true;
+ this.importButton.Click += new System.EventHandler(this.importButton_Click);
+ //
+ // exportButton
+ //
+ this.exportButton.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+ this.exportButton.Location = new System.Drawing.Point(12, 464);
+ this.exportButton.Name = "exportButton";
+ this.exportButton.Size = new System.Drawing.Size(93, 23);
+ this.exportButton.TabIndex = 22;
+ this.exportButton.Text = "Export NSBMD";
+ this.exportButton.UseVisualStyleBackColor = true;
+ this.exportButton.Click += new System.EventHandler(this.exportButton_Click);
+ //
+ // buildingOpenGLControl
+ //
+ this.buildingOpenGLControl.AccumBits = ((byte)(0));
+ this.buildingOpenGLControl.AutoCheckErrors = false;
+ this.buildingOpenGLControl.AutoFinish = false;
+ this.buildingOpenGLControl.AutoMakeCurrent = true;
+ this.buildingOpenGLControl.AutoSwapBuffers = true;
+ this.buildingOpenGLControl.BackColor = System.Drawing.Color.Black;
+ this.buildingOpenGLControl.ColorBits = ((byte)(32));
+ this.buildingOpenGLControl.DepthBits = ((byte)(24));
+ this.buildingOpenGLControl.Location = new System.Drawing.Point(3, 8);
+ this.buildingOpenGLControl.Name = "buildingOpenGLControl";
+ this.buildingOpenGLControl.Size = new System.Drawing.Size(500, 500);
+ this.buildingOpenGLControl.StencilBits = ((byte)(0));
+ this.buildingOpenGLControl.TabIndex = 21;
+ this.buildingOpenGLControl.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.buildingOpenGLControl_PreviewKeyDown);
+ //
+ // interiorCheckBox
+ //
+ this.interiorCheckBox.AutoSize = true;
+ this.interiorCheckBox.Enabled = false;
+ this.interiorCheckBox.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+ this.interiorCheckBox.Location = new System.Drawing.Point(120, 499);
+ this.interiorCheckBox.Name = "interiorCheckBox";
+ this.interiorCheckBox.Size = new System.Drawing.Size(139, 17);
+ this.interiorCheckBox.TabIndex = 20;
+ this.interiorCheckBox.Text = "Interior Models (HG/SS)";
+ this.interiorCheckBox.UseVisualStyleBackColor = true;
+ this.interiorCheckBox.CheckedChanged += new System.EventHandler(this.interiorCheckBox_CheckedChanged);
+ //
+ // buildingsListBox
+ //
+ this.buildingsListBox.FormattingEnabled = true;
+ this.buildingsListBox.Location = new System.Drawing.Point(12, 12);
+ this.buildingsListBox.Name = "buildingsListBox";
+ this.buildingsListBox.Size = new System.Drawing.Size(248, 446);
+ this.buildingsListBox.TabIndex = 19;
+ this.buildingsListBox.SelectedIndexChanged += new System.EventHandler(this.buildingsListBox_SelectedIndexChanged);
+ //
+ // panel1
+ //
+ this.panel1.Controls.Add(this.buildingOpenGLControl);
+ this.panel1.Location = new System.Drawing.Point(266, 4);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(507, 512);
+ this.panel1.TabIndex = 26;
+ //
+ // BuildingEditor
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(784, 525);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.textureComboBox);
+ this.Controls.Add(this.importButton);
+ this.Controls.Add(this.exportButton);
+ this.Controls.Add(this.interiorCheckBox);
+ this.Controls.Add(this.buildingsListBox);
+ this.Name = "BuildingEditor";
+ this.Text = "Building Editor";
+ this.panel1.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ComboBox textureComboBox;
+ private System.Windows.Forms.Button importButton;
+ private System.Windows.Forms.Button exportButton;
+ private Tao.Platform.Windows.SimpleOpenGlControl buildingOpenGLControl;
+ private System.Windows.Forms.CheckBox interiorCheckBox;
+ private System.Windows.Forms.ListBox buildingsListBox;
+ private System.Windows.Forms.Panel panel1;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/BuildingEditor.cs b/DS_Map/BuildingEditor.cs
new file mode 100644
index 0000000..e5a1b90
--- /dev/null
+++ b/DS_Map/BuildingEditor.cs
@@ -0,0 +1,260 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using LibNDSFormats.NSBMD;
+using LibNDSFormats.NSBTX;
+using Tao.OpenGl;
+
+namespace DS_Map
+{
+ public partial class BuildingEditor : Form
+ {
+ #region Variables
+ string folder;
+ bool disableHandlers = new bool();
+ RomInfo info;
+ NSBMD currentNSBMD;
+ NSBMDGlRenderer renderer = new NSBMDGlRenderer();
+
+ public static float ang = 0.0f;
+ public static float dist = 12.8f;
+ public static float elev = 50.0f;
+ public static float tempAng = 0.0f;
+ public static float tempDist = 0.0f;
+ public static float tempElev = 0.0f;
+ public float perspective = 45f;
+ #endregion
+
+ public BuildingEditor(RomInfo romInfo)
+ {
+ InitializeComponent();
+ info = romInfo;
+
+ buildingOpenGLControl.InitializeContexts();
+ buildingOpenGLControl.MakeCurrent();
+ buildingOpenGLControl.MouseWheel += new MouseEventHandler(buildingOpenGLControl_MouseWheel);
+ Gl.glEnable(Gl.GL_TEXTURE_2D);
+
+ if (romInfo.GetVersion() == "HeartGold" || romInfo.GetVersion() == "SoulSilver") interiorCheckBox.Enabled = true;
+
+ disableHandlers = true;
+ FillListBox(false);
+ FillTexturesBox();
+ textureComboBox.SelectedIndex = 0;
+ disableHandlers = false;
+ buildingsListBox.SelectedIndex = 0;
+ }
+
+ #region Subroutines
+ private void CreateEmbeddedTexturesFile(int modelID, bool interior)
+ {
+ string readingPath = folder + info.GetBuildingModelsFolderPath(interior) + "\\" + modelID.ToString("D4");
+ string writingPath = Path.GetTempPath() + "BLDtexture.nsbtx";
+
+ using (BinaryReader reader = new BinaryReader(new FileStream(readingPath, FileMode.Open)))
+ {
+ BinaryWriter writer = new BinaryWriter(new FileStream(writingPath, FileMode.Create));
+
+ reader.BaseStream.Position = 0x8;
+ int nsbmdSize = reader.ReadInt32(); // Read size of NSBMD file
+ reader.BaseStream.Position = 0x14;
+ int texturesOffset = reader.ReadInt32(); // Read starting offset of embedded textures sections
+ int texturesSize = nsbmdSize - texturesOffset + 0x14; // Calculate size of embedded textures section
+ reader.BaseStream.Position = texturesOffset;
+
+ writer.Write((UInt32)0x30585442); // Write magic code BTX0
+ writer.Write((UInt32)0x0001FEFF); // Sequence needed after BTX0
+ writer.Write((UInt32)texturesSize); // Write size of textures block
+ writer.Write((UInt32)0x00010010); // Needed sequence
+ writer.Write((UInt32)0x00000014); // Needed sequence
+ while (reader.BaseStream.Position < reader.BaseStream.Length) writer.Write(reader.ReadByte()); // Write texture data to file
+
+ writer.Close();
+ }
+
+
+ }
+ private void FillListBox(bool interior)
+ {
+ int modelCount = Directory.GetFiles(folder + info.GetBuildingModelsFolderPath(interior)).Length;
+ for (int i = 0; i < modelCount; i++)
+ {
+ using (BinaryReader reader = new BinaryReader(File.OpenRead(folder + info.GetBuildingModelsFolderPath(interior) + "\\" + i.ToString("D4"))))
+ {
+ reader.BaseStream.Position = 0x14;
+ if (reader.ReadUInt32() == 0x304C444D) reader.BaseStream.Position = 0x34;
+ else reader.BaseStream.Position = 0x38;
+ string nsbmdName = Encoding.UTF8.GetString(reader.ReadBytes(16));
+ buildingsListBox.Items.Add(i + ": " + nsbmdName);
+ }
+ }
+ }
+ private void FillTexturesBox()
+ {
+ int texturesCount = Directory.GetFiles(folder + info.GetBuildingTexturesFolderPath()).Length;
+ textureComboBox.Items.Add("Embedded textures");
+ for (int i = 0; i < texturesCount; i++) textureComboBox.Items.Add("Texture " + i);
+ }
+ private void LoadBuildingModel(int modelID, bool interior)
+ {
+ string path = folder + info.GetBuildingModelsFolderPath(interior) + "\\" + modelID.ToString("D4");
+ using (Stream fs = new FileStream(path, FileMode.Open)) currentNSBMD = NSBMDLoader.LoadNSBMD(fs);
+ }
+ private void LoadModelTextures(int fileID)
+ {
+ string path;
+ if (fileID > -1) path = folder + info.GetBuildingTexturesFolderPath() + "\\" + fileID.ToString("D4");
+ else path = Path.GetTempPath() + "BLDtexture.nsbtx"; // Load Embedded textures if the argument passed to this function is -1
+ try
+ {
+ currentNSBMD.materials = NSBTXLoader.LoadNsbtx(new MemoryStream(File.ReadAllBytes(path)), out currentNSBMD.Textures, out currentNSBMD.Palettes);
+ currentNSBMD.MatchTextures();
+ }
+ catch { }
+ }
+ private void RenderModel()
+ {
+ MKDS_Course_Editor.NSBTA.NSBTA.NSBTA_File ani = new MKDS_Course_Editor.NSBTA.NSBTA.NSBTA_File();
+ MKDS_Course_Editor.NSBTP.NSBTP.NSBTP_File tp = new MKDS_Course_Editor.NSBTP.NSBTP.NSBTP_File();
+ MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File ca = new MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File();
+ int[] aniframeS = new int[0];
+
+ buildingOpenGLControl.Invalidate(); // Invalidate drawing surface
+ SetupRenderer(ang, dist, elev, perspective); // Adjust rendering settings
+
+ /* Render the building model */
+ renderer.Model = currentNSBMD.models[0];
+ Gl.glScalef(currentNSBMD.models[0].modelScale / 32, currentNSBMD.models[0].modelScale / 32, currentNSBMD.models[0].modelScale / 32);
+ renderer.RenderModel("", ani, aniframeS, aniframeS, aniframeS, aniframeS, aniframeS, ca, false, -1, 0.0f, 0.0f, dist, elev, ang, true, tp, currentNSBMD);
+ }
+ private void SetupRenderer(float ang, float dist, float elev, float perspective)
+ {
+ Gl.glEnable(Gl.GL_RESCALE_NORMAL);
+ Gl.glEnable(Gl.GL_COLOR_MATERIAL);
+ Gl.glEnable(Gl.GL_DEPTH_TEST);
+ Gl.glEnable(Gl.GL_NORMALIZE);
+ Gl.glDisable(Gl.GL_CULL_FACE);
+ Gl.glFrontFace(Gl.GL_CCW);
+ Gl.glClearDepth(1);
+ Gl.glEnable(Gl.GL_ALPHA_TEST);
+ Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
+ Gl.glEnable(Gl.GL_BLEND);
+ Gl.glAlphaFunc(Gl.GL_GREATER, 0f);
+ Gl.glClearColor(51f / 255f, 51f / 255f, 51f / 255f, 1f);
+ float aspect;
+ Gl.glViewport(0, 0, buildingOpenGLControl.Width, buildingOpenGLControl.Height);
+ aspect = buildingOpenGLControl.Width / buildingOpenGLControl.Height;//(vp[2] - vp[0]) / (vp[3] - vp[1]);
+ Gl.glMatrixMode(Gl.GL_PROJECTION);
+ Gl.glLoadIdentity();
+ Glu.gluPerspective(perspective, aspect, 0.02f, 1000000.0f);//0.02f, 32.0f);
+ Gl.glTranslatef(0, 0, -dist);
+ Gl.glRotatef(elev, 1, 0, 0);
+ Gl.glRotatef(ang, 0, 1, 0);
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glLoadIdentity();
+ Gl.glTranslatef(0, 0, -dist);
+ Gl.glRotatef(elev, 1, 0, 0);
+ Gl.glRotatef(-ang, 0, 1, 0);
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLoadIdentity();
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+ Gl.glColor3f(1.0f, 1.0f, 1.0f);
+ Gl.glDepthMask(Gl.GL_TRUE);
+ Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
+ }
+ #endregion
+
+ private void buildingOpenGLControl_MouseWheel(object sender, MouseEventArgs e) // Zoom In/Out
+ {
+ if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) dist += (float)e.Delta / 200;
+ else dist -= (float)e.Delta / 200;
+ RenderModel();
+ }
+ private void buildingsListBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (disableHandlers) return;
+
+ LoadBuildingModel(buildingsListBox.SelectedIndex, interiorCheckBox.Checked);
+ CreateEmbeddedTexturesFile(buildingsListBox.SelectedIndex, interiorCheckBox.Checked);
+ LoadModelTextures(textureComboBox.SelectedIndex - 1);
+ RenderModel();
+ }
+ private void exportButton_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog em = new SaveFileDialog();
+ em.Filter = "NSBMD model (*.nsbmd)|*.nsbmd";
+ if (em.ShowDialog(this) != DialogResult.OK)
+ return;
+
+ else File.Copy(folder + info.GetBuildingModelsFolderPath(interiorCheckBox.Checked) + "\\" + buildingsListBox.SelectedIndex.ToString("D4"), em.FileName, true);
+ }
+ private void importButton_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog im = new OpenFileDialog();
+ im.Filter = "NSBMD model (*.nsbmd)|*.nsbmd";
+ if (im.ShowDialog(this) != DialogResult.OK)
+ return;
+
+ using (BinaryReader reader = new BinaryReader(new FileStream(im.FileName, FileMode.Open)))
+ {
+ if (reader.ReadUInt32() != 0x30444D42)
+ {
+ MessageBox.Show("Please select an NSBMD file.", "Invalid File");
+ return;
+ }
+ else
+ {
+ File.Copy(im.FileName, folder + info.GetBuildingModelsFolderPath(interiorCheckBox.Checked) + "\\" + buildingsListBox.SelectedIndex.ToString("D4"), true);
+ buildingsListBox_SelectedIndexChanged(null, null);
+ }
+ }
+ }
+ private void interiorCheckBox_CheckedChanged(object sender, EventArgs e)
+ {
+ disableHandlers = true;
+
+ buildingsListBox.Items.Clear();
+ FillListBox(interiorCheckBox.Checked);
+
+ disableHandlers = false;
+
+ buildingsListBox.SelectedIndex = 0;
+ }
+ private void textureComboBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (disableHandlers) return;
+ LoadModelTextures(textureComboBox.SelectedIndex - 1);
+ RenderModel();
+ }
+
+ private void buildingOpenGLControl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
+ {
+ switch (e.KeyCode)
+ {
+ case Keys.Right:
+ ang += 1;
+ break;
+ case Keys.Left:
+ ang -= 1;
+ break;
+ case Keys.Down:
+ elev += 1;
+ break;
+ case Keys.Up:
+ elev -= 1;
+ break;
+ }
+ RenderModel();
+ }
+ }
+}
diff --git a/DS_Map/BuildingEditor.resx b/DS_Map/BuildingEditor.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/BuildingEditor.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
\ No newline at end of file
diff --git a/DS_Map/DS Map.csproj b/DS_Map/DS Map.csproj
new file mode 100644
index 0000000..ef687ed
--- /dev/null
+++ b/DS_Map/DS Map.csproj
@@ -0,0 +1,418 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E3C66521-EE89-4406-92C4-FC1D40DC4200}
+ WinExe
+ DS_Map
+ DS Map
+ v4.5.2
+ 512
+ true
+ false
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+ false
+
+
+
+ False
+ .\HelixToolkit.dll
+
+
+ False
+ ..\..\..\..\..\Desktop\sdsme\Map_Editor\OpenTK.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\..\..\..\Desktop\sdsme\Map_Editor\Tao.OpenGl.dll
+
+
+ False
+ ..\..\..\..\..\Desktop\sdsme\Map_Editor\Tao.Platform.Windows.dll
+
+
+
+
+
+
+
+
+ Form
+
+
+ ASMHacksDialog.cs
+
+
+ Form
+
+
+ BuildingEditor.cs
+
+
+
+ Form
+
+
+ WildEditorHGSS.cs
+
+
+ Form
+
+
+ WildEditorDPPt.cs
+
+
+ Form
+
+
+ GiveItemDialog.cs
+
+
+ Form
+
+
+ GivePokémonDialog.cs
+
+
+
+ Form
+
+
+ InsertValueDialog.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ Main Window.cs
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+ Form
+
+
+ SPK.cs
+
+
+ ASMHacksDialog.cs
+
+
+ BuildingEditor.cs
+
+
+ WildEditorHGSS.cs
+
+
+ GiveItemDialog.cs
+
+
+ GivePokémonDialog.cs
+
+
+ InsertValueDialog.cs
+
+
+ Main Window.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ Designer
+ Resources.Designer.cs
+
+
+
+
+ Designer
+
+
+
+
+
+
+ SPK.cs
+
+
+ WildEditorDPPt.cs
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4.5.2 %28x86 e x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
\ No newline at end of file
diff --git a/DS_Map/DataGridViewDoubleBuffered.cs b/DS_Map/DataGridViewDoubleBuffered.cs
new file mode 100644
index 0000000..c03b393
--- /dev/null
+++ b/DS_Map/DataGridViewDoubleBuffered.cs
@@ -0,0 +1,14 @@
+// DataGridView with double buffering to speed up performance
+
+using System.Windows.Forms;
+
+namespace DS_Map
+{
+ public class DataGridViewDoubleBuffered : DataGridView
+ {
+ public DataGridViewDoubleBuffered()
+ {
+ DoubleBuffered = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/EncounterFile.cs b/DS_Map/EncounterFile.cs
new file mode 100644
index 0000000..aa89dc3
--- /dev/null
+++ b/DS_Map/EncounterFile.cs
@@ -0,0 +1,463 @@
+using System.IO;
+
+namespace DS_Map
+{
+ /* ---------------------- WILD POKMON DATA STRUCTURE (DPPt):----------------------------
+
+ 0x0 // byte: Walking encounter rate
+ 0x4 // byte: Level of
+ 0x2 // ushort: Matrix number
+ 0x4 // ushort: Script file number
+ 0x6 // ushort: Level script file number
+ 0x8 // ushort: Message file number
+ 0xA // ushort: Day music track number
+ 0xC // ushort: Night music track number
+ 0xE // ushort: Wild Pokmon file number
+ 0x10 // ushort: Event file number
+
+ * Diamond/Pearl:
+ 0x12 // ushort: Index of map name in message file #382 (US version)
+
+ * Platinum:
+ 0x12 // byte: Index of map name in message file #382 (US version)
+ 0x13 // byte: Map name textbox type value
+
+ 0x14 // byte: Weather value
+ 0x15 // byte: Camera value
+ 0x16 // byte: Boolean flag: show name when entering map
+ 0x17 // byte: Bitwise permission flags:
+
+ ----------------- 1: Allow Fly
+ ----------------- 2: ?
+ ----------------- 3: ?
+ ----------------- 4: Allow Bike usage
+ ----------------- 5: ?
+ ----------------- 6: ?
+ ----------------- 7: Escape Rope
+ ----------------- 8: ?
+
+ /* ---------------------- WILD POKMON DATA STRUCTURE (HGSS):----------------------------
+
+ 0x0 // byte: Wild Pokmon file number
+ 0x1 // byte: Area data value
+ 0x2 // byte: ?
+ 0x3 // byte: ?
+ 0x4 // ushort: Matrix number
+ 0x6 // ushort: Script file number
+ 0x8 // ushort: Level script file
+ 0xA // ushort: Message file number
+ 0xC // ushort: Day music track number
+ 0xE // ushort: Night music track number
+ 0x10 // ushort: Event file number
+ 0x12 // byte: Index of map name in message file #382 (US version)
+ 0x13 // byte: Map name textbox type value
+ 0x14 // byte: Weather value
+ 0x15 // byte: Camera value
+ 0x16 // byte: Follow mode (for the Pokmon following hero)
+ 0x17 // byte: Bitwise permission flags:
+
+ ----------------- 1: Allow Fly
+ ----------------- 2: ?
+ ----------------- 3: ?
+ ----------------- 4: Allow Bike usage
+ ----------------- 5: ?
+ ----------------- 6: ?
+ ----------------- 7: Escape Rope
+ ----------------- 8: ?
+
+ ----------------------------------------------------------------------------------*/
+
+ ///
+ /// General class to store common wild Pokmon data across all Gen IV Pokmon NDS games
+ ///
+ public abstract class EncounterFile
+ {
+ #regionFields(19)
+
+ /* Encounter rates */
+ public byte goodRodRate { get; set; }
+ public byte oldRodRate { get; set; }
+ public byte superRodRate { get; set; }
+ public byte surfRate { get; set; }
+ public byte walkingRate { get; set; }
+
+ /* Levels */
+ public byte[] goodRodMaxLevels = new byte[5];
+ public byte[] goodRodMinLevels = new byte[5];
+ public byte[] oldRodMaxLevels = new byte[5];
+ public byte[] oldRodMinLevels = new byte[5];
+ public byte[] walkingLevels = new byte[12];
+ public byte[] superRodMaxLevels = new byte[5];
+ public byte[] superRodMinLevels = new byte[5];
+ public byte[] surfMaxLevels = new byte[5];
+ public byte[] surfMinLevels = new byte[5];
+
+ /* Encounters */
+ public ushort[] goodRodPokmon = new ushort[5];
+ public ushort[] oldRodPokmon = new ushort[5];
+ public ushort[] superRodPokmon = new ushort[5];
+ public ushort[] surfPokmon = new ushort[5];
+ public ushort[] swarmPokmon { get; set; }
+ #endregion
+
+ #region Methods (1)
+ public abstract byte[] SaveEncounterFile();
+ #endregion
+ }
+
+ ///
+ /// Class to store wild Pokmon data from Pokmon Diamond, Pearl and Platinum
+ ///
+ public class EncounterFileDPPt: EncounterFile
+ {
+ #regionFields(9)
+ /* Field encounters */
+ public uint[] radarPokmon = new uint[4];
+ public uint[] walkingPokmon = new uint[12];
+
+ /* Time-specific encounters */
+ public uint[] morningPokmon = new uint[2];
+ public uint[] nightPokmon = new uint[2];
+
+ /* Dual slot exclusives */
+ public uint[] rubyPokmon = new uint[2];
+ public uint[] sapphirePokmon = new uint[2];
+ public uint[] emeraldPokmon = new uint[2];
+ public uint[] fireRedPokmon = new uint[2];
+ public uint[] leafGreenPokmon = new uint[2];
+ #endregion
+
+ #regionConstructors(1)
+ public EncounterFileDPPt(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ /* Walking encounters */
+ walkingRate = (byte)reader.ReadInt32();
+ for (int i = 0; i < 12; i++)
+ {
+ walkingLevels[i] = (byte)reader.ReadUInt32();
+ walkingPokmon[i] = reader.ReadUInt32();
+ }
+
+ /* Swarms */
+ swarmPokmon = new ushort[2];
+ for (int i = 0; i < 2; i++) swarmPokmon[i] = (ushort)reader.ReadUInt32();
+
+ /* Time-specific encounters */
+ for (int i = 0; i < 2; i++) morningPokmon[i] = reader.ReadUInt32();
+ for (int i = 0; i < 2; i++) nightPokmon[i] = reader.ReadUInt32();
+
+ /* Pok-Radar encounters */
+ for (int i = 0; i < 4; i++) radarPokmon[i] = reader.ReadUInt32();
+
+ reader.BaseStream.Position = 0xA4;
+
+ /* Dual-slot encounters */
+ for (int i = 0; i < 2; i++) rubyPokmon[i] = reader.ReadUInt32();
+ for (int i = 0; i < 2; i++) sapphirePokmon[i] = reader.ReadUInt32();
+ for (int i = 0; i < 2; i++) emeraldPokmon[i] = reader.ReadUInt32();
+ for (int i = 0; i < 2; i++) fireRedPokmon[i] = reader.ReadUInt32();
+ for (int i = 0; i < 2; i++) leafGreenPokmon[i] = reader.ReadUInt32();
+
+ /* Surf encounters */
+ surfRate = (byte)reader.ReadInt32();
+ for (int i = 0; i < 5; i++)
+ {
+ surfMaxLevels[i] = reader.ReadByte();
+ surfMinLevels[i] = reader.ReadByte();
+ reader.BaseStream.Position += 0x2;
+ surfPokmon[i] = (ushort)reader.ReadUInt32();
+ }
+
+ reader.BaseStream.Position = 0x124;
+
+ /* Old Rod encounters */
+ oldRodRate = (byte)reader.ReadInt32();
+ for (int i = 0; i < 5; i++)
+ {
+ oldRodMaxLevels[i] = reader.ReadByte();
+ oldRodMinLevels[i] = reader.ReadByte();
+ reader.BaseStream.Position += 0x2;
+ oldRodPokmon[i] = (ushort)reader.ReadUInt32();
+ }
+
+ /* Good Rod encounters */
+ goodRodRate = (byte)reader.ReadInt32();
+ for (int i = 0; i < 5; i++)
+ {
+ goodRodMaxLevels[i] = reader.ReadByte();
+ goodRodMinLevels[i] = reader.ReadByte();
+ reader.BaseStream.Position += 0x2;
+ goodRodPokmon[i] = (ushort)reader.ReadUInt32();
+ }
+
+ /* Super Rod encounters */
+ superRodRate = (byte)reader.ReadInt32();
+ for (int i = 0; i < 5; i++)
+ {
+ superRodMaxLevels[i] = reader.ReadByte();
+ superRodMinLevels[i] = reader.ReadByte();
+ reader.BaseStream.Position += 0x2;
+ superRodPokmon[i] = (ushort)reader.ReadUInt32();
+ }
+ }
+ }
+ #endregionConstructors
+
+ #region Methods (1)
+ public override byte[] SaveEncounterFile()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ writer.Write((uint)walkingRate);
+
+ /* Walking encounters */
+ for (int i = 0; i < 12; i++)
+ {
+ writer.Write((uint)walkingLevels[i]);
+ writer.Write(walkingPokmon[i]);
+ }
+
+ /* Swarms */
+ for (int i = 0; i < 2; i++) writer.Write((uint)swarmPokmon[i]);
+
+ /* Time-specific encounters */
+ for (int i = 0; i < 2; i++) writer.Write(morningPokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(nightPokmon[i]);
+
+ /* Pok-Radar encounters */
+ for (int i = 0; i < 4; i++) writer.Write(radarPokmon[i]);
+
+ writer.BaseStream.Position = 0xA4;
+
+ /* Dual-slot encounters */
+ for (int i = 0; i < 2; i++) writer.Write(rubyPokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(sapphirePokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(emeraldPokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(fireRedPokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(leafGreenPokmon[i]);
+
+ /* Surf encounters */
+ writer.Write((uint)surfRate);
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(surfMaxLevels[i]);
+ writer.Write(surfMinLevels[i]);
+ writer.BaseStream.Position += 0x2;
+ writer.Write((uint)surfPokmon[i]);
+ }
+
+ writer.BaseStream.Position = 0x124;
+
+ /* Old Rod encounters */
+ writer.Write((uint)oldRodRate);
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(oldRodMaxLevels[i]);
+ writer.Write(oldRodMinLevels[i]);
+ writer.BaseStream.Position += 0x2;
+ writer.Write((uint)oldRodPokmon[i]);
+ }
+
+ /* Good Rod encounters */
+ writer.Write((uint)goodRodRate);
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(goodRodMaxLevels[i]);
+ writer.Write(goodRodMinLevels[i]);
+ writer.BaseStream.Position += 0x2;
+ writer.Write((uint)goodRodPokmon[i]);
+ }
+
+ /* Super Rod encounters */
+ writer.Write((uint)superRodRate);
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(superRodMaxLevels[i]);
+ writer.Write(superRodMinLevels[i]);
+ writer.BaseStream.Position += 0x2;
+ writer.Write((uint)superRodPokmon[i]);
+ }
+ }
+ return newData.ToArray();
+ }
+ #endregion
+ }
+
+ ///
+ /// Class to store wild Pokmon data from Pokmon HeartGold and SoulSilver
+ ///
+ public class EncounterFileHGSS : EncounterFile
+ {
+ #regionFields(9)
+ public byte rockSmashRate;
+ public ushort[] morningPokmon = new ushort[12];
+ public ushort[] dayPokmon = new ushort[12];
+ public ushort[] nightPokmon = new ushort[12];
+ public ushort[] hoennMusicPokmon = new ushort[2];
+ public ushort[] sinnohMusicPokmon = new ushort[2];
+ public ushort[] rockSmashPokmon = new ushort[2];
+ public byte[] rockSmashMinLevels = new byte[2];
+ public byte[] rockSmashMaxLevels = new byte[2];
+ #endregion
+
+ #regionConstructors(1)
+ public EncounterFileHGSS(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ /* Encounter rates */
+ walkingRate = reader.ReadByte();
+ surfRate = reader.ReadByte();
+ rockSmashRate = reader.ReadByte();
+ oldRodRate = reader.ReadByte();
+ goodRodRate = reader.ReadByte();
+ superRodRate = reader.ReadByte();
+
+ reader.BaseStream.Position += 0x2;
+
+ /* Walking encounters levels */
+ for (int i = 0; i < 12; i++) walkingLevels[i] = reader.ReadByte();
+
+ /* Morning walking encounters */
+ for (int i = 0; i < 12; i++) morningPokmon[i] = reader.ReadUInt16();
+
+ /* Day walking encounters */
+ for (int i = 0; i < 12; i++) dayPokmon[i] = reader.ReadUInt16();
+
+ /* Night walking encounters */
+ for (int i = 0; i < 12; i++) nightPokmon[i] = reader.ReadUInt16();
+
+ /* PokGear music encounters */
+ for (int i = 0; i < 2; i++) hoennMusicPokmon[i] = reader.ReadUInt16();
+ for (int i = 0; i < 2; i++) sinnohMusicPokmon[i] = reader.ReadUInt16();
+
+ /* Surf encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ surfMinLevels[i] = reader.ReadByte();
+ surfMaxLevels[i] = reader.ReadByte();
+ surfPokmon[i] = reader.ReadUInt16();
+ }
+
+ /* Rock Smash encounters */
+ for (int i = 0; i < 2; i++)
+ {
+ rockSmashMinLevels[i] = reader.ReadByte();
+ rockSmashMaxLevels[i] = reader.ReadByte();
+ rockSmashPokmon[i] = reader.ReadUInt16();
+ }
+
+ /* Old Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ oldRodMinLevels[i] = reader.ReadByte();
+ oldRodMaxLevels[i] = reader.ReadByte();
+ oldRodPokmon[i] = reader.ReadUInt16();
+ }
+
+ /* Good Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ goodRodMinLevels[i] = reader.ReadByte();
+ goodRodMaxLevels[i] = reader.ReadByte();
+ goodRodPokmon[i] = reader.ReadUInt16();
+ }
+
+ /* Super Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ superRodMinLevels[i] = reader.ReadByte();
+ superRodMaxLevels[i] = reader.ReadByte();
+ superRodPokmon[i] = reader.ReadUInt16();
+ }
+
+ /* Swarm encounters */
+ swarmPokmon = new ushort[4];
+ for (int i = 0; i < 4; i++) swarmPokmon[i] = reader.ReadUInt16();
+ }
+ }
+ #endregion
+
+ #region Methods(1)
+ public override byte[] SaveEncounterFile()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ /* Encounter rates */
+ writer.Write(walkingRate);
+ writer.Write(surfRate);
+ writer.Write(rockSmashRate);
+ writer.Write(oldRodRate);
+ writer.Write(goodRodRate);
+ writer.Write(superRodRate);
+
+ writer.BaseStream.Position += 0x2;
+
+ /* Walking encounters levels */
+ for (int i = 0; i < 12; i++) writer.Write(walkingLevels[i]);
+
+ /* Morning walking encounters */
+ for (int i = 0; i < 12; i++) writer.Write(morningPokmon[i]);
+
+ /* Day walking encounters */
+ for (int i = 0; i < 12; i++) writer.Write(dayPokmon[i]);
+
+ /* Night walking encounters */
+ for (int i = 0; i < 12; i++) writer.Write(nightPokmon[i]);
+
+ /* PokGear music encounters */
+ for (int i = 0; i < 2; i++) writer.Write(hoennMusicPokmon[i]);
+ for (int i = 0; i < 2; i++) writer.Write(sinnohMusicPokmon[i]);
+
+ /* Surf encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(surfMinLevels[i]);
+ writer.Write(surfMaxLevels[i]);
+ writer.Write(surfPokmon[i]);
+ }
+
+ /* Rock Smash encounters */
+ for (int i = 0; i < 2; i++)
+ {
+ writer.Write(rockSmashMinLevels[i]);
+ writer.Write(rockSmashMaxLevels[i]);
+ writer.Write(rockSmashPokmon[i]);
+ }
+
+ /* Old Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(oldRodMinLevels[i]);
+ writer.Write(oldRodMaxLevels[i]);
+ writer.Write(oldRodPokmon[i]);
+ }
+
+ /* Good Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(goodRodMinLevels[i]);
+ writer.Write(goodRodMaxLevels[i]);
+ writer.Write(goodRodPokmon[i]);
+ }
+
+ /* Super Rod encounters */
+ for (int i = 0; i < 5; i++)
+ {
+ writer.Write(superRodMinLevels[i]);
+ writer.Write(superRodMaxLevels[i]);
+ writer.Write(superRodPokmon[i]);
+ }
+
+ /* Swarm encounters */
+ for (int i = 0; i < 4; i++) writer.Write(swarmPokmon[i]);
+ }
+ return newData.ToArray();
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/EventFile.cs b/DS_Map/EventFile.cs
new file mode 100644
index 0000000..53bfd7f
--- /dev/null
+++ b/DS_Map/EventFile.cs
@@ -0,0 +1,400 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// Classes to store event data in Pokmon NDS games
+ ///
+ public class EventFile
+ {
+ #regionFields(4)
+ public List spawnables = new List();
+ public List overworlds = new List();
+ public List warps = new List();
+ public List triggers = new List();
+ #endregion
+
+ #regionConstructors(1)
+ public EventFile(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ /* Read spawnables */
+ uint spawnablesCount = reader.ReadUInt32();
+ for (int i = 0; i < spawnablesCount; i++) spawnables.Add(new Spawnable(new MemoryStream(reader.ReadBytes(0x14))));
+
+ /* Read overworlds */
+ uint overworldsCount = reader.ReadUInt32();
+ for (int i = 0; i < overworldsCount; i++) overworlds.Add(new Overworld(new MemoryStream(reader.ReadBytes(0x20))));
+
+ /* Read warps */
+ uint warpsCount = reader.ReadUInt32();
+ for (int i = 0; i < warpsCount; i++) warps.Add(new Warp(new MemoryStream(reader.ReadBytes(0xC))));
+
+ /* Read triggers */
+ uint triggersCount = reader.ReadUInt32();
+ for (int i = 0; i < triggersCount; i++) triggers.Add(new Trigger(new MemoryStream(reader.ReadBytes(0x10))));
+
+ }
+ }
+ #endregion
+
+ #regionMethods (1)
+ public byte[] Save()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ /* Write spawnables */
+ writer.Write((uint)spawnables.Count);
+ for (int i = 0; i < spawnables.Count; i++) writer.Write(spawnables[i].Save());
+
+ /* Write overworlds */
+ writer.Write((uint)overworlds.Count);
+ for (int i = 0; i < overworlds.Count; i++) writer.Write(overworlds[i].Save());
+
+ /* Write warps */
+ writer.Write((uint)warps.Count);
+ for (int i = 0; i < warps.Count; i++) writer.Write(warps[i].Save());
+
+ /* Write triggers */
+ writer.Write((uint)triggers.Count);
+ for (int i = 0; i < triggers.Count; i++) writer.Write(triggers[i].Save());
+ }
+ return newData.ToArray();
+ }
+ #endregion
+
+ }
+
+ public abstract class Event
+ {
+ #regionFields(6)
+ public short xMapPosition;
+ public short yMapPosition;
+ public short zPosition;
+ public ushort xMatrixPosition;
+ public ushort yMatrixPosition;
+ #endregion
+
+ #region Methods (1)
+ public abstract byte[] Save();
+ #endregion
+ }
+
+ public class Spawnable : Event
+ {
+ #regionFields(7)
+ public ushort scriptNumber;
+ public ushort unknown1;
+ public ushort unknown2;
+ public ushort unknown3;
+ public ushort unknown4;
+ public ushort orientation;
+ public ushort unknown5;
+ #endregion
+
+ #regionConstructors(2)
+ public Spawnable(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ scriptNumber = reader.ReadUInt16();
+ unknown1 = reader.ReadUInt16();
+
+ /* Decompose x coordinate in matrix and map positions */
+ int xPosition = reader.ReadInt16();
+ xMapPosition = (short)(xPosition % 32);
+ xMatrixPosition = (ushort)(xPosition / 32);
+
+ unknown2 = reader.ReadUInt16();
+
+ /* Decompose y coordinate in matrix and map positions */
+ int yPosition = reader.ReadInt16();
+ yMapPosition = (short)(yPosition % 32);
+ yMatrixPosition = (ushort)(yPosition / 32);
+
+ unknown3 = reader.ReadUInt16();
+ zPosition = reader.ReadInt16();
+ unknown4 = reader.ReadUInt16();
+ orientation = reader.ReadUInt16();
+ unknown5 = reader.ReadUInt16();
+ }
+ }
+ public Spawnable(int xMatrixPosition, int yMatrixPosition)
+ {
+ scriptNumber = 0;
+ unknown1 = 0;
+ unknown2 = 0;
+ unknown3 = 0;
+ unknown4 = 0;
+ unknown5 = 0;
+ orientation = 0;
+
+ xMapPosition = 0;
+ yMapPosition = 0;
+ zPosition = 0;
+ this.xMatrixPosition = (ushort)xMatrixPosition;
+ this.yMatrixPosition = (ushort)yMatrixPosition;
+ }
+ #endregion
+
+ #regionMethods (1)
+ public override byte[] Save()
+ {
+ using (BinaryWriter writer = new BinaryWriter(new MemoryStream()))
+ {
+ writer.Write(scriptNumber);
+ writer.Write(unknown1);
+ short xCoordinate = (short)(xMapPosition + 32 * xMatrixPosition);
+ writer.Write(xCoordinate);
+ writer.Write(unknown2);
+ short yCoordinate = (short)(yMapPosition + 32 * yMatrixPosition);
+ writer.Write(yCoordinate);
+ writer.Write(unknown3);
+ writer.Write(zPosition);
+ writer.Write(unknown4);
+ writer.Write(orientation);
+ writer.Write(unknown5);
+
+ return ((MemoryStream)writer.BaseStream).ToArray();
+ }
+ }
+ #endregion
+ }
+
+ public class Overworld : Event
+ {
+ #regionFields(14)
+ public ushort owID;
+ public ushort spriteID;
+ public ushort movement;
+ public ushort type;
+ public ushort flag;
+ public ushort scriptNumber;
+ public ushort orientation;
+ public ushort sightRange;
+ public ushort unknown1;
+ public ushort unknown2;
+ public ushort xRange;
+ public ushort yRange;
+ public ushort unknown3;
+ public bool is3D = new bool();
+ #endregion
+
+ #regionConstructors(2)
+ public Overworld(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ owID = reader.ReadUInt16();
+ spriteID = reader.ReadUInt16();
+ movement = reader.ReadUInt16();
+ type = reader.ReadUInt16();
+ flag = reader.ReadUInt16();
+ scriptNumber = reader.ReadUInt16();
+ orientation = reader.ReadUInt16();
+ sightRange = reader.ReadUInt16();
+ unknown1 = reader.ReadUInt16();
+ unknown2 = reader.ReadUInt16();
+ xRange = reader.ReadUInt16();
+ yRange = reader.ReadUInt16();
+
+ /* Decompose x-y coordinates in matrix and map positions */
+ int xPosition = reader.ReadInt16();
+ int yPosition = reader.ReadInt16();
+ xMapPosition = (short)(xPosition % 32);
+ yMapPosition = (short)(yPosition % 32);
+ xMatrixPosition = (ushort)(xPosition / 32);
+ yMatrixPosition = (ushort)(yPosition / 32);
+
+ zPosition = reader.ReadInt16();
+ unknown3 = reader.ReadUInt16();
+ }
+ }
+ public Overworld(int owID, int xMatrixPosition, int yMatrixPosition)
+ {
+ this.owID = (ushort)owID;
+ spriteID = 1;
+ movement = 0;
+ type = 0;
+ flag = 0;
+ scriptNumber = 0;
+ orientation = 1;
+ sightRange = 0;
+ unknown1 = 0;
+ unknown2 = 0;
+ xRange = 0;
+ yRange = 0;
+ unknown3 = 0;
+
+ xMapPosition = 16;
+ yMapPosition = 16;
+ zPosition = 0;
+ this.xMatrixPosition = (ushort)xMatrixPosition;
+ this.yMatrixPosition = (ushort)yMatrixPosition;
+ }
+ #endregion
+
+ #regionMethods (1)
+ public override byte[] Save()
+ {
+ using (BinaryWriter writer = new BinaryWriter(new MemoryStream()))
+ {
+ writer.Write(owID);
+ writer.Write(spriteID);
+ writer.Write(movement);
+ writer.Write(type);
+ writer.Write(flag);
+ writer.Write(scriptNumber);
+ writer.Write(orientation);
+ writer.Write(sightRange);
+ writer.Write(unknown1);
+ writer.Write(unknown2);
+ writer.Write(xRange);
+ writer.Write(yRange);
+ short xCoordinate = (short)(xMapPosition + 32 * xMatrixPosition);
+ writer.Write(xCoordinate);
+ short yCoordinate = (short)(yMapPosition + 32 * yMatrixPosition);
+ writer.Write(yCoordinate);
+ writer.Write(zPosition);
+ writer.Write(unknown3);
+
+ return ((MemoryStream)writer.BaseStream).ToArray();
+ }
+ }
+ #endregion
+
+ }
+
+ public class Warp : Event
+ {
+ #regionFields(4)
+ public ushort header;
+ public ushort anchor;
+ public ushort unknown1;
+ public ushort unknown2;
+ #endregion
+
+ #regionConstructors(2)
+ public Warp(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ /* Decompose x-y coordinates in matrix and map positions */
+ int xPosition = reader.ReadInt16();
+ int yPosition = reader.ReadInt16();
+ xMapPosition = (short)(xPosition % 32);
+ yMapPosition = (short)(yPosition % 32);
+ xMatrixPosition = (ushort)(xPosition / 32);
+ yMatrixPosition = (ushort)(yPosition / 32);
+
+ header = reader.ReadUInt16();
+ anchor = reader.ReadUInt16();
+ unknown1 = reader.ReadUInt16();
+ unknown2 = reader.ReadUInt16();
+ }
+ }
+ public Warp(int xMatrixPosition, int yMatrixPosition)
+ {
+ header = 0;
+ anchor = 0;
+
+ xMapPosition = 0;
+ yMapPosition = 0;
+ this.xMatrixPosition = (ushort)xMatrixPosition;
+ this.yMatrixPosition = (ushort)yMatrixPosition;
+ }
+ #endregion
+
+ #regionMethods (1)
+ public override byte[] Save()
+ {
+ using (BinaryWriter writer = new BinaryWriter(new MemoryStream()))
+ {
+ ushort xCoordinate = (ushort)(xMapPosition + 32 * xMatrixPosition);
+ writer.Write(xCoordinate);
+ ushort yCoordinate = (ushort)(yMapPosition + 32 * yMatrixPosition);
+ writer.Write(yCoordinate);
+ writer.Write(header);
+ writer.Write(anchor);
+ writer.Write(unknown1);
+ writer.Write(unknown2);
+
+ return ((MemoryStream)writer.BaseStream).ToArray();
+ }
+ }
+ #endregion
+
+ }
+
+ public class Trigger : Event
+ {
+ #regionFields(7)
+ public ushort scriptNumber;
+ public ushort width;
+ public ushort length;
+ public ushort unknown1;
+ public ushort unknown2;
+ public ushort flag;
+ #endregionFields
+
+ #regionConstructors(2)
+ public Trigger(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ scriptNumber = reader.ReadUInt16();
+
+ /* Decompose x-y coordinates in matrix and map positions */
+ int xPosition = reader.ReadInt16();
+ int yPosition = reader.ReadInt16();
+ xMapPosition = (short)(xPosition % 32);
+ yMapPosition = (short)(yPosition % 32);
+ xMatrixPosition = (ushort)(xPosition / 32);
+ yMatrixPosition = (ushort)(yPosition / 32);
+
+ width = reader.ReadUInt16();
+ length = reader.ReadUInt16();
+ unknown1 = reader.ReadUInt16();
+ unknown2 = reader.ReadUInt16();
+ flag = reader.ReadUInt16();
+ }
+ }
+ public Trigger(int xMatrixPosition, int yMatrixPosition)
+ {
+ scriptNumber = 0;
+ flag = 0;
+ width = 1;
+ length = 1;
+
+ xMapPosition = 0;
+ yMapPosition = 0;
+ this.xMatrixPosition = (ushort)xMatrixPosition;
+ this.yMatrixPosition = (ushort)yMatrixPosition;
+ }
+ #endregion
+
+ #regionMethods (1)
+ public override byte[] Save()
+ {
+ using (BinaryWriter writer = new BinaryWriter(new MemoryStream()))
+ {
+ writer.Write(scriptNumber);
+ ushort xCoordinate = (ushort)(xMapPosition + 32 * xMatrixPosition);
+ writer.Write(xCoordinate);
+ ushort yCoordinate = (ushort)(yMapPosition + 32 * yMatrixPosition);
+ writer.Write(yCoordinate);
+ writer.Write(width);
+ writer.Write(length);
+ writer.Write(unknown1);
+ writer.Write(unknown2);
+ writer.Write(flag);
+
+ return ((MemoryStream)writer.BaseStream).ToArray();
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/GiveItemDialog.Designer.cs b/DS_Map/GiveItemDialog.Designer.cs
new file mode 100644
index 0000000..f960727
--- /dev/null
+++ b/DS_Map/GiveItemDialog.Designer.cs
@@ -0,0 +1,109 @@
+namespace DS_Map
+{
+ partial class GiveItemDialog
+ {
+ ///
+ /// 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 Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.itemComboBox = new System.Windows.Forms.ComboBox();
+ this.itemLabel = new System.Windows.Forms.Label();
+ this.quantityNumericUpDown = new System.Windows.Forms.NumericUpDown();
+ this.label1 = new System.Windows.Forms.Label();
+ this.okButton = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.quantityNumericUpDown)).BeginInit();
+ this.SuspendLayout();
+ //
+ // itemComboBox
+ //
+ this.itemComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.itemComboBox.FormattingEnabled = true;
+ this.itemComboBox.Location = new System.Drawing.Point(12, 32);
+ this.itemComboBox.Name = "itemComboBox";
+ this.itemComboBox.Size = new System.Drawing.Size(154, 21);
+ this.itemComboBox.TabIndex = 0;
+ //
+ // itemLabel
+ //
+ this.itemLabel.AutoSize = true;
+ this.itemLabel.Location = new System.Drawing.Point(12, 15);
+ this.itemLabel.Name = "itemLabel";
+ this.itemLabel.Size = new System.Drawing.Size(27, 13);
+ this.itemLabel.TabIndex = 1;
+ this.itemLabel.Text = "Item";
+ //
+ // quantityNumericUpDown
+ //
+ this.quantityNumericUpDown.Location = new System.Drawing.Point(179, 33);
+ this.quantityNumericUpDown.Name = "quantityNumericUpDown";
+ this.quantityNumericUpDown.Size = new System.Drawing.Size(78, 20);
+ this.quantityNumericUpDown.TabIndex = 2;
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(176, 15);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(46, 13);
+ this.label1.TabIndex = 3;
+ this.label1.Text = "Quantity";
+ //
+ // okButton
+ //
+ this.okButton.Location = new System.Drawing.Point(12, 67);
+ this.okButton.Name = "okButton";
+ this.okButton.Size = new System.Drawing.Size(245, 23);
+ this.okButton.TabIndex = 4;
+ this.okButton.Text = "OK";
+ this.okButton.UseVisualStyleBackColor = true;
+ this.okButton.Click += new System.EventHandler(this.okButton_Click);
+ //
+ // GiveItemDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(275, 102);
+ this.Controls.Add(this.okButton);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.quantityNumericUpDown);
+ this.Controls.Add(this.itemLabel);
+ this.Controls.Add(this.itemComboBox);
+ this.Name = "GiveItemDialog";
+ this.Text = "Give Item";
+ ((System.ComponentModel.ISupportInitialize)(this.quantityNumericUpDown)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ public System.Windows.Forms.ComboBox itemComboBox;
+ private System.Windows.Forms.Label itemLabel;
+ public System.Windows.Forms.NumericUpDown quantityNumericUpDown;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Button okButton;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/GiveItemDialog.cs b/DS_Map/GiveItemDialog.cs
new file mode 100644
index 0000000..a9a2562
--- /dev/null
+++ b/DS_Map/GiveItemDialog.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Windows.Forms;
+
+namespace DS_Map
+{
+ public partial class GiveItemDialog : Form
+ {
+ public bool okSelected = new bool();
+ public string command;
+
+ public GiveItemDialog(string[] itemNames)
+ {
+ InitializeComponent();
+ itemComboBox.DataSource = itemNames;
+ }
+
+ private void okButton_Click(object sender, EventArgs e)
+ {
+ okSelected = true;
+ this.Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/GiveItemDialog.resx b/DS_Map/GiveItemDialog.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/GiveItemDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
\ No newline at end of file
diff --git a/DS_Map/GivePokémonDialog.Designer.cs b/DS_Map/GivePokémonDialog.Designer.cs
new file mode 100644
index 0000000..7f44313
--- /dev/null
+++ b/DS_Map/GivePokémonDialog.Designer.cs
@@ -0,0 +1,260 @@
+namespace DS_Map
+{
+ partial class GivePokémonDialog
+ {
+ ///
+ /// 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 Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.speciesComboBox = new System.Windows.Forms.ComboBox();
+ this.levelNumericUpDown = new System.Windows.Forms.NumericUpDown();
+ this.label2 = new System.Windows.Forms.Label();
+ this.movesetCheckBox = new System.Windows.Forms.CheckBox();
+ this.movesetGroupBox = new System.Windows.Forms.GroupBox();
+ this.label6 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.move4ComboBox = new System.Windows.Forms.ComboBox();
+ this.move3ComboBox = new System.Windows.Forms.ComboBox();
+ this.move2ComboBox = new System.Windows.Forms.ComboBox();
+ this.move1ComboBox = new System.Windows.Forms.ComboBox();
+ this.okButton = new System.Windows.Forms.Button();
+ this.itemLabel = new System.Windows.Forms.Label();
+ this.itemComboBox = new System.Windows.Forms.ComboBox();
+ ((System.ComponentModel.ISupportInitialize)(this.levelNumericUpDown)).BeginInit();
+ this.movesetGroupBox.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(8, 12);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(45, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Species";
+ //
+ // speciesComboBox
+ //
+ this.speciesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.speciesComboBox.FormattingEnabled = true;
+ this.speciesComboBox.Location = new System.Drawing.Point(12, 28);
+ this.speciesComboBox.Name = "speciesComboBox";
+ this.speciesComboBox.Size = new System.Drawing.Size(151, 21);
+ this.speciesComboBox.TabIndex = 1;
+ //
+ // levelNumericUpDown
+ //
+ this.levelNumericUpDown.Location = new System.Drawing.Point(202, 28);
+ this.levelNumericUpDown.Name = "levelNumericUpDown";
+ this.levelNumericUpDown.Size = new System.Drawing.Size(95, 20);
+ this.levelNumericUpDown.TabIndex = 2;
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(199, 12);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(33, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Level";
+ //
+ // movesetCheckBox
+ //
+ this.movesetCheckBox.AutoSize = true;
+ this.movesetCheckBox.Enabled = false;
+ this.movesetCheckBox.Location = new System.Drawing.Point(202, 87);
+ this.movesetCheckBox.Name = "movesetCheckBox";
+ this.movesetCheckBox.Size = new System.Drawing.Size(128, 17);
+ this.movesetCheckBox.TabIndex = 7;
+ this.movesetCheckBox.Text = "Moveset (HGSS only)";
+ this.movesetCheckBox.UseVisualStyleBackColor = true;
+ this.movesetCheckBox.CheckedChanged += new System.EventHandler(this.movesetCheckBox_CheckedChanged);
+ //
+ // movesetGroupBox
+ //
+ this.movesetGroupBox.Controls.Add(this.label6);
+ this.movesetGroupBox.Controls.Add(this.label5);
+ this.movesetGroupBox.Controls.Add(this.label4);
+ this.movesetGroupBox.Controls.Add(this.label3);
+ this.movesetGroupBox.Controls.Add(this.move4ComboBox);
+ this.movesetGroupBox.Controls.Add(this.move3ComboBox);
+ this.movesetGroupBox.Controls.Add(this.move2ComboBox);
+ this.movesetGroupBox.Controls.Add(this.move1ComboBox);
+ this.movesetGroupBox.Enabled = false;
+ this.movesetGroupBox.Location = new System.Drawing.Point(11, 112);
+ this.movesetGroupBox.Name = "movesetGroupBox";
+ this.movesetGroupBox.Size = new System.Drawing.Size(319, 145);
+ this.movesetGroupBox.TabIndex = 8;
+ this.movesetGroupBox.TabStop = false;
+ this.movesetGroupBox.Text = "Moveset";
+ //
+ // label6
+ //
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(160, 87);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(43, 13);
+ this.label6.TabIndex = 7;
+ this.label6.Text = "Move 4";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(5, 87);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(43, 13);
+ this.label5.TabIndex = 6;
+ this.label5.Text = "Move 3";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(160, 26);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(43, 13);
+ this.label4.TabIndex = 5;
+ this.label4.Text = "Move 2";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(5, 26);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(43, 13);
+ this.label3.TabIndex = 4;
+ this.label3.Text = "Move 1";
+ //
+ // move4ComboBox
+ //
+ this.move4ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.move4ComboBox.FormattingEnabled = true;
+ this.move4ComboBox.Location = new System.Drawing.Point(163, 103);
+ this.move4ComboBox.Name = "move4ComboBox";
+ this.move4ComboBox.Size = new System.Drawing.Size(147, 21);
+ this.move4ComboBox.TabIndex = 3;
+ //
+ // move3ComboBox
+ //
+ this.move3ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.move3ComboBox.FormattingEnabled = true;
+ this.move3ComboBox.Location = new System.Drawing.Point(8, 103);
+ this.move3ComboBox.Name = "move3ComboBox";
+ this.move3ComboBox.Size = new System.Drawing.Size(144, 21);
+ this.move3ComboBox.TabIndex = 2;
+ //
+ // move2ComboBox
+ //
+ this.move2ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.move2ComboBox.FormattingEnabled = true;
+ this.move2ComboBox.Location = new System.Drawing.Point(163, 42);
+ this.move2ComboBox.Name = "move2ComboBox";
+ this.move2ComboBox.Size = new System.Drawing.Size(147, 21);
+ this.move2ComboBox.TabIndex = 1;
+ //
+ // move1ComboBox
+ //
+ this.move1ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.move1ComboBox.FormattingEnabled = true;
+ this.move1ComboBox.Location = new System.Drawing.Point(8, 42);
+ this.move1ComboBox.Name = "move1ComboBox";
+ this.move1ComboBox.Size = new System.Drawing.Size(144, 21);
+ this.move1ComboBox.TabIndex = 0;
+ //
+ // okButton
+ //
+ this.okButton.Location = new System.Drawing.Point(247, 263);
+ this.okButton.Name = "okButton";
+ this.okButton.Size = new System.Drawing.Size(75, 23);
+ this.okButton.TabIndex = 9;
+ this.okButton.Text = "OK";
+ this.okButton.UseVisualStyleBackColor = true;
+ this.okButton.Click += new System.EventHandler(this.okButton_Click);
+ //
+ // itemLabel
+ //
+ this.itemLabel.AutoSize = true;
+ this.itemLabel.Location = new System.Drawing.Point(10, 63);
+ this.itemLabel.Name = "itemLabel";
+ this.itemLabel.Size = new System.Drawing.Size(27, 13);
+ this.itemLabel.TabIndex = 11;
+ this.itemLabel.Text = "Item";
+ //
+ // itemComboBox
+ //
+ this.itemComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.itemComboBox.FormattingEnabled = true;
+ this.itemComboBox.Location = new System.Drawing.Point(13, 80);
+ this.itemComboBox.Name = "itemComboBox";
+ this.itemComboBox.Size = new System.Drawing.Size(150, 21);
+ this.itemComboBox.TabIndex = 12;
+ //
+ // GivePokémonDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(343, 292);
+ this.Controls.Add(this.itemComboBox);
+ this.Controls.Add(this.itemLabel);
+ this.Controls.Add(this.okButton);
+ this.Controls.Add(this.movesetGroupBox);
+ this.Controls.Add(this.movesetCheckBox);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.levelNumericUpDown);
+ this.Controls.Add(this.speciesComboBox);
+ this.Controls.Add(this.label1);
+ this.Name = "GivePokémonDialog";
+ this.Text = "Give Pokémon";
+ ((System.ComponentModel.ISupportInitialize)(this.levelNumericUpDown)).EndInit();
+ this.movesetGroupBox.ResumeLayout(false);
+ this.movesetGroupBox.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.ComboBox speciesComboBox;
+ private System.Windows.Forms.NumericUpDown levelNumericUpDown;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.CheckBox movesetCheckBox;
+ private System.Windows.Forms.GroupBox movesetGroupBox;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.ComboBox move4ComboBox;
+ private System.Windows.Forms.ComboBox move3ComboBox;
+ private System.Windows.Forms.ComboBox move2ComboBox;
+ private System.Windows.Forms.ComboBox move1ComboBox;
+ private System.Windows.Forms.Button okButton;
+ private System.Windows.Forms.Label itemLabel;
+ private System.Windows.Forms.ComboBox itemComboBox;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/GivePokémonDialog.cs b/DS_Map/GivePokémonDialog.cs
new file mode 100644
index 0000000..86f3a71
--- /dev/null
+++ b/DS_Map/GivePokémonDialog.cs
@@ -0,0 +1,36 @@
+using System.Windows.Forms;
+
+namespace DS_Map
+{
+ public partial class GivePokémonDialog : Form
+ {
+ public string command = "GivePokémon ";
+ public bool okSelected;
+ public GivePokémonDialog(string[] pokémonNames, string[] itemNames, string[] moveNames)
+ {
+ InitializeComponent();
+ speciesComboBox.DataSource = pokémonNames;
+ itemComboBox.DataSource = itemNames;
+ move1ComboBox.Items.AddRange(moveNames);
+ move2ComboBox.Items.AddRange(moveNames);
+ move3ComboBox.Items.AddRange(moveNames);
+ move4ComboBox.Items.AddRange(moveNames);
+ }
+
+ private void movesetCheckBox_CheckedChanged(object sender, System.EventArgs e)
+ {
+ if (movesetCheckBox.Checked) movesetGroupBox.Enabled = true;
+ else movesetGroupBox.Enabled = false;
+ }
+
+ private void okButton_Click(object sender, System.EventArgs e)
+ {
+ command += "0x" + speciesComboBox.SelectedIndex.ToString("X") + " ";
+ command += "0x" + ((int)levelNumericUpDown.Value).ToString("X") + " ";
+ command += "0x" + itemComboBox.SelectedIndex.ToString("X") + " ";
+ command += "0x800C";
+ okSelected = true;
+ this.Close();
+ }
+ }
+}
diff --git a/DS_Map/GivePokémonDialog.resx b/DS_Map/GivePokémonDialog.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/GivePokémonDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
\ No newline at end of file
diff --git a/DS_Map/Graphics/Area Icons/areaicon00.png b/DS_Map/Graphics/Area Icons/areaicon00.png
new file mode 100644
index 0000000..160762b
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon00.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon01.png b/DS_Map/Graphics/Area Icons/areaicon01.png
new file mode 100644
index 0000000..160762b
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon01.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon02.png b/DS_Map/Graphics/Area Icons/areaicon02.png
new file mode 100644
index 0000000..a8c5464
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon02.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon03.png b/DS_Map/Graphics/Area Icons/areaicon03.png
new file mode 100644
index 0000000..dd515f8
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon03.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon04.png b/DS_Map/Graphics/Area Icons/areaicon04.png
new file mode 100644
index 0000000..72f252e
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon04.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon05.png b/DS_Map/Graphics/Area Icons/areaicon05.png
new file mode 100644
index 0000000..8210bce
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon05.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon06.png b/DS_Map/Graphics/Area Icons/areaicon06.png
new file mode 100644
index 0000000..923d551
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon06.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon07.png b/DS_Map/Graphics/Area Icons/areaicon07.png
new file mode 100644
index 0000000..30b5df8
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon07.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon08.png b/DS_Map/Graphics/Area Icons/areaicon08.png
new file mode 100644
index 0000000..8b0e47f
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon08.png differ
diff --git a/DS_Map/Graphics/Area Icons/areaicon09.png b/DS_Map/Graphics/Area Icons/areaicon09.png
new file mode 100644
index 0000000..6572778
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/areaicon09.png differ
diff --git a/DS_Map/Graphics/Area Icons/dp.png b/DS_Map/Graphics/Area Icons/dp.png
new file mode 100644
index 0000000..7c39ffa
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/dp.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgsscave.png b/DS_Map/Graphics/Area Icons/hgsscave.png
new file mode 100644
index 0000000..955e39b
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgsscave.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgssfield.png b/DS_Map/Graphics/Area Icons/hgssfield.png
new file mode 100644
index 0000000..68b6ed4
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgssfield.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgssforest.png b/DS_Map/Graphics/Area Icons/hgssforest.png
new file mode 100644
index 0000000..58346fb
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgssforest.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgssgray.png b/DS_Map/Graphics/Area Icons/hgssgray.png
new file mode 100644
index 0000000..1f8d320
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgssgray.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgsstown.png b/DS_Map/Graphics/Area Icons/hgsstown.png
new file mode 100644
index 0000000..92284db
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgsstown.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgsswall.png b/DS_Map/Graphics/Area Icons/hgsswall.png
new file mode 100644
index 0000000..1ba3b8b
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgsswall.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgsswater.png b/DS_Map/Graphics/Area Icons/hgsswater.png
new file mode 100644
index 0000000..c749af9
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgsswater.png differ
diff --git a/DS_Map/Graphics/Area Icons/hgsswood.png b/DS_Map/Graphics/Area Icons/hgsswood.png
new file mode 100644
index 0000000..ec9c093
Binary files /dev/null and b/DS_Map/Graphics/Area Icons/hgsswood.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera0.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera0.png
new file mode 100644
index 0000000..79cda7c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera0.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera1.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera1.png
new file mode 100644
index 0000000..75b87c0
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera1.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera10.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera10.png
new file mode 100644
index 0000000..7f89c59
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera10.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera11.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera11.png
new file mode 100644
index 0000000..cb106ed
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera11.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera12.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera12.png
new file mode 100644
index 0000000..bd84c3d
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera12.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera13.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera13.png
new file mode 100644
index 0000000..310e5a3
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera13.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera14.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera14.png
new file mode 100644
index 0000000..53b4d74
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera14.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera15.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera15.png
new file mode 100644
index 0000000..9189a54
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera15.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera2.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera2.png
new file mode 100644
index 0000000..9f48e63
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera2.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera3.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera3.png
new file mode 100644
index 0000000..28f616c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera3.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera4.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera4.png
new file mode 100644
index 0000000..0f59b19
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera4.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera5.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera5.png
new file mode 100644
index 0000000..12792a4
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera5.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera6.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera6.png
new file mode 100644
index 0000000..256e506
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera6.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera7.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera7.png
new file mode 100644
index 0000000..6d92556
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera7.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera8.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera8.png
new file mode 100644
index 0000000..90047af
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera8.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/dpcamera9.png b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera9.png
new file mode 100644
index 0000000..933a4f9
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/dpcamera9.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera0.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera0.png
new file mode 100644
index 0000000..732a04c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera0.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera1.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera1.png
new file mode 100644
index 0000000..1572b45
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera1.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera10.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera10.png
new file mode 100644
index 0000000..1e8fc6b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera10.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera11.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera11.png
new file mode 100644
index 0000000..1e8fc6b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera11.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera12.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera12.png
new file mode 100644
index 0000000..1c6ca86
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera12.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera13.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera13.png
new file mode 100644
index 0000000..e7a6e7c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera13.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera14.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera14.png
new file mode 100644
index 0000000..1a70e86
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera14.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera15.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera15.png
new file mode 100644
index 0000000..df647a1
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera15.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera2.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera2.png
new file mode 100644
index 0000000..25d3ed2
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera2.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera3.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera3.png
new file mode 100644
index 0000000..e09c86c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera3.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera4.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera4.png
new file mode 100644
index 0000000..9160128
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera4.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera5.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera5.png
new file mode 100644
index 0000000..fa37d1c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera5.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera6.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera6.png
new file mode 100644
index 0000000..4aef89e
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera6.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera7.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera7.png
new file mode 100644
index 0000000..0b582a8
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera7.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera8.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera8.png
new file mode 100644
index 0000000..b69096c
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera8.png differ
diff --git a/DS_Map/Graphics/Camera Angles/DPPt/ptcamera9.png b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera9.png
new file mode 100644
index 0000000..4bbb52a
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/DPPt/ptcamera9.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera000.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera000.png
new file mode 100644
index 0000000..bc70052
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera000.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera001.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera001.png
new file mode 100644
index 0000000..c56240b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera001.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera002.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera002.png
new file mode 100644
index 0000000..c56240b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera002.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera003.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera003.png
new file mode 100644
index 0000000..c56240b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera003.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera004.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera004.png
new file mode 100644
index 0000000..c56240b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera004.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera006.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera006.png
new file mode 100644
index 0000000..c56240b
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera006.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera020.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera020.png
new file mode 100644
index 0000000..926760a
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera020.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera036.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera036.png
new file mode 100644
index 0000000..20496ad
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera036.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera049.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera049.png
new file mode 100644
index 0000000..7155238
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera049.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera051.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera051.png
new file mode 100644
index 0000000..7155238
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera051.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera067.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera067.png
new file mode 100644
index 0000000..b5df5f6
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera067.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera068.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera068.png
new file mode 100644
index 0000000..b5df5f6
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera068.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera084.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera084.png
new file mode 100644
index 0000000..d5f562e
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera084.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera116.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera116.png
new file mode 100644
index 0000000..8b56991
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera116.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera129.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera129.png
new file mode 100644
index 0000000..d2c7af6
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera129.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera148.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera148.png
new file mode 100644
index 0000000..c44944d
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera148.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera163.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera163.png
new file mode 100644
index 0000000..4d791e0
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera163.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera195.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera195.png
new file mode 100644
index 0000000..e39e883
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera195.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera211.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera211.png
new file mode 100644
index 0000000..03136ce
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera211.png differ
diff --git a/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera244.png b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera244.png
new file mode 100644
index 0000000..3e59381
Binary files /dev/null and b/DS_Map/Graphics/Camera Angles/HGSS/hgsscamera244.png differ
diff --git a/DS_Map/Graphics/ColorTable.txt b/DS_Map/Graphics/ColorTable.txt
new file mode 100644
index 0000000..ae2507b
--- /dev/null
+++ b/DS_Map/Graphics/ColorTable.txt
@@ -0,0 +1,256 @@
+0x00 #FFFFFF #000000
+0x01 #FFFFFF #000000
+0x02 #009900 #000000
+0x03 #006600 #FFFFFF
+0x04 #FFFFFF #000000
+0x05 #FFFFFF #000000
+0x06 #FFFFFF #000000
+0x07 #FFFFFF #000000
+0x08 #FFFFFF #000000
+0x09 #FFFFFF #000000
+0x0A #FFFFFF #000000
+0x0B #FFFFFF #000000
+0x0C #FFFFFF #000000
+0x0D #FFFFFF #000000
+0x0E #FFFFFF #000000
+0x0F #FFFFFF #000000
+0x10 #0099FF #000000
+0x11 #FFFFFF #000000
+0x12 #FFFFFF #000000
+0x13 #FFFFFF #000000
+0x14 #FFFFFF #000000
+0x15 #0066FF #FFFFFF
+0x16 #99FFFF #000000
+0x17 #FFFFFF #000000
+0x18 #FFFFFF #000000
+0x19 #FFFFFF #000000
+0x1A #FFFFFF #000000
+0x1B #FFFFFF #000000
+0x1C #FFFFFF #000000
+0x1D #FFFFFF #000000
+0x1E #FFFFFF #000000
+0x1F #FFFFFF #000000
+0x20 #FFFFFF #000000
+0x21 #FFFF99 #000000
+0x22 #FFFFFF #000000
+0x23 #FFFFFF #000000
+0x24 #FFFFFF #000000
+0x25 #FFFFFF #000000
+0x26 #FFFFFF #000000
+0x27 #FFFFFF #000000
+0x28 #FFFFFF #000000
+0x29 #FFFFFF #000000
+0x2A #FFFFFF #000000
+0x2B #FFFFFF #000000
+0x2C #FFFFFF #000000
+0x2D #FFFFFF #000000
+0x2E #FFFFFF #000000
+0x2F #FFFFFF #000000
+0x30 #FFFFFF #000000
+0x31 #FFFFFF #000000
+0x32 #FFFFFF #000000
+0x33 #FFFFFF #000000
+0x34 #FFFFFF #000000
+0x35 #FFFFFF #000000
+0x36 #FFFFFF #000000
+0x37 #FFFFFF #000000
+0x38 #8A4B08 #FFFFFF
+0x39 #8A4B08 #FFFFFF
+0x3A #8A4B08 #FFFFFF
+0x3B #8A4B08 #FFFFFF
+0x3C #FFFFFF #000000
+0x3D #FFFFFF #000000
+0x3E #FFFFFF #000000
+0x3F #FFFFFF #000000
+0x40 #FFFFFF #000000
+0x41 #FFFFFF #000000
+0x42 #FFFFFF #000000
+0x43 #FFFFFF #000000
+0x44 #FFFFFF #000000
+0x45 #FFFFFF #000000
+0x46 #FFFFFF #000000
+0x47 #FFFFFF #000000
+0x48 #FFFFFF #000000
+0x49 #FFFFFF #000000
+0x4A #FFFFFF #000000
+0x4B #FFFFFF #000000
+0x4C #FFFFFF #000000
+0x4D #FFFFFF #000000
+0x4E #FFFFFF #000000
+0x4F #FFFFFF #000000
+0x50 #FFFFFF #000000
+0x51 #FFFFFF #000000
+0x52 #FFFFFF #000000
+0x53 #FFFFFF #000000
+0x54 #FFFFFF #000000
+0x55 #FFFFFF #000000
+0x56 #FFFFFF #000000
+0x57 #FFFFFF #000000
+0x58 #FFFFFF #000000
+0x59 #FFFFFF #000000
+0x5A #FFFFFF #000000
+0x5B #FFFFFF #000000
+0x5C #FFFFFF #000000
+0x5D #FFFFFF #000000
+0x5E #FFFFFF #000000
+0x5F #FFFFFF #000000
+0x60 #FFFFFF #000000
+0x61 #FFFFFF #000000
+0x62 #FFFFFF #000000
+0x63 #FFFFFF #000000
+0x64 #FFFFFF #000000
+0x65 #FFFFFF #000000
+0x66 #FFFFFF #000000
+0x67 #FFFFFF #000000
+0x68 #FFFFFF #000000
+0x69 #9900FF #FFFFFF
+0x6A #FFFFFF #000000
+0x6B #FFFFFF #000000
+0x6C #FFFFFF #000000
+0x6D #FFFFFF #000000
+0x6E #9900FF #FFFFFF
+0x6F #FFFFFF #000000
+0x70 #FF9900 #000000
+0x71 #FF9900 #000000
+0x72 #FF9900 #000000
+0x73 #FF9900 #000000
+0x74 #FFFFFF #000000
+0x75 #FFFFFF #000000
+0x76 #FFFFFF #000000
+0x77 #FFFFFF #000000
+0x78 #FFFFFF #000000
+0x79 #FFFFFF #000000
+0x7A #FFFFFF #000000
+0x7B #FFFFFF #000000
+0x7C #FFFFFF #000000
+0x7D #FFFFFF #000000
+0x7E #FFFFFF #000000
+0x7F #FFFFFF #000000
+0x80 #FFFFFF #000000
+0x81 #FFFFFF #000000
+0x82 #FFFFFF #000000
+0x83 #FFFFFF #000000
+0x84 #FFFFFF #000000
+0x85 #FFFFFF #000000
+0x86 #FFFFFF #000000
+0x87 #FFFFFF #000000
+0x88 #FFFFFF #000000
+0x89 #FFFFFF #000000
+0x8A #FFFFFF #000000
+0x8B #FFFFFF #000000
+0x8C #FFFFFF #000000
+0x8D #FFFFFF #000000
+0x8E #FFFFFF #000000
+0x8F #FFFFFF #000000
+0x90 #FFFFFF #000000
+0x91 #FFFFFF #000000
+0x92 #FFFFFF #000000
+0x93 #FFFFFF #000000
+0x94 #FFFFFF #000000
+0x95 #FFFFFF #000000
+0x96 #FFFFFF #000000
+0x97 #FFFFFF #000000
+0x98 #FFFFFF #000000
+0x99 #FFFFFF #000000
+0x9A #FFFFFF #000000
+0x9B #FFFFFF #000000
+0x9C #FFFFFF #000000
+0x9D #FFFFFF #000000
+0x9E #FFFFFF #000000
+0x9F #FFFFFF #000000
+0xA0 #FFFFFF #000000
+0xA1 #FFFFFF #000000
+0xA2 #FFFFFF #000000
+0xA3 #FFFFFF #000000
+0xA4 #FFFFFF #000000
+0xA5 #FFFFFF #000000
+0xA6 #FFFFFF #000000
+0xA7 #FFFFFF #000000
+0xA8 #FFFFFF #000000
+0xA9 #FFFFFF #000000
+0xAA #FFFFFF #000000
+0xAB #FFFFFF #000000
+0xAC #FFFFFF #000000
+0xAD #FFFFFF #000000
+0xAE #FFFFFF #000000
+0xAF #FFFFFF #000000
+0xB0 #FFFFFF #000000
+0xB1 #FFFFFF #000000
+0xB2 #FFFFFF #000000
+0xB3 #FFFFFF #000000
+0xB4 #FFFFFF #000000
+0xB5 #FFFFFF #000000
+0xB6 #FFFFFF #000000
+0xB7 #FFFFFF #000000
+0xB8 #FFFFFF #000000
+0xB9 #FFFFFF #000000
+0xBA #FFFFFF #000000
+0xBB #FFFFFF #000000
+0xBC #FFFFFF #000000
+0xBD #FFFFFF #000000
+0xBE #FFFFFF #000000
+0xBF #FFFFFF #000000
+0xC0 #FFFFFF #000000
+0xC1 #FFFFFF #000000
+0xC2 #FFFFFF #000000
+0xC3 #FFFFFF #000000
+0xC4 #FFFFFF #000000
+0xC5 #FFFFFF #000000
+0xC6 #FFFFFF #000000
+0xC7 #FFFFFF #000000
+0xC8 #FFFFFF #000000
+0xC9 #FFFFFF #000000
+0xCA #FFFFFF #000000
+0xCB #FFFFFF #000000
+0xCC #FFFFFF #000000
+0xCD #FFFFFF #000000
+0xCE #FFFFFF #000000
+0xCF #FFFFFF #000000
+0xD0 #FFFFFF #000000
+0xD1 #FFFFFF #000000
+0xD2 #FFFFFF #000000
+0xD3 #FFFFFF #000000
+0xD4 #FFFFFF #000000
+0xD5 #FFFFFF #000000
+0xD6 #FFFFFF #000000
+0xD7 #FFFFFF #000000
+0xD8 #FFFFFF #000000
+0xD9 #FFFFFF #000000
+0xDA #FFFFFF #000000
+0xDB #FFFFFF #000000
+0xDC #FFFFFF #000000
+0xDD #FFFFFF #000000
+0xDE #FFFFFF #000000
+0xDF #FFFFFF #000000
+0xE0 #FFFFFF #000000
+0xE1 #FFFFFF #000000
+0xE2 #FFFFFF #000000
+0xE3 #FFFFFF #000000
+0xE4 #FFFFFF #000000
+0xE5 #FFFFFF #000000
+0xE6 #FFFFFF #000000
+0xE7 #FFFFFF #000000
+0xE8 #FFFFFF #000000
+0xE9 #FFFFFF #000000
+0xEA #FFFFFF #000000
+0xEB #FFFFFF #000000
+0xEC #FFFFFF #000000
+0xED #FFFFFF #000000
+0xEE #FFFFFF #000000
+0xEF #FFFFFF #000000
+0xF0 #FFFFFF #000000
+0xF1 #FFFFFF #000000
+0xF2 #FFFFFF #000000
+0xF3 #FFFFFF #000000
+0xF4 #FFFFFF #000000
+0xF5 #FFFFFF #000000
+0xF6 #FFFFFF #000000
+0xF7 #FFFFFF #000000
+0xF8 #FFFFFF #000000
+0xF9 #FFFFFF #000000
+0xFA #FFFFFF #000000
+0xFB #FFFFFF #000000
+0xFC #FFFFFF #000000
+0xFD #FFFFFF #000000
+0xFE #FFFFFF #000000
+0xFF #FFFFFF #000000
\ No newline at end of file
diff --git a/DS_Map/Graphics/Event Icons/blue_sign.png b/DS_Map/Graphics/Event Icons/blue_sign.png
new file mode 100644
index 0000000..d27997f
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/blue_sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/brown_sign.png b/DS_Map/Graphics/Event Icons/brown_sign.png
new file mode 100644
index 0000000..d1b3458
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/brown_sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/dawn_platinum.png b/DS_Map/Graphics/Event Icons/dawn_platinum.png
new file mode 100644
index 0000000..940f2bc
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/dawn_platinum.png differ
diff --git a/DS_Map/Graphics/Event Icons/dppt_suitcase.png b/DS_Map/Graphics/Event Icons/dppt_suitcase.png
new file mode 100644
index 0000000..4b944cb
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/dppt_suitcase.png differ
diff --git a/DS_Map/Graphics/Event Icons/gray_sign.png b/DS_Map/Graphics/Event Icons/gray_sign.png
new file mode 100644
index 0000000..50f96d5
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/gray_sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/overworld.png b/DS_Map/Graphics/Event Icons/overworld.png
new file mode 100644
index 0000000..a5fce40
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/overworld.png differ
diff --git a/DS_Map/Graphics/Event Icons/red_sign.png b/DS_Map/Graphics/Event Icons/red_sign.png
new file mode 100644
index 0000000..51c714a
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/red_sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/route_sign.png b/DS_Map/Graphics/Event Icons/route_sign.png
new file mode 100644
index 0000000..78cdcb8
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/route_sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/sign.png b/DS_Map/Graphics/Event Icons/sign.png
new file mode 100644
index 0000000..e4fa172
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/sign.png differ
diff --git a/DS_Map/Graphics/Event Icons/trigger.png b/DS_Map/Graphics/Event Icons/trigger.png
new file mode 100644
index 0000000..9304781
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/trigger.png differ
diff --git a/DS_Map/Graphics/Event Icons/warp.png b/DS_Map/Graphics/Event Icons/warp.png
new file mode 100644
index 0000000..626460b
Binary files /dev/null and b/DS_Map/Graphics/Event Icons/warp.png differ
diff --git a/DS_Map/Graphics/Program Icons/arrowdown.png b/DS_Map/Graphics/Program Icons/arrowdown.png
new file mode 100644
index 0000000..1dff350
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/arrowdown.png differ
diff --git a/DS_Map/Graphics/Program Icons/arrowleft.png b/DS_Map/Graphics/Program Icons/arrowleft.png
new file mode 100644
index 0000000..f6701b6
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/arrowleft.png differ
diff --git a/DS_Map/Graphics/Program Icons/arrowright.png b/DS_Map/Graphics/Program Icons/arrowright.png
new file mode 100644
index 0000000..d0f3e59
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/arrowright.png differ
diff --git a/DS_Map/Graphics/Program Icons/arrowup.png b/DS_Map/Graphics/Program Icons/arrowup.png
new file mode 100644
index 0000000..daa4831
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/arrowup.png differ
diff --git a/DS_Map/Graphics/Program Icons/building_editor.png b/DS_Map/Graphics/Program Icons/building_editor.png
new file mode 100644
index 0000000..073af87
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/building_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/clearflag.png b/DS_Map/Graphics/Program Icons/clearflag.png
new file mode 100644
index 0000000..baab1c1
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/clearflag.png differ
diff --git a/DS_Map/Graphics/Program Icons/closemsg.png b/DS_Map/Graphics/Program Icons/closemsg.png
new file mode 100644
index 0000000..ab7c915
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/closemsg.png differ
diff --git a/DS_Map/Graphics/Program Icons/dualslot_encounters.png b/DS_Map/Graphics/Program Icons/dualslot_encounters.png
new file mode 100644
index 0000000..87a7ebb
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/dualslot_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/egg.png b/DS_Map/Graphics/Program Icons/egg.png
new file mode 100644
index 0000000..eda8e8a
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/egg.png differ
diff --git a/DS_Map/Graphics/Program Icons/event_editor.png b/DS_Map/Graphics/Program Icons/event_editor.png
new file mode 100644
index 0000000..d413b27
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/event_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/give_badge.png b/DS_Map/Graphics/Program Icons/give_badge.png
new file mode 100644
index 0000000..9974683
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/give_badge.png differ
diff --git a/DS_Map/Graphics/Program Icons/give_pokedex.png b/DS_Map/Graphics/Program Icons/give_pokedex.png
new file mode 100644
index 0000000..d6773a9
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/give_pokedex.png differ
diff --git a/DS_Map/Graphics/Program Icons/give_pokegear.png b/DS_Map/Graphics/Program Icons/give_pokegear.png
new file mode 100644
index 0000000..5658318
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/give_pokegear.png differ
diff --git a/DS_Map/Graphics/Program Icons/give_shoes.png b/DS_Map/Graphics/Program Icons/give_shoes.png
new file mode 100644
index 0000000..50f23f0
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/give_shoes.png differ
diff --git a/DS_Map/Graphics/Program Icons/giveitem.png b/DS_Map/Graphics/Program Icons/giveitem.png
new file mode 100644
index 0000000..281c83d
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/giveitem.png differ
diff --git a/DS_Map/Graphics/Program Icons/givemom.png b/DS_Map/Graphics/Program Icons/givemom.png
new file mode 100644
index 0000000..4a06f73
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/givemom.png differ
diff --git a/DS_Map/Graphics/Program Icons/good_rod_encounters.png b/DS_Map/Graphics/Program Icons/good_rod_encounters.png
new file mode 100644
index 0000000..28a3591
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/good_rod_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/legendary_battle.png b/DS_Map/Graphics/Program Icons/legendary_battle.png
new file mode 100644
index 0000000..5ecf7b5
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/legendary_battle.png differ
diff --git a/DS_Map/Graphics/Program Icons/map_editor.png b/DS_Map/Graphics/Program Icons/map_editor.png
new file mode 100644
index 0000000..b7d9429
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/map_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/map_header.ico b/DS_Map/Graphics/Program Icons/map_header.ico
new file mode 100644
index 0000000..6312bd9
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/map_header.ico differ
diff --git a/DS_Map/Graphics/Program Icons/matrix_editor.png b/DS_Map/Graphics/Program Icons/matrix_editor.png
new file mode 100644
index 0000000..b2ed2c5
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/matrix_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/message.png b/DS_Map/Graphics/Program Icons/message.png
new file mode 100644
index 0000000..e5d2e9f
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/message.png differ
diff --git a/DS_Map/Graphics/Program Icons/money.png b/DS_Map/Graphics/Program Icons/money.png
new file mode 100644
index 0000000..c016427
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/money.png differ
diff --git a/DS_Map/Graphics/Program Icons/old_rod_encounters.png b/DS_Map/Graphics/Program Icons/old_rod_encounters.png
new file mode 100644
index 0000000..c92ffff
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/old_rod_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/open_file.png b/DS_Map/Graphics/Program Icons/open_file.png
new file mode 100644
index 0000000..f37bb3e
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/open_file.png differ
diff --git a/DS_Map/Graphics/Program Icons/pokéradar_encounters.png b/DS_Map/Graphics/Program Icons/pokéradar_encounters.png
new file mode 100644
index 0000000..91b1019
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/pokéradar_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/radio_encounters.png b/DS_Map/Graphics/Program Icons/radio_encounters.png
new file mode 100644
index 0000000..333ac5f
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/radio_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/rock_smash_encounters.png b/DS_Map/Graphics/Program Icons/rock_smash_encounters.png
new file mode 100644
index 0000000..ee3097b
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/rock_smash_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/save_rom.png b/DS_Map/Graphics/Program Icons/save_rom.png
new file mode 100644
index 0000000..3a9dcf3
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/save_rom.png differ
diff --git a/DS_Map/Graphics/Program Icons/script_editor.png b/DS_Map/Graphics/Program Icons/script_editor.png
new file mode 100644
index 0000000..61679c7
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/script_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/setflag.png b/DS_Map/Graphics/Program Icons/setflag.png
new file mode 100644
index 0000000..d1a063d
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/setflag.png differ
diff --git a/DS_Map/Graphics/Program Icons/super_rod_encounters.png b/DS_Map/Graphics/Program Icons/super_rod_encounters.png
new file mode 100644
index 0000000..f282099
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/super_rod_encounters.png differ
diff --git a/DS_Map/Graphics/Program Icons/takeitem.png b/DS_Map/Graphics/Program Icons/takeitem.png
new file mode 100644
index 0000000..b1b3f35
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/takeitem.png differ
diff --git a/DS_Map/Graphics/Program Icons/takemom.png b/DS_Map/Graphics/Program Icons/takemom.png
new file mode 100644
index 0000000..68d4688
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/takemom.png differ
diff --git a/DS_Map/Graphics/Program Icons/takemoney.png b/DS_Map/Graphics/Program Icons/takemoney.png
new file mode 100644
index 0000000..c318003
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/takemoney.png differ
diff --git a/DS_Map/Graphics/Program Icons/text_editor.png b/DS_Map/Graphics/Program Icons/text_editor.png
new file mode 100644
index 0000000..d8b2f10
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/text_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/texture_background.png b/DS_Map/Graphics/Program Icons/texture_background.png
new file mode 100644
index 0000000..172bf1e
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/texture_background.png differ
diff --git a/DS_Map/Graphics/Program Icons/tileset_editor.png b/DS_Map/Graphics/Program Icons/tileset_editor.png
new file mode 100644
index 0000000..84f2dc7
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/tileset_editor.png differ
diff --git a/DS_Map/Graphics/Program Icons/trainer_battle.png b/DS_Map/Graphics/Program Icons/trainer_battle.png
new file mode 100644
index 0000000..502055e
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/trainer_battle.png differ
diff --git a/DS_Map/Graphics/Program Icons/walking_encounters_dppt.png b/DS_Map/Graphics/Program Icons/walking_encounters_dppt.png
new file mode 100644
index 0000000..35b7432
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/walking_encounters_dppt.png differ
diff --git a/DS_Map/Graphics/Program Icons/walking_encounters_hgss.png b/DS_Map/Graphics/Program Icons/walking_encounters_hgss.png
new file mode 100644
index 0000000..25f4b00
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/walking_encounters_hgss.png differ
diff --git a/DS_Map/Graphics/Program Icons/wild_battle.png b/DS_Map/Graphics/Program Icons/wild_battle.png
new file mode 100644
index 0000000..8758674
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/wild_battle.png differ
diff --git a/DS_Map/Graphics/Program Icons/wild_editor.png b/DS_Map/Graphics/Program Icons/wild_editor.png
new file mode 100644
index 0000000..160e658
Binary files /dev/null and b/DS_Map/Graphics/Program Icons/wild_editor.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpblizzard.gif b/DS_Map/Graphics/Weather/DPPt/dpblizzard.gif
new file mode 100644
index 0000000..3a4392c
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpblizzard.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpcloudy.png b/DS_Map/Graphics/Weather/DPPt/dpcloudy.png
new file mode 100644
index 0000000..c6206a1
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpcloudy.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpdark.png b/DS_Map/Graphics/Weather/DPPt/dpdark.png
new file mode 100644
index 0000000..99c4d9a
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpdark.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpdiamondsnow.gif b/DS_Map/Graphics/Weather/DPPt/dpdiamondsnow.gif
new file mode 100644
index 0000000..09fdde2
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpdiamondsnow.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpfog.png b/DS_Map/Graphics/Weather/DPPt/dpfog.png
new file mode 100644
index 0000000..c796a84
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpfog.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dphail.gif b/DS_Map/Graphics/Weather/DPPt/dphail.gif
new file mode 100644
index 0000000..157fe5d
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dphail.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpheavyrain.gif b/DS_Map/Graphics/Weather/DPPt/dpheavyrain.gif
new file mode 100644
index 0000000..fbf2c86
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpheavyrain.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dplightning.gif b/DS_Map/Graphics/Weather/DPPt/dplightning.gif
new file mode 100644
index 0000000..400beff
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dplightning.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dplightsandstorm.gif b/DS_Map/Graphics/Weather/DPPt/dplightsandstorm.gif
new file mode 100644
index 0000000..3cbbb45
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dplightsandstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpnormal.png b/DS_Map/Graphics/Weather/DPPt/dpnormal.png
new file mode 100644
index 0000000..a9f5b8a
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpnormal.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dprain.gif b/DS_Map/Graphics/Weather/DPPt/dprain.gif
new file mode 100644
index 0000000..5460252
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dprain.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dprocksascending.gif b/DS_Map/Graphics/Weather/DPPt/dprocksascending.gif
new file mode 100644
index 0000000..d42c742
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dprocksascending.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpsandfall.gif b/DS_Map/Graphics/Weather/DPPt/dpsandfall.gif
new file mode 100644
index 0000000..6097027
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpsandfall.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpsandstorm.gif b/DS_Map/Graphics/Weather/DPPt/dpsandstorm.gif
new file mode 100644
index 0000000..2d9c565
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpsandstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpsnowslow.gif b/DS_Map/Graphics/Weather/DPPt/dpsnowslow.gif
new file mode 100644
index 0000000..3260dab
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpsnowslow.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/dpthunderstorm.gif b/DS_Map/Graphics/Weather/DPPt/dpthunderstorm.gif
new file mode 100644
index 0000000..f505ef6
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/dpthunderstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptblizzard.gif b/DS_Map/Graphics/Weather/DPPt/ptblizzard.gif
new file mode 100644
index 0000000..d35b696
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptblizzard.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptcloudy.png b/DS_Map/Graphics/Weather/DPPt/ptcloudy.png
new file mode 100644
index 0000000..63df5a5
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptcloudy.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptdark.png b/DS_Map/Graphics/Weather/DPPt/ptdark.png
new file mode 100644
index 0000000..f948fc0
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptdark.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptdiamondsnow.gif b/DS_Map/Graphics/Weather/DPPt/ptdiamondsnow.gif
new file mode 100644
index 0000000..adc54e5
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptdiamondsnow.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptfog.png b/DS_Map/Graphics/Weather/DPPt/ptfog.png
new file mode 100644
index 0000000..53d1ead
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptfog.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptforestweather.gif b/DS_Map/Graphics/Weather/DPPt/ptforestweather.gif
new file mode 100644
index 0000000..3a0ea09
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptforestweather.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/pthail.gif b/DS_Map/Graphics/Weather/DPPt/pthail.gif
new file mode 100644
index 0000000..09c3949
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/pthail.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptheavyrain.gif b/DS_Map/Graphics/Weather/DPPt/ptheavyrain.gif
new file mode 100644
index 0000000..c1b9288
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptheavyrain.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptlightning.gif b/DS_Map/Graphics/Weather/DPPt/ptlightning.gif
new file mode 100644
index 0000000..eb99389
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptlightning.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptlightsandstorm.gif b/DS_Map/Graphics/Weather/DPPt/ptlightsandstorm.gif
new file mode 100644
index 0000000..eaef096
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptlightsandstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptnormal.png b/DS_Map/Graphics/Weather/DPPt/ptnormal.png
new file mode 100644
index 0000000..b04c956
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptnormal.png differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptrain.gif b/DS_Map/Graphics/Weather/DPPt/ptrain.gif
new file mode 100644
index 0000000..2cca211
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptrain.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptrocksascending.gif b/DS_Map/Graphics/Weather/DPPt/ptrocksascending.gif
new file mode 100644
index 0000000..e61ff06
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptrocksascending.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptsandfall.gif b/DS_Map/Graphics/Weather/DPPt/ptsandfall.gif
new file mode 100644
index 0000000..b0d3f10
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptsandfall.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptsandstorm.gif b/DS_Map/Graphics/Weather/DPPt/ptsandstorm.gif
new file mode 100644
index 0000000..680ee68
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptsandstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptsnowslow.gif b/DS_Map/Graphics/Weather/DPPt/ptsnowslow.gif
new file mode 100644
index 0000000..913e940
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptsnowslow.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptspotlight.gif b/DS_Map/Graphics/Weather/DPPt/ptspotlight.gif
new file mode 100644
index 0000000..9b3eb55
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptspotlight.gif differ
diff --git a/DS_Map/Graphics/Weather/DPPt/ptthunderstorm.gif b/DS_Map/Graphics/Weather/DPPt/ptthunderstorm.gif
new file mode 100644
index 0000000..62072e9
Binary files /dev/null and b/DS_Map/Graphics/Weather/DPPt/ptthunderstorm.gif differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgssdark.png b/DS_Map/Graphics/Weather/HGSS/hgssdark.png
new file mode 100644
index 0000000..283371e
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgssdark.png differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgssdark2.png b/DS_Map/Graphics/Weather/HGSS/hgssdark2.png
new file mode 100644
index 0000000..335a134
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgssdark2.png differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgssfog.png b/DS_Map/Graphics/Weather/HGSS/hgssfog.png
new file mode 100644
index 0000000..4f01913
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgssfog.png differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgsshail.gif b/DS_Map/Graphics/Weather/HGSS/hgsshail.gif
new file mode 100644
index 0000000..990343d
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgsshail.gif differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgssnormal.png b/DS_Map/Graphics/Weather/HGSS/hgssnormal.png
new file mode 100644
index 0000000..875c03b
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgssnormal.png differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgssrain.gif b/DS_Map/Graphics/Weather/HGSS/hgssrain.gif
new file mode 100644
index 0000000..40569e0
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgssrain.gif differ
diff --git a/DS_Map/Graphics/Weather/HGSS/hgsssnow.gif b/DS_Map/Graphics/Weather/HGSS/hgsssnow.gif
new file mode 100644
index 0000000..9c74c0e
Binary files /dev/null and b/DS_Map/Graphics/Weather/HGSS/hgsssnow.gif differ
diff --git a/DS_Map/Header.cs b/DS_Map/Header.cs
new file mode 100644
index 0000000..46cd72b
--- /dev/null
+++ b/DS_Map/Header.cs
@@ -0,0 +1,850 @@
+using System.IO;
+
+namespace DS_Map
+{
+ /* ---------------------- HEADER DATA STRUCTURE (DPPt):----------------------------
+
+ 0x0 // byte: Area data value
+ 0x1 // byte: Unknown value
+ 0x2 // ushort: Matrix number
+ 0x4 // ushort: Script file number
+ 0x6 // ushort: Level script file number
+ 0x8 // ushort: Message file number
+ 0xA // ushort: Day music track number
+ 0xC // ushort: Night music track number
+ 0xE // ushort: Wild Pokmon file number
+ 0x10 // ushort: Event file number
+
+ * Diamond/Pearl:
+ 0x12 // ushort: Index of map name in message file #382 (US version)
+
+ * Platinum:
+ 0x12 // byte: Index of map name in message file #382 (US version)
+ 0x13 // byte: Map name textbox type value
+
+ 0x14 // byte: Weather value
+ 0x15 // byte: Camera value
+ 0x16 // byte: Boolean flag: show name when entering map
+ 0x17 // byte: Bitwise permission flags:
+
+ ----------------- 1: Allow Fly
+ ----------------- 2: ?
+ ----------------- 3: ?
+ ----------------- 4: Allow Bike usage
+ ----------------- 5: ?
+ ----------------- 6: ?
+ ----------------- 7: Escape Rope
+ ----------------- 8: ?
+
+ /* ---------------------- HEADER DATA STRUCTURE (HGSS):----------------------------
+
+ 0x0 // byte: Wild Pokmon file number
+ 0x1 // byte: Area data value
+ 0x2 // byte: ?
+ 0x3 // byte: ?
+ 0x4 // ushort: Matrix number
+ 0x6 // ushort: Script file number
+ 0x8 // ushort: Level script file
+ 0xA // ushort: Message file number
+ 0xC // ushort: Day music track number
+ 0xE // ushort: Night music track number
+ 0x10 // ushort: Event file number
+ 0x12 // byte: Index of map name in message file #382 (US version)
+ 0x13 // byte: Map name textbox type value
+ 0x14 // byte: Weather value
+ 0x15 // byte: Camera value
+ 0x16 // byte: Follow mode (for the Pokmon following hero)
+ 0x17 // byte: Bitwise permission flags:
+
+ ----------------- 1: Allow Fly
+ ----------------- 2: ?
+ ----------------- 3: ?
+ ----------------- 4: Allow Bike usage
+ ----------------- 5: ?
+ ----------------- 6: ?
+ ----------------- 7: Escape Rope
+ ----------------- 8: ?
+
+ ----------------------------------------------------------------------------------*/
+
+ ///
+ /// General class to store common map header data across all Gen IV Pokmon NDS games
+ ///
+ public abstract class Header
+ {
+ #regionFields(10)
+ public byte areaData { get; set; }
+ public byte camera { get; set; }
+ public ushort events { get; set; }
+ public byte flags { get; set; }
+ public ushort levelScript { get; set; }
+ public ushort matrix { get; set; }
+ public ushort script { get; set; }
+ public byte showName { get; set; }
+ public ushort text { get; set; }
+ public byte weather { get; set; }
+ public ushort wildPokmon { get; set; }
+ #endregionFields
+
+ #region Methods (1)
+ public abstract byte[] SaveHeader();
+ #endregion
+ }
+
+ ///
+ /// Class to store map header data from Pokmon Diamond and Pearl
+ ///
+ public class HeaderDP: Header
+ {
+ #regionFields(5)
+ public byte unknown1 { get; set; }
+ public ushort musicDay { get; set; }
+ public ushort musicNight { get; set; }
+ public ushort mapName { get; set; }
+ #endregionFields
+
+ #regionConstructors(1)
+ public HeaderDP(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ areaData = reader.ReadByte();
+ unknown1 = reader.ReadByte();
+ matrix = reader.ReadUInt16();
+ script = reader.ReadUInt16();
+ levelScript = reader.ReadUInt16();
+ text = reader.ReadUInt16();
+ musicDay = reader.ReadUInt16();
+ musicNight = reader.ReadUInt16();
+ wildPokmon = reader.ReadUInt16();
+ events = reader.ReadUInt16();
+ mapName = reader.ReadUInt16();
+ weather = StandardizeWeather(reader.ReadByte());
+ camera = reader.ReadByte();
+ showName = reader.ReadByte();
+ flags = reader.ReadByte();
+ }
+ }
+ #endregionConstructors
+
+ #region Methods (1)
+ public override byte[] SaveHeader()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ writer.Write(areaData);
+ writer.Write(unknown1);
+ writer.Write(matrix);
+ writer.Write(script);
+ writer.Write(levelScript);
+ writer.Write(text);
+ writer.Write(musicDay);
+ writer.Write(musicNight);
+ writer.Write(wildPokmon);
+ writer.Write(events);
+ writer.Write(mapName);
+ writer.Write(weather);
+ writer.Write(camera);
+ writer.Write(showName);
+ writer.Write(flags);
+ }
+ return newData.ToArray();
+ }
+ public byte StandardizeWeather(byte weather)
+ {
+ /* This function was written to avoid having to account
+ for duplicate weather values , since many share the same
+ weather conditions */
+
+ switch (weather)
+ {
+ case 8:
+ case 13:
+ case 18:
+ case 19:
+ case 20:
+ case 23:
+ case 25:
+ return 0; // Normal weather
+ case 21:
+ case 26:
+ case 27:
+ return 6; // Diamond snow
+ case 28:
+ return 5; // Snowfall
+ case 24:
+ return 4; // Thunderstorm
+ default:
+ return weather;
+ }
+ }
+ #endregion
+ }
+
+ ///
+ /// Class to store map header data from Pokmon Platinum
+ ///
+ public class HeaderPt : Header
+ {
+ #regionFields(5)
+ public byte areaIcon { get; set; }
+ public byte mapName { get; set; }
+ public ushort musicDay { get; set; }
+ public ushort musicNight { get; set; }
+ public byte unknown1 { get; set; }
+ #endregionFields
+
+ #regionConstructors(1)
+ public HeaderPt(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ areaData = reader.ReadByte();
+ unknown1 = reader.ReadByte();
+ matrix = reader.ReadUInt16();
+ script = reader.ReadUInt16();
+ levelScript = reader.ReadUInt16();
+ text = reader.ReadUInt16();
+ musicDay = reader.ReadUInt16();
+ musicNight = reader.ReadUInt16();
+ wildPokmon = reader.ReadUInt16();
+ events = reader.ReadUInt16();
+ mapName = reader.ReadByte();
+ areaIcon = reader.ReadByte();
+ weather = StandardizeWeather(reader.ReadByte());
+ camera = reader.ReadByte();
+ showName = reader.ReadByte();
+ flags = reader.ReadByte();
+ }
+ }
+ #endregionConstructors
+
+ #region Methods(1)
+ public override byte[] SaveHeader()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ writer.Write(areaData);
+ writer.Write(unknown1);
+ writer.Write(matrix);
+ writer.Write(script);
+ writer.Write(levelScript);
+ writer.Write(text);
+ writer.Write(musicDay);
+ writer.Write(musicNight);
+ writer.Write(wildPokmon);
+ writer.Write(events);
+ writer.Write(mapName);
+ writer.Write(areaIcon);
+ writer.Write(weather);
+ writer.Write(camera);
+ writer.Write(showName);
+ writer.Write(flags);
+ }
+ return newData.ToArray();
+ }
+ public byte StandardizeWeather(byte weather)
+ {
+ /* This function was written to avoid having to account
+ for duplicate weather values , since many share the same
+ weather conditions */
+
+ switch (weather)
+ {
+ case 8:
+ case 13:
+ case 18:
+ case 19:
+ case 20:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 33:
+ return 0; // Normal weather
+ case 21:
+ case 34:
+ case 35:
+ return 6; // Diamond snow
+ case 36:
+ return 5; // Snowfall
+ case 32:
+ return 2; // Rain
+ default:
+ return weather;
+ }
+ }
+ #endregion
+ }
+
+ ///
+ /// Class to store map header data from Pokmon HeartGold and SoulSilver
+ ///
+ public class HeaderHGSS : Header
+ {
+ #regionFields(7)
+ public byte areaIcon { get; set; }
+ public byte followMode { get; set; }
+ public byte mapName { get; set; }
+ public ushort musicDay { get; set; }
+ public ushort musicNight { get; set; }
+ public byte unknown1 { get; set; }
+ public byte unknown2 { get; set; }
+ #endregion
+
+ #regionConstructors(1)
+ public HeaderHGSS(Stream data)
+ {
+ using (BinaryReader reader = new BinaryReader(data))
+ {
+ wildPokmon = reader.ReadByte();
+ areaData = reader.ReadByte();
+ unknown1 = reader.ReadByte();
+ unknown2 = reader.ReadByte();
+ matrix = reader.ReadUInt16();
+ script = reader.ReadUInt16();
+ levelScript = reader.ReadUInt16();
+ text = reader.ReadUInt16();
+ musicDay = reader.ReadUInt16();
+ musicNight = reader.ReadUInt16();
+ events = reader.ReadUInt16();
+ mapName = reader.ReadByte();
+ areaIcon = StandardizeAreaIcon(reader.ReadByte());
+ weather = StandardizeWeather(reader.ReadByte());
+ camera = reader.ReadByte();
+ followMode = reader.ReadByte();
+ flags = reader.ReadByte();
+ }
+ }
+ #endregionConstructors
+
+ #region Methods(1)
+ public override byte[] SaveHeader()
+ {
+ MemoryStream newData = new MemoryStream();
+ using (BinaryWriter writer = new BinaryWriter(newData))
+ {
+ writer.Write((byte)wildPokmon);
+ writer.Write(areaData);
+ writer.Write(unknown1);
+ writer.Write(unknown2);
+ writer.Write(matrix);
+ writer.Write(script);
+ writer.Write(levelScript);
+ writer.Write(text);
+ writer.Write(musicDay);
+ writer.Write(musicNight);
+ writer.Write(events);
+ writer.Write(mapName);
+ writer.Write(areaIcon);
+ writer.Write(weather);
+ writer.Write(camera);
+ writer.Write(followMode);
+ writer.Write(flags);
+ }
+ return newData.ToArray();
+ }
+ public byte StandardizeAreaIcon(byte areaIcon)
+ {
+ /* This function was written to avoid having to account
+ for duplicate values of the map name textbox types, since
+ many share the same textbox image */
+
+ switch (areaIcon)
+ {
+ /* Water textbox values */
+ case 182:
+ case 198:
+ return 166;
+ /* Town textbox values*/
+ case 147:
+ case 163:
+ case 179:
+ case 195:
+ return 131;
+ /* Wall textbox values */
+ case 33:
+ case 65:
+ case 81:
+ case 97:
+ case 113:
+ case 145:
+ case 161:
+ case 193:
+ case 209:
+ return 17;
+ /* Gray textbox values */
+ case 25:
+ case 41:
+ case 57:
+ case 73:
+ case 89:
+ case 105:
+ case 121:
+ case 137:
+ case 153:
+ case 169:
+ case 185:
+ case 201:
+ case 217:
+ return 9;
+ /* Cave textbox values */
+ case 148:
+ case 164:
+ case 180:
+ case 196:
+ return 132;
+ /* Field textbox values */
+ case 151:
+ return 135;
+ /* Wooden textbox values */
+ case 50:
+ case 162:
+ case 194:
+ return 2;
+ /* Forest textbox values */
+ case 181:
+ return 165;
+ default:
+ return areaIcon;
+ }
+ }
+ public byte StandardizeWeather(byte weather)
+ {
+ /* This function was written to avoid having to account
+ for duplicate weather values , since many share the same
+ weather conditions */
+
+ switch (weather)
+ {
+ case 0:
+ case 1:
+ case 26:
+ return 0;
+ case 22:
+ case 23:
+ return 22;
+ default:
+ return weather; // No name displayed
+ }
+ }
+ #endregion
+ }
+
+ public class HeaderDatabase
+ {
+ public string[] PtAreaIconValues = new string[]
+ {
+ "[00] City",
+ "[01] City",
+ "[02] Town 1",
+ "[03] Town 2",
+ "[04] Cave",
+ "[05] Forest",
+ "[06] Water",
+ "[07] Field",
+ "[08] Island",
+ "[09] Wood"
+ };
+ public string[] HGSSAreaIconValues = new string[]
+ {
+ "[002] Wood",
+ "[009] Gray",
+ "[017] Wall",
+ "[048] Not displayed",
+ "[131] Town",
+ "[132] Cave",
+ "[135] Field",
+ "[152] Lake",
+ "[165] Forest",
+ "[166] Water"
+ };
+ public string[] DPPtCameraValues = new string[]
+ {
+ "[000] Normal 3D",
+ "[001] Normal 3D n.2",
+ "[002] Normal 3D n.3",
+ "[003] Normal 3D n.4",
+ "[004] 2D Interior view",
+ "[005] 3D Enlarged buildings",
+ "[006] 3D Top View n.1",
+ "[007] Normal 3D n.5",
+ "[008] 3D Top View n.2",
+ "[009] Frontal 3D n.1",
+ "[010] Normal 3D n.6",
+ "[011] Normal 3D n.7",
+ "[012] Normal 3D n.8",
+ "[013] Frontal 3D n.2",
+ "[014] 3D Top View n.3",
+ "[015] Normal 3D n.9"
+ };
+ public string[] HGSSCameraValues = new string[]
+ {
+ "[000] Normal 3D",
+ "[001] Normal 3D",
+ "[002] Normal 3D",
+ "[003] Normal 3D",
+ "[004] Normal 3D",
+ "[006] Normal 3D",
+ "[020] Frontal 3D n.1",
+ "[036] Frontal 3D n.2",
+ "[049] Full Frontal 3D",
+ "[051] Full Frontal 3D",
+ "[067] Interior 2D View",
+ "[068] Interior 2D View",
+ "[084] Normal 3D",
+ "[116] Higher Normal 3D",
+ "[129] Top View n.1",
+ "[148] Top View n.2",
+ "[163] 3D Enlarged Buildings",
+ "[195] Normal 3D",
+ "[211] Full Frontal 3D",
+ "[244] Higher Interior 2D View"
+
+ };
+ public string[] DPMusicValues = new string[]
+ {
+ "[1000] Mystery Zone",
+ "[1001] Foreign Building (silence)",
+ "[1002] Pal Park",
+ "[1004] Twinleaf Town (Day)",
+ "[1005] Sandgem Town (Day)",
+ "[1006] Floaroma Town (Day)",
+ "[1008] Route 225 (Day)",
+ "[1009] Valor Lakefront (Day)",
+ "[1010] Jubilife City (Day)",
+ "[1011] Canalave City (Day)",
+ "[1012] Oreburgh City (Day)",
+ "[1013] Eterna City (Day)",
+ "[1014] Hearthome City (Day)",
+ "[1015] Pastoria City (Day)",
+ "[1016] Veilstone City (Day)",
+ "[1017] Sunyshore City (Day)",
+ "[1018] Snowpoint City (Day)",
+ "[1019] Pokmon League (Day)",
+ "[1020] Fight Area (Day)",
+ "[1021] Route 201 (Day)",
+ "[1022] Route 203 (Day)",
+ "[1023] Route 205 (Day)",
+ "[1024] Route 206 (Day)",
+ "[1025] Route 209 (Day)",
+ "[1026] Route 215 (Day)",
+ "[1027] Route 216 (Day)",
+ "[1028] Route 228 (Day)",
+ "[1033] Twinleaf Town (Night)",
+ "[1034] Sandgem Town (Night)",
+ "[1035] Floaroma Town (Night)",
+ "[1037] Route 225 (Night)",
+ "[1038] Valor Lakefront (Night)",
+ "[1039] Jubilife City (Night)",
+ "[1040] Canalave City (Night)",
+ "[1041] Oreburgh City (Night)",
+ "[1042] Eterna City (Night)",
+ "[1043] Hearthome CIty (Night)",
+ "[1044] Pastoria City (Night)",
+ "[1045] Veilstone City (Night)",
+ "[1046] Sunyshore City (Night)",
+ "[1047] Snowpoint City (Night)",
+ "[1048] Pokmon League (Night)",
+ "[1049] Fight Area (Night)",
+ "[1050] Route 201 (Night)",
+ "[1051] Route 203 (Night)",
+ "[1052] Route 205 (Night)",
+ "[1053] Route 206 (Night)",
+ "[1054] Route 209 (Night)",
+ "[1055] Route 215 (Night)",
+ "[1056] Route 216 (Night)",
+ "[1057] Route 228 (Night)",
+ "[1060] Mystery Zone",
+ "[1062] Victory Road",
+ "[1063] Eterna Forest",
+ "[1064] Old Chateau",
+ "[1065] Cavern on the Lake",
+ "[1066] Amity Square",
+ "[1067] Team Galactic HQ",
+ "[1068] Eterna Galactic building",
+ "[1069] Great Marsh",
+ "[1070] Lake theme (Day)",
+ "[1071] Mt. Coronet",
+ "[1072] Spear Pillar",
+ "[1073] Stark Mountain (inside)",
+ "[1074] Cave 1",
+ "[1075] Cave 2",
+ "[1076] Elite 4 - Showdown",
+ "[1077] Hall of Fame",
+ "[1085] Pokmon Center (Day)",
+ "[1086] Pokmon Center (Night)",
+ "[1087] Gym theme",
+ "[1088] Rowan's Lab",
+ "[1089] Poffin House",
+ "[1090] Pokmon Mart",
+ "[1091] Game Corner",
+ "[1092] Battle Tower (inside)",
+ "[1093] Jubilife TV",
+ "[1094] Team Galactic Lab",
+ "[1096] Hall of Origin",
+ "[1097] GTS theme"
+ };
+ public string[] PtMusicValues = new string[]
+ {
+ "[1000] Mystery Zone",
+ "[1001] Foreign Building (silence)",
+ "[1002] Pal Park",
+ "[1004] Twinleaf Town (Day)",
+ "[1005] Sandgem Town (Day)",
+ "[1006] Floaroma Town (Day)",
+ "[1008] Route 225 (Day)",
+ "[1009] Valor Lakefront (Day)",
+ "[1010] Jubilife City (Day)",
+ "[1011] Canalave City (Day)",
+ "[1012] Oreburgh City (Day)",
+ "[1013] Eterna City (Day)",
+ "[1014] Hearthome City (Day)",
+ "[1015] Pastoria City (Day)",
+ "[1016] Veilstone City (Day)",
+ "[1017] Sunyshore City (Day)",
+ "[1018] Snowpoint City (Day)",
+ "[1019] Pokmon League (Day)",
+ "[1020] Fight Area (Day)",
+ "[1021] Route 201 (Day)",
+ "[1022] Route 203 (Day)",
+ "[1023] Route 205 (Day)",
+ "[1024] Route 206 (Day)",
+ "[1025] Route 209 (Day)",
+ "[1026] Route 215 (Day)",
+ "[1027] Route 216 (Day)",
+ "[1028] Route 228 (Day)",
+ "[1033] Twinleaf Town (Night)",
+ "[1034] Sandgem Town (Night)",
+ "[1035] Floaroma Town (Night)",
+ "[1037] Route 225 (Night)",
+ "[1038] Valor Lakefront (Night)",
+ "[1039] Jubilife City (Night)",
+ "[1040] Canalave City (Night)",
+ "[1041] Oreburgh City (Night)",
+ "[1042] Eterna City (Night)",
+ "[1043] Hearthome CIty (Night)",
+ "[1044] Pastoria City (Night)",
+ "[1045] Veilstone City (Night)",
+ "[1046] Sunyshore City (Night)",
+ "[1047] Snowpoint City (Night)",
+ "[1048] Pokmon League (Night)",
+ "[1049] Fight Area (Night)",
+ "[1050] Route 201 (Night)",
+ "[1051] Route 203 (Night)",
+ "[1052] Route 205 (Night)",
+ "[1053] Route 206 (Night)",
+ "[1054] Route 209 (Night)",
+ "[1055] Route 215 (Night)",
+ "[1056] Route 216 (Night)",
+ "[1057] Route 228 (Night)",
+ "[1060] Mystery Zone",
+ "[1062] Victory Road",
+ "[1063] Eterna Forest",
+ "[1064] Old Chateau",
+ "[1065] Cavern on the Lake",
+ "[1066] Amity Square",
+ "[1067] Team Galactic HQ",
+ "[1068] Eterna Galactic building",
+ "[1069] Great Marsh",
+ "[1070] Lake theme (Day)",
+ "[1071] Mt. Coronet",
+ "[1072] Spear Pillar",
+ "[1073] Stark Mountain (inside)",
+ "[1074] Cave 1",
+ "[1075] Cave 2",
+ "[1076] Elite 4 - Showdown",
+ "[1077] Hall of Fame",
+ "[1085] Pokmon Center (Day)",
+ "[1086] Pokmon Center (Night)",
+ "[1087] Gym theme",
+ "[1088] Rowan's Lab",
+ "[1089] Poffin House",
+ "[1090] Pokmon Mart",
+ "[1091] Game Corner",
+ "[1092] Battle Tower (inside)",
+ "[1093] Jubilife TV",
+ "[1094] Team Galactic Lab",
+ "[1096] Hall of Origin",
+ "[1097] GTS theme",
+ "[1190] Distortion World",
+ "[1191] Battle Arcade",
+ "[1192] Battle Hall",
+ "[1193] Battle Castle",
+ "[1194] Battle Factory",
+ "[1195] Battle Factory",
+ "[1196] Global Terminal"
+ };
+ public string[] HGSSMusicValues = new string[]
+ {
+ "[1000] Mystery Zone",
+ "[1001] Bell Tower music",
+ "[1018] New Bark Town",
+ "[1019] Cherrygrove City",
+ "[1020] Violet City",
+ "[1021] Azalea Town",
+ "[1022] Goldenrod City",
+ "[1023] Ecruteak City",
+ "[1024] Olivine City",
+ "[1025] Cianwood City",
+ "[1026] Mahogany Town",
+ "[1027] Blackthorn City",
+ "[1028] Route 29",
+ "[1029] Route 30/31",
+ "[1030] Route 32",
+ "[1031] Route 33",
+ "[1032] Route 34",
+ "[1033] Route 35/36/37",
+ "[1034] Route 40/41",
+ "[1035] Route 45/46",
+ "[1036] Route 38/39",
+ "[1037] Route 42/43/44",
+ "[1038] Vermillion City",
+ "[1039] Saffron City",
+ "[1040] Cerulean City",
+ "[1041] Lavender Town",
+ "[1042] Celadon City",
+ "[1043] Fuchsia City",
+ "[1044] Pewter City",
+ "[1045] Viridian City",
+ "[1046] Pallet Town",
+ "[1047] Cinnabar Island",
+ "[1050] Route 1",
+ "[1051] Route 2/22",
+ "[1052] Route 6",
+ "[1053] Route 4/5/9/10",
+ "[1054] Route 8/10",
+ "[1055] Route 7/16",
+ "[1056] Route 18/19/20",
+ "[1057] Route 3",
+ "[1058] Route 20/21",
+ "[1059] Route 11",
+ "[1060] Route 12/13/14/15",
+ "[1061] Route 24/25",
+ "[1062] Route 26/27",
+ "[1063] Pokmon Center",
+ "[1064] Pokmon Mart",
+ "[1065] Gym theme",
+ "[1066] Prof. Elm lab",
+ "[1068] Kimono Girls theater",
+ "[1069] Mystery Zone",
+ "[1070] Battle Park",
+ "[1071] Battle Tower",
+ "[1072] Sprout Tower",
+ "[1073] Ilex Forest",
+ "[1074] Ruins of Alph",
+ "[1075] National Park",
+ "[1076] Burned Tower",
+ "[1077] Bell Tower",
+ "[1078] Lighthouse",
+ "[1079] Team Rocket HQ",
+ "[1080] Ice Path",
+ "[1082] Diglett's Cave",
+ "[1083] Viridian Forest",
+ "[1084] Victory Road",
+ "[1085] Indigo Plateau",
+ "[1092] (?)",
+ "[1096] S.S. Aqua",
+ "[1097] Mt. Moon Plaza",
+ "[1134] Pokathlon Dome (inside)",
+ "[1141] Pokathlon Dome (outside)",
+ "[1143] Battle Factory",
+ "[1144] Battle Hall",
+ "[1145] Battle Arcade",
+ "[1146] Battle Castle",
+ "[1154] GTS Terminal",
+ "[1157] Route 47/48",
+ "[1158] Safari Zone gate",
+ "[1159] Pal Park",
+ "[1168] Sinjoh Ruins",
+ "[1216] Route 17"
+ };
+ public string[] DPShowNameValues = new string[]
+ {
+ "[000] Show",
+ "[001] Show",
+ "[002] Show",
+ "[003] Show",
+ "[004] Don't show"
+ };
+ public string[] PtShowNameValues = new string[]
+ {
+ "[000] Show",
+ "[001] Show",
+ "[002] Show",
+ "[003] Show",
+ "[004] Don't show",
+ "[128] Don't show",
+ "[129] Show",
+ "[130] Show",
+ "[131] Show",
+ "[132] Don't show",
+ "[134] Show"
+ };
+ public string[] DPWeatherValues = new string[]
+ {
+ "[00] Normal",
+ "[01] Normal, somewhat dark",
+ "[02] Rain",
+ "[03] Heavy rain",
+ "[04] Thunderstorm",
+ "[05] Snowfall, slow",
+ "[06] Diamond dust",
+ "[07] Blizzard",
+ "[09] Volcanic ash fall, slow",
+ "[10] Sand storm",
+ "[11] Hail",
+ "[12] Rocks ascending (?)",
+ "[14] Fog",
+ "[15] Deep fog",
+ "[16] Dark, Flash usable",
+ "[17] Lightning, no rain",
+ "[22] Volcanic ash fall, steady",
+ };
+ public string[] PtWeatherValues = new string[]
+ {
+ "[00] Normal",
+ "[01] Normal, somewhat dark",
+ "[02] Rain",
+ "[03] Heavy rain",
+ "[04] Thunderstorm",
+ "[05] Snowfall, slow",
+ "[06] Diamond dust",
+ "[07] Blizzard",
+ "[09] Volcanic ash fall, slow",
+ "[10] Sand storm",
+ "[11] Hail",
+ "[12] Rocks ascending (?)",
+ "[14] Fog",
+ "[15] Deep fog",
+ "[16] Dark, Flash usable",
+ "[17] Lightning, no rain",
+ "[22] Volcanic ash fall, steady",
+ "[23] Eterna forest weather",
+ "[24] Player in circle of light",
+ "[25] Player in a circle of light",
+ };
+ public string[] HGSSWeatherValues = new string[]
+ {
+ "[00] Normal",
+ "[02] Heavy rain",
+ "[10] Diamond snow",
+ "[16] Hail",
+ "[18] Fog",
+ "[22] Cave Dark",
+ "[24] Cave Dark after flash",
+ };
+
+ #region Constructors (1)
+ public HeaderDatabase()
+ {
+
+ }
+ #endregion
+
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/HelixToolkit.dll b/DS_Map/HelixToolkit.dll
new file mode 100644
index 0000000..f522a76
Binary files /dev/null and b/DS_Map/HelixToolkit.dll differ
diff --git a/DS_Map/InsertValueDialog.Designer.cs b/DS_Map/InsertValueDialog.Designer.cs
new file mode 100644
index 0000000..b61e99b
--- /dev/null
+++ b/DS_Map/InsertValueDialog.Designer.cs
@@ -0,0 +1,103 @@
+namespace DS_Map
+{
+ partial class InsertValueDialog
+ {
+ ///
+ /// 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 Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
+ this.okButton = new System.Windows.Forms.Button();
+ this.backButton = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(19, 12);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(35, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "label1";
+ //
+ // numericUpDown1
+ //
+ this.numericUpDown1.Hexadecimal = true;
+ this.numericUpDown1.Location = new System.Drawing.Point(22, 31);
+ this.numericUpDown1.Maximum = new decimal(new int[] {
+ 65535,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Name = "numericUpDown1";
+ this.numericUpDown1.Size = new System.Drawing.Size(197, 20);
+ this.numericUpDown1.TabIndex = 1;
+ //
+ // okButton
+ //
+ this.okButton.Location = new System.Drawing.Point(22, 57);
+ this.okButton.Name = "okButton";
+ this.okButton.Size = new System.Drawing.Size(99, 23);
+ this.okButton.TabIndex = 2;
+ this.okButton.Text = "OK";
+ this.okButton.UseVisualStyleBackColor = true;
+ this.okButton.Click += new System.EventHandler(this.okButton_Click);
+ //
+ // backButton
+ //
+ this.backButton.Location = new System.Drawing.Point(127, 57);
+ this.backButton.Name = "backButton";
+ this.backButton.Size = new System.Drawing.Size(92, 23);
+ this.backButton.TabIndex = 3;
+ this.backButton.Text = "Back";
+ this.backButton.UseVisualStyleBackColor = true;
+ //
+ // InsertValueDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(243, 90);
+ this.Controls.Add(this.backButton);
+ this.Controls.Add(this.okButton);
+ this.Controls.Add(this.numericUpDown1);
+ this.Controls.Add(this.label1);
+ this.Name = "InsertValueDialog";
+ this.Text = "Insert Value";
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ public System.Windows.Forms.NumericUpDown numericUpDown1;
+ private System.Windows.Forms.Button okButton;
+ private System.Windows.Forms.Button backButton;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/InsertValueDialog.cs b/DS_Map/InsertValueDialog.cs
new file mode 100644
index 0000000..cb8eed1
--- /dev/null
+++ b/DS_Map/InsertValueDialog.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace DS_Map
+{
+ public partial class InsertValueDialog : Form
+ {
+ public bool okSelected = new bool();
+
+ public InsertValueDialog(string valueLabel, string format)
+ {
+ InitializeComponent();
+ label1.Text = valueLabel;
+ if (format == "hex") numericUpDown1.Hexadecimal = true;
+ else numericUpDown1.Hexadecimal = false;
+ }
+
+ private void okButton_Click(object sender, EventArgs e)
+ {
+ okSelected = true;
+ this.Close();
+ }
+ }
+}
diff --git a/DS_Map/InsertValueDialog.resx b/DS_Map/InsertValueDialog.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/InsertValueDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/EndianBinaryReader.cs b/DS_Map/LibNDSFormats/EndianBinaryReader.cs
new file mode 100644
index 0000000..d558d3b
--- /dev/null
+++ b/DS_Map/LibNDSFormats/EndianBinaryReader.cs
@@ -0,0 +1,368 @@
+// CTools library - Library functions for CTools
+// Copyright (C) 2010 Chadderz
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace System.IO
+{
+ public sealed class EndianBinaryReader : IDisposable
+ {
+ private bool disposed;
+ private byte[] buffer;
+
+ public Stream BaseStream { get; private set; }
+ public Endianness Endianness { get; set; }
+ public Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } }
+
+ private bool Reverse { get { return SystemEndianness != Endianness; } }
+
+ public EndianBinaryReader(Stream baseStream)
+ : this(baseStream, Endianness.BigEndian)
+ { }
+
+ public EndianBinaryReader(Stream baseStream, Endianness endianness)
+ {
+ if (baseStream == null) throw new ArgumentNullException("baseStream");
+ if (!baseStream.CanRead) throw new ArgumentException("baseStream");
+
+ BaseStream = baseStream;
+ Endianness = endianness;
+ }
+
+ ~EndianBinaryReader()
+ {
+ Dispose(false);
+ }
+
+ private void FillBuffer(int bytes, int stride)
+ {
+ if (buffer == null || buffer.Length < bytes)
+ buffer = new byte[bytes];
+
+ BaseStream.Read(buffer, 0, bytes);
+
+ if (Reverse)
+ for (int i = 0; i < bytes; i += stride)
+ {
+ Array.Reverse(buffer, i, stride);
+ }
+ }
+
+ public byte ReadByte()
+ {
+ FillBuffer(1, 1);
+
+ return buffer[0];
+ }
+
+ public byte[] ReadBytes(int count)
+ {
+ byte[] temp;
+
+ FillBuffer(count, 1);
+ temp = new byte[count];
+ Array.Copy(buffer, 0, temp, 0, count);
+ return temp;
+ }
+
+ public sbyte ReadSByte()
+ {
+ FillBuffer(1, 1);
+
+ unchecked
+ {
+ return (sbyte)buffer[0];
+ }
+ }
+
+ public sbyte[] ReadSBytes(int count)
+ {
+ sbyte[] temp;
+
+ temp = new sbyte[count];
+ FillBuffer(count, 1);
+
+ unchecked
+ {
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = (sbyte)buffer[i];
+ }
+ }
+
+ return temp;
+ }
+
+ public char ReadChar(Encoding encoding)
+ {
+ int size;
+
+ size = GetEncodingSize(encoding);
+ FillBuffer(size, size);
+ return encoding.GetChars(buffer, 0, size)[0];
+ }
+
+ public char[] ReadChars(Encoding encoding, int count)
+ {
+ int size;
+
+ size = GetEncodingSize(encoding);
+ FillBuffer(size * count, size);
+ return encoding.GetChars(buffer, 0, size * count);
+ }
+
+ private static int GetEncodingSize(Encoding encoding)
+ {
+ if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII)
+ return 1;
+ else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode)
+ return 2;
+
+ return 1;
+ }
+
+ public string ReadStringNT(Encoding encoding)
+ {
+ string text;
+
+ text = "";
+
+ do
+ {
+ text += ReadChar(encoding);
+ } while (!text.EndsWith("\0", StringComparison.Ordinal));
+
+ return text.Remove(text.Length - 1);
+ }
+
+ public string ReadString(Encoding encoding, int count)
+ {
+ return new string(ReadChars(encoding, count));
+ }
+
+ public double ReadDouble()
+ {
+ const int size = sizeof(double);
+ FillBuffer(size, size);
+ return BitConverter.ToDouble(buffer, 0);
+ }
+
+ public double[] ReadDoubles(int count)
+ {
+ const int size = sizeof(double);
+ double[] temp;
+
+ temp = new double[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToDouble(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public Single ReadSingle()
+ {
+ const int size = sizeof(Single);
+ FillBuffer(size, size);
+ return BitConverter.ToSingle(buffer, 0);
+ }
+
+ public Single[] ReadSingles(int count)
+ {
+ const int size = sizeof(Single);
+ Single[] temp;
+
+ temp = new Single[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToSingle(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public Int32 ReadInt32()
+ {
+ const int size = sizeof(Int32);
+ FillBuffer(size, size);
+ return BitConverter.ToInt32(buffer, 0);
+ }
+
+ public Int32[] ReadInt32s(int count)
+ {
+ const int size = sizeof(Int32);
+ Int32[] temp;
+
+ temp = new Int32[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToInt32(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public Int64 ReadInt64()
+ {
+ const int size = sizeof(Int64);
+ FillBuffer(size, size);
+ return BitConverter.ToInt64(buffer, 0);
+ }
+
+ public Int64[] ReadInt64s(int count)
+ {
+ const int size = sizeof(Int64);
+ Int64[] temp;
+
+ temp = new Int64[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToInt64(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public Int16 ReadInt16()
+ {
+ const int size = sizeof(Int16);
+ FillBuffer(size, size);
+ return BitConverter.ToInt16(buffer, 0);
+ }
+
+ public Int16[] ReadInt16s(int count)
+ {
+ const int size = sizeof(Int16);
+ Int16[] temp;
+
+ temp = new Int16[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToInt16(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public UInt16 ReadUInt16()
+ {
+ const int size = sizeof(UInt16);
+ FillBuffer(size, size);
+ return BitConverter.ToUInt16(buffer, 0);
+ }
+
+ public UInt16[] ReadUInt16s(int count)
+ {
+ const int size = sizeof(UInt16);
+ UInt16[] temp;
+
+ temp = new UInt16[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToUInt16(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public UInt32 ReadUInt32()
+ {
+ const int size = sizeof(UInt32);
+ FillBuffer(size, size);
+ return BitConverter.ToUInt32(buffer, 0);
+ }
+
+ public UInt32[] ReadUInt32s(int count)
+ {
+ const int size = sizeof(UInt32);
+ UInt32[] temp;
+
+ temp = new UInt32[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToUInt32(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public UInt64 ReadUInt64()
+ {
+ const int size = sizeof(UInt64);
+ FillBuffer(size, size);
+ return BitConverter.ToUInt64(buffer, 0);
+ }
+
+ public UInt64[] ReadUInt64s(int count)
+ {
+ const int size = sizeof(UInt64);
+ UInt64[] temp;
+
+ temp = new UInt64[count];
+ FillBuffer(size * count, size);
+
+ for (int i = 0; i < count; i++)
+ {
+ temp[i] = BitConverter.ToUInt64(buffer, size * i);
+ }
+ return temp;
+ }
+
+ public void Close()
+ {
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ if (BaseStream != null)
+ {
+ BaseStream.Close();
+ }
+ }
+
+ buffer = null;
+
+ disposed = true;
+ }
+ }
+ }
+
+ public enum Endianness
+ {
+ BigEndian,
+ LittleEndian,
+ }
+}
diff --git a/DS_Map/LibNDSFormats/Export3DTools/Face.cs b/DS_Map/LibNDSFormats/Export3DTools/Face.cs
new file mode 100644
index 0000000..0868b55
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/Face.cs
@@ -0,0 +1,9 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System;
+
+ public class Face
+ {
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/Group.cs b/DS_Map/LibNDSFormats/Export3DTools/Group.cs
new file mode 100644
index 0000000..f12bb86
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/Group.cs
@@ -0,0 +1,42 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Reflection;
+
+ public class Group
+ {
+ private List PolygonList = new List();
+
+ public void Add(Polygon g)
+ {
+ this.PolygonList.Add(g);
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return this.PolygonList.GetEnumerator();
+ }
+
+ public Polygon this[int i]
+ {
+ get
+ {
+ return this.PolygonList[i];
+ }
+ set
+ {
+ this.PolygonList[i] = value;
+ }
+ }
+
+ public Polygon[] Polygons
+ {
+ get
+ {
+ return this.PolygonList.ToArray();
+ }
+ }
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/OBJWriter.cs b/DS_Map/LibNDSFormats/Export3DTools/OBJWriter.cs
new file mode 100644
index 0000000..8d4d74d
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/OBJWriter.cs
@@ -0,0 +1,38 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using OpenTK;
+ using System;
+ using System.Collections.Generic;
+
+ public class OBJWriter
+ {
+ private List Normals = new List();
+ private List TexCoords = new List();
+ private List Vertices = new List();
+
+ public void AddTriangle(Vector3[] Vertice)
+ {
+ this.Vertices.AddRange(Vertice);
+ }
+
+ public void AddTriangle(Vector3[] Vertice, Vector2 TexCoord)
+ {
+ this.Vertices.AddRange(Vertice);
+ this.TexCoords.Add(TexCoord);
+ }
+
+ public void AddTriangle(Vector3[] Vertice, Vector3 Normal)
+ {
+ this.Vertices.AddRange(Vertice);
+ this.Normals.Add(Normal);
+ }
+
+ public void AddTriangle(Vector3[] Vertice, Vector2 TexCoord, Vector3 Normal)
+ {
+ this.Vertices.AddRange(Vertice);
+ this.TexCoords.Add(TexCoord);
+ this.Normals.Add(Normal);
+ }
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/Polygon.cs b/DS_Map/LibNDSFormats/Export3DTools/Polygon.cs
new file mode 100644
index 0000000..4b309b6
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/Polygon.cs
@@ -0,0 +1,22 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using OpenTK;
+ using System;
+
+ public class Polygon
+ {
+ public Vector3[] Normals;
+ public PolygonType PolyType;
+ public Vector2[] TexCoords;
+ public Vector3[] Vertex;
+
+ public Polygon(PolygonType PolyType, Vector3[] Normals, Vector2[] TexCoords, Vector3[] Vertex)
+ {
+ this.PolyType = PolyType;
+ this.Normals = Normals;
+ this.TexCoords = TexCoords;
+ this.Vertex = Vertex;
+ }
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/PolygonType.cs b/DS_Map/LibNDSFormats/Export3DTools/PolygonType.cs
new file mode 100644
index 0000000..5d216d4
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/PolygonType.cs
@@ -0,0 +1,13 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System;
+
+ public enum PolygonType
+ {
+ Triangle,
+ Quad,
+ TriangleStrip,
+ QuadStrip
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/Quad.cs b/DS_Map/LibNDSFormats/Export3DTools/Quad.cs
new file mode 100644
index 0000000..6b92d50
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/Quad.cs
@@ -0,0 +1,13 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System.Windows;
+ using System.Windows.Media.Media3D;
+
+ public class Quad : Face
+ {
+ public Vector3D[] Normal = new Vector3D[4];
+ public Point[] TexCoord = new Point[4];
+ public Point3D[] Vertex = new Point3D[4];
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/QuadStrip.cs b/DS_Map/LibNDSFormats/Export3DTools/QuadStrip.cs
new file mode 100644
index 0000000..4c5416b
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/QuadStrip.cs
@@ -0,0 +1,14 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System.Collections.Generic;
+ using System.Windows;
+ using System.Windows.Media.Media3D;
+
+ public class QuadStrip : Face
+ {
+ public List Normal = new List();
+ public List TexCoord = new List();
+ public List Vertex = new List();
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/Triangle.cs b/DS_Map/LibNDSFormats/Export3DTools/Triangle.cs
new file mode 100644
index 0000000..287de26
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/Triangle.cs
@@ -0,0 +1,13 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System.Windows;
+ using System.Windows.Media.Media3D;
+
+ public class Triangle : Face
+ {
+ public Vector3D[] Normal = new Vector3D[3];
+ public Point[] TexCoord = new Point[3];
+ public Point3D[] Vertex = new Point3D[3];
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Export3DTools/TriangleStrip.cs b/DS_Map/LibNDSFormats/Export3DTools/TriangleStrip.cs
new file mode 100644
index 0000000..744df02
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Export3DTools/TriangleStrip.cs
@@ -0,0 +1,14 @@
+namespace MKDS_Course_Editor.Export3DTools
+{
+ using System.Collections.Generic;
+ using System.Windows;
+ using System.Windows.Media.Media3D;
+
+ public class TriangleStrip : Face
+ {
+ public List Normal = new List();
+ public List TexCoord = new List();
+ public List Vertex = new List();
+ }
+}
+
diff --git a/DS_Map/LibNDSFormats/Helper.cs b/DS_Map/LibNDSFormats/Helper.cs
new file mode 100644
index 0000000..e3524a0
--- /dev/null
+++ b/DS_Map/LibNDSFormats/Helper.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Drawing;
+using OpenTK;
+
+namespace SM64DSe
+{
+ static class Helper
+ {
+ public static ushort ColorToBGR15(Color color)
+ {
+ uint r = (uint)((color.R & 0xF8) >> 3);
+ uint g = (uint)((color.G & 0xF8) << 2);
+ uint b = (uint)((color.B & 0xF8) << 7);
+ return (ushort)(r | g | b);
+ }
+
+ public static Color BGR15ToColor(ushort bgr15)
+ {
+ byte red = (byte)((bgr15 << 3) & 0xF8);
+ byte green = (byte)((bgr15 >> 2) & 0xF8);
+ byte blue = (byte)((bgr15 >> 7) & 0xF8);
+ return Color.FromArgb(red, green, blue);
+ }
+
+ public static ushort BlendColorsBGR15(ushort c1, int w1, ushort c2, int w2)
+ {
+ int r1 = c1 & 0x1F;
+ int g1 = (c1 >> 5) & 0x1F;
+ int b1 = (c1 >> 10) & 0x1F;
+ int r2 = c2 & 0x1F;
+ int g2 = (c2 >> 5) & 0x1F;
+ int b2 = (c2 >> 10) & 0x1F;
+
+ int rf = ((r1 * w1) + (r2 * w2)) / (w1 + w2);
+ int gf = ((g1 * w1) + (g2 * w2)) / (w1 + w2);
+ int bf = ((b1 * w1) + (b2 * w2)) / (w1 + w2);
+ return (ushort)(rf | (gf << 5) | (bf << 10));
+ }
+
+ public static bool VectorsEqual(Vector3 a, Vector3 b)
+ {
+ float epsilon = 0.00001f;
+ if (Math.Abs(a.X - b.X) > epsilon) return false;
+ if (Math.Abs(a.Y - b.Y) > epsilon) return false;
+ if (Math.Abs(a.Z - b.Z) > epsilon) return false;
+ return true;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBCA.cs b/DS_Map/LibNDSFormats/NSBCA.cs
new file mode 100644
index 0000000..fee069b
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBCA.cs
@@ -0,0 +1,515 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace MKDS_Course_Editor.NSBCA
+{
+ public class NSBCA
+ {
+ public struct NSBCA_File
+ {
+ public header Header;
+ public struct header
+ {
+ public string ID;
+ public byte[] Magic;
+ public Int32 file_size;
+ public Int16 header_size;
+ public Int16 nSection;
+ public Int32[] Section_Offset;
+ }
+ public jnt0 JNT0;
+ public struct jnt0 //Scale Rotation and Translation
+ {
+ public string ID;
+ public Int32 Size;
+ //3D Info Structure
+ public byte dummy;
+ public byte num_objs;
+ public short section_size;
+ public UnknownBlock unknownBlock;
+ public Info infoBlock;
+ public string[] names;
+
+ public struct UnknownBlock
+ {
+ public short header_size;
+ public short section_size;
+ public int constant; // 0x017F
+
+ public short[] unknown1;
+ public short[] unknown2;
+ }
+ public struct Info
+ {
+ public short header_size;
+ public short data_size;
+
+ public info[] Data;
+
+ public struct info
+ {
+ public Int32 Objectoffset;
+ }
+ }
+ }
+ public J_AC[] JAC;
+ public struct J_AC
+ {
+ public string ID;
+ public Int16 NrFrames;
+ public Int16 NrObjects;
+ public Int32 Unknown1;
+ public Int32 Offset1;
+ public Int32 Offset2;
+
+ public byte[] JointData;
+ public byte[] RotationData;
+
+ public Int32[] ObjInfoOffset;
+
+ public objInfo[] ObjInfo;
+ public struct objInfo
+ {
+ public Int16 Flag;
+ public byte Unknown1;
+ public byte ID;
+
+ public int tStart;
+ public int tEnd;
+ public int rStart;
+ public int rEnd;
+ public int sStart;
+ public int sEnd;
+ public List[] translate;
+ public List[] translate_keyframes;
+ public List rotate;
+ public List[] rotate_keyframes;
+ public List[][] scale;
+ public List[][] scale_keyframes;
+ }
+ }
+ }
+ /*
+ * I've been studying the NSBCA format heavily over the last few days trying to figure it out.
+ * I've determined that the first offset in a joint animation contains Pivoting data, and the second section contains Rotation data.
+ * Rotation keyframes are called when the second byte equals 0 and Pivot keyframes are called when it equals 128, however the data itself is definitely stored a little differently to how it is stored in NSBMD files.
+ * Scaling keyframes hold two scaling values for whatever reason, with Translation keyframes being just straight values that can be a signed word/dword.
+ * Each animation has a frame length, however each object in an animation seems to have a start and end position that typically don't match up with the total number of frames.
+ * Now I haven't had much experience with model animations, but I'm guessing this might have like a decay effect on the animation if anyone has ever played around with animations in Maya?
+ * The trickiest part is calculating the right number of keyframes stored in each object as there isn't an actual value written down anywhere.
+ * From what I can tell it's calculated based on a bunch of things including the difference in object frame length over animation frame length, the rate in which the object (and possibly the animation) plays back as well as rounding to the upper whole number.
+ * This looks a bit funky and overcomplicated but so far all the animations I've been working with calculate the correct number of keyframes, so I'm assuming I'm on the right track.
+ * Am yet to get to the point of loading animations into a model, but hopefully I won't get some spastic result :S
+
+
+
+
+ Object Flag: --zyx-Sr-RZYX-T-
+ > found in the header of each object of an animation
+ ===========================
+ T - has Translation keyframes (0 Yes| 1 No)
+ XYZ - flags for Translation attributes
+ R - has Rotation/Pivot keyframes (0 Yes| 1 No)
+ r - flag for Rotation/Pivot attribute
+ S - has Scale keyframes (0 Yes| 1 No)
+ xyz - flags for Scale attributes
+ ===========================
+ if T-XYZ = 1
+ > Fixed Translation value (signed dword)
+ if R-r = 1
+ > Fixed Rotation/Pivot value (dword/2*word?)
+ if S-xyz = 1
+ > Fixed Scale value (2*dword)
+
+ Note: The below is only done when the bit flag equals 0 for that attribute (TX, TY, TZ, R/P, SX, SY, SZ)
+
+ a|b = datasize = playback speed
+ > a & b are flags stored in the object header for each attribute
+
+ Translate
+ -----------------------------------------------------------
+ 2|0 = word = 1/1
+ 2|1 = word = 1/2
+ 2|2 = word = 1/3
+ 0|1 = dword = 1/2
+
+ Rotate
+ -----------------------------------------------------------
+ 0|0 = 2*byte = 1/1
+ 0|1 = 2*byte = 1/2
+ 0|2 = 2*byte = 1/3
+ > byte0 = index
+ > byte1 = 0 Rotation | 128 Pivot
+ > not completely sure on rotation yet
+
+ Scale
+ -----------------------------------------------------------
+ 2|1 = 2*word = 1/1
+ 2|1 = 2*word = 1/2
+ -----------------------------------------------------------
+
+ Attribute [animation flag|start|end|a|b] bytes/keyframes - animation length
+ > bytes - the actual size of the data stored
+ > keyframes - bytes/datasize(see above)
+
+ Basabasa - 0 Pivot - 33 Rotation
+ ===========================================================
+ Translate [3|0|34|2|1] 38/19 - 36 Frames
+ Rotate [3|0|34|0|1] 38/19 - 36 Frames
+ Scale [3|0|34|2|1] 76/19 - 36 Frames
+ ===========================================================
+
+ Basabasa2 - 1 Pivot - 20 Rotation
+ ===========================================================
+ Rotate [3|0|78|0|1] 82/41 - 80 Frames
+ ===========================================================
+
+ Bilikyu - 31 Pivot
+ ===========================================================
+ Translate [3|0|58|2|1] 62/31 - 60 Frames
+ Rotate [3|0|58|0|1] 62/31 - 60 Frames
+ ===========================================================
+
+ Donketu - 12 Pivot / 20 Rotation
+ ===========================================================
+ Translate [3|0|10|0|1] 24/06 - 11 Frames (dword)
+ Translate [3|0|10|2|1] 12/06 - 11 Frames
+ Translate [1|0|02|2|0] 04/02 - 02 Frames
+ Rotate [3|0|10|0|1] 14/07 - 11 Frames
+ ===========================================================
+
+ Gesso - 39 Pivot
+ ===========================================================
+ Translate [0|0|16|2|2] 14/07 - 19 Frames
+ Translate [0|0|16|2|2] 12/06 - 18 Frames
+ Translate [0|0|12|2|2] 10/05 - 14 Frames
+ Scale [0|0|16|2|2] 28/07 - 19 Frames
+ Scale [0|0|16|2|2] 24/06 - 18 Frames
+ Rotate [0|0|16|0|2] 16/08 - 19 Frames
+ Rotate [0|0|16|0|2] 16/08 - 18 Frames
+ Rotate [0|0|12|0|2] 14/07 - 14 Frames
+ ===========================================================
+
+ TTL Bird
+ ===========================================================
+ Translate [1|0|05|2|0] 10/05 - 05 Frames
+ Rotate [1|0|05|0|0] 10/05 - 05 Frames
+ ===========================================================
+
+ Gamaguchi - 11 Pivot - 52 Rotation
+ ===========================================================
+ Translate [3|0|08|2|0] 16/08 - 08 Frames
+ Translate [3|0|07|2|0] 14/07 - 07 Frames
+ Translate [3|0|16|2|0] 32/16 - 16 Frames
+ Rotate [3|0|08|0|0] 16/08 - 08 Frames
+ Rotate [1|0|07|0|0] 14/07 - 07 Frames
+ Rotate [3|0|16|0|0] 32/16 - 16 Frames
+ Scale [3|0|08|2|0] 32/08 - 08 Frames
+ Scale [1|0|07|2|0] 28/07 - 07 Frames
+ ===========================================================
+ */
+ public static NSBCA_File Read(string Filename)
+ {
+ byte[] file_ = File.ReadAllBytes(Filename);
+ if (file_[0] == 76 && file_[1] == 90 && file_[2] == 55 && file_[3] == 55)
+ {
+ }
+ EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(file_), Endianness.LittleEndian);
+ NSBCA_File ns = new NSBCA_File();
+ ns.Header.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.Header.ID == "BCA0")
+ {
+ ns.Header.Magic = er.ReadBytes(4);
+ ns.Header.file_size = er.ReadInt32();
+ ns.Header.header_size = er.ReadInt16();
+ ns.Header.nSection = er.ReadInt16();
+ ns.Header.Section_Offset = new Int32[ns.Header.nSection];
+ for (int i = 0; i < ns.Header.nSection; i++)
+ {
+ ns.Header.Section_Offset[i] = er.ReadInt32();
+ }
+
+ ns.JNT0.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.JNT0.ID == "JNT0")
+ {
+ ns.JNT0.Size = er.ReadInt32();
+ //3D Info Structure
+ ns.JNT0.dummy = er.ReadByte();
+ ns.JNT0.num_objs = er.ReadByte();
+ ns.JNT0.section_size = er.ReadInt16();
+ ns.JNT0.unknownBlock.header_size = er.ReadInt16();
+ ns.JNT0.unknownBlock.section_size = er.ReadInt16();
+ ns.JNT0.unknownBlock.constant = er.ReadInt32();
+ ns.JNT0.unknownBlock.unknown1 = new short[ns.JNT0.num_objs];
+ ns.JNT0.unknownBlock.unknown2 = new short[ns.JNT0.num_objs];
+ for (int i = 0; i < ns.JNT0.num_objs; i++)
+ {
+ ns.JNT0.unknownBlock.unknown1[i] = er.ReadInt16();
+ ns.JNT0.unknownBlock.unknown2[i] = er.ReadInt16();
+ }
+
+ ns.JNT0.infoBlock.header_size = er.ReadInt16();
+ ns.JNT0.infoBlock.data_size = er.ReadInt16();
+ ns.JNT0.infoBlock.Data = new NSBCA_File.jnt0.Info.info[ns.JNT0.num_objs];
+ for (int i = 0; i < ns.JNT0.num_objs; i++)
+ {
+ ns.JNT0.infoBlock.Data[i].Objectoffset = er.ReadInt32();
+ }
+ ns.JNT0.names = new string[ns.JNT0.num_objs];
+ for (int i = 0; i < ns.JNT0.num_objs; i++)
+ {
+ ns.JNT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
+ }
+ ns.JAC = new NSBCA_File.J_AC[ns.JNT0.num_objs];
+ for (int i = 0; i < ns.JNT0.num_objs; i++)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset;
+ ns.JAC[i].ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.JAC[i].ID == "J" + (char)0x00 + "AC")
+ {
+ ns.JAC[i].NrFrames = er.ReadInt16();
+ ns.JAC[i].NrObjects = er.ReadInt16();
+ ns.JAC[i].Unknown1 = er.ReadInt32();
+ ns.JAC[i].Offset1 = er.ReadInt32();
+ ns.JAC[i].Offset2 = er.ReadInt32();
+ long curposs = er.BaseStream.Position;
+ if (ns.JAC[i].Offset2 != ns.JAC[i].Offset1)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].Offset1;
+ ns.JAC[i].JointData = er.ReadBytes(ns.JAC[i].Offset2 - ns.JAC[i].Offset1);
+ er.BaseStream.Position = curposs;
+ }
+
+ long dataoffset = 0;
+
+
+ ns.JAC[i].ObjInfoOffset = new Int32[ns.JAC[i].NrObjects];
+ for (int j = 0; j < ns.JAC[i].NrObjects; j++)
+ {
+ ns.JAC[i].ObjInfoOffset[j] = er.ReadInt16();
+ }
+
+ ns.JAC[i].ObjInfo = new NSBCA_File.J_AC.objInfo[ns.JAC[i].NrObjects];
+
+ for (int j = 0; j < ns.JAC[i].NrObjects; j++)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].ObjInfoOffset[j];// + 8;
+ ns.JAC[i].ObjInfo[j].Flag = er.ReadInt16();
+ ns.JAC[i].ObjInfo[j].Unknown1 = er.ReadByte();
+ ns.JAC[i].ObjInfo[j].ID = er.ReadByte();
+ ns.JAC[i].ObjInfo[j].translate = new List[3];
+ ns.JAC[i].ObjInfo[j].translate[0] = new List();
+ ns.JAC[i].ObjInfo[j].translate[1] = new List();
+ ns.JAC[i].ObjInfo[j].translate[2] = new List();
+ ns.JAC[i].ObjInfo[j].translate_keyframes = new List[3];
+ ns.JAC[i].ObjInfo[j].translate_keyframes[0] = new List();
+ ns.JAC[i].ObjInfo[j].translate_keyframes[1] = new List();
+ ns.JAC[i].ObjInfo[j].translate_keyframes[2] = new List();
+ ns.JAC[i].ObjInfo[j].rotate = new List();
+ ns.JAC[i].ObjInfo[j].rotate_keyframes = new List[2];
+ ns.JAC[i].ObjInfo[j].rotate_keyframes[0] = new List();
+ ns.JAC[i].ObjInfo[j].rotate_keyframes[1] = new List();
+ ns.JAC[i].ObjInfo[j].scale = new List[3][];
+ ns.JAC[i].ObjInfo[j].scale[0] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale[1] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale[2] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale[0][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale[0][1] = new List();
+ ns.JAC[i].ObjInfo[j].scale[1][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale[1][1] = new List();
+ ns.JAC[i].ObjInfo[j].scale[2][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale[2][1] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes = new List[3][];
+ ns.JAC[i].ObjInfo[j].scale_keyframes[0] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale_keyframes[1] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale_keyframes[2] = new List[2];
+ ns.JAC[i].ObjInfo[j].scale_keyframes[0][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes[0][1] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes[1][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes[1][1] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes[2][0] = new List();
+ ns.JAC[i].ObjInfo[j].scale_keyframes[2][1] = new List();
+ double[] speed = {
+ 1.0D, 0.5D, 0.33333333333333331D
+ };
+ if (((ns.JAC[i].ObjInfo[j].Flag >> 1) & 1) == 0)
+ {
+ //struct.DModelAnimation.MTransformAni trans[] = new struct.DModelAnimation.MTransformAni[3];
+ //string msg = new StringBuilder().Append(msg).Append("\n -> Translate: ").ToString();
+ //string[] type = { "X", "Y", "Z" };
+ for (int k = 0; k < 3; k++)
+ {
+ //trans[k] = new struct.DModelAnimation.MTransformAni(this);
+ int tflag = ns.JAC[i].ObjInfo[j].Flag >> 3 + k & 1;
+ //msg = new StringBuilder().Append(msg).Append("\n -> T").Append(type[k]).Append(tflag).Append("[").ToString();
+ if (tflag == 1)
+ {
+ int tvar = er.ReadInt32();
+ //trans[k].setFrame((float)tvar / divide);
+ ns.JAC[i].ObjInfo[j].translate[k].Add((float)tvar / 4096f);
+ //msg = (new StringBuilder()).Append(msg).Append(tvar).ToString();
+ continue;
+ }
+ else
+ {
+ int param2 = er.ReadInt32();
+ int startFrame = param2 & 0xffff;
+ ns.JAC[i].ObjInfo[j].tStart = startFrame;
+ int endFrame = param2 >> 16 & 0xfff;
+ ns.JAC[i].ObjInfo[j].tEnd = endFrame;
+ int var2 = param2 >> 28 & 3;
+ int speedId = param2 >> 30 & 3;
+ int toffset = er.ReadInt32();
+ int width = var2 != 0 ? 2 : 4;
+ int extra = (ns.JAC[i].Unknown1 != 3 ? 0 : ns.JAC[i].NrFrames - endFrame);
+ int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames + extra) * speed[speedId]);
+ long curpos = er.BaseStream.Position;
+ for (int t = 0; t < length; t++)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + toffset + (t * width);
+ if (dataoffset == 0)
+ {
+ dataoffset = toffset;
+ }
+ float keyFrame = (width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16());
+ ns.JAC[i].ObjInfo[j].translate_keyframes[k].Add((float)LibNDSFormats.NSBMD.NSBMDGlRenderer.sign((int)keyFrame, (width != 2 ? 32 : 16)) / 4096f);
+ //m = (new StringBuilder()).append(m).append("\n -> #").append(t).append(": ").append(keyFrame).toString();
+ }
+ er.BaseStream.Position = curpos;
+ }
+ }
+ }
+ if (((ns.JAC[i].ObjInfo[j].Flag >> 6) & 1) == 0)
+ {
+ int rflag = ns.JAC[i].ObjInfo[j].Flag >> 8 & 1;
+ if (rflag == 1)
+ {
+ //dataParser _tmp14 = pa;
+ int rvar = er.ReadInt32(); //dataParser.getInt(data, jump, 4);
+ ns.JAC[i].ObjInfo[j].rotate.Add((float)rvar);
+ //msg = (new StringBuilder()).append(msg).append(rvar).toString();
+ //jump += 4;
+ }
+ else
+ {
+ int param2 = er.ReadInt32();
+ int startFrame = param2 & 0xffff;
+ ns.JAC[i].ObjInfo[j].rStart = startFrame;
+ int endFrame = param2 >> 16 & 0xfff;
+ ns.JAC[i].ObjInfo[j].rEnd = endFrame;
+ int var2 = param2 >> 28 & 3;
+ int speedId = param2 >> 30 & 3;
+ int roffset = er.ReadInt32();
+ int width = 2;//var2 != 0 ? 2 : 4;
+ int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames) * speed[speedId]);
+ long curpos = er.BaseStream.Position;
+ for (int r = 0; r < length; r++)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + roffset + (r * width);
+ if (dataoffset == 0)
+ {
+ dataoffset = roffset;
+ }
+ int rvar6 = er.ReadInt16();
+ int rindex = rvar6 & 0x7fff;
+ int mode = rvar6 >> 15 & 1;
+ ns.JAC[i].ObjInfo[j].rotate_keyframes[0].Add(rindex);
+ ns.JAC[i].ObjInfo[j].rotate_keyframes[1].Add(mode);
+ }
+ er.BaseStream.Position = curpos;
+
+ }
+ }
+ if ((ns.JAC[i].ObjInfo[j].Flag >> 9 & 1) == 0)
+ {
+ //struct.DModelAnimation.MScaleAni scale[] = new struct.DModelAnimation.MScaleAni[3];
+ //msg = (new StringBuilder()).append(msg).append("\n -> Scale: ").toString();
+ for (int k = 0; k < 3; k++)
+ {
+ //scale[k] = new struct.DModelAnimation.MScaleAni(this);
+ int sflag = ns.JAC[i].ObjInfo[j].Flag >> 11 + k & 1;
+ //msg = (new StringBuilder()).append(msg).append("\n -> S").append(type[k]).append(sflag).append("[").toString();
+ if (sflag == 1)
+ {
+ //dataParser _tmp19 = pa;
+ int svar1 = er.ReadInt32();//dataParser.getInt(data, jump, 4);
+ ns.JAC[i].ObjInfo[j].scale[k][0].Add((float)svar1 / 4096f);
+ //dataParser _tmp20 = pa;
+ int svar2 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4);
+ ns.JAC[i].ObjInfo[j].scale[k][1].Add((float)svar2 / 4096f);
+
+ //int svar3 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4);
+ //int svar4 = er.ReadInt32();//dataParser.getSign(data, jump + 4, 4);
+ //ns.JAC[i].ObjInfo[j].scale[k][1].Add((float)svar2 / 4096f);
+ //scale[k].setFrame(new float[] {
+ // (float)svar1 / divide, (float)svar2 / divide
+ //});
+ //msg = (new StringBuilder()).append(msg).append(svar1).append("|").append(svar2).toString();
+ //jump += 8;
+ continue;
+ }
+ else
+ {
+ int param2 = er.ReadInt32();
+ int startFrame = param2 & 0xffff;
+ ns.JAC[i].ObjInfo[j].sStart = startFrame;
+ int endFrame = param2 >> 16 & 0xfff;
+ ns.JAC[i].ObjInfo[j].sEnd = endFrame;
+ int var2 = param2 >> 28 & 3;
+ int speedId = param2 >> 30 & 3;
+ int soffset = er.ReadInt32();
+ int width = var2 != 0 ? 2 : 4;
+ int length = (int)Math.Ceiling((double)(ns.JAC[i].NrFrames) * speed[speedId]);
+ long curpos = er.BaseStream.Position;
+ for (int s = 0; s < length; s++)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] +/* ns.JNT0.section_size*/ns.JNT0.infoBlock.Data[i].Objectoffset + soffset + (s * width * 2);
+ if (dataoffset == 0)
+ {
+ dataoffset = soffset;
+ }
+ ns.JAC[i].ObjInfo[j].scale_keyframes[k][0].Add((float)(width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16()) / 4096f);
+ ns.JAC[i].ObjInfo[j].scale_keyframes[k][1].Add((float)(width != 2 ? (float)er.ReadInt32() : (float)er.ReadInt16()) / 4096f);
+ }
+ er.BaseStream.Position = curpos;
+ }
+ }
+ }
+ }
+ if (dataoffset != 0)
+ {
+ curposs = er.BaseStream.Position;
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.JNT0.infoBlock.Data[i].Objectoffset + ns.JAC[i].Offset2;
+ ns.JAC[i].RotationData = er.ReadBytes((int)dataoffset - ns.JAC[i].Offset2);
+ er.BaseStream.Position = curposs;
+ }
+ }
+ else
+ {
+ //MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ }
+ }
+ else
+ {
+ //MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ }
+ else
+ {
+ //MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ er.Close();
+ return ns;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs b/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs
new file mode 100644
index 0000000..39a57d5
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using LibNDSFormats.NSBMD;
+
+namespace LibNDSFormats.NSBCA
+{
+ ///
+ /// Loader for NSBCA files & data.
+ ///
+ public static class NSBCALoader
+ {
+ #region Methods (2)
+
+ // Public Methods (2)
+
+ ///
+ /// Load NSBTX from stream.
+ ///
+ /// Stream to use.
+ /// Material definitions.
+ public static IEnumerable LoadNsbca(Stream stream)
+ {
+ List animation = new List();
+ var reader = new EndianBinaryReader(stream, Endianness.LittleEndian);
+ byte[] id = reader.ReadBytes(4);
+ if (id == new byte[] { 0x42, 0x43, 0x41, 0x30 })
+ {
+ throw new Exception();
+ }
+ int i = reader.ReadInt32();
+ if (i == NSBMD.NSBMD.NDS_TYPE_MAGIC1)
+ {
+ i = reader.ReadInt32();
+ if (i == stream.Length)
+ {
+ int numblock = reader.ReadInt32();
+ numblock >>= 16;
+ int r = reader.ReadInt32();
+ id = reader.ReadBytes(4);
+ if (numblock == 1 && r == 0x14)
+ {
+ animation.AddRange(ReadJnt0(stream, 0x14));
+ }
+ }
+ }
+ reader.Close();
+ return animation;
+ }
+
+ ///
+ /// Load NSBTX from file.
+ ///
+ /// File to use.
+ /// Material definitions.
+ public static IEnumerable LoadNsbca(FileInfo fileInfo)
+ {
+ IEnumerable result = null;
+ using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open))
+ {
+ result = LoadNsbca(fileStream);
+ }
+ return result;
+ }
+
+ ///
+ /// Load materials in stream.
+ ///
+ /// Stream to use.
+ /// Material definitions.
+ public static IEnumerable ReadJnt0(Stream stream, int blockoffset)
+ {
+ EndianBinaryReader reader = new EndianBinaryReader(stream, Endianness.LittleEndian);
+ int blocksize, blockptr, blocklimit;
+ int num, objnum, i, j, r;
+ List dataoffset = new List();
+ int sec1offset, sec2offset;
+ NSBMDAnimation[] animation = new NSBMDAnimation[1];
+ List animlen = new List();
+
+ ////////////////////////////////////////////////
+ // joint
+ blockptr = blockoffset + 4; // already read the ID, skip 4 bytes
+ blocksize = reader.ReadInt32(); // block size
+ blocklimit = blocksize + blockoffset;
+
+ reader.ReadByte(); // skip dummy 0
+ num = reader.ReadByte(); //assert(num > 0); // no of joint must == 1
+ Console.WriteLine("No. of Joint = %02x\n", num);
+
+ //dataoffset = (int*)malloc(sizeof(int));
+ //if (!dataoffset) return NULL;
+
+ reader.BaseStream.Seek(10 + (num << 2), SeekOrigin.Current); // skip [char xyz], useless
+ blockptr += 10;
+
+ reader.BaseStream.Seek(4, SeekOrigin.Current); // go straight to joint data offset
+ blockptr += 4;
+ for (i = 0; i < num; i++)
+ dataoffset.Add(getdword(reader.ReadBytes(4)) + blockoffset);
+
+ //fseek( fnsbca, 16 * num, SEEK_CUR ); // skip names
+ blockptr += 16 * num;
+
+ for (i = 0; i < num; i++)
+ {
+ reader.BaseStream.Seek(dataoffset[i], SeekOrigin.Begin);
+ //j = getdword();
+ if (reader.ReadBytes(4) == new byte[] {0x4A,0x00,0x41,0x43 }) return null;
+ blockptr += 4;
+
+ animlen.Add(getword(reader.ReadBytes(2)));
+ objnum = getword(reader.ReadBytes(2));
+ //if (objnum != g_model[0].objnum) return NULL;
+ blockptr += 4;
+
+ //animation = (ANIMATION*)calloc(sizeof(ANIMATION), objnum);
+ //if (!animation) return NULL;
+ animation = new NSBMDAnimation[objnum];
+
+ reader.BaseStream.Seek(4, SeekOrigin.Current); // skip 4 zeros
+ blockptr += 4;
+
+ sec1offset = getdword(reader.ReadBytes(4)) + dataoffset[i];
+ sec2offset = getdword(reader.ReadBytes(4)) + dataoffset[i];
+ blockptr += 8;
+
+ for (j = 0; j < objnum; j++)
+ {
+ animation[j] = new NSBMDAnimation();
+ animation[j].dataoffset = getword(reader.ReadBytes(2)) + dataoffset[i];
+ }
+
+ for (j = 0; j < objnum; j++)
+ {
+ NSBMD.NSBMDAnimation anim = animation[j];
+ r = getdword(reader.ReadBytes(4));
+ anim.flag = r;
+ // if ((r >> 1 & 1) == 0)
+ //{ // any transformation?
+ if ((r >> 1 & 1) == 0)
+ { // translation
+ if ((r & 4) == 1)
+ { // use Base T
+ }
+ else
+ {
+ if ((r & 8) == 1)
+ { // consTX
+ anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ if ((r & 0x10) == 1)
+ { // consTY
+ anim.m_trans[1] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ if ((r & 0x20) == 1)
+ { // consTZ
+ anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ }
+ }
+ if ((r >> 6 & 1) == 0)
+ { // rotation
+ if ((r & 0x100) == 1)
+ { // constR
+ anim.a = ((float)getword(reader.ReadBytes(2))) / 4096.0f;
+ anim.b = ((float)getword(reader.ReadBytes(2))) / 4096.0f;
+ }
+ else
+ {
+ }
+ }
+ if ((r >> 9 & 1) == 0)
+ { // scale
+ if ((r & 0x400) == 1)
+ { // use Base S
+ }
+ else
+ {
+ if ((r & 0x800) == 1)
+ { // consSX
+ anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ if ((r & 0x1000) == 1)
+ {// consSY
+ anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ if ((r & 0x2000) == 1)
+ {// consSZ
+ anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f;
+ }
+ else
+ {
+ }
+ }
+ // }
+ }
+ animation[j] = anim;
+ }
+
+ }
+ reader.Close();
+ //free(dataoffset);
+ return animation;
+ }
+ static Int32 getdword(byte[] b)
+ {
+ Int32 v;
+ v = b[0];
+ v |= b[1] << 8;
+ v |= b[2] << 16;
+ v |= b[3] << 24;
+ return v;
+ }
+ static Int32 getword(byte[] b)
+ {
+ Int32 v;
+ v = b[0];
+ v |= b[1] << 8;
+ return v;
+ }
+ #endregion Methods
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBMD/MTX44.cs b/DS_Map/LibNDSFormats/NSBMD/MTX44.cs
new file mode 100644
index 0000000..383dc55
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/MTX44.cs
@@ -0,0 +1,354 @@
+// 4x4 matrix class.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Diagnostics;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// 4x4 matrix class.
+ ///
+ internal class MTX44
+ {
+ #regionFields(1)
+
+ ///
+ /// Float values of matrix.
+ ///
+ private float[] _array = new float[4*4];
+
+ #endregionFields
+
+ #regionProperties(2)
+
+ // TODO: Index check!
+
+ ///
+ /// 2-dimensional index accessor.
+ ///
+ public float this[int x, int y]
+ {
+ get { return _array[x + y*4]; }
+ set { _array[x + y*4] = value; }
+ }
+
+ public void SetValues(float[] array)
+ {
+ this._array = array;
+ }
+
+ ///
+ /// Index accessor.
+ ///
+ public float this[int index]
+ {
+ get { return _array[index]; }
+ set { _array[index] = value; }
+ }
+
+ #endregionProperties
+
+ #regionMethods(8)
+
+ //PublicMethods(7)
+
+ ///
+ /// Get float array.
+ ///
+ public float[] Floats
+ {
+ get {
+ return _array;
+ }
+ }
+
+ ///
+ /// Clone this matrix.
+ ///
+ /// Clone of matrix.
+ public MTX44 Clone()
+ {
+ var clone = new MTX44();
+ for (var i = 0; i < 4*4; ++i)
+ {
+ clone._array[i] = _array[i];
+ }
+ return clone;
+ }
+
+ public void translate(float x, float y, float z)
+ {
+ MTX44 b = new MTX44();
+ b.LoadIdentity();
+ b[12] = x;
+ b[13] = y;
+ b[14] = z;
+ MultMatrix(b).CopyValuesTo(this);
+ }
+
+ ///
+ /// Load identity.
+ ///
+ public void LoadIdentity()
+ {
+ Zero();
+ this[0, 0] =
+ this[1, 1] =
+ this[2, 2] =
+ this[3, 3] = 1.0f;
+ }
+
+ ///
+ /// Multiplicate this matrix with another.
+ ///
+ /// Other matrix.
+ /// Multiplication result.
+ public MTX44 MultMatrix(MTX44 b)
+ {
+ MTX44 m = new MTX44();
+ MTX44 a = this;
+ int i, j, k;
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ m._array[(i << 2) + j] = 0.0f;
+ for (k = 0; k < 4; k++)
+ m._array[(i << 2) + j] += a._array[(k << 2) + j]*b._array[(i << 2) + k];
+ }
+ }
+
+ return m;
+ }
+ public static MTX44 mtx_Rotate(int pivot, int neg, float a, float b)
+ {
+ float[] data = new float[16];
+ data[15] = 1.0F;
+ float one = 1.0F;
+ float a2 = a;
+ float b2 = b;
+ switch (neg)
+ {
+ case 1: // '\001'
+ case 3: // '\003'
+ case 5: // '\005'
+ case 7: // '\007'
+ case 9: // '\t'
+ case 11: // '\013'
+ case 13: // '\r'
+ case 15: // '\017'
+ one = -1F;
+ // fall through
+ goto case 2;
+ case 2: // '\002'
+ case 4: // '\004'
+ case 6: // '\006'
+ case 8: // '\b'
+ case 10: // '\n'
+ case 12: // '\f'
+ case 14: // '\016'
+ default:
+ switch (neg)
+ {
+ case 2: // '\002'
+ case 3: // '\003'
+ case 6: // '\006'
+ case 7: // '\007'
+ case 10: // '\n'
+ case 11: // '\013'
+ case 14: // '\016'
+ case 15: // '\017'
+ b2 = -b2;
+ // fall through
+ goto case 4;
+ case 4: // '\004'
+ case 5: // '\005'
+ case 8: // '\b'
+ case 9: // '\t'
+ case 12: // '\f'
+ case 13: // '\r'
+ default:
+ switch (neg)
+ {
+ case 4: // '\004'
+ case 5: // '\005'
+ case 6: // '\006'
+ case 7: // '\007'
+ case 12: // '\f'
+ case 13: // '\r'
+ case 14: // '\016'
+ case 15: // '\017'
+ a2 = -a2;
+ // fall through
+ goto case 8;
+ case 8: // '\b'
+ case 9: // '\t'
+ case 10: // '\n'
+ case 11: // '\013'
+ default:
+ switch (pivot)
+ {
+ case 0: // '\0'
+ data[0] = one;
+ data[5] = a;
+ data[6] = b;
+ data[9] = b2;
+ data[10] = a2;
+ break;
+
+ case 1: // '\001'
+ data[1] = one;
+ data[4] = a;
+ data[6] = b;
+ data[8] = b2;
+ data[10] = a2;
+ break;
+
+ case 2: // '\002'
+ data[2] = one;
+ data[4] = a;
+ data[5] = b;
+ data[8] = b2;
+ data[9] = a2;
+ break;
+
+ case 3: // '\003'
+ data[4] = one;
+ data[1] = a;
+ data[2] = b;
+ data[9] = b2;
+ data[10] = a2;
+ break;
+
+ case 4: // '\004'
+ data[5] = one;
+ data[0] = a;
+ data[2] = b;
+ data[8] = b2;
+ data[10] = a2;
+ break;
+
+ case 5: // '\005'
+ data[6] = one;
+ data[0] = a;
+ data[1] = b;
+ data[8] = b2;
+ data[9] = a2;
+ break;
+
+ case 6: // '\006'
+ data[8] = one;
+ data[1] = a;
+ data[2] = b;
+ data[5] = b2;
+ data[6] = a2;
+ break;
+
+ case 7: // '\007'
+ data[9] = one;
+ data[0] = a;
+ data[2] = b;
+ data[4] = b2;
+ data[6] = a2;
+ break;
+
+ case 8: // '\b'
+ data[10] = one;
+ data[0] = a;
+ data[1] = b;
+ data[4] = b2;
+ data[5] = a2;
+ break;
+
+ case 9: // '\t'
+ data[0] = -a;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ MTX44 matr = new MTX44();
+ matr._array = data;
+ return matr;
+ }
+ ///
+ /// Multiplicate this matrix with vector.
+ ///
+ /// Vector.
+ /// Multiplication result.
+ public float[] MultVector(float[] v)
+ {
+ /* MTX44 a = this;
+ float[] dest = new float[3];
+ float x = v[0];
+ float y = v[1];
+ float z = v[2];
+ dest[0] = x*a[(0 << 2) + 0] + y*a[(1 << 2) + 0] + z*a[(2 << 2) + 0] + a[(3 << 2) + 0];
+ dest[1] = x*a[(0 << 2) + 1] + y*a[(1 << 2) + 1] + z*a[(2 << 2) + 1] + a[(3 << 2) + 1];
+ dest[2] = x*a[(0 << 2) + 2] + y*a[(1 << 2) + 2] + z*a[(2 << 2) + 2] + a[(3 << 2) + 2];
+ return dest;*/
+ float[] vtxTrans = new float[3];
+ for(int i = 0; i < 3; i++)
+ {
+ float c0 = v[0] * this[0 + i];
+ float c1 = v[1] * this[4 + i];
+ float c2 = v[2] * this[8 + i];
+ float c3 = this[12 + i];
+ vtxTrans[i] = c0 + c1 + c2 + c3;
+ }
+
+
+ return vtxTrans;
+ }
+
+ public MTX44()
+ {
+ this.LoadIdentity();
+ }
+
+ ///
+ /// Scale this matrix.
+ ///
+ /// X scale factor.
+ /// Y scale factor.
+ /// Z scale factor.
+ public void Scale(float x, float y, float z)
+ {
+ MTX44 m = new MTX44();
+ m.LoadIdentity();
+
+
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+ this.MultMatrix(m).CopyValuesTo(this);
+ }
+
+ ///
+ /// Fill matrix with zeroes.
+ ///
+ public void Zero()
+ {
+ for (int i = 0; i < 4*4; ++i)
+ _array[i] = 0f;
+ _array = new float[4 * 4];
+ }
+
+ ///
+ /// Copy values to another matrix.
+ ///
+ /// Other matrix.
+ public void CopyValuesTo(MTX44 m)
+ {
+ for (int i = 0; i < 4*4; ++i)
+ m._array[i] = this[i];
+ }
+
+ #endregionMethods
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs
new file mode 100644
index 0000000..92d8458
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs
@@ -0,0 +1,1300 @@
+// NSBMD data definition.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using LibNDSFormats.NSBTX;
+using SM64DSe;
+using System.Drawing;
+
+
+namespace LibNDSFormats.NSBMD
+{
+ // Class for storing NSBMD data.
+ // Adapted from kiwi.ds NSBMD viewer.
+ public class NSBMD
+ {
+
+ #region Constants
+
+ public const int NDS_TYPE_MDL0 = 0x304c444d;
+ public const int NDS_TYPE_TEX0 = 0x30584554;
+ public const int NDS_TYPE_BMD0 = 0x30444d42;
+ public const int NDS_TYPE_MAGIC2 = 0x0002feff;
+ public const int NDS_TYPE_MAGIC1 = 0x0001feff;
+ public const int NDS_TYPE_BTX0 = 0x30585442;
+
+ #endregion Constants
+
+ ///
+ /// Models in NSBMD.
+ ///
+ public NSBMDModel[] models;
+
+ ///
+ /// Materials in NSBMD.
+ ///
+ public IEnumerable materials;
+ ///
+ /// NSBMD materials.
+ ///
+ public List Textures = new List();
+ ///
+ /// NSBMD materials.
+ ///
+ public List Palettes = new List();
+ ///
+ /// Match up model / NSBMD textures.
+ ///
+ public void MatchTextures()
+ {
+ for (var i = 0; i < models.Length; i++)
+ {
+ //models[i].Materials.Clear();
+ //models[i].Materials.AddRange(materials);
+ /*int t7 = 0;
+ for (var j = 0; j < models[i].Materials.Count-1; j++)
+ {
+ try
+ {
+ if (materials.ToArray()[models[i].tex_mat.IndexOf(j)].format != 0)
+ {
+ Console.WriteLine("Texture {0}:", j.ToString());
+ Console.WriteLine("Texture Name: '{0}'", models[i].Materials[j].texname);
+ Console.WriteLine("Palette Name: '{0}'", models[i].Materials[j].palname);
+ string matname = models[i].Materials[j].MaterialName;
+ materials.ToArray()[models[i].tex_mat.IndexOf(j)].CopyTo(models[i].Materials[j]);
+ models[i].Materials[j].MaterialName = matname;
+ if (models[i].Materials[j].format != 7)
+ {
+ models[i].Materials[j].paldata = materials.ToArray()[models[i].pal_mat.IndexOf(j)].paldata;
+ models[i].Materials[j].palname = materials.ToArray()[models[i].pal_mat.IndexOf(j)].palname;
+ models[i].Materials[j].palsize = materials.ToArray()[models[i].pal_mat.IndexOf(j)].palsize;
+ Console.WriteLine("Texture Name: '{0}'", models[i].Materials[j].texname);
+ Console.WriteLine("Palette Name: '{0}'", models[i].Materials[j].palname);
+ }
+ else
+ {
+ t7++;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+
+ }
+ }*/
+ int t7 = 0;
+ for (var j = 0; j < models[i].Polygons.Count - 1; j++)
+ {
+ for (int k = 0; k < models[i].Textures.Count; k++)
+ {
+ if (models[i].Textures[k].texmatid.Contains((uint)models[i].Polygons[j].MatId))
+ {
+ int texid = k;
+ for (int l = 0; l < Textures.Count; l++)
+ {
+ if (Textures[l].texname == models[i].Textures[k].texname) { texid = l; break; }
+ }
+ models[i].Materials[models[i].Polygons[j].MatId].spdata = Textures[texid].spdata; //RITORNA QUI
+ models[i].Materials[models[i].Polygons[j].MatId].texdata = Textures[texid].texdata;
+ models[i].Materials[models[i].Polygons[j].MatId].texname = Textures[texid].texname;
+ models[i].Materials[models[i].Polygons[j].MatId].texoffset = Textures[texid].texoffset;
+ models[i].Materials[models[i].Polygons[j].MatId].texsize = Textures[texid].texsize;
+ models[i].Materials[models[i].Polygons[j].MatId].width = Textures[texid].width;
+ models[i].Materials[models[i].Polygons[j].MatId].height = Textures[texid].height;
+ models[i].Materials[models[i].Polygons[j].MatId].format = Textures[texid].format;
+ models[i].Materials[models[i].Polygons[j].MatId].color0 = Textures[texid].color0;
+ break;
+ }
+ }
+ if (models[i].Materials[models[i].Polygons[j].MatId].format != 7)
+ {
+ for (int k = 0; k < models[i].Palettes.Count; k++)
+ {
+ if (models[i].Palettes[k].palmatid.Contains((uint)models[i].Polygons[j].MatId))
+ {
+ int palid = k;
+ for (int l = 0; l < Palettes.Count; l++)
+ {
+ if (Palettes[l].palname == models[i].Palettes[k].palname) { palid = l; break; }
+ }
+ models[i].Materials[models[i].Polygons[j].MatId].paldata = Palettes[palid].paldata;
+ models[i].Materials[models[i].Polygons[j].MatId].palname = Palettes[palid].palname;
+ models[i].Materials[models[i].Polygons[j].MatId].paloffset = Palettes[palid].paloffset;
+ models[i].Materials[models[i].Polygons[j].MatId].palsize = Palettes[palid].palsize;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ ///
+ /// Match up model / NSBMD textures.
+ ///
+ public void MatchTextures_org()
+ {
+ for (var i = 0; i < models.Length; i++)
+ {
+ for (var j = 0; j < models[i].Materials.Count; j++)
+ {
+ /*bool gottex = false;
+ bool gotpal = false;
+ foreach (var mat1 in materials)
+ {
+ if (j >= models[i].Materials.Count)
+ continue;
+ var mat2 = models[i].Materials[j];
+
+
+ // match texture
+ if (!gottex && mat1.texname.Equals(mat2.texname))
+ {
+ Console.WriteLine("tex '{0}' matched.", mat2.texname);
+ mat1.CopyTo(mat2);
+
+ gottex = true;
+ }
+ // match palette
+ if (mat2.format != 7 // NB. direct texture has no palette
+ && !gotpal
+ && (mat1.palname).Equals(mat2.palname))
+ {
+ Console.WriteLine("pal '{0}' matched.", mat1.palname);
+ mat2.palname = mat1.palname;
+ mat2.palsize = mat1.palsize;
+ mat2.paldata = mat1.paldata;
+ //mat1->palsize = 0;
+ gotpal = true;
+ }
+ }*/
+ try
+ {
+ if (materials.ToArray()[models[i].tex_mat.IndexOf(j)].format != 0)
+ {
+ Console.WriteLine("Texture {0}:", j.ToString());
+ Console.WriteLine("Texture Name: '{0}'", models[i].Materials[j].texname);
+ Console.WriteLine("Palette Name: '{0}'", models[i].Materials[j].palname);
+ string matname = models[i].Materials[j].MaterialName;
+ models[i].Materials[j] = materials.ToArray()[models[i].tex_mat.IndexOf(j)].CopyTo(models[i].Materials[j]);
+ models[i].Materials[j].MaterialName = matname;
+ //if (models[i].Materials[j].format != 7)
+ {
+ models[i].Materials[j].paldata = materials.ToArray()[models[i].pal_mat.IndexOf(j)].paldata;
+ models[i].Materials[j].palname = materials.ToArray()[models[i].pal_mat.IndexOf(j)].palname;
+ models[i].Materials[j].palsize = materials.ToArray()[models[i].pal_mat.IndexOf(j)].palsize;
+ Console.WriteLine("Texture Name: '{0}'", models[i].Materials[j].texname);
+ Console.WriteLine("Palette Name: '{0}'", models[i].Materials[j].palname);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+
+ }
+ }
+ }
+
+ /*for (var i = 0; i < models.Length; i++)
+ {
+ for (var j = 0; j < models[i].Materials.Count; j++)
+ {
+ bool gottex = false;
+ bool gotpal = false;
+ foreach (var mat1 in materials)
+ {
+ if (j >= models[i].Materials.Count)
+ continue;
+ var mat2 = models[i].Materials[j];
+
+ // match texture
+ if (!gottex && mat1.texname.Equals(mat2.texname))
+ {
+ Console.WriteLine("tex '{0}' matched.", mat2.texname);
+ mat1.CopyTo(mat2);
+
+ gottex = true;
+ }
+ for (int q = 0; q < materials.ToList().Count; q++)
+ {
+
+ if (mat2.format != 7 // NB. direct texture has no palette
+ && !gotpal
+ && materials.ToList()[q].palname.Contains(mat2.texname)
+ && (mat1.palname).Equals(mat2.palname))
+ {
+ Console.WriteLine("pal '{0}' matched.", materials.ToArray()[q].palname);
+ mat2.palname = materials.ToArray()[q].palname;
+ mat2.palsize = materials.ToArray()[q].palsize;
+ mat2.paldata = materials.ToArray()[q].paldata;
+ //mat1->palsize = 0;
+ gotpal = true;
+ }
+ }*/
+ /*// match palette
+ if (mat2.format != 7 // NB. direct texture has no palette
+ && !gotpal
+ && (mat1.palname).Equals(mat2.palname))
+ {
+ Console.WriteLine("pal '{0}' matched.", mat1.palname);
+ mat2.palname = mat1.palname;
+ mat2.palsize = mat1.palsize;
+ mat2.paldata = mat1.paldata;
+ //mat1->palsize = 0;
+ gotpal = true;
+ }*/
+ // models[i].Materials[j] = mat2;
+ }
+
+ public void ClearTextures()
+ {
+ for (var i = 0; i < models.Length; i++)
+ {
+ models[i].Materials.Clear();
+ }
+
+ }
+
+
+ ///
+ /// Decode objects.
+ ///
+ public static bool DecodeCode(Stream stream, uint codeoffset, uint codelimit, NSBMDModel mod, int maxstack)
+ {
+ var reader = new BinaryReader(stream);
+ Console.WriteLine("DecodeCode");
+ UInt32 codeptr = codeoffset;
+ bool begin = false; // whether there is a 0x0b begin code
+ int count = 0;
+
+ int stackID = -1;
+ int polyStack = -1;
+ int polystack2 = -1;
+ int curjoint = -1;
+ int matid = -1;
+ int emptystack = maxstack - 1;
+ stream.Seek(codeoffset, SeekOrigin.Begin);
+ while (codeptr < codelimit)
+ {
+ int c = reader.ReadByte();
+ Console.WriteLine(BitConverter.ToString(new byte[] { (byte)c }, 0, 1));
+ int d, e, f, g, h, i, j, k;
+ switch (c)
+ {
+ ////////////////////////////////////////////
+ // bone-definition related byte
+ case 0x06: //NodeDesc[000]
+ d = reader.ReadByte();
+ e = reader.ReadByte();
+ f = reader.ReadByte(); // dummy '0'
+ // printf("DEBUG: %08x: 06: %02x --> %02x\n", codeptr, d, e);
+ codeptr += 4;
+ //curjoint = d;
+ mod.Objects[d].ParentID = e;
+ mod.Objects[d].StackID = stackID = polystack2 = emptystack = emptystack+1;//stackID + 1;//-1;
+ mod.Objects[d].RestoreID = -1;
+ break;
+ case 0x26: //NodeDesc[001]
+ d = reader.ReadByte();
+ e = reader.ReadByte();
+ f = reader.ReadByte(); // dummy '0'
+ g = reader.ReadByte(); // store stackID
+ // printf("DEBUG: %08x: %02x: %02x --> %02x\n", codeptr, c, d, e);
+ codeptr += 5;
+ //curjoint = d;
+ mod.Objects[d].ParentID = e;
+ mod.Objects[d].StackID = stackID = polystack2 = g;
+ mod.Objects[d].RestoreID = -1;
+ break;
+ case 0x46: // 4 bytes follow
+ d = reader.ReadByte();
+ e = reader.ReadByte();
+ f = reader.ReadByte(); // dummy '0'
+ g = reader.ReadByte(); // restore stackID
+ // printf("DEBUG: %08x: %02x: %02x --> %02x\n", codeptr, c, d, e);
+ codeptr += 5;
+ //curjoint = d;
+ mod.Objects[d].ParentID = e;
+ mod.Objects[d].StackID = stackID = polystack2 = emptystack = emptystack+1; //stackID + 1;
+ mod.Objects[d].RestoreID = stackID = g;
+ break;
+ case 0x66: //NodeDesc[011]
+ d = reader.ReadByte();
+ e = reader.ReadByte();
+ f = reader.ReadByte(); // dummy '0'
+ g = reader.ReadByte(); // store stackID
+ h = reader.ReadByte(); // restore stackID
+ // printf("DEBUG: %08x: 66: %02x --> %02x\n", codeptr, d, e);
+ codeptr += 6;
+ //curjoint = d;
+ mod.Objects[d].ParentID = e;
+ mod.Objects[d].StackID = stackID = polystack2 = g;
+ mod.Objects[d].RestoreID = h;
+ break;
+ ////////////////////////////////////////////
+ // node's visibility
+ case 0x02: //Node
+ d = reader.ReadByte(); // node ID
+ e = reader.ReadByte(); // 1 = visible, 0 = hide
+ curjoint = d;
+ //polystack2 = mod.Objects[d].StackID;
+ mod.Objects[d].visible = e == 1;
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr += 3;
+ break;
+ ////////////////////////////////////////////
+ // stackID for polygon
+ case 0x03: //Mtx
+ polyStack = reader.ReadByte();
+ codeptr += 2;
+ break;
+ ////////////////////////////////////////////
+ // unknown
+ case 0x07://NodeDesc_BB[000]
+ d = reader.ReadByte();
+ mod.Objects[d].isBillboard = true;
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr += 2;
+ break;
+ case 0x08:
+ d = reader.ReadByte();
+ mod.Objects[d].isBillboard = true;
+ mod.Objects[d].isYBillboard = true;
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr += 2;
+ break;
+ case 0x09://NodeMix[000] Weight
+ d = reader.ReadByte();
+ polyStack = d;
+ e = reader.ReadByte();
+ codeptr += 2;
+
+ for (int l = 0; l < e; l++)
+ {
+ int var0 = reader.ReadByte();
+ int var1 = reader.ReadByte();
+ int var2 = reader.ReadByte() & 0xff;
+ codeptr += 3;
+ }
+ codeptr += 1;
+ break;
+ ////////////////////////////////////////////
+ // look like BEGIN and END pair
+ case 0x0b: // 0 byte follows
+ if (begin)
+ {
+ //printf("DEBUG: %08x: previous 0x0b not ended.", codeptr);
+ }
+ begin = true;
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr++;
+ break;
+ case 0x2b: // 0 byte follows
+ if (!begin)
+ {
+ //printf( "DEBUG: %08x: previous 0x0b already ended.", codeptr );
+ }
+ begin = false;
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr++;
+ break;
+ ////////////////////////////////////////////
+ case 0x04: //Mat[000]
+ case 0x24:
+ case 0x44:
+ matid = reader.ReadByte();
+ codeptr+=2;
+ count++;
+ break;
+ case 0x05://Shp
+ d = reader.ReadByte();
+ mod.Polygons[d].MatId = matid;
+ if (polyStack != -1)
+ {
+ mod.Polygons[d].StackID = polyStack;
+ }
+ else
+ {
+ mod.Polygons[d].StackID = polystack2;
+ }
+ mod.Polygons[d].JointID = curjoint;
+ mod.Objects[curjoint].childs.Add(d);
+ matid = -1;
+ codeptr += 2;
+ break;
+ case 0x0C://EnvMap
+ d = reader.ReadByte();
+ mod.Materials[d].isEnvironmentMap = true;
+ codeptr += 2;
+ break;
+ ////////////////////////////////////////////
+ case 0x01: //Ret
+ // printf( "DEBUG: %08x: %02x\n", codeptr, c );
+ codeptr++;
+ return true;
+ case 0x00://padding
+ //codeptr++;
+ break;
+ default:
+ // TODO
+ //printf( "DEBUG: %08x: decodecode: unknown code %02x.\n", codeptr, c );
+ //getchar();
+ return false;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// ReadMld0.
+ ///
+ private static NSBMDModel[] ReadMdl0(Stream stream, int blockoffset)
+ {
+ var reader = new EndianBinaryReader(stream, Endianness.LittleEndian);
+
+
+ int blocksize;
+ int blockptr;
+ int blocklimit;
+ byte num;
+ uint r;
+ List model = new List();
+
+ ////////////////////////////////////////////////
+ // model
+ blockptr = blockoffset + 4; // already read the ID, skip 4 bytes
+ blocksize = reader.ReadInt32(); // block size
+ blocklimit = blocksize + blockoffset;
+
+ stream.Skip(1); // skip dummy '0'
+ num = reader.ReadByte(); // no of model
+ if (num <= 0)
+ throw new Exception();
+ for (var i = 0; i < num; ++i)
+ model.Add(new NSBMDModel());
+ var modelOffset = new UInt32[num];
+
+ stream.Skip(10 + 4 + (num * 4)); // skip [char xyz], useless, go straight to model data offset
+ blockptr += 10 + 4;
+
+ ////////////////////////////////////////////////
+ // copy model dataoffset
+ for (var i = 0; i < num; i++)
+ modelOffset[i] = (uint)(reader.ReadUInt32() + blockoffset);
+
+ ////////////////////////////////////////////////
+ // copy model names
+ for (var i = 0; i < num; i++)
+ model[i].Name = Utils.ReadNSBMDString(reader);
+
+ ////////////////////////////////////////////////
+ // parse model data
+
+ uint totalsize_base = reader.ReadUInt32();
+ uint codeoffset_base = reader.ReadUInt32();
+ uint texpaloffset_base = reader.ReadUInt32();
+ uint polyoffset_base = reader.ReadUInt32();
+ uint polyend_base = reader.ReadUInt32();
+ stream.Skip(4);
+ uint matnum = reader.ReadByte(); // no. of material
+ uint polynum = reader.ReadByte(); // no. of polygon
+ byte laststack = reader.ReadByte();
+ byte unknown1m = reader.ReadByte();
+ float modelscale = (float)reader.ReadInt32() / 4096f;
+ float boundscale = (float)reader.ReadInt32();// / 4096f;
+ int vertexcount = reader.ReadInt16();
+ int surfacecount = reader.ReadInt16();
+ int trianglecount = reader.ReadInt16();
+ int quadcount = reader.ReadInt16();
+
+ model[0].laststackid = laststack;
+ model[0].modelScale = modelscale;
+ model[0].boundScale = boundscale;
+ model[0].boundXmin = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+ model[0].boundYmin = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+ model[0].boundZmin = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+ model[0].boundXmax = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+ model[0].boundYmax = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+ model[0].boundZmax = (float)NSBMDGlRenderer.sign(reader.ReadInt16(), 16) / 4096f;
+
+ var polyOffsets = new UInt32[polynum];
+ var polyDataSize = new UInt32[polynum];
+
+ for (var i = 0; i < 1; i++)
+ {
+ var mod = model[i];
+
+ stream.Seek(modelOffset[i], SeekOrigin.Begin);
+
+ // the following variables are all offset values
+ long totalsize;
+ uint codeoffset;
+ UInt32 texpaloffset;
+ UInt32 polyoffset;
+ long polyend;
+
+ long texoffset;
+ long paloffset;
+
+ uint modoffset = modelOffset[i];
+ totalsize = totalsize_base + modoffset;
+ codeoffset = codeoffset_base + modoffset;
+ // additional model data, bone definition etc., just follow NsbmdObject section
+ texpaloffset = texpaloffset_base + modoffset;
+ polyoffset = polyoffset_base + modoffset;
+ polyend = polyend_base + modoffset;
+
+ stream.Skip(5 * 4 + 4 + 2 + 38); // go straight to NsbmdObject
+
+ ////////////////////////////////////////////////
+ // NsbmdObject section
+ UInt32 objnum;
+ int objdatabase;
+ UInt32[] objdataoffset;
+ UInt32[] objdatasize;
+ objdatabase = (int)stream.Position;
+ stream.Skip(1); // skip dummy '0'
+ objnum = reader.ReadByte(); // no of NsbmdObject
+
+ stream.Skip(14 + (objnum * 4)); // skip bytes, go striaght to NsbmdObject data offset
+
+ for (i = 0; i < objnum; ++i)
+ mod.Objects.Add(new NSBMDObject());
+
+
+ objdataoffset = new UInt32[objnum];
+ objdatasize = new UInt32[objnum];
+
+
+ for (var j = 0; j < objnum; j++)
+ objdataoffset[j] = (UInt32)(reader.ReadUInt32() + objdatabase);
+
+ for (var j = 0; j < objnum - 1; j++)
+ objdatasize[j] = objdataoffset[j + 1] - objdataoffset[j];
+ objdatasize[objnum - 1] = (UInt32)(codeoffset - objdataoffset[objnum - 1]);
+
+
+ ////////////////////////////////////////////////
+ // copy NsbmdObject names
+ for (var j = 0; j < objnum; j++)
+ {
+ mod.Objects[j].Name = Utils.ReadNSBMDString(reader);
+ // TO DEBUG
+ Console.WriteLine(mod.Objects[j].Name);
+ }
+
+ ////////////////////////////////////////////////
+ // parse NsbmdObject information
+ for (var j = 0; j < objnum; j++)
+ {
+ if (objdatasize[j] <= 4)
+ continue;
+
+ stream.Seek(objdataoffset[j], SeekOrigin.Begin);
+ ParseNsbmdObject(reader, mod.Objects[j], modelscale);
+ }
+
+ ////////////////////////////////////////////////
+ // material section
+ stream.Seek(texpaloffset, SeekOrigin.Begin); // now get the texture and palette offset
+ texoffset = reader.ReadUInt16() + texpaloffset;
+ paloffset = reader.ReadUInt16() + texpaloffset;
+
+ // allocate memory for material
+ for (var j = 0; j <= matnum; j++)//i <= matnum; ++i)
+ mod.Materials.Add(new NSBMDMaterial());
+
+ ////////////////////////////////////////////////
+ // parse material definition
+ // defines RotA material by pairing texture and palette
+ stream.Seek(16 + (matnum * 4), SeekOrigin.Current); // go straight to material data offset
+ for (var j = 0; j < matnum; j++) // TODO: BAD!
+ {
+ mod.Materials[j] = new NSBMDMaterial();
+ blockptr = (int)stream.Position;
+ r = reader.ReadUInt32() + texpaloffset/* + 4 + 12*/;// skip 18 bytes (+ 2 bytes for texoffset, 2 bytes for paloffset)
+ stream.Seek(r, SeekOrigin.Begin);
+ //mod.Materials[j].repeat = reader.ReadByte();
+ //reader.BaseStream.Position -= 1;
+ int dummy = reader.ReadInt16();
+ int sectionSize = reader.ReadInt16();
+ int unknown1 = reader.ReadInt32();//DifAmbColors
+ int unknown2 = reader.ReadInt32();//SpeEmiColors
+ int unknown3 = reader.ReadInt32();//PolyAttrib
+ int constant2 = reader.ReadInt32();//PolyAttrib Mask
+ int texVramOffset = reader.ReadInt16();
+ int texImageParam = reader.ReadInt16();
+ int constant3 = reader.ReadInt32();//texImageParam Mask
+ int constant4 = reader.ReadInt32();
+ int matWidth = reader.ReadInt16();
+ int matHeight = reader.ReadInt16();
+ int unknown4 = reader.ReadInt16();
+ int unknown5 = reader.ReadInt16();
+ int unknown6 = reader.ReadInt32();
+ //int unknown7 = reader.ReadInt32();//if srt S Scale
+ //int unknown8 = reader.ReadInt32();//if srt T Scale
+ //int unknown9 = reader.ReadInt16();//if srt & 60 Rot
+ //int unknownA = reader.ReadInt16();//if srt & 60 S Trans
+ //int unknownB = reader.ReadInt16();//if srt & 60 T Trans
+
+ //uint polyParam = reader.ReadUInt32();
+ //reader.ReadInt16();
+ //ushort texImageParam = reader.ReadUInt16();
+ mod.Materials[j].repeatS = texImageParam & 1;
+ mod.Materials[j].repeatT = texImageParam >> 1 & 1;
+ mod.Materials[j].flipS = texImageParam >> 2 & 1;
+ mod.Materials[j].flipT = texImageParam >> 3 & 1;
+ /*if ((texImageParam >> 14 & 0x03) == 1)
+ {
+ mod.Materials[j].scaleS = /*1 << /(texImageParam >> 12 & 2) + 1;
+ mod.Materials[j].scaleT = /*1 << /(texImageParam >> 14 & 2) + 1;
+ }
+ else
+ {
+ mod.Materials[j].scaleS = 1;
+ mod.Materials[j].scaleT = 1;
+ }*/
+ switch (texImageParam >> 14 & 0x03)
+ {
+ case 0:
+ mod.Materials[j].scaleS = 1;
+ mod.Materials[j].scaleT = 1;
+ mod.Materials[j].transS = 0;
+ mod.Materials[j].transT = 0;
+ break;
+
+ case 1:
+ {
+ int sscale = (int)reader.ReadInt32();// >> 0 & 0xFFFFFFFF;
+ sscale = NSBMDGlRenderer.sign(sscale, 32);
+ int tscale = (int)reader.ReadInt32();// >> 0 & 0xFFFFFFFF;
+ tscale = NSBMDGlRenderer.sign(tscale, 32);
+ //int strans = (int)unknown2 >> 0 & 0xFFFF;
+ //int ttrans = (int)unknown2 >> 16 & 0xFFFF;
+
+ mod.Materials[j].scaleS = (float)sscale / 4096f;
+ mod.Materials[j].scaleT = (float)tscale / 4096f;
+ if (sectionSize >= 60)
+ {
+ mod.Materials[j].rot = (float)reader.ReadInt16() / 4096f;
+ mod.Materials[j].transS = (float)reader.ReadInt16() / 4096f;
+ mod.Materials[j].transT = (float)reader.ReadInt16() / 4096f;
+ }
+ else
+ {
+
+ }
+ break;
+ }
+ case 2:
+ case 3:
+ mod.Materials[j].mtx = new float[16];
+ for (int k = 0; k < 16; k++)
+ {
+ mod.Materials[j].mtx[k] = reader.ReadInt32();
+ }
+ break;
+
+ default:
+ break;
+ // throw new Exception(String.Format("BMD: unsupported texture coord transform mode {0}", matgroup.m_TexParams >> 30));
+ }
+ mod.Materials[j].width = matWidth;
+ mod.Materials[j].height = matHeight;
+ int width = 8 << (texImageParam >> 4 & 7);
+ int height = 8 << (texImageParam >> 7 & 7);
+ //int m_DifAmbColors = reader.ReadInt32();
+ //int m_SpeEmiColors = reader.ReadInt32();
+ mod.Materials[j].DiffuseColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown1 & 0x7FFF));
+ mod.Materials[j].AmbientColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown1 >> 16 & 0x7FFF));
+ mod.Materials[j].SpecularColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown2 & 0x7FFF));
+ mod.Materials[j].EmissionColor = SM64DSe.Helper.BGR15ToColor((ushort)(unknown2 >> 16 & 0x7FFF));
+ int a = (int)((unknown3 >> 16) & 31);
+ mod.Materials[j].Alpha = a;//a * 2 + 1;//a * 2 + (a + 31) / 32;
+ mod.Materials[j].PolyAttrib = (uint)unknown3;
+ mod.Materials[j].diffuseColor = (unknown1 >> 15 & 1) == 1;
+ mod.Materials[j].shine = (unknown2 >> 15 & 1) == 1;
+ stream.Seek(blockptr + 4, SeekOrigin.Begin);
+ }
+ for (var j = 0; j < matnum; j++)
+ {
+ mod.Materials[j].MaterialName = Utils.ReadNSBMDString(reader);
+ }
+
+ ////////////////////////////////////////////////
+ // now go to read the texture definition
+ stream.Seek(texoffset, SeekOrigin.Begin);
+ stream.Skip(1); // skip dummy '0'
+ int texnum = reader.ReadByte();
+ Debug.Assert(texnum <= matnum);
+ Console.WriteLine(String.Format("texnum: {0}", texnum));
+
+ if (texnum > 0)
+ {
+ stream.Seek(14 + (texnum * 4), SeekOrigin.Current); // go straight to data offsets
+ for (var j = 0; j < texnum; j++)
+ {
+ Int32 flags = reader.ReadInt32();
+ int numPairs = flags >> 16 & 0xf;
+ int dummy = flags >> 24 & 0xf;
+ blockptr = (int)stream.Position;
+ stream.Seek((flags & 0xffff) + texpaloffset, SeekOrigin.Begin);
+ NSBMDTexture t = new NSBMDTexture();
+ for (int k = 0; k < numPairs; k++)
+ {
+ uint texmatid = reader.ReadByte();
+ mod.tex_mat.Add((int)texmatid);
+ mod.Materials[j].texmatid.Add(texmatid);
+ t.texmatid.Add(texmatid);
+ }
+ mod.Textures.Add(t);
+ stream.Seek(blockptr, SeekOrigin.Begin);
+ }
+
+ for (var j = 0; j < texnum; j++) // copy texture names
+ {
+ NSBMDMaterial mat = mod.Materials[j];
+
+ mat.texname = Utils.ReadNSBMDString(reader);
+ reader.BaseStream.Position -= 16;
+ mod.Textures[j].texname = Utils.ReadNSBMDString(reader);
+
+ Console.WriteLine("tex (matid={0}): {1}", mat.texmatid, mat.texname);
+ }
+ }
+
+ ////////////////////////////////////////////////
+ // now go to read the palette definition
+ stream.Seek(paloffset, SeekOrigin.Begin);
+ stream.Skip(1); // skip dummy '0'
+ int palnum = reader.ReadByte(); // no of palette definition
+ Debug.Assert(palnum <= matnum); // may not always hold?
+ Console.WriteLine("DEBUG: palnum = {0}", palnum);
+
+ if (palnum > 0)
+ {
+ stream.Seek(14 + (palnum * 4), SeekOrigin.Current); // go straight to data offsets
+ for (var j = 0; j < palnum; j++) // matching palette with material
+ {
+ Int32 flags = reader.ReadInt32();
+ int numPairs = flags >> 16 & 0xf;
+ int dummy = flags >> 24 & 0xf;
+ blockptr = (int)stream.Position;
+ stream.Seek((flags & 0xffff) + texpaloffset, SeekOrigin.Begin);
+ NSBMDPalette t = new NSBMDPalette();
+ for (int k = 0; k < numPairs; k++)
+ {
+ uint texmatid = reader.ReadByte();
+ mod.tex_mat.Add((int)texmatid);
+ mod.Materials[j].texmatid.Add(texmatid);
+ t.palmatid.Add(texmatid);
+ }
+ mod.Palettes.Add(t);
+ stream.Seek(blockptr, SeekOrigin.Begin);
+ }
+ for (var j = 0; j < palnum; j++) // copy palette names
+ {
+ int palmatid = (int)mod.Materials[j].palmatid;
+ mod.Materials[palmatid].palname = Utils.ReadNSBMDString(reader);
+ reader.BaseStream.Position -= 16;
+ mod.Palettes[j].palname = Utils.ReadNSBMDString(reader);
+ // TO DEBUG
+ Console.WriteLine("pal (matid={0}): {1}", palmatid, mod.Materials[palmatid].palname);
+ }
+ }
+ ////////////////////////////////////////////////
+ // Polygon
+ stream.Seek(polyoffset, SeekOrigin.Begin);
+ stream.Skip(1); // skip dummy '0'
+ r = reader.ReadByte(); // no of polygon
+ Console.WriteLine("DEBUG: polynum = {0}", polynum);
+
+ for (var j = 0; j <= polynum; j++)
+ {
+ mod.Polygons.Add(new NSBMDPolygon());
+ }
+
+
+ stream.Skip(14 + (polynum * 4)); // skip bytes, go straight to data offset
+
+
+ for (var j = 0; j < polynum; j++)
+ polyOffsets[j] = reader.ReadUInt32() + polyoffset;
+ try
+ {
+ for (var j = 0; j < polynum; j++) // copy polygon names
+ {
+ mod.Polygons[j].Name = Utils.ReadNSBMDString(reader);
+ Console.WriteLine(mod.Polygons[j].Name);
+ }
+ }
+ catch { }
+ ////////////////////////////////////////////////
+ // now go to the polygon data, there is RotA 16-byte-header before geometry commands
+ for (var j = 0; j < polynum; j++)
+ {
+ var poly = mod.Polygons[j];
+ //////////////////////////////////////////////////////////
+ poly.MatId = -1; // DEFAULT: indicate no associated material
+ //////////////////////////////////////////////////////////
+ //stream.Seek(polyOffsets[j] + 8, SeekOrigin.Begin); // skip 8 unknown bytes
+ short dummy = reader.ReadInt16();
+ short headerSize = reader.ReadInt16();
+ int unknown2 = reader.ReadInt32();
+ polyOffsets[j] += reader.ReadUInt32();
+ polyDataSize[j] = reader.ReadUInt32();
+ //printf( "poly %2d '%-16s': dataoffset: %08x datasize %08x\n", j, poly->polyname, poly->dataoffset, poly->datasize );
+ }
+ //}
+
+ ////////////////////////////////////////////////
+ // read the polygon data into memory
+ for (var j = 0; j < polynum; j++)
+ {
+ var poly = mod.Polygons[j];
+ stream.Seek(polyOffsets[j], SeekOrigin.Begin);
+ poly.PolyData = reader.ReadBytes((int)polyDataSize[j]);
+ }
+ //}
+
+ ////////////////////////////////////////////////
+ // decode the additional model data
+ DecodeCode(stream, codeoffset, texpaloffset, mod, laststack);
+ }
+
+ //modelnum = num;
+ return model.ToArray();
+ }
+ public static float getFixed(int value, int sign, int var, int frac)
+ {
+ float fixe = value;
+ if (sign == 1)
+ {
+ fixe = NSBMDGlRenderer.sign(value, GetSizeOfObject(value));
+ }
+ float divide = 1 << frac;
+ fixe /= divide;
+ return fixe;
+ }
+ public static int GetSizeOfObject(object obj)
+ {
+ if (obj is Int32)
+ {
+ return 32;
+ }
+ if (obj is Int16)
+ {
+ return 16;
+ }
+ if (obj is byte)
+ {
+ return 8;
+ }
+ return -1;
+ }
+
+ ///
+ /// Parse single NSBMD object.
+ ///
+ private static void ParseNsbmdObject(EndianBinaryReader reader, NSBMDObject nsbmdObject, float modelscale)
+ {
+ UInt16 v = reader.ReadUInt16();
+ Int16 divide = reader.ReadInt16();
+ divide = (short)NSBMDGlRenderer.sign(divide, 16);
+ int unknown = v >> 12 & 0xf;
+ nsbmdObject.StackID = unknown;
+ //nsbmdObject.isBillboard = ((v >> 12 & 0xf) == 1?true:false);
+ float[] s = NSBMDGlRenderer.loadIdentity();
+ float[] r = NSBMDGlRenderer.loadIdentity();
+ float[] t = NSBMDGlRenderer.loadIdentity();
+ if ((v & 1) == 0)
+ {
+ nsbmdObject.Trans = true;
+
+ nsbmdObject.X = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f; //(float)(reader.ReadDouble() / 4096d);//.ReadUInt32() / 4096;
+ nsbmdObject.Y = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f;//(float)(reader.ReadDouble() / 4096d);
+ nsbmdObject.Z = (float)reader.ReadInt32() / 4096f / modelscale;//(float)getdword(reader.ReadBytes(4)) / 4096f;//(float)(reader.ReadDouble() / 4096d);
+ t = NSBMDGlRenderer.translate(t, nsbmdObject.X, nsbmdObject.Y, nsbmdObject.Z);
+ }
+ if ((v >> 3 & 0x1) == 0x1)
+ {
+ nsbmdObject.IsRotated = true;
+ float a = reader.ReadInt16();
+ a = NSBMDGlRenderer.sign((int)a, 16) / 4096f;
+ float b = reader.ReadInt16();
+ b = NSBMDGlRenderer.sign((int)b, 16) / 4096f;
+ nsbmdObject.Pivot = (int)(v >> 4) & 0x0f;
+ nsbmdObject.Neg = (int)(v >> 8) & 0x0f;
+ nsbmdObject.RotA = a;
+ nsbmdObject.RotB = b;
+ nsbmdObject.rotate_mtx = mtxPivot(new float[] { nsbmdObject.RotA, nsbmdObject.RotB }, nsbmdObject.Pivot, nsbmdObject.Neg);
+ r = NSBMDGlRenderer.multMatrix(r, nsbmdObject.rotate_mtx);
+ }
+ if ((v >> 1 & 1) == 0 && (v >> 3 & 1) == 0)
+ {
+ float[] a = new float[16];
+ a[0] = 1.0F;
+ a[5] = 1.0F;
+ a[10] = 1.0F;
+ a[15] = 1.0F;
+ float[] rotate = new float[8];
+ //msg = (new StringBuilder()).append(msg).append(" | R: ").toString();
+ for (int j = 0; j < rotate.Length; j++)
+ {
+ //dataParser _tmp4 = pa;
+ int value = NSBMDGlRenderer.sign(reader.ReadInt16(),16); //dataParser.getSign(data, offset + 4 + j * 2 + jump, 2);
+ rotate[j] = (float)value / 4096f;
+ //msg = (new StringBuilder()).append(msg).append(pad(Integer.valueOf(value), 4)).toString();
+ //if(j + 1 < rotate.length)
+ // msg = (new StringBuilder()).append(msg).append(", ").toString();
+ }
+
+ a[0] = (float)divide / 4096f;
+ a[1] = rotate[0];
+ a[2] = rotate[1];
+ a[4] = rotate[2];
+ a[5] = rotate[3];
+ a[6] = rotate[4];
+ a[8] = rotate[5];
+ a[9] = rotate[6];
+ a[10] = rotate[7];
+ nsbmdObject.rotate_mtx = a;
+ nsbmdObject.IsRotated = true;
+ r = NSBMDGlRenderer.multMatrix(r, nsbmdObject.rotate_mtx);
+ }
+ if ((v >> 2 & 1) == 0)
+ {
+ float[] scale = new float[3];
+ for (int j = 0; j < scale.Length; j++)
+ {
+ int value = reader.ReadInt32();
+ scale[j] = (float)value / 4096f;
+ }
+ nsbmdObject.scale = scale;
+ nsbmdObject.IsScaled = true;
+ s = NSBMDGlRenderer.scale(s, scale[0], scale[1], scale[2]);
+ }
+ nsbmdObject.materix = NSBMDGlRenderer.loadIdentity();
+ nsbmdObject.materix = NSBMDGlRenderer.multMatrix(nsbmdObject.materix, t);
+ nsbmdObject.materix = NSBMDGlRenderer.multMatrix(nsbmdObject.materix, r);
+ nsbmdObject.materix = NSBMDGlRenderer.multMatrix(nsbmdObject.materix, s);
+ }
+ public static float[] mtxPivot(float[] ab, int pv, int neg)
+ {
+ float[] data = new float[16];
+ data[15] = 1.0F;
+ float one = 1.0F;
+ float a = ab[0];
+ float b = ab[1];
+ float a2 = a;
+ float b2 = b;
+ switch (neg)
+ {
+ case 1: // '\001'
+ case 3: // '\003'
+ case 5: // '\005'
+ case 7: // '\007'
+ case 9: // '\t'
+ case 11: // '\013'
+ case 13: // '\r'
+ case 15: // '\017'
+ one = -1F;
+ // fall through
+ goto case 2;
+ case 2: // '\002'
+ case 4: // '\004'
+ case 6: // '\006'
+ case 8: // '\b'
+ case 10: // '\n'
+ case 12: // '\f'
+ case 14: // '\016'
+ default:
+ switch (neg)
+ {
+ case 2: // '\002'
+ case 3: // '\003'
+ case 6: // '\006'
+ case 7: // '\007'
+ case 10: // '\n'
+ case 11: // '\013'
+ case 14: // '\016'
+ case 15: // '\017'
+ b2 = -b2;
+ // fall through
+ goto case 4;
+ case 4: // '\004'
+ case 5: // '\005'
+ case 8: // '\b'
+ case 9: // '\t'
+ case 12: // '\f'
+ case 13: // '\r'
+ default:
+ switch (neg)
+ {
+ case 4: // '\004'
+ case 5: // '\005'
+ case 6: // '\006'
+ case 7: // '\007'
+ case 12: // '\f'
+ case 13: // '\r'
+ case 14: // '\016'
+ case 15: // '\017'
+ a2 = -a2;
+ // fall through
+ goto case 8;
+ case 8: // '\b'
+ case 9: // '\t'
+ case 10: // '\n'
+ case 11: // '\013'
+ default:
+ switch (pv)
+ {
+ case 0: // '\0'
+ data[0] = one;
+ data[5] = a;
+ data[6] = b;
+ data[9] = b2;
+ data[10] = a2;
+ break;
+
+ case 1: // '\001'
+ data[1] = one;
+ data[4] = a;
+ data[6] = b;
+ data[8] = b2;
+ data[10] = a2;
+ break;
+
+ case 2: // '\002'
+ data[2] = one;
+ data[4] = a;
+ data[5] = b;
+ data[8] = b2;
+ data[9] = a2;
+ break;
+
+ case 3: // '\003'
+ data[4] = one;
+ data[1] = a;
+ data[2] = b;
+ data[9] = b2;
+ data[10] = a2;
+ break;
+
+ case 4: // '\004'
+ data[5] = one;
+ data[0] = a;
+ data[2] = b;
+ data[8] = b2;
+ data[10] = a2;
+ break;
+
+ case 5: // '\005'
+ data[6] = one;
+ data[0] = a;
+ data[1] = b;
+ data[8] = b2;
+ data[9] = a2;
+ break;
+
+ case 6: // '\006'
+ data[8] = one;
+ data[1] = a;
+ data[2] = b;
+ data[5] = b2;
+ data[6] = a2;
+ break;
+
+ case 7: // '\007'
+ data[9] = one;
+ data[0] = a;
+ data[2] = b;
+ data[4] = b2;
+ data[6] = a2;
+ break;
+
+ case 8: // '\b'
+ data[10] = one;
+ data[0] = a;
+ data[1] = b;
+ data[4] = b2;
+ data[5] = a2;
+ break;
+
+ case 9: // '\t'
+ data[0] = -a;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ return data;
+ }
+ static Int32 getdword(byte[] b)
+ {
+ Int32 v;
+ v = b[0];
+ v |= b[1] << 8;
+ v |= b[2] << 16;
+ v |= b[3] << 24;
+ return v;
+ }
+ static Int32 getword(byte[] b)
+ {
+ Int32 v;
+ v = b[0];
+ v |= b[1] << 8;
+ return v;
+ }
+ ///
+ /// Generate NSBMD from stream.
+ ///
+ internal static NSBMD FromStream(Stream stream)
+ {
+ var result = new NSBMD();
+
+ var reader = new BinaryReader(stream);
+
+ int tmp;
+ tmp = reader.ReadInt32();
+ if (tmp != NDS_TYPE_BMD0)
+ throw new Exception();
+ tmp = reader.ReadInt32();
+ if (tmp != NDS_TYPE_MAGIC2)
+ throw new Exception();
+ int filesize = reader.ReadInt32();
+ if (filesize > stream.Length)
+ throw new Exception();
+ int numblock = reader.ReadInt32();
+ numblock >>= 16;
+ if (numblock == 0)
+ {
+ throw new Exception("DEBUG: no of block zero.\n");
+ }
+ ///////////////////////////////////////////////////////
+ // allocate memory for storing blockoffset
+ int[] blockoffset = new int[numblock];
+ for (int i = 0; i < numblock; i++)
+ {
+ tmp = reader.ReadInt32();
+ blockoffset[i] = tmp;
+ }
+
+ ///////////////////////////////////////////////////////
+ // now go to read the blocks
+ for (int i = 0; i < numblock; i++)
+ {
+ stream.Position = blockoffset[i];
+ int id = reader.ReadInt32();
+ int texnum = 0, palnum = 0;
+
+ switch (id)
+ {
+ case NDS_TYPE_MDL0:
+ result.models = ReadMdl0(stream, blockoffset[i]);
+
+ break;
+ case NDS_TYPE_TEX0:
+ result.materials = NSBTXLoader.ReadTex0(stream, blockoffset[i], out texnum, out palnum, out result.Textures, out result.Palettes);
+ break;
+ default:
+ throw new Exception("Unknown ID");
+ break;
+ }
+ }
+
+ return result;
+ }
+ }
+
+ ///
+ /// Type for storing RGBA data in.
+ ///
+ public struct RGBA
+ {
+ #region Data Members (6)
+
+ public byte A;
+ public byte R;
+ public byte G;
+ public byte B;
+
+ ///
+ /// Transparent color.
+ ///
+ public static RGBA Transparent = new RGBA { R = 0xFF, A = 0x0 };
+
+ public static RGBA fromColor(System.Drawing.Color c)
+ {
+ RGBA a = new RGBA();
+ a.R = c.R;
+ a.G = c.G;
+ a.B = c.B;
+ a.A = c.A;
+ return a;
+ }
+
+ ///
+ /// Index accessor.
+ ///
+ public byte this[int i]
+ {
+ get
+ {
+ switch (i)
+ {
+ case 0:
+ return R;
+ break;
+ case 1:
+ return G;
+ break;
+ case 2:
+ return B;
+ break;
+ case 3:
+ return A;
+ break;
+ default:
+ throw new Exception();
+ break;
+ }
+ }
+ set
+ {
+ switch (i)
+ {
+ case 0:
+ R = value;
+ break;
+ case 1:
+ G = value;
+ break;
+ case 2:
+ B = value;
+ break;
+ case 3:
+ A = value;
+ break;
+ default:
+ throw new Exception();
+ break;
+ }
+ }
+ }
+ public Color ToColor()
+ {
+ return Color.FromArgb(A, R, G, B);
+ }
+ #endregion Data Members
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDAnimation.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDAnimation.cs
new file mode 100644
index 0000000..387a192
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDAnimation.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// Type for NSBCA objects.
+ ///
+ public class NSBMDAnimation
+ {
+ public int dataoffset = 0;
+ public int flag = 0;
+ public float[] m_trans = new float[3];
+ public float a, b = 0;
+ public float[] m_scale = new float[3];
+ public int frame = 0;
+ public int framelen = 0;
+ public List animdata = new List();
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDGlRenderer.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDGlRenderer.cs
new file mode 100644
index 0000000..e72a8e9
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDGlRenderer.cs
@@ -0,0 +1,3498 @@
+// OpenGL Renderer for NSBMD models.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Collections.Generic;
+using Tao.OpenGl;
+using System.IO;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Media3D;
+using OpenTK;
+using HelixToolkit;
+using MKDS_Course_Editor.Export3DTools;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// OpenGL renderer for NSBMD models.
+ ///
+ public class NSBMDGlRenderer
+ {
+ #regionFields(11)
+ private bool writevertex = true;
+ public List normals = new List();
+ public List vertex = new List();
+ List md = new List();
+ public static DependencyProperty matName = DependencyProperty.Register("MatName", typeof(string), typeof(DiffuseMaterial));
+ public static DependencyProperty polyName = DependencyProperty.Register("PolyName", typeof(string), typeof(DiffuseMaterial));
+ List matt = new List();
+ List mattt = new List();
+ public List vertex_normal = new List();
+ private static MTX44 CurrentMatrix;
+ private static bool g_mat = true;
+ private static string file;
+ public static bool gOptColoring = true;
+ private static bool gOptTexture = true;
+
+ private static bool gOptWireFrame = false;
+ private static MTX44[] MatrixStack = new MTX44[31];
+ private const float SCALE_IV = 4096.0f;
+ private static int stackID;
+
+ private int[] Tx;
+ private int[] Ty;
+ private int[] Tz;
+ //private int[] T2;
+ private int[] R;
+ //private int[] R2;
+ private int[] Sx;
+ private int[] Sy;
+ private int[] Sz;
+ private int[] S2x;
+ private int[] S2y;
+ private int[] S2z;
+ //private int[] S2;
+ private int[] frame;
+ private int[] nr;
+ private int[] frame_;
+
+ //private static int gCurrentPoly;
+ private static int gCurrentVertex;
+ private static bool gOptVertexMode;
+ private int matstart;
+ private static readonly String[] TEXTURE_FORMATS = new String[] { "", "A3I5", "4-Color", "16-Color", "256-Color", "4x4-Texel", "A5I3", "Direct Texture" };
+
+ #endregionFields
+
+ #regionConstructors(1)
+
+ public NSBMDGlRenderer()
+ {
+ this.matstart = 0;
+ // Init matrix stack.
+ for (int i = 0; i < MatrixStack.Length; ++i)
+ MatrixStack[i] = new MTX44();
+ }
+ ///
+ /// Ctor.
+ ///
+ public NSBMDGlRenderer(int matstart)
+ {
+ this.matstart = matstart;
+ // Init matrix stack.
+ for (int i = 0; i < MatrixStack.Length; ++i)
+ MatrixStack[i] = new MTX44();
+ }
+
+ #endregionConstructors
+
+ #regionMethods(8)
+
+ //PublicMethods(1)
+
+ ///
+ /// Model to render.
+ ///
+ private NSBMDModel _model;
+
+ ///
+ /// Model to render.
+ ///
+ public NSBMDModel Model
+ {
+ get { return _model; }
+ set
+ {
+ _model = value;
+ try
+ {
+ MakeTexture(_model);
+ }
+ catch
+ {
+
+ }
+ }
+ }
+ public enum RenderMode
+ {
+ Opaque = 1,
+ Translucent,
+ Picking
+ }
+ public static float[] rotate(float[] a, float x, float y, float z)
+ {
+ float[] b = loadIdentity();
+ float cx = (float)Math.Cos(x);
+ float sx = (float)Math.Sin(x);
+ float cy = (float)Math.Cos(y);
+ float sy = (float)Math.Sin(y);
+ float cz = (float)Math.Cos(z);
+ float sz = (float)Math.Sin(z);
+ b[0] = cy * cz;
+ b[1] = cy * sz;
+ b[2] = -sy;
+ b[4] = cz * sx * sy - sz * cx;
+ b[5] = sx * sy + cx * cz;
+ b[6] = sx * cy;
+ b[8] = cx * cz * sy + sx * sz;
+ b[9] = cx * sy * sz - sx * cz;
+ b[10] = cx * cy;
+ return multMatrix(a, b);
+ }
+ int lastselectedanim = -2;
+ public void RenderModel(string file2, MKDS_Course_Editor.NSBTA.NSBTA.NSBTA_File ani, int[] aniframeS, int[] aniframeT, int[] aniframeScaleS, int[] aniframeScaleT, int[] aniframeR, MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File ca, bool anim, int selectedani, float X, float Y, float dist, float elev, float ang, MKDS_Course_Editor.NSBTP.NSBTP.NSBTP_File p, NSBMD nsb)
+ {
+ RenderModel(file2, ani, aniframeS, aniframeT, aniframeScaleS, aniframeScaleT, aniframeR, ca, anim, selectedani, X, Y, dist, elev, ang, true, p, nsb);
+ }
+ public void RenderModel(string file2, MKDS_Course_Editor.NSBTA.NSBTA.NSBTA_File ani, int[] aniframeS, int[] aniframeT, int[] aniframeScaleS, int[] aniframeScaleT, int[] aniframeR, MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File ca, bool anim, int selectedani, float X, float Y, float dist, float elev, float ang, bool licht, MKDS_Course_Editor.NSBTP.NSBTP.NSBTP_File p, NSBMD nsb)
+ {
+ if (lastselectedanim != selectedani && selectedani != -1)
+ {
+ Tx = new int[ca.JAC[selectedani].ObjInfo.Length];
+ Ty = new int[ca.JAC[selectedani].ObjInfo.Length];
+ Tz = new int[ca.JAC[selectedani].ObjInfo.Length];
+ R = new int[ca.JAC[selectedani].ObjInfo.Length];
+ Sx = new int[ca.JAC[selectedani].ObjInfo.Length];
+ Sy = new int[ca.JAC[selectedani].ObjInfo.Length];
+ Sz = new int[ca.JAC[selectedani].ObjInfo.Length];
+ S2x = new int[ca.JAC[selectedani].ObjInfo.Length];
+ S2y = new int[ca.JAC[selectedani].ObjInfo.Length];
+ S2z = new int[ca.JAC[selectedani].ObjInfo.Length];
+ lastselectedanim = selectedani;
+ }
+ if (frame == null && p.Header.file_size != 0)
+ {
+ frame = new int[p.MPT.names.Length];
+ frame_ = new int[p.MPT.names.Length];
+ nr = new int[p.MPT.names.Length];
+ }
+ RenderModel(file2, ani, aniframeS, aniframeT, aniframeScaleS, aniframeScaleT, aniframeR, ca, RenderMode.Opaque, anim, anim, selectedani, X, Y, dist, elev, ang, licht, p, nsb); //anim, anim);
+ RenderModel(file2, ani, aniframeS, aniframeT, aniframeScaleS, aniframeScaleT, aniframeR, ca, RenderMode.Translucent, false, anim, selectedani, X, Y, dist, elev, ang, licht, p, nsb);
+ }
+ //MTX44[] mt;
+ ///
+ /// Render model to OpenGL surface.
+ ///
+ public void RenderModel(string file2, MKDS_Course_Editor.NSBTA.NSBTA.NSBTA_File ani, int[] aniframeS, int[] aniframeT, int[] aniframeScaleS, int[] aniframeScaleT, int[] aniframeR, MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File ca, RenderMode r, bool anim, bool anim2, int selectedanim, float X, float Y, float dist, float elev, float ang, bool licht, MKDS_Course_Editor.NSBTP.NSBTP.NSBTP_File p, NSBMD nsb)
+ {
+ MTX44 tmp = new MTX44();
+ file = file2;
+ for (var j = 0; j < Model.Polygons.Count - 1; j++)
+ {
+ var poly = Model.Polygons[j];
+ int matid = poly.MatId;
+ var mat = Model.Materials[matid];
+ }
+ int light = Gl.glIsEnabled(Gl.GL_LIGHTING);
+ Gl.glDisable(Gl.GL_LIGHTING);
+ Gl.glLineWidth(2.0F);
+
+ if (light == 1)
+ {
+ Gl.glEnable(Gl.GL_LIGHTING);
+ }
+ Gl.glLineWidth(1.0F);
+
+ ////////////////////////////////////////////////////////////
+ // prepare the matrix stack
+ for (var i = 0; i < Model.Objects.Count; i++)
+ {
+ var obj = Model.Objects[i];
+ var m_trans = obj.TransVect;
+
+
+ if (obj.RestoreID != -1)
+ Gl.glLoadMatrixf(MatrixStack[obj.RestoreID].Floats);
+ if (obj.StackID != -1)
+ {
+ if (obj.Trans)
+ Gl.glTranslatef(m_trans[0], m_trans[1], m_trans[2]);
+
+
+ Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, MatrixStack[obj.StackID].Floats);
+ stackID = obj.StackID; // save the last stackID
+ }
+ }
+ Gl.glLoadIdentity();
+ ////////////////////////////////////////////////////////////
+ // display one polygon of the current model at a time
+ //Todo
+
+ ////////////////////////////////////////////////////////////
+ // display all polygons of the current model
+ for (var i = 0; i < Model.Polygons.Count - 1; i++)
+ {
+ var poly = Model.Polygons[i];
+
+ if (gOptTexture && !gOptWireFrame && g_mat)
+ {
+ int matid = poly.MatId;
+ if (matid == -1)
+ {
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+ if (writevertex)
+ {
+ mattt.Add(new ImageBrush());
+ }
+ }
+ else
+ {
+ if (writevertex)
+ {
+ mattt.Add(matt[matid]);
+ }
+ NSBMDMaterial mat = Model.Materials[matid];
+ if ((mat.format == 1 || mat.format == 6) && r == RenderMode.Translucent) continue;
+ if ((mat.format == 0 || mat.format == 2 || mat.format == 3 || mat.format == 4 || mat.format == 5 || mat.format == 7) && r != RenderMode.Opaque) continue;
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, matid + 1 + matstart);
+
+ // Convert pixel coords to normalised STs
+ Gl.glMatrixMode(Gl.GL_TEXTURE);
+ Gl.glLoadIdentity();
+ if (p.Header.file_size != 0 && new List(p.MPT.names).Contains(mat.MaterialName))
+ {
+ NSBMDMaterial mmm = mat;
+ int texid = 0;
+ for (int l = 0; l < nsb.Textures.Count; l++)
+ {
+ if (nsb.Textures[l].texname == p.AnimData[new List(p.MPT.names).IndexOf(mat.MaterialName)].KeyFrames[frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)]].texName) { texid = l; break; }
+ }
+ mmm.spdata = nsb.Textures[texid].spdata;
+ mmm.texdata = nsb.Textures[texid].texdata;
+ mmm.texname = nsb.Textures[texid].texname;
+ mmm.texoffset = nsb.Textures[texid].texoffset;
+ mmm.texsize = nsb.Textures[texid].texsize;
+ mmm.width = nsb.Textures[texid].width;
+ mmm.height = nsb.Textures[texid].height;
+ mmm.format = nsb.Textures[texid].format;
+ mmm.color0 = nsb.Textures[texid].color0;
+
+ int palid = 0;
+ for (int l = 0; l < nsb.Textures.Count; l++)
+ {
+ if (nsb.Palettes[l].palname == p.AnimData[new List(p.MPT.names).IndexOf(mat.MaterialName)].KeyFrames[frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)]].palName) { palid = l; break; }
+ }
+ mmm.paldata = nsb.Palettes[palid].paldata;
+ mmm.palname = nsb.Palettes[palid].palname;
+ mmm.paloffset = nsb.Palettes[palid].paloffset;
+ mmm.palsize = nsb.Palettes[palid].palsize;
+ MakeTexture(matid, mmm);
+ if (anim2)
+ {
+ if (nr[new List(p.MPT.names).IndexOf(mat.MaterialName)] == Math.Round((float)(p.MPT.infoBlock.Data[new List(p.MPT.names).IndexOf(mat.MaterialName)].Unknown1) / 512f))
+ {
+ nr[new List(p.MPT.names).IndexOf(mat.MaterialName)] = 0;
+ if (frame[new List(p.MPT.names).IndexOf(mat.MaterialName)] == p.MPT.NoFrames - 1)
+ {
+ frame[new List(p.MPT.names).IndexOf(mat.MaterialName)] = 0;
+ frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)] = 0;
+ }
+ else
+ {
+ frame[new List(p.MPT.names).IndexOf(mat.MaterialName)]++;
+ if (p.AnimData[new List(p.MPT.names).IndexOf(mat.MaterialName)].KeyFrames.Length != frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)] + 1)
+ {
+ if (frame[new List(p.MPT.names).IndexOf(mat.MaterialName)] == p.AnimData[new List(p.MPT.names).IndexOf(mat.MaterialName)].KeyFrames[frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)] + 1].Start)
+ {
+ frame_[new List(p.MPT.names).IndexOf(mat.MaterialName)]++;
+ }
+ }
+ }
+ }
+ else
+ {
+ nr[new List(p.MPT.names).IndexOf(mat.MaterialName)]++;//= (float)p.MPT.infoBlock.Data[new List(p.MPT.names).IndexOf(mat.MaterialName)].Unknown1 / 4096f;
+ }
+ }
+ }
+ try
+ {
+ if (ani.Header.file_size != 0 && new List(ani.MAT.names).Contains(mat.MaterialName))
+ {
+ int index = new List(ani.MAT.names).IndexOf(mat.MaterialName);
+ Gl.glScaled((double)ani.SRTData[index].scaleS[aniframeScaleS[index]], (double)ani.SRTData[index].scaleT[aniframeScaleT[index]], 1);
+ Gl.glRotated((double)ani.SRTData[index].rotate[aniframeR[index]], 1, 0, 0);
+ Gl.glTranslated((double)ani.SRTData[index].translateS[aniframeS[index]], (double)ani.SRTData[index].translateT[aniframeT[index]], 0);
+ if (anim2)
+ {
+ if (aniframeS[index] == ani.SRTData[index].translateS.Length - 1)
+ {
+ aniframeS[index] = 0;
+ }
+ else
+ {
+ aniframeS[index]++;
+ }
+ if (aniframeT[index] == ani.SRTData[index].translateT.Length - 1)
+ {
+ aniframeT[index] = 0;
+ }
+ else
+ {
+ aniframeT[index]++;
+ }
+ if (aniframeR[index] == (ani.SRTData[index].rotate.Length - 2) / 2)
+ {
+ aniframeR[index] = 0;
+ }
+ else
+ {
+ aniframeR[index]++;
+ }
+ if (aniframeScaleS[index] == ani.SRTData[index].scaleS.Length - 1)
+ {
+ aniframeScaleS[index] = 0;
+ }
+ else
+ {
+ aniframeScaleS[index]++;
+ }
+ if (aniframeScaleT[index] == ani.SRTData[index].scaleT.Length - 1)
+ {
+ aniframeScaleT[index] = 0;
+ }
+ else
+ {
+ aniframeScaleT[index]++;
+ }
+ }
+ goto noscale;
+ }
+ else
+ {
+ goto scale;
+ }
+ }
+ catch
+ {
+
+ }
+ noscale:
+ if (!mat.isEnvironmentMap)
+ {
+ Gl.glScalef(1.0f / ((float)mat.width), 1.0f / ((float)mat.height), 1.0f);
+ }
+ goto end;
+ scale:
+ if (!mat.isEnvironmentMap)
+ {
+ if (mat.mtx == null)
+ {
+ Gl.glScalef((float)mat.scaleS / (mat.width), (mat.scaleT / mat.height), 1.0f);
+ Gl.glRotatef(mat.rot, 0, 1, 0);
+ Gl.glTranslatef(mat.transS, mat.transT, 0);
+ }
+ else
+ {
+ Gl.glScalef(1.0f / ((float)mat.width), 1.0f / ((float)mat.height), 1.0f);
+ Gl.glMultMatrixf(mat.mtx);
+ }
+ }
+ end:
+
+ Gl.glEnable(Gl.GL_ALPHA_TEST);
+ Gl.glAlphaFunc(Gl.GL_GREATER, 0f);
+ Gl.glColor4f(0xff, 0xff, 0xff, 0xff);
+
+ if (licht && (((mat.PolyAttrib >> 0) & 0x1) == 0 && ((mat.PolyAttrib >> 1) & 0x1) == 0 && ((mat.PolyAttrib >> 2) & 0x1) == 0 && ((mat.PolyAttrib >> 3) & 0x1) == 0) == false)
+ {
+ //Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, new float[] { (float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, new float[] { (float)mat.AmbientColor.R / 255f, (float)mat.AmbientColor.G / 255f, (float)mat.AmbientColor.B / 255f, (float)mat.AmbientColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, new float[] { (float)mat.SpecularColor.R / 255f, (float)mat.SpecularColor.G / 255f, (float)mat.SpecularColor.B / 255f, (float)mat.SpecularColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_EMISSION, new float[] { (float)mat.EmissionColor.R / 255f, (float)mat.EmissionColor.G / 255f, (float)mat.EmissionColor.B / 255f, (float)mat.EmissionColor.A / 255f });
+ //Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, new float[] { 1, 1, 1, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, new float[] { (float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, new float[] { (float)mat.AmbientColor.R / 255f, (float)mat.AmbientColor.G / 255f, (float)mat.AmbientColor.B / 255f, (float)mat.AmbientColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, new float[] { (float)mat.SpecularColor.R / 255f, (float)mat.SpecularColor.G / 255f, (float)mat.SpecularColor.B / 255f, (float)mat.SpecularColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_EMISSION, new float[] { (float)mat.EmissionColor.R / 255f, (float)mat.EmissionColor.G / 255f, (float)mat.EmissionColor.B / 255f, (float)mat.EmissionColor.A / 255f });
+ //Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_POSITION, new float[] { 1.0f, 1.0f, 1.0f, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_DIFFUSE, new float[] { (float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_AMBIENT, new float[] { (float)mat.AmbientColor.R / 255f, (float)mat.AmbientColor.G / 255f, (float)mat.AmbientColor.B / 255f, (float)mat.AmbientColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_SPECULAR, new float[] { (float)mat.SpecularColor.R / 255f, (float)mat.SpecularColor.G / 255f, (float)mat.SpecularColor.B / 255f, (float)mat.SpecularColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_EMISSION, new float[] { (float)mat.EmissionColor.R / 255f, (float)mat.EmissionColor.G / 255f, (float)mat.EmissionColor.B / 255f, (float)mat.EmissionColor.A / 255f });
+ //Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_POSITION, new float[] { 1.0f, 1.0f, 1.0f, 0 });
+ Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_DIFFUSE, new float[] { (float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_AMBIENT, new float[] { (float)mat.AmbientColor.R / 255f, (float)mat.AmbientColor.G / 255f, (float)mat.AmbientColor.B / 255f, (float)mat.AmbientColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_SPECULAR, new float[] { (float)mat.SpecularColor.R / 255f, (float)mat.SpecularColor.G / 255f, (float)mat.SpecularColor.B / 255f, (float)mat.SpecularColor.A / 255f });
+ Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_EMISSION, new float[] { (float)mat.EmissionColor.R / 255f, (float)mat.EmissionColor.G / 255f, (float)mat.EmissionColor.B / 255f, (float)mat.EmissionColor.A / 255f });
+
+ Gl.glEnable(Gl.GL_LIGHTING);
+ if (((mat.PolyAttrib >> 0) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT0);
+ else Gl.glDisable(Gl.GL_LIGHT0);
+ if (((mat.PolyAttrib >> 1) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT1);
+ else Gl.glDisable(Gl.GL_LIGHT1);
+ if (((mat.PolyAttrib >> 2) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT2);
+ else Gl.glDisable(Gl.GL_LIGHT2);
+ if (((mat.PolyAttrib >> 3) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT3);
+ else Gl.glDisable(Gl.GL_LIGHT3);
+
+ if (mat.diffuseColor)
+ {
+ Gl.glColor4f((float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f);
+ }
+
+ }
+ else
+ {
+ Gl.glDisable(Gl.GL_LIGHTING);
+ Gl.glDisable(Gl.GL_LIGHT0);
+ Gl.glDisable(Gl.GL_LIGHT1);
+ Gl.glDisable(Gl.GL_LIGHT2);
+ Gl.glDisable(Gl.GL_LIGHT3);
+ if (mat.diffuseColor)
+ {
+ Gl.glColor4f((float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f);
+ }
+
+ }
+ Gl.glEnable(Gl.GL_BLEND);
+ if (mat.isEnvironmentMap)
+ {
+ Gl.glTexGeni(Gl.GL_S, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
+ Gl.glTexGeni(Gl.GL_T, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
+ Gl.glEnable(Gl.GL_TEXTURE_GEN_S);
+ Gl.glEnable(Gl.GL_TEXTURE_GEN_T);
+
+ }
+ else
+ {
+ Gl.glDisable(Gl.GL_TEXTURE_GEN_S);
+ Gl.glDisable(Gl.GL_TEXTURE_GEN_T);
+ Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ int mode = -1;
+ switch ((mat.PolyAttrib >> 4) & 0x3)
+ {
+ case 0:
+ mode = Gl.GL_MODULATE;
+ break;
+ case 1:
+ mode = Gl.GL_DECAL;
+ break;
+ case 2:
+ mode = Gl.GL_MODULATE;
+ break;
+ case 3:
+ mode = Gl.GL_MODULATE;
+ break;
+ }
+ Gl.glTexEnvi(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, mode);
+ int cullmode = -1;
+
+ switch (mat.PolyAttrib >> 6 & 0x03)
+ {
+ case 0x03: cullmode = Gl.GL_NONE; break;
+ case 0x02: cullmode = Gl.GL_BACK; break;
+ case 0x01: cullmode = Gl.GL_FRONT; break;
+ case 0x00: cullmode = Gl.GL_FRONT_AND_BACK; break;
+ }
+ Gl.glCullFace(cullmode);
+ }
+
+ }
+ else
+ {
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+ }
+
+ if (!gOptColoring)
+ {
+ Gl.glColor3f(1, 1, 1);
+ }
+ stackID = poly.StackID; // the first matrix used by this polygon
+ Process3DCommand(poly.PolyData, Model.Materials[poly.MatId], poly.JointID, true);
+
+ }
+ writevertex = false;
+ }
+ ///
+ /// Render model to OpenGL surface.
+ ///
+ public void RenderModel(float elev, float ang)
+ {
+ MTX44 tmp = new MTX44();
+ for (var j = 0; j < Model.Polygons.Count - 1; j++)
+ {
+ var poly = Model.Polygons[j];
+ int matid = poly.MatId;
+ var mat = Model.Materials[matid];
+ }
+
+ Gl.glLineWidth(2.0F);
+ float xmin = Model.boundXmin;
+ float ymin = Model.boundYmin;
+ float zmin = Model.boundZmin;
+ float xmax = Model.boundXmax + Model.boundXmin;
+ float ymax = Model.boundYmax + Model.boundYmin;
+ float zmax = -Model.boundZmax + Model.boundZmin;
+
+ Gl.glLineWidth(1.0F);
+
+ ////////////////////////////////////////////////////////////
+ // prepare the matrix stack
+ for (var i = 0; i < Model.Objects.Count; i++)
+ {
+ var obj = Model.Objects[i];
+ var m_trans = obj.TransVect;
+ float[] f = loadIdentity();
+ if (obj.RestoreID != -1)
+ {
+ Gl.glLoadMatrixf(MatrixStack[obj.RestoreID].Floats);
+ }
+ if (obj.StackID != -1)
+ {
+
+ Gl.glMultMatrixf(obj.materix);
+ if (obj.isBillboard)
+ {
+ if (!obj.isYBillboard)
+ {
+ Gl.glRotatef(elev, 1, 0, 0);
+ }
+ Gl.glRotatef(-ang, 0, 1, 0);
+ }
+ Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, MatrixStack[obj.StackID].Floats);
+ stackID = obj.StackID; // save the last stackID
+ }
+ else
+ {
+
+ }
+ if (obj.visible)
+ {
+ //light = Gl.glIsEnabled(Gl.GL_LIGHTING);
+ //Gl.glDisable(Gl.GL_LIGHTING);
+ //drawJoint(0.1f);
+ //if (light == 1)
+ //{
+ // Gl.glEnable(Gl.GL_LIGHTING);
+ //}
+ }
+
+ }
+ Gl.glLoadIdentity();
+
+ Gl.glLoadIdentity();
+
+ // display all polygons of the current model
+ for (var i = 0; i < Model.Polygons.Count - 1; i++)
+ {
+ var poly = Model.Polygons[i];
+
+ if (gOptTexture && !gOptWireFrame && g_mat)
+ {
+ int matid = poly.MatId;
+ if (matid == -1)
+ {
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+ if (writevertex)
+ {
+ mattt.Add(new ImageBrush());
+ }
+ }
+ else
+ {
+ if (writevertex)
+ {
+ mattt.Add(matt[matid]);
+ }
+ var mat = Model.Materials[matid];
+
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+
+ // Convert pixel coords to normalised STs
+ Gl.glMatrixMode(Gl.GL_TEXTURE);
+ Gl.glLoadIdentity();
+
+ scale:
+ if (!mat.isEnvironmentMap)
+ {
+ Gl.glScalef((float)mat.scaleS / ((float)mat.width), (float)mat.scaleT / ((float)mat.height), 1.0f);
+ }
+ end:
+ //Gl.glColor4f(1, 1, 0, 0);
+ Gl.glEnable(Gl.GL_ALPHA_TEST);
+ Gl.glAlphaFunc(Gl.GL_GREATER, 0f);
+
+ if (((mat.PolyAttrib >> 0xf) & 0x1) == 1 && (((mat.PolyAttrib >> 0) & 0x1) == 0 && ((mat.PolyAttrib >> 1) & 0x1) == 0 && ((mat.PolyAttrib >> 2) & 0x1) == 0 && ((mat.PolyAttrib >> 2) & 0x1) == 0) == false)
+ {
+ Gl.glEnable(Gl.GL_LIGHTING);
+ if (((mat.PolyAttrib >> 0) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT0);
+ else Gl.glDisable(Gl.GL_LIGHT0);
+ if (((mat.PolyAttrib >> 1) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT1);
+ else Gl.glDisable(Gl.GL_LIGHT1);
+ if (((mat.PolyAttrib >> 2) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT2);
+ else Gl.glDisable(Gl.GL_LIGHT2);
+ if (((mat.PolyAttrib >> 3) & 0x1) == 1) Gl.glEnable(Gl.GL_LIGHT3);
+ else Gl.glDisable(Gl.GL_LIGHT3);
+
+ Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_DIFFUSE);
+ Gl.glColor4f((float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f);
+ Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_AMBIENT);
+ Gl.glColor4f((float)mat.AmbientColor.R / 255f, (float)mat.AmbientColor.G / 255f, (float)mat.AmbientColor.B / 255f, (float)mat.AmbientColor.A / 255f);
+ Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_SPECULAR);
+ Gl.glColor4f((float)mat.SpecularColor.R / 255f, (float)mat.SpecularColor.G / 255f, (float)mat.SpecularColor.B / 255f, (float)mat.SpecularColor.A / 255f);
+ Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION);
+ Gl.glColor4f((float)mat.EmissionColor.R / 255f, (float)mat.EmissionColor.G / 255f, (float)mat.EmissionColor.B / 255f, (float)mat.EmissionColor.A / 255f);
+
+
+ Gl.glEnable(Gl.GL_COLOR_MATERIAL);
+ }
+ else
+ {
+ Gl.glDisable(Gl.GL_LIGHTING);
+ Gl.glColorMaterial(Gl.GL_FRONT_AND_BACK, Gl.GL_DIFFUSE);
+ Gl.glColor4f((float)mat.DiffuseColor.R / 255f, (float)mat.DiffuseColor.G / 255f, (float)mat.DiffuseColor.B / 255f, (float)mat.DiffuseColor.A / 255f);
+ Gl.glEnable(Gl.GL_COLOR_MATERIAL);
+ }
+ Gl.glEnable(Gl.GL_BLEND);
+ if (mat.isEnvironmentMap)
+ {
+ Gl.glTexGeni(Gl.GL_S, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
+ Gl.glTexGeni(Gl.GL_T, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
+ Gl.glEnable(Gl.GL_TEXTURE_GEN_S);
+ Gl.glEnable(Gl.GL_TEXTURE_GEN_T);
+ //Gl.glBlendFunc(Gl.GL_ONE, Gl.GL_ONE);
+ }
+ else
+ {
+ Gl.glDisable(Gl.GL_TEXTURE_GEN_S);
+ Gl.glDisable(Gl.GL_TEXTURE_GEN_T);
+ Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ int mode = -1;
+ switch ((mat.PolyAttrib >> 4) & 0x3)
+ {
+ case 0:
+ mode = Gl.GL_MODULATE;
+ break;
+ case 1:
+ mode = Gl.GL_DECAL;
+ break;
+ case 2:
+ mode = Gl.GL_MODULATE;
+ break;
+ case 3:
+ mode = Gl.GL_MODULATE;
+ break;
+ }
+ Gl.glTexEnvi(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, mode);
+ int cullmode = -1;
+ //Gl.glEnable(Gl.GL_CULL_FACE);
+ switch (mat.PolyAttrib >> 6 & 0x03)
+ {
+ case 0x03: cullmode = Gl.GL_NONE; break;
+ case 0x02: cullmode = Gl.GL_BACK; break;
+ case 0x01: cullmode = Gl.GL_FRONT; break;
+ case 0x00: cullmode = Gl.GL_FRONT_AND_BACK; break;
+ }
+ Gl.glCullFace(cullmode);
+ }
+
+ }
+ else
+ {
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
+ }
+
+ if (!gOptColoring)
+ {
+ //Gl.glColor3f(1, 1, 1);
+ }
+ stackID = poly.StackID; // the first matrix used by this polygon
+ Process3DCommand(poly.PolyData, Model.Materials[poly.MatId], poly.JointID, false);
+ }
+ writevertex = false;
+ }
+ public bool doJointAnimation(MKDS_Course_Editor.NSBCA.NSBCA.NSBCA_File ca, int selectedanim, bool anim, int i)
+ {
+ try
+ {
+ if (ca.Header.file_size != 0 && selectedanim != -1)
+ {
+ float[] s = loadIdentity();
+ float[] r = loadIdentity();
+ float[] t = loadIdentity();
+ //float[] mt = loadIdentity();
+ //scale
+ float scalex = float.NaN;
+ float scaley = float.NaN;
+ float scalez = float.NaN;
+ if (ca.JAC[selectedanim].ObjInfo[i].scale[0][0].Count != 0)
+ {
+ scalex = ca.JAC[selectedanim].ObjInfo[i].scale[0][0][0];// + ca.JAC[selectedanim].ObjInfo[i].scale[0][1][0]) / 2;// - ca.JAC[selectedanim].ObjInfo[i].scale[0][1][S2x[i]];//ca.JAC[selectedanim].ObjInfo[i].scale[0][0][S2x[i]];
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0].Count != 0)
+ {
+ scalex = ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0][Sx[i]];// -ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][1][Sx[i]];
+ }
+ if (ca.JAC[selectedanim].ObjInfo[i].scale[1][0].Count != 0)
+ {
+ scaley = ca.JAC[selectedanim].ObjInfo[i].scale[1][0][0];// + ca.JAC[selectedanim].ObjInfo[i].scale[1][1][0]) / 2;// -ca.JAC[selectedanim].ObjInfo[i].scale[1][1][S2y[i]];//ca.JAC[selectedanim].ObjInfo[i].scale[1][0][S2y[i]];
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][0].Count != 0)
+ {
+ scaley = ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][0][Sy[i]];// -ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][1][Sy[i]];
+ }
+ if (ca.JAC[selectedanim].ObjInfo[i].scale[2][0].Count != 0)
+ {
+ scalez = ca.JAC[selectedanim].ObjInfo[i].scale[2][0][0];// + ca.JAC[selectedanim].ObjInfo[i].scale[2][1][0]) / 2;// -ca.JAC[selectedanim].ObjInfo[i].scale[2][1][S2z[i]];//ca.JAC[selectedanim].ObjInfo[i].scale[2][0][S2z[i]];
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][0].Count != 0)
+ {
+ scalez = ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][0][Sz[i]];// -ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][1][Sz[i]];
+ }
+ if (!float.IsNaN(scalex) && !float.IsNaN(scaley) && !float.IsNaN(scalez))
+ {
+ s = scale(s, scalex, scaley, scalez);
+ }
+ else
+ {
+ //s = scale(s, Model.Objects[i].scale[0], Model.Objects[i].scale[1], Model.Objects[i].scale[2]);
+ }
+
+ /*if(ca.JAC[selectedanim].ObjInfo[i].scale[0][0].Count != 0)
+ {
+ //mt = scale(mt, ca.JAC[0].ObjInfo[i].scale[0][0][S2[i]], ca.JAC[0].ObjInfo[i].scale[0][1][S2[i]], ca.JAC[0].ObjInfo[i].scale[0][2][S2[i]]);
+ s = scale(s, ca.JAC[selectedanim].ObjInfo[i].scale[0][0][S2[i]], ca.JAC[selectedanim].ObjInfo[i].scale[1][0][S2[i]], ca.JAC[selectedanim].ObjInfo[i].scale[2][0][S2[i]]);
+ //Gl.glScalef(ca.JAC[selectedanim].ObjInfo[i].scale[0][0][S2[i]], ca.JAC[selectedanim].ObjInfo[i].scale[1][0][S2[i]], ca.JAC[selectedanim].ObjInfo[i].scale[2][0][S2[i]]);
+ }*/
+ try
+ {
+ if (ca.JAC[selectedanim].ObjInfo[i].rotate.Count != 0)
+ {
+ if ((((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) >> 15 & 0x1) == 1)
+ {
+ int pvneg = ca.JAC[selectedanim].JointData[(((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 6];//Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 6 + 0);
+ int a = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 6 + 2);
+ int b = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 6 + 4);
+ a = sign(a, 16);
+ b = sign(b, 16);
+ //mt = multMatrix(mt, Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ //Gl.glMultMatrixf(Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ r = NSBMD.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f));//multMatrix(r, Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ }
+ else
+ {
+ int x = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 10 + 2);
+ x = sign(x, 16);
+ int y = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 10 + 4);
+ y = sign(y, 16);
+ int z = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (((int)ca.JAC[selectedanim].ObjInfo[i].rotate[0]) & 0x7fff) * 10 + 6);
+ z = sign(z, 16);
+ OpenTK.Matrix4 X = OpenTK.Matrix4.CreateRotationX((float)x / 131072F);//((float)x * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 Y = OpenTK.Matrix4.CreateRotationY((float)y / 131072F);//((float)y * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 Z = OpenTK.Matrix4.CreateRotationZ((float)z / 131072F);//((float)z * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 full = OpenTK.Matrix4.Identity;
+ full = OpenTK.Matrix4.Mult(full, X);
+ full = OpenTK.Matrix4.Mult(full, Y);
+ full = OpenTK.Matrix4.Mult(full, Z);
+ }
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0].Count != 0)
+ {
+ //Gl.glMultMatrixf(Nsbmd.mtxPivot(new float[]{ca.JAC[0].ObjInfo[i].rotate_keyframes[1][R[i]],ca.JAC[0].ObjInfo[i].rotate_keyframes[0][R[i]]}, obj.Pivot, obj.Neg));
+ //Gl.glRotatef(ca.JAC[0].ObjInfo[i].rotate_keyframes[0][R[i]], 0,(ca.JAC[0].ObjInfo[i].rotate_keyframes[1][R[i]] == 1 ? 1 : 0),(ca.JAC[0].ObjInfo[i].rotate_keyframes[1][R[i]] == 0 ? 1 : 0));
+ if (ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[1][R[i]] == 1)
+ {
+ int pvneg = ca.JAC[selectedanim].JointData[(int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 6];//Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 6 + 0);
+ int a = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 6 + 2);
+ int b = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].JointData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 6 + 4);
+ a = sign(a, 16);
+ b = sign(b, 16);
+ //mt = multMatrix(mt, Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ //Gl.glMultMatrixf(Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ r = NSBMD.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f));//multMatrix(r, Nsbmd.mtxPivot(new float[] { (float)a / 4096f, (float)b / 4096f }, (pvneg >> 0 & 0x0f), (pvneg >> 4 & 0x0f)));
+ }
+ else
+ {
+ float param = ca.JAC[selectedanim].RotationData[(int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 10];
+ //float u = (float)Math.Pow(2.0f, param) * (float)180 / 131072F;
+ int x = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 10 + 2);
+ x = sign(x, 16);
+ int y = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 10 + 4);
+ y = sign(y, 16);
+ int z = Utils.Read2BytesAsInt16(ca.JAC[selectedanim].RotationData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 10 + 6);
+ z = sign(z, 16);
+ OpenTK.Matrix4 X = OpenTK.Matrix4.CreateRotationX((float)x / 131072F);//((float)x * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 Y = OpenTK.Matrix4.CreateRotationY((float)y / 131072F);//((float)y * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 Z = OpenTK.Matrix4.CreateRotationZ((float)z / 131072F);//((float)z * (float)Math.PI) / 32768F);
+ OpenTK.Matrix4 full = OpenTK.Matrix4.Identity;
+ full = OpenTK.Matrix4.Mult(full, X);
+ full = OpenTK.Matrix4.Mult(full, Y);
+ full = OpenTK.Matrix4.Mult(full, Z);
+ /*int x = (param) & 0xFF;
+ if ((x & 0x200) != 0) x |= -256;
+ int y = (param >> 8) & 0xFF;
+ if ((y & 0x200) != 0) y |= -256;
+ int z = (param >> 16) & 0xFF;
+ if ((z & 0x200) != 0) z |= -256;*/
+ //Gl.glRotatef((float)x / 32768F * 180F, 1, 0, 0);
+ //Gl.glRotatef((float)y / 32768F * 180F, 0, 1, 0);
+ //Gl.glRotatef((float)z / 32768F * 180F, 0, 0, 1);
+ //param /= 4096f;
+ //float un = 2048f;//(float)Utils.Read4BytesAsInt32(ca.JAC[selectedanim].RotationData, (int)ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0][R[i]] * 10 + 6) / 4096f;
+ //Gl.glRotatef(x / un, 1, 0, 0);//((float)x * (float)Math.PI) / 180f, 1, 0, 0);
+ //Gl.glRotatef(y / un, 0, 1, 0);//((float)y * (float)Math.PI) / 180f, 0, 1, 0);
+ //Gl.glRotatef(z / un, 0, 0, 1);//((float)z * (float)Math.PI) / 180f, 0, 0, 1);
+ //mt = rotate(mt, x, y, z);
+ //Gl.glMultMatrixf(full.ToFloat());
+ }
+ }
+ else
+ {
+ //r = multMatrix(r, Model.Objects[i].rotate_mtx);
+ }
+ }
+ catch (Exception e) { }
+
+ float transx = float.NaN;
+ float transy = float.NaN;
+ float transz = float.NaN;
+ if (ca.JAC[selectedanim].ObjInfo[i].translate[0].Count != 0)
+ {
+ transx = ca.JAC[selectedanim].ObjInfo[i].translate[0][0];// Model.modelScale;
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0].Count != 0)
+ {
+ transx = ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0][Tx[i]];// Model.modelScale;
+ }
+ if (ca.JAC[selectedanim].ObjInfo[i].translate[1].Count != 0)
+ {
+ transy = ca.JAC[selectedanim].ObjInfo[i].translate[1][0];// Model.modelScale;
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1].Count != 0)
+ {
+ transy = ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1][Ty[i]];// Model.modelScale;
+ }
+ if (ca.JAC[selectedanim].ObjInfo[i].translate[2].Count != 0)
+ {
+ transz = ca.JAC[selectedanim].ObjInfo[i].translate[2][0];// Model.modelScale;
+ }
+ else if (ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2].Count != 0)
+ {
+ transz = ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2][Tz[i]];// Model.modelScale;
+ }
+ if (!float.IsNaN(transx) && !float.IsNaN(transy) && !float.IsNaN(transz))
+ {
+ t = translate(t, transx / Model.modelScale/* - (Model.Objects[i].X)*/, transy / Model.modelScale/* - (Model.Objects[i].Y)*/, transz / Model.modelScale/* - (Model.Objects[i].Z)*/);
+ }
+ else
+ {
+ //t = translate(t, Model.Objects[i].X, Model.Objects[i].Y, Model.Objects[i].Z);
+ }
+
+
+
+ //if(ca.JAC[selectedanim].ObjInfo[i].translate[0].Count != 0)
+ //{
+ //mt = translate(mt, ca.JAC[0].ObjInfo[i].translate[0][T2[i]], ca.JAC[0].ObjInfo[i].translate_keyframes[1][T2[i]], ca.JAC[0].ObjInfo[i].translate_keyframes[2][T2[i]]);
+ //Gl.glTranslatef(ca.JAC[selectedanim].ObjInfo[i].translate[0][T2[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1][T2[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2][T2[i]] / Model.modelScale);
+ // t = translate(t,ca.JAC[selectedanim].ObjInfo[i].translate[0][T2[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1][T2[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2][T2[i]] / Model.modelScale);
+ //}
+ float[] m = loadIdentity();
+ //Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, m);
+ m = multMatrix(m, t);
+ //m = translate(m, Model.Objects[i].X, Model.Objects[i].Y, Model.Objects[i].Z);
+ //if (Model.Objects[i].IsRotated)
+ //{
+ //float[] rt = loadIdentity();
+ //rt = multMatrix(rt, r);
+ //rt = multMatrix(rt, Model.Objects[i].rotate_mtx);
+ m = multMatrix(m, r);
+ // m = multMatrix(m, Model.Objects[i].rotate_mtx);
+
+ //}
+ //else
+ //{
+ // m = multMatrix(m, r);
+ //}
+ m = multMatrix(m, s);
+ //m = scale(m, Model.Objects[i].scale[0], Model.Objects[i].scale[1], Model.Objects[i].scale[2]);
+ Gl.glMultMatrixf(m);
+ //s = loadIdentity();
+ //r = loadIdentity();
+ //t = loadIdentity();
+ //Gl.glMultMatrixf(mt);
+ //mt = loadIdentity();
+ //if(ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0].Count != 0)
+ // {
+ //mt = scale(mt, ca.JAC[0].ObjInfo[i].scale_keyframes[0][0][S[i]], ca.JAC[0].ObjInfo[i].scale_keyframes[0][1][S[i]], ca.JAC[0].ObjInfo[i].scale_keyframes[0][2][S[i]]);
+ //Gl.glScalef((ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][1][S[i]]), (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][1][S[i]]), (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][1][S[i]]));
+ //s = scale(s, (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][1][S[i]]), (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][1][S[i]]), (ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][0][S[i]] - ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][1][S[i]]));
+ //}
+
+ //if(ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0].Count != 0)
+ //{
+ //mt = translate(mt, ca.JAC[0].ObjInfo[i].translate_keyframes[0][T[i]], ca.JAC[0].ObjInfo[i].translate_keyframes[1][T[i]], ca.JAC[0].ObjInfo[i].translate_keyframes[2][T[i]]);
+ //Gl.glTranslatef(ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0][T[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1][T[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2][T[i]] / Model.modelScale);
+ // t = translate(t, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0][T[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1][T[i]] / Model.modelScale, ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2][T[i]] / Model.modelScale);
+ //}
+ // m = loadIdentity();
+ //m = multMatrix(m, t);
+ //m = multMatrix(m, r);
+ //m = multMatrix(m, s);
+ //Gl.glMultMatrixf(m);
+ if (anim)
+ {
+ if (Tx[i] == ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[0].Count - 1)
+ {
+ Tx[i] = 0;
+ }
+ else
+ {
+ Tx[i]++;
+ }
+ if (Ty[i] == ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[1].Count - 1)
+ {
+ Ty[i] = 0;
+ }
+ else
+ {
+ Ty[i]++;
+ }
+ if (Tz[i] == ca.JAC[selectedanim].ObjInfo[i].translate_keyframes[2].Count - 1)
+ {
+ Tz[i] = 0;
+ }
+ else
+ {
+ Tz[i]++;
+ }
+ if (R[i] == ca.JAC[selectedanim].ObjInfo[i].rotate_keyframes[0].Count - 1)
+ {
+ R[i] = 0;
+ }
+ else
+ {
+ R[i]++;
+ }
+ if (Sx[i] == ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[0][0].Count - 1)
+ {
+ Sx[i] = 0;
+ }
+ else
+ {
+ Sx[i]++;
+ }
+ if (Sy[i] == ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[1][0].Count - 1)
+ {
+ Sy[i] = 0;
+ }
+ else
+ {
+ Sy[i]++;
+ }
+ if (Sz[i] == ca.JAC[selectedanim].ObjInfo[i].scale_keyframes[2][0].Count - 1)
+ {
+ Sz[i] = 0;
+ }
+ else
+ {
+ Sz[i]++;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch { return true; }
+ }
+ public static float[] translate(float[] a, float x, float y, float z)
+ {
+ float[] b = loadIdentity();
+ b[12] = x;
+ b[13] = y;
+ b[14] = z;
+ return multMatrix(a, b);
+ }
+ public static float[] loadIdentity()
+ {
+ float[] a = new float[16];
+ a[0] = 1.0F;
+ a[5] = 1.0F;
+ a[10] = 1.0F;
+ a[15] = 1.0F;
+ return a;
+ }
+ public static float[] scale(float[] a, float x, float y, float z)
+ {
+ float[] b = loadIdentity();
+ b[0] = x;
+ b[5] = y;
+ b[10] = z;
+ return multMatrix(a, b);
+ }
+
+ private void setColor(int drawMode, float[] color)
+ {
+ /*bool checkJoint = true;
+ bool selJoint = true;
+ if(jointId < Frame.jointList.length)
+ {
+ checkJoint = Frame.jointList[jointId].isChecked();
+ selJoint = Frame.jointList[jointId].isSelected();
+ }
+ boolean checkStack = visible[stackId];
+ boolean checkPoly = Frame.polygonList[polyId].isChecked();
+ boolean checkMat = true;
+ boolean selMat = true;
+ if(matId < Frame.materialList.length)
+ {
+ checkMat = Frame.materialList[matId].isChecked();
+ selMat = Frame.materialList[matId].isSelected();
+ }
+ boolean selPoly = Frame.polygonList[polyId].isSelected();*/
+ switch (drawMode)
+ {
+ case 0: // '\0'
+ default:
+ break;
+
+ case 1: // '\001'
+ color = lineColorOff;
+ /*if(selPoly)
+ {
+ color = lineColorOn;
+ if(Frame.points)
+ color = lineColorEdit;
+ }*/
+ break;
+
+ case 2: // '\002'
+ color = pointColorOff;
+ /*if(selPoly)
+ color = pointColorOn;*/
+ break;
+
+ case 3: // '\003'
+ color = jointColor;
+ /*if(selJoint)
+ color = jointColorOn;*/
+ break;
+
+ case 4: // '\004'
+ color = linkColor;
+ /*if(selJoint)
+ color = linkColorOn;*/
+ break;
+ }
+ float alpha = color[3];
+ //if(drawMode == 0 && !checkPoly || (drawMode == 3 || drawMode == 4) && !checkJoint)
+ // alpha = 0.2F;
+ //if(drawMode == 0 && !checkStack)
+ // alpha = 0.0F;
+ Gl.glColor4f(color[0], color[1], color[2], alpha);
+ }
+
+ private float[] baseColor = {
+ 1.0F, 1.0F, 1.0F, 1.0F
+ };
+ private float[] shadeColor = {
+ 0.3F, 0.3F, 0.3F, 1.0F
+ };
+ private float[] selColor = {
+ 1.0F, 0.0F, 0.0F, 1.0F
+ };
+ private float[] lineColorOff = {
+ 0.0F, 0.02745098F, 0.5686275F, 1.0F
+ };
+ private float[] lineColorOn = {
+ 0.2627451F, 1.0F, 0.6392157F, 1.0F
+ };
+ private float[] lineColorEdit = {
+ 0.3921569F, 0.8627451F, 1.0F, 1.0F
+ };
+ private float[] pointColorOff = {
+ 0.3921569F, 0.1960784F, 0.4313726F, 1.0F
+ };
+ private float[] pointColorOn = {
+ 0.7843137F, 0.0F, 0.7843137F, 1.0F
+ };
+ private float[] pointColorEdit = {
+ 0.7843137F, 0.0F, 0.7843137F, 1.0F
+ };
+ private float[] jointColor = {
+ 0.0F, 0.4F, 0.0F, 1.0F
+ };
+ private float[] jointColorOn = {
+ 0.4F, 0.0F, 0.0F, 1.0F
+ };
+ private float[] linkColor = {
+ 0.0F, 0.0F, 0.8F, 0.8F
+ };
+ private float[] linkColorOn = {
+ 0.8F, 0.0F, 0.0F, 0.8F
+ };
+ public static float[] multMatrix(float[] a, float[] b)
+ {
+ float[] c = new float[16];
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ c[(i << 2) + j] = 0.0F;
+ for (int k = 0; k < 4; k++)
+ c[(i << 2) + j] += a[(k << 2) + j] * b[(i << 2) + k];
+
+ }
+
+ }
+
+ return c;
+ }
+ public static float[] loadMatrix(float[] fmatrix, int stack)
+ {
+ float[] a = new float[16];
+ a[0] = 1.0F;
+ a[5] = 1.0F;
+ a[10] = 1.0F;
+ a[15] = 1.0F;
+ for (int i = 0; i < a.Length; i++)
+ a[i] = fmatrix[stack * 16 + i];
+
+ return a;
+ }
+
+ public float[] pullVector(float[] fmatrix, int offset)
+ {
+ float[] cmatrix = new float[16];
+ for (int i = 0; i < cmatrix.Length; i++)
+ cmatrix[i] = fmatrix[offset + i];
+
+ return multVector(cmatrix, new float[] {
+ 0.0F, 0.0F, 0.0F
+ });
+ }
+
+ public float[] multVector(float[] cmatrix, float[] vtxState)
+ {
+ float[] vtxTrans = new float[3];
+ for (int i = 0; i < 3; i++)
+ {
+ float c0 = vtxState[0] * cmatrix[0 + i];
+ float c1 = vtxState[1] * cmatrix[4 + i];
+ float c2 = vtxState[2] * cmatrix[8 + i];
+ float c3 = cmatrix[12 + i];
+ vtxTrans[i] = c0 + c1 + c2 + c3;
+ }
+
+ return vtxTrans;
+ }
+
+ //PrivateMethods(7)
+
+ ///
+ /// Convert texel.
+ ///
+ private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, RGBA[] pal, RGBA[] rgbaOut)
+ {
+ int w = width / 4;
+ int h = height / 4;
+
+ // traverse 'w x h blocks' of 4x4-texel
+ for (int y = 0; y < h; y++)
+ for (int x = 0; x < w; x++)
+ {
+ int index = y * w + x;
+ UInt32 t = tex[index];
+ UInt16 d = data[index];
+ UInt16 addr = (ushort)(d & 0x3fff);
+ UInt16 mode = (ushort)((d >> 14) & 3);
+
+ // traverse every texel in the 4x4 texels
+ for (int r = 0; r < 4; r++)
+ for (int c = 0; c < 4; c++)
+ {
+ int texel = (int)((t >> ((r * 4 + c) * 2)) & 3);
+ RGBA pixel = rgbaOut[(y * 4 + r) * width + (x * 4 + c)];
+
+ switch (mode)
+ {
+ case 0:
+ pixel = pal[(addr << 1) + texel];
+ if (texel == 3) pixel = RGBA.Transparent; // make it transparent, alpha = 0
+ break;
+ case 2:
+ pixel = pal[(addr << 1) + texel];
+ break;
+ case 1:
+ switch (texel)
+ {
+ case 0:
+ case 1:
+ pixel = pal[(addr << 1) + texel];
+ break;
+ case 2:
+ pixel.R = (byte)((pal[(addr << 1)].R + pal[(addr << 1) + 1].R) / 2L);
+ pixel.G = (byte)((pal[(addr << 1)].G + pal[(addr << 1) + 1].G) / 2L);
+ pixel.B = (byte)((pal[(addr << 1)].B + pal[(addr << 1) + 1].B) / 2L);
+ pixel.A = 0xff;
+ break;
+ case 3:
+ pixel = RGBA.Transparent; // make it transparent, alpha = 0
+ break;
+ }
+ break;
+ case 3:
+ switch (texel)
+ {
+ case 0:
+ case 1:
+ pixel = pal[(addr << 1) + texel];
+ break;
+ case 2:
+ pixel.R = (byte)((pal[(addr << 1)].R * 5L + pal[(addr << 1) + 1].R * 3L) / 8);
+ pixel.G = (byte)((pal[(addr << 1)].G * 5L + pal[(addr << 1) + 1].G * 3L) / 8);
+ pixel.B = (byte)((pal[(addr << 1)].B * 5L + pal[(addr << 1) + 1].B * 3L) / 8);
+ pixel.A = 0xff;
+ break;
+ case 3:
+ pixel.R = (byte)((pal[(addr << 1)].R * 3L + pal[(addr << 1) + 1].R * 5L) / 8);
+ pixel.G = (byte)((pal[(addr << 1)].G * 3L + pal[(addr << 1) + 1].G * 5L) / 8);
+ pixel.B = (byte)((pal[(addr << 1)].B * 3L + pal[(addr << 1) + 1].B * 5L) / 8);
+ pixel.A = 0xff;
+ break;
+ }
+ break;
+ }
+ rgbaOut[(y * 4 + r) * width + (x * 4 + c)] = pixel;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Convert texel (wrapper for type safety issues).
+ ///
+ private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, RGBA[] pal, RGBA[] rgbaOut)
+ {
+ var list1 = new List();
+ for (int i = 0; i < (tex.Length + 1) / 4; ++i)
+ list1.Add(Utils.Read4BytesAsUInt32(tex, i * 4));
+
+ var list2 = new List();
+ for (int i = 0; i < (data.Length + 1) / 2; ++i)
+ list2.Add(Utils.Read2BytesAsUInt16(data, i * 2));
+ var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
+ }
+
+
+ ///
+ /// Make texture for model.
+ ///
+ /// NSBMD Model
+ private void MakeTexture(NSBMDModel mod)
+ {
+ Gl.glMatrixMode(Gl.GL_TEXTURE_MATRIX);
+ Gl.glLoadIdentity();
+
+
+ Console.WriteLine("DEBUG: making texture for model '{0}'...", mod.Name);
+
+ for (int i = 0; i < mod.Materials.Count - 1; i++)
+ {
+ try
+ {
+ if (mod.Materials[i].format == 0) // format 0 is no texture
+ {
+ matt.Add(new ImageBrush());
+ continue;
+ }
+ var mat = mod.Materials[i];
+ if (mat == null || (mat.paldata == null && mat.format != 7))
+ {
+ matt.Add(new ImageBrush());
+ continue;
+ }
+ int pixelnum = mat.width * mat.height;
+
+ var image = new RGBA[pixelnum];
+
+
+ switch (mat.format)
+ {
+ // No Texture
+ case 0:
+ //puts( "ERROR: format 0" );
+ mattt.Add(new ImageBrush());
+ continue;
+ // A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)
+ case 1:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ int index = mat.texdata[j] & 0x1f;
+ int alpha = (mat.texdata[j] >> 5);// & 7;
+ alpha = ((alpha * 4) + (alpha / 2)) * 8;// << 3;
+ image[j] = mat.paldata[index];
+ image[j].A = (byte)alpha;
+ }
+
+ break;
+ // 4-Color Palette Texture
+ case 2:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ uint index = mat.texdata[j / 4];
+ index = (index >> ((j % 4) << 1)) & 3;
+ image[j] = mat.paldata[index];
+ }
+ break;
+ // 16-Color Palette Texture
+ case 3:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ var matindex = j / 2;
+ if (mat.texdata.Length < matindex)
+ continue;
+ int index = mat.texdata[matindex];
+ index = (index >> ((j % 2) << 2)) & 0x0f;
+ if (mat.paldata == null)
+ continue;
+ if (index < 0 || index >= mat.paldata.Length)
+ continue;
+ if (j < 0 || j >= pixelnum)
+ continue;
+ image[j] = mat.paldata[index];
+ }
+ break;
+ // 256-Color Palette Texture
+ case 4:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ image[j] = mat.paldata[mat.texdata[j]];
+ }
+ break;
+ // 4x4-Texel Compressed Texture
+ case 5:
+ convert_4x4texel_b(mat.texdata, mat.width, mat.height, mat.spdata, mat.paldata, image);
+ break;
+ // A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)
+ case 6:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ int index = mat.texdata[j] & 0x7;
+ int alpha = (mat.texdata[j] >> 3);
+ alpha *= 8; //((alpha * 4) + (alpha / 2)) << 3;
+ image[j] = mat.paldata[index];
+ image[j].A = (byte)alpha;
+ }
+ break;
+ // Direct Color Texture
+ case 7:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ //UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
+ //image[j].R = (byte)(((p >> 0) & 0x1f) << 3);
+ //image[j].G = (byte)(((p >> 5) & 0x1f) << 3);
+ //image[j].B = (byte)(((p >> 10) & 0x1f) << 3);
+ //image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
+ image[j] = RGBA.fromColor(Tinke.Convertir.BGR555(mat.texdata[j * 2], mat.texdata[j * 2 + 1]));
+ UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
+ image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
+ }
+ break;
+ }
+
+ Console.WriteLine("convert matid = {0}", i);
+ Console.WriteLine("\ttex '{0}': {1} [{2},{3}] texsize = {4}", mat.texname, TEXTURE_FORMATS[mat.format], mat.width,
+ mat.height, mat.texsize);
+ Console.WriteLine("\tpal '{0}': pixelnum = {1}, repeat = {2}", mat.palname, pixelnum, mat.repeat);
+
+ var imageBytesList = new List();
+ System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(mat.width, mat.height);
+ for (int k = 0; k < image.Length; ++k)
+ {
+ bitmap.SetPixel(k - ((k / (mat.width)) * (mat.width)), k / (mat.width), image[k].ToColor());
+ imageBytesList.Add(image[k].R);
+ imageBytesList.Add(image[k].G);
+ imageBytesList.Add(image[k].B);
+ imageBytesList.Add((image[k].A));
+
+ }
+ var imageBytes = imageBytesList.ToArray();
+ if (mat.flipS == 1 && mat.flipT == 1)
+ {
+ System.Drawing.Bitmap bitmap2 = new System.Drawing.Bitmap(mat.width * 2, mat.height * 2);
+ using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap2))
+ {
+ g.DrawImage(bitmap, 0, 0);
+ System.Drawing.Bitmap tmp = bitmap;
+ tmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX);
+ g.DrawImage(tmp, mat.width, 0);
+ tmp = bitmap;
+ tmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
+ g.DrawImage(tmp, mat.width, mat.height);
+ tmp = bitmap;
+ tmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX);
+ g.DrawImage(tmp, 0, mat.height);
+ }
+ bitmap = bitmap2;
+ }
+ else if (mat.flipS == 1)
+ {
+ //br.TileMode = System.Windows.Media.TileMode.FlipX;
+ System.Drawing.Bitmap bitmap2 = new System.Drawing.Bitmap(mat.width * 2, mat.height);
+ using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap2))
+ {
+ g.DrawImage(bitmap, 0, 0);
+ System.Drawing.Bitmap tmp = bitmap;
+ tmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX);
+ g.DrawImage(tmp, mat.width, 0);
+ }
+ bitmap = bitmap2;
+ }
+ else if (mat.flipT == 1)
+ {
+ //br.TileMode = System.Windows.Media.TileMode.FlipY;
+ System.Drawing.Bitmap bitmap2 = new System.Drawing.Bitmap(mat.width, mat.height * 2);
+ using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap2))
+ {
+ g.DrawImage(bitmap, 0, 0);
+ System.Drawing.Bitmap tmp = bitmap;
+ tmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
+ g.DrawImage(tmp, 0, mat.height);
+ }
+ bitmap = bitmap2;
+ }
+ else if (mat.repeatS == 1 || mat.repeatT == 1)
+ {
+ //br.TileMode = System.Windows.Media.TileMode.Tile;
+ }
+ else
+ {
+ //br.TileMode = System.Windows.Media.TileMode.None;
+ }
+ ImageBrush br = new ImageBrush(CreateBitmapSourceFromBitmap(bitmap));
+ br.Viewbox = new Rect(0, 0, br.ImageSource.Width, br.ImageSource.Height);
+ br.ViewboxUnits = BrushMappingMode.Absolute;
+ br.Viewport = new Rect(0, 0, 1, 1);
+ br.ViewportUnits = BrushMappingMode.Absolute;
+ br.Stretch = Stretch.None;
+
+ //br.ImageSource = CreateBitmapSourceFromBitmap(bitmap);
+ br.Opacity = (double)(((mat.Alpha + 1) * 8) - 1) / 1.0d;
+ matt.Add(br);
+ //ttt
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1 + matstart);
+ Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, mat.width, mat.height, 0, Gl.GL_RGBA,
+ Gl.GL_UNSIGNED_BYTE,
+ imageBytes);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
+
+ if (mat.flipS == 1 && mat.repeatS == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_MIRRORED_REPEAT);
+ }
+ else if (mat.repeatS == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
+ }
+ else
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP);
+ }
+ if (mat.flipT == 1 && mat.repeatT == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_MIRRORED_REPEAT);
+ }
+ else if (mat.repeatT == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
+ }
+ else
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP);
+ }
+ }
+ catch
+ {
+ matt.Add(new ImageBrush());
+ }
+ }
+
+ }
+ ///
+ /// Make texture for model.
+ ///
+ /// NSBMD Model
+ private void MakeTexture(int i, NSBMDMaterial m)
+ {
+ try
+ {
+ if (m.format == 0) // format 0 is no texture
+ {
+ //matt.Add(new System.Windows.Media.ImageBrush());
+ return;
+ }
+ var mat = m;
+ if (mat == null || (mat.paldata == null && mat.format != 7))
+ {
+ //matt.Add(new System.Windows.Media.ImageBrush());
+ return;
+ }
+ int pixelnum = mat.width * mat.height;
+
+ var image = new RGBA[pixelnum];
+
+
+ switch (mat.format)
+ {
+ // No Texture
+ case 0:
+ //puts( "ERROR: format 0" );
+ //mattt.Add(new System.Windows.Media.ImageBrush());
+ return;
+ // A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)
+ case 1:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ int index = mat.texdata[j] & 0x1f;
+ int alpha = (mat.texdata[j] >> 5);// & 7;
+ alpha = ((alpha * 4) + (alpha / 2)) * 8;// << 3;
+ image[j] = mat.paldata[index];
+ image[j].A = (byte)alpha;
+ }
+
+ break;
+ // 4-Color Palette Texture
+ case 2:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ uint index = mat.texdata[j / 4];
+ index = (index >> ((j % 4) << 1)) & 3;
+ image[j] = mat.paldata[index];
+ }
+ break;
+ // 16-Color Palette Texture
+ case 3:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ var matindex = j / 2;
+ if (mat.texdata.Length < matindex)
+ continue;
+ int index = mat.texdata[matindex];
+ index = (index >> ((j % 2) << 2)) & 0x0f;
+ if (mat.paldata == null)
+ continue;
+ if (index < 0 || index >= mat.paldata.Length)
+ continue;
+ if (j < 0 || j >= pixelnum)
+ continue;
+ image[j] = mat.paldata[index];
+ }
+ break;
+ // 256-Color Palette Texture
+ case 4:
+ if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
+ // made palette entry 0 transparent
+ for (int j = 0; j < pixelnum; j++)
+ {
+ image[j] = mat.paldata[mat.texdata[j]];
+ }
+ break;
+ // 4x4-Texel Compressed Texture
+ case 5:
+ convert_4x4texel_b(mat.texdata, mat.width, mat.height, mat.spdata, mat.paldata, image);
+ break;
+ // A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)
+ case 6:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ int index = mat.texdata[j] & 0x7;
+ int alpha = (mat.texdata[j] >> 3);
+ alpha *= 8; //((alpha * 4) + (alpha / 2)) << 3;
+ image[j] = mat.paldata[index];
+ image[j].A = (byte)alpha;
+ }
+ break;
+ // Direct Color Texture
+ case 7:
+ for (int j = 0; j < pixelnum; j++)
+ {
+ //UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
+ //image[j].R = (byte)(((p >> 0) & 0x1f) << 3);
+ //image[j].G = (byte)(((p >> 5) & 0x1f) << 3);
+ //image[j].B = (byte)(((p >> 10) & 0x1f) << 3);
+ //image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
+ image[j] = RGBA.fromColor(Tinke.Convertir.BGR555(mat.texdata[j * 2], mat.texdata[j * 2 + 1]));
+ UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
+ image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
+ }
+ break;
+ }
+
+ Console.WriteLine("convert matid = {0}", i);
+ Console.WriteLine("\ttex '{0}': {1} [{2},{3}] texsize = {4}", mat.texname, TEXTURE_FORMATS[mat.format], mat.width,
+ mat.height, mat.texsize);
+ Console.WriteLine("\tpal '{0}': pixelnum = {1}, repeat = {2}", mat.palname, pixelnum, mat.repeat);
+
+ var imageBytesList = new List();
+ //System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(mat.width, mat.height);
+ for (int k = 0; k < image.Length; ++k)
+ {
+ //bitmap.SetPixel(k - ((k / (mat.width)) * (mat.width)), k / (mat.width), image[k].ToColor());
+ imageBytesList.Add(image[k].R);
+ imageBytesList.Add(image[k].G);
+ imageBytesList.Add(image[k].B);
+ //if (image[k].A != 0)
+ //{
+ // imageBytesList.Add((byte)(image[k].A - (255 - (((mat.Alpha + 1) * 8) - 1))));
+ //}
+ //else
+ //{
+ imageBytesList.Add((byte)(image[k].A));
+ //}
+ }
+
+ var imageBytes = imageBytesList.ToArray();
+
+ //ttt
+ Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1 + matstart);
+ Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, mat.width, mat.height, 0, Gl.GL_RGBA,
+ Gl.GL_UNSIGNED_BYTE,
+ imageBytes);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
+ Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
+
+ if (mat.flipS == 1 && mat.repeatS == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_MIRRORED_REPEAT);
+ }
+ else if (mat.repeatS == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
+ }
+ else
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP);
+ }
+ if (mat.flipT == 1 && mat.repeatT == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_MIRRORED_REPEAT);
+ }
+ else if (mat.repeatT == 1)
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
+ }
+ else
+ {
+ Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP);
+ }
+ }
+ catch
+ {
+ //matt.Add(new System.Windows.Media.ImageBrush());
+ }
+ }
+ [System.Runtime.InteropServices.DllImport("gdi32.dll")]
+ private static extern bool DeleteObject(IntPtr hObject);
+
+ public static System.Windows.Media.Imaging.BitmapSource CreateBitmapSourceFromBitmap(System.Drawing.Bitmap bitmap)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException("bitmap");
+
+ IntPtr hBitmap = bitmap.GetHbitmap();
+
+ try
+ {
+ return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
+ hBitmap,
+ IntPtr.Zero,
+ System.Windows.Int32Rect.Empty,
+ System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
+ }
+ finally
+ {
+ DeleteObject(hBitmap);
+ }
+
+ }
+ private System.Windows.Media.Imaging.BitmapImage Bitmap2BitmapImage(System.Drawing.Bitmap dImg)
+ {
+ MemoryStream ms = new MemoryStream();
+ dImg.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
+ System.Windows.Media.Imaging.BitmapImage bImg = new System.Windows.Media.Imaging.BitmapImage();
+ bImg.BeginInit();
+ bImg.StreamSource = ms;
+ bImg.EndInit();
+ return bImg;
+ }
+
+ ///
+ /// Process polygon 3d commands.
+ ///
+ /// Data of specific polygon.
+ private void Process3DCommand(byte[] polydata, NSBMDMaterial m, int jointID, bool color)
+ {
+ Gl.glMatrixMode(Gl.GL_MODELVIEW);
+ Gl.glLoadIdentity();
+ MaterialHelper.CreateMaterial(new ImageBrush());
+
+ md.Add(new MeshBuilder());
+ IList poi = new List();
+ IList nor = new List();
+ IList tex = new List();
+ int typ = -1;
+ if (polydata == null)
+ return;
+ int commandptr = 0;
+ int commandlimit = polydata.Length;
+ int[] command = new int[4];
+ int cur_vertex, mode, i;
+ float[] vtx_state = { 0.0f, 0.0f, 0.0f };
+ float[] vtx_trans = { 0.0f, 0.0f, 0.0f };
+ cur_vertex = gCurrentVertex; // for vertex_mode
+ if (Model.Objects.Count > 0)
+ {
+ CurrentMatrix = MatrixStack[stackID].Clone();
+ }
+ else
+ {
+ CurrentMatrix.LoadIdentity();
+ }
+ if (Model.Objects.Count > 1)
+ {
+ //CurrentMatrix.Scale(Model.modelScale, Model.modelScale, Model.modelScale);
+ }
+ while (commandptr < commandlimit)
+ {
+ for (i = 0; i < 4; ++i)
+ {
+ if (commandptr >= commandlimit)
+ command[i] = 0xFF;
+ else
+ {
+ command[i] = polydata[commandptr];
+ commandptr++;
+ }
+ }
+
+
+ for (i = 0; i < 4 && commandptr < commandlimit; i++)
+ {
+ switch (command[i])
+ {
+ case 0: // No Operation (for padding packed GXFIFO commands)
+ break;
+ case 0x10:
+ {
+ int param = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ switch (param)
+ {
+ case 0:
+ // Gl.glMatrixMode(Gl.GL_PROJECTION_MATRIX);
+ break;
+ case 1:
+ // Gl.glMatrixMode(Gl.GL_MODELVIEW_MATRIX);
+ break;
+ case 2:
+ break;
+ case 3:
+ // Gl.glMatrixMode(Gl.GL_TEXTURE_MATRIX);
+ break;
+ }
+ break;
+ }
+ case 0x11: break;
+ case 0x12: commandptr += 4; break;
+ case 0x13: commandptr += 4; break;
+ case 0x14:
+ /*
+ MTX_RESTORE - Restore Current Matrix from Stack (W)
+ Sets C=[N]. The stack pointer S is not used, and is left unchanged.
+ Parameter Bit0-4: Stack Address (0..30) (31 causes overflow in GXSTAT.15)
+ Parameter Bit5-31: Not used
+ */
+
+ stackID = Utils.Read4BytesAsInt32(polydata, commandptr) & 0x1F;// & 0x0000001F;
+ commandptr += 4;
+ MatrixStack[stackID].CopyValuesTo(CurrentMatrix);
+ break;
+ case 0x15:
+ {
+ CurrentMatrix.LoadIdentity();
+ break;
+ }
+ case 0x16:
+ {
+ for (int j = 0; j < 16; j++)
+ {
+ CurrentMatrix[j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f;
+ commandptr += 4;
+ }
+ break;
+ }
+ case 0x17:
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ for (int k = 0; k < 3; j++)
+ {
+ CurrentMatrix[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f;
+ commandptr += 4;
+ }
+ }
+ break;
+ }
+ case 0x18:
+ {
+ MTX44 f = new MTX44();
+ f.LoadIdentity();
+ for (int j = 0; j < 16; j++)
+ {
+ f[j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f;
+ commandptr += 4;
+ }
+ CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix);
+ break;
+ }
+ case 0x19:
+ {
+ MTX44 f = new MTX44();
+ f.LoadIdentity();
+ for (int j = 0; j < 4; j++)
+ {
+ for (int k = 0; k < 3; j++)
+ {
+ f[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f;
+ commandptr += 4;
+ }
+ }
+ CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix);
+ break;
+ }
+ case 0x1A:
+ {
+ MTX44 f = new MTX44();
+ f.LoadIdentity();
+ for (int j = 0; j < 3; j++)
+ {
+ for (int k = 0; k < 3; j++)
+ {
+ f[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f;
+ commandptr += 4;
+ }
+ }
+ CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix);
+ break;
+ }
+ case 0x1b:
+ /*
+ MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)
+ Sets C=M*C. Parameters: 3, m[0..2] (MTX_SCALE doesn't change Vector Matrix)
+ */
+ {
+ int x, y, z;
+ x = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ y = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ z = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ //CurrentMatrix[0] = (float)sign(x, 32) / SCALE_IV;
+ //CurrentMatrix[5] = (float)sign(y, 32) / SCALE_IV;
+ //CurrentMatrix[10] = (float)sign(z, 32) / SCALE_IV;
+ //CurrentMatrix.SetValues(scale(CurrentMatrix.Floats, x, y, z));
+ CurrentMatrix.Scale((float)x / SCALE_IV / Model.modelScale, (float)y / SCALE_IV / Model.modelScale, (float)z / SCALE_IV / Model.modelScale);
+ //CurrentMatrix.Scale((float)sign(x, 32) / SCALE_IV, (float)sign(y, 32) / SCALE_IV, (float)sign(z, 32) / SCALE_IV);
+ break;
+ }
+ case 0x1c:
+ /*
+ MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)
+ Sets C=M*C. Parameters: 3, m[0..2] (x,y,z position)
+ */
+ {
+ int x, y, z;
+ x = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ y = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ z = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ CurrentMatrix.translate((float)sign(x, 32) / SCALE_IV / Model.modelScale, (float)sign(y, 32) / SCALE_IV / Model.modelScale, (float)sign(z, 32) / SCALE_IV / Model.modelScale);
+ break;
+ }
+ case 0x20: // Directly Set Vertex Color (W)
+ {
+ Int64 rgb, r, g, b;
+
+ rgb = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ if (gOptColoring)
+ {
+ r = (rgb >> 0) & 0x1F;
+ g = (rgb >> 5) & 0x1F;
+ b = (rgb >> 10) & 0x1F;
+ if (color)
+ {
+ Gl.glColor4f(((float)r) / 31.0f, ((float)g) / 31.0f, ((float)b) / 31.0f, m.Alpha / 31.0f);
+ }
+ }
+ }
+ break;
+
+ case 0x21:
+ /*
+ Set Normal Vector (W)
+ 0-9 X-Component of Normal Vector (1bit sign + 9bit fractional part)
+ 10-19 Y-Component of Normal Vector (1bit sign + 9bit fractional part)
+ 20-29 Z-Component of Normal Vector (1bit sign + 9bit fractional part)
+ 30-31 Not used
+ */
+ {
+ Int64 xyz, x, y, z;
+
+ xyz = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = (xyz >> 0) & 0x3FF;
+ if ((x & 0x200) != 0)
+ x |= -1024;
+ y = (xyz >> 10) & 0x3FF;
+ if ((y & 0x200) != 0) y |= -1024;
+ z = (xyz >> 20) & 0x3FF;
+ if ((z & 0x200) != 0) z |= -1024;
+ Gl.glNormal3f(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f);
+ if (writevertex)
+ {
+ //normals.Add(new float[] { ((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f });
+ //mod.Normals.Add(new System.Windows.Media.Media3D.Vector3D(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f))
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f));
+ }
+ break;
+ }
+ case 0x22:
+ /*
+ Set Texture Coordinates (W)
+ Parameter 1, Bit 0-15 S-Coordinate (X-Coordinate in Texture Source)
+ Parameter 1, Bit 16-31 T-Coordinate (Y-Coordinate in Texture Source)
+ Both values are 1bit sign + 11bit integer + 4bit fractional part.
+ A value of 1.0 (=1 SHL 4) equals to one Texel.
+ */
+ {
+ Int64 st, s, t;
+
+ st = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ s = (st >> 0) & 0xffff;
+ if ((s & 0x8000) != 0) s |= unchecked((int)0xFFFF0000);//-65536;
+ t = (st >> 16) & 0xffff;
+ if ((t & 0x8000) != 0) t |= unchecked((int)0xFFFF0000);//-65536;
+ Gl.glTexCoord2f(((float)s) / 16.0f, ((float)t) / 16.0f);
+
+ if (writevertex)
+ {
+ //mod.TextureCoordinates.Add(new System.Windows.Point((float)s/1024f,(float)t/1024f));
+ tex.Add(new System.Windows.Point(((float)m.scaleS / (float)m.width) * ((float)s / 16f) / (m.flipS + 1), -((float)m.scaleT / (float)m.height) * ((float)t / 16f) / (m.flipT + 1)));
+ }
+ break;
+ }
+ case 0x23:
+ /*
+ VTX_16 - Set Vertex XYZ Coordinates (W)
+ Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part)
+ Parameter 1, Bit 16-31 Y-Coordinate (signed, with 12bit fractional part)
+ Parameter 2, Bit 0-15 Z-Coordinate (signed, with 12bit fractional part)
+ Parameter 2, Bit 16-31 Not used
+ */
+ {
+ int parameter, x, y, z;
+
+ parameter = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = sign((parameter >> 0) & 0xFFFF, 16);
+ //if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536;
+ y = sign((parameter >> 16) & 0xFFFF, 16);
+ //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536;
+
+ parameter = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ z = sign(parameter & 0xFFFF, 16);
+ // if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536;
+
+ vtx_state[0] = ((float)x) / SCALE_IV;
+ vtx_state[1] = ((float)y) / SCALE_IV;
+ vtx_state[2] = ((float)z) / SCALE_IV;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x24:
+ /*
+ VTX_10 - Set Vertex XYZ Coordinates (W)
+ Parameter 1, Bit 0-9 X-Coordinate (signed, with 6bit fractional part)
+ Parameter 1, Bit 10-19 Y-Coordinate (signed, with 6bit fractional part)
+ Parameter 1, Bit 20-29 Z-Coordinate (signed, with 6bit fractional part)
+ Parameter 1, Bit 30-31 Not used
+ */
+ {
+ int xyz, x, y, z;
+
+ xyz = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = sign((xyz >> 0) & 0x3FF, 10);
+ // if ((x & 0x200) != 0) x |= unchecked((int)0xFFFFFC00);//-1024;
+ y = sign((xyz >> 10) & 0x3FF, 10);
+ //if ((y & 0x200) != 0) y |= unchecked((int)0xFFFFFC00);//-1024;
+ z = sign((xyz >> 20) & 0x3FF, 10);
+ // if ((z & 0x200) != 0) z |= unchecked((int)0xFFFFFC00);//-1024;
+
+ vtx_state[0] = (float)x / 64.0f;
+ vtx_state[1] = (float)y / 64.0f;
+ vtx_state[2] = (float)z / 64.0f;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x25:
+ /*
+ VTX_XY - Set Vertex XY Coordinates (W)
+ Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part)
+ Parameter 1, Bit 16-31 Y-Coordinate (signed, with 12bit fractional part)
+ */
+ {
+ int xy, x, y;
+
+ xy = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = sign((xy >> 0) & 0xFFFF, 16);
+ //if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536;
+ y = sign((xy >> 16) & 0xFFFF, 16);
+ //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536;
+
+ vtx_state[0] = ((float)x) / SCALE_IV;
+ vtx_state[1] = ((float)y) / SCALE_IV;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x26:
+ /*
+ VTX_XZ - Set Vertex XZ Coordinates (W)
+ Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part)
+ Parameter 1, Bit 16-31 Z-Coordinate (signed, with 12bit fractional part)
+ */
+ {
+ int xz, x, z;
+
+ xz = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = sign((xz >> 0) & 0xFFFF, 16);
+ // if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536;
+ z = sign((xz >> 16) & 0xFFFF, 16);
+ // if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536;
+
+ vtx_state[0] = ((float)x) / SCALE_IV;
+ vtx_state[2] = ((float)z) / SCALE_IV;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ // vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x27:
+ /*
+ VTX_YZ - Set Vertex YZ Coordinates (W)
+ Parameter 1, Bit 0-15 Y-Coordinate (signed, with 12bit fractional part)
+ Parameter 1, Bit 16-31 Z-Coordinate (signed, with 12bit fractional part)
+ */
+ {
+ int yz, y, z;
+ yz = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ y = sign((yz >> 0) & 0xFFFF, 16);
+ //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536;
+ z = sign((yz >> 16) & 0xFFFF, 16);
+ //if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536;
+
+ vtx_state[1] = ((float)y) / SCALE_IV;
+ vtx_state[2] = ((float)z) / SCALE_IV;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x28:
+ /*
+ VTX_DIFF - Set Relative Vertex Coordinates (W)
+ Parameter 1, Bit 0-9 X-Difference (signed, with 9bit fractional part)
+ Parameter 1, Bit 10-19 Y-Difference (signed, with 9bit fractional part)
+ Parameter 1, Bit 20-29 Z-Difference (signed, with 9bit fractional part)
+ Parameter 1, Bit 30-31 Not used
+ */
+ {
+ int xyz, x, y, z;
+ xyz = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+
+ x = sign((xyz >> 0) & 0x3FF, 10);
+ //if ((x & 0x200) != 0) x |= unchecked((int)0xFFFFFC00);//-1024;
+ y = sign((xyz >> 10) & 0x3FF, 10);
+ //if ((y & 0x200) != 0) y |= unchecked((int)0xFFFFFC00);
+ z = sign((xyz >> 20) & 0x3FF, 10);
+ //if ((z & 0x200) != 0) z |= unchecked((int)0xFFFFFC00);
+
+
+ vtx_state[0] += ((float)x) / SCALE_IV;
+ vtx_state[1] += ((float)y) / SCALE_IV;
+ vtx_state[2] += ((float)z) / SCALE_IV;
+ if (stackID != -1)
+ {
+ vtx_trans = CurrentMatrix.MultVector(vtx_state);
+ Gl.glVertex3fv(vtx_trans);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_trans);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if (nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0));
+ }
+ }
+ }
+ else
+ {
+ Gl.glVertex3fv(vtx_state);
+ if (writevertex)
+ {
+ //vertex.Add(vtx_state);
+ //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2]));
+ if (poi.Count > tex.Count && tex.Count != 0)
+ {
+ tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ else if (tex.Count == 0)
+ {
+ tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity));
+ }
+ if (poi.Count > nor.Count && nor.Count != 0)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ else if(nor.Count == 0)
+ {
+ nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity,0));
+ }
+ }
+ }
+ if (writevertex)
+ {
+ // vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count));
+ }
+ break;
+ }
+ case 0x29:
+ {
+ int param = Utils.Read4BytesAsInt32(polydata, commandptr);
+ commandptr += 4;
+ /*int light = (param >> 0) & 0x10;
+ int polygonMode = (param >> 4) & 0x4;
+ switch (polygonMode)
+ {
+ case 0:
+ mode = Gl.GL_MODULATE;
+ break;
+ case 1:
+ mode = Gl.GL_DECAL;
+ break;
+ case 2:
+ mode = Gl.GL_SHADOW_AMBIENT_SGIX;
+ break;
+ case 3:
+ mode = Gl.GL_QUAD_STRIP;
+ break;
+ default:
+ //return ;// FALSE;
+ throw new Exception();
+ break;
+ }*/
+ break;
+ }
+ case 0x2A: commandptr += 4; break;
+ case 0x2B: commandptr += 4; break;
+
+ // lighting commands
+ case 0x30: commandptr += 4; break;
+ case 0x31: commandptr += 4; break;
+ case 0x32: commandptr += 4; break;
+ case 0x33:
+ {
+
+ commandptr += 4;
+ break;
+ }
+ case 0x34: commandptr += 128; break;
+ case 0x40: // Start of Vertex List (W)
+ {
+ mode = Utils.Read4BytesAsInt32(polydata, commandptr);
+ //mode = mode & 0x3;
+ commandptr += 4;
+ typ = mode;
+ switch (mode)
+ {
+ case 0:
+ mode = Gl.GL_TRIANGLES;
+ break;
+ case 1:
+ mode = Gl.GL_QUADS;
+ break;
+ case 2:
+ mode = Gl.GL_TRIANGLE_STRIP;
+ break;
+ case 3:
+ mode = Gl.GL_QUAD_STRIP;
+ break;
+ default:
+ //return ;// FALSE;
+ throw new Exception();
+ break;
+ }
+
+ Gl.glBegin(mode);
+ break;
+ }
+ case 0x41:
+ Gl.glEnd();
+
+ if (writevertex)
+ {
+ switch (typ)
+ {
+ case 0:
+ {
+ for (int j = 0; j < poi.Count / 3; j++)
+ {
+ if (tex.Count > j * 3 + 2)
+ {
+ md[md.Count - 1].AddTriangle(poi[j * 3], poi[j * 3 + 1], poi[j * 3 + 2], tex[j * 3], tex[j * 3 + 1], tex[j * 3 + 2]);
+ }
+ else
+ {
+ md[md.Count - 1].AddTriangle(poi[j * 3], poi[j * 3 + 1], poi[j * 3 + 2]);
+ }
+ }
+
+ break;
+ }
+ case 1:
+ {
+ for (int j = 0; j < poi.Count / 4; j++)
+ {
+ if (tex.Count > j * 4 + 3)
+ {
+ md[md.Count - 1].AddQuad(poi[j * 4], poi[j * 4 + 1], poi[j * 4 + 2], poi[j * 4 + 3], tex[j * 4], tex[j * 4 + 1], tex[j * 4 + 2], tex[j * 4 + 3]);
+ }
+ else
+ {
+ md[md.Count - 1].AddQuad(poi[j * 4], poi[j * 4 + 1], poi[j * 4 + 2], poi[j * 4 + 3]);
+ }
+ }
+
+ break;
+ }
+ case 2:
+ {
+ while (poi.Count > nor.Count)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ while (poi.Count > tex.Count)
+ {
+ tex.Add(tex[tex.Count - 1]);
+ }
+ md[md.Count - 1].AddTriangles(poi, nor, tex);
+ //md[mo].AddTriangleStrip(poi, nor, tex);
+ break;
+ }
+ case 3:
+ {
+ while (poi.Count > nor.Count)
+ {
+ nor.Add(nor[nor.Count - 1]);
+ }
+ while (poi.Count > tex.Count)
+ {
+ tex.Add(tex[tex.Count - 1]);
+ }
+ md[md.Count - 1].AddQuads(poi, nor, tex);
+ //md.AddQuads(poi, nor, tex);
+ break;
+ }
+ default:
+ //return ;// FALSE;
+ break;
+ }
+ }
+ nor.Clear();
+ tex.Clear();
+ poi.Clear();
+ //nr++;
+ // for vertex mode, display at maximum certain number of vertex-list
+ // decrease cur_vertex so that when we reach 0, stop rendering any further
+ cur_vertex--;
+ if (cur_vertex < 0 && gOptVertexMode)
+ return; //TRUE;
+ break;
+ case 0x50: commandptr += 4; break;
+ case 0x60: commandptr += 4; break;
+ case 0x70: commandptr += 12; break;
+ case 0x71: commandptr += 8; break;
+ case 0x72: commandptr += 4; break;
+ default:
+ break;
+ //return FALSE;
+ }
+ }
+ }
+ }
+ public static int sign(int data, int size)
+ {
+ if ((data & 1 << size - 1) != 0)
+ data |= -1 << size;
+ return data;
+ }
+
+ ///
+ /// Process polygon 3d commands.
+ ///
+ /// Data of specific polygon.
+ public void ClearOBJ()
+ {
+ md.Clear();
+ writevertex = true;
+ }
+ public void RipModel(string file)
+ {
+ NSBMDPolygon polygon;
+ int matId;
+ NSBMDMaterial material;
+ int num3;
+ DiffuseMaterial material2;
+ MeshBuilder builder;
+ Model3D modeld;
+ MTX44 mtx = new MTX44();
+ List list = new List();
+ List list2 = new List();
+ for (int i = 0; i < (this.Model.Polygons.Count - 1); i++)
+ {
+ polygon = this.Model.Polygons[i];
+ matId = polygon.MatId;
+ material = this.Model.Materials[matId];
+ }
+ MTX44 mtx2 = new MTX44();
+ mtx2.LoadIdentity();
+ for (num3 = 0; num3 < this.Model.Objects.Count; num3++)
+ {
+ NSBMDObject obj2 = this.Model.Objects[num3];
+ float[] transVect = obj2.TransVect;
+ float[] numArray2 = loadIdentity();
+ if (obj2.RestoreID != -1)
+ {
+ mtx2 = MatrixStack[obj2.RestoreID];
+ }
+ if (obj2.StackID != -1)
+ {
+ if (obj2.visible)
+ {
+ MTX44 b = new MTX44();
+ b.SetValues(obj2.materix);
+ mtx2 = mtx2.MultMatrix(b);
+ }
+ else
+ {
+ mtx2.Zero();
+ }
+ MatrixStack[obj2.StackID] = mtx2;
+ stackID = obj2.StackID;
+ float[] numArray3 = mtx2.MultVector(new float[3]);
+ list2.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ }
+ }
+ num3 = 0;
+ while (num3 < (this.Model.Polygons.Count - 1))
+ {
+ polygon = this.Model.Polygons[num3];
+ if ((gOptTexture && !gOptWireFrame) && g_mat)
+ {
+ matId = polygon.MatId;
+ if (matId == -1)
+ {
+ this.mattt.Add(new ImageBrush());
+ }
+ else
+ {
+ this.mattt.Add(this.matt[matId]);
+ material = this.Model.Materials[matId];
+ }
+ }
+ stackID = polygon.StackID;
+ list.Add(Process3DCommandRipper(polygon.PolyData, Model.Materials[polygon.MatId], polygon.JointID, true));
+ num3++;
+ }
+ File.Create(file).Close();
+ ObjExporter exporter = new ObjExporter(file, "Created with DS Pokmon Rom Editor " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
+ int index = 0;
+ foreach (Group group in list)
+ {
+ ImageBrush brush = new ImageBrush();
+ try
+ {
+ brush.ImageSource = this.mattt[index].ImageSource;
+ brush.Opacity = this.mattt[index].Opacity;
+ brush.Viewbox = this.mattt[index].Viewbox;
+ brush.ViewboxUnits = this.mattt[index].ViewboxUnits;
+ brush.Viewport = this.mattt[index].Viewport;
+ brush.ViewportUnits = this.mattt[index].ViewportUnits;
+ }
+ catch
+ {
+ }
+ if (brush.ImageSource != null)
+ {
+ material2 = new DiffuseMaterial(brush);
+ }
+ else
+ {
+ material2 = new DiffuseMaterial(new SolidColorBrush());
+ }
+ material2.SetValue(matName, this.Model.Materials[this.Model.Polygons[index].MatId].MaterialName);
+ material2.SetValue(polyName, this.Model.Polygons[index].Name);
+ material2.Brush.Opacity = ((float)this.Model.Materials[this.Model.Polygons[index].MatId].Alpha) / 31f;
+ material2.AmbientColor = Color.FromArgb(this.Model.Materials[this.Model.Polygons[index].MatId].AmbientColor.A, this.Model.Materials[this.Model.Polygons[index].MatId].AmbientColor.R, this.Model.Materials[this.Model.Polygons[index].MatId].AmbientColor.G, this.Model.Materials[this.Model.Polygons[index].MatId].AmbientColor.B);
+ material2.Color = Color.FromArgb(0xff, this.Model.Materials[this.Model.Polygons[index].MatId].DiffuseColor.R, this.Model.Materials[this.Model.Polygons[index].MatId].DiffuseColor.G, this.Model.Materials[this.Model.Polygons[index].MatId].DiffuseColor.B);
+ builder = new MeshBuilder();
+ foreach (MKDS_Course_Editor.Export3DTools.Polygon polygon2 in group)
+ {
+ IList list3;
+ IList list4;
+ IList list5;
+ switch (polygon2.PolyType)
+ {
+ case PolygonType.Triangle:
+ list3 = new List();
+ list4 = new List();
+ list5 = new List();
+ num3 = 0;
+ goto Label_08AB;
+
+ case PolygonType.Quad:
+ list3 = new List();
+ list4 = new List();
+ list5 = new List();
+ num3 = 0;
+ goto Label_0C5E;
+
+ case PolygonType.TriangleStrip:
+ list3 = new List();
+ list4 = new List();
+ list5 = new List();
+ num3 = 0;
+ goto Label_0D66;
+
+ case PolygonType.QuadStrip:
+ list3 = new List();
+ list4 = new List();
+ list5 = new List();
+ num3 = 0;
+ goto Label_0E7C;
+
+ default:
+ {
+ continue;
+ }
+ }
+ Label_0608:
+ list3.Add(new Point3D((double)polygon2.Vertex[num3].X, (double)polygon2.Vertex[num3].Y, (double)polygon2.Vertex[num3].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3].X, (double)polygon2.Normals[num3].Y, (double)polygon2.Normals[num3].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3].X, (double)polygon2.TexCoords[num3].Y));
+ list3.Add(new Point3D((double)polygon2.Vertex[num3 + 1].X, (double)polygon2.Vertex[num3 + 1].Y, (double)polygon2.Vertex[num3 + 1].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3 + 1].X, (double)polygon2.Normals[num3 + 1].Y, (double)polygon2.Normals[num3 + 1].Z));
+ list5.Add(new Point((double)polygon2.TexCoords[num3 + 1].X, (double)polygon2.TexCoords[num3 + 1].Y));
+ list3.Add(new Point3D((double)polygon2.Vertex[num3 + 2].X, (double)polygon2.Vertex[num3 + 2].Y, (double)polygon2.Vertex[num3 + 2].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3 + 2].X, (double)polygon2.Normals[num3 + 2].Y, (double)polygon2.Normals[num3 + 2].Z));
+ list5.Add(new Point((double)polygon2.TexCoords[num3 + 2].X, (double)polygon2.TexCoords[num3 + 2].Y));
+ builder.AddTriangles(list3, list4, list5);
+ list3.Clear();
+ list4.Clear();
+ list5.Clear();
+ num3 += 3;
+ Label_08AB:
+ if (num3 < polygon2.Vertex.Length)
+ {
+ goto Label_0608;
+ }
+ continue;
+ Label_08E4:
+ list3.Add(new Point3D((double)polygon2.Vertex[num3].X, (double)polygon2.Vertex[num3].Y, (double)polygon2.Vertex[num3].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3].X, (double)polygon2.Normals[num3].Y, (double)polygon2.Normals[num3].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3].X, (double)polygon2.TexCoords[num3].Y));
+ list3.Add(new Point3D((double)polygon2.Vertex[num3 + 1].X, (double)polygon2.Vertex[num3 + 1].Y, (double)polygon2.Vertex[num3 + 1].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3 + 1].X, (double)polygon2.Normals[num3 + 1].Y, (double)polygon2.Normals[num3 + 1].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3 + 1].X, (double)polygon2.TexCoords[num3 + 1].Y));
+ list3.Add(new Point3D((double)polygon2.Vertex[num3 + 2].X, (double)polygon2.Vertex[num3 + 2].Y, (double)polygon2.Vertex[num3 + 2].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3 + 2].X, (double)polygon2.Normals[num3 + 2].Y, (double)polygon2.Normals[num3 + 2].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3 + 2].X, (double)polygon2.TexCoords[num3 + 2].Y));
+ list3.Add(new Point3D((double)polygon2.Vertex[num3 + 3].X, (double)polygon2.Vertex[num3 + 3].Y, (double)polygon2.Vertex[num3 + 3].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3 + 3].X, (double)polygon2.Normals[num3 + 3].Y, (double)polygon2.Normals[num3 + 3].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3 + 3].X, (double)polygon2.TexCoords[num3 + 3].Y));
+ builder.AddQuads(list3, list4, list5);
+ list3.Clear();
+ list4.Clear();
+ list5.Clear();
+ num3 += 4;
+ Label_0C5E:
+ if (num3 < polygon2.Vertex.Length)
+ {
+ goto Label_08E4;
+ }
+ continue;
+ Label_0C97:
+ list3.Add(new Point3D((double)polygon2.Vertex[num3].X, (double)polygon2.Vertex[num3].Y, (double)polygon2.Vertex[num3].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3].X, (double)polygon2.Normals[num3].Y, (double)polygon2.Normals[num3].Z));
+ list5.Add(new Point((double)polygon2.TexCoords[num3].X, (double)polygon2.TexCoords[num3].Y));
+ num3++;
+ Label_0D66:
+ if (num3 < polygon2.Vertex.Length)
+ {
+ goto Label_0C97;
+ }
+ builder.AddTriangleStrip(list3, list4, list5);
+ continue;
+ Label_0DAD:
+ list3.Add(new Point3D((double)polygon2.Vertex[num3].X, (double)polygon2.Vertex[num3].Y, (double)polygon2.Vertex[num3].Z));
+ list4.Add(new Vector3D((double)polygon2.Normals[num3].X, (double)polygon2.Normals[num3].Y, (double)polygon2.Normals[num3].Z));
+ list5.Add(new System.Windows.Point((double)polygon2.TexCoords[num3].X, (double)polygon2.TexCoords[num3].Y));
+ num3++;
+ Label_0E7C:
+ if (num3 < polygon2.Vertex.Length)
+ {
+ goto Label_0DAD;
+ }
+ builder.AddTriangleStrip(list3, list4, list5);
+ }
+ modeld = new GeometryModel3D(builder.ToMesh(false), material2);
+ exporter.Export(modeld);
+ index++;
+ }
+
+ exporter.Close();
+ this.writevertex = false;
+ }
+ private Group Process3DCommandRipper(byte[] polydata, NSBMDMaterial m, int jointID, bool color)
+ {
+ Group group = new Group();
+ Vector3 item = new Vector3(float.NaN, 0f, 0f);
+ System.Drawing.Color white = System.Drawing.Color.White;
+ Vector2 vector2 = new Vector2(float.NaN, 0f);
+ List list = new List();
+ List list2 = new List();
+ List list3 = new List();
+ int num = -1;
+ if (polydata != null)
+ {
+ int index = 0;
+ int length = polydata.Length;
+ int[] numArray = new int[4];
+ float[] numArray4 = new float[3];
+ float[] v = numArray4;
+ numArray4 = new float[3];
+ float[] numArray3 = numArray4;
+ int gCurrentVertex = NSBMDGlRenderer.gCurrentVertex;
+ if (this.Model.Objects.Count > 0)
+ {
+ CurrentMatrix = MatrixStack[stackID].Clone();
+ }
+ else
+ {
+ CurrentMatrix.LoadIdentity();
+ }
+ if (this.Model.Objects.Count > 1)
+ {
+ }
+ while (index < length)
+ {
+ int num7 = 0;
+ while (num7 < 4)
+ {
+ if (index >= length)
+ {
+ numArray[num7] = 0xff;
+ }
+ else
+ {
+ numArray[num7] = polydata[index];
+ index++;
+ }
+ num7++;
+ }
+ for (num7 = 0; (num7 < 4) && (index < length); num7++)
+ {
+ int num6;
+ int num8;
+ int num9;
+ int num10;
+ MTX44 mtx;
+ int num11;
+ int num12;
+ int num13;
+ int num26;
+ switch (numArray[num7])
+ {
+ case 0x70:
+ {
+ index += 12;
+ continue;
+ }
+ case 0x71:
+ {
+ index += 8;
+ continue;
+ }
+ case 0x72:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x60:
+ {
+ index += 4;
+ continue;
+ }
+ case 80:
+ {
+ index += 4;
+ continue;
+ }
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 0x1d:
+ case 30:
+ case 0x1f:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ case 0x11:
+ {
+ continue;
+ }
+ case 0x10:
+ {
+ num8 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ continue;
+ }
+ case 0x12:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x13:
+ {
+ index += 4;
+ continue;
+ }
+ case 20:
+ {
+ stackID = Utils.Read4BytesAsInt32(polydata, index) & 0x1f;
+ index += 4;
+ MatrixStack[stackID].CopyValuesTo(CurrentMatrix);
+ continue;
+ }
+ case 0x15:
+ {
+ CurrentMatrix.LoadIdentity();
+ continue;
+ }
+ case 0x16:
+ {
+ num9 = 0;
+ while (num9 < 0x10)
+ {
+ CurrentMatrix[num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f;
+ index += 4;
+ num9++;
+ }
+ continue;
+ }
+ case 0x17:
+ num9 = 0;
+ goto Label_039C;
+
+ case 0x18:
+ mtx = new MTX44();
+ mtx.LoadIdentity();
+ num9 = 0;
+ goto Label_03E8;
+
+ case 0x19:
+ mtx = new MTX44();
+ mtx.LoadIdentity();
+ num9 = 0;
+ goto Label_0466;
+
+ case 0x1a:
+ mtx = new MTX44();
+ mtx.LoadIdentity();
+ num9 = 0;
+ goto Label_04E3;
+
+ case 0x1b:
+ {
+ num11 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num12 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num13 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ CurrentMatrix.Scale((((float)num11) / 4096f) / this.Model.modelScale, (((float)num12) / 4096f) / this.Model.modelScale, (((float)num13) / 4096f) / this.Model.modelScale);
+ continue;
+ }
+ case 0x1c:
+ {
+ num11 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num12 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num13 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ CurrentMatrix.translate((((float)sign(num11, 0x20)) / 4096f) / this.Model.modelScale, (((float)sign(num12, 0x20)) / 4096f) / this.Model.modelScale, (((float)sign(num13, 0x20)) / 4096f) / this.Model.modelScale);
+ continue;
+ }
+ case 0x20:
+ {
+ long num14 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ if (gOptColoring)
+ {
+ long num15 = num14 & 0x1fL;
+ long num16 = (num14 >> 5) & 0x1fL;
+ long num17 = (num14 >> 10) & 0x1fL;
+ if (color)
+ {
+ white = System.Drawing.Color.FromArgb((int)(((float)m.Alpha) / 31f), (int)(((float)num15) / 31f), (int)(((float)num16) / 31f), (int)(((float)num17) / 31f));
+ }
+ }
+ continue;
+ }
+ case 0x21:
+ {
+ long num18 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ long num19 = num18 & 0x3ffL;
+ if ((num19 & 0x200L) != 0L)
+ {
+ num19 |= -1024L;
+ }
+ long num20 = (num18 >> 10) & 0x3ffL;
+ if ((num20 & 0x200L) != 0L)
+ {
+ num20 |= -1024L;
+ }
+ long num21 = (num18 >> 20) & 0x3ffL;
+ if ((num21 & 0x200L) != 0L)
+ {
+ num21 |= -1024L;
+ }
+ item = new Vector3(((float)num19) / 512f, ((float)num20) / 512f, ((float)num21) / 512f);
+ continue;
+ }
+ case 0x22:
+ {
+ long num22 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ long num23 = num22 & 0xffffL;
+ if ((num23 & 0x8000L) != 0L)
+ {
+ num23 |= -65536L;
+ }
+ long num24 = (num22 >> 0x10) & 0xffffL;
+ if ((num24 & 0x8000L) != 0L)
+ {
+ num24 |= -65536L;
+ }
+ vector2 = new Vector2(((m.scaleS / ((float)m.width)) * (((float)num23) / 16f)) / ((float)(m.flipS + 1)), (-(m.scaleT / ((float)m.height)) * (((float)num24) / 16f)) / ((float)(m.flipT + 1)));
+ continue;
+ }
+ case 0x23:
+ {
+ int num25 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num11 = sign(num25 & 0xffff, 0x10);
+ num12 = sign((num25 >> 0x10) & 0xffff, 0x10);
+ num25 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num13 = sign(num25 & 0xffff, 0x10);
+ v[0] = ((float)num11) / 4096f;
+ v[1] = ((float)num12) / 4096f;
+ v[2] = ((float)num13) / 4096f;
+ if (stackID == -1)
+ {
+ goto Label_08E2;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_090F;
+ }
+ case 0x24:
+ num26 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num11 = sign(num26 & 0x3ff, 10);
+ num12 = sign((num26 >> 10) & 0x3ff, 10);
+ num13 = sign((num26 >> 20) & 0x3ff, 10);
+ v[0] = ((float)num11) / 64f;
+ v[1] = ((float)num12) / 64f;
+ v[2] = ((float)num13) / 64f;
+ if (stackID == -1)
+ {
+ goto Label_09E1;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_0A0E;
+
+ case 0x25:
+ {
+ int num27 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num11 = sign(num27 & 0xffff, 0x10);
+ num12 = sign((num27 >> 0x10) & 0xffff, 0x10);
+ v[0] = ((float)num11) / 4096f;
+ v[1] = ((float)num12) / 4096f;
+ if (stackID == -1)
+ {
+ goto Label_0ABF;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_0AEC;
+ }
+ case 0x26:
+ {
+ int num28 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num11 = sign(num28 & 0xffff, 0x10);
+ num13 = sign((num28 >> 0x10) & 0xffff, 0x10);
+ v[0] = ((float)num11) / 4096f;
+ v[2] = ((float)num13) / 4096f;
+ if (stackID == -1)
+ {
+ goto Label_0B9D;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_0BCA;
+ }
+ case 0x27:
+ {
+ int num29 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num12 = sign(num29 & 0xffff, 0x10);
+ num13 = sign((num29 >> 0x10) & 0xffff, 0x10);
+ v[1] = ((float)num12) / 4096f;
+ v[2] = ((float)num13) / 4096f;
+ if (stackID == -1)
+ {
+ goto Label_0C7B;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_0CA8;
+ }
+ case 40:
+ num26 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num11 = sign(num26 & 0x3ff, 10);
+ num12 = sign((num26 >> 10) & 0x3ff, 10);
+ num13 = sign((num26 >> 20) & 0x3ff, 10);
+ v[0] += ((float)num11) / 4096f;
+ v[1] += ((float)num12) / 4096f;
+ v[2] += ((float)num13) / 4096f;
+ if (stackID == -1)
+ {
+ goto Label_0DAA;
+ }
+ numArray3 = CurrentMatrix.MultVector(v);
+ list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ goto Label_0DD7;
+
+ case 0x29:
+ {
+ num8 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ continue;
+ }
+ case 0x2a:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x2b:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x30:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x31:
+ {
+ index += 4;
+ continue;
+ }
+ case 50:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x33:
+ {
+ index += 4;
+ continue;
+ }
+ case 0x34:
+ {
+ index += 0x80;
+ continue;
+ }
+ case 0x40:
+ num6 = Utils.Read4BytesAsInt32(polydata, index);
+ index += 4;
+ num = num6;
+ switch (num6)
+ {
+ case 0:
+ goto Label_0E92;
+
+ case 1:
+ goto Label_0E97;
+
+ case 2:
+ goto Label_0E9C;
+
+ case 3:
+ goto Label_0EA1;
+ }
+ throw new Exception();
+
+ case 0x41:
+ switch (num)
+ {
+ case 0:
+ goto Label_0ED1;
+
+ case 1:
+ goto Label_0EF6;
+
+ case 2:
+ goto Label_0F1B;
+
+ case 3:
+ goto Label_0F40;
+ }
+ goto Label_0F67;
+
+ default:
+ {
+ continue;
+ }
+ }
+ Label_0358:
+ num10 = 0;
+ while (num10 < 3)
+ {
+ CurrentMatrix[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f;
+ index += 4;
+ num9++;
+ }
+ num9++;
+ Label_039C:
+ if (num9 < 4)
+ {
+ goto Label_0358;
+ }
+ continue;
+ Label_03C1:
+ mtx[num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f;
+ index += 4;
+ num9++;
+ Label_03E8:
+ if (num9 < 0x10)
+ {
+ goto Label_03C1;
+ }
+ CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix);
+ continue;
+ Label_0425:
+ num10 = 0;
+ while (num10 < 3)
+ {
+ mtx[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f;
+ index += 4;
+ num9++;
+ }
+ num9++;
+ Label_0466:
+ if (num9 < 4)
+ {
+ goto Label_0425;
+ }
+ CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix);
+ continue;
+ Label_04A2:
+ num10 = 0;
+ while (num10 < 3)
+ {
+ mtx[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f;
+ index += 4;
+ num9++;
+ }
+ num9++;
+ Label_04E3:
+ if (num9 < 3)
+ {
+ goto Label_04A2;
+ }
+ CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix);
+ continue;
+ Label_08E2:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_090F:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_09E1:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_0A0E:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_0ABF:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_0AEC:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_0B9D:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_0BCA:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_0C7B:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_0CA8:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_0DAA:
+ list.Add(new Vector3(v[0], v[1], v[2]));
+ list2.Add(item);
+ list3.Add(vector2);
+ Label_0DD7:
+ if (this.writevertex)
+ {
+ }
+ continue;
+ Label_0E92:
+ num6 = 4;
+ continue;
+ Label_0E97:
+ num6 = 7;
+ continue;
+ Label_0E9C:
+ num6 = 5;
+ continue;
+ Label_0EA1:
+ num6 = 8;
+ continue;
+ Label_0ED1:
+ group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.Triangle, list2.ToArray(), list3.ToArray(), list.ToArray()));
+ goto Label_0F67;
+ Label_0EF6:
+ group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.Quad, list2.ToArray(), list3.ToArray(), list.ToArray()));
+ goto Label_0F67;
+ Label_0F1B:
+ group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.TriangleStrip, list2.ToArray(), list3.ToArray(), list.ToArray()));
+ goto Label_0F67;
+ Label_0F40:
+ group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.QuadStrip, list2.ToArray(), list3.ToArray(), list.ToArray()));
+ Label_0F67:
+ list2.Clear();
+ list.Clear();
+ list3.Clear();
+ gCurrentVertex--;
+ if ((gCurrentVertex < 0) && gOptVertexMode)
+ {
+ return group;
+ }
+ }
+ }
+ }
+ return group;
+ }
+
+ #endregionMethods
+
+ /*------------------------------------------------------------
+ combine texture + palette data obtained from NSBMD / NSBTX files
+ This functions convert all textures of a model into 32-bit bitmap for OpenGL use
+ A model has a number of "materials"; Material means a pair of texture and palette.
+------------------------------------------------------------*/
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDLoader.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDLoader.cs
new file mode 100644
index 0000000..bc2e44c
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDLoader.cs
@@ -0,0 +1,23 @@
+// Loader for NSBMD files.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System.IO;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// Loader for NSBMD data.
+ ///
+ public static class NSBMDLoader
+ {
+ ///
+ /// Load NSBMD from stream.
+ ///
+ /// Stream with NSBMD data.
+ /// NSBMD object.
+ public static NSBMD LoadNSBMD(Stream stream)
+ {
+ return NSBMD.FromStream(stream);
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDMaterial.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDMaterial.cs
new file mode 100644
index 0000000..891bb82
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDMaterial.cs
@@ -0,0 +1,79 @@
+// Material type for NSBMD models.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Drawing;
+using System.Collections.Generic;
+
+namespace LibNDSFormats.NSBMD
+{
+ public class NSBMDMaterial
+ {
+ #regionFields(16)
+
+ public int color0;
+ public int format;
+ public int height;
+ public RGBA[] paldata;
+ public uint palmatid;
+ public string palname = String.Empty;
+ public UInt32 paloffset;
+ public UInt32 palsize;
+ public byte repeat;
+ public byte[] spdata;
+ public byte[] texdata;
+ public List texmatid = new List();
+ public bool isEnvironmentMap = false;
+ public string texname = String.Empty;
+ public UInt32 texoffset;
+ public UInt32 texsize;
+ public int width;
+ public string MaterialName;
+ public int repeatS;
+ public int repeatT;
+ public int flipS;
+ public int flipT;
+ public float rot;
+ public float scaleT;
+ public float scaleS;
+ public float transT;
+ public float transS;
+ public Color DiffuseColor;
+ public Color AmbientColor;
+ public Color SpecularColor;
+ public Color EmissionColor;
+ public uint PolyAttrib;
+ public int Alpha;
+ public bool diffuseColor;
+ public bool shine;
+ public float[] mtx = null;
+
+ #endregionFields
+
+ #regionMethods(1)
+
+ //PublicMethods(1)
+
+ ///
+ /// Copy data to other NSBMD material
+ ///
+ /// Other NSBMD material.
+ public NSBMDMaterial CopyTo(NSBMDMaterial other1)
+ {
+ NSBMDMaterial other = other1;
+ other.texname = texname;
+ other.texoffset = texoffset;
+ other.texsize = texsize;
+ other.format = format;
+ other.color0 = color0;
+ other.width = width;
+ other.height = height;
+ other.texdata = texdata;
+ other.spdata = spdata;
+ other.MaterialName = MaterialName;
+ return other;
+ }
+
+ #endregionMethods
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDModel.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDModel.cs
new file mode 100644
index 0000000..893956a
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDModel.cs
@@ -0,0 +1,56 @@
+// Model definition for NSBMD.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System.Collections.Generic;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// NSBMD model type.
+ ///
+ public class NSBMDModel
+ {
+ #regionFields(3)
+ ///
+ /// NSBMD materials.
+ ///
+ public readonly List Materials = new List();
+ ///
+ /// NSBMD materials.
+ ///
+ public readonly List Textures = new List();
+ ///
+ /// NSBMD materials.
+ ///
+ public readonly List Palettes = new List();
+ ///
+ /// NSBMD objects.
+ ///
+ public readonly List Objects = new List();
+ ///
+ /// NSBMD polygons.
+ ///
+ public readonly List Polygons = new List();
+
+ #endregionFields
+
+ #regionProperties(1)
+
+ ///
+ /// Model name.
+ ///
+ public string Name { get; set; }
+ public List tex_mat = new List();
+ public List pal_mat = new List();
+ public float boundXmin;
+ public float boundYmin;
+ public float boundZmin;
+ public float boundXmax;
+ public float boundYmax;
+ public float boundZmax;
+ public float boundScale;
+ public float modelScale;
+ public int laststackid;
+ #endregionProperties
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDObject.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDObject.cs
new file mode 100644
index 0000000..726999f
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDObject.cs
@@ -0,0 +1,104 @@
+// Object definiton for NSBMD models.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Collections.Generic;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// Type for NSBMD objects.
+ ///
+ public class NSBMDObject
+ {
+ #regionFields(7)
+
+ private readonly float[] _transVect = new float[3];
+ private float _x;
+ private float _y;
+ private float _z;
+ private const float FACTOR1 = 1f;
+ // StackID used by this object
+ public int RestoreID = -1;
+ // rotation
+ public int StackID = -1;
+
+ public bool visible = true;
+
+ public List childs = new List();
+
+ public float[] rotate_mtx = NSBMDGlRenderer.loadIdentity();
+ public float[] scale = new float[3];
+
+ public float[] materix = NSBMDGlRenderer.loadIdentity();
+
+ public bool isBillboard = false;
+ public bool isYBillboard = false;
+
+ #endregionFields
+
+ #regionProperties(12)
+
+ public bool IsRotated { get; set; }
+ public bool IsRotated2 { get; set; }
+
+ public bool IsScaled { get; set; }
+
+ // this object's ParentID object ID
+ public String Name { get; set; }
+
+ public int Neg { get; set; }
+
+ // RestoreID is the ID of the matrix in stack{ get; set; } to be restored as current matrix
+ public int ParentID { get; set; }
+
+ public int Pivot { get; set; }
+
+
+ // applies to rotation matrix
+ public float RotA { get; set; }
+
+ // rotation
+ public float RotB { get; set; }
+
+ // Name of this object
+ public bool Trans { get; set; }
+
+ public float[] TransVect
+ {
+ get { return _transVect; }
+ }
+
+ public float X
+ {
+ get { return _x; }
+ set
+ {
+ _x = value;
+ TransVect[0] = value/FACTOR1;
+ }
+ }
+
+ public float Y
+ {
+ get { return _y; }
+ set
+ {
+ _y = value;
+ TransVect[1] = value/FACTOR1;
+ }
+ }
+
+ public float Z
+ {
+ get { return _z; }
+ set
+ {
+ _z = value;
+ TransVect[2] = value/FACTOR1;
+ }
+ }
+
+ #endregionProperties
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDPalette.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDPalette.cs
new file mode 100644
index 0000000..91da949
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDPalette.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace LibNDSFormats.NSBMD
+{
+ public class NSBMDPalette
+ {
+ public int color0;
+ public RGBA[] paldata;
+ public List palmatid = new List();
+ public string palname = String.Empty;
+ public UInt32 paloffset;
+ public UInt32 palsize;
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDPolygon.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDPolygon.cs
new file mode 100644
index 0000000..3515a4c
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDPolygon.cs
@@ -0,0 +1,41 @@
+// Polygon definition for NSBMD models.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+
+namespace LibNDSFormats.NSBMD
+{
+ ///
+ /// Type for NSBMd polygons.
+ ///
+ public class NSBMDPolygon
+ {
+ #regionProperties(4)
+
+ ///
+ /// Used material ID.
+ ///
+ public int MatId { get; set; }
+
+ ///
+ /// Name of polygon.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Polygon data.
+ ///
+ public byte[] PolyData { get; set; }
+
+ //public UInt32 DataOffset{ get; set; }
+ //public int DataSize{ get; set; }
+ ///
+ /// StackID of polygon.
+ ///
+ public int StackID { get; set; }
+
+ public int JointID { get; set; }
+
+ #endregionProperties
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMDTexture.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMDTexture.cs
new file mode 100644
index 0000000..ef400eb
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBMD/NSBMDTexture.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace LibNDSFormats.NSBMD
+{
+ public class NSBMDTexture
+ {
+ public int format;
+ public int height;
+ public byte repeat;
+ public byte[] spdata;
+ public byte[] texdata;
+ public List texmatid = new List();
+ public string texname = String.Empty;
+ public UInt32 texoffset;
+ public UInt32 texsize;
+ public int width;
+ public int color0;
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTA.cs b/DS_Map/LibNDSFormats/NSBTA.cs
new file mode 100644
index 0000000..3515d0d
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTA.cs
@@ -0,0 +1,335 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Windows.Forms;
+
+namespace MKDS_Course_Editor.NSBTA
+{
+ public class NSBTA
+ {
+ public struct NSBTA_File
+ {
+ public header Header;
+ public struct header
+ {
+ public string ID;
+ public byte[] Magic;
+ public Int32 file_size;
+ public Int16 header_size;
+ public Int16 nSection;
+ public Int32[] Section_Offset;
+ }
+ public srt0 SRT0;
+ public struct srt0 //Scale Rotation and Translation
+ {
+ public string ID;
+ public Int32 Size;
+ //3D Info Structure
+ public byte dummy;
+ public byte num_objs;
+ public short section_size;
+ public UnknownBlock unknownBlock;
+ public Info infoBlock;
+ public string[] names;
+
+ public struct UnknownBlock
+ {
+ public short header_size;
+ public short section_size;
+ public int constant; // 0x017F
+
+ public short[] unknown1;
+ public short[] unknown2;
+ }
+ public struct Info
+ {
+ public short header_size;
+ public short data_size;
+
+ public info[] Data;
+
+ public struct info
+ {
+ public Int32 MAToffset;
+ }
+ }
+ }
+ public M_AT MAT;
+ public struct M_AT
+ {
+ public string ID;
+ public Int16 Unknown1;
+ public byte Unknown2;
+ public byte Unknown3;
+ //3D Info Structure
+ public byte dummy;
+ public byte num_objs;
+ public short section_size;
+ public UnknownBlock unknownBlock;
+ public Info infoBlock;
+ public string[] names;
+
+ public struct UnknownBlock
+ {
+ public short header_size;
+ public short section_size;
+ public int constant; // 0x017F
+
+ public short[] unknown1;
+ public short[] unknown2;
+ }
+ public struct Info
+ {
+ public short header_size;
+ public short data_size;
+
+ public info[] Data;
+
+ public struct info
+ {
+ public Int16[] frame;
+ public Int16[] var1;
+ public Int16[] var2;
+ public Int16[] var3;
+ public int[] frameStep;
+ }
+ }
+ }
+ public srtData[] SRTData;
+ public struct srtData
+ {
+ public decimal[] scaleS;
+ public decimal[] scaleT;
+ public decimal[] rotate;
+ public decimal[] translateS;
+ public decimal[] translateT;
+ }
+ }
+
+ public static NSBTA_File Read(string Filename)
+ {
+ EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(Filename), Endianness.LittleEndian);
+ NSBTA_File ns = new NSBTA_File();
+ ns.Header.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.Header.ID == "BTA0")
+ {
+ ns.Header.Magic = er.ReadBytes(4);
+ ns.Header.file_size = er.ReadInt32();
+ ns.Header.header_size = er.ReadInt16();
+ ns.Header.nSection = er.ReadInt16();
+ ns.Header.Section_Offset = new Int32[ns.Header.nSection];
+ for (int i = 0; i < ns.Header.nSection; i++)
+ {
+ ns.Header.Section_Offset[i] = er.ReadInt32();
+ }
+ ns.SRT0.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.SRT0.ID == "SRT0")
+ {
+ ns.SRT0.Size = er.ReadInt32();
+ //3D Info Structure
+ ns.SRT0.dummy = er.ReadByte();
+ ns.SRT0.num_objs = er.ReadByte();
+ ns.SRT0.section_size = er.ReadInt16();
+ ns.SRT0.unknownBlock.header_size = er.ReadInt16();
+ ns.SRT0.unknownBlock.section_size = er.ReadInt16();
+ ns.SRT0.unknownBlock.constant = er.ReadInt32();
+ ns.SRT0.unknownBlock.unknown1 = new short[ns.SRT0.num_objs];
+ ns.SRT0.unknownBlock.unknown2 = new short[ns.SRT0.num_objs];
+ for (int i = 0; i < ns.SRT0.num_objs; i++)
+ {
+ ns.SRT0.unknownBlock.unknown1[i] = er.ReadInt16();
+ ns.SRT0.unknownBlock.unknown2[i] = er.ReadInt16();
+ }
+
+ ns.SRT0.infoBlock.header_size = er.ReadInt16();
+ ns.SRT0.infoBlock.data_size = er.ReadInt16();
+ ns.SRT0.infoBlock.Data = new NSBTA_File.srt0.Info.info[ns.SRT0.num_objs];
+ for (int i = 0; i < ns.SRT0.num_objs; i++)
+ {
+ ns.SRT0.infoBlock.Data[i].MAToffset = er.ReadInt32();
+ }
+ ns.SRT0.names = new string[ns.SRT0.num_objs];
+ for (int i = 0; i < ns.SRT0.num_objs; i++)
+ {
+ ns.SRT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
+ }
+
+ ns.MAT.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.MAT.ID == "M"+(char)0x00+"AT")
+ {
+ ns.MAT.Unknown1 = er.ReadInt16();
+ ns.MAT.Unknown2 = er.ReadByte();
+ ns.MAT.Unknown3 = er.ReadByte();
+ //3D Info Structure
+ ns.MAT.dummy = er.ReadByte();
+ ns.MAT.num_objs = er.ReadByte();
+ ns.MAT.section_size = er.ReadInt16();
+ ns.MAT.unknownBlock.header_size = er.ReadInt16();
+ ns.MAT.unknownBlock.section_size = er.ReadInt16();
+ ns.MAT.unknownBlock.constant = er.ReadInt32();
+ ns.MAT.unknownBlock.unknown1 = new short[ns.MAT.num_objs];
+ ns.MAT.unknownBlock.unknown2 = new short[ns.MAT.num_objs];
+ for (int i = 0; i < ns.MAT.num_objs; i++)
+ {
+ ns.MAT.unknownBlock.unknown1[i] = er.ReadInt16();
+ ns.MAT.unknownBlock.unknown2[i] = er.ReadInt16();
+ }
+
+ ns.MAT.infoBlock.header_size = er.ReadInt16();
+ ns.MAT.infoBlock.data_size = er.ReadInt16();
+ ns.MAT.infoBlock.Data = new NSBTA_File.M_AT.Info.info[ns.MAT.num_objs];
+ ns.SRTData = new NSBTA_File.srtData[ns.MAT.num_objs];
+ for (int i = 0; i < ns.MAT.num_objs; i++)
+ {
+ ns.MAT.infoBlock.Data[i].frame = new short[5];
+ ns.MAT.infoBlock.Data[i].var1 = new short[5];
+ ns.MAT.infoBlock.Data[i].var2 = new short[5];
+ ns.MAT.infoBlock.Data[i].var3 = new short[5];
+ ns.MAT.infoBlock.Data[i].frameStep = new int[5];
+ for (int j = 0; j < 5; j++)
+ {
+ ns.MAT.infoBlock.Data[i].frame[j] = er.ReadInt16();
+ ns.MAT.infoBlock.Data[i].var1[j] = (short)(er.ReadInt16() / 4096);
+ ns.MAT.infoBlock.Data[i].var2[j] = er.ReadInt16();
+ ns.MAT.infoBlock.Data[i].var3[j] = (short)(er.ReadInt16() / 4096);
+ }
+ if (ns.MAT.infoBlock.Data[i].var1[0] > 1)
+ {
+ ns.SRTData[i].scaleS = new decimal[1];
+ ns.SRTData[i].scaleS[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[0] / 4096);
+ }
+ else
+ {
+ ns.SRTData[i].scaleS = new decimal[ns.MAT.infoBlock.Data[i].frame[0]];
+ }
+ if (ns.MAT.infoBlock.Data[i].var1[1] > 1)
+ {
+ ns.SRTData[i].scaleT = new decimal[1];
+ ns.SRTData[i].scaleT[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[1] / 4096);
+ }
+ else
+ {
+ ns.SRTData[i].scaleT = new decimal[ns.MAT.infoBlock.Data[i].frame[1]];
+ }
+ if (ns.MAT.infoBlock.Data[i].var1[2] > 1)
+ {
+ ns.SRTData[i].rotate = new decimal[2];
+ ns.SRTData[i].rotate[0] = ns.MAT.infoBlock.Data[i].var2[2];
+ ns.SRTData[i].rotate[1] = ns.MAT.infoBlock.Data[i].var3[2];
+ }
+ else
+ {
+ ns.SRTData[i].rotate = new decimal[ns.MAT.infoBlock.Data[i].frame[2] * 2];
+ }
+ if (ns.MAT.infoBlock.Data[i].var1[3] > 1)
+ {
+ ns.SRTData[i].translateS = new decimal[1];
+ ns.SRTData[i].translateS[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[3] / 4096);
+ }
+ else
+ {
+ ns.SRTData[i].translateS = new decimal[ns.MAT.infoBlock.Data[i].frame[3]];
+ ns.MAT.infoBlock.Data[i].frameStep[3] = Math.Abs(ns.MAT.infoBlock.Data[i].var1[3] >> 1);
+
+ }
+ if (ns.MAT.infoBlock.Data[i].var1[4] > 1)
+ {
+ ns.SRTData[i].translateT = new decimal[1];
+ ns.SRTData[i].translateT[0] = Math.Abs(ns.MAT.infoBlock.Data[i].var2[4] / 4096);
+ }
+ else
+ {
+ ns.SRTData[i].translateT = new decimal[ns.MAT.infoBlock.Data[i].frame[4]];
+ ns.MAT.infoBlock.Data[i].frameStep[4] = Math.Abs(ns.MAT.infoBlock.Data[i].var1[4] >> 1);
+ }
+ //ns.SRTData[i].scaleS = new decimal[ns.MAT.infoBlock.Data[i].var1[0] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[0]];
+ //ns.SRTData[i].scaleT = new decimal[ns.MAT.infoBlock.Data[i].var1[1] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[1]];
+ //ns.SRTData[i].rotate = new decimal[ns.MAT.infoBlock.Data[i].var1[2] == 2 ? ns.MAT.infoBlock.Data[i].var1[2] == 3 ? 2 : 1 : ns.MAT.infoBlock.Data[i].frame[2]];
+ //ns.SRTData[i].translateS = new decimal[ns.MAT.infoBlock.Data[i].var1[3] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[3]];
+ //ns.SRTData[i].translateT = new decimal[ns.MAT.infoBlock.Data[i].var1[4] == 3 ? 1 : ns.MAT.infoBlock.Data[i].frame[4]];
+ }
+ ns.MAT.names = new string[ns.MAT.num_objs];
+ for (int i = 0; i < ns.MAT.num_objs; i++)
+ {
+ ns.MAT.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
+ }
+ for (int i = 0; i < ns.MAT.num_objs; i++)
+ {
+ if (ns.SRTData[i].scaleS.Length != 1)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[0] + 8;
+ for (int j = 0; j < ns.SRTData[i].scaleS.Length; j++)
+ {
+ ns.SRTData[i].scaleS[j] = (decimal)(er.ReadInt16() / 4096d);
+ }
+ }
+ if (ns.SRTData[i].scaleT.Length != 1)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[1] + 8;
+ for (int j = 0; j < ns.SRTData[i].scaleT.Length; j++)
+ {
+ ns.SRTData[i].scaleT[j] = (decimal)(er.ReadInt16() / 4096d);
+ }
+ }
+ if (ns.SRTData[i].rotate.Length != 2)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[2] + 8;
+ for (int j = 0; j < ns.SRTData[i].rotate.Length; j++)
+ {
+ ns.SRTData[i].rotate[j] = (decimal)(er.ReadInt16() / 4096d);
+ }
+ }
+ if (ns.SRTData[i].translateS.Length != 1)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[3] + 8;
+
+ for (int j = 0; j < ns.SRTData[i].translateS.Length; j += (ns.MAT.infoBlock.Data[i].frameStep[3] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[3]))
+ {
+ decimal value = (decimal)(er.ReadInt16() / 4096d);
+ for (int k = 0; k < (ns.MAT.infoBlock.Data[i].frameStep[3] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[3]); k++)
+ {
+ ns.SRTData[i].translateS[j + k] = value;
+ }
+ }
+ }
+ if (ns.SRTData[i].translateT.Length != 1)
+ {
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.SRT0.section_size + ns.MAT.infoBlock.Data[i].var2[4] + 8;
+ for (int j = 0; j < ns.SRTData[i].translateT.Length; j +=( ns.MAT.infoBlock.Data[i].frameStep[4] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[4]))
+ {
+ decimal value = (decimal)(er.ReadInt16() / 4096d);
+ for (int k = 0; k < (ns.MAT.infoBlock.Data[i].frameStep[4] == 0 ? 1 : ns.MAT.infoBlock.Data[i].frameStep[4]); k++)
+ {
+ ns.SRTData[i].translateT[j + k] = value;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ }
+ else
+ {
+ MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ }
+ else
+ {
+ MessageBox.Show("Error");
+ er.Close();
+ return ns;
+ }
+ er.Close();
+ return ns;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTP.cs b/DS_Map/LibNDSFormats/NSBTP.cs
new file mode 100644
index 0000000..22aaf16
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTP.cs
@@ -0,0 +1,240 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.IO;
+
+namespace MKDS_Course_Editor.NSBTP
+{
+ public class NSBTP
+ {
+ public struct NSBTP_File
+ {
+ public header Header;
+ public struct header
+ {
+ public string ID;
+ public byte[] Magic;
+ public Int32 file_size;
+ public Int16 header_size;
+ public Int16 nSection;
+ public Int32[] Section_Offset;
+ }
+ public pat0 PAT0;
+ public struct pat0 //Scale Rotation and Translation
+ {
+ public string ID;
+ public Int32 Size;
+ //3D Info Structure
+ public byte dummy;
+ public byte num_objs;
+ public short section_size;
+ public UnknownBlock unknownBlock;
+ public Info infoBlock;
+ public string[] names;
+
+ public struct UnknownBlock
+ {
+ public short header_size;
+ public short section_size;
+ public int constant; // 0x017F
+
+ public short[] unknown1;
+ public short[] unknown2;
+ }
+ public struct Info
+ {
+ public short header_size;
+ public short data_size;
+
+ public info[] Data;
+
+ public struct info
+ {
+ public Int32 MPToffset;
+ }
+ }
+ }
+ public M_PT MPT;
+ public struct M_PT
+ {
+ public string ID;
+ public Int16 NoFrames;
+ public byte NoTex;
+ public byte NoPal;
+ public Int16 Texoffset;
+ public Int16 Paloffset;
+ //3D Info Structure
+ public byte dummy;
+ public byte num_objs;
+ public short section_size;
+ public UnknownBlock unknownBlock;
+ public Info infoBlock;
+ public string[] names;
+
+ public struct UnknownBlock
+ {
+ public short header_size;
+ public short section_size;
+ public int constant; // 0x017F
+
+ public short[] unknown1;
+ public short[] unknown2;
+ }
+ public struct Info
+ {
+ public short header_size;
+ public short data_size;
+
+
+ public info[] Data;
+
+ public struct info
+ {
+ public Int32 KeyFrames;
+ public short Unknown1;
+ public short Offset;
+ }
+ }
+ }
+ public animData[] AnimData;
+ public struct animData
+ {
+ public keyFrame[] KeyFrames;
+ public struct keyFrame
+ {
+ public short Start;
+ public byte texId;
+ public byte palId;
+ public string texName;
+ public string palName;
+ }
+ }
+ }
+ public static NSBTP_File Read(string Filename)
+ {
+ EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(Filename), Endianness.LittleEndian);
+ NSBTP_File ns = new NSBTP_File();
+ ns.Header.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.Header.ID == "BTP0")
+ {
+ ns.Header.Magic = er.ReadBytes(4);
+ ns.Header.file_size = er.ReadInt32();
+ ns.Header.header_size = er.ReadInt16();
+ ns.Header.nSection = er.ReadInt16();
+ ns.Header.Section_Offset = new Int32[ns.Header.nSection];
+ for (int i = 0; i < ns.Header.nSection; i++)
+ {
+ ns.Header.Section_Offset[i] = er.ReadInt32();
+ }
+ ns.PAT0.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.PAT0.ID == "PAT0")
+ {
+ ns.PAT0.Size = er.ReadInt32();
+ //3D Info Structure
+ ns.PAT0.dummy = er.ReadByte();
+ ns.PAT0.num_objs = er.ReadByte();
+ ns.PAT0.section_size = er.ReadInt16();
+ ns.PAT0.unknownBlock.header_size = er.ReadInt16();
+ ns.PAT0.unknownBlock.section_size = er.ReadInt16();
+ ns.PAT0.unknownBlock.constant = er.ReadInt32();
+ ns.PAT0.unknownBlock.unknown1 = new short[ns.PAT0.num_objs];
+ ns.PAT0.unknownBlock.unknown2 = new short[ns.PAT0.num_objs];
+ for (int i = 0; i < ns.PAT0.num_objs; i++)
+ {
+ ns.PAT0.unknownBlock.unknown1[i] = er.ReadInt16();
+ ns.PAT0.unknownBlock.unknown2[i] = er.ReadInt16();
+ }
+
+ ns.PAT0.infoBlock.header_size = er.ReadInt16();
+ ns.PAT0.infoBlock.data_size = er.ReadInt16();
+ ns.PAT0.infoBlock.Data = new NSBTP_File.pat0.Info.info[ns.PAT0.num_objs];
+ for (int i = 0; i < ns.PAT0.num_objs; i++)
+ {
+ ns.PAT0.infoBlock.Data[i].MPToffset = er.ReadInt32();
+ }
+ ns.PAT0.names = new string[ns.PAT0.num_objs];
+ for (int i = 0; i < ns.PAT0.num_objs; i++)
+ {
+ ns.PAT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
+ }
+
+ ns.MPT.ID = er.ReadString(Encoding.ASCII, 4);
+ if (ns.MPT.ID == "M" + (char)0x00 + "PT")
+ {
+ ns.MPT.NoFrames = er.ReadInt16();
+ ns.MPT.NoTex = er.ReadByte();
+ ns.MPT.NoPal = er.ReadByte();
+ ns.MPT.Texoffset = er.ReadInt16();
+ ns.MPT.Paloffset = er.ReadInt16();
+ //3D Info Structure
+ ns.MPT.dummy = er.ReadByte();
+ ns.MPT.num_objs = er.ReadByte();
+ ns.MPT.section_size = er.ReadInt16();
+ ns.MPT.unknownBlock.header_size = er.ReadInt16();
+ ns.MPT.unknownBlock.section_size = er.ReadInt16();
+ ns.MPT.unknownBlock.constant = er.ReadInt32();
+ ns.MPT.unknownBlock.unknown1 = new short[ns.MPT.num_objs];
+ ns.MPT.unknownBlock.unknown2 = new short[ns.MPT.num_objs];
+ for (int i = 0; i < ns.MPT.num_objs; i++)
+ {
+ ns.MPT.unknownBlock.unknown1[i] = er.ReadInt16();
+ ns.MPT.unknownBlock.unknown2[i] = er.ReadInt16();
+ }
+
+ ns.MPT.infoBlock.header_size = er.ReadInt16();
+ ns.MPT.infoBlock.data_size = er.ReadInt16();
+ ns.MPT.infoBlock.Data = new NSBTP_File.M_PT.Info.info[ns.MPT.num_objs];
+ ns.AnimData = new NSBTP_File.animData[ns.MPT.num_objs];
+ for (int i = 0; i < ns.MPT.num_objs; i++)
+ {
+ ns.MPT.infoBlock.Data[i].KeyFrames = er.ReadInt32();
+ ns.MPT.infoBlock.Data[i].Unknown1 = er.ReadInt16();
+ ns.MPT.infoBlock.Data[i].Offset = er.ReadInt16();
+ ns.AnimData[i].KeyFrames = new NSBTP_File.animData.keyFrame[ns.MPT.infoBlock.Data[i].KeyFrames];
+ for (int j = 0; j < ns.MPT.infoBlock.Data[i].KeyFrames; j++)
+ {
+ long curpos = er.BaseStream.Position;
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.infoBlock.Data[i].Offset + j*4 + 8;
+ ns.AnimData[i].KeyFrames[j].Start = er.ReadInt16();
+ ns.AnimData[i].KeyFrames[j].texId = er.ReadByte();
+ ns.AnimData[i].KeyFrames[j].palId = er.ReadByte();
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Texoffset + ns.AnimData[i].KeyFrames[j].texId * 16 + 8;
+ ns.AnimData[i].KeyFrames[j].texName = LibNDSFormats.Utils.ReadNSBMDString(er);
+ er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Paloffset + ns.AnimData[i].KeyFrames[j].palId * 16 + 8;
+ ns.AnimData[i].KeyFrames[j].palName = LibNDSFormats.Utils.ReadNSBMDString(er);
+ er.BaseStream.Position = curpos;
+ }
+ }
+ ns.MPT.names = new string[ns.MPT.num_objs];
+ for (int i = 0; i < ns.MPT.num_objs; i++)
+ {
+ ns.MPT.names[i] = LibNDSFormats.Utils.ReadNSBMDString(er);
+ }
+ }
+ else
+ {
+ MessageBox.Show("NSBTP Error");
+ er.Close();
+ return ns;
+ }
+ }
+ else
+ {
+ MessageBox.Show("NSBTP Error");
+ er.Close();
+ return ns;
+ }
+ }
+ else
+ {
+ MessageBox.Show("NSBTP Error");
+ er.Close();
+ return ns;
+ }
+ er.Close();
+ return ns;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/File.cs b/DS_Map/LibNDSFormats/NSBTX/File.cs
new file mode 100644
index 0000000..4459072
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/File.cs
@@ -0,0 +1,377 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace NSMBe4.DSFileSystem
+{
+ public class File : IComparable
+ {
+ public bool isSystemFile;
+ byte[] file2;
+ protected string nameP;
+ public string name { get { return nameP; } }
+
+ protected int idP;
+ public int id { get { return idP; } }
+
+ protected Directory parentDirP;
+ public Directory parentDir { get { return parentDirP; } }
+
+ //if allocationFile is not null,
+ //these are the offsets within the alloc file where the offsets
+ //of this file are found.
+
+ protected File beginFile;
+ protected int beginOffset;
+ protected File endFile;
+ protected int endOffset;
+ protected bool endIsSize; //means that the end offset is the size of the file
+ protected bool fixedFile; //means that the file cant be moved nor changed size
+
+ public int fileBegin;
+ public int fileSize;
+
+ public int alignment = 4; // word align by default
+ public bool canChangeOffset = true; //false for arm9 and 7 bins
+
+ public Filesystem parent;
+
+ protected Object editedBy = null;
+ public Boolean beingEdited
+ {
+ get { return editedBy != null; }
+ }
+
+ public File(Filesystem parent, Directory parentDir, string name)
+ {
+ this.parent = parent;
+ this.parentDirP = parentDir;
+ this.nameP = name;
+ this.fileBegin = 0;
+ this.fileSize = (int)parent.s.Length;
+ this.isSystemFile = true;
+ }
+
+ public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, File alFile, int alBeg, int alEnd)
+ {
+ this.parent = parent;
+ this.parentDirP = parentDir;
+ this.isSystemFile = systemFile;
+ this.idP = id;
+ this.nameP = name;
+ this.beginFile = alFile;
+ this.endFile = alFile;
+ this.beginOffset = alBeg;
+ this.endOffset = alEnd;
+ refreshOffsets();
+ }
+
+ public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, File alFile, int alBeg, int alEnd, bool endsize)
+ {
+ this.parent = parent;
+ this.parentDirP = parentDir;
+ this.isSystemFile = systemFile;
+ this.idP = id;
+ this.nameP = name;
+ this.beginFile = alFile;
+ this.endFile = alFile;
+ this.beginOffset = alBeg;
+ this.endOffset = alEnd;
+ this.endIsSize = endsize;
+ refreshOffsets();
+ }
+
+ public File(Filesystem parent, Directory parentDir, bool systemFile, int id, string name, int alBeg, int alSize)
+ {
+ this.parent = parent;
+ this.parentDirP = parentDir;
+ this.isSystemFile = systemFile;
+ this.idP = id;
+ this.nameP = name;
+ this.fileBegin = alBeg;
+ this.fileSize = alSize;
+ refreshOffsets();
+ }
+
+ public virtual byte[] getContents()
+ {
+ // enableEdition();
+ byte[] file = new byte[fileSize];
+ parent.s.Seek(fileBegin, SeekOrigin.Begin);
+ parent.s.Read(file, 0, file.Length);
+ return file;
+ }
+
+ public void dumpFile(int ind)
+ {
+ for (int i = 0; i < ind; i++)
+ Console.Out.Write(" ");
+ Console.Out.WriteLine("[" + id + "] " + name + ", at " + fileBegin.ToString("X") + ", size: " + fileSize);
+ }
+
+
+ public virtual void refreshOffsets()
+ {
+ if (beginFile != null)
+ fileBegin = (int)beginFile.getUintAt(beginOffset) + parent.fileDataOffset;
+
+ if (endFile != null)
+ {
+ int end = (int)endFile.getUintAt(endOffset);
+ if (endIsSize)
+ fileSize = (int)end;
+ else
+ fileSize = (int)end + parent.fileDataOffset - fileBegin;
+ }
+ }
+
+ public virtual void saveOffsets()
+ {
+ if (beginFile != null)
+ beginFile.setUintAt(beginOffset, (uint)(fileBegin - parent.fileDataOffset));
+
+ if (endFile != null)
+ if (endIsSize)
+ endFile.setUintAt(endOffset, (uint)fileSize);
+ else
+ endFile.setUintAt(endOffset, (uint)(fileBegin + fileSize - parent.fileDataOffset));
+ }
+
+ public uint getUintAt(int offset)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
+
+ uint res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ res |= (uint)parent.s.ReadByte() << 8 * i;
+ }
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ return res;
+ }
+
+ public void setUintAt(int offset, uint val)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
+ for (int i = 0; i < 4; i++)
+ {
+ parent.s.WriteByte((byte)(val & 0xFF));
+ val >>= 8;
+ }
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ }
+
+ public ushort getUshortAt(int offset)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
+
+ ushort res = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ res |= (ushort)(parent.s.ReadByte() << 8 * i);
+ }
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ return res;
+ }
+
+
+ public void setUshortAt(int offset, ushort val)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offset, SeekOrigin.Begin);
+ for (int i = 0; i < 2; i++)
+ {
+ parent.s.WriteByte((byte)(val & 0xFF));
+ val >>= 8;
+ }
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ }
+
+ public byte getByteAt(int offs)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offs, SeekOrigin.Begin);
+ byte res = (byte)parent.s.ReadByte();
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ return res;
+ }
+
+ public void setByteAt(int offs, byte val)
+ {
+ enableEdition();
+ long pos = parent.s.Position;
+ parent.s.Seek(fileBegin + offs, SeekOrigin.Begin);
+ parent.s.WriteByte(val);
+ parent.s.Seek(pos, SeekOrigin.Begin);
+ }
+
+ public bool isAGoodEditor(object editor)
+ {
+ if (!beingEdited)
+ return false;
+
+ if (editor == editedBy)
+ return true;
+
+ if (editor is InlineFile && inlineEditors.Contains(editor as InlineFile))
+ return true;
+
+ return false;
+ }
+ public virtual void replace(byte[] newFile, object editor)
+ {
+ //if (!isAGoodEditor(editor))
+ // throw new Exception("NOT CORRECT EDITOR " + name);
+
+ if (newFile.Length != fileSize && fixedFile)
+ throw new Exception("TRYING TO RESIZE FIXED FILE: " + name);
+
+ // enableEdition();
+
+ // Console.Out.WriteLine("Replacing: [" + id + "] " + name);
+ int newStart = fileBegin;
+ if (newFile.Length > fileSize) //if we insert a bigger file
+ { //it might not fit in the current place
+ if (canChangeOffset)
+ {
+ newStart = parent.findFreeSpace(newFile.Length, alignment);
+ if (newStart % alignment != 0)
+ newStart += alignment - newStart % alignment;
+ }
+ else
+ {
+ parent.allFiles.Sort();
+ if (!(parent.allFiles.IndexOf(this) == parent.allFiles.Count - 1))
+ {
+ File nextFile = parent.allFiles[parent.allFiles.IndexOf(this) + 1];
+ parent.moveAllFiles(nextFile, fileBegin + newFile.Length);
+ }
+ }
+ }
+ /*else if (parent is NarcFilesystem)
+ {
+ parent.allFiles.Sort();
+ if (!(parent.allFiles.IndexOf(this) == parent.allFiles.Count - 1))
+ {
+ File nextFile = parent.allFiles[parent.allFiles.IndexOf(this) + 1];
+ parent.moveAllFiles(nextFile, fileBegin + newFile.Length);
+ }
+ }*/
+ if (newStart % alignment != 0)
+ Console.Out.Write("Warning: File is not being aligned: " + nameP + ", at " + newStart.ToString("X"));
+ //write the file
+ parent.s.Seek(newStart, SeekOrigin.Begin);
+ parent.s.Write(newFile, 0, newFile.Length);
+ //if (parent is NarcFilesystem)
+ // parent.s.SetLength(parent.allFiles[parent.allFiles.Count - 1].fileBegin + parent.allFiles[parent.allFiles.Count - 1].fileSize + 10);
+ //update ending pos
+ fileBegin = newStart;
+ fileSize = newFile.Length;
+ saveOffsets();
+ parent.fileMoved(this); //NEEDED FOR UPDATING TOTAL USED ROM SIZE IN HEADER
+ }
+
+ public void moveTo(int newOffs)
+ {
+ if (newOffs % alignment != 0)
+ Console.Out.Write("Warning: File is not being aligned: " + nameP + ", at " + newOffs.ToString("X"));
+ byte[] data = getContents();
+ parent.s.Seek(newOffs, SeekOrigin.Begin);
+ parent.s.Write(data, 0, data.Length);
+ fileBegin = newOffs;
+ saveOffsets();
+ }
+
+ public int CompareTo(object obj)
+ {
+ File f = obj as File;
+ if (fileBegin == f.fileBegin)
+ return fileSize.CompareTo(f.fileSize);
+ return fileBegin.CompareTo(f.fileBegin);
+ }
+
+ public virtual void beginEdit(Object editor)
+ {
+ if (beingEdited)
+ throw new Exception();
+ else
+ editedBy = editor;
+ }
+
+ public virtual void endEdit(Object editor)
+ {
+ //if (!beingEdited)
+ // throw new Exception("NOT EDITING FILE " + name);
+ //if (editor != editedBy)
+ // throw new Exception("NOT CORRECT EDITOR" + name);
+
+ editedBy = null;
+ }
+
+ public bool beingEditedBy(Object ed)
+ {
+ return ed == editedBy;
+ }
+
+
+ public bool isAddrInFile(int addr)
+ {
+ return addr >= fileBegin && addr < fileBegin + fileSize;
+ }
+
+ private List inlineEditors = new List();
+
+ public void beginEditInline(InlineFile f)
+ {
+ if (inlineEditors.Count == 0)
+ beginEdit(this);
+
+ inlineEditors.Add(f);
+ }
+
+ public void endEditInline(InlineFile f)
+ {
+ if (!inlineEditors.Contains(f))
+ throw new Exception("ERROR: INLINE FILE");
+ inlineEditors.Remove(f);
+ if (inlineEditors.Count == 0)
+ endEdit(this);
+ }
+
+ //Intended for compressed files like overlays.
+ //Must decompress the file so it's editable and still playable.
+ public virtual void enableEdition() { }
+
+
+ public string getPath()
+ {
+ return parentDir.getPath() + "/" + name;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/Filepallete.cs b/DS_Map/LibNDSFormats/NSBTX/Filepallete.cs
new file mode 100644
index 0000000..f44efb5
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/Filepallete.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NSMBe4.DSFileSystem;
+using System.Drawing;
+
+namespace NSMBe4
+{
+ public class FilePalette : Palette
+ {
+ File f;
+ string name;
+
+ public FilePalette(File f)
+ : this(f, f.name)
+ {
+ }
+
+ public FilePalette(File f, string name)
+ {
+ this.f = f;
+ f.beginEdit(this);
+ this.name = name;
+
+ pal = arrayToPalette(f.getContents());
+ if (pal.Length != 0)
+ {
+ //pal[0] = Color.Transparent;
+ }
+
+ }
+ public static Color[] arrayToPalette(byte[] data)
+ {
+ ByteArrayInputStream ii = new ByteArrayInputStream(data);
+ Color[] pal = new Color[data.Length / 2];
+ for (int i = 0; i < pal.Length; i++)
+ {
+ pal[i] = NSMBTileset.fromRGB15(ii.readUShort());
+ }
+ return pal;
+ }
+
+ public override void save()
+ {
+ ByteArrayOutputStream oo = new ByteArrayOutputStream();
+ for (int i = 0; i < pal.Length; i++)
+ oo.writeUShort(NSMBTileset.toRGB15(pal[i]));
+
+ f.replace(oo.getArray(), this);
+
+ }
+ public override byte[] getRawData()
+ {
+ ByteArrayOutputStream oo = new ByteArrayOutputStream();
+ for (int i = 0; i < pal.Length; i++)
+ oo.writeUShort(NSMBTileset.toRGB15(pal[i]));
+
+ return oo.getArray();
+
+ }
+
+ public override void close()
+ {
+ f.endEdit(this);
+ }
+
+ public override string ToString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs b/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs
new file mode 100644
index 0000000..1d3da4c
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs
@@ -0,0 +1,350 @@
+// Loader for NSBTX files/data.
+// Code adapted from kiwi.ds' NSBMD Model Viewer.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using LibNDSFormats.NSBMD;
+using System.Linq;
+
+namespace LibNDSFormats.NSBTX
+{
+ ///
+ /// Loader for NSBTX files & data.
+ ///
+ public static class NSBTXLoader
+ {
+ #region Methods (2)
+
+ // Public Methods (2)
+
+ ///
+ /// Load NSBTX from stream.
+ ///
+ /// Stream to use.
+ /// Material definitions.
+ public static IEnumerable LoadNsbtx(Stream stream, out List texs, out List pals)
+ {
+ texs = new List();
+ pals = new List();
+ var materials = new List();
+ var reader = new BinaryReader(stream);
+ int id = reader.ReadInt32();
+ if (id != NSBMD.NSBMD.NDS_TYPE_BTX0)
+ throw new Exception();
+ int i = reader.ReadInt32();
+ if (i == NSBMD.NSBMD.NDS_TYPE_MAGIC1)
+ {
+ i = reader.ReadInt32();
+ if (i == stream.Length)
+ {
+ int numblock = reader.ReadInt32();
+ numblock >>= 16;
+ int r = reader.ReadInt32();
+ id = reader.ReadInt32();
+ if (numblock == 1 && r == 0x14)
+ {
+ int texnum;
+ int palnum;
+ materials.AddRange(ReadTex0(stream, 0x14, out texnum, out palnum, out texs, out pals));
+ }
+ }
+ }
+ return materials;
+ }
+
+ ///
+ /// Load NSBTX from file.
+ ///
+ /// File to use.
+ /// Material definitions.
+ public static IEnumerable LoadNsbtx(FileInfo fileInfo, out List texs, out List pals)
+ {
+ texs = new List();
+ pals = new List();
+ IEnumerable result = null;
+ using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open))
+ {
+ result = LoadNsbtx(fileStream, out texs, out pals);
+ }
+ return result;
+ }
+
+ ///
+ /// Load materials in stream.
+ ///
+ /// Stream to use.
+ /// Material definitions.
+ public static IEnumerable ReadTex0(Stream stream, int blockoffset, out int ptexnum, out int ppalnum, out List texs, out List pals)
+ {
+ EndianBinaryReader reader = new EndianBinaryReader(stream, Endianness.LittleEndian);
+ UInt32 blocksize, blockptr, blocklimit;
+ int texnum;
+ UInt32 texdataoffset;
+ int texdatasize;
+ UInt32 sptexoffset; // for 4x4 compressed texels only
+ int sptexsize; // for 4x4 compressed texels only
+ UInt32 spdataoffset; // for 4x4 compressed texels only
+ int palnum;
+ UInt32 paldefoffset;
+ UInt32 paldataoffset;
+ int paldatasize;
+ NSBMDMaterial[] material = null;
+ int i, j;
+ texs = new List();
+ pals = new List();
+
+ blockptr = (uint)(blockoffset + 4); // already read the block ID, so skip 4 bytes
+ blocksize = reader.ReadUInt32(); // block size
+ blocklimit = (uint)(blocksize + blockoffset);
+ Console.WriteLine("DEBUG: blockoffset = {0}, blocksize = {1}", blockoffset, blocksize);
+
+ stream.Skip(4); // skip 4 padding 0s
+ texdatasize = reader.ReadUInt16() << 3; // total texture data size div8
+ stream.Skip(6); // skip 6 bytes
+ texdataoffset = (uint)(reader.ReadUInt32() + blockoffset);
+
+ stream.Skip(4); // skip 4 padding 0s
+ sptexsize = reader.ReadUInt16() << 3; // for format 5 4x4-texel, data size div8
+ stream.Skip(6); // skip 6 bytesmhm
+ sptexoffset = (uint)(reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, data offset
+ spdataoffset = (uint)(reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, palette info
+
+ stream.Skip(4); // skip 4 bytes
+ paldatasize = reader.ReadUInt16() << 3; // total palette data size div8
+ stream.Skip(2); // skip 2 bytes
+ paldefoffset = (uint)(reader.ReadUInt32() + blockoffset);
+ paldataoffset = (uint)(reader.ReadUInt32() + blockoffset);
+
+ // printf( "texdataoffset = %08x texdatasize = %08x\n", texdataoffset, texdatasize );
+ // printf( "sptexoffset = %08x sptexsize = %08x spdataoffset = %08x\n", sptexoffset, sptexsize, spdataoffset );
+ // printf( "paldataoffset = %08x paldatasize = %08x\n", paldataoffset, paldatasize );
+
+ ////////////////////////////////////////////////
+ // texture definition
+
+ stream.Skip(1); // skip dummy '0'
+ texnum = reader.ReadByte(); // no of texture
+ blockptr = (uint)stream.Position;
+ stream.Seek(paldefoffset, SeekOrigin.Begin);
+ stream.Skip(1); // skip dummy '0'
+ palnum = reader.ReadByte(); // no of palette
+ stream.Seek(blockptr, SeekOrigin.Begin);
+
+ Console.WriteLine("texnum = {0}, palnum = {1}", texnum, palnum);
+
+ // allocate memory for material, great enough to hold all texture and palette
+ material = new NSBMDMaterial[(texnum > palnum ? texnum : palnum)];
+ for (i = 0; i < material.Length; i++)
+ material[i] = new NSBMDMaterial();
+
+
+ stream.Skip(14 + (texnum * 4)); // go straight to texture info
+
+ for (i = 0; i < texnum; i++)
+ {
+ UInt32 offset;
+ int param;
+ int format;
+ int width;
+ int height;
+
+ var mat = material[i];
+
+ offset = (uint)(reader.ReadUInt16() << 3);
+ param = reader.ReadUInt16(); // texture parameter
+ stream.Skip(4); // skip 4 bytes
+
+ format = (param >> 10) & 7; // format 0..7, see DSTek
+ width = 8 << ((param >> 4) & 7);
+ height = 8 << ((param >> 7) & 7);
+ mat.color0 = (param >> 13) & 1;
+
+ if (format == 5)
+ mat.texoffset = offset + sptexoffset; // 4x4-Texel Compressed Texture
+ else
+ mat.texoffset = offset + texdataoffset;
+
+ mat.format = format;
+ mat.width = width;
+ mat.height = height;
+ NSBMDTexture t = new NSBMDTexture();
+ t.format = format;
+ t.width = width;
+ t.height = height;
+ t.color0 = (param >> 13) & 1;
+ texs.Add(t);
+ }
+
+ ////////////////////////////////////////////
+ // copy texture names
+ for (i = 0; i < texnum; i++)
+ {
+ material[i].texname = Utils.ReadNSBMDString(reader);
+ reader.BaseStream.Position -= 16;
+ texs[i].texname = Utils.ReadNSBMDString(reader);
+ }
+
+ ////////////////////////////////////////////////
+ // calculate each texture's size
+ for (i = 0; i < texnum; i++)
+ {
+ int[] bpp = { 0, 8, 2, 4, 8, 2, 8, 16 };
+
+ var mat = material[i];
+ mat.texsize = (uint)(mat.width * mat.height * bpp[mat.format] / 8);
+ Console.WriteLine("tex {0} '{1}': offset = {2} size = {3} [W,H] = [{4}, {5}]",
+ i, mat.texname, mat.texoffset, mat.texsize, mat.width, mat.height);
+ texs[i].texsize = (uint)(mat.width * mat.height * bpp[mat.format] / 8);
+ }
+
+ ////////////////////////////////////////////////
+ // palette definition
+ stream.Seek(paldefoffset + 2, SeekOrigin.Begin); // skip palnum, already read
+ stream.Seek(14 + (palnum * 4), SeekOrigin.Current); // go straight to palette info
+ for (i = 0; i < palnum; i++)
+ {
+ uint curOffset = (uint)((reader.ReadUInt16() << 3) + paldataoffset);
+ stream.Seek(2, SeekOrigin.Current); // skip 2 bytes
+ material[i].paloffset = curOffset;
+ NSBMDPalette t = new NSBMDPalette();
+ t.paloffset = curOffset;
+ pals.Add(t);
+ }
+
+ ////////////////////////////////////////////////
+ // copy palette names
+ for (i = 0; i < palnum; i++)
+ {
+ var mat = material[i];
+ mat.palname = Utils.ReadNSBMDString(reader);
+ reader.BaseStream.Position -= 16;
+ pals[i].palname = Utils.ReadNSBMDString(reader);
+ }
+
+ ////////////////////////////////////////////////
+ // calculate each palette's size
+ // assume the palettes are stored sequentially
+ /*for (i = 0; i < palnum - 1; i++)
+ {
+ int r;
+ var mat = material[i];
+ r = i;
+ try { while (material[r].paloffset == mat.paloffset) r++; }
+ catch { }
+ // below is RotA stupid way to calculate the size of palette: next's offset - current's offset
+ // it works most of the time
+ if (r != palnum)
+ {
+ mat.palsize = material[r].paloffset - mat.paloffset;
+ pals[i].palsize = material[r].paloffset - mat.paloffset;
+ }
+ else
+ {
+ mat.palsize = blocklimit - mat.paloffset;
+ pals[i].palsize = blocklimit - mat.paloffset;
+ }
+ //printf("pal '%s' size = %d\n", mat->palname, mat->palsize);
+ }
+ material[i].palsize = blocklimit - material[i].paloffset;
+ pals[i].palsize = blocklimit - material[i].paloffset;*/
+ List offsets = new List();
+ for (int k = 0; k < pals.Count; k++)
+ {
+ if (!offsets.Contains((int)pals[k].paloffset))
+ {
+ offsets.Add((int)pals[k].paloffset);
+ }
+ }
+ offsets.Add((int)blocklimit);
+ offsets.Sort();
+ for (int k = 0; k < pals.Count; k++)
+ {
+ int pallength;
+ int l = -1;
+ do
+ {
+ l++;
+ }
+ while (offsets[l] - pals[k].paloffset <= 0);//nsbtx.PalInfo.infoBlock.PalInfo[i + j].Palette_Offset - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset == 0)
+ pallength = offsets[l] - (int)pals[k].paloffset;
+ //RGBA[] c_ = pals[k].paldata;
+ //List c = new List();
+ //c.AddRange(pals[k].paldata.Take(pallength / 2));
+ //pals[k].paldata = c.ToArray();
+ pals[k].palsize = (uint)pallength;
+ material[k].palsize = (uint)pallength;
+ }
+
+ ////////////////////////////////////////////////
+ // traverse each texture
+ for (i = 0; i < texnum; i++)
+ {
+ var mat = material[i];
+ stream.Seek(mat.texoffset, SeekOrigin.Begin);
+
+ ////////////////////////////////////////////////
+ // read texture into memory
+ byte[] by = reader.ReadBytes((int)mat.texsize);
+ mat.texdata = by;
+ texs[i].texdata = by;
+
+ Console.WriteLine("DEBUG: texoffset = {0}, texsize = {1}", mat.texoffset, mat.texsize);
+
+ ////////////////////////////////////////////////
+ // additional data for format 5 4x4 compressed texels
+ if (mat.format == 5)
+ {
+ UInt32 r = mat.texsize / 2;//>> 1;
+ stream.Seek(spdataoffset + (mat.texoffset - sptexoffset) / 2, SeekOrigin.Begin);
+
+ by = reader.ReadBytes((int)r);
+ mat.spdata = by;
+ texs[i].spdata = by;
+ Console.WriteLine("DEBUG: 4x4-texel spdataoffset = {0}, spdatasize = {1}", spdataoffset, r);
+
+ //spdataoffset += r;
+ }
+ }
+
+
+ ////////////////////////////////////////////////
+ // traverse each palette
+ for (i = 0; i < palnum; i++)
+ {
+ try
+ {
+ NSBMDMaterial mat = material[i];
+ var palentry = mat.palsize >> 1;
+
+ RGBA[] rgbq = new RGBA[palentry];
+
+ Console.WriteLine("DEBUG: converting pal '{0}', palentry = {1}", mat.palname, palentry);
+
+ stream.Seek(mat.paloffset, SeekOrigin.Begin);
+ for (j = 0; j < palentry; j++)
+ {
+ UInt16 p = reader.ReadUInt16();
+ rgbq[j].R = (byte)(((p >> 0) & 0x1f) << 3); // red
+ rgbq[j].G = (byte)(((p >> 5) & 0x1f) << 3); // green
+ rgbq[j].B = (byte)(((p >> 10) & 0x1f) << 3); // blue
+ //rgbq[j].RotA = (p&0x8000) ? 0xff : 0;
+ rgbq[j].A = (p & 0x8000) == 0 ? (byte)0xff : (byte)0;//0xff; // alpha
+ }
+ mat.paldata = rgbq;
+ pals[i].paldata = rgbq;
+ }
+ catch
+ {
+ }
+ }
+
+ ptexnum = texnum;
+ ppalnum = palnum;
+
+ return material;
+ }
+
+ #endregion Methods
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/NSBTX/Rom.cs b/DS_Map/LibNDSFormats/NSBTX/Rom.cs
new file mode 100644
index 0000000..50f57f1
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/Rom.cs
@@ -0,0 +1,665 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NSMBe4.DSFileSystem;
+using System.IO;
+using System.Runtime.InteropServices;
+
+
+/**
+ * This class handles internal NSMB-specific data in the ROM.
+ * Right now it can decompress the Overlay data and read
+ * data from several tables contained in the ROM.
+ *
+ * Data description about overlay 0: (From an old text file)
+ * 76 max tilesets. Each table is 0x130 big.
+ *
+ * 2F8E4: Object definition indexes (unt+hd) table
+ * 2FA14: Object definitions (unt) table
+ * 2FB44: Tile behaviours (chk) table
+ * 2FC74: Animated tileset graphics (ncg) table
+ * 2FDA4: Jyotyu tile behaviour file
+ * 30D74: Background graphics (ncg) table
+ * 30EA4: Tileset graphics (ncg) table
+ * 30FD4: Foreground graphics (ncg) table
+ * 31104: Foreground design (nsc) table
+ * 31234: Background design (nsc) table
+ * 31364: Background palette (ncl) table
+ * 31494: Tileset palette (ncl) table
+ * 315C4: Foreground palette (ncl) table
+ * 316F4: Map16 (pnl) table
+ *
+ **/
+
+namespace NSMBe4
+{
+ public static class ROM
+ {
+ public static byte[] Overlay0;
+ //public static NitroROMFilesystem FS;
+ public static string filename;
+ public static System.IO.FileInfo romfile;
+ public static Dictionary> descriptions;
+ public static string DescriptionPath;
+
+ /*public static void load(String filename)
+ {
+ ROM.filename = filename;
+ FS = new NitroROMFilesystem(filename);
+ romfile = new System.IO.FileInfo(filename);
+
+ LoadDescriptions();
+ LoadOverlay0();
+
+ if (Overlay0 != null)
+ {
+ if (Overlay0[28] == 0x84)
+ Region = Origin.US;
+ else if (Overlay0[28] == 0x64)
+ Region = Origin.EU;
+ else if (Overlay0[28] == 0x04)
+ Region = Origin.JP;
+ else if (Overlay0[28] == 0xC4)
+ Region = Origin.KR;
+ else
+ {
+ Region = Origin.US;
+ System.Windows.Forms.MessageBox.Show(LanguageManager.Get("General", "UnknownRegion"), LanguageManager.Get("General", "Warning"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
+ }
+ }
+ else
+ {
+ Region = Origin.US;
+ System.Windows.Forms.MessageBox.Show(LanguageManager.Get("General", "UnknownRegion"), LanguageManager.Get("General", "Warning"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
+ }
+
+ // SaveOverlay0();
+ }*/
+
+ //public static void close()
+ //{
+ // if (FS == null) return;
+ // FS.close();
+ //}
+
+ /*public static void SaveOverlay0()
+ {
+ OverlayFile ov = FS.arm9ovs[0];
+ ov.decompress();
+ ov.beginEdit(FS);
+ ov.replace(Overlay0, FS);
+ ov.endEdit(FS);
+ }*/
+
+ /*public static void LoadOverlay0()
+ {
+ if (FS.arm9ovs.Length == 0)
+ return;
+
+ OverlayFile ov = FS.arm9ovs[0];
+ ov.decompress();
+
+ Overlay0 = ov.getContents();
+ }*/
+
+ public static void LoadDescriptions()
+ {
+ DescriptionPath = filename.Substring(0, filename.LastIndexOf('.') + 1) + "txt";
+ descriptions = new Dictionary>();
+ int lineNum = 0;
+ try
+ {
+ if (!System.IO.File.Exists(DescriptionPath)) return;
+ System.IO.StreamReader s = new System.IO.StreamReader(DescriptionPath);
+ List curList = null;
+ while (!s.EndOfStream)
+ {
+ lineNum++;
+ string line = s.ReadLine();
+ if (line != "")
+ {
+ if (line.StartsWith("["))
+ {
+ int num = int.Parse(line.Substring(1, line.Length - 2));
+ descriptions.Add(num, new List());
+ curList = descriptions[num];
+ }
+ else if (curList != null)
+ {
+ curList.Add(line);
+ }
+ }
+ }
+ s.Close();
+ }
+ catch (Exception ex)
+ {
+ System.Windows.Forms.MessageBox.Show("An error occurred while reading tileset descriptions on line " + lineNum.ToString() + ".\n\nThe original error message was:\n" + ex.Message);
+ }
+ }
+
+ public enum Origin
+ {
+ US = 0, EU = 1, JP = 2, KR = 3
+ }
+
+ public static Origin Region = Origin.US;
+
+ public enum Data : int
+ {//
+ Number_FileOffset = 0,
+ Table_TS_UNT_HD = 1,
+ Table_TS_UNT = 2,
+ Table_TS_CHK = 3,
+ Table_TS_ANIM_NCG = 4,
+ Table_BG_NCG = 5,
+ Table_TS_NCG = 6,
+ Table_FG_NCG = 7,
+ Table_FG_NSC = 8,
+ Table_BG_NSC = 9,
+ Table_BG_NCL = 10,
+ Table_TS_NCL = 11,
+ Table_FG_NCL = 12,
+ Table_TS_PNL = 13,
+ Table_Jyotyu_NCL = 14,
+ File_Jyotyu_CHK = 15,
+ File_Modifiers = 16,
+ Table_Sprite_CLASSID = 17,
+ }
+
+ public static int[,] Offsets = {
+ {131, 135, 131, 131}, //File Offset (Overlay Count)
+ {0x2F8E4, 0x2F0F8, 0x2ECE4, 0x2EDA4}, //TS_UNT_HD
+ {0x2FA14, 0x2F228, 0x2EE14, 0x2EED4}, //TS_UNT
+ {0x2FB44, 0x2F358, 0x2EF44, 0x2F004}, //TS_CHK
+ {0x2FC74, 0x2F488, 0x2F074, 0x2F134}, //TS_ANIM_NCG
+ {0x30D74, 0x30588, 0x30174, 0x30234}, //BG_NCG
+ {0x30EA4, 0x306B8, 0x302A4, 0x30364}, //TS_NCG
+ {0x30FD4, 0x307E8, 0x303D4, 0x30494}, //FG_NCG
+ {0x31104, 0x30918, 0x30504, 0x305C4}, //FG_NSC
+ {0x31234, 0x30A48, 0x30634, 0x306F4}, //BG_NSC
+ {0x31364, 0x30B78, 0x30764, 0x30824}, //BG_NCL
+ {0x31494, 0x30CA8, 0x30894, 0x30954}, //TS_NCL
+ {0x315C4, 0x30DD8, 0x309C4, 0x30A84}, //FG_NCL
+ {0x316F4, 0x30F08, 0x30AF4, 0x30BB4}, //TS_PNL
+ {0x30CD8, 0x304EC, 0x300D8, 0x30198}, //Jyotyu_NCL
+ {0x2FDA4, 0x2F5B8, 0x2F1A4, 0x2FC74}, //Jyotyu_CHK
+ {0x2C930, 0x2BDF0, 0x2BD30, 0x2BDF0}, //Modifiers
+ {0x29BD8, 0x00000, 0x00000, 0x00000}, //Sprite Class IDs
+ {0x2CBBC, 0, 0, 0}, //weird table¿?
+ };
+
+ public static int[] FileSizes = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //Don't include tables
+ 0x400, //Jyotyu_CHK
+ 0x288, //Modifiers
+ };
+
+ public static ushort GetFileIDFromTable(int id, Data datatype)
+ {
+ return GetFileIDFromTable(id, GetOffset(datatype));
+ }
+
+ public static ushort GetFileIDFromTable(int id, int tableoffset)
+ {
+ int off = tableoffset + (id << 2);
+ return (ushort)((Overlay0[off] | (Overlay0[off + 1] << 8)) + GetOffset(Data.Number_FileOffset));
+ }
+
+ public static ushort GetClassIDFromTable(int id)
+ {
+ int off = GetOffset(Data.Table_Sprite_CLASSID) + (id << 1);
+ return (ushort)((Overlay0[off] | (Overlay0[off + 1] << 8)));
+ }
+
+ public static void SetFileIDFromTable(int id, Data datatype, ushort fid)
+ {
+ SetFileIDFromTable(id, GetOffset(datatype), fid);
+ }
+
+ public static string getDataForSprite(int id)
+ {
+ int offs = 0x2CBBC + id * 20;
+ string s = "";
+
+ for (int i = 0; i < 20; i++)
+ s += String.Format("{0:X2}", Overlay0[offs++]) + " ";
+
+ return s;
+ }
+
+ public static void SetFileIDFromTable(int id, int tableoffset, ushort fid)
+ {
+ int off = tableoffset + (id << 2);
+ fid -= (ushort)GetOffset(Data.Number_FileOffset);
+ Overlay0[off] = (byte)(fid & 0xFF);
+ Overlay0[off + 1] = (byte)(fid >> 8);
+ }
+
+ public static int GetOffset(Data datatype)
+ {
+ return Offsets[(int)datatype, (int)Region];
+ }
+
+ public static byte[] GetInlineFile(Data datatype)
+ {
+ byte[] output = new byte[FileSizes[(int)datatype]];
+ Array.Copy(Overlay0, GetOffset(datatype), output, 0, output.Length);
+ return output;
+ }
+
+ //public static void ReplaceInlineFile(Data datatype, byte[] NewFile)
+ //{
+ // Array.Copy(NewFile, 0, Overlay0, GetOffset(datatype), NewFile.Length);
+ // SaveOverlay0();
+ //}
+
+ public static byte[] DecompressOverlay(byte[] sourcedata)
+ {
+ uint DataVar1, DataVar2;
+ //uint last 8-5 bytes
+ DataVar1 = (uint)(sourcedata[sourcedata.Length - 8] | (sourcedata[sourcedata.Length - 7] << 8) | (sourcedata[sourcedata.Length - 6] << 16) | (sourcedata[sourcedata.Length - 5] << 24));
+ //uint last 4 bytes
+ DataVar2 = (uint)(sourcedata[sourcedata.Length - 4] | (sourcedata[sourcedata.Length - 3] << 8) | (sourcedata[sourcedata.Length - 2] << 16) | (sourcedata[sourcedata.Length - 1] << 24));
+
+ byte[] memory = new byte[sourcedata.Length + DataVar2];
+ sourcedata.CopyTo(memory, 0);
+
+ uint r0, r1, r2, r3, r5, r6, r7, r12;
+ bool N, V;
+ r0 = (uint)sourcedata.Length;
+
+ if (r0 == 0)
+ {
+ return null;
+ }
+ r1 = DataVar1;
+ r2 = DataVar2;
+ r2 = r0 + r2; //length + datavar2 -> decompressed length
+ r3 = r0 - (r1 >> 0x18); //delete the latest 3 bits??
+ r1 &= 0xFFFFFF; //save the latest 3 bits
+ r1 = r0 - r1;
+ a958:
+ if (r3 <= r1)
+ { //if r1 is 0 they will be equal
+ goto a9B8; //return the memory buffer
+ }
+ r3 -= 1;
+ r5 = memory[r3];
+ r6 = 8;
+ a968:
+ SubS(out r6, r6, 1, out N, out V);
+ if (N != V)
+ {
+ goto a958;
+ }
+ if ((r5 & 0x80) != 0)
+ {
+ goto a984;
+ }
+ r3 -= 1;
+ r0 = memory[r3];
+ r2 -= 1;
+ memory[r2] = (byte)r0;
+ goto a9AC;
+ a984:
+ r3 -= 1;
+ r12 = memory[r3];
+ r3 -= 1;
+ r7 = memory[r3];
+ r7 |= (r12 << 8);
+ r7 &= 0xFFF;
+ r7 += 2;
+ r12 += 0x20;
+ a99C:
+ r0 = memory[r2 + r7];
+ r2 -= 1;
+ memory[r2] = (byte)r0;
+ SubS(out r12, r12, 0x10, out N, out V);
+ if (N == V)
+ {
+ goto a99C;
+ }
+ a9AC:
+ r5 <<= 1;
+ if (r3 > r1)
+ {
+ goto a968;
+ }
+ a9B8:
+ return memory;
+ }
+
+ private static void SubS(out uint dest, uint v1, uint v2, out bool N, out bool V)
+ {
+ dest = v1 - v2;
+ N = (dest & 2147483648) != 0;
+ V = ((((v1 & 2147483648) != 0) && ((v2 & 2147483648) == 0) && ((dest & 2147483648) == 0)) || ((v1 & 2147483648) == 0) && ((v2 & 2147483648) != 0) && ((dest & 2147483648) != 0));
+ }
+
+ static private unsafe int[] Search(byte* source, int position, int lenght) //Function taken from Nintenlord's compressor. All credits for this code goes to Nintenlord!
+ {
+ int SlidingWindowSize = 4096;
+ int ReadAheadBufferSize = 18;
+
+ if (position >= lenght)
+ return new int[2] { -1, 0 };
+ if ((position < 2) || ((lenght - position) < 2))
+ return new int[2] { 0, 0 };
+
+ List results = new List();
+
+ for (int i = 1; (i < SlidingWindowSize) && (i < position); i++)
+ {
+ if (source[position - (i + 1)] == source[position])
+ {
+ results.Add(i + 1);
+ }
+ }
+ if (results.Count == 0)
+ return new int[2] { 0, 0 };
+
+ int amountOfBytes = 0;
+
+ bool Continue = true;
+ while (amountOfBytes < ReadAheadBufferSize && Continue)
+ {
+ amountOfBytes++;
+ for (int i = results.Count - 1; i >= 0; i--)
+ {
+ if (source[position + amountOfBytes] != source[position - results[i] + (amountOfBytes % results[i])])
+ {
+ if (results.Count > 1)
+ results.RemoveAt(i);
+ else
+ Continue = false;
+ }
+ }
+ }
+ return new int[2] { amountOfBytes, results[0] }; //lenght of data is first, then position
+ }
+
+ static public unsafe byte[] LZ77_Compress(byte[] source, bool header = false)//Function taken from Nintenlord's compressor. All credits for this code goes to Nintenlord!
+ {
+ fixed (byte* pointer = &source[0])
+ {
+ return Compress(pointer, source.Length, header);
+ }
+ }
+
+ static public unsafe byte[] Compress(byte* source, int lenght, bool header = false) //Function taken from Nintenlord's compressor. All credits for this code goes to Nintenlord!
+ {
+ int position = 0;
+ int BlockSize = 8;
+
+ List CompressedData = new List();
+ if (header) //0x37375A4C
+ {
+ CompressedData.Add(0x4C);
+ CompressedData.Add(0x5A);
+ CompressedData.Add(0x37);
+ CompressedData.Add(0x37);
+ }
+ CompressedData.Add(0x10);
+
+ {
+ byte* pointer = (byte*)&lenght;
+ for (int i = 0; i < 3; i++)
+ CompressedData.Add(*(pointer++));
+ }
+
+ while (position < lenght)
+ {
+ byte isCompressed = 0;
+ List tempList = new List();
+
+ for (int i = 0; i < BlockSize; i++)
+ {
+ int[] searchResult = Search(source, position, lenght);
+
+ if (searchResult[0] > 2)
+ {
+ byte add = (byte)((((searchResult[0] - 3) & 0xF) << 4) + (((searchResult[1] - 1) >> 8) & 0xF));
+ tempList.Add(add);
+ add = (byte)((searchResult[1] - 1) & 0xFF);
+ tempList.Add(add);
+ position += searchResult[0];
+ isCompressed |= (byte)(1 << (BlockSize - (i + 1)));
+ }
+ else if (searchResult[0] >= 0)
+ tempList.Add(source[position++]);
+ else
+ break;
+ }
+ CompressedData.Add(isCompressed);
+ CompressedData.AddRange(tempList);
+ }
+ while (CompressedData.Count % 4 != 0)
+ CompressedData.Add(0);
+
+ return CompressedData.ToArray();
+ }
+
+ public static byte[] LZ77_FastCompress(byte[] source)
+ {
+ int DataLen = 4;
+ DataLen += source.Length;
+ DataLen += (int)Math.Ceiling((double)source.Length / 8);
+ byte[] dest = new byte[DataLen];
+
+ dest[0] = 0;
+ dest[1] = (byte)(source.Length & 0xFF);
+ dest[2] = (byte)((source.Length >> 8) & 0xFF);
+ dest[3] = (byte)((source.Length >> 16) & 0xFF);
+
+ int FilePos = 4;
+ int UntilNext = 0;
+
+ for (int SrcPos = 0; SrcPos < source.Length; SrcPos++)
+ {
+ if (UntilNext == 0)
+ {
+ dest[FilePos] = 0;
+ FilePos++;
+ UntilNext = 8;
+ }
+ dest[FilePos] = source[SrcPos];
+ FilePos++;
+ UntilNext -= 1;
+ }
+
+ return dest;
+ }
+
+ public static byte[] LZ77_Decompress(byte[] source)
+ {
+ // This code converted from Elitemap
+ int DataLen;
+ DataLen = source[1] | (source[2] << 8) | (source[3] << 16);
+ byte[] dest = new byte[DataLen];
+ int i, j, xin, xout;
+ xin = 4;
+ xout = 0;
+ int length, offset, windowOffset, data;
+ byte d;
+ while (DataLen > 0)
+ {
+ d = source[xin++];
+ if (d != 0)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ if ((d & 0x80) != 0)
+ {
+ data = ((source[xin] << 8) | source[xin + 1]);
+ xin += 2;
+ length = (data >> 12) + 3;
+ offset = data & 0xFFF;
+ windowOffset = xout - offset - 1;
+ for (j = 0; j < length; j++)
+ {
+ dest[xout++] = dest[windowOffset++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ }
+ else
+ {
+ dest[xout++] = source[xin++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ d <<= 1;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 8; i++)
+ {
+ dest[xout++] = source[xin++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ }
+ }
+ return dest;
+ }
+
+ public static byte[] LZ77_DecompressWithHeader(byte[] source)
+ {
+ // This code converted from Elitemap
+ int DataLen;
+ DataLen = source[5] | (source[6] << 8) | (source[7] << 16);
+ byte[] dest = new byte[DataLen];
+ int i, j, xin, xout;
+ xin = 8;
+ xout = 0;
+ int length, offset, windowOffset, data;
+ byte d;
+ while (DataLen > 0)
+ {
+ d = source[xin++];
+ if (d != 0)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ if ((d & 0x80) != 0)
+ {
+ data = ((source[xin] << 8) | source[xin + 1]);
+ xin += 2;
+ length = (data >> 12) + 3;
+ offset = data & 0xFFF;
+ windowOffset = xout - offset - 1;
+ for (j = 0; j < length; j++)
+ {
+ dest[xout++] = dest[windowOffset++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ }
+ else
+ {
+ dest[xout++] = source[xin++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ d <<= 1;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 8; i++)
+ {
+ dest[xout++] = source[xin++];
+ DataLen--;
+ if (DataLen == 0)
+ {
+ return dest;
+ }
+ }
+ }
+ }
+ return dest;
+ }
+
+ private static ushort[] CRC16Table = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+ };
+
+ // from ndstool
+ public static ushort CalcCRC16(byte[] data)
+ {
+ ushort crc = 0xFFFF;
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ crc = (ushort)((crc >> 8) ^ CRC16Table[(crc ^ data[i]) & 0xFF]);
+ }
+
+ return crc;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/bytearrayinputstream.cs b/DS_Map/LibNDSFormats/NSBTX/bytearrayinputstream.cs
new file mode 100644
index 0000000..ce19a32
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/bytearrayinputstream.cs
@@ -0,0 +1,180 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace NSMBe4
+{
+ public class ByteArrayInputStream
+ {
+ private byte[] array;
+ private uint pos = 0, origin = 0;
+ private Stack savedPositions = new Stack();
+
+ public ByteArrayInputStream(byte[] array)
+ {
+ this.array = array;
+ pos = 0;
+ }
+
+ public void setOrigin(uint o)
+ {
+ this.origin = o;
+ }
+
+ public void savePos()
+ {
+ savedPositions.Push(pos);
+ }
+
+ public void loadPos()
+ {
+ pos = savedPositions.Pop();
+ }
+
+ public int available
+ {
+ get
+ {
+ return (int)(array.Length - pos - origin);
+ }
+ }
+
+ public bool lengthAvailable(int len)
+ {
+ return available >= len;
+ }
+
+ public byte readByte()
+ {
+ return array[origin + pos++];
+ }
+
+ public void dumpAsciiData()
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ Console.Out.Write((char)array[i]);
+ if ((i % 60) == 0)
+ Console.Out.WriteLine();
+ }
+ }
+
+ public void write(byte[] data)
+ {
+ Array.Copy(data, 0, array, pos + origin, data.Length);
+ pos += (uint)data.Length;
+ }
+
+ public void writeByte(byte b)
+ {
+ array[origin + pos++] = b;
+ }
+
+ public void seek(uint pos)
+ {
+ this.pos = pos;
+ }
+ public void seek(int pos)
+ {
+ this.pos = (uint)pos;
+ }
+
+ public void skip(uint bytes)
+ {
+ pos += bytes;
+ }
+
+ public byte[] getData()
+ {
+ return array;
+ }
+ public void skipback(uint bytes)
+ {
+ pos -= bytes;
+ }
+
+
+ public uint getPos()
+ {
+ return pos;
+ }
+
+ public ushort readUShort()
+ {
+ pos += 2;
+ return (ushort)(array[pos - 2 + origin] | array[pos - 1 + origin] << 8);
+ }
+
+ public uint readUInt()
+ {
+ uint res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ res |= (uint)readByte() << 8 * i;
+ }
+ return res;
+ }
+ public int readInt()
+ {
+ uint res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ res |= (uint)readByte() << 8 * i;
+ }
+ return (int)res;
+ }
+
+ public long readLong()
+ {
+ long res = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ res |= (long)readByte() << 8 * i;
+ }
+ return res;
+ }
+
+ public void read(byte[] dest)
+ {
+ Array.Copy(array, pos + origin, dest, 0, dest.Length);
+ pos += (uint)(dest.Length);
+ }
+
+ public bool end()
+ {
+ return pos + origin >= array.Length;
+ }
+
+ public string ReadString(int l)
+ {
+ if (l == 0) return ""; // simple error checking
+
+ byte[] arr = new byte[l];
+ read(arr);
+
+ StringBuilder NewStr = new StringBuilder(l);
+ for (int i = 0; i < l; i++)
+ if (arr[i] != 0)
+ NewStr.Append((char)arr[i]);
+
+ return NewStr.ToString().Trim();
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/directory.cs b/DS_Map/LibNDSFormats/NSBTX/directory.cs
new file mode 100644
index 0000000..9669ca2
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/directory.cs
@@ -0,0 +1,76 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace NSMBe4.DSFileSystem
+{
+ public class Directory
+ {
+ private bool isSystemFolderP;
+ public bool isSystemFolder { get { return isSystemFolderP; } }
+
+ private string nameP;
+ public string name { get { return nameP; } }
+
+ private int idP;
+ public int id { get { return idP; } }
+
+ private Directory parentDirP;
+ public Directory parentDir { get { return parentDirP; } }
+
+ public List childrenFiles = new List();
+ public List childrenDirs = new List();
+
+ private Filesystem parent;
+
+ public Directory(Filesystem parent, Directory parentDir, bool system, string name, int id)
+ {
+ this.parent = parent;
+ this.parentDirP = parentDir;
+ this.isSystemFolderP = system;
+ this.nameP = name;
+ this.idP = id;
+ }
+
+ public void dumpFiles()
+ {
+ dumpFiles(2);
+ }
+
+ public void dumpFiles(int ind)
+ {
+ for (int i = 0; i < ind; i++)
+ Console.Out.Write(" ");
+ Console.Out.WriteLine("[DIR" + id + "] " + name);
+ foreach (Directory d in childrenDirs)
+ d.dumpFiles(ind + 4);
+ foreach (File f in childrenFiles)
+ f.dumpFile(ind + 4);
+ }
+
+ public string getPath()
+ {
+ if (parentDir == null)
+ return "FS";
+ else
+ return parentDir.getPath() + "/" + name;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/externalfilesystemsource.cs b/DS_Map/LibNDSFormats/NSBTX/externalfilesystemsource.cs
new file mode 100644
index 0000000..a6af457
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/externalfilesystemsource.cs
@@ -0,0 +1,56 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace NSMBe4.DSFileSystem
+{
+ public class ExternalFilesystemSource : FilesystemSource
+ {
+ public string fileName;
+
+ public ExternalFilesystemSource(string n)
+ {
+ this.fileName = n;
+ }
+
+ public override Stream load()
+ {
+ s = new MemoryStream(System.IO.File.ReadAllBytes(fileName));
+ return s;
+ }
+
+ public override void save()
+ {
+ System.IO.File.WriteAllBytes(fileName,((MemoryStream)s).ToArray());
+ //just do nothing, any modifications are directly written to disk
+ }
+
+ public override void close()
+ {
+ s.Close();
+ }
+
+ public override string getDescription()
+ {
+ return fileName;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/filesystem2.cs b/DS_Map/LibNDSFormats/NSBTX/filesystem2.cs
new file mode 100644
index 0000000..51149ad
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/filesystem2.cs
@@ -0,0 +1,253 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace NSMBe4.DSFileSystem
+{
+ public class Filesystem
+ {
+ protected FilesystemSource source;
+ public List allFiles = new List();
+ public List allDirs = new List();
+ protected Dictionary filesById = new Dictionary();
+ // protected Dictionary filesByName = new Dictionary();
+ protected Dictionary dirsById = new Dictionary();
+ // protected Dictionary dirsByName = new Dictionary();
+ public Stream s;
+ public Directory mainDir;
+ protected File freeSpaceDelimiter;
+ public int fileDataOffset = 0;
+
+ //public FilesystemBrowser viewer;
+
+ public Filesystem(FilesystemSource fs)
+ {
+ this.source = fs;
+ this.s = source.load();
+ }
+
+ public File getFileById(int id)
+ {
+ if (!filesById.ContainsKey(id))
+ return null;
+ return filesById[id];
+ }
+
+ public File getFileByName(string name)
+ {
+ foreach (File f in allFiles)
+ if (!f.isSystemFile && f.name == name)
+ return f;
+
+ return null;
+ }
+
+ public Directory getDirByPath(string path)
+ {
+ string[] shit = path.Split(new char[] { '/' });
+ Directory dir = mainDir;
+ for (int i = 0; i < shit.Length; i++)
+ {
+ Directory newDir = null;
+ foreach (Directory d in dir.childrenDirs)
+ if (d.name == shit[i])
+ {
+ newDir = d;
+ break;
+ }
+ if (newDir == null) return null;
+
+ dir = newDir;
+ }
+ return dir;
+ }
+
+ protected void addFile(File f)
+ {
+ allFiles.Add(f);
+ if (f.id != -1)
+ if (!filesById.ContainsKey(f.id))
+ filesById.Add(f.id, f);
+ // filesByName.Add(f.name, f);
+ }
+
+
+ protected void addDir(Directory d)
+ {
+ allDirs.Add(d);
+ if (d.id != -1)
+ dirsById.Add(d.id, d);
+ // dirsByName.Add(d.name, d);
+ }
+
+ //Tries to find LEN bytes of continuous unused space AFTER the freeSpaceDelimiter (usually fat or fnt)
+ public int findFreeSpace(int len, int align)
+ {
+ allFiles.Sort(); //sort by offset
+
+ File bestSpace = null;
+ int bestSpaceLeft = int.MaxValue;
+
+ for (int i = allFiles.IndexOf(freeSpaceDelimiter); i < allFiles.Count - 1; i++)
+ {
+ int spBegin = allFiles[i].fileBegin + allFiles[i].fileSize; //- 1 + 1;
+ if (spBegin % align != 0)
+ spBegin += align - spBegin % align;
+
+ int spEnd = allFiles[i + 1].fileBegin - 1;
+ if (spEnd % align != 0)
+ spEnd -= spEnd % align;
+ int spSize = spEnd - spBegin + 1;
+ if (spSize >= len)
+ {
+ int spLeft = len - spSize;
+ if (spLeft < bestSpaceLeft && (allFiles[i].fileBegin >= 0x1400000))
+ {
+ bestSpaceLeft = spLeft;
+ bestSpace = allFiles[i];
+ }
+ }
+ }
+
+ if (bestSpace != null)
+ return bestSpace.fileBegin + bestSpace.fileSize + 10;
+ else //if (allFiles[allFiles.Count - 1].fileBegin >= 0x1400000)
+ return allFiles[allFiles.Count - 1].fileBegin + allFiles[allFiles.Count - 1].fileSize + 10;
+ // else
+ // return 0x1400000; //just add the file at the very end
+
+ //The 0x1400000 hack is not needed anymore. We now know what data we were overwriting: the RSA sig.
+ //See http://board.dirbaio.net/thread.php?id=185 for more details...
+ }
+
+ //yeah, i'm tired of looking through the dump myself ;)
+ public bool findErrors()
+ {
+ allFiles.Sort();
+ bool res = false;
+ for (int i = 0; i < allFiles.Count - 1; i++)
+ {
+ int firstEnd = allFiles[i].fileBegin + allFiles[i].fileSize - 1;
+ int secondStart = allFiles[i + 1].fileBegin;
+
+ if (firstEnd >= secondStart)
+ {
+ Console.Out.WriteLine("ERROR: FILES OVERLAP:");
+ allFiles[i].dumpFile(2);
+ allFiles[i + 1].dumpFile(2);
+ res = true;
+ }
+ }
+
+ return res;
+ }
+
+ public void close()
+ {
+ source.close();
+ }
+
+ public void save()
+ {
+ source.save();
+ }
+
+ public void dumpFilesOrdered(TextWriter outs)
+ {
+ allFiles.Sort();
+ foreach (File f in allFiles)
+ outs.WriteLine(f.fileBegin.ToString("X8") + " .. " + (f.fileBegin + f.fileSize - 1).ToString("X8") + ": " + f.getPath());
+ }
+
+ public virtual void fileMoved(File f)
+ {
+ }
+
+ public int getFilesystemEnd()
+ {
+ allFiles.Sort();
+ File lastFile = allFiles[allFiles.Count - 1];
+ int end = lastFile.fileBegin + lastFile.fileSize; //well, 1 byte doesnt matter
+ return end;
+ }
+
+
+
+ public uint readUInt(Stream s)
+ {
+ uint res = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ res |= (uint)s.ReadByte() << 8 * i;
+ }
+ return res;
+ }
+
+
+ public void moveAllFiles(File first, int firstOffs)
+ {
+ allFiles.Sort();
+ Console.Out.WriteLine("Moving file " + first.name);
+ Console.Out.WriteLine("Into " + firstOffs.ToString("X"));
+
+
+ int firstStart = first.fileBegin;
+ int diff = (int)firstOffs - (int)firstStart;
+ Console.Out.WriteLine("DIFF " + diff.ToString("X"));
+ //if (diff < 0)
+ //throw new Exception("DOSADJODJOSAJD");
+ // return;
+
+ //WARNING: I assume all the aligns are powers of 2
+ int maxAlign = 4;
+ for (int i = allFiles.IndexOf(first); i < allFiles.Count; i++)
+ {
+ if (allFiles[i].alignment > maxAlign)
+ maxAlign = allFiles[i].alignment;
+ }
+
+ //To preserve the alignment of all the moved files
+ if (diff % maxAlign != 0)
+ diff += (int)(maxAlign - diff % maxAlign);
+
+
+ int fsEnd = getFilesystemEnd();
+ int toCopy = (int)fsEnd - (int)firstStart;
+ byte[] data = new byte[toCopy];
+
+ s.Seek(firstStart, SeekOrigin.Begin);
+ s.Read(data, 0, toCopy);
+ s.Seek(firstStart + diff, SeekOrigin.Begin);
+ s.Write(data, 0, toCopy);
+
+ for (int i = allFiles.IndexOf(first); i < allFiles.Count; i++)
+ allFiles[i].fileBegin += diff;
+ for (int i = allFiles.IndexOf(first); i < allFiles.Count; i++)
+ allFiles[i].saveOffsets();
+ }
+
+ //public void filesystemModified()
+ //{
+ // if (viewer != null && !viewer.IsDisposed)
+ // viewer.Load(this);
+ //}
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/filesystemsource.cs b/DS_Map/LibNDSFormats/NSBTX/filesystemsource.cs
new file mode 100644
index 0000000..52b4101
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/filesystemsource.cs
@@ -0,0 +1,34 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace NSMBe4.DSFileSystem
+{
+ public abstract class FilesystemSource
+ {
+ protected Stream s;
+
+ public abstract Stream load();
+ public abstract void save();
+ public abstract void close();
+ public abstract string getDescription();
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/image3d.cs b/DS_Map/LibNDSFormats/NSBTX/image3d.cs
new file mode 100644
index 0000000..a91ff63
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/image3d.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NSMBe4.DSFileSystem;
+
+namespace NSMBe4
+{
+ public class Image3D : PixelPalettedImage
+ {
+ private InlineFile f;
+ private byte[] data;
+ public bool color0Transp;
+ public int width, height;
+
+ public byte bpp
+ {
+ get { return bpps[format]; }
+ }
+
+ // 0 1 2 3 4 5 6 7
+ public static byte[] bpps = new byte[] { 0, 8, 2, 4, 8, 2, 8, 16 };
+
+ public static string[] formatNames = {
+ "Error?", //0
+ "A3I5 Translucent", //1
+ "2bpp Paletted", //2
+ "4bpp Paletted", //3
+ "8bpp Paletted",//4
+ "4x4-Texeled",//5
+ "A5I3 Translucent",//6
+ "16-bit Color Texture" //7
+ };
+
+ public Image3D(InlineFile f, bool color0, int width, int height, int format, long offset2)
+ {
+ this.f = f;
+ this.color0Transp = color0;
+ this.color0 = color0;
+ this.width = width;
+ this.height = height;
+ this.format = format;
+ offset = offset2;
+ f.beginEdit(this);
+ data = f.getContents();
+ }
+
+ private int getPixelVal(int x, int y)
+ {
+ int i = x + y * width;
+ if (bpp == 8) return data[i];
+ if (bpp == 16) return data[i * 2] | data[i * 2 + 1] << 8;
+ if (bpp == 4)
+ {
+ int res = data[i / 2];
+ res = res >> ((i % 2) * 4);
+ res &= 0xF;
+ return res;
+ }
+ if (bpp == 2)
+ {
+ int res = data[i / 4];
+ res = res >> ((i % 4) * 2);
+ res &= 0x3;
+ return res;
+ }
+ throw new Exception("Unsupported BPP Value: " + bpp);
+ }
+
+ private void setPixelVal(int x, int y, int v)
+ {
+ int i = x + y * width;
+ if (bpp == 8) data[i] = (byte)v;
+ else if (bpp == 16)
+ {
+ data[i * 2] = (byte)(v & 0xFF);
+ data[i * 2 + 1] = (byte)((v >> 8) & 0xFF);
+ }
+
+ else if (bpp == 4)
+ {
+ int res = data[i / 2];
+ res &= ~(0xF << ((i % 2) * 4));
+ res |= (v & 0xF) << ((i % 2) * 4);
+ data[i / 2] = (byte)res;
+ }
+
+ else if (bpp == 2)
+ {
+ int res = data[i / 4];
+ res &= ~(0xF << ((i % 4) * 2));
+ res |= (v & 0xF) << ((i % 4) * 2);
+ data[i / 4] = (byte)res;
+ }
+ else
+ throw new Exception("Unsupported BPP Value: " + bpp);
+ }
+ public override int getPixel(int x, int y)
+ {
+ if (x < 0 || x >= width) return 0;
+ if (y < 0 || y >= height) return 0;
+ int val = getPixelVal(x, y);
+ if (format == 1) val &= 0x1F;
+ if (format == 6) val &= 0x07;
+ return val;
+ }
+
+ public override void setPixel(int x, int y, int c)
+ {
+ if (x < 0 || x >= width) return;
+ if (y < 0 || y >= height) return;
+ if (format == 1)
+ {
+ c &= 0x1F;
+ c |= getPixelVal(x, y) & (~0x1F);
+ }
+ if (format == 6)
+ {
+ c &= 0x07;
+ c |= getPixelVal(x, y) & (~0x07);
+ }
+
+ setPixelVal(x, y, c);
+ }
+
+ public override int getWidth()
+ {
+ return width;
+ }
+
+ public override int getHeight()
+ {
+ return height;
+ }
+
+ public override byte[] getRawData()
+ {
+ return data;
+ }
+ public override byte[] getRawData5()
+ {
+ return null;
+ }
+ public override void setRawData(byte[] data)
+ {
+ this.data = (byte[])data.Clone();
+ }
+
+ public override void save()
+ {
+ f.replace(data, this);
+ }
+
+ public override void close()
+ {
+ f.endEdit(this);
+ }
+
+
+ public override string ToString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/image3dformat5.cs b/DS_Map/LibNDSFormats/NSBTX/image3dformat5.cs
new file mode 100644
index 0000000..001d0f7
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/image3dformat5.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NSMBe4.DSFileSystem;
+using System.Drawing;
+using NSMBe4.NSBMD;
+
+namespace NSMBe4
+{
+ public class Image3Dformat5 : PalettedImage
+ {
+ InlineFile f;
+ InlineFile f5;
+ byte[] fdata;
+ byte[] f5data;
+
+
+ int width, height;
+ public Image3Dformat5(InlineFile f, InlineFile f5, int width, int height)
+ {
+ this.f = f;
+ this.f5 = f5;
+ f.beginEdit(this);
+ f5.beginEdit(this);
+ this.width = width;
+ this.height = height;
+ offset = f.fileBegin;
+ offset5 = f5.fileBegin;
+ fdata = f.getContents();
+ f5data = f5.getContents();
+ format = 5;
+ }
+
+ public override int getWidth()
+ {
+ return width;
+ }
+
+ public override int getHeight()
+ {
+ return height;
+ }
+
+ public override Bitmap render(Palette p)
+ {
+ int w = getWidth();
+ int h = getHeight();
+
+ Bitmap b = new Bitmap(w, h);
+
+ ByteArrayInputStream f5data = new ByteArrayInputStream(f5.getContents());
+ ByteArrayInputStream data = new ByteArrayInputStream(f.getContents());
+
+ for (uint y = 0; y < h / 4; y++)
+ for (uint x = 0; x < w / 4; x++)
+ {
+ ushort palDat = f5data.readUShort();
+ ushort palOffs = (ushort)((palDat & 0x3FFF) * 2);
+ ushort mode = (ushort)((palDat >> 14) & 3);
+
+ for (uint yy = 0; yy < 4; yy++)
+ {
+ byte row = data.readByte();
+ for (uint xx = 0; xx < 4; xx++)
+ {
+ byte color = (byte)(row >> (byte)(xx * 2));
+ color &= 3;
+ Color col;
+ col = p.getColorSafe(palOffs + color);
+ switch (mode)
+ {
+ case 0:
+ if (color == 3) col = Color.Transparent;
+ break;
+ case 1:
+ if (color == 2) col = ImageTiler.colorMean(p.getColorSafe(palOffs), p.getColorSafe(palOffs + 1), 1, 1);
+ if (color == 3) col = Color.Transparent;
+ break;
+ case 3:
+ if (color == 2) col = ImageTiler.colorMean(p.getColorSafe(palOffs), p.getColorSafe(palOffs + 1), 5, 3);
+ if (color == 3) col = ImageTiler.colorMean(p.getColorSafe(palOffs), p.getColorSafe(palOffs + 1), 3, 5);
+ break;
+ }
+ b.SetPixel((int)x * 4 + (int)xx, (int)y * 4 + (int)yy, col);
+ }
+ }
+ }
+ return b;
+ }
+
+ public override void close()
+ {
+ f.endEdit(this);
+ f5.endEdit(this);
+ }
+
+ public override void replaceWithPal(Bitmap b, Palette p)
+ {
+ throw new InvalidOperationException("Not allowed on these image types!");
+ }
+
+ public override void replaceImgAndPal(Bitmap b, Palette p)
+ {
+ /*ImageTexeler it = new ImageTexeler(b, (int)p.pal.Length / 4);
+
+ f.replace(it.texdata, this);
+ f5.replace(it.f5data, this);
+ fdata = it.texdata;
+ f5data = it.f5data;
+
+ p.pal = it.finalPalette;
+ p.save();*/
+ }
+
+ public override void save()
+ {
+
+ }
+
+ public override byte[] getRawData()
+ {
+ return fdata;
+ }
+ public override byte[] getRawData5()
+ {
+ return f5data;
+ }
+
+ public override void setRawData(byte[] data)
+ {
+ }
+
+ public override string ToString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/imageindexer.cs b/DS_Map/LibNDSFormats/NSBTX/imageindexer.cs
new file mode 100644
index 0000000..71d5a14
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/imageindexer.cs
@@ -0,0 +1,853 @@
+/*
+* This file is part of NSMB Editor 5.
+*
+* NSMB Editor 5 is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* NSMB Editor 5 is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with NSMB Editor 5. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace NSMBe4
+{
+ /**
+ * This is the core of all the image importing.
+ * Takes one or more RGB bitmaps and outputs:
+ * - The image data common to all images. (tiled or non-tiled)
+ * - One palette for each image, so that viewing the image data with
+ * it shows the original image.
+ *
+ * It could still be optimized more, I know.
+ * ~Dirbaio
+ */
+
+ public class ImageIndexer
+ {
+ private List boxes;
+ private Dictionary freqTable;
+ private Dictionary colorTable;
+ public Color[][] palettes;
+ private MultiColor[] multiPalette;
+ private int width, height;
+ private int paletteCount, boxColorCount;
+ private bool useAlpha;
+ private List bl;
+ public Byte[,] imageData;
+
+ public ImageIndexer(List bl, bool useAlpha)
+ : this(bl, 256, useAlpha, 0)
+ {
+ }
+
+ public ImageIndexer(List bl)
+ : this(bl, 256, true, 0)
+ {
+ }
+
+ public ImageIndexer(List bl, int paletteCount, bool useAlpha, int transpCol)
+ {
+ this.bl = bl;
+ this.paletteCount = paletteCount;
+ this.useAlpha = useAlpha;
+
+ boxColorCount = bl.Count * 3;
+ //COMPUTE FREQUENCY TABLE
+
+ freqTable = new Dictionary();
+
+ //Quick check just in case...
+ width = bl[0].Width;
+ height = bl[0].Height;
+ foreach (Bitmap b in bl)
+ {
+ if (b.Width != width || b.Height != height)
+ throw new Exception("Not all images have the same size!!");
+ }
+
+
+ for (int x = 0; x < width; x++)
+ for (int y = 0; y < height; y++)
+ {
+ MultiColor c = new MultiColor(boxColorCount);
+ for (int i = 0; i < bl.Count; i++)
+ {
+ NSMBe4.NSBMD.ImageTexeler.LockBitmap iii = new NSBMD.ImageTexeler.LockBitmap(bl[i]);
+ iii.LockBits();
+ c.setColor(i, iii.GetPixel(x, y));
+ iii.UnlockBits();
+ }
+ c.calcHash();
+ if (!c.allTransparent())
+ if (freqTable.ContainsKey(c))
+ freqTable[c]++;
+ else
+ freqTable[c] = 1;
+ }
+
+ int ct = 0;
+ foreach (MultiColor c in freqTable.Keys)
+ if (c.someTransparent()) ct++;
+ Console.Out.WriteLine("Transparent: " + ct);
+
+
+ Dictionary newFreqTable = new Dictionary();
+ foreach (MultiColor c in freqTable.Keys)
+ {
+ if (!c.deleteFlag)
+ {
+ int cnt = freqTable[c];
+ foreach (MultiColor c2 in freqTable.Keys)
+ {
+ if (c2 == null) continue;
+ if (c2.deleteFlag) continue;
+ if (c2 == c) continue;
+
+ if (c.diff(c2) == 0)
+ {
+ cnt += freqTable[c2];
+ c.merge(c2);
+ c2.deleteFlag = true;
+ }
+ }
+ c.deleteFlag = true;
+ c.removeAllTransparent();
+ newFreqTable.Add(c, cnt);
+ }
+ }
+ freqTable = newFreqTable;
+
+ ct = 0;
+ foreach (MultiColor c in freqTable.Keys)
+ if (c.someTransparent()) ct++;
+ Console.Out.WriteLine("Transparent2: " + ct);
+
+ // NOW CREATE THE PALETTE ZONES
+ Box startBox = shrinkBox(new Box(boxColorCount));
+ boxes = new List();
+ boxes.Add(startBox);
+
+ while (boxes.Count < (useAlpha ? paletteCount - 1 : paletteCount))
+ {
+ Console.Out.WriteLine(boxes.Count);
+ Box bo = getDominantBox();
+ if (bo == null)
+ break;
+
+ split(bo);
+ }
+
+
+ multiPalette = new MultiColor[paletteCount];
+ for (int j = useAlpha ? 1 : 0; j < paletteCount; j++)
+ if ((useAlpha ? j : j + 1) <= boxes.Count)
+ multiPalette[j] = boxes[useAlpha ? j - 1 : j].center();
+
+ //NOW CREATE THE PALETTE COLORS
+ palettes = new Color[bl.Count][];
+ for (int i = 0; i < bl.Count; i++)
+ {
+ palettes[i] = new Color[paletteCount];
+ for (int j = useAlpha ? 1 : 0; j < paletteCount; j++)
+ {
+ if ((useAlpha ? j : j + 1) > boxes.Count)
+ palettes[i][j] = palettes[i][j-1];//Color.Fuchsia;
+ else
+ palettes[i][j] = boxes[useAlpha ? j - 1 : j].center().getColor(i);
+ // Console.Out.WriteLine(i + ": " + boxes[i] + ": "+ palette[i]);
+ }
+ if (useAlpha)
+ palettes[i][0] = Color.Transparent;
+
+ }
+
+ //NOW MAP ORIGINAL COLORS TO PALETTE ENTRIES
+ colorTable = new Dictionary();
+ foreach (MultiColor c in freqTable.Keys)
+ colorTable[c] = closestMultiColor(c);
+
+ //NOW INDEX THE WHOLE IMAGES
+ imageData = new byte[width, height];
+ for (int x = 0; x < width; x++)
+ {
+ for (int y = 0; y < height; y++)
+ {
+ MultiColor c = new MultiColor(boxColorCount);
+ for (int i = 0; i < bl.Count; i++)
+ {
+ NSMBe4.NSBMD.ImageTexeler.LockBitmap iii = new NSBMD.ImageTexeler.LockBitmap(bl[i]);
+ iii.LockBits();
+ c.setColor(i, iii.GetPixel(x, y));
+ iii.UnlockBits();
+ }
+ c.calcHash();
+ if (c.allTransparent())
+ imageData[x, y] = (byte)transpCol;
+ else
+ imageData[x, y] = closestMultiColor(c);
+ }
+ }
+
+ Console.Out.WriteLine("DONE");
+ /*
+
+ }*/
+ }
+
+
+
+
+
+ //PUBLIC DATA-RETRIEVING FUNCTIONS
+ public byte[] getTiledImageData()
+ {
+
+ byte[] palettedImage = new byte[width * height];
+ int tileCount = width * height / 64;
+ int tileWidth = width / 8;
+
+ for (int t = 0; t < tileCount; t++)
+ for (int y = 0; y < 8; y++)
+ for (int x = 0; x < 8; x++)
+ {
+ int tx = (t % tileWidth) * 8;
+ int ty = (int)(t / tileWidth) * 8;
+ palettedImage[t * 64 + y * 8 + x] =
+ imageData[tx + x, ty + y];
+ }
+ return palettedImage;
+ }
+ public byte[] getTiledImageDataPart(int px, int py, int ptx, int pty)
+ {
+
+ byte[] palettedImage = new byte[ptx * pty];
+ int tileCount = ptx * pty / 64;
+ int tileWidth = ptx / 8;
+
+ for (int t = 0; t < tileCount; t++)
+ for (int y = 0; y < 8; y++)
+ for (int x = 0; x < 8; x++)
+ {
+ int tx = (t % tileWidth) * 8;
+ int ty = (int)(t / tileWidth) * 8;
+ palettedImage[t * 64 + y * 8 + x] =
+ imageData[tx + x + px, ty + y + py];
+ }
+ return palettedImage;
+ }
+
+ public Bitmap previewImage(int i)
+ {
+ Bitmap b = new Bitmap(width, height);
+ for (int x = 0; x < width; x++)
+ for (int y = 0; y < height; y++)
+ {
+ b.SetPixel(x, y, palettes[i][imageData[x, y]]);
+ }
+ return b;
+ }
+
+
+
+
+
+ //ALGORITHM CORE
+ private byte closestMultiColor(MultiColor mc)
+ {
+ if (mc.allTransparent()) return 0;
+ else
+ {
+ int best = -1;
+ float bestd = float.PositiveInfinity;
+ for (int i = 0; i < multiPalette.Length; i++)
+ {
+ if (multiPalette[i] == null) continue;
+ float d = mc.diff(multiPalette[i]);
+ if (d < bestd || best == -1)
+ {
+ best = i;
+ bestd = d;
+ }
+ }
+ return (byte)best;
+ }
+ }
+
+ private void split(Box b)
+ {
+ byte dim = b.dominantDimensionNum(freqTable); //0, 1, 2 = r, g, b
+ List values = new List();
+ int total = 0;
+ foreach (MultiColor c in freqTable.Keys)
+ if (b.inside(c))
+ {
+ if (!c.transp[dim])
+ {
+ values.Add(new byteint(c.data[dim], freqTable[c]));
+ total += freqTable[c];
+ }
+ }
+ values.Sort();
+
+ if (values.Count == 0)
+ throw new Exception("WTF?!");
+
+ byte m = median(values, total);
+ if (m == values[0].b)
+ m++;
+
+ Console.Out.Write("Split: " + b + " ");
+ Box nb = new Box(b);
+ nb.setDimMax(dim, (byte)(m - 1));
+ b.setDimMin(dim, m);
+ boxes.Add(shrinkBox(nb));
+ boxes.Remove(b);
+ boxes.Add(shrinkBox(b));
+ // Console.Out.WriteLine(b + " " + nb);
+ }
+
+ private byte median(List values, int total)
+ {
+ //Naive median algorithm
+ //Binary search would be better?
+ int acum = 0;
+ foreach (byteint val in values)
+ {
+ acum += val.i;
+ if (acum * 2 > total)
+ return val.b;
+ }
+ //median is best, not mean!
+ /*
+ int totalval = 0;
+ foreach (byteint val in values)
+ {
+ totalval += val.b;
+ }
+ return (byte)(totalval / total);*/
+
+ throw new Exception("Bad, bad, bad!");
+ }
+
+ private Box getDominantBox()
+ {
+ Box best = null;
+ int bestDim = 0;
+
+ foreach (Box b in boxes)
+ {
+ int dim = b.dominantDimension(freqTable);
+ if ((dim > bestDim || best == null) && b.canSplit(freqTable))
+ {
+ bestDim = dim;
+ best = b;
+ }
+ }
+ return best;
+ }
+
+ private Box shrinkBox(Box b)
+ {
+ byte[] min = (byte[])b.min.Clone();
+ byte[] max = (byte[])b.max.Clone();
+ bool[] def = new bool[b.max.Length];
+
+ foreach (MultiColor c in freqTable.Keys)
+ if (b.inside(c))
+ {
+ for (int i = 0; i < c.data.Length; i++)
+ {
+ if (!c.transp[i])
+ if (def[i])
+ {
+ if (min[i] > c.data[i]) min[i] = c.data[i];
+ if (max[i] < c.data[i]) max[i] = c.data[i];
+ }
+ else
+ {
+ min[i] = c.data[i];
+ max[i] = c.data[i];
+ def[i] = true;
+ }
+ }
+ }
+
+ return new Box(min, max);
+ }
+
+ public static byte reduce(int c)
+ {
+ return (byte)((c >> 3) << 3);
+ }
+
+
+
+
+
+ //HELPER CLASSES
+ private class MultiColor
+ {
+ public byte[] data;
+ public bool[] transp;
+ public bool deleteFlag;
+ public MultiColor(int count)
+ {
+ data = new byte[count];
+ transp = new bool[count];
+ deleteFlag = false;
+ }
+
+ public void setColor(int i, Color c)
+ {
+ transp[i * 3 + 0] = c.A < 128;
+ transp[i * 3 + 1] = c.A < 128;
+ transp[i * 3 + 2] = c.A < 128;
+ if (c.A >= 128)
+ {
+ data[i * 3 + 0] = reduce(c.R);
+ data[i * 3 + 1] = reduce(c.G);
+ data[i * 3 + 2] = reduce(c.B);
+ }
+ else
+ {
+ data[i * 3 + 0] = 0;
+ data[i * 3 + 1] = 255;
+ data[i * 3 + 2] = 255;
+ }
+ }
+
+ public void merge(MultiColor b)
+ {
+ for (int i = 0; i < data.Length; i++)
+ if (transp[i])
+ {
+ transp[i] = b.transp[i];
+ data[i] = b.data[i];
+ }
+ calcHash();
+ }
+
+ public Color getColor(int i)
+ {
+ if (transp[i * 3]) return Color.Transparent;
+ return Color.FromArgb(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
+ }
+
+ public bool allTransparent()
+ {
+ for (int i = 0; i < transp.Length; i += 3)
+ if (!transp[i]) return false;
+ return true;
+ }
+ public bool someTransparent()
+ {
+ for (int i = 0; i < transp.Length; i += 3)
+ if (transp[i]) return true;
+ return false;
+ }
+
+ private int thehash;
+ public void calcHash()
+ {
+ unchecked
+ {
+ const int p = 16777619;
+ int hash = (int)2166136261;
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ hash = (hash ^ data[i]) * p;
+ if (transp[i]) hash++;
+ }
+
+ hash += hash << 13;
+ hash ^= hash >> 7;
+ hash += hash << 3;
+ hash ^= hash >> 17;
+ hash += hash << 5;
+
+ thehash = hash;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return thehash;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is MultiColor)
+ {
+ MultiColor c = obj as MultiColor;
+ if (data.Length != c.data.Length)
+ return false;
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ if (data[i] != c.data[i]) return false;
+ if (transp[i] != c.transp[i]) return false;
+ }
+ return true;
+ }
+ else return false;
+ }
+
+ public float diff(MultiColor b)
+ {
+ float res = 0;
+ for (int i = 0; i < data.Length; i++)
+ if (!transp[i] && !b.transp[i])
+ {
+ float d = data[i] - b.data[i];
+ res += d * d;
+ }
+ return res;
+ }
+
+ internal void removeAllTransparent()
+ {
+ for (int i = 0; i < data.Length; i++)
+ if (transp[i])
+ {
+ transp[i] = false;
+ data[i] = 0;
+ }
+ }
+ }
+
+ private class Box
+ {
+ public byte[] min, max;
+ private bool splittable = false;
+ private bool splittablecached = false;
+ public Box(byte[] min, byte[] max)
+ {
+ this.min = min;
+ this.max = max;
+ }
+
+ public Box(int count)
+ {
+ min = new byte[count];
+ max = new byte[count];
+ for (int i = 0; i < count; i++)
+ {
+ min[i] = 0;
+ max[i] = 255;
+ }
+ }
+
+ public Box(Box b)
+ {
+ this.min = (byte[])b.min.Clone();
+ this.max = (byte[])b.max.Clone();
+ }
+
+ public bool inside(MultiColor c)
+ {
+ for (int i = 0; i < min.Length; i++)
+ {
+ if (c.transp[i]) continue;
+ if (c.data[i] < min[i]) return false;
+ if (c.data[i] > max[i]) return false;
+ }
+ return true;
+ }
+
+ public int dominantDimension(Dictionary freqTable)
+ {
+ int d = dominantDimensionNum(freqTable);
+ if (d == 255) return 0;
+ return max[d] - min[d];
+ }
+
+ public byte dominantDimensionNum(Dictionary freqTable)
+ {
+ int d = -1;
+ int dl = -1;
+ for (int i = 0; i < min.Length; i++)
+ {
+ int il = max[i] - min[i];
+ if (il > dl && canSplitInDim(i, freqTable))
+ {
+ dl = il;
+ d = i;
+ }
+ }
+ return (byte)d;
+ }
+
+ public void setDimMin(byte d, byte a)
+ {
+ min[d] = a;
+ splittablecached = false;
+ }
+ public void setDimMax(byte d, byte a)
+ {
+ max[d] = a;
+ splittablecached = false;
+ }
+
+ public bool canSplitInDim(int i, Dictionary freqTable)
+ {
+ byte data = 0;
+ bool seen = false;
+
+ foreach (MultiColor c in freqTable.Keys)
+ {
+ if (inside(c))
+ {
+ if (!c.transp[i])
+ {
+ if (!seen) //First val we see
+ {
+ seen = true;
+ data = c.data[i];
+ }
+ else
+ {
+ if (data != c.data[i])
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public bool canSplit(Dictionary freqTable)
+ {
+ if (splittablecached) return splittable;
+ else
+ {
+ splittablecached = true;
+ splittable = canSplit2(freqTable);
+ return splittable;
+ }
+ }
+ public bool canSplit2(Dictionary freqTable)
+ {
+ //Whoa... This gets complicated if I have to
+ //take into acount the "don't care" of transparent colors...
+ byte[] data = new byte[min.Length];
+ bool[] seen = new bool[min.Length];
+
+ foreach (MultiColor c in freqTable.Keys)
+ {
+ if (inside(c))
+ {
+ for (int i = 0; i < min.Length; i++)
+ {
+ if (!c.transp[i])
+ {
+ if (!seen[i]) //First val we see
+ {
+ seen[i] = true;
+ data[i] = c.data[i];
+ }
+ else
+ {
+ if (data[i] != c.data[i])
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public MultiColor center()
+ {
+ MultiColor res = new MultiColor(min.Length);
+ for (int i = 0; i < min.Length; i++)
+ res.data[i] = (byte)((min[i] + max[i]) / 2);
+ return res;
+ }
+
+ public override string ToString()
+ {
+ return arr2str(min) + " - " + arr2str(max);
+ // return "("+r1+"-"+r2+","+g1+"-"+g2+","+b1+"-"+b2+")";
+ }
+
+ private string arr2str(byte[] a)
+ {
+ string s = "(" + a[0];
+ for (int i = 1; i < a.Length; i++)
+ s += ", " + a[i];
+ return s + ")";
+ }
+ }
+
+ private class byteint : IComparable
+ {
+ public byte b;
+ public int i;
+ public byteint(byte b, int i)
+ {
+ this.b = b;
+ this.i = i;
+ }
+
+ public int CompareTo(object obj)
+ {
+ byteint bi = obj as byteint;
+ return b.CompareTo(bi.b);
+ }
+
+ public static bool operator <(byteint a, byteint b)
+ {
+ return a.b < b.b;
+ }
+ public static bool operator >(byteint a, byteint b)
+ {
+ return a.b > b.b;
+ }
+
+ public override string ToString()
+ {
+ return "(" + b + ", " + i + ")";
+ }
+ }
+
+
+
+
+
+ //GENERAL PURPOSE FUNCTIONS
+ public static Color[] createPaletteForImage(Bitmap b)
+ {
+ return createPaletteForImage(b, 256, false);
+ }
+
+ public static Color[] createPaletteForImage(Bitmap b, int palLen)
+ {
+ return createPaletteForImage(b, palLen, false);
+ }
+
+ public static Color[] createPaletteForImage(Bitmap b, int palLen, bool alpha)
+ {
+ List bl = new List();
+ bl.Add(b);
+
+ ImageIndexer i = new ImageIndexer(bl, palLen, alpha, 0);
+
+ return i.palettes[0];
+ }
+
+ public static byte[] indexImageWithPalette(Bitmap b, Color[] palette)
+ {
+ //More efficient now.
+ byte[] palettedImage = new byte[b.Width * b.Height];
+ int tileCount = b.Width * b.Height / 64;
+ int tileWidth = b.Width / 8;
+
+ for (int t = 0; t < tileCount; t++)
+ for (int y = 0; y < 8; y++)
+ for (int x = 0; x < 8; x++)
+ {
+ int tx = (t % tileWidth) * 8;
+ int ty = (int)(t / tileWidth) * 8;
+ Color c = b.GetPixel(tx + x, ty + y);
+ if (c.A != 0)
+ {
+ c = Color.FromArgb(c.R, c.G, c.B);
+
+ palettedImage[t * 64 + y * 8 + x] = closest(c, palette);
+ }
+ else
+ palettedImage[t * 64 + y * 8 + x] = 0;
+ }
+
+ return palettedImage;
+ }
+
+ public static byte[] indexImageWithPalette2(Bitmap b, Color[] palette)
+ {
+ //More efficient now.
+ byte[] palettedImage = new byte[b.Width * b.Height];
+ int tileCount = b.Width * b.Height / 64;
+ int tileWidth = b.Width / 8;
+
+ for (int t = 0; t < tileCount; t++)
+ for (int y = 0; y < 8; y++)
+ for (int x = 0; x < 8; x++)
+ {
+ int tx = (t % tileWidth) * 8;
+ int ty = (int)(t / tileWidth) * 8;
+ Color c = b.GetPixel(tx + x, ty + y);
+ if (c.A != 0)
+ {
+ c = Color.FromArgb(c.R, c.G, c.B);
+
+ palettedImage[t * 64 + y * 8 + x] = closest(c, palette);
+ }
+ else
+ palettedImage[t * 64 + y * 8 + x] = 0;
+ }
+
+ return palettedImage;
+ }
+
+ public static float colorDifference(Color a, Color b)
+ {
+ if (a.A != b.A) return float.MaxValue;
+
+ float res = 0;
+ res += (a.R - b.R) * (a.R - b.R) / 40;
+ res += (a.G - b.G) * (a.G - b.G) / 40;
+ res += (a.B - b.B) * (a.B - b.B) / 40;
+
+ if (res > float.MaxValue)
+ return float.MaxValue;
+
+ return res;
+ }
+
+ public static float colorDifferenceWithoutAlpha(Color a, Color b)
+ {
+ int res = 0;
+ res += (a.R - b.R) * (a.R - b.R) / 40;
+ res += (a.G - b.G) * (a.G - b.G) / 40;
+ res += (a.B - b.B) * (a.B - b.B) / 40;
+
+ if (res > float.MaxValue)
+ return float.MaxValue;
+
+ return (ushort)res;
+ }
+
+
+ public static byte closest(Color c, Color[] palette)
+ {
+ int best = 0;
+ float bestDif = colorDifference(c, palette[0]);
+ for (int i = 0; i < palette.Length; i++)
+ {
+ float dif = colorDifference(c, palette[i]);
+ if (dif < bestDif)
+ {
+ bestDif = dif;
+ best = i;
+ }
+ }
+ if (best >= 256)
+ Console.Out.WriteLine("GRAAH");
+ return (byte)best;
+ }
+ }
+}
diff --git a/DS_Map/LibNDSFormats/NSBTX/imagetexeler.cs b/DS_Map/LibNDSFormats/NSBTX/imagetexeler.cs
new file mode 100644
index 0000000..95727a8
--- /dev/null
+++ b/DS_Map/LibNDSFormats/NSBTX/imagetexeler.cs
@@ -0,0 +1,761 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+
+namespace NSMBe4.NSBMD
+{
+ public class ImageTexeler
+ {
+ Bitmap img;
+
+ List palettes;
+
+ List paletteCounts;
+ int[,] paletteNumbers;
+ float[,] paletteDiffs;
+
+ public byte[] f5data, texdata;
+ public Color[] finalPalette;
+
+ /*public ImageTexeler(Bitmap img, int paletteMaxNum)
+ {
+ this.img = img;
+
+ int tx = img.Width / 4;
+ int ty = img.Height / 4;
+ palettes = new Color[tx * ty][];
+ paletteCounts = new int[tx * ty];
+ paletteNumbers = new int[tx, ty];
+ paletteDiffs = new float[tx * ty, tx * ty];
+
+ int palNum = 0;
+ for (int x = 0; x < tx; x++)
+ for (int y = 0; y < ty; y++)
+ {
+ ImageIndexerFast iif = new ImageIndexerFast(img, x * 4, y * 4);
+ palettes[palNum] = iif.palette;
+ paletteNumbers[x, y] = palNum;
+ paletteCounts[palNum] = 1;
+ int similar = calcPaletteDiffs(palNum);
+ /* if (similar != -1)
+ {
+ paletteCounts[palNum] = 0;
+ paletteCounts[similar]++;
+ paletteNumbers[x, y] = similar;
+ }
+
+ palNum++;
+ }
+
+ while (countUsedPalettes() > paletteMaxNum)
+ {
+ Console.Out.WriteLine(countUsedPalettes());
+ int besta = -1;
+ int bestb = -1;
+ float bestDif = float.MaxValue;
+
+
+ //Find the two most similar palettes
+ for (int i = 0; i < palettes.Length; i++)
+ {
+ if (paletteCounts[i] == 0) continue;
+ for (int j = 0; j < palettes.Length; j++)
+ {
+ if (i == j) continue;
+ if (paletteCounts[j] == 0) continue;
+
+ if (paletteDiffs[i, j] < bestDif)
+ {
+ bestDif = paletteDiffs[i, j];
+ besta = j;
+ bestb = i;
+ }
+ }
+ }
+
+ //Merge the Palettes!!!
+ palettes[besta] = palMerge(palettes[besta], palettes[bestb]);
+ calcPaletteDiffs(besta);
+ paletteCounts[besta] += paletteCounts[bestb];
+ paletteCounts[bestb] = 0;
+
+ for (int x = 0; x < tx; x++)
+ for (int y = 0; y < ty; y++)
+ if (paletteNumbers[x, y] == bestb)
+ paletteNumbers[x, y] = besta;
+ }
+
+
+
+ //CREATE THE FINAL PAL
+ int currNum = 0;
+ finalPalette = new Color[paletteMaxNum * 4];
+ int[] newPalNums = new int[palettes.Length];
+ for (int i = 0; i < palettes.Length; i++)
+ {
+ if (paletteCounts[i] != 0)
+ {
+ transparentToTheEnd(palettes[i]);//
+ newPalNums[i] = currNum;
+ Array.Copy(palettes[i], 0, finalPalette, currNum * 4, 4);
+ currNum++;
+ }
+ }
+
+ ByteArrayOutputStream texDat = new ByteArrayOutputStream();
+ ByteArrayOutputStream f5Dat = new ByteArrayOutputStream();
+ for (int y = 0; y < ty; y++)
+ for (int x = 0; x < tx; x++)
+ {
+ //Find out if texel has transparent.
+
+ bool hasTransparent = false;
+ for (int yy = 0; yy < 4; yy++)
+ for (int xx = 0; xx < 4; xx++)
+ {
+ Color coll = img.GetPixel(x * 4 + xx, y * 4 + yy);
+ if (coll.A < 128)
+ hasTransparent = true;
+ }
+
+ //WRITE THE IMAGE DATA
+ for (int yy = 0; yy < 4; yy++)
+ {
+ byte b = 0;
+ byte pow = 1;
+ for (int xx = 0; xx < 4; xx++)
+ {
+ Color coll = img.GetPixel(x * 4 + xx, y * 4 + yy);
+ byte col;
+ if (coll.A < 128)
+ {
+ col = 3;
+ }
+ else
+ {
+ col = (byte)ImageIndexer.closest(coll, palettes[paletteNumbers[x, y]]);
+ if (col == 3) { col = 2; }
+ }
+ b |= (byte)(pow * col);
+ pow *= 4;
+ }
+ texDat.writeByte(b);
+ }
+
+
+ //WRITE THE FORMAT-5 SPECIFIC DATA
+ ushort dat = (ushort)(newPalNums[paletteNumbers[x, y]] * 2);
+ if (!hasTransparent || !ContainsTransparent(img))
+ {
+ dat |= 2 << 14;
+ }
+ f5Dat.writeUShort(dat);
+ }
+
+ f5data = f5Dat.getArray();
+ texdata = texDat.getArray();
+
+ }*/
+ public ImageTexeler(Bitmap img, int paletteMaxNum, ref System.ComponentModel.BackgroundWorker bw, bool color2 = false)
+ {
+ this.color2 = false;
+ color2 = false;
+ //this.color2 = color2;
+ //bool trans = true;//ContainsTransparent(img);
+ Bitmap im = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format64bppPArgb);
+ using (Graphics gr = Graphics.FromImage(im))
+ {
+ gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
+ gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
+ gr.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
+ gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
+ gr.DrawImage(img, 0, 0);
+ }
+ this.img = im;
+ LockBitmap iii = new LockBitmap(img);
+ iii.LockBits();
+ int tx = img.Width / 4;
+ int ty = img.Height / 4;
+ palettes = new List();//[tx * ty][];
+ paletteCounts = new List();//new int[tx * ty];
+ paletteNumbers = new int[tx, ty];
+ paletteDiffs = new float[tx * ty, tx * ty];
+ double add = 18d / (double)(tx * ty);
+ double Progress = 10;
+ int palNum = 0;
+ double percent = 0;
+ double add2 = 100d / (double)(tx * ty);
+ for (int x = 0; x < tx; x++)
+ for (int y = 0; y < ty; y++)
+ {
+
+ Bitmap ni = new Bitmap(4, 4/*, System.Drawing.Imaging.PixelFormat.Format16bppRgb555*/);
+ /*using (Graphics gr = Graphics.FromImage(ni))
+ {
+ //gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+ //gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
+ //gr.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
+ //gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
+ gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;//.AntiAlias;
+ gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
+ gr.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
+ gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
+
+ gr.DrawImage(this.img, new Rectangle(0, 0, 4, 4), new Rectangle(x * 4, y * 4, 4, 4), GraphicsUnit.Pixel);
+ }*/
+ LockBitmap nn = new LockBitmap(ni);
+ nn.LockBits();
+ bool haveTransparent = false;
+ for (int x1 = 0; x1 < 4; x1++)
+ for (int y1 = 0; y1 < 4; y1++)
+ {
+ Color c = iii.GetPixel(x * 4 + x1, y * 4 + y1);
+ nn.SetPixel(x1, y1, c);
+ if (c.A < 128)
+ {
+ haveTransparent = true;
+ //goto end;
+ }
+ }
+ //end:
+ nn.UnlockBits();
+ List