From 7f5a546b0566a17d966710ae9dbecfa301a8df55 Mon Sep 17 00:00:00 2001 From: DavidSM64 Date: Fri, 16 Mar 2018 11:38:26 -0500 Subject: [PATCH] v0.2 Beta build 3 release Version 0.2 (Beta Build 3) Changelog: Changes by Davideesk: * Added more camera modes (Top, Bottom, Left, Right, Front, Back) - Removed Field of View slider to make room for the buttons. That feature was kinda pointless anyway * Added a menu for changing warps (Edit -> Warp), which should make it easier to select a level without having to remember the level id. - Note: Multi-selecting warps doesn't really work at the moment, so you can only change one warp at a time. * 'Drop to Ground' will now find the closest triangle to the y-pos, instead of just selecting the highest point. This may need to be tweaked even more. * Quad64 should now be a 32-bit program again. Changes by aglab2: * The editor should now only save changes you make, instead of just overwriting the entire ROM file * Reordered the level list by in-game courses, instead of by level ID. * Added Kaze's objects from "More Object's patch" to the default object-combo name list. * Various fixes related to saving --- Quad64.csproj | 11 +- src/Forms/EditWarp.Designer.cs | 395 ++++++++++++++++++++ src/Forms/EditWarp.cs | 118 ++++++ src/Forms/EditWarp.resx | 635 +++++++++++++++++++++++++++++++++ src/Forms/MainForm.Designer.cs | 184 +++++++--- src/Forms/MainForm.cs | 336 +++++++++++++---- src/Globals.cs | 1 + src/ROM.cs | 2 +- src/Scripts/CollisionMap.cs | 15 +- src/Scripts/LevelScripts.cs | 1 - src/Viewer/Camera.cs | 163 ++++++++- 11 files changed, 1728 insertions(+), 133 deletions(-) create mode 100644 src/Forms/EditWarp.Designer.cs create mode 100644 src/Forms/EditWarp.cs create mode 100644 src/Forms/EditWarp.resx diff --git a/Quad64.csproj b/Quad64.csproj index 1ecbc06..f38473a 100644 --- a/Quad64.csproj +++ b/Quad64.csproj @@ -41,7 +41,7 @@ true - AnyCPU + x86 pdbonly true bin\Release\ @@ -81,6 +81,12 @@ + + Form + + + EditWarp.cs + Component @@ -207,6 +213,9 @@ + + EditWarp.cs + MainForm.cs diff --git a/src/Forms/EditWarp.Designer.cs b/src/Forms/EditWarp.Designer.cs new file mode 100644 index 0000000..2ef8074 --- /dev/null +++ b/src/Forms/EditWarp.Designer.cs @@ -0,0 +1,395 @@ +namespace Quad64.src.Forms +{ + partial class EditWarp + { + /// + /// 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditWarp)); + this.cancelButton = new System.Windows.Forms.Button(); + this.selectButton = new System.Windows.Forms.Button(); + this.panel_warp_controls = new System.Windows.Forms.Panel(); + this.label7 = new System.Windows.Forms.Label(); + this.w_warpToID = new System.Windows.Forms.NumericUpDown(); + this.label6 = new System.Windows.Forms.Label(); + this.w_selectLevel = new System.Windows.Forms.ComboBox(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.w_areaID = new System.Windows.Forms.NumericUpDown(); + this.w_warpFrom = new System.Windows.Forms.NumericUpDown(); + this.panel_instWarp_controls = new System.Windows.Forms.Panel(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.iw_tz = new System.Windows.Forms.NumericUpDown(); + this.iw_ty = new System.Windows.Forms.NumericUpDown(); + this.iw_tx = new System.Windows.Forms.NumericUpDown(); + this.iw_area = new System.Windows.Forms.NumericUpDown(); + this.iw_trigger = new System.Windows.Forms.NumericUpDown(); + this.panel_warp_controls.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.w_warpToID)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.w_areaID)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.w_warpFrom)).BeginInit(); + this.panel_instWarp_controls.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.iw_tz)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_ty)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_tx)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_area)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_trigger)).BeginInit(); + this.SuspendLayout(); + // + // cancelButton + // + this.cancelButton.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cancelButton.Location = new System.Drawing.Point(225, 192); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(100, 27); + this.cancelButton.TabIndex = 4; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // selectButton + // + this.selectButton.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.selectButton.Location = new System.Drawing.Point(82, 193); + this.selectButton.Name = "selectButton"; + this.selectButton.Size = new System.Drawing.Size(100, 27); + this.selectButton.TabIndex = 3; + this.selectButton.Text = "Save"; + this.selectButton.UseVisualStyleBackColor = true; + this.selectButton.Click += new System.EventHandler(this.selectButton_Click); + // + // panel_warp_controls + // + this.panel_warp_controls.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel_warp_controls.BackColor = System.Drawing.Color.DarkGray; + this.panel_warp_controls.Controls.Add(this.label7); + this.panel_warp_controls.Controls.Add(this.w_warpToID); + this.panel_warp_controls.Controls.Add(this.label6); + this.panel_warp_controls.Controls.Add(this.w_selectLevel); + this.panel_warp_controls.Controls.Add(this.label9); + this.panel_warp_controls.Controls.Add(this.label10); + this.panel_warp_controls.Controls.Add(this.w_areaID); + this.panel_warp_controls.Controls.Add(this.w_warpFrom); + this.panel_warp_controls.Location = new System.Drawing.Point(0, 0); + this.panel_warp_controls.Name = "panel_warp_controls"; + this.panel_warp_controls.Size = new System.Drawing.Size(407, 183); + this.panel_warp_controls.TabIndex = 5; + this.panel_warp_controls.Visible = false; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label7.Location = new System.Drawing.Point(20, 118); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(108, 19); + this.label7.TabIndex = 20; + this.label7.Text = "To Warp ID:"; + // + // w_warpToID + // + this.w_warpToID.Location = new System.Drawing.Point(134, 117); + this.w_warpToID.Maximum = new decimal(new int[] { + 99999, + 0, + 0, + 0}); + this.w_warpToID.Name = "w_warpToID"; + this.w_warpToID.Size = new System.Drawing.Size(74, 20); + this.w_warpToID.TabIndex = 19; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label6.Location = new System.Drawing.Point(38, 64); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(90, 19); + this.label6.TabIndex = 18; + this.label6.Text = "To Level:"; + // + // w_selectLevel + // + this.w_selectLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.w_selectLevel.FormattingEnabled = true; + this.w_selectLevel.Location = new System.Drawing.Point(134, 63); + this.w_selectLevel.Name = "w_selectLevel"; + this.w_selectLevel.Size = new System.Drawing.Size(261, 21); + this.w_selectLevel.TabIndex = 17; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label9.Location = new System.Drawing.Point(47, 91); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(81, 19); + this.label9.TabIndex = 16; + this.label9.Text = "To Area:"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label10.Location = new System.Drawing.Point(103, 25); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(90, 19); + this.label10.TabIndex = 15; + this.label10.Text = "Warp ID: "; + // + // w_areaID + // + this.w_areaID.Location = new System.Drawing.Point(134, 91); + this.w_areaID.Maximum = new decimal(new int[] { + 7, + 0, + 0, + 0}); + this.w_areaID.Name = "w_areaID"; + this.w_areaID.Size = new System.Drawing.Size(74, 20); + this.w_areaID.TabIndex = 11; + // + // w_warpFrom + // + this.w_warpFrom.Location = new System.Drawing.Point(199, 26); + this.w_warpFrom.Maximum = new decimal(new int[] { + 99999, + 0, + 0, + 0}); + this.w_warpFrom.Name = "w_warpFrom"; + this.w_warpFrom.Size = new System.Drawing.Size(99, 20); + this.w_warpFrom.TabIndex = 10; + // + // panel_instWarp_controls + // + this.panel_instWarp_controls.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel_instWarp_controls.BackColor = System.Drawing.Color.DarkGray; + this.panel_instWarp_controls.Controls.Add(this.label5); + this.panel_instWarp_controls.Controls.Add(this.label4); + this.panel_instWarp_controls.Controls.Add(this.label3); + this.panel_instWarp_controls.Controls.Add(this.label2); + this.panel_instWarp_controls.Controls.Add(this.label1); + this.panel_instWarp_controls.Controls.Add(this.iw_tz); + this.panel_instWarp_controls.Controls.Add(this.iw_ty); + this.panel_instWarp_controls.Controls.Add(this.iw_tx); + this.panel_instWarp_controls.Controls.Add(this.iw_area); + this.panel_instWarp_controls.Controls.Add(this.iw_trigger); + this.panel_instWarp_controls.Location = new System.Drawing.Point(0, 0); + this.panel_instWarp_controls.Name = "panel_instWarp_controls"; + this.panel_instWarp_controls.Size = new System.Drawing.Size(407, 183); + this.panel_instWarp_controls.TabIndex = 6; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.Location = new System.Drawing.Point(31, 131); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(189, 19); + this.label5.TabIndex = 9; + this.label5.Text = "Teleport on Z axis: "; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label4.Location = new System.Drawing.Point(31, 105); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(189, 19); + this.label4.TabIndex = 8; + this.label4.Text = "Teleport on Y axis: "; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(31, 80); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(189, 19); + this.label3.TabIndex = 7; + this.label3.Text = "Teleport on X axis: "; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(130, 54); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(90, 19); + this.label2.TabIndex = 6; + this.label2.Text = "To Area: "; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(103, 28); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(117, 19); + this.label1.TabIndex = 5; + this.label1.Text = "Trigger ID: "; + // + // wi_tz + // + this.iw_tz.Location = new System.Drawing.Point(226, 131); + this.iw_tz.Maximum = new decimal(new int[] { + 32767, + 0, + 0, + 0}); + this.iw_tz.Minimum = new decimal(new int[] { + 32768, + 0, + 0, + -2147483648}); + this.iw_tz.Name = "wi_tz"; + this.iw_tz.Size = new System.Drawing.Size(99, 20); + this.iw_tz.TabIndex = 4; + // + // iw_ty + // + this.iw_ty.Location = new System.Drawing.Point(226, 105); + this.iw_ty.Maximum = new decimal(new int[] { + 32767, + 0, + 0, + 0}); + this.iw_ty.Minimum = new decimal(new int[] { + 32768, + 0, + 0, + -2147483648}); + this.iw_ty.Name = "iw_ty"; + this.iw_ty.Size = new System.Drawing.Size(99, 20); + this.iw_ty.TabIndex = 3; + // + // iw_tx + // + this.iw_tx.Location = new System.Drawing.Point(226, 79); + this.iw_tx.Maximum = new decimal(new int[] { + 32767, + 0, + 0, + 0}); + this.iw_tx.Minimum = new decimal(new int[] { + 32768, + 0, + 0, + -2147483648}); + this.iw_tx.Name = "iw_tx"; + this.iw_tx.Size = new System.Drawing.Size(99, 20); + this.iw_tx.TabIndex = 2; + // + // iw_area + // + this.iw_area.Location = new System.Drawing.Point(226, 53); + this.iw_area.Maximum = new decimal(new int[] { + 7, + 0, + 0, + 0}); + this.iw_area.Name = "iw_area"; + this.iw_area.Size = new System.Drawing.Size(99, 20); + this.iw_area.TabIndex = 1; + // + // iw_trigger + // + this.iw_trigger.Location = new System.Drawing.Point(226, 27); + this.iw_trigger.Maximum = new decimal(new int[] { + 3, + 0, + 0, + 0}); + this.iw_trigger.Name = "iw_trigger"; + this.iw_trigger.Size = new System.Drawing.Size(99, 20); + this.iw_trigger.TabIndex = 0; + // + // EditWarp + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(407, 228); + this.Controls.Add(this.panel_instWarp_controls); + this.Controls.Add(this.panel_warp_controls); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.selectButton); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EditWarp"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Edit Warp"; + this.Load += new System.EventHandler(this.EditWarp_Load); + this.panel_warp_controls.ResumeLayout(false); + this.panel_warp_controls.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.w_warpToID)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.w_areaID)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.w_warpFrom)).EndInit(); + this.panel_instWarp_controls.ResumeLayout(false); + this.panel_instWarp_controls.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.iw_tz)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_ty)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_tx)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_area)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.iw_trigger)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button selectButton; + private System.Windows.Forms.Panel panel_warp_controls; + private System.Windows.Forms.Panel panel_instWarp_controls; + private System.Windows.Forms.NumericUpDown iw_trigger; + private System.Windows.Forms.NumericUpDown iw_area; + private System.Windows.Forms.NumericUpDown iw_tz; + private System.Windows.Forms.NumericUpDown iw_ty; + private System.Windows.Forms.NumericUpDown iw_tx; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.NumericUpDown w_areaID; + private System.Windows.Forms.NumericUpDown w_warpFrom; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.ComboBox w_selectLevel; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.NumericUpDown w_warpToID; + } +} \ No newline at end of file diff --git a/src/Forms/EditWarp.cs b/src/Forms/EditWarp.cs new file mode 100644 index 0000000..78a2a08 --- /dev/null +++ b/src/Forms/EditWarp.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Quad64.src.Forms +{ + public partial class EditWarp : Form + { + public byte fromID, toLevel, toArea, toID, triggerID; + public short tX, tY, tZ; + public bool pressedSaved = false; + bool isInstantWarp = false; + List levelIds = new List(); + + public EditWarp(string title, byte fromID, byte toLevel, byte toArea, byte toID) + { + this.fromID = fromID; + this.toLevel = toLevel; + this.toArea = toArea; + this.toID = toID; + isInstantWarp = false; + InitializeComponent(); + Text = title; + } + + public EditWarp(byte triggerID, byte toArea, short teleX, short teleY, short teleZ) + { + this.triggerID = triggerID; + this.toArea = toArea; + tX = teleX; + tY = teleY; + tZ = teleZ; + isInstantWarp = true; + InitializeComponent(); + Text = "Update Instant Warp"; + } + + private void EditWarp_Load(object sender, EventArgs e) + { + if (Globals.useHexadecimal) + { + iw_trigger.Hexadecimal = true; + iw_area.Hexadecimal = true; + iw_tx.Hexadecimal = true; + iw_ty.Hexadecimal = true; + iw_tz.Hexadecimal = true; + + w_areaID.Hexadecimal = true; + w_warpFrom.Hexadecimal = true; + w_warpToID.Hexadecimal = true; + } + + + if (!isInstantWarp) + { + panel_instWarp_controls.Hide(); + panel_warp_controls.Show(); + w_warpFrom.Value = fromID; + w_warpToID.Value = toID; + w_areaID.Value = toArea; + levelIds.Clear(); + foreach (KeyValuePair entry in ROM.Instance.levelIDs) + { + w_selectLevel.Items.Add(entry.Key + " (0x" + entry.Value.ToString("X2") + ")"); + levelIds.Add(entry.Value); + if (entry.Value == toLevel) + { + w_selectLevel.SelectedIndex = w_selectLevel.Items.Count - 1; + } + } + } + else + { + panel_instWarp_controls.Show(); + panel_warp_controls.Hide(); + iw_trigger.Value = triggerID; + iw_area.Value = toArea; + iw_tx.Value = tX; + iw_ty.Value = tY; + iw_tz.Value = tZ; + } + } + + private void cancelButton_Click(object sender, EventArgs e) + { + pressedSaved = false; + Hide(); + } + + private void selectButton_Click(object sender, EventArgs e) + { + if (!isInstantWarp) + { + fromID = (byte)w_warpFrom.Value; + toID = (byte)w_warpToID.Value; + toArea = (byte)w_areaID.Value; + toLevel = (byte)levelIds[w_selectLevel.SelectedIndex]; + } + else + { + panel_instWarp_controls.Show(); + panel_warp_controls.Hide(); + iw_trigger.Value = triggerID; + iw_area.Value = toArea; + iw_tx.Value = tX; + iw_ty.Value = tY; + iw_tz.Value = tZ; + } + pressedSaved = true; + Hide(); + } + } +} diff --git a/src/Forms/EditWarp.resx b/src/Forms/EditWarp.resx new file mode 100644 index 0000000..4969adf --- /dev/null +++ b/src/Forms/EditWarp.resx @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA + IACoJQAA7h4AADg4AAABACAA6DIAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAADCDgAAwg4AAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABixkQAaOVoBk2VBlKuTAlS+mpkBtxiQgAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEbMHABvp2EATMApH4+5hY5rqUXvuW9K78GShovcWjYav2lRAPVS + JwAAAAAAAAAAAAAAAAAAAAAAAAAAADO+CgAdxgAHn8aTVUSTKs1Dayz+fpxk/6B7Z/93NzD9qkkzxs6o + nUnuJwAE300mAAAAAAAAAAAAJ64AAP///wCu0qUlWKc/mUd6N/MtVib/KFkE/1iSLf+bUzL/cwIB/3sW + Ff+URzrtvmJJhdu/txjW//8AxFI3AC6uBwAosAAwTZQ10j9lL/8XaGX/DIGn/yZeOP+DoGb/onpo/2sR + Hf9OJ1n/TyVA/4I3M/2wVD690y8EIMw3EACAv20AiMB4VEtyM/0bWUT/GnCL/xhuj/8oXhn/UpAj/5pN + KP92DRD/OVie/x9nr/9rDyL/mkg+9s6Fb0TMf2sAXLZCAF61RWI0axj/GGN5/wU6tv8cRkP/M2AH/4qm + df+kgnP/eggG/2QvX/8QVcr/RSxi/5ozKPvJc1tNy3BYAIW6dQCBuXBxQmko/zJpNf8gVaL/JVAz/0Ry + IP9LkCX/nk4t/4YpJf+BEh//NCmU/2gJLv+YPTT+yINwWct8ZwBKojAAXq5HfzBjE/8wXQL/Pmwi/zmD + H/+at5v/QV+d/2xJoP+8lpb/mC8g/3QjN/9/AxD/lS0j/8dzXGTKblcAaZNdAHKvYI1BZij/M3YP/4uu + gv9HcpL/VViv/zcyl/9CQan/YVi6/4RSk/+zgHj/kB4R/445Mv/FdF5xxXtoAP///wBstlSahKt4/0+B + hf9cZ7L/QkGY/wAZjP8APJr/AjSl/wsumP9WWLD/cmC2/5ZZf/+zgXP/yn9pfsltUgBF/wADHXNRl2B1 + uf9hYJ7/BAGK/wAbo/8Bi3v/D5uQ/xKvqf8DYo//BQat/xYWp/91drn/gFur/5gqSIBsHHQAAAD/AAQL + 1B9mZd2DaGit4BAPlP8PIpz/Fnxp/w15Vf8Oh23/BVKA/xERqv8fH63+enq83kxM34AlDL4eAAb6AAAA + AADY2OwA///oAjU06Sxtbc+TVlWs6RkfkP8QOoj/DzeT/xshqP9sa7ziV1fUh05M5Cn//+IB8/HiAAAA + AAAAAAAAAAAAAAAAAADKyvcA////BDY15Td2dcqgQkCu7VpYuuRoZ9KORELiLf///wLt7PUAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wB7e/QApKT5CCMi5EY0MuA5///7BMbF8wAAAAAAAAAAAAAA + AAAAAAAAAAAAAPw/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAAAEAAIAB + AADAAwAA8A8AAPw/AAAoAAAAGAAAADAAAAABACAAAAAAAAAJAADCDgAAwg4AAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6seAAD/RgFSkggqrkwKLP8AGgHMNA0AAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADV1dUA7tv0C1q9QGM/ngPWuEQK19NcQWPP4ucLz83NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ60AAACcAAE2tA8yq8ejp3iwaPZus07/xHRV/717 + avfLrqag0kAZKOn//wDQLAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0dEA3tTfEIvGeWswpA3dUHtA/1doS/+tvaH/wa2i/2RPTf+JUUb/wTwZ1NKPfV3N7vUK0dHRAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiMBzAMfKwQImswA3fb5qsYWefPkgVwX/JE4A/zJn + Ev9Qnh7/slYm/2gbFf9qAQD/dBkM/6uMhfTNh3Od0zIIJNcZAADNVTcAAAAAAAAAAAAAAAAAAAAAACKv + AACuz6QAdsJgFLrPs3hCoyXjM28a/y5KJP8jThn/L10D/ytoBv9mrEX/vGtK/2wSCf+GAAD/gAAA/2se + Hv+PNiT+wVE00NPAulfQb1YI0IVyAAAAAAAAAAAAAAAAAC+tCAArrQEuRK8kuYCXePovVhj/GUwy/wx1 + k/8Gfqn/HVU9/05uMf+1wq3/wrSs/2wyL/9yBRf/Xw89/2EYNf9cDBr/di0l/6uLg/LMSyqUzTMMF8w6 + FQAAAAAAAAAAADqyFgA4tRNuN4ge/yhIC/8lWSH/FX+h/yaft/8IjMv/IFxB/ztrGf9boyz/s2E0/2wh + G/92Eh3/K1in/w1ruv81Tn3/ewEG/24cGP+wPyP40D4XVM0+GAAAAAAAzsTJAJfNjACwzad5cYVn/yhQ + Bv8VYnj/FGiA/yBidP8UXIP/LlwI/yZoAv9Upyr/uVkw/2sPBf+HBAT/VE+E/xptzf8cbrX/Zg4v/4UK + C/+le3X70Z6QXM6cjwAAAAAAkcKCAACiAAB6wmWHOnQi/yJYGv8KZbT/BTqy/wo0jP8lUST/L18A/0tv + MP+3xrH/xLSt/2ouK/+FAAD/dy9H/yRNwP8NaM7/IkmV/30KE/+iUkP/z5SEa82NfAAAAAAAM64NABql + AAI5sxWWLG0S/ypXCf8peIj/BT/c/wcmo/8oUBj/L2EA/0dwLP94rlP/uHxZ/20wLf+GAAD/iw4R/zw6 + nf8FOMn/RSVl/4MJD/+eLxn/z0AactE6EgC1al0AmsOMAIK/awSryKKiXnJR/ylTAP88cjD/Nmuk/xxS + ev8tWwz/Smoq/0GQJf82mgr/sj4U/5tEMf9/LCz/iwUE/3YiRf8hKKv/awMn/4wGBf+ZaWX/z6GVg9ut + oADInJEAlcKGALbNrQd8vWmyM2Ud/ypVAP8xYAH/OWkU/y5kC/8weQ7/prqc/26ih/8XPZ7/TB2e/7N7 + jP+3mpH/iyUU/4EUE/9kHkn/dgUc/4sEA/+VSDz/z5iJie8AAADLqaAAMK8KAC+2BQkxqw6+I14K/yxY + AP8tXgH/WnVB/1iaRP8tlDP/pLTF/7W11v85OK7/Q0S2/7y72P+3nbr/sDcw/6JcTv+DOTb/hwcG/4wF + Bf+TJBL/zT0WmcdEIQPLPhkAj8F+AInKdAyXvY3MTmI+/zNiEf8siAv/o8SW/5Ovsf8iNr3/Jye1/0A/ + f/8SEYX/IyOd/1FQn/8qKMP/Ryq3/7ygtP/CkoH/lSYP/38bGP+MVVH/zJGBoNBQMATMemUAo8SXALHL + pxaJvHnUcpZl/4GqfP8jeVT/a3vF/6qoxv9AP4v/AQB7/wAKlv8AE6T/AQew/wgYov8SG5H/Wlyp/7Cy + 0/+FZrX/oDVJ/6qBev+ecGb/zKSZss/MzQfMta8AOrEWADuzFB8qqwnafbZ9/7/F0/9LUcf/DQyZ/xMS + eP8EDJD/AEKZ/wCOkv8BpZb/AIih/wCRnf8DQJP/Fhen/ygom/8WF7X/aFrI/83CzP/Ibl7/zj4Zus9Z + OAjOTSoAJI4uACWWIyEYWHbPKzfO/3Z1vf8/P2X/AQGE/wAAr/8ALLD/AKp2/weNaP8gnKX/Hra2/xG2 + m/8APYf/AACz/wUEtv8ZGaP/aGiW/3Z30P9IKrj/iChbvs49EwqrMzgAEkKRAA9WbgMMCeI0ODfjmpyc + ze1hYZP/Bwd+/wAAmP8HJ7H/Fppq/wiRM/8MXWT/FHB1/xKvbP8ARHH/AQGy/wgIrf8fH6H/fn6o/4GB + 1OkbHeWZIRTNNf+aAAFrMooAAAAAAAAAAADp5MgA7urNB8nI4kFBQeCqICDE8kpKkf8jJIH/GyyR/yRs + cf8GhVX/AHtX/wFLhf8MGaP/ODig/0REq/8aGsztZ2bepOHf3zuOj+MFycngAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAACUABgX4QAAANoKgoHhT7+/3bhMTLz2CgmM/xEShv8FFKb/DBis/xoaov8ZGKr/dXTI8MDA + 36VNTuVBAADiCAcH4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhAGlo + 4BAZGONdY2PaxJGRtPsuLY7/UlGk/5eXxvI/P92uJiTfSry42Al0cNkAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI2N5AD///MA9vPgFoKC5WkcHNrKNDPatre2 + 40zs7OYK///sAAUF1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAIR/VADIvxwEWFd4bHBfXEQAH/wA+JaAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA/8P/AP+B/wD+AP8A/AA/APAAHwDgAAcAwAADAMAAAwDAAAMAwAADAIAA + AwCAAAMAgAADAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAOAABwD4AB8A/gB/AP+B/wD/x/8AKAAAACAA + AABAAAAAAQAgAAAAAAAAEAAAwg4AAMIOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhqEAAAP//AFWQBxC0SAkT/wBDAMs1DQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7QfAEW2KAMvsQw+QZ0EsblEC7XRMw4+z0kkA89E + HgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtrulAGR7IgDb0NsXq8uhfD61HOY7owX/vUQP/9BF + I+bOpZt8zNveFMnNzADRx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2vAAAVqQAGMbAJSJ7Ikb2uvqr6Uag3/4i+ + cf/JjXj/vVg//8CtqPrPopayzToUOs4dAALONQ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM3MzADQ19EA19HZGlK5M4QsrgXoZJhU/05Y + Rf96iHT/x87D/87Gwf+HeXb/VklJ/6lrXP/NORLf0Fo7cszZ3RLMzMwAzs7OAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAprgAAAKQABne/YU7K0MjEZKtP+hln + AP8fRAf/JUoC/2GJUP9sr0P/wHFJ/4dcVf9MAwP/XQ8K/4YfCP/BcFr40MrIr8uDbjjFIwACyFQ0AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwA////AIK/biMqsQKOVbQ57Y6Z + if81UST/IEUA/y1aAP8tWwD/I34E/zmjA/++Qwz/iSMM/2QBAP+EAAD/YwEA/2g2Mf+omJT/zF5B39A5 + EmvNh3YPzykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO7IXACmuAgm5zbNZpsmczi6c + Df0lYw7/KEIR/yBHHP8nUxv/L10D/yxaAP8zgRb/f7xl/8mEav+JMBz/YwAA/44AAP+MAAD/dAEB/10a + GP+HKxb/wUEg+NCtpKjOvbgxyAAAAstKJAAAAAAAAAAAAAAAAAAAAAAAAAAAADSuDQA4rREkMbEKl5K/ + hO+BkHz/HUkF/x5DD/8XVFf/B3um/whxnP8cUET/LVgE/36Rcv/M0Mr/z8rI/4hybv9jAQD/egQX/2gF + LP9+CBT/ZA8q/18CBf9pHRL/qZmV/82OftrOOhNnzDsZDMw8GAAAAAAAAAAAAAAAAAAAAAAAK64DACyv + BIUpowX/O2It/ypFEP8nUgv/FWd//xSWzf8Lqtf/AJnW/xVYcP8uWAb/cZBk/361XP/Cg2L/iWpk/2MB + AP9tGTL/IEql/y03gv8dZZ//XCBA/3UAAP9eIiL/jUo7/8k2D+/MOxVXzDgSAAAAAAAAAAAAAAAAAAAA + AABWuTkATroukVqVSP8jPw3/LVoA/x9gSf8Lh7r/OIxy/yuUtf8Hcrj/Jlos/y5aAP8pggv/OaMC/71C + C/+KKRP/YQAA/4wPEP9IZ5//Am7T/wGN1P8lV5L/ggIN/4UAAP9uHhv/uFg//M9GInTNTCoAAAAAAAAA + AAAAAAAAy8LFANa1zQTF0cGgk5uQ/ypIDP8pWxb/C2Oj/w9kjP8kVDT/DF2v/xhRYv8vXgL/LFoA/yeC + Cf9ksz//xmlE/4omD/9hAAD/jgEA/25GZP8YW8r/NHrD/xBquf9ZED7/igAC/4IlJf+ypKH90K6lds6z + qwAAAAAAAAAAAAAAAACtyKUAwMu9CZLHgqpJhjb/IUYA/x5qTP8BX9D/Bjit/wkyl/8NO4D/KlYT/zBg + AP8tWgH/cJBi/8bQxP/QxMD/imRc/2ABAP+NAAD/hicv/y5Uuf8mUL3/CnfQ/w5ar/9tCyj/hBUR/6xv + Yf/PrKOLzaKWAAAAAAAAAAAAAAAAADmwFgA+sBwOLbMGshx5Af8gRQD/K3E3/xVxwP8APNn/ASzA/xYy + Uf8tWgX/MGAA/zBcBf+JloL/pcKR/8eolf+KfHv/YAMD/40AAP+NCwr/VEmL/wM20v8AUtH/FVGt/2oR + L/+FDgn/py0O/9FGIZHOQRwAAAAAAAAAAAAAAAAAPbEaADavERdUujbDTn0+/yRHAv80ZAr/OoaB/xFO + 1/8AI9j/DzKA/y1aB/8xYwD/L1wF/z6NJf9Fpg3/vk4Z/5NBL/9lDg7/jwMD/44AAP+BIjX/JDrB/w4k + tv9dCkD/iAEG/4YWFP+jTTj/0UsomQD//wC7b18AAAAAAAAAAACxx6gArsekGsTPwMl3gHL/I0gA/y9e + AP9Acyz/Sn2X/yZinf8mXzH/MF8A/0RiJ/9ihVL/LakL/zWbDP+1PRX/wDwZ/4daVP94Jyf/iggI/5AH + Bv9eNnf/EyK3/2MEL/+OAAD/hhcX/56OjP/Rs6uqyJSGCcqflAAAAAAAAAAAAK7HpQC0ya0jksSD2jxv + Kv8jSQD/L18A/zBfAf87ahT/NmoR/yhbAP8rbQ7/na6W/6fFov8qgVD/FDig/0UZoP+fO1b/ya2n/6eL + hP98IRX/fw0K/4YaIv9NKWv/aQcs/40AAP+FDgz/mmJW/9KxqKvO19kKzsbEAAAAAAAAAAAAPLEZAD+z + GyUvrgneGGIA/yVLAP8wYAD/MWEA/zRdCf9IaS7/LIwO/zauE/+30K//ys/U/2Zu1v8cGtf/HyDY/3tw + 0v/RzdP/06qe/8M7Fv+WMRr/eC8t/4QOD/+OAwT/jgAA/4ULCf+ZJw3/0EgkuMZfRRHHWTwAAAAAAAAA + AAA2sREAM7INL0axJ/A2YyX/J1AA/y5fAP8nXQP/cIpi/6a8oP86oDf/H2Nv/2x01f+/vtr/mZin/ykp + dP86Oob/qaq4/7y93v92Z8z/hihf/8BRRP+zpKD/hU9J/3sQDP+MBgb/hwwL/5U6J//QQhzEzTAHF800 + DAAAAAAAAAAAAKLIlwCiyZUyssWs9lpkUf8yUBT/L3IR/yqcCP+byYz/yNHL/1lwvP8XGNv/Dw65/yQk + d/8TE2j/AwOW/xERrf8vL5L/Li6W/w8QyP8gGtn/hme1/9PNzP/LhnD/oisM/3wkG/94Ghv/kXVz/8+m + m8bNhHEYzIp5AAAAAAAAAAAAv9C7AMPMvkOfwZX4W4BP/5ifk/9UsD7/Iog4/26Gt//LyuP/tLPI/zg4 + hv8CAWX/AACG/wACp/8AAq//AAC1/wYGtf8SFKH/FhaL/1NTpf/Cw9X/x8nj/5ZmnP+3MCj/vWtW/4d3 + dv+VbGP/zbu32szKyiPLxsYAAAAAAAAAAAA/tBsAULcyUjayEPlsvFL/ztTL/2qNpP8XJcz/FBPT/zg4 + mP8wMGb/BwZ7/wAJoP8AOab/AG6T/wBrjv8AOpv/AE+d/wFih/8LL5P/JCWb/1JSjv8+Prb/GBXZ/0Af + tf+vg57/0MK8/8laOv/OVTXcznJbJM5uVQAAAAAAAAAAACCsAAAsrQRdI54T+1WMgv/Cwt//xsXb/1pZ + q/8ICG7/AABx/wAAnv8AGKr/AG6L/wCrff8Dton/BM6g/wPEqP8CyLP/AJOX/wApm/8DA7f/DQ2x/xMT + k/8aGpf/dHXI/8zO4f/BuM//sExV/8o0EejOOxMrzToUAAAAAAAAAAAAEDCsAB54SlkUO6DrERXc/z8/ + 2f9eXnv/GBhK/wAAjf8AALP/AAC3/wA8sf8AtX7/AJ9S/xZqgv8woq//Iqe2/yfBsP8FmYD/ACiE/wAB + sv8AALb/Bga5/xkZqv9MTIH/dHSp/zg44P8nFcj/cyRz6agzPC2gMUUAAAAAAAAAAAADAP8ADCHBCRIP + 4ksfH+GweHjf9KSktP9OTnX/BgZw/wAAl/8AALP/CDe1/xCnbv8Doyv/BnFO/w8/hP8RSoz/J6yE/wap + X/8ANGv/AAGy/wMDuP8NDbD/JCSa/21tkv+Tk77/Skrh8w8Q47AcFdZPf0KAB2Q2lwAAAAAAAAAAAAAA + AAAPD9wA6OflAHBv3A/Z2NpbvLvjvktK2PgNDaz/CQl0/wgHdf8KEaD/LlOf/yuJWP8RoCf/AJMo/wCV + L/8Bmkr/AGB4/wIUof8MDLH/GBic/xISlv8bG7r/eXnZ99fW4Li6uuFOFhbhDjo66QAPD9wAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUB2gAnJdwVExLeZygo4sqDg9T7k5Oh/y8ucP8EA37/GiCi/x1P + mv8DYJH/AFaG/wEsnP8KEa//GRmf/1palf+Xl7X/V1fZ9BIS47wcG99chn7EFBEQ4gAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIi0wD///8Ao5/WG97c33afn+LUNjbO/AkJ + l/8LC27/BgWG/wECrv8JCrb/Gxqi/xcWlf8VFbH/X17W+cfG4cHPz+JbUlLgEv//xwALC+EAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADJyeEA///oAjc1 + 2iYUE9+IRUXh3peXx/90c4z/Hh53/0JCkf+UlK7/eHjU+iQk4skcGtpsd3LSGP///wDf39sAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAUFDiAAIE5AO2tNwv1dXilHBw3+UZGcj/NTTP/aem4M3d3eJqa2vhGwAA3AEMDN4AAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAABgY3wAWFuAFDg7fOhER4ZgYFt13KiXTHxkV1gAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAP8AHBrVBC4nzAIiHdQAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//n////gf///w + D///wAP//4AB//4AAH/8AAA/8AAAD+AAAAfgAAAH4AAAB8AAAAfAAAAHwAAAB8AAAAfAAAADwAAAA8AA + AAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAAD8AAAD/wAAD//AAD//4AD///gB///+D////5//ygA + AAAwAAAAYAAAAAEAIAAAAAAAACQAAMIOAADCDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAN4AAFaOAgHLOQUD1DMGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAA9rRcAOq0WGTuhA1TBPgtezjQNGc01DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAHK0AAA2tAAQxrQw3L64IoDekAvHBPwz1zjUNoM0yCzfSIAAE0CgAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADR0dEA6tbvEp/Hk3BHtCXUJ68A/TSmAf/CPgv/zjML/c1L + KdTMmItwyt3kEsvHxwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0uQAAAGkAAFWuMQWsw5891NLVp6/Kp+1Mtiz/KK8A/1Gv + J//FWzT/zjYO/81TMv/Nq6Ltzc/Pps2roizOJwACtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2pAAAZpwABKa4AFy6vB3Z0v13e0dHR/KO2 + nf9KnDL/bLhW/7TLrP/Ntq7/yXRf/7JROP+6opz/zs7O/M58Zs/NOhRgzjMLC/8AAADcAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAztDOAP/b/wdYtzo8K68DtSyx + BPVptlL/nJ6b/0FIPP9baVX/wMa//9HR0P/Pzs3/x8C+/2pbWP9IQkH/op+f/8lxWv/POBHvzjcQms1i + RSrK+f8Fy8vLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALzLtQCpyJ0Cx8zEIdbQ + 2HZ5wGTcMLEJ/ySXAv8yaCH/KTob/xg1AP9qdGD/ucS2/5zCif/KnIn/x7q2/2hiYv8nAAD/RiIh/387 + Kv+5MQ7/zz0X/c5+as3N1tldx9XVD/+amgCf//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHawAAA6o + AAVEtCNPqsigtdXS1f1/uG7/IHoF/xJEAP8XMwD/J1IA/ylUAP9QdDz/YrNL/0CpD//CSBj/x2tT/21I + Qf9PAAD/bQAA/0kCAf9fEgT/ni8S/8uLev/Q1NTtzKeck8hkSDPFQh4Dx1k7AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAorwEAKK8BISauAIY5sxXincaQ/6+vsP9IYj//FDUA/x9BAP8rWAD/MWMA/yxWAP8kbAX/JqgD/zOm + Af/CPQv/xzQO/20eDP9SAAD/igAA/4AAAP9bAAD/TAsF/3pZUv+7vr//z5iJ/s1JJsjOMwxa0CEDBtAa + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AACmyZ4A/+j/ANDR0gnJzMVaVrc4vyivAPgyqA//X4BV/ztFMv8fOgf/J04B/y5dAP8vXgD/MWMA/ytW + AP8fawD/J6gC/0asGf/ETyP/xzQO/24ZBv9SAAD/iQAA/40AAP+JAAD/bwAA/00NDf9aSUn/om1f/8s+ + Gv7ONxDnzWFFkczV2CLCwcEAzc3NAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAALwAAC6sAAAARQABeL9lJL7NupTM0cvpXbdD/iGRAP8WTgL/HDYI/yJFAf8kTxn/IEky/ydS + GP8uWgT/MmMB/ytVAP8nbQr/YbRJ/6nInv/Nq5//x2dN/24gD/9RAAD/iQAA/40AAP+NAAD/jAAA/38A + AP9eBAP/SBMO/30hCv++NBD/zXRc+c/Q0cbOwr9QzFExCMAAAADLNwsAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAASa0iAD2tFxAlrQBSTbctyrHLqvq7v7v/RHc0/xA2AP8bOwH/JU0O/x1O + Qf8KXpL/A3Os/wxVfv8bRT7/LlwL/ylVAP9geVH/v8i8/9LS0//P0ND/x7y4/25STf9RAAD/iAAA/4IA + DP94ARj/iQAE/4UFDP92Bxn/bQEG/0sCAP9aFAb/pGJR/8nLzP7PopbuzVEwiMsyCiTJSCkBykAdAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOK0RAzatD4UsrgT1RLAk/omdgv9TWU7/HTQJ/yNK + AP8mVCL/ElJ9/wJ1vf8AqNP/ALDW/wCYzf8HT5n/KlUc/ypVAP90fWr/xsrF/7DIpP/LsaX/yMTD/25l + Zf9QAAD/iAAB/1cURf8iIYr/UgxI/2gWMv83P3j/UxtK/30BBf9dAAD/SR0b/4B7e/+6joL/zkgk/M04 + EcLMPBk1zD0bAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALa4FBSyuBNQlqwD/JncO/yQ2 + Gf8dPQH/KlYA/yxcDf8SYYX/C47W/yCw1v8TqNb/AqHX/wCX1f8MVJT/LVwS/ytVAP9feVD/fLxq/1Ct + JP/DWC7/yIRy/25UUP9QAAD/iAAB/2gkO/8fZrz/CU+5/yQ6jP8TfbL/FGqq/28PJv+KAAD/cAAA/00O + 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 + AP8vXgD/L14A/zBfAf84ZhD/QnEk/zNpC/8xZAD/JlUA/yJVCv+KnoP/zMnM/5fFiv8xpR//HX1C/xMx + qv9AGaf/lihI/8VGL//No5j/wcPE/45tZ/9hGRH/fRIR/48JCf+SEBD/X0Nm/yUzoP9NDU7/hQAG/4wA + AP+VCgr/ZiUg/7eVjP/QxcPgz8/PMdDQ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwvVoAbrxXiUKz + IPgggQP/FC4A/yxZAP8vXgD/L14A/y9eAP8xZAD/MWMA/y5aBP8gUwT/G3MA/zKmD/+qyaH/1NPT/6C+ + pv8wXZb/CxLU/w0N4/8NDuP/IBHM/39Ejf/Iq63/z9DP/8yYiv+yNRT/dR0K/2wWEP+DEBD/jgwN/3sO + IP+FAwr/jAAA/4wAAP+WCgr/ZRMM/7Y+Hv/PdV7iypqNN8mdkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAArrQQAK60DjSetAfkbeQD/FS4A/y1aAP8vXgD/MGEA/zNnAP8uWwP/QVom/1dySv83mRv/Jq8A/ze1 + Dv+yzan/29zY/83N3/+PjuP/R0fi/xYWzv8aGtP/T0/j/5aX4v/Q0N3/2NfU/9Ofjf/SPRP/yDIK/5g/ + Kf9uR0T/cRwd/4sLC/+TBQT/jAAA/4sAAP+XCQn/ZREL/7UuC//PNg/px0clUcdIJwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAArrgMAK64DpzGuDP83eSL/FzEB/y5cAP8zZgD/MWEA/yVQAv9JaTb/oZ+h/6bD + nf9IuCb/I58T/yRxYP9zfcz/xsbh/+Pj4v/U1NT/d3eZ/x0da/8nJ3T/jY2p/9zc2//i4uL/wcDf/4Jq + vf+YLk3/yzEN/9BjRv+3qaX/h318/2onI/95Dg7/lAoK/44BAf+XCQn/ZBUR/7E3GP/PNQ3tzTQMXs00 + DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZuT0AW7o/tYzAfP9ufGj/GzgC/zNmAP8pVQH/HVQA/yN9 + Bv95sWj/1NPU/6rJo/89iGH/ETqd/w8Y0v8aGuH/Skrb/3t7r/9ZWWb/HR1P/w0Ndf8gIJb/PT18/3Fx + gv9/f8L/RETf/xoa4v8nFMb/XxyE/7FcZf/Rv7n/ysfH/6hWQP95Hgz/ZxIO/4oPDv+dDQ3/Yxwb/66A + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAmQA3MdQAJyPRAhgY4B1sa+F5z87g0N3d4fjDw9z/aWmw/xcXeP8+P5X/q6vQ/9nZ + 4P/Z2eHmlZXhrCoq4FAAANwIQji9AUE3vgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/DwAC+pZ4C4d3VLsbG4YhjY+HSGxvi+g4O + 4f8VFeL/SEjf8K2s36nk5OBT4ODeDeDg3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADeAAAA + 3QgEBOE2FBPdkBAQ4NsXFdyxIB3UXh4Y0BgeGNEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAvLMwALSrNERIR3jMhHdUeKCPQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///5///8AAP///D///wAA///wD///AAD//+AH//8AAP//gAH//wAA//4AAP// + AAD//AAAP/8AAP/wAAAf/wAA/+AAAAf/AAD/wAAAA/8AAP8AAAAB/wAA/AAAAAB/AAD4AAAAAB8AAPAA + AAAADwAA8AAAAAAPAADwAAAAAA8AAPAAAAAADwAA8AAAAAAPAADwAAAAAA8AAPAAAAAADwAA8AAAAAAP + AADwAAAAAA8AAPAAAAAADwAA8AAAAAAPAADwAAAAAA8AAPAAAAAADwAA8AAAAAAPAADwAAAAAA8AAPAA + AAAADwAA8AAAAAAPAADgAAAAAA8AAOAAAAAADwAA4AAAAAAPAADgAAAAAA8AAOAAAAAADwAA4AAAAAAP + AADgAAAAAA8AAPgAAAAAHwAA/gAAAAB/AAD/gAAAAf8AAP/gAAAH/wAA//AAAA//AAD//AAAP/8AAP// + AAD//wAA///AB///AAD///Af//8AAP///D///wAA////////AAAoAAAAOAAAAHAAAAABACAAAAAAAAAx + AADCDgAAwg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnrwAgzzUKMAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOa0TgCiuAO/ONQ3/zTUNgAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAP7QfMDOtDM8orwD/KK8A/841Df/ONQ3/zTQNz89FHzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHR0YCCwW//KK8A/yiv + AP8orwD/zjUN/841Df/ONQ3/zX1o/8vHx4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJu7h0DR0dHP0dHR/3/BbP8orwD/Kq8C/1i5O//OZkv/zjcP/841 + Df/Of2r/zs7O/8zLys/Pj38gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+v + ABAprgCPXbpB/9HR0f/R0dH/b6Fg/zOcFP+OxH7/zNDL/87Lyv/OlIX/uD4f/69xYP/Ozs7/zs7O/81o + Te/MNA1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzrwtAKK4A3yivAP9hukb/yMjI/3Bx + cP8SFw3/lqCT/9HR0f/R0dH/zs7O/87Ozv+mmZb/FREQ/3l5ef/Jycn/zmhN/841Df/ONQ2/zzcPIAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADPz88QztDOj0y2LP8orwD/KK8A/0aQMP8xNS//EykB/xkwA/+kpKT/0dHR/7PL + rP/OsKj/zs7O/6enp/8RBQX/JQIC/0M8PP+uVDz/zjUN/841Df/NVjfvzMzMcAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArMiiUM7N + ze/O0M3/SLUn/yWjAP8TUwD/CxwA/xs6AP8wYQD/I0ME/52km/+BwW3/NLEP/84/Gf/OhXL/p6Ce/yYF + Bf9tAAD/TwAA/ykFAv96Hwj/yTQN/85YOv/Ozs7/zs7Ov7+3ryAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL68AECiuAK+HwnX/0dHR/8rOyf81gx7/CycA/xIp + AP8lTQD/Ll0A/zRpAP8hQQL/OJEd/yivAf8orwD/zjUN/842Dv+oQyn/JgQD/3oAAP+JAAD/awAA/zQA + AP9EDwT/r00z/87Ozf/Ozs7/zYJt78hUNHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACmvA1AorgDvKK8A/47Efv+8vLz/UlVR/w0eAv8dPgD/LFkA/y9eAP8vXgD/NWoA/x9A + AP8hjgD/KK8A/yivAP/ONQ3/zjUN/6grC/8mAgD/egAA/4wAAP+MAAD/fwAA/1AAAP8pCgj/e3p5/8nJ + yf/OgW3/zjUN/840Da/PLw8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM/PzyDCyry/ObIV/yiv + AP8nrAD/WYBO/yAmGv8VLgD/J1AA/y9dAf8vXgD/L14A/y9eAP81agD/Hj8A/yGPAP8orwD/RbUk/85Q + L//ONQ3/qSwL/yYCAf95AAD/jAAA/4wAAP+MAAD/iQAA/2sAAP80AgL/RD09/7BqWP/ONQ3/zjUN/81T + M+/MzMxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjyJpw0dHR78TPwf81shD/I5cA/w89AP8OIAH/IEMA/y1a + Af8kSyT/HT42/ypUD/8vXQH/L14A/zZrAP8dPgD/K5IM/3m/ZP/Ez8H/zsPA/858Zv+pMxT/JgIB/3kA + AP+MAAD/jAAA/4wAAP+MAAD/jAAA/38AAP9QAAD/KgcE/3wgCP/JNA3/zlMz/87Nzf/Ozs6vz7+/EAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAnrwAgKK4Av5PFhP/R0dH/vMi5/yBpCv8KHwD/FzMA/ylUAP8rWA7/FTtf/wJfsf8Cbav/DD9z/x0+ + Nf8rVgz/NmwA/x89BP+WqZD/0dHQ/9HR0f/Ozs7/zs3N/6qQif8mBAP/eAAA/4wAAP+JAAP/gwAL/4wA + AP+MAAD/fwYT/4cBA/9sAAD/NAAA/0UQBP+wRiv/zsvK/87Ozv/NeGLvzDYMUAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPa0WcDGuCv8orwD/nseR/6ur + q/84PTX/DyMA/yJIAP8tWwP/IEhD/wdBpf8AkMv/ALjX/wCy1f8AmMr/Akml/yVJI/82bAD/Iz0J/7Cw + sP/R0dH/yc/H/87Hxf/Ozs7/qqqq/yUHB/94AAD/jAAA/1UHQ/8iD4T/XgA2/4oAAv9VL1T/MB94/30B + Ev+AAAD/UQAA/yoJB/99enn/ycnJ/858Zv/ONQ3/yz4ar88vDxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwrQn/KK8A/yeoAP9NZ0b/FR8N/xo4AP8rVgD/L14A/x1P + U/8BaNL/AaXW/wSr1/8AqNf/AKfX/wCk1/8BTcL/Jk0j/zdtAP8jPAr/sLGw/6fJnf9Oty//zlk6/86s + o/+qqqr/JQcH/3cAAP+MAAD/TTdd/wFfzf8DQ7r/Mwls/0hIYv8Am83/MCt3/4sAAf+KAAD/bAAA/zUC + Av9FPj7/sWlW/841Df/ONQ3/y0AcjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAACivAP8orwD/IGoK/wUMAP8kSwD/Ll0A/y9eAP8rWBX/Bm+6/wWg1/9Jt83/Q6/I/xqe + 1v8Al9f/AI/W/xJOf/8uXAT/N24A/yE6CP9ZoUT/L7AI/yivAP/ONQ3/zj0X/6tjUP8lBwb/dwAA/4wA + AP+HCQv/ToG0/wF01P8Absv/Bk+5/wCj1P8Dhsf/Zwwv/4wAAP+MAAD/gAAA/1YFBf8wExD/tjAN/841 + Df/KPRi/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7EJ/3a/ + Yf9gaF3/FS4A/y9eAP8vXgD/L14C/xZUc/8Aktf/EpTF/0B3Mf9OhVD/QKTP/wCH1/8FXLv/J1Eg/y9e + AP83bgD/GTgA/yOXAP8orwD/KK8A/841Df/ONQ3/rCwL/yUCAf92AAD/jAAA/4wCAv+Ci5z/B2XU/wBx + 1P8AhdT/AJHU/wCj1P8gOY//hgAH/4wAAP+MAAD/jgMD/1wVFf+fbWD/zkUh/841Db8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsyqL/0dHR/2FiYP8YNQD/L14A/y9e + AP8nVib/A3HL/wCE1P8XfGz/L14A/ytiNf8OhNP/AGjS/xc6XP8vXgD/L14A/zdvAP8ZNwD/I5kA/yiv + AP8qsAP/zjcP/841Df+sLAv/JQIB/3YAAP+MAAD/jAAA/4osMP8sd87/AFrT/xdk0v8Sh9T/AJXU/wZD + qv97ABP/jAAA/4wAAP+PAwP/cBMT/5eXl//Ou7b/znJZvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAx7+/QNHR0f/R0dH/UFVN/xo5AP8vXgD/Ll4D/w5OmP8Addf/A0q2/ylX + Fv8tWgb/CS6T/wBn1/8HNZv/LVkJ/y9eAP8vXgD/OHAA/xg1AP8jmgD/QLQe/5PFhP/OkoL/zkcj/6wt + C/8lAgH/dQAA/4wAAP+MAAD/jhYW/2SXxf8BTNP/KCmf/4+gtf8NitT/AV6+/zQIYv9/AA//jAAA/44C + Av95FBT/jo6O/87Ozv/Ozc2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADPz89Ayc/H/4HBbv8XPwr/HT0A/y9eAP8gZEP/AWfV/wBf1/8CMbj/EjFv/xApcf8APc7/ADq6/yFH + L/8vXgD/L14A/y9eAP84cAD/GTUC/2qqV//Azrz/0dHR/87Ozv/Ou7b/rWFN/yUDAf91AAD/jAAA/4wA + AP+MAQH/fVtp/xFb1P8HNL3/aWSc/xyB1P8AhdT/AHvH/xYdkv+AAA//jgIC/38UFP+DT0L/zr66/8nG + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAADw/fIFBQ4p/MzOH/4eHh/+Hh4f/X19j/aGiL/wwMQP89PWr/wsLG/+Hh + 4f/h4eH/1NTh/3p64d8NDd9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAM/ExDDh4eG/wMDh/15e4f8VFeH/Dg7d/xMT4f9LS+H/s7Ph/97e4d/f399gAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAfH99ADQ3hvw8P4f8PD+H/Dw/h/xgX2+80L9NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJyXRYA4O + 4c8hHdWAr4+PEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////8A////5////wD////D////AP///wD///8A///+AH// + /wD///gAH///AP//4AAP//8A///AAAP//wD//wAAAf//AP/+AAAAf/8A//gAAAA//wD/8AAAAA//AP/A + AAAAB/8A/4AAAAAB/wD+AAAAAAD/APwAAAAAAD8A/AAAAAAAPwD8AAAAAAA/APwAAAAAAD8A/AAAAAAA + PwD4AAAAAAA/APgAAAAAAD8A+AAAAAAAPwD4AAAAAAA/APgAAAAAAD8A+AAAAAAAHwD4AAAAAAAfAPgA + AAAAAB8A+AAAAAAAHwD4AAAAAAAfAPgAAAAAAB8A+AAAAAAAHwD4AAAAAAAfAPgAAAAAAB8A+AAAAAAA + HwDwAAAAAAAfAPAAAAAAAB8A8AAAAAAAHwDwAAAAAAAfAPAAAAAAAB8A8AAAAAAAHwDwAAAAAAAfAPgA + AAAAAB8A/gAAAAAAfwD/gAAAAAH/AP/gAAAAB/8A//gAAAAf/wD//gAAAH//AP//AAAB//8A///AAAf/ + /wD///AAH///AP///AB///8A////Af///wD////D////AP////////8A/////////wA= + + + \ No newline at end of file diff --git a/src/Forms/MainForm.Designer.cs b/src/Forms/MainForm.Designer.cs index 0813eab..eaf091c 100644 --- a/src/Forms/MainForm.Designer.cs +++ b/src/Forms/MainForm.Designer.cs @@ -80,12 +80,16 @@ private void InitializeComponent() this.splitContainer2 = new System.Windows.Forms.SplitContainer(); this.splitContainer3 = new System.Windows.Forms.SplitContainer(); this.panel3 = new System.Windows.Forms.Panel(); + this.radioButton_front = new System.Windows.Forms.RadioButton(); + this.radioButton_back = new System.Windows.Forms.RadioButton(); + this.radioButton_top = new System.Windows.Forms.RadioButton(); + this.radioButton_bottom = new System.Windows.Forms.RadioButton(); + this.radioButton_left = new System.Windows.Forms.RadioButton(); + this.radioButton_right = new System.Windows.Forms.RadioButton(); this.keepOnGround = new System.Windows.Forms.CheckBox(); this.dropToGround = new System.Windows.Forms.Button(); this.radioButton2 = new System.Windows.Forms.RadioButton(); this.radioButton1 = new System.Windows.Forms.RadioButton(); - this.fovText = new System.Windows.Forms.Label(); - this.trackBar_FOV = new System.Windows.Forms.TrackBar(); this.camSpeedLabel = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.trackBar_camSpeed = new System.Windows.Forms.TrackBar(); @@ -105,6 +109,7 @@ private void InitializeComponent() this.moveObj = new System.Windows.Forms.PictureBox(); this.movObj_UpDown = new System.Windows.Forms.PictureBox(); this.glControl1 = new OpenTK.GLControl(); + this.warpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); this.panel1.SuspendLayout(); @@ -117,7 +122,6 @@ private void InitializeComponent() this.splitContainer3.Panel2.SuspendLayout(); this.splitContainer3.SuspendLayout(); this.panel3.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar_FOV)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBar_camSpeed)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBar_moveSpeed)).BeginInit(); this.moveCamPanel.SuspendLayout(); @@ -199,6 +203,7 @@ private void InitializeComponent() this.modelIDToolStripMenuItem, this.behaviorToolStripMenuItem, this.behParametersToolStripMenuItem, + this.warpToolStripMenuItem, this.toolStripSeparator5, this.objectComboNameToolStripMenuItem}); this.editToolStripMenuItem.Name = "editToolStripMenuItem"; @@ -248,25 +253,25 @@ private void InitializeComponent() // bParam1ToolStripMenuItem // this.bParam1ToolStripMenuItem.Name = "bParam1ToolStripMenuItem"; - this.bParam1ToolStripMenuItem.Size = new System.Drawing.Size(130, 22); + this.bParam1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.bParam1ToolStripMenuItem.Text = "B. Param 1"; // // bParam2ToolStripMenuItem // this.bParam2ToolStripMenuItem.Name = "bParam2ToolStripMenuItem"; - this.bParam2ToolStripMenuItem.Size = new System.Drawing.Size(130, 22); + this.bParam2ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.bParam2ToolStripMenuItem.Text = "B. Param 2"; // // bParam3ToolStripMenuItem // this.bParam3ToolStripMenuItem.Name = "bParam3ToolStripMenuItem"; - this.bParam3ToolStripMenuItem.Size = new System.Drawing.Size(130, 22); + this.bParam3ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.bParam3ToolStripMenuItem.Text = "B. Param 3"; // // bParam4ToolStripMenuItem // this.bParam4ToolStripMenuItem.Name = "bParam4ToolStripMenuItem"; - this.bParam4ToolStripMenuItem.Size = new System.Drawing.Size(130, 22); + this.bParam4ToolStripMenuItem.Size = new System.Drawing.Size(152, 22); this.bParam4ToolStripMenuItem.Text = "B. Param 4"; // // toolStripSeparator5 @@ -637,12 +642,16 @@ private void InitializeComponent() this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.panel3.BackColor = System.Drawing.Color.Gray; + this.panel3.Controls.Add(this.radioButton_front); + this.panel3.Controls.Add(this.radioButton_back); + this.panel3.Controls.Add(this.radioButton_top); + this.panel3.Controls.Add(this.radioButton_bottom); + this.panel3.Controls.Add(this.radioButton_left); + this.panel3.Controls.Add(this.radioButton_right); this.panel3.Controls.Add(this.keepOnGround); this.panel3.Controls.Add(this.dropToGround); this.panel3.Controls.Add(this.radioButton2); this.panel3.Controls.Add(this.radioButton1); - this.panel3.Controls.Add(this.fovText); - this.panel3.Controls.Add(this.trackBar_FOV); this.panel3.Controls.Add(this.camSpeedLabel); this.panel3.Controls.Add(this.label6); this.panel3.Controls.Add(this.trackBar_camSpeed); @@ -659,6 +668,96 @@ private void InitializeComponent() this.panel3.Size = new System.Drawing.Size(649, 120); this.panel3.TabIndex = 5; // + // radioButton_front + // + this.radioButton_front.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_front.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_front.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_front.Location = new System.Drawing.Point(561, 99); + this.radioButton_front.Name = "radioButton_front"; + this.radioButton_front.Size = new System.Drawing.Size(44, 20); + this.radioButton_front.TabIndex = 22; + this.radioButton_front.Text = "Front"; + this.radioButton_front.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_front.UseVisualStyleBackColor = true; + this.radioButton_front.CheckedChanged += new System.EventHandler(this.radioButton_front_CheckedChanged); + // + // radioButton_back + // + this.radioButton_back.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_back.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_back.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_back.Location = new System.Drawing.Point(604, 99); + this.radioButton_back.Name = "radioButton_back"; + this.radioButton_back.Size = new System.Drawing.Size(44, 20); + this.radioButton_back.TabIndex = 21; + this.radioButton_back.Text = "Back"; + this.radioButton_back.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_back.UseVisualStyleBackColor = true; + this.radioButton_back.CheckedChanged += new System.EventHandler(this.radioButton_back_CheckedChanged); + // + // radioButton_top + // + this.radioButton_top.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_top.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_top.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_top.Location = new System.Drawing.Point(561, 61); + this.radioButton_top.Name = "radioButton_top"; + this.radioButton_top.Size = new System.Drawing.Size(44, 20); + this.radioButton_top.TabIndex = 20; + this.radioButton_top.Text = "Top"; + this.radioButton_top.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_top.UseVisualStyleBackColor = true; + this.radioButton_top.CheckedChanged += new System.EventHandler(this.radioButton5_CheckedChanged); + // + // radioButton_bottom + // + this.radioButton_bottom.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_bottom.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_bottom.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_bottom.Location = new System.Drawing.Point(604, 61); + this.radioButton_bottom.Name = "radioButton_bottom"; + this.radioButton_bottom.Size = new System.Drawing.Size(44, 20); + this.radioButton_bottom.TabIndex = 19; + this.radioButton_bottom.Text = "Bttm"; + this.radioButton_bottom.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_bottom.UseVisualStyleBackColor = true; + this.radioButton_bottom.CheckedChanged += new System.EventHandler(this.radioButton4_CheckedChanged); + // + // radioButton_left + // + this.radioButton_left.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_left.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_left.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_left.Location = new System.Drawing.Point(561, 80); + this.radioButton_left.Name = "radioButton_left"; + this.radioButton_left.Size = new System.Drawing.Size(44, 20); + this.radioButton_left.TabIndex = 18; + this.radioButton_left.Text = "Left"; + this.radioButton_left.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_left.UseVisualStyleBackColor = true; + this.radioButton_left.CheckedChanged += new System.EventHandler(this.radioButton_left_CheckedChanged); + // + // radioButton_right + // + this.radioButton_right.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.radioButton_right.Appearance = System.Windows.Forms.Appearance.Button; + this.radioButton_right.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.radioButton_right.Location = new System.Drawing.Point(604, 80); + this.radioButton_right.Name = "radioButton_right"; + this.radioButton_right.Size = new System.Drawing.Size(44, 20); + this.radioButton_right.TabIndex = 17; + this.radioButton_right.Text = "Right"; + this.radioButton_right.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.radioButton_right.UseVisualStyleBackColor = true; + this.radioButton_right.CheckedChanged += new System.EventHandler(this.radioButton_right_CheckedChanged); + // // keepOnGround // this.keepOnGround.Appearance = System.Windows.Forms.Appearance.Button; @@ -692,9 +791,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.radioButton2.Appearance = System.Windows.Forms.Appearance.Button; this.radioButton2.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.radioButton2.Location = new System.Drawing.Point(605, 98); + this.radioButton2.Location = new System.Drawing.Point(604, 42); this.radioButton2.Name = "radioButton2"; - this.radioButton2.Size = new System.Drawing.Size(40, 20); + this.radioButton2.Size = new System.Drawing.Size(44, 20); this.radioButton2.TabIndex = 16; this.radioButton2.Text = "Orbit"; this.radioButton2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -708,9 +807,9 @@ private void InitializeComponent() this.radioButton1.Appearance = System.Windows.Forms.Appearance.Button; this.radioButton1.Checked = true; this.radioButton1.Font = new System.Drawing.Font("Corbel", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.radioButton1.Location = new System.Drawing.Point(569, 98); + this.radioButton1.Location = new System.Drawing.Point(561, 42); this.radioButton1.Name = "radioButton1"; - this.radioButton1.Size = new System.Drawing.Size(38, 20); + this.radioButton1.Size = new System.Drawing.Size(44, 20); this.radioButton1.TabIndex = 15; this.radioButton1.TabStop = true; this.radioButton1.Text = "Fly"; @@ -718,40 +817,13 @@ private void InitializeComponent() this.radioButton1.UseVisualStyleBackColor = true; this.radioButton1.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged); // - // fovText - // - this.fovText.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Right))); - this.fovText.AutoSize = true; - this.fovText.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.fovText.Location = new System.Drawing.Point(579, 54); - this.fovText.Name = "fovText"; - this.fovText.Size = new System.Drawing.Size(63, 14); - this.fovText.TabIndex = 14; - this.fovText.Text = "FOV: 60°"; - // - // trackBar_FOV - // - this.trackBar_FOV.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.trackBar_FOV.Location = new System.Drawing.Point(565, 67); - this.trackBar_FOV.Maximum = 120; - this.trackBar_FOV.Minimum = 15; - this.trackBar_FOV.Name = "trackBar_FOV"; - this.trackBar_FOV.Size = new System.Drawing.Size(86, 45); - this.trackBar_FOV.SmallChange = 2; - this.trackBar_FOV.TabIndex = 13; - this.trackBar_FOV.TabStop = false; - this.trackBar_FOV.TickFrequency = 15; - this.trackBar_FOV.Value = 60; - this.trackBar_FOV.ValueChanged += new System.EventHandler(this.trackBar1_ValueChanged); - // // camSpeedLabel // this.camSpeedLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); this.camSpeedLabel.AutoSize = true; this.camSpeedLabel.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.camSpeedLabel.Location = new System.Drawing.Point(592, 13); + this.camSpeedLabel.Location = new System.Drawing.Point(616, 2); this.camSpeedLabel.Name = "camSpeedLabel"; this.camSpeedLabel.Size = new System.Drawing.Size(35, 14); this.camSpeedLabel.TabIndex = 12; @@ -764,11 +836,11 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.label6.AutoSize = true; this.label6.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label6.Location = new System.Drawing.Point(569, 0); + this.label6.Location = new System.Drawing.Point(559, 2); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(77, 14); + this.label6.Size = new System.Drawing.Size(63, 14); this.label6.TabIndex = 11; - this.label6.Text = "Cam speed:"; + this.label6.Text = "Cam spd:"; this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // trackBar_camSpeed @@ -776,7 +848,7 @@ private void InitializeComponent() this.trackBar_camSpeed.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); this.trackBar_camSpeed.LargeChange = 10; - this.trackBar_camSpeed.Location = new System.Drawing.Point(565, 25); + this.trackBar_camSpeed.Location = new System.Drawing.Point(565, 14); this.trackBar_camSpeed.Maximum = 100; this.trackBar_camSpeed.Name = "trackBar_camSpeed"; this.trackBar_camSpeed.Size = new System.Drawing.Size(82, 45); @@ -832,7 +904,7 @@ private void InitializeComponent() this.moveCamPanel.Controls.Add(this.label2); this.moveCamPanel.Controls.Add(this.moveCam_strafe); this.moveCamPanel.Controls.Add(this.moveCam_InOut); - this.moveCamPanel.Location = new System.Drawing.Point(436, 2); + this.moveCamPanel.Location = new System.Drawing.Point(434, 2); this.moveCamPanel.Margin = new System.Windows.Forms.Padding(1); this.moveCamPanel.Name = "moveCamPanel"; this.moveCamPanel.Size = new System.Drawing.Size(125, 120); @@ -1001,6 +1073,14 @@ private void InitializeComponent() this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp); this.glControl1.Resize += new System.EventHandler(this.glControl1_Resize); // + // warpToolStripMenuItem + // + this.warpToolStripMenuItem.Enabled = false; + this.warpToolStripMenuItem.Name = "warpToolStripMenuItem"; + this.warpToolStripMenuItem.Size = new System.Drawing.Size(189, 22); + this.warpToolStripMenuItem.Text = "Warp"; + this.warpToolStripMenuItem.Click += new System.EventHandler(this.warpToolStripMenuItem_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1014,7 +1094,7 @@ private void InitializeComponent() this.MinimumSize = new System.Drawing.Size(820, 522); this.Name = "MainForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Quad64 v0.2 (Beta build 2)"; + this.Text = "Quad64 v0.2 (Beta build 3)"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); this.Shown += new System.EventHandler(this.Form1_Shown); this.menuStrip1.ResumeLayout(false); @@ -1033,7 +1113,6 @@ private void InitializeComponent() this.splitContainer3.ResumeLayout(false); this.panel3.ResumeLayout(false); this.panel3.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar_FOV)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBar_camSpeed)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.trackBar_moveSpeed)).EndInit(); this.moveCamPanel.ResumeLayout(false); @@ -1087,8 +1166,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label3; private System.Windows.Forms.TrackBar trackBar_moveSpeed; private System.Windows.Forms.Label objSpeedLabel; - private System.Windows.Forms.Label fovText; - private System.Windows.Forms.TrackBar trackBar_FOV; private System.Windows.Forms.Label camSpeedLabel; private System.Windows.Forms.Label label6; private System.Windows.Forms.TrackBar trackBar_camSpeed; @@ -1130,6 +1207,13 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem bParam4ToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; private System.Windows.Forms.ToolStripMenuItem objectComboNameToolStripMenuItem; + private System.Windows.Forms.RadioButton radioButton_right; + private System.Windows.Forms.RadioButton radioButton_front; + private System.Windows.Forms.RadioButton radioButton_back; + private System.Windows.Forms.RadioButton radioButton_top; + private System.Windows.Forms.RadioButton radioButton_bottom; + private System.Windows.Forms.RadioButton radioButton_left; + private System.Windows.Forms.ToolStripMenuItem warpToolStripMenuItem; } } diff --git a/src/Forms/MainForm.cs b/src/Forms/MainForm.cs index be49bd7..53fd68e 100644 --- a/src/Forms/MainForm.cs +++ b/src/Forms/MainForm.cs @@ -58,7 +58,7 @@ private void initTreeView() treeView1.Nodes.Add(makeTreeNode("Macro 3D Objects", Color.FromArgb(0, 0, 192))); treeView1.Nodes.Add(makeTreeNode("Special 3D Objects", Color.FromArgb(0, 192, 0))); treeView1.Nodes.Add(makeTreeNode("Warps", Color.FromArgb(0, 0, 0))); - treeView1.Anchor = (AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left| AnchorStyles.Right ); + treeView1.Anchor = (AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right); treeView1.Size = new Size(217, 206); treeView1.TabIndex = 0; treeView1.TabStop = false; @@ -80,7 +80,7 @@ public MainForm() glControl1.CreateControl(); SettingsFile.LoadGlobalSettings("default"); glControl1.MouseWheel += new MouseEventHandler(glControl1_Wheel); - ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, (float)glControl1.Width/(float)glControl1.Height, 100f, 100000f); + ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, (float)glControl1.Width / (float)glControl1.Height, 100f, 100000f); glControl1.Enabled = false; KeyPreview = true; treeView1.HideSelection = false; @@ -121,7 +121,7 @@ private void loadROM(bool startingUp) BehaviorNameFile.parseBehaviorNames(Globals.getDefaultBehaviorNamesPath()); ModelComboFile.parseObjectCombos(Globals.getDefaultObjectComboPath()); rom.setSegment(0x15, Globals.seg15_location[0], Globals.seg15_location[1], false); - rom.setSegment(0x02, Globals.seg02_location[0], Globals.seg02_location[1], + rom.setSegment(0x02, Globals.seg02_location[0], Globals.seg02_location[1], rom.isSegmentMIO0(0x02), rom.Seg02_isFakeMIO0, rom.Seg02_uncompressedOffset); level = new Level(0x10, 1); LevelScripts.parse(ref level, 0x15, 0); @@ -155,7 +155,7 @@ private void refreshObjectsInList() { obj.Title = obj.getObjectComboName(); objects.Nodes.Add(obj.Title); - // objects.Nodes.Add("0x" + obj.Behavior.ToString("X8")); + // objects.Nodes.Add("0x" + obj.Behavior.ToString("X8")); } TreeNode macro_objects = treeView1.Nodes[1]; @@ -192,7 +192,7 @@ private void refreshObjectsInList() } EndUpdate(treeView1); } - + private void glControl1_Paint(object sender, PaintEventArgs e) { GL.ClearColor(bgColor); @@ -237,7 +237,7 @@ private void selectObject(int mx, int my) GL.ReadPixels(mx, h - my, 1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, pixel); if (pixel[0] == pixel[1] && pixel[1] == pixel[2]) { - if(pixel[2] == 255 || pixel[2] == 0) + if (pixel[2] == 255 || pixel[2] == 0) return; // If a pixel is fully white or fully black, then ignore picking. } if (pixel[2] > 0 && pixel[2] < 4) @@ -249,7 +249,7 @@ private void selectObject(int mx, int my) bool setSelected = !treeViewAlreadyHasNodeSelected(treeView1.Nodes[Globals.list_selected].Nodes[Globals.item_selected]); treeView1.ToggleNode(treeView1.Nodes[Globals.list_selected].Nodes[Globals.item_selected], setSelected); - if(setSelected) + if (setSelected) updateAfterSelect(treeView1.Nodes[Globals.list_selected].Nodes[Globals.item_selected]); else treeView1_updateMultiselection(); @@ -259,7 +259,7 @@ private void selectObject(int mx, int my) treeView1.SelectSingleNode(treeView1.Nodes[Globals.list_selected].Nodes[Globals.item_selected]); updateAfterSelect(treeView1.Nodes[Globals.list_selected].Nodes[Globals.item_selected]); } - + if (camera.isOrbitCamera()) { camera.updateOrbitCamera(ref camMtx); @@ -334,10 +334,10 @@ private void glControl1_KeyUp(object sender, KeyEventArgs e) case Keys.A: isADown = false; break; case Keys.D: isDDown = false; break; } - if(!isWDown && !isSDown && !isADown && !isDDown) + if (!isWDown && !isSDown && !isADown && !isDDown) myTimer.Enabled = false; } - + private void glControl1_Leave(object sender, EventArgs e) { isWDown = false; @@ -386,34 +386,6 @@ private void glControl1_KeyDown(object sender, KeyEventArgs e) isControlDown = e.Control; switch (e.KeyCode) { - case Keys.P: - /* - if (Globals.list_selected != -1 && Globals.item_selected != -1) - { - int listSel = Globals.list_selected; - int objSel = Globals.item_selected; - Object3D obj = getSelectedObject(); - if (obj == null) return; - string newName = Prompts.ShowInputDialog("Type the new combo name", "New combo name"); - if (newName.Length > 0) - { - obj.Title = newName; - uint segmentAddress = 0; - if (level.ModelIDs.ContainsKey(obj.ModelID)) - segmentAddress = level.ModelIDs[obj.ModelID].GeoDataSegAddress; - ObjectComboEntry oce = new ObjectComboEntry(newName, obj.ModelID, - segmentAddress, obj.getBehaviorAddress()); - Globals.insertNewEntry(oce); - refreshObjectsInList(); - treeView1.SelectedNode = treeView1.Nodes[listSel].Nodes[objSel]; - Globals.list_selected = listSel; - Globals.item_selected = objSel; - propertyGrid1.Refresh(); - } - ModelComboFile.writeObjectCombosFile(Globals.getDefaultObjectComboPath()); - Console.WriteLine("Saved Object Combos!"); - }*/ - break; case Keys.W: isWDown = true; myTimer.Enabled = true; @@ -468,7 +440,7 @@ private void glControl1_Load(object sender, EventArgs e) GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Gequal, 0.5f); - + if (Globals.doBackfaceCulling) GL.Enable(EnableCap.CullFace); else @@ -479,14 +451,14 @@ private void glControl1_Resize(object sender, EventArgs e) { glControl1.Context.Update(glControl1.WindowInfo); GL.Viewport(0, 0, glControl1.Width, glControl1.Height); - ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, (float)glControl1.Width/(float)glControl1.Height, 100f, 100000f); + ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, (float)glControl1.Width / (float)glControl1.Height, 100f, 100000f); glControl1.Invalidate(); } - + private void loadROMToolStripMenuItem_Click(object sender, EventArgs e) { DialogResult saveResult = Prompts.ShowShouldSaveDialog(); - if(saveResult != DialogResult.Cancel) + if (saveResult != DialogResult.Cancel) loadROM(false); } @@ -497,7 +469,7 @@ private void saveROMAsToolStripMenuItem_Click(object sender, EventArgs e) DialogResult result = saveFileDialog1.ShowDialog(); if (result == DialogResult.OK) // Test result. { - if(saveFileDialog1.FilterIndex == 1 || saveFileDialog1.FilterIndex == 4) + if (saveFileDialog1.FilterIndex == 1 || saveFileDialog1.FilterIndex == 4) ROM.Instance.saveFileAs(saveFileDialog1.FileName, ROM_Endian.BIG); else if (saveFileDialog1.FilterIndex == 2) ROM.Instance.saveFileAs(saveFileDialog1.FileName, ROM_Endian.MIXED); @@ -510,7 +482,7 @@ private void saveROMToolStripMenuItem_Click(object sender, EventArgs e) { ROM.Instance.saveFile(); } - + private void settingsToolStripMenuItem_Click(object sender, EventArgs e) { SettingsForm settings = new SettingsForm(); @@ -578,7 +550,45 @@ private void replaceSpecialObject(int index, ref SelectComboPreset comboWindow) = area.SpecialObjects[index].getObjectComboName(); area.SpecialObjects[index].UpdateProperties(); } - + + private void replaceWarp(int index, ref EditWarp editWarpWindow) + { + //Console.WriteLine(comboWindow.ReturnPresetMacro.PresetID); + Area area = level.getCurrentArea(); + area.Warps[index].WarpFrom_ID = editWarpWindow.fromID; + area.Warps[index].WarpTo_AreaID = editWarpWindow.toArea; + area.Warps[index].WarpTo_LevelID = editWarpWindow.toLevel; + area.Warps[index].WarpTo_WarpID = editWarpWindow.toID; + + treeView1.Nodes[3].Nodes[index].Text = area.Warps[index].ToString(); + // area.SpecialObjects[index].UpdateProperties(); + } + + private void replacePaintingWarp(int index, ref EditWarp editWarpWindow) + { + //Console.WriteLine(comboWindow.ReturnPresetMacro.PresetID); + Area area = level.getCurrentArea(); + area.PaintingWarps[index].WarpFrom_ID = editWarpWindow.fromID; + area.PaintingWarps[index].WarpTo_AreaID = editWarpWindow.toArea; + area.PaintingWarps[index].WarpTo_LevelID = editWarpWindow.toLevel; + area.PaintingWarps[index].WarpTo_WarpID = editWarpWindow.toID; + + treeView1.Nodes[3].Nodes[index].Text = area.Warps[index].ToString(); + // area.SpecialObjects[index].UpdateProperties(); + } + + private void replaceInstantWarp(int index, ref EditWarp editWarpWindow) + { + //Console.WriteLine(comboWindow.ReturnPresetMacro.PresetID); + Area area = level.getCurrentArea(); + area.InstantWarps[index].AreaID = editWarpWindow.toArea; + area.InstantWarps[index].TriggerID = editWarpWindow.triggerID; + area.InstantWarps[index].TeleX = editWarpWindow.tX; + area.InstantWarps[index].TeleY = editWarpWindow.tY; + area.InstantWarps[index].TeleZ = editWarpWindow.tZ; + treeView1.Nodes[3].Nodes[index].Text = area.InstantWarps[index].ToString(); + } + private void behaviorToolStripMenuItem_Click(object sender, EventArgs e) { SelectBehavior behWindow = new SelectBehavior(); @@ -597,7 +607,7 @@ private void behaviorToolStripMenuItem_Click(object sender, EventArgs e) glControl1.Update(); // Needed after calling propertyGrid1.Refresh(); } } - + private void objectComboNameToolStripMenuItem_Click(object sender, EventArgs e) { RenameObjectCombo roc = new RenameObjectCombo(getSelectedObject().Title); @@ -621,8 +631,8 @@ private void objectComboNameToolStripMenuItem_Click(object sender, EventArgs e) area.SpecialObjects[node.Index].renameObjectCombo(roc.ReturnName); } } - // Console.WriteLine("Changed object combo name to " + roc.ReturnName); - + // Console.WriteLine("Changed object combo name to " + roc.ReturnName); + updateSelectedObjectsInROM(); glControl1.Invalidate(); propertyGrid1.Refresh(); @@ -641,7 +651,7 @@ private void objectComboPresetToolStripMenuItem_Click(object sender, EventArgs e comboWindow = new SelectComboPreset(level, 0, "Select Object Combos", Color.DarkRed); comboWindow.ShowDialog(); - if(comboWindow.ClickedSelect) + if (comboWindow.ClickedSelect) { if (!Globals.isMultiSelected) replaceObject(Globals.item_selected, ref comboWindow); @@ -692,17 +702,66 @@ private void objectComboPresetToolStripMenuItem_Click(object sender, EventArgs e Globals.needToSave = true; } + + private void warpToolStripMenuItem_Click(object sender, EventArgs e) + { + int warpIndex = 0; + bool isPaintingWarp = false; + object warp = getSelectedWarp(out warpIndex, out isPaintingWarp); + Area area = level.getCurrentArea(); + if (warp is Warp) + { + Warp w = (Warp)warp; + string title = "Update Painting Warp"; + if (w.ToString().StartsWith("Warp ")) + title = "Update Warp"; + + EditWarp editWarpWindow = new EditWarp(title, w.WarpFrom_ID, w.WarpTo_LevelID, w.WarpTo_AreaID, w.WarpTo_WarpID); + editWarpWindow.ShowDialog(); + if (editWarpWindow.pressedSaved) + { + if(isPaintingWarp) + replacePaintingWarp(warpIndex - area.Warps.Count, ref editWarpWindow); + else + replaceWarp(warpIndex, ref editWarpWindow); + updateSelectedWarpsInROM(); + glControl1.Invalidate(); + propertyGrid1.Refresh(); + glControl1.Update(); // Needed after calling propertyGrid1.Refresh(); + Globals.needToSave = true; + } + } + else if (warp is WarpInstant) + { + WarpInstant w = (WarpInstant)warp; + EditWarp editWarpWindow = new EditWarp(w.TriggerID, w.AreaID, w.TeleX, w.TeleY, w.TeleZ); + editWarpWindow.ShowDialog(); + if (editWarpWindow.pressedSaved) + { + replaceInstantWarp(warpIndex - area.Warps.Count - area.PaintingWarps.Count, ref editWarpWindow); + updateSelectedWarpsInROM(); + glControl1.Invalidate(); + propertyGrid1.Refresh(); + glControl1.Update(); // Needed after calling propertyGrid1.Refresh(); + Globals.needToSave = true; + } + } + + //EditWarp editWarpWindow = new EditWarp(); + //editWarpWindow.ShowDialog(); + } + private void Form1_Shown(object sender, EventArgs e) { string glString = GL.GetString(StringName.Version).Split(' ')[0]; if (glString.StartsWith("1.")) { MessageBox.Show( - "Error: You have an outdated version of OpenGL, which is not supported by this program."+ + "Error: You have an outdated version of OpenGL, which is not supported by this program." + " The program will now exit.\n\n" + "OpenGL version: [" + GL.GetString(StringName.Version) + "]\n", - "OpenGL version error", - MessageBoxButtons.OK, + "OpenGL version error", + MessageBoxButtons.OK, MessageBoxIcon.Error ); Close(); @@ -741,7 +800,7 @@ private void trySwitchArea(ushort toArea) private void Form1_KeyDown(object sender, KeyEventArgs e) { - + } private void resetObjectVariables() @@ -792,8 +851,7 @@ private void selectLeveToolStripMenuItem_Click(object sender, EventArgs e) switchLevel(newLevel.levelID); } } - - + private void testROMToolStripMenuItem_Click(object sender, EventArgs e) { LaunchROM.OpenEmulator(); @@ -838,12 +896,15 @@ private void updateAfterSelect(TreeNode node) Globals.isMultiSelected = false; Globals.isMultiSelectedFromMultipleLists = false; + Globals.isMultiSelectedFromSpecialObjects = false; + Globals.isMultiSelectedFromBothNormalWarpsAndInstantWarps = false; propertyGrid1.SelectedObject = null; Globals.list_selected = -1; Globals.item_selected = -1; objectComboPresetToolStripMenuItem.Enabled = false; objectComboNameToolStripMenuItem.Enabled = false; behaviorToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = false; glControl1.Invalidate(); glControl1.Update(); @@ -853,24 +914,29 @@ private void updateAfterSelect(TreeNode node) objectComboPresetToolStripMenuItem.Enabled = true; objectComboNameToolStripMenuItem.Enabled = true; behaviorToolStripMenuItem.Enabled = true; + warpToolStripMenuItem.Enabled = false; if (treeView1.SelectedNodes.Count > 1) { Area area = level.getCurrentArea(); string parent_text = treeView1.SelectedNodes[0].Parent.Text; - + if (parent_text.Equals("3D Objects")) Globals.list_selected = 0; else if (parent_text.Equals("Macro 3D Objects")) Globals.list_selected = 1; else if (parent_text.Equals("Special 3D Objects")) Globals.list_selected = 2; - - if(Globals.list_selected != 0) + else if (parent_text.Equals("Warps")) + Globals.list_selected = 3; + + if (Globals.list_selected != 0) behaviorToolStripMenuItem.Enabled = false; Globals.isMultiSelectedFromMultipleLists = false; Globals.isMultiSelectedFromSpecialObjects = false; bool hasSO_8 = false, hasSO_10 = false, hasSO_12 = false; + Globals.isMultiSelectedFromBothNormalWarpsAndInstantWarps = false; + bool hasRegularWarp = false, hasInstantWarp = false; if (Globals.list_selected == 2) { Object3D obj3d_0 = area.SpecialObjects[treeView1.SelectedNodes[0].Index]; @@ -897,6 +963,7 @@ private void updateAfterSelect(TreeNode node) objectComboPresetToolStripMenuItem.Enabled = false; objectComboNameToolStripMenuItem.Enabled = false; behaviorToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = false; if (Globals.list_selected != 2 || (Globals.list_selected == 2 && Globals.isMultiSelectedFromSpecialObjects)) break; } @@ -918,22 +985,25 @@ private void updateAfterSelect(TreeNode node) } //Console.WriteLine(hasSO_8 + "/" + hasSO_10 + "/" + hasSO_12); - if (atLeastTwoBools(hasSO_8, hasSO_10, hasSO_12)) { + if (atLeastTwoBools(hasSO_8, hasSO_10, hasSO_12)) + { Globals.isMultiSelectedFromSpecialObjects = true; objectComboPresetToolStripMenuItem.Enabled = false; objectComboNameToolStripMenuItem.Enabled = false; behaviorToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = false; if (Globals.isMultiSelectedFromMultipleLists) break; } } } - + Object3D[] selectedObjs = new Object3D[treeView1.SelectedNodes.Count]; + object[] selectedWarps = new object[treeView1.SelectedNodes.Count]; Object3D.FLAGS showFlags = Object3D.FLAGS.POSITION_X | Object3D.FLAGS.POSITION_Y | Object3D.FLAGS.POSITION_Z | - Object3D.FLAGS.ROTATION_Y | Object3D.FLAGS.BPARAM_1 | Object3D.FLAGS.BPARAM_2; - + Object3D.FLAGS.ROTATION_Y | Object3D.FLAGS.BPARAM_1 | Object3D.FLAGS.BPARAM_2;; + for (int i = 0; i < treeView1.SelectedNodes.Count; i++) { string local_parent_text = treeView1.SelectedNodes[i].Parent.Text; @@ -952,20 +1022,32 @@ private void updateAfterSelect(TreeNode node) else if (selectedObjs[i].createdFromLevelScriptCommand == Object3D.FROM_LS_CMD.CMD_2E_10) showFlags &= ~(Object3D.FLAGS.BPARAM_1 | Object3D.FLAGS.BPARAM_2); } + else if (local_parent_text.Equals("Warps")) + { + if (treeView1.SelectedNodes[i].Index < area.Warps.Count) + selectedWarps[i] = area.Warps[treeView1.SelectedNodes[i].Index]; + else if (treeView1.SelectedNodes[i].Index < area.Warps.Count + area.PaintingWarps.Count) + selectedWarps[i] = area.PaintingWarps[treeView1.SelectedNodes[i].Index - area.Warps.Count]; + else + selectedWarps[i] = area.InstantWarps[treeView1.SelectedNodes[i].Index - area.Warps.Count - area.PaintingWarps.Count]; + } } for (int i = 0; i < selectedObjs.Length; i++) { { selectedObjs[i].RevealTemporaryHiddenFields(); - // Console.WriteLine(Globals.isMultiSelectedFromSpecialObjects); + // Console.WriteLine(Globals.isMultiSelectedFromSpecialObjects); if (Globals.isMultiSelectedFromMultipleLists || Globals.isMultiSelectedFromSpecialObjects) { selectedObjs[i].HideFieldsTemporarly(showFlags); } } } - - propertyGrid1.SelectedObjects = selectedObjs; + + if(Globals.list_selected == 3) + propertyGrid1.SelectedObjects = selectedWarps; + else + propertyGrid1.SelectedObjects = selectedObjs; treeView1_updateMultiselection(); Globals.isMultiSelected = true; @@ -973,7 +1055,7 @@ private void updateAfterSelect(TreeNode node) glControl1.Update(); return; } - // Console.WriteLine("Single Node!"); + // Console.WriteLine("Single Node!"); Globals.isMultiSelected = false; Globals.isMultiSelectedFromMultipleLists = false; Globals.isMultiSelectedFromSpecialObjects = false; @@ -981,6 +1063,7 @@ private void updateAfterSelect(TreeNode node) if (node.Parent.Text.Equals("3D Objects")) { behaviorToolStripMenuItem.Enabled = true; + warpToolStripMenuItem.Enabled = false; Globals.list_selected = 0; Globals.item_selected = node.Index; propertyGrid1.SelectedObject = level.getCurrentArea().Objects[node.Index]; @@ -995,6 +1078,7 @@ private void updateAfterSelect(TreeNode node) else if (node.Parent.Text.Equals("Macro 3D Objects")) { behaviorToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = false; Globals.list_selected = 1; Globals.item_selected = node.Index; propertyGrid1.SelectedObject = level.getCurrentArea().MacroObjects[node.Index]; @@ -1009,6 +1093,7 @@ private void updateAfterSelect(TreeNode node) else if (node.Parent.Text.Equals("Special 3D Objects")) { behaviorToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = false; Globals.list_selected = 2; Globals.item_selected = node.Index; propertyGrid1.SelectedObject = level.getCurrentArea().SpecialObjects[node.Index]; @@ -1023,6 +1108,8 @@ private void updateAfterSelect(TreeNode node) else if (node.Parent.Text.Equals("Warps")) { behaviorToolStripMenuItem.Enabled = false; + objectComboNameToolStripMenuItem.Enabled = false; + warpToolStripMenuItem.Enabled = true; Globals.list_selected = 3; Globals.item_selected = node.Index; Area area = level.getCurrentArea(); @@ -1034,7 +1121,7 @@ private void updateAfterSelect(TreeNode node) propertyGrid1.SelectedObject = area.InstantWarps[node.Index - area.Warps.Count - area.PaintingWarps.Count]; } } - + Object3D obj = getSelectedObject(); if (obj != null) { @@ -1060,12 +1147,14 @@ private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) private void trackBar1_ValueChanged(object sender, EventArgs e) { + /* fovText.Text = "FOV: " + trackBar_FOV.Value + "°"; FOV = trackBar_FOV.Value * ((float)Math.PI/180.0f); if (FOV < 0.1f) FOV = 0.1f; ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, (float)glControl1.Width / (float)glControl1.Height, 100f, 100000f); glControl1.Invalidate(); + */ } private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) @@ -1120,7 +1209,7 @@ private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEv if (obj == null) continue; - + Object3D.FLAGS flag = obj.getFlagFromDisplayName(e.ChangedItem.Label); if (flag != 0) if (!obj.isPropertyShown(flag)) @@ -1162,7 +1251,9 @@ private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEv } else if (Globals.list_selected == 3) { - object warp = getSelectedWarp(); + int index = 0; + bool isPaintingWarp = false; + object warp = getSelectedWarp(out index, out isPaintingWarp); string warpTypeName = warp.GetType().Name; if (warpTypeName.Equals("Warp")) { @@ -1209,7 +1300,7 @@ private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) e.DrawDefault = true; } } - + private void radioButton2_CheckedChanged(object sender, EventArgs e) { if (radioButton2.Checked) @@ -1231,6 +1322,66 @@ private void radioButton1_CheckedChanged(object sender, EventArgs e) } + private void radioButton4_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_bottom.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.BOTTOM, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + + private void radioButton5_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_top.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.TOP, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + + private void radioButton_left_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_left.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.LEFT, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + + private void radioButton_right_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_right.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.RIGHT, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + + private void radioButton_front_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_front.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.FRONT, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + + private void radioButton_back_CheckedChanged(object sender, EventArgs e) + { + if (radioButton_back.Checked) + { + camera.setCameraMode_LookDirection(LookDirection.BACK, ref camMtx); + camera.updateMatrix(ref camMtx); + glControl1.Invalidate(); + } + } + private void starAct_CheckedChanged(object sender, EventArgs e) { RadioButton box = (RadioButton)sender; @@ -1263,7 +1414,7 @@ private void moveCam_InOut_MouseMove(object sender, MouseEventArgs e) glControl1.Invalidate(); } } - + bool moveCam_strafe_mouseDown = false; private void moveCam_strafe_MouseDown(object sender, MouseEventArgs e) { @@ -1285,7 +1436,7 @@ private void moveCam_strafe_MouseMove(object sender, MouseEventArgs e) glControl1.Invalidate(); } } - + private Object3D getSelectedObject() { if (Globals.list_selected == -1 || Globals.item_selected == -1) @@ -1320,22 +1471,28 @@ private Object3D getSelectedObject() } } - private object getSelectedWarp() + private object getSelectedWarp(out int warpIndex, out bool isPaintingWarp) { + isPaintingWarp = false; if (Globals.list_selected == -1 || Globals.item_selected == -1) + { + warpIndex = -1; return null; + } switch (Globals.list_selected) { case 3: { Area area = level.getCurrentArea(); int index = Globals.item_selected; + warpIndex = index; if (index < area.Warps.Count) { propertyGrid1.SelectedObject = area.Warps[index]; } else if (index < area.Warps.Count + area.PaintingWarps.Count) { + isPaintingWarp = true; propertyGrid1.SelectedObject = area.PaintingWarps[index - area.Warps.Count]; } else @@ -1345,7 +1502,37 @@ private object getSelectedWarp() return propertyGrid1.SelectedObject; } default: - return null; + { + warpIndex = -1; + return null; + } + } + } + + void updateSelectedWarpsInROM() + { + if (!Globals.isMultiSelected) + { + int index = 0; + bool isPaintingWarp = false; + object warp = getSelectedWarp(out index, out isPaintingWarp); + if (warp is Warp) + ((Warp)warp).updateROMData(); + else if (warp is WarpInstant) + ((WarpInstant)warp).updateROMData(); + } + else + { + Area area = level.getCurrentArea(); + foreach (int index in Globals.multi_selected_nodes[3]) + { + if (index < area.Warps.Count) + area.Warps[index].updateROMData(); + else if (index < area.Warps.Count + area.PaintingWarps.Count) + area.PaintingWarps[index - area.Warps.Count].updateROMData(); + else + area.InstantWarps[index - area.Warps.Count - area.PaintingWarps.Count].updateROMData(); + } } } @@ -1949,6 +2136,7 @@ private void trackBar2_ValueChanged(object sender, EventArgs e) Globals.objSpeedMultiplier = newValue / 100.0f; } + private const int WM_USER = 0x0400; private const int EM_SETEVENTMASK = (WM_USER + 69); private const int WM_SETREDRAW = 0x0b; diff --git a/src/Globals.cs b/src/Globals.cs index ad7bdb9..c0890e5 100644 --- a/src/Globals.cs +++ b/src/Globals.cs @@ -43,6 +43,7 @@ class Globals public static bool isMultiSelected = false; public static bool isMultiSelectedFromMultipleLists = false; public static bool isMultiSelectedFromSpecialObjects = false; + public static bool isMultiSelectedFromBothNormalWarpsAndInstantWarps = false; public static List> multi_selected_nodes = new List>(); // Keeps track if the user needs to save their changes. diff --git a/src/ROM.cs b/src/ROM.cs index 7a012d5..8afab6a 100644 --- a/src/ROM.cs +++ b/src/ROM.cs @@ -239,7 +239,7 @@ public void WriteToFileEx() } stream.Close(); } - + public void readFile(string filename) { filepath = filename; diff --git a/src/Scripts/CollisionMap.cs b/src/Scripts/CollisionMap.cs index d84e356..b6d0f48 100644 --- a/src/Scripts/CollisionMap.cs +++ b/src/Scripts/CollisionMap.cs @@ -135,15 +135,20 @@ public short dropToGround(Vector3 pos) } if (found.Count == 0) return (short)pos.Y; - - float highestY = -0x2000; + + int closest_index = 0; + float closest_abs = 9999999.0f; // Console.WriteLine("Found " + found.Count + " triangles under position"); for (int i = 0; i < found.Count; i++) { - if (found[i] > highestY) - highestY = found[i]; + float abs = Math.Abs(pos.Y - found[i]); + if(abs < closest_abs) + { + closest_abs = abs; + closest_index = i; + } } - return (short)highestY; + return (short)found[closest_index]; } public void buildCollisionMap() diff --git a/src/Scripts/LevelScripts.cs b/src/Scripts/LevelScripts.cs index e40c20f..92f1e9a 100644 --- a/src/Scripts/LevelScripts.cs +++ b/src/Scripts/LevelScripts.cs @@ -462,7 +462,6 @@ private static void CMD_22(ref Level lvl, ref string desc, byte[] cmd) if (modelID == 0x7A) Globals.DEBUG_PARSING_DL = true; - desc = "Define Model ID 0x" + modelID.ToString("X2") + "; Load Geometry layout from 0x" + seg.ToString("X2") + off.ToString("X6"); //Console.WriteLine("Size of seg 0x"+seg.ToString("X2")+" = " + rom.getSegment(seg).Length); diff --git a/src/Viewer/Camera.cs b/src/Viewer/Camera.cs index 897e3c5..462eb36 100644 --- a/src/Viewer/Camera.cs +++ b/src/Viewer/Camera.cs @@ -10,7 +10,15 @@ namespace Quad64 enum CameraMode { FLY = 0, - ORBIT = 1 + ORBIT = 1, + LOOK_DIRECTION = 2 + } + + enum LookDirection + { + TOP, BOTTOM, + LEFT, RIGHT, + FRONT, BACK } class Camera @@ -44,6 +52,17 @@ class Camera private float orbitDistance = 500.0f; private float orbitTheta = 0.0f, orbitPhi = 0.0f; + private LookDirection currentLookDirection; + private Vector3[] lookPositions = new Vector3[] + { + new Vector3(0, 12500, 0), // top + new Vector3(0, -12500, 0), // bottom + new Vector3(-12500, 0, 0), // left + new Vector3(12500, 0, 0), // right + new Vector3(0, 0, 12500), // front + new Vector3(0, 0, -12500) // back + }; + public Camera() { setRotationFromLookAt(); @@ -159,10 +178,57 @@ public void setCameraMode(CameraMode mode, ref Matrix4 cameraMatrix) } } + public void setCameraMode_LookDirection(LookDirection dir, ref Matrix4 cameraMatrix) + { + camMode = CameraMode.LOOK_DIRECTION; + currentLookDirection = dir; + switch (currentLookDirection) + { + case LookDirection.TOP: + pos = lookPositions[(int)LookDirection.TOP]; + lookat = new Vector3(pos.X, -25000, pos.Z - 1); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + case LookDirection.BOTTOM: + pos = lookPositions[(int)LookDirection.BOTTOM]; + lookat = new Vector3(pos.X, 25000, pos.Z + 1); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + case LookDirection.LEFT: + pos = lookPositions[(int)LookDirection.LEFT]; + lookat = new Vector3(25000, pos.Y, pos.Z); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + case LookDirection.RIGHT: + pos = lookPositions[(int)LookDirection.RIGHT]; + lookat = new Vector3(-25000, pos.Y, pos.Z); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + case LookDirection.FRONT: + pos = lookPositions[(int)LookDirection.FRONT]; + lookat = new Vector3(pos.X, pos.Y, -25000); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + case LookDirection.BACK: + pos = lookPositions[(int)LookDirection.BACK]; + lookat = new Vector3(pos.X, pos.Y, 25000); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + setRotationFromLookAt(); + break; + } + } + public void updateCameraMatrixWithMouse(int mouseX, int mouseY, ref Matrix4 cameraMatrix) { if (camMode == CameraMode.ORBIT && Globals.item_selected > -1) updateCameraMatrixWithMouse_ORBIT(mouseX, mouseY, ref cameraMatrix); + else if (camMode == CameraMode.LOOK_DIRECTION) + updateCameraMatrixWithMouse_LOOK(pos, mouseX, mouseY, ref cameraMatrix); else updateCameraMatrixWithMouse_FLY(mouseX, mouseY, ref cameraMatrix); } @@ -171,6 +237,8 @@ public void updateCameraOffsetWithMouse(Vector3 orgPos, int mouseX, int mouseY, { if (camMode == CameraMode.ORBIT && Globals.item_selected > -1) updateCameraOffsetWithMouse_ORBIT(mouseX, mouseY, ref cameraMatrix); + else if (camMode == CameraMode.LOOK_DIRECTION) + updateCameraMatrixWithMouse_LOOK(pos, mouseX, mouseY, ref cameraMatrix); else updateCameraOffsetWithMouse_FLY(orgPos, mouseX, mouseY, w, h, ref cameraMatrix); } @@ -179,6 +247,8 @@ public void updateCameraMatrixWithScrollWheel(int amt, ref Matrix4 cameraMatrix) { if (camMode == CameraMode.ORBIT && Globals.item_selected > -1) updateCameraMatrixWithScrollWheel_ORBIT(amt, ref cameraMatrix); + else if (camMode == CameraMode.LOOK_DIRECTION) + updateCameraMatrixWithScrollWheel_LOOK(amt, ref cameraMatrix); else updateCameraMatrixWithScrollWheel_FLY(amt, ref cameraMatrix); } @@ -195,6 +265,97 @@ public void updateMatrix(ref Matrix4 cameraMatrix) cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); } + private void updateCameraMatrixWithScrollWheel_LOOK(int amt, ref Matrix4 cameraMatrix) + { + offsetCam(amt, amt, amt); + orientateCam(CamAngleX, CamAngleY); + switch (currentLookDirection) + { + case LookDirection.TOP: + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z - 1, 0, 1, 0); + break; + case LookDirection.BOTTOM: + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z + 1, 0, 1, 0); + break; + default: + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, lookat.X, lookat.Y, lookat.Z, 0, 1, 0); + break; + } + } + + private void updateCameraMatrixWithMouse_LOOK(Vector3 orgPos, int mouseX, int mouseY, ref Matrix4 cameraMatrix) + { + if (resetMouse) + { + lastMouseX = mouseX; + lastMouseY = mouseY; + resetMouse = false; + } + int MousePosX = mouseX - lastMouseX; + int MousePosY = mouseY - lastMouseY; + + double pitch = CamAngleY - (Math.PI / 2); + double yaw = CamAngleX - (Math.PI / 2); + float CamLX = (float)Math.Sin(yaw); + float CamLY = (float)Math.Cos(pitch); + float CamLZ = (float)-Math.Cos(yaw); + + float m = 8f; + + switch (currentLookDirection) + { + case LookDirection.TOP: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m) - + ((MousePosY * Globals.camSpeedMultiplier) * (CamLZ) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m) - + ((MousePosY * Globals.camSpeedMultiplier) * (CamLX) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y - 1000, pos.Z - 1, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + case LookDirection.BOTTOM: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m) + + ((MousePosY * Globals.camSpeedMultiplier) * (CamLZ) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m) + + ((MousePosY * Globals.camSpeedMultiplier) * (CamLX) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y + 1000, pos.Z + 1, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + case LookDirection.LEFT: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m); + pos.Y = orgPos.Y - ((MousePosY * Globals.camSpeedMultiplier) * (-1f) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X + 12500, pos.Y, pos.Z, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + case LookDirection.RIGHT: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m); + pos.Y = orgPos.Y - ((MousePosY * Globals.camSpeedMultiplier) * (-1f) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X - 12500, pos.Y, pos.Z, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + case LookDirection.FRONT: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m); + pos.Y = orgPos.Y - ((MousePosY * Globals.camSpeedMultiplier) * (-1f) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y, pos.Z - 12500, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + case LookDirection.BACK: + pos.X = orgPos.X - ((MousePosX * Globals.camSpeedMultiplier) * (CamLX) * m); + pos.Y = orgPos.Y - ((MousePosY * Globals.camSpeedMultiplier) * (-1f) * m); + pos.Z = orgPos.Z - ((MousePosX * Globals.camSpeedMultiplier) * (CamLZ) * m); + cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y, pos.Z + 12500, 0, 1, 0); + lookPositions[(int)currentLookDirection] = pos; + break; + } + + lastMouseX = mouseX; + lastMouseY = mouseY; + //Console.WriteLine("CamAngleX = " + CamAngleX + ", CamAngleY = " + CamAngleY); + //setRotationFromLookAt(); + } + private void updateCameraMatrixWithMouse_FLY(int mouseX, int mouseY, ref Matrix4 cameraMatrix) { if (resetMouse)