UltimateZoneBuilder/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs

381 lines
11 KiB
C#
Raw Normal View History

#region ================== Namespaces
using System;
2013-04-08 13:28:04 +00:00
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Config;
2013-04-08 13:28:04 +00:00
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Windows;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
2013-04-08 13:28:04 +00:00
{
[EditMode(DisplayName = "Draw Curve Mode",
SwitchAction = "drawcurvemode",
ButtonImage = "DrawCurveMode.png", //mxd
ButtonOrder = int.MinValue + 2, //mxd
ButtonGroup = "000_drawing", //mxd
2013-04-08 13:28:04 +00:00
AllowCopyPaste = false,
Volatile = true,
Optional = false)]
public class DrawCurveMode : DrawGeometryMode
{
#region ================== Variables
private readonly HintLabel hintlabel;
2013-04-08 13:28:04 +00:00
private Curve curve;
private int segmentlength;
private const int MIN_SEGMENT_LENGTH = 16;
private const int MAX_SEGMENT_LENGTH = 4096; //just some arbitrary number
2013-04-08 13:28:04 +00:00
// Interface
private DrawCurveOptionsPanel panel;
#endregion
#region ================== Constructor/Disposer
public DrawCurveMode()
{
hintlabel = new HintLabel(General.Colors.InfoLine);
labeluseoffset = false;
2013-04-08 13:28:04 +00:00
}
public override void Dispose()
{
Added, Texture Browser: added "Show textures in subdirectories" checkbox (enabled by default). When enabled, textures from current PK3/PK7/Directory resource directory and it's subdirectories will be shown. Otherwise, only textures from current directory will be shown. Removed, Texture Browser: removed "Show image sizes" checkbox. "Show texture and flat sizes in browsers" preferences setting is now used instead. Fixed, Things mode: event line between pre-last and the last PatrolPoint was not drawn. Fixed, Things mode: highlight range for sizeless things (things with "fixedsize" game configuration property) was calculated incorrectly. Fixed: fixed a crash when opening Script Editor after using "Open map in current wad" command to switch to UDMF map with SCRIPTS lump when current script configuration was not saved in the wad's .dbs file. Fixed: map closing events were not triggered when using "Open map in current wad" command, which could potentially result in plugin crashes/incorrect behavior. Fixed: Sector Drawing overrides panel could trigger an exception when closing the map during resource loading. Internal: added "Debug + Profiler" solution configuration, added 2 profiling methods to DebugConsole. Internal: rewrote MainForm.DisplayStatus() / StatusInfo to handle selection info in a more structured way. Fixed, internal: some destructors could potentially be executed more than once potentially leading to exceptions. Other destructors were not called at all. Updated ZDoom_DECORATE.cfg.
2015-09-16 12:10:43 +00:00
// Not already disposed?
if(!isdisposed)
{
// Clean up
if(hintlabel != null) hintlabel.Dispose();
// Done
base.Dispose();
}
2013-04-08 13:28:04 +00:00
}
#endregion
#region ================== Methods
protected override void Update()
{
2013-04-08 13:28:04 +00:00
PixelColor stitchcolor = General.Colors.Highlight;
PixelColor losecolor = General.Colors.Selection;
snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState;
snaptogrid = snaptocardinaldirection || General.Interface.ShiftState ^ General.Interface.SnapToGrid;
2013-04-08 13:28:04 +00:00
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex curp = GetCurrentPosition();
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
2013-04-08 13:28:04 +00:00
// Update label positions (mxd)
if(labels.Count > 0)
{
// Update labels for already drawn lines
for(int i = 0; i < labels.Count - 1; i++)
labels[i].Move(points[i].pos, points[i + 1].pos);
// Update label for active line
labels[labels.Count - 1].Move(points[points.Count - 1].pos, curp.pos);
}
2013-04-08 13:28:04 +00:00
// Render drawing lines
if(renderer.StartOverlay(true))
{
2013-04-08 13:28:04 +00:00
// Go for all points to draw lines
if(points.Count > 0)
{
2013-04-08 13:28:04 +00:00
//update curve
List<Vector2D> verts = new List<Vector2D>();
for(int i = 0; i < points.Count; i++) verts.Add(points[i].pos);
if(curp.pos != verts[verts.Count-1]) verts.Add(curp.pos);
curve = CurveTools.CurveThroughPoints(verts, 0.5f, 0.75f, segmentlength);
2013-04-08 13:28:04 +00:00
// Render lines
for(int i = 1; i < curve.Shape.Count; i++)
{
2013-04-08 13:28:04 +00:00
// Determine line color
PixelColor c = snaptonearest ? stitchcolor : losecolor;
2013-04-08 13:28:04 +00:00
// Render line
renderer.RenderLine(curve.Shape[i - 1], curve.Shape[i], LINE_THICKNESS, c, true);
2013-04-08 13:28:04 +00:00
}
//render "inactive" vertices
for(int i = 1; i < curve.Shape.Count - 1; i++)
{
2013-04-08 13:28:04 +00:00
// Determine vertex color
PixelColor c = !snaptonearest ? stitchcolor : losecolor;
2013-04-08 13:28:04 +00:00
// Render vertex
2020-05-21 12:20:02 +00:00
renderer.RenderRectangleFilled(new RectangleF((float)(curve.Shape[i].x - vsize), (float)(curve.Shape[i].y - vsize), vsize * 2.0f, vsize * 2.0f), c, true);
2013-04-08 13:28:04 +00:00
}
}
if(points.Count > 0)
{
2013-04-08 13:28:04 +00:00
// Render vertices
for(int i = 0; i < points.Count; i++)
{
2013-04-08 13:28:04 +00:00
// Determine vertex color
PixelColor c = points[i].stitch ? stitchcolor : losecolor;
2013-04-08 13:28:04 +00:00
// Render vertex
2020-05-21 12:20:02 +00:00
renderer.RenderRectangleFilled(new RectangleF((float)(points[i].pos.x - vsize), (float)(points[i].pos.y - vsize), vsize * 2.0f, vsize * 2.0f), c, true);
2013-04-08 13:28:04 +00:00
}
}
// Determine point color
PixelColor color = snaptonearest ? stitchcolor : losecolor;
2013-04-08 13:28:04 +00:00
// Render vertex at cursor
2020-05-21 12:20:02 +00:00
renderer.RenderRectangleFilled(new RectangleF((float)(curp.pos.x - vsize), (float)(curp.pos.y - vsize), vsize * 2.0f, vsize * 2.0f), color, true);
2013-04-08 13:28:04 +00:00
// Render labels
renderer.RenderText(labels.ToArray());
2013-04-08 13:28:04 +00:00
//Render info label
Vector2D start = new Vector2D(mousemappos.x + (32 / renderer.Scale), mousemappos.y - (16 / renderer.Scale));
Vector2D end = new Vector2D(mousemappos.x + (96 / renderer.Scale), mousemappos.y);
hintlabel.Move(start, end);
hintlabel.Text = "SEG LEN: " + segmentlength;
renderer.RenderText(hintlabel.TextLabel);
2013-04-08 13:28:04 +00:00
// Done
renderer.Finish();
}
// Done
renderer.Present();
}
#endregion
#region ================== Events
public override void OnEngage()
{
base.OnEngage();
//setup settings panel
panel.SegmentLength = segmentlength;
panel.Register();
}
public override void OnAccept()
{
2013-04-08 13:28:04 +00:00
Cursor.Current = Cursors.AppStarting;
General.Settings.FindDefaultDrawSettings();
// When points have been drawn
if(points.Count > 0)
{
2013-04-08 13:28:04 +00:00
// Make undo for the draw
General.Map.UndoRedo.CreateUndo("Curve draw");
// Make an analysis and show info
string[] adjectives =
{
"beautiful", "lovely", "romantic", "stylish", "cheerful", "comical",
2013-04-08 13:28:04 +00:00
"awesome", "accurate", "adorable", "adventurous", "attractive", "cute",
"elegant", "glamorous", "gorgeous", "handsome", "magnificent", "unusual",
"outstanding", "mysterious", "amusing", "charming", "fantastic", "jolly"
};
2013-04-08 13:28:04 +00:00
string word = adjectives[points.Count % adjectives.Length];
word = (points.Count > adjectives.Length) ? "very " + word : word;
string a = ((word[0] == 'a') || (word[0] == 'e') || (word[0] == 'o') || (word[0] == 'u')) ? "an " : "a ";
General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " curve.");
2013-04-08 13:28:04 +00:00
List<DrawnVertex> verts = new List<DrawnVertex>();
// If we have a curve...
if(points.Count > 2)
{
// Is it an (auto)closed curve?
int lastpoint;
if(drawingautoclosed || points[0].pos == points[points.Count - 1].pos)
lastpoint = curve.Segments.Count;
else
lastpoint = curve.Segments.Count - 1;
2013-04-08 13:28:04 +00:00
for(int i = 0; i < lastpoint; i++)
{
2013-04-08 13:28:04 +00:00
int next = (i == curve.Segments.Count - 1 ? 0 : i + 1);
bool stitch = points[i].stitch && points[next].stitch;
bool stitchline = points[i].stitchline && points[next].stitchline;
// Add segment points except the last one
for(int c = 0; c < curve.Segments[i].Points.Length - 1; c++)
{
2013-04-08 13:28:04 +00:00
DrawnVertex dv = new DrawnVertex();
dv.pos = curve.Segments[i].Points[c];
dv.stitch = stitch;
dv.stitchline = stitchline;
verts.Add(dv);
}
}
// Add the last point
2013-04-08 13:28:04 +00:00
DrawnVertex end = new DrawnVertex();
end.pos = curve.Segments[lastpoint - 1].End;
2013-04-08 13:28:04 +00:00
end.stitch = verts[verts.Count - 1].stitch;
end.stitchline = verts[verts.Count - 1].stitchline;
verts.Add(end);
}
else
{
2013-04-08 13:28:04 +00:00
verts = points;
}
// Make the drawing
if(Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
2013-04-08 13:28:04 +00:00
{
// Snap to map format accuracy
General.Map.Map.SnapAllToAccuracy();
2013-04-08 13:28:04 +00:00
// Clear selection
General.Map.Map.ClearAllSelected();
2013-04-08 13:28:04 +00:00
// Update cached values
General.Map.Map.Update();
2013-04-08 13:28:04 +00:00
//mxd. Outer sectors may require some splittin...
if(General.Settings.SplitJoinedSectors) Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
// Edit new sectors?
List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
General.Interface.ShowEditSectors(newsectors);
2013-04-08 13:28:04 +00:00
// Update the used textures
General.Map.Data.UpdateUsedTextures();
2013-04-08 13:28:04 +00:00
//mxd
General.Map.Renderer2D.UpdateExtraFloorFlag();
2013-04-08 13:28:04 +00:00
// Map is changed
General.Map.IsChanged = true;
}
else
{
// 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();
}
2013-04-08 13:28:04 +00:00
}
// Done
Cursor.Current = Cursors.Default;
if(continuousdrawing)
{
// Reset settings
points.Clear();
labels.Clear();
drawingautoclosed = false;
2013-04-08 13:28:04 +00:00
// Redraw display
General.Interface.RedrawDisplay();
}
else
{
// Return to original mode
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
}
}
private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs)
{
segmentlength = panel.SegmentLength;
Update();
}
public override void OnHelp()
{
General.ShowHelp("/gzdb/features/classic_modes/mode_drawcurve.html");
}
#endregion
#region ================== mxd. Settings panel
protected override void SetupInterface()
{
// Load stored settings
segmentlength = General.Clamp(General.Settings.ReadPluginSetting("drawcurvemode.segmentlength", 32), MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH);
// Add options docker
panel = new DrawCurveOptionsPanel(MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH);
panel.SegmentLength = segmentlength;
panel.OnValueChanged += OptionsPanelOnValueChanged;
panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
panel.OnAutoCloseDrawingChanged += OnAutoCloseDrawingChanged;
// Needs to be set after adding the events...
panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawcurvemode.continuousdrawing", false);
panel.AutoCloseDrawing = General.Settings.ReadPluginSetting("drawlinesmode.autoclosedrawing", false);
}
protected override void AddInterface()
{
panel.Register();
}
protected override void RemoveInterface()
{
// Store settings
General.Settings.WritePluginSetting("drawcurvemode.segmentlength", segmentlength);
General.Settings.WritePluginSetting("drawcurvemode.continuousdrawing", panel.ContinuousDrawing);
General.Settings.WritePluginSetting("drawlinesmode.autoclosedrawing", panel.AutoCloseDrawing);
// Remove the buttons
panel.Unregister();
}
#endregion
#region ================== Actions
2013-04-08 13:28:04 +00:00
[BeginAction("increasesubdivlevel")]
protected virtual void IncreaseSubdivLevel()
{
if(segmentlength < MAX_SEGMENT_LENGTH)
{
int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
segmentlength += increment;
2013-04-08 13:28:04 +00:00
if(segmentlength > MAX_SEGMENT_LENGTH) segmentlength = MAX_SEGMENT_LENGTH;
panel.SegmentLength = segmentlength;
2013-04-08 13:28:04 +00:00
Update();
}
}
[BeginAction("decreasesubdivlevel")]
protected virtual void DecreaseSubdivLevel()
{
if(segmentlength > MIN_SEGMENT_LENGTH)
{
int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
segmentlength -= increment;
2013-04-08 13:28:04 +00:00
if(segmentlength < MIN_SEGMENT_LENGTH) segmentlength = MIN_SEGMENT_LENGTH;
panel.SegmentLength = segmentlength;
2013-04-08 13:28:04 +00:00
Update();
}
}
#endregion
2013-04-08 13:28:04 +00:00
}
}