#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 vslopeTags; // SortedDictionary public SortedDictionary> 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>(); 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 thingsList = new List(); thingsList.Add(t); vslopeDic.Add(t.AngleDoom, thingsList); } } } // Generate ListBox items vslopeTags = new List(); vslopegroups.Items.Clear(); foreach (KeyValuePair> 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 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 GetThingsList() { int tagid = tagID.GetResult(0); bool tagexist = vslopeTags.Contains(tagid); if (tagexist) { return vslopeDic[tagid]; } return null; } public List GetThingsList(int tagid) { bool tagexist = vslopeTags.Contains(tagid); if (tagexist) { return vslopeDic[tagid]; } return null; } public int GetGroupsAt(Vector2D pos, ref List groups, bool vertexgroups, bool trianglegroups) { int numgroups = 0; foreach (KeyValuePair> 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 } }