ZoneBuilder/Source/Plugins/BuilderModes/Interface/VertexSlopeAssistForm.cs

603 lines
17 KiB
C#

#region ================== Namespaces
using System;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.Geometry;
using System.Drawing;
using System.Collections.Generic;
using CodeImp.DoomBuilder.Map;
#endregion
//JBR Vertex Slope Assistant form
namespace CodeImp.DoomBuilder.BuilderModes.Interface
{
public partial class VertexSlopeAssistForm : DelayedForm
{
#region ================== Properties / Variables
[Serializable]
public delegate void ContextEventHandler(object sender, int action);
private bool blockEvents;
public event EventHandler OnDrawNewTaggedTriangle;
public event EventHandler OnDrawNewEmptyTriangle;
public event EventHandler OnGroupChanged;
public event EventHandler OnGroupChoosen;
public event EventHandler OnGroupNewTriangle;
public event EventHandler OnGroupNewVertex;
public event EventHandler OnGroupModify;
public event EventHandler OnGroupModifyAsTriangle;
public event EventHandler OnGroupModifyAsVertex;
public event EventHandler OnGroupTag;
public event EventHandler OnGroupDelete;
public event EventHandler OnValueChanged;
public event EventHandler OnRotateAll;
public event EventHandler OnFlipAll;
public event EventHandler OnRotateHeight;
public event EventHandler OnFlipHeight;
public event ContextEventHandler OnContextSet;
public bool AffineVSlopes { get { return affinevslopes.Checked; } }
public int TagID { get { return tagID.GetResult(0); } set { tagID.Text = value.ToString(); UpdateForm(); } }
public Vector3D Vertex1 { get { return GetVector3DFromUI(vslopeX1, vslopeY1, vslopeZ1); } set { SetVector3DFromUI(vslopeX1, vslopeY1, vslopeZ1, value); } }
public Vector3D Vertex2 { get { return GetVector3DFromUI(vslopeX2, vslopeY2, vslopeZ2); } set { SetVector3DFromUI(vslopeX2, vslopeY2, vslopeZ2, value); } }
public Vector3D Vertex3 { get { return GetVector3DFromUI(vslopeX3, vslopeY3, vslopeZ3); } set { SetVector3DFromUI(vslopeX3, vslopeY3, vslopeZ3, value); } }
public bool Vertex1AbsZ { get { return vslopeAbsZ1.Checked; } set { vslopeAbsZ1.Checked = value; } }
public bool Vertex2AbsZ { get { return vslopeAbsZ2.Checked; } set { vslopeAbsZ2.Checked = value; } }
public bool Vertex3AbsZ { get { return vslopeAbsZ3.Checked; } set { vslopeAbsZ3.Checked = value; } }
public string ModeText { get { return currentmode.Text; } set { currentmode.Text = value; } }
public const int HEIGHTADJ_STEP = 1;
public const int HEIGHTADJ_SMALL = 4;
public const int HEIGHTADJ_BIG = 16;
// List[GroupIndex] = Linedef Tag
public List<int> vslopeTags;
// SortedDictionary<Linedef Tag, List of VSlopes>
public SortedDictionary<int, List<Thing>> vslopeDic;
#endregion
#region ================== Constructor / Disposer
public VertexSlopeAssistForm()
{
InitializeComponent();
blockEvents = true;
vslopeX1.Text = "0";
vslopeY1.Text = "0";
vslopeZ1.Text = "0";
vslopeX2.Text = "0";
vslopeY2.Text = "0";
vslopeZ2.Text = "0";
vslopeX3.Text = "0";
vslopeY3.Text = "0";
vslopeZ3.Text = "0";
tooltip.SetToolTip(heightAdj, string.Format("Hold Ctrl to change value by {0}.\nHold Shift to change value by {1}.", HEIGHTADJ_SMALL, HEIGHTADJ_BIG));
CreateList();
tagID.Text = General.Map.Map.GetNewTag(vslopeTags).ToString();
blockEvents = false;
}
#endregion
#region ================== Methods
private Vector3D GetVector3DFromUI(Controls.ButtonsNumericTextbox X, Controls.ButtonsNumericTextbox Y, Controls.ButtonsNumericTextbox Z)
{
return new Vector3D(X.GetResult(0), Y.GetResult(0), Z.GetResult(0));
}
private void SetVector3DFromUI(Controls.ButtonsNumericTextbox X, Controls.ButtonsNumericTextbox Y, Controls.ButtonsNumericTextbox Z, Vector3D value)
{
blockEvents = true;
X.Text = value.x.ToString();
Y.Text = value.y.ToString();
Z.Text = value.z.ToString();
blockEvents = false;
}
// http://www.jeffreythompson.org/collision-detection/tri-point.php
private bool TriangleCollision(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y, float px, float py)
{
// get the area of the triangle
float areaOrig = Math.Abs((p2x - p1x) * (p3y - p1y) - (p3x - p1x) * (p2y - p1y));
// get the area of 3 triangles made between the point and the corners of the triangle
float area1 = Math.Abs((p1x - px) * (p2y - py) - (p2x - px) * (p1y - py));
float area2 = Math.Abs((p2x - px) * (p3y - py) - (p3x - px) * (p2y - py));
float area3 = Math.Abs((p3x - px) * (p1y - py) - (p1x - px) * (p3y - py));
// if the sum of the three areas equals the original, we're inside the triangle!
return (area1 + area2 + area3 == areaOrig);
}
private bool PointBoxCollision(float px, float py, float left, float bottom, float width, float height)
{
// Graphic axis direction of going up being positive
float right = left + width;
float top = bottom + height;
return px >= left && px < right && py >= bottom && py < top;
}
public void OpenContextLinedefMenu(int mx, int my, bool tagexist)
{
setAction704Item.Enabled = tagexist;
setAction705Item.Enabled = tagexist;
setAction714Item.Enabled = tagexist;
setAction715Item.Enabled = tagexist;
contextVSlopeLinedef.Show(mx, my);
}
public void OpenContextGroupMenu(int mx, int my, bool tagexist)
{
if (tagexist)
contextExistingGroup.Show(mx, my);
else
contextNewGroup.Show(mx, my);
}
public void CreateList()
{
// Create dictionary
vslopeDic = new SortedDictionary<int, List<Thing>>();
vslopegroups.Items.Clear();
foreach (Thing t in General.Map.Map.Things)
{
if (t.SRB2Type == 750) // Vertex Slope
{
if (vslopeDic.ContainsKey(t.AngleDoom))
{
vslopeDic[t.AngleDoom].Add(t);
}
else
{
List<Thing> thingsList = new List<Thing>();
thingsList.Add(t);
vslopeDic.Add(t.AngleDoom, thingsList);
}
}
}
// Generate ListBox items
vslopeTags = new List<int>();
vslopegroups.Items.Clear();
foreach (KeyValuePair<int, List<Thing>> kvp in vslopeDic)
{
vslopeTags.Add(kvp.Key);
if (kvp.Value.Count == 3)
{
vslopegroups.Items.Add(string.Format("Tag {0} - Triangle", kvp.Key));
}
else if (kvp.Value.Count == 1)
{
vslopegroups.Items.Add(string.Format("Tag {0} - Vertex", kvp.Key));
}
else
{
vslopegroups.Items.Add(string.Format("Tag {0} - INVALID! {1} Vertices", kvp.Key, kvp.Value.Count));
}
}
// Select tag from list
int tagid = tagID.GetResult(0);
vslopegroups.SelectedIndex = vslopeTags.IndexOf(tagid);
}
public void UpdateForm()
{
blockEvents = true;
int tagid = tagID.GetResult(0);
bool tagexist = vslopeTags.Contains(tagid);
toolNewTriangleGroup.Enabled = !tagexist;
toolNewVertexGroup.Enabled = !tagexist;
toolRemakeGroup.Enabled = tagexist;
toolRemakeAsTriangleGroup.Enabled = tagexist;
toolRemakeAsVertexGroup.Enabled = tagexist;
toolChangeTagGroup.Enabled = tagexist;
toolDeleteGroup.Enabled = tagexist;
toolDrawNewTaggedTriangle.Enabled = !tagexist;
if (tagexist)
vslopegroups.ContextMenuStrip = contextExistingGroup;
else
vslopegroups.ContextMenuStrip = contextNewGroup;
vslopegroups.SelectedIndex = vslopeTags.IndexOf(tagid);
if (tagexist)
{
List<Thing> things = vslopeDic[tagid];
if (things.Count >= 1)
{
Thing thing = things[0];
Vector3D pos = thing.Position;
vslopeX1.Text = pos.x.ToString();
vslopeY1.Text = pos.y.ToString();
if (thing.Parameter == 0)
{
vslopeAbsZ1.Checked = false;
labelVSlope1.Text = "H1:";
vslopeZ1.Text = pos.z.ToString();
}
else
{
vslopeAbsZ1.Checked = true;
labelVSlope1.Text = "Z1:";
vslopeZ1.Text = thing.GetFlagsValue().ToString();
}
}
if (things.Count >= 2)
{
Thing thing = things[1];
Vector3D pos = thing.Position;
vslopeX2.Text = pos.x.ToString();
vslopeY2.Text = pos.y.ToString();
if (thing.Parameter == 0)
{
vslopeAbsZ2.Checked = false;
labelVSlope2.Text = "H2:";
vslopeZ2.Text = pos.z.ToString();
}
else
{
vslopeAbsZ2.Checked = true;
labelVSlope2.Text = "Z2:";
vslopeZ2.Text = thing.GetFlagsValue().ToString();
}
}
if (things.Count >= 3)
{
Thing thing = things[2];
Vector3D pos = thing.Position;
vslopeX3.Text = pos.x.ToString();
vslopeY3.Text = pos.y.ToString();
if (thing.Parameter == 0)
{
vslopeAbsZ3.Checked = false;
labelVSlope3.Text = "H3:";
vslopeZ3.Text = pos.z.ToString();
}
else
{
vslopeAbsZ3.Checked = true;
labelVSlope3.Text = "Z3:";
vslopeZ3.Text = thing.GetFlagsValue().ToString();
}
}
vslopeX1.Enabled = (things.Count >= 1);
vslopeY1.Enabled = (things.Count >= 1);
vslopeZ1.Enabled = (things.Count >= 1);
vslopeAbsZ1.Enabled = (things.Count >= 1);
vslopeX2.Enabled = (things.Count >= 2);
vslopeY2.Enabled = (things.Count >= 2);
vslopeZ2.Enabled = (things.Count >= 2);
vslopeAbsZ2.Enabled = (things.Count >= 2);
vslopeX3.Enabled = (things.Count >= 3);
vslopeY3.Enabled = (things.Count >= 3);
vslopeZ3.Enabled = (things.Count >= 3);
vslopeAbsZ3.Enabled = (things.Count >= 3);
}
else
{
vslopeX1.Enabled = false;
vslopeY1.Enabled = false;
vslopeZ1.Enabled = true;
vslopeAbsZ1.Enabled = true;
vslopeX2.Enabled = false;
vslopeY2.Enabled = false;
vslopeZ2.Enabled = true;
vslopeAbsZ2.Enabled = true;
vslopeX3.Enabled = false;
vslopeY3.Enabled = false;
vslopeZ3.Enabled = true;
vslopeAbsZ3.Enabled = true;
}
blockEvents = false;
}
public int VerticesInTag()
{
int tagid = tagID.GetResult(0);
bool tagexist = vslopeTags.Contains(tagid);
if (tagexist)
{
return vslopeDic[tagid].Count;
}
return 0;
}
public int VerticesInTag(int tagid)
{
bool tagexist = vslopeTags.Contains(tagid);
if (tagexist)
{
return vslopeDic[tagid].Count;
}
return 0;
}
public List<Thing> GetThingsList()
{
int tagid = tagID.GetResult(0);
bool tagexist = vslopeTags.Contains(tagid);
if (tagexist)
{
return vslopeDic[tagid];
}
return null;
}
public List<Thing> GetThingsList(int tagid)
{
bool tagexist = vslopeTags.Contains(tagid);
if (tagexist)
{
return vslopeDic[tagid];
}
return null;
}
public int GetGroupsAt(Vector2D pos, ref List<int> groups, bool vertexgroups, bool trianglegroups)
{
int numgroups = 0;
foreach (KeyValuePair<int, List<Thing>> kvp in vslopeDic)
{
if (vertexgroups && kvp.Value.Count == 1)
{
if (PointBoxCollision(pos.x, pos.y, kvp.Value[0].Position.x - 8f, kvp.Value[0].Position.y - 8f, 16f, 16f))
{
numgroups++;
groups.Add(kvp.Key);
}
}
else if (trianglegroups && kvp.Value.Count == 3)
{
if (TriangleCollision(
kvp.Value[0].Position.x, kvp.Value[0].Position.y,
kvp.Value[1].Position.x, kvp.Value[1].Position.y,
kvp.Value[2].Position.x, kvp.Value[2].Position.y,
pos.x, pos.y))
{
numgroups++;
groups.Add(kvp.Key);
}
}
}
return numgroups;
}
#endregion
#region ================== Interface
// Window closing
private void VertexSlopeAssistForm_FormClosing(object sender, FormClosingEventArgs e)
{
// User closing the window?
if (e.CloseReason == CloseReason.UserClosing)
{
// Just cancel
General.Editing.CancelMode();
e.Cancel = true;
}
}
// This shows the window
public void Show(Form owner)
{
// Position at left-top of owner
this.Location = new Point(owner.Location.X + 20, owner.Location.Y + 90);
blockEvents = true;
CreateList();
blockEvents = false;
tagID_ValueChanged(tagID, EventArgs.Empty);
// Show window
base.Show(owner);
}
// Some value got changed
private void ValueChanged(object sender, EventArgs e)
{
if (!blockEvents) General.Interface.RedrawDisplay();
}
// Cancel clicked
private void cancel_Click(object sender, EventArgs e)
{
// Cancel now
General.Editing.CancelMode();
}
// Apply clicked
private void apply_Click(object sender, EventArgs e)
{
// Apply now
General.Editing.AcceptMode();
}
private void VertexSlopeAssistForm_HelpRequested(object sender, HelpEventArgs hlpevent)
{
General.ShowHelp("e_vertexslopeassist.html");
}
private void tagID_ValueChanged(object sender, EventArgs e)
{
if (blockEvents) return;
UpdateForm();
if (OnGroupChanged != null) OnGroupChanged(sender, e);
ValueChanged(sender, e);
}
private void vslopegroups_SelectedIndexChanged(object sender, EventArgs e)
{
if (blockEvents) return;
if (vslopegroups.SelectedIndex == -1) return;
int tagid = vslopeTags[vslopegroups.SelectedIndex];
tagID.Text = tagid.ToString();
if (OnGroupChanged != null) OnGroupChanged(sender, e);
ValueChanged(sender, e);
}
private void vslopegroups_DoubleClick(object sender, EventArgs e)
{
if (OnGroupChoosen != null) OnGroupChoosen(sender, e);
ValueChanged(sender, e);
}
private void drawNewTaggedTriangle_Click(object sender, EventArgs e)
{
if (OnDrawNewTaggedTriangle != null) OnDrawNewTaggedTriangle(sender, e);
ValueChanged(sender, e);
}
private void drawNewEmptyTriangle_Click(object sender, EventArgs e)
{
if (OnDrawNewEmptyTriangle != null) OnDrawNewEmptyTriangle(sender, e);
ValueChanged(sender, e);
}
private void newtag_Click(object sender, EventArgs e)
{
tagID.Text = General.Map.Map.GetNewTag(vslopeTags).ToString();
ValueChanged(sender, e);
}
private void newTriangleGroup_Click(object sender, EventArgs e)
{
if (OnGroupNewTriangle != null) OnGroupNewTriangle(sender, e);
ValueChanged(sender, e);
}
private void newVertexGroup_Click(object sender, EventArgs e)
{
if (OnGroupNewVertex != null) OnGroupNewVertex(sender, e);
ValueChanged(sender, e);
}
private void remakeGroup_Click(object sender, EventArgs e)
{
if (OnGroupModify != null) OnGroupModify(sender, e);
ValueChanged(sender, e);
}
private void remakeAsTriangleGroup_Click(object sender, EventArgs e)
{
if (OnGroupModifyAsTriangle != null) OnGroupModifyAsTriangle(sender, e);
ValueChanged(sender, e);
}
private void remakeAsVertexGroup_Click(object sender, EventArgs e)
{
if (OnGroupModifyAsVertex != null) OnGroupModifyAsVertex(sender, e);
ValueChanged(sender, e);
}
private void changeTagGroup_Click(object sender, EventArgs e)
{
if (OnGroupTag != null) OnGroupTag(sender, e);
ValueChanged(sender, e);
}
private void deleteGroup_Click(object sender, EventArgs e)
{
if (OnGroupDelete != null) OnGroupDelete(sender, e);
ValueChanged(sender, e);
}
private void vslope_ValueChanged(object sender, EventArgs e)
{
if (blockEvents) return;
if (OnValueChanged != null) OnValueChanged(sender, e);
ValueChanged(sender, e);
}
private void rot_all_Click(object sender, EventArgs e)
{
if (OnRotateAll != null) OnRotateAll(sender, e);
ValueChanged(sender, e);
}
private void flip_all_Click(object sender, EventArgs e)
{
if (OnFlipAll != null) OnFlipAll(sender, e);
ValueChanged(sender, e);
}
private void rot_height_Click(object sender, EventArgs e)
{
if (OnRotateHeight != null) OnRotateHeight(sender, e);
ValueChanged(sender, e);
}
private void flip_height_Click(object sender, EventArgs e)
{
if (OnFlipHeight != null) OnFlipHeight(sender, e);
ValueChanged(sender, e);
}
private void heightAdj_ValueChanged(object sender, EventArgs e)
{
int adjust = -heightAdj.Value;
// Modifiers
if ((ModifierKeys & Keys.Control) == Keys.Control)
adjust *= HEIGHTADJ_SMALL;
else if ((ModifierKeys & Keys.Shift) == Keys.Shift)
adjust *= HEIGHTADJ_BIG;
else
adjust *= HEIGHTADJ_STEP;
// Adjust heights...
vslopeZ1.Text = (vslopeZ1.GetResult(0) + adjust).ToString();
vslopeZ2.Text = (vslopeZ2.GetResult(0) + adjust).ToString();
vslopeZ3.Text = (vslopeZ3.GetResult(0) + adjust).ToString();
heightAdj.Value = 0;
}
private void setAction704Item_Click(object sender, EventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, 704);
ValueChanged(sender, e);
}
private void setAction705Item_Click(object sender, EventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, 705);
ValueChanged(sender, e);
}
private void setAction714Item_Click(object sender, EventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, 714);
ValueChanged(sender, e);
}
private void setAction715Item_Click(object sender, EventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, 715);
ValueChanged(sender, e);
}
private void removeActionItem_Click(object sender, EventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, 0);
ValueChanged(sender, e);
}
private void contextVSlopeLinedef_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
if (OnContextSet != null) OnContextSet(sender, -1);
ValueChanged(sender, e);
}
#endregion
}
}