mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2025-02-06 15:51:04 +00:00
764 lines
21 KiB
C#
764 lines
21 KiB
C#
|
#region ================== Namespaces
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Drawing;
|
|||
|
using System.Windows.Forms;
|
|||
|
using CodeImp.DoomBuilder.Actions;
|
|||
|
using CodeImp.DoomBuilder.Controls;
|
|||
|
using CodeImp.DoomBuilder.Editing;
|
|||
|
using CodeImp.DoomBuilder.Geometry;
|
|||
|
using CodeImp.DoomBuilder.Map;
|
|||
|
using CodeImp.DoomBuilder.Rendering;
|
|||
|
using CodeImp.DoomBuilder.Windows;
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
//JBR Draw Shape Mode
|
|||
|
namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
{
|
|||
|
[EditMode(DisplayName = "Draw Shape Mode",
|
|||
|
SwitchAction = "drawshapemode",
|
|||
|
ButtonImage = "DrawShapeMode.png",
|
|||
|
ButtonOrder = int.MinValue + 6,
|
|||
|
ButtonGroup = "000_drawing",
|
|||
|
AllowCopyPaste = false,
|
|||
|
Volatile = true,
|
|||
|
Optional = false)]
|
|||
|
|
|||
|
public class DrawShapeMode : DrawGeometryMode
|
|||
|
{
|
|||
|
#region ================== Variables
|
|||
|
|
|||
|
public const int CLOSESHAPE_ORIGIN = 0;
|
|||
|
public const int CLOSESHAPE_VERTICES = 1;
|
|||
|
public const int SHAPE = 2;
|
|||
|
public const int LINEDEFS = 3;
|
|||
|
public const int VERTICES = 4;
|
|||
|
public const int THINGS = 5;
|
|||
|
|
|||
|
protected static int thingtype = 1; // Changed when adding things
|
|||
|
|
|||
|
protected static bool previewreference = true;
|
|||
|
protected static bool ellipse = true;
|
|||
|
protected static int firstpointtype = 0;
|
|||
|
protected static int sides = 8;
|
|||
|
protected static int spikiness = 0;
|
|||
|
protected static int spikingmode = 0;
|
|||
|
protected static int createas = 0;
|
|||
|
protected static bool frontoutside = false;
|
|||
|
protected static float startangle = 0f;
|
|||
|
protected static float sweepangle = Angle2D.PI2;
|
|||
|
protected static bool limitonquad = true;
|
|||
|
protected static int transformonquad = 0; // Leave as always 0 for now
|
|||
|
|
|||
|
protected Vector2D start;
|
|||
|
protected Vector2D end;
|
|||
|
protected Vector2D origin;
|
|||
|
|
|||
|
//interface
|
|||
|
private DrawShapeOptionsPanel panel;
|
|||
|
private Docker docker;
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ================== Constructor
|
|||
|
|
|||
|
public DrawShapeMode()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ================== Methods
|
|||
|
|
|||
|
// This generates the shape from a vertex
|
|||
|
protected static List<Vector2D> GenerateShape(Vector2D origin, int sides, int spikiness, int spikingmode, float radiusX, float radiusY, float start, float end)
|
|||
|
{
|
|||
|
if (sides <= 0) return new List<Vector2D>();
|
|||
|
float spikeX = (float)spikiness / 100f * radiusX;
|
|||
|
float spikeY = (float)spikiness / 100f * radiusY;
|
|||
|
float spikeDef = (float)spikiness;
|
|||
|
|
|||
|
// Make list
|
|||
|
List<Vector2D> points = new List<Vector2D>();
|
|||
|
|
|||
|
// Spiking fun!
|
|||
|
int spiketype = spikingmode >> 2;
|
|||
|
int spikematch = spikingmode & 1;
|
|||
|
if ((spikingmode & 2) == 2)
|
|||
|
{
|
|||
|
spikeX = -spikeX;
|
|||
|
spikeY = -spikeY;
|
|||
|
}
|
|||
|
|
|||
|
// FEATURE: In some spikingmodes, if spikiness is over 100% the spikes can cross between center for interesting results!
|
|||
|
|
|||
|
// Plot each side
|
|||
|
for (int i = 0; i < sides + 1; i++)
|
|||
|
{
|
|||
|
float offX = 0f;
|
|||
|
float offY = 0f;
|
|||
|
if (spiketype == 0)
|
|||
|
{
|
|||
|
// Spike outside and inside
|
|||
|
if ((i & 1) == spikematch)
|
|||
|
{
|
|||
|
offX = spikeX;
|
|||
|
offY = spikeY;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (spiketype == 1)
|
|||
|
{
|
|||
|
// Spike zig-zag and gear
|
|||
|
offX = spikeX;
|
|||
|
offY = spikeY;
|
|||
|
if ((spikematch == 0) || (i & 1) == spikematch)
|
|||
|
{
|
|||
|
spikeX = -spikeX;
|
|||
|
spikeY = -spikeY;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (spiketype == 2)
|
|||
|
{
|
|||
|
// Simulate the DrawEllipse spikiness
|
|||
|
if ((i & 1) == spikematch)
|
|||
|
{
|
|||
|
offX = spikeDef;
|
|||
|
offY = spikeDef;
|
|||
|
}
|
|||
|
}
|
|||
|
float delta = (float)i / sides;
|
|||
|
float angle = start + (end - start) * delta;
|
|||
|
float x = (float)Math.Cos(angle) * (radiusX + offX);
|
|||
|
float y = (float)Math.Sin(angle) * (radiusY + offY);
|
|||
|
Vector2D vertex = new Vector2D(x, y);
|
|||
|
|
|||
|
points.Add(origin + vertex);
|
|||
|
}
|
|||
|
|
|||
|
// Done
|
|||
|
return points;
|
|||
|
}
|
|||
|
|
|||
|
// Calculate origin and radius from 2 vectors
|
|||
|
protected static void CalculateOrigin(int firstpointtype, bool ellipse, Vector2D start, Vector2D end, out Vector2D origin, out Vector2D endpoint, out float radiusX, out float radiusY)
|
|||
|
{
|
|||
|
origin = start;
|
|||
|
endpoint = end;
|
|||
|
if (firstpointtype == 1)
|
|||
|
{
|
|||
|
// 1st point in corner like DrawEllipse
|
|||
|
origin = (start + end) / 2f;
|
|||
|
float centerX = (end.x - start.x) / 2f;
|
|||
|
float centerY = (end.y - start.y) / 2f;
|
|||
|
radiusX = Math.Abs(centerX);
|
|||
|
radiusY = Math.Abs(centerY);
|
|||
|
if (!ellipse)
|
|||
|
{
|
|||
|
if (radiusX > radiusY)
|
|||
|
{
|
|||
|
radiusY = radiusX;
|
|||
|
centerY = (centerY >= 0f) ? Math.Abs(centerX) : -Math.Abs(centerX);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
radiusX = radiusY;
|
|||
|
centerX = (centerX >= 0f) ? Math.Abs(centerY) : -Math.Abs(centerY);
|
|||
|
}
|
|||
|
origin.x = start.x + centerX;
|
|||
|
origin.y = start.y + centerY;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (firstpointtype == 2)
|
|||
|
{
|
|||
|
// 1st point in side/corner towards origin
|
|||
|
radiusX = Math.Abs(end.x - start.x);
|
|||
|
radiusY = Math.Abs(end.y - start.y);
|
|||
|
origin = end;
|
|||
|
endpoint = start;
|
|||
|
if (!ellipse)
|
|||
|
{
|
|||
|
if (radiusX > radiusY)
|
|||
|
radiusY = radiusX;
|
|||
|
else
|
|||
|
radiusX = radiusY;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// 1st point in center towards radius
|
|||
|
if (ellipse)
|
|||
|
{
|
|||
|
radiusX = Math.Abs(end.x - start.x);
|
|||
|
radiusY = Math.Abs(end.y - start.y);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float radius = (end - start).GetLength();
|
|||
|
radiusX = radius;
|
|||
|
radiusY = radius;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Recalculate angle from quadrant
|
|||
|
protected static float ReCalculateAngleFromQuadrant(int transformonquad, float angle, bool inverse, Vector2D start, Vector2D end)
|
|||
|
{
|
|||
|
Vector2D delta = end - start;
|
|||
|
if (transformonquad == 0) // top-right quadrant (1)
|
|||
|
{
|
|||
|
if (delta.x < 0)
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 3
|
|||
|
angle += inverse ? -Angle2D.PI : Angle2D.PI;
|
|||
|
else // quadrant 2
|
|||
|
angle += inverse ? -Angle2D.PIHALF : Angle2D.PIHALF;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 4
|
|||
|
angle += inverse ? -Angle2D.PIANDHALF : Angle2D.PIANDHALF;
|
|||
|
else // quadrant 1
|
|||
|
angle += inverse ? -0 : 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (transformonquad == 1) // top-left quadrant (2)
|
|||
|
{
|
|||
|
if (delta.x < 0)
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 3
|
|||
|
angle += inverse ? -Angle2D.PIHALF : Angle2D.PIHALF;
|
|||
|
else // quadrant 2
|
|||
|
angle += inverse ? -0 : 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 4
|
|||
|
angle += inverse ? -Angle2D.PI : Angle2D.PI;
|
|||
|
else // quadrant 1
|
|||
|
angle += inverse ? Angle2D.PIHALF : -Angle2D.PIHALF;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (transformonquad == 2) // bottom-left quadrant (3)
|
|||
|
{
|
|||
|
if (delta.x < 0)
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 3
|
|||
|
angle += inverse ? -0 : 0;
|
|||
|
else // quadrant 2
|
|||
|
angle += inverse ? Angle2D.PIHALF : -Angle2D.PIHALF;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 4
|
|||
|
angle += inverse ? -Angle2D.PIHALF : Angle2D.PIHALF;
|
|||
|
else // quadrant 1
|
|||
|
angle += inverse ? Angle2D.PI : -Angle2D.PI;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (transformonquad == 3) // bottom-right quadrant (4)
|
|||
|
{
|
|||
|
if (delta.x < 0)
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 3
|
|||
|
angle += inverse ? Angle2D.PIHALF : -Angle2D.PIHALF;
|
|||
|
else // quadrant 2
|
|||
|
angle += inverse ? Angle2D.PI : -Angle2D.PI;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (delta.y < 0) // quadrant 4
|
|||
|
angle += inverse ? -0 : 0;
|
|||
|
else // quadrant 1
|
|||
|
angle += inverse ? Angle2D.PIANDHALF : -Angle2D.PIANDHALF;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (transformonquad == 4) // Flip around (disabled!)
|
|||
|
{
|
|||
|
if (delta.x < 0)
|
|||
|
{
|
|||
|
// Flip horizontally
|
|||
|
if (angle < Angle2D.PI)
|
|||
|
angle = Angle2D.PI - angle;
|
|||
|
else
|
|||
|
angle = Angle2D.PI2 + Angle2D.PI - angle;
|
|||
|
}
|
|||
|
if (delta.y < 0)
|
|||
|
{
|
|||
|
// Flip vertically
|
|||
|
angle = Angle2D.PI2 - angle;
|
|||
|
}
|
|||
|
}
|
|||
|
if (angle < 0f) angle += Angle2D.PI2;
|
|||
|
if (angle >= Angle2D.PI2) angle -= Angle2D.PI2;
|
|||
|
return angle;
|
|||
|
}
|
|||
|
|
|||
|
// Allow user to modify angles by using the mouse
|
|||
|
protected void EndpointDrawShapeAngle(bool doSweepAngle)
|
|||
|
{
|
|||
|
Vector2D delta = end - start;
|
|||
|
float angle = -(float)Math.Atan2(-delta.y, delta.x);
|
|||
|
if (angle < 0f) angle = Angle2D.PI2 + angle;
|
|||
|
if (doSweepAngle)
|
|||
|
{
|
|||
|
float restartang = startangle;
|
|||
|
if (limitonquad) restartang = ReCalculateAngleFromQuadrant(transformonquad, restartang, false, start, end);
|
|||
|
sweepangle = angle - restartang;
|
|||
|
if (sweepangle < 0f) sweepangle += Angle2D.PI2;
|
|||
|
if (sweepangle == 0f || sweepangle > Angle2D.PI2) sweepangle = Angle2D.PI2;
|
|||
|
panel.SweepAngle = Angle2D.RadToDeg(sweepangle);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
startangle = angle;
|
|||
|
if (limitonquad) startangle = ReCalculateAngleFromQuadrant(transformonquad, startangle, true, start, end);
|
|||
|
panel.StartAngle = Angle2D.RadToDeg(startangle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// This draws a point at a specific location
|
|||
|
protected virtual bool AddPointAt(List<DrawnVertex> shapepts, Vector2D pos, bool stitch, bool stitchline)
|
|||
|
{
|
|||
|
if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
|
|||
|
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
|
|||
|
return false;
|
|||
|
|
|||
|
DrawnVertex newpoint = new DrawnVertex();
|
|||
|
newpoint.pos = pos;
|
|||
|
newpoint.stitch = stitch;
|
|||
|
newpoint.stitchline = stitchline;
|
|||
|
shapepts.Add(newpoint);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
override protected void Update()
|
|||
|
{
|
|||
|
PixelColor stitchcolor = General.Colors.Highlight;
|
|||
|
PixelColor losecolor = General.Colors.Selection;
|
|||
|
|
|||
|
snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState; //mxd
|
|||
|
snaptogrid = (snaptocardinaldirection || General.Interface.ShiftState ^ General.Interface.SnapToGrid);
|
|||
|
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
|
|||
|
|
|||
|
DrawnVertex curp = GetCurrentPosition();
|
|||
|
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
|
|||
|
|
|||
|
// Render drawing lines
|
|||
|
if (renderer.StartOverlay(true))
|
|||
|
{
|
|||
|
PixelColor color = snaptonearest ? stitchcolor : losecolor;
|
|||
|
|
|||
|
if (points.Count == 1)
|
|||
|
{
|
|||
|
// Update ending point
|
|||
|
if (curp.pos.IsFinite()) end = curp.pos;
|
|||
|
|
|||
|
// Generate shape
|
|||
|
Vector2D endpoint;
|
|||
|
float radiusX, radiusY;
|
|||
|
CalculateOrigin(firstpointtype, ellipse, start, end, out origin, out endpoint, out radiusX, out radiusY);
|
|||
|
float angle = startangle;
|
|||
|
if (limitonquad) angle = ReCalculateAngleFromQuadrant(transformonquad, startangle, false, start, end);
|
|||
|
List<Vector2D> shapevecs = GenerateShape(origin, sides, spikiness, spikingmode, radiusX, radiusY, angle, angle + sweepangle);
|
|||
|
|
|||
|
// Check if the shape is closed
|
|||
|
bool isShapeClosed = shapevecs[0].CloseTo(shapevecs[shapevecs.Count - 1], 0.1f);
|
|||
|
|
|||
|
// render reference
|
|||
|
if (previewreference)
|
|||
|
{
|
|||
|
List<Vector2D> refcircle = GenerateShape(origin, 32, 0, 0, radiusX, radiusY, angle, angle + sweepangle);
|
|||
|
for (int i = 1; i < refcircle.Count; i++)
|
|||
|
renderer.RenderLine(refcircle[i - 1], refcircle[i], LINE_THICKNESS, General.Colors.Grid, true);
|
|||
|
renderer.RenderLine(origin, shapevecs[0], LINE_THICKNESS, General.Colors.Grid, true);
|
|||
|
renderer.RenderLine(origin, shapevecs[shapevecs.Count - 1], LINE_THICKNESS, General.Colors.Grid, true);
|
|||
|
}
|
|||
|
renderer.RenderRectangleFilled(new RectangleF(start.x - vsize, start.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine, true);
|
|||
|
renderer.RenderRectangleFilled(new RectangleF(endpoint.x - vsize, endpoint.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine, true);
|
|||
|
|
|||
|
// render labels
|
|||
|
Vector2D[] labelCoords = new[] {
|
|||
|
new Vector2D(origin.x - radiusX, origin.y - radiusY),
|
|||
|
new Vector2D(origin.x + radiusX, origin.y - radiusY),
|
|||
|
new Vector2D(origin.x + radiusX, origin.y + radiusY),
|
|||
|
new Vector2D(origin.x - radiusX, origin.y + radiusY),
|
|||
|
new Vector2D(origin.x - radiusX, origin.y - radiusY)
|
|||
|
};
|
|||
|
for (int i = 1; i < 5; i++)
|
|||
|
{
|
|||
|
labels[i - 1].Move(labelCoords[i], labelCoords[i - 1]);
|
|||
|
renderer.RenderText(labels[i - 1].TextLabel);
|
|||
|
}
|
|||
|
labels[4].Move(origin, shapevecs[0]);
|
|||
|
renderer.RenderText(labels[4].TextLabel);
|
|||
|
labels[5].Move(shapevecs[0], shapevecs[1]);
|
|||
|
renderer.RenderText(labels[5].TextLabel);
|
|||
|
if (sweepangle < Angle2D.PI2)
|
|||
|
{
|
|||
|
labels[5].Move(origin, shapevecs[shapevecs.Count - 1]);
|
|||
|
renderer.RenderText(labels[5].TextLabel);
|
|||
|
}
|
|||
|
|
|||
|
// render shape
|
|||
|
if (createas <= LINEDEFS)
|
|||
|
{
|
|||
|
for (int i = 1; i < shapevecs.Count; i++)
|
|||
|
renderer.RenderLine(shapevecs[i - 1], shapevecs[i], LINE_THICKNESS, color, true);
|
|||
|
|
|||
|
if (!isShapeClosed && createas == CLOSESHAPE_ORIGIN)
|
|||
|
{
|
|||
|
renderer.RenderLine(shapevecs[shapevecs.Count - 1], origin, LINE_THICKNESS, color, true);
|
|||
|
renderer.RenderLine(origin, shapevecs[0], LINE_THICKNESS, color, true);
|
|||
|
}
|
|||
|
if (!isShapeClosed && createas == CLOSESHAPE_VERTICES)
|
|||
|
{
|
|||
|
renderer.RenderLine(shapevecs[shapevecs.Count - 1], shapevecs[0], LINE_THICKNESS, color, true);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// render vertices
|
|||
|
for (int i = 0; i < shapevecs.Count; i++)
|
|||
|
renderer.RenderRectangleFilled(new RectangleF(shapevecs[i].x - vsize, shapevecs[i].y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Render vertex at cursor
|
|||
|
renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
|
|||
|
}
|
|||
|
|
|||
|
// Done
|
|||
|
renderer.Finish();
|
|||
|
}
|
|||
|
|
|||
|
// Done
|
|||
|
renderer.Present();
|
|||
|
}
|
|||
|
|
|||
|
// This draws a point at a specific location
|
|||
|
override public bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline)
|
|||
|
{
|
|||
|
if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
|
|||
|
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
|
|||
|
return false;
|
|||
|
|
|||
|
DrawnVertex newpoint = new DrawnVertex();
|
|||
|
newpoint.pos = pos;
|
|||
|
newpoint.stitch = true; //stitch
|
|||
|
newpoint.stitchline = stitchline;
|
|||
|
points.Add(newpoint);
|
|||
|
|
|||
|
if (points.Count == 1) //add point and labels
|
|||
|
{
|
|||
|
start = newpoint.pos;
|
|||
|
labels.AddRange(new[] {
|
|||
|
new LineLengthLabel(false, true),
|
|||
|
new LineLengthLabel(false, true),
|
|||
|
new LineLengthLabel(false, true),
|
|||
|
new LineLengthLabel(false, true),
|
|||
|
new LineLengthLabel(true, true),
|
|||
|
new LineLengthLabel(true, true)
|
|||
|
});
|
|||
|
Update();
|
|||
|
}
|
|||
|
else if (points[0].pos == points[1].pos) //nothing is drawn
|
|||
|
{
|
|||
|
points = new List<DrawnVertex>();
|
|||
|
FinishDraw();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
end = newpoint.pos;
|
|||
|
FinishDraw();
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
override public void RemovePoint()
|
|||
|
{
|
|||
|
if (points.Count > 0) points.RemoveAt(points.Count - 1);
|
|||
|
if (labels.Count > 0) labels = new List<LineLengthLabel>();
|
|||
|
Update();
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ================== Events
|
|||
|
|
|||
|
public override void OnEngage()
|
|||
|
{
|
|||
|
base.OnEngage();
|
|||
|
|
|||
|
// Create and setup settings panel
|
|||
|
panel = new DrawShapeOptionsPanel();
|
|||
|
panel.PreviewReference = previewreference;
|
|||
|
panel.Ellipse = ellipse;
|
|||
|
panel.FirstPointType = firstpointtype;
|
|||
|
panel.CreateAs = createas;
|
|||
|
panel.FrontOutside = frontoutside;
|
|||
|
panel.Sides = sides;
|
|||
|
panel.Spikiness = spikiness;
|
|||
|
panel.SpikingMode = spikingmode;
|
|||
|
panel.StartAngle = Angle2D.RadToDeg(startangle);
|
|||
|
panel.SweepAngle = Angle2D.RadToDeg(sweepangle);
|
|||
|
panel.LimitAngleQuad = limitonquad;
|
|||
|
panel.OnValueChanged += OptionsPanelOnValueChanged;
|
|||
|
|
|||
|
// Add docker
|
|||
|
docker = new Docker("drawshape", "Draw Shape", panel);
|
|||
|
General.Interface.AddDocker(docker);
|
|||
|
General.Interface.SelectDocker(docker);
|
|||
|
}
|
|||
|
|
|||
|
public override void OnDisengage()
|
|||
|
{
|
|||
|
base.OnDisengage();
|
|||
|
|
|||
|
// Remove docker
|
|||
|
General.Interface.RemoveDocker(docker);
|
|||
|
panel.Dispose();
|
|||
|
panel = null;
|
|||
|
}
|
|||
|
|
|||
|
override public void OnAccept()
|
|||
|
{
|
|||
|
Cursor.Current = Cursors.AppStarting;
|
|||
|
General.Settings.FindDefaultDrawSettings();
|
|||
|
|
|||
|
if (points.Count == 2)
|
|||
|
{
|
|||
|
// Make undo for the draw
|
|||
|
General.Map.UndoRedo.CreateUndo(String.Format("{0} sides shape draw", sides));
|
|||
|
|
|||
|
// Generate shape
|
|||
|
Vector2D endpoint;
|
|||
|
float radiusX, radiusY;
|
|||
|
CalculateOrigin(firstpointtype, ellipse, start, end, out origin, out endpoint, out radiusX, out radiusY);
|
|||
|
float angle = startangle;
|
|||
|
if (limitonquad) angle = ReCalculateAngleFromQuadrant(transformonquad, startangle, false, start, end);
|
|||
|
List<Vector2D> shapevecs = GenerateShape(origin, sides, spikiness, spikingmode, radiusX, radiusY, angle, angle + sweepangle);
|
|||
|
|
|||
|
if (points.Count > 0)
|
|||
|
{
|
|||
|
// Delete last vertex if match with first
|
|||
|
bool wasClosedShape = shapevecs[0].CloseTo(shapevecs[shapevecs.Count - 1], 0.001f);
|
|||
|
if (wasClosedShape)
|
|||
|
{
|
|||
|
shapevecs.RemoveAt(shapevecs.Count - 1);
|
|||
|
}
|
|||
|
|
|||
|
// Flip normals by reversing the list
|
|||
|
if (!frontoutside) shapevecs.Reverse();
|
|||
|
|
|||
|
// Make the drawing
|
|||
|
if (createas < LINEDEFS)
|
|||
|
{
|
|||
|
List<DrawnVertex> shapepts = new List<DrawnVertex>();
|
|||
|
foreach (Vector2D t in shapevecs) AddPointAt(shapepts, t, true, true);
|
|||
|
if (!wasClosedShape && createas == CLOSESHAPE_ORIGIN)
|
|||
|
{
|
|||
|
AddPointAt(shapepts, origin, true, true); // Go toward origin before closing
|
|||
|
}
|
|||
|
if (wasClosedShape || createas <= CLOSESHAPE_VERTICES)
|
|||
|
{
|
|||
|
AddPointAt(shapepts, shapevecs[0], true, true); // Close the shape
|
|||
|
}
|
|||
|
if (!Tools.DrawLines(shapepts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate))
|
|||
|
{
|
|||
|
// Drawing failed
|
|||
|
// NOTE: I have to call this twice, because the first time only cancels this volatile mode
|
|||
|
General.Map.UndoRedo.WithdrawUndo();
|
|||
|
General.Map.UndoRedo.WithdrawUndo();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
List<Vertex> vertices = new List<Vertex>();
|
|||
|
|
|||
|
// Create each point
|
|||
|
if (createas != THINGS)
|
|||
|
{
|
|||
|
for (int i = 0; i < shapevecs.Count; i++)
|
|||
|
{
|
|||
|
Vertex vp = General.Map.Map.CreateVertex(shapevecs[i]);
|
|||
|
if (vp == null)
|
|||
|
{
|
|||
|
General.Map.UndoRedo.WithdrawUndo();
|
|||
|
return;
|
|||
|
}
|
|||
|
vertices.Add(vp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// of for things create things....
|
|||
|
if (createas == THINGS)
|
|||
|
{
|
|||
|
// Pick the thing to add...
|
|||
|
ThingBrowserForm f = new ThingBrowserForm(thingtype);
|
|||
|
if (f.ShowDialog(BuilderPlug.Me.MenusForm) != DialogResult.OK)
|
|||
|
{
|
|||
|
f.Dispose();
|
|||
|
General.Map.UndoRedo.WithdrawUndo();
|
|||
|
return;
|
|||
|
}
|
|||
|
thingtype = f.SelectedType;
|
|||
|
f.Dispose();
|
|||
|
|
|||
|
// ... and place them
|
|||
|
for (int i = 0; i < shapevecs.Count; i++)
|
|||
|
{
|
|||
|
Thing tp = General.Map.Map.CreateThing();
|
|||
|
if (tp == null)
|
|||
|
{
|
|||
|
General.Map.UndoRedo.WithdrawUndo();
|
|||
|
return;
|
|||
|
}
|
|||
|
General.Settings.ApplyDefaultThingSettings(tp);
|
|||
|
tp.SRB2Type = thingtype;
|
|||
|
tp.Parameter = 0;
|
|||
|
tp.Move(shapevecs[i]);
|
|||
|
tp.UpdateConfiguration();
|
|||
|
}
|
|||
|
|
|||
|
//Update Things filter
|
|||
|
General.Map.ThingsFilter.Update();
|
|||
|
}
|
|||
|
|
|||
|
// Create linedefs
|
|||
|
if (createas == LINEDEFS && shapevecs.Count > 1)
|
|||
|
{
|
|||
|
for (int i = 1; i < shapevecs.Count; i++)
|
|||
|
{
|
|||
|
// Join points together
|
|||
|
General.Map.Map.CreateLinedef(vertices[i - 1], vertices[i]);
|
|||
|
}
|
|||
|
if (wasClosedShape)
|
|||
|
{
|
|||
|
// Join first with last vertex for closed shape
|
|||
|
General.Map.Map.CreateLinedef(vertices[shapevecs.Count - 1], vertices[0]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Snap to map format accuracy
|
|||
|
General.Map.Map.SnapAllToAccuracy();
|
|||
|
|
|||
|
// Clear selection
|
|||
|
General.Map.Map.ClearAllSelected();
|
|||
|
|
|||
|
// Update cached values
|
|||
|
General.Map.Map.Update();
|
|||
|
|
|||
|
// Edit new sectors?
|
|||
|
List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
|
|||
|
if (BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
|
|||
|
General.Interface.ShowEditSectors(newsectors);
|
|||
|
|
|||
|
// Update the used textures
|
|||
|
General.Map.Data.UpdateUsedTextures();
|
|||
|
|
|||
|
//mxd
|
|||
|
General.Map.Renderer2D.UpdateExtraFloorFlag();
|
|||
|
|
|||
|
// Map is changed
|
|||
|
General.Map.IsChanged = true;
|
|||
|
|
|||
|
// Show info
|
|||
|
General.Interface.DisplayStatus(StatusType.Action, String.Format("Created {0} sides shape.", sides));
|
|||
|
}
|
|||
|
|
|||
|
// Done
|
|||
|
Cursor.Current = Cursors.Default;
|
|||
|
|
|||
|
// Return to original mode
|
|||
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|||
|
}
|
|||
|
|
|||
|
private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs)
|
|||
|
{
|
|||
|
previewreference = panel.PreviewReference;
|
|||
|
ellipse = panel.Ellipse;
|
|||
|
firstpointtype = panel.FirstPointType;
|
|||
|
createas = panel.CreateAs;
|
|||
|
frontoutside = panel.FrontOutside;
|
|||
|
sides = panel.Sides;
|
|||
|
spikiness = panel.Spikiness;
|
|||
|
spikingmode = panel.SpikingMode;
|
|||
|
startangle = Angle2D.DegToRad(panel.StartAngle);
|
|||
|
sweepangle = Angle2D.DegToRad(panel.SweepAngle);
|
|||
|
limitonquad = panel.LimitAngleQuad;
|
|||
|
Update();
|
|||
|
}
|
|||
|
|
|||
|
// Mouse moves
|
|||
|
public override void OnMouseMove(MouseEventArgs e)
|
|||
|
{
|
|||
|
base.OnMouseMove(e);
|
|||
|
if (e.Button == MouseButtons.Middle)
|
|||
|
{
|
|||
|
EndpointDrawShapeAngle(General.Interface.CtrlState);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override void OnHelp()
|
|||
|
{
|
|||
|
General.ShowHelp("mode_drawshape.html");
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ================== Actions
|
|||
|
|
|||
|
[BeginAction("increasebevel")]
|
|||
|
protected void IncreaseBevel()
|
|||
|
{
|
|||
|
if (spikiness < 4096)
|
|||
|
{
|
|||
|
spikiness++;
|
|||
|
panel.Spikiness = spikiness;
|
|||
|
Update();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[BeginAction("decreasebevel")]
|
|||
|
protected void DecreaseBevel()
|
|||
|
{
|
|||
|
if (spikiness > 0)
|
|||
|
{
|
|||
|
spikiness--;
|
|||
|
panel.Spikiness = spikiness;
|
|||
|
Update();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[BeginAction("increasesubdivlevel")]
|
|||
|
protected void IncreaseSubdivLevel()
|
|||
|
{
|
|||
|
if (sides < 1024)
|
|||
|
{
|
|||
|
sides++;
|
|||
|
panel.Sides = sides;
|
|||
|
Update();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[BeginAction("decreasesubdivlevel")]
|
|||
|
protected void DecreaseSubdivLevel()
|
|||
|
{
|
|||
|
if (sides > 2)
|
|||
|
{
|
|||
|
sides--;
|
|||
|
panel.Sides = sides;
|
|||
|
Update();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
}
|
|||
|
}
|