UltimateZoneBuilder/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs
MaxED 3d2d9e21ef Changed, Classic modes: displayed mouse map position coordinates are now snapped to current grid size.
Updated model pitch handling to match current GZDoom implementation.
Fixed imprecise vertex coordinates generated by Draw Ellipse mode.
Fixed a resource loading exception when opened map file wad was located in the root of a Directory resource.
Internal: changed output of all InterpolationTools methods from int to float.
Fixed, Internal: InterpolationTools.InterpolateColor() delta usage was inverted.
2016-06-03 20:22:07 +00:00

262 lines
8 KiB
C#

#region ================== Namespaces
using System;
using System.Collections.Generic;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Draw Ellipse Mode",
SwitchAction = "drawellipsemode",
ButtonImage = "DrawEllipseMode.png", //mxd
ButtonOrder = int.MinValue + 4, //mxd
ButtonGroup = "000_drawing", //mxd
AllowCopyPaste = false,
Volatile = true,
Optional = false)]
public class DrawEllipseMode : DrawRectangleMode
{
#region ================== Variables
// Interface
private DrawEllipseOptionsPanel panel;
// Drawing
private float angle; // in radians
#endregion
#region ================== Constructor
public DrawEllipseMode()
{
autoclosedrawing = false;
}
#endregion
#region ================== Settings panel
override protected void SetupInterface()
{
maxsubdivisions = 512;
minsubdivisions = 3;
minpointscount = 3;
alwaysrendershapehints = true;
// Load stored settings
subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawellipsemode.subdivisions", 8), minsubdivisions, maxsubdivisions);
bevelwidth = General.Settings.ReadPluginSetting("drawellipsemode.bevelwidth", 0);
int angledeg = General.Settings.ReadPluginSetting("drawellipsemode.angle", 0);
angle = Angle2D.DegToRad(angledeg);
currentbevelwidth = bevelwidth;
//Add options docker
panel = new DrawEllipseOptionsPanel();
panel.MaxSubdivisions = maxsubdivisions;
panel.MinSubdivisions = minsubdivisions;
panel.MinSpikiness = (int)General.Map.FormatInterface.MinCoordinate;
panel.MaxSpikiness = (int)General.Map.FormatInterface.MaxCoordinate;
panel.Spikiness = bevelwidth;
panel.Angle = angledeg;
panel.Subdivisions = subdivisions;
panel.OnValueChanged += OptionsPanelOnValueChanged;
panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
// Needs to be set after adding the OnContinuousDrawingChanged event...
panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawellipsemode.continuousdrawing", false);
}
override protected void AddInterface()
{
panel.Register();
}
override protected void RemoveInterface()
{
// Store settings
General.Settings.WritePluginSetting("drawellipsemode.subdivisions", subdivisions);
General.Settings.WritePluginSetting("drawellipsemode.bevelwidth", bevelwidth);
General.Settings.WritePluginSetting("drawellipsemode.angle", panel.Angle);
General.Settings.WritePluginSetting("drawellipsemode.continuousdrawing", panel.ContinuousDrawing);
// Remove the buttons
panel.Unregister();
}
#endregion
#region ================== Methods
override protected Vector2D[] GetShape(Vector2D pStart, Vector2D pEnd)
{
// No shape
if(pEnd.x == pStart.x && pEnd.y == pStart.y) return new Vector2D[0];
// Line
if(pEnd.x == pStart.x || pEnd.y == pStart.y) return new[] { pStart, pEnd };
// Got shape
if(subdivisions < 6)
currentbevelwidth = 0; // Works strange otherwise
else if(bevelwidth < 0)
currentbevelwidth = -Math.Min(Math.Abs(bevelwidth), Math.Min(width, height) / 2) + 1;
else
currentbevelwidth = bevelwidth;
Vector2D[] shape = new Vector2D[subdivisions + 1];
bool doBevel = false;
float hw = width / 2.0f;
float hh = height / 2.0f;
Vector2D center = new Vector2D(pStart.x + hw, pStart.y + hh);
float curAngle = angle;
float angleStep = -Angle2D.PI / subdivisions * 2;
for(int i = 0; i < subdivisions; i++)
{
float px, py;
if(doBevel)
{
px = (float)Math.Round(center.x - (float)Math.Sin(curAngle) * (hw + currentbevelwidth));
py = (float)Math.Round(center.y - (float)Math.Cos(curAngle) * (hh + currentbevelwidth));
}
else
{
px = (float)Math.Round(center.x - (float)Math.Sin(curAngle) * hw);
py = (float)Math.Round(center.y - (float)Math.Cos(curAngle) * hh);
}
doBevel = !doBevel;
shape[i] = new Vector2D(px, py);
curAngle += angleStep;
}
// Add final point
shape[subdivisions] = shape[0];
return shape;
}
protected override string GetHintText()
{
List<string> result = new List<string>();
if(bevelwidth != 0) result.Add("BVL: " + bevelwidth);
if(subdivisions != 0) result.Add("VERTS: " + subdivisions);
if(panel.Angle != 0) result.Add("ANGLE: " + panel.Angle);
return string.Join("; ", result.ToArray());
}
#endregion
#region ================== Events
public override void OnAccept()
{
switch(points.Count - 1) // Last point matches the first one
{
case 3: undoname = "Triangle draw"; shapename = "triangle"; break;
case 4: undoname = "Rhombus draw"; shapename = "rhombus"; break;
case 5: undoname = "Pentagon draw"; shapename = "pentagon"; break;
case 6: undoname = "Hexagon draw"; shapename = "hexagon"; break;
case 7: undoname = "Heptagon draw"; shapename = "heptagon"; break;
case 8: undoname = "Octagon draw"; shapename = "octagon"; break;
case 9: undoname = "Enneagon draw"; shapename = "enneagon"; break;
case 10: undoname = "Decagon draw"; shapename = "decagon"; break;
case 11: undoname = "Hendecagon draw"; shapename = "hendecagon"; break;
case 12: undoname = "Dodecagon draw"; shapename = "dodecagon"; break;
case 13: undoname = "Tridecagon draw"; shapename = "tridecagon"; break;
case 14: undoname = "Tetradecagon draw"; shapename = "tetradecagon"; break;
case 15: undoname = "Pentadecagon draw"; shapename = "pentadecagon"; break;
case 16: undoname = "Hexadecagon draw"; shapename = "hexadecagon"; break;
case 17: undoname = "Heptadecagon draw"; shapename = "heptadecagon"; break;
case 18: undoname = "Octadecagon draw"; shapename = "octadecagon"; break;
case 19: undoname = "Enneadecagon draw"; shapename = "enneadecagon"; break;
case 20: undoname = "Icosagon draw"; shapename = "icosagon"; break;
default: undoname = "Ellipse draw"; shapename = "ellipse"; break;
}
base.OnAccept();
}
private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs)
{
bevelwidth = panel.Spikiness;
subdivisions = Math.Min(maxsubdivisions, panel.Subdivisions);
angle = Angle2D.DegToRad(panel.Angle);
Update();
}
public override void OnHelp()
{
General.ShowHelp("/gzdb/features/classic_modes/mode_drawellipse.html");
}
#endregion
#region ================== Actions
override protected void IncreaseSubdivLevel()
{
if(maxsubdivisions - subdivisions > 1)
{
subdivisions += (subdivisions % 2 != 0 ? 1 : 2);
panel.Subdivisions = subdivisions;
Update();
}
}
override protected void DecreaseSubdivLevel()
{
if(subdivisions - minsubdivisions > 1)
{
subdivisions -= (subdivisions % 2 != 0 ? 1 : 2);
panel.Subdivisions = subdivisions;
Update();
}
}
protected override void IncreaseBevel()
{
if(points.Count < 2 || currentbevelwidth == bevelwidth || bevelwidth < 0)
{
bevelwidth = Math.Min(bevelwidth + General.Map.Grid.GridSize, panel.MaxSpikiness);
panel.Spikiness = bevelwidth;
Update();
}
}
protected override void DecreaseBevel()
{
if(bevelwidth > 0 || currentbevelwidth <= bevelwidth + 1)
{
bevelwidth = Math.Max(bevelwidth - General.Map.Grid.GridSize, panel.MinSpikiness);
panel.Spikiness = bevelwidth;
Update();
}
}
[BeginAction("rotateclockwise")]
private void IncreaseAngle()
{
panel.Angle = General.ClampAngle(panel.Angle + 5);
angle = Angle2D.DegToRad(panel.Angle);
Update();
}
[BeginAction("rotatecounterclockwise")]
private void DecreaseAngle()
{
panel.Angle = General.ClampAngle(panel.Angle - 5);
angle = Angle2D.DegToRad(panel.Angle);
Update();
}
#endregion
}
}