mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-23 12:22:35 +00:00
59c4a75b11
Added "doomthingrotationangles" Game Configuration property. When enabled, editor actions related to changing thing angle will snap the resulting angle to 45 degree increments. This property is set to true for vanilla game configurations. Fixed a crash when changing game configuration from one without Thing actions support to one with them while in Things mode. Fixed, cosmetic, DB2 bug: current editing mode button was deselected after reloading resources. Updated documentation ("Game Configuration - Basic Settings" page).
380 lines
11 KiB
C#
380 lines
11 KiB
C#
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using CodeImp.DoomBuilder.Actions;
|
|
using CodeImp.DoomBuilder.Config;
|
|
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
|
|
{
|
|
[EditMode(DisplayName = "Draw Curve Mode",
|
|
SwitchAction = "drawcurvemode",
|
|
ButtonImage = "DrawCurveMode.png", //mxd
|
|
ButtonOrder = int.MinValue + 2, //mxd
|
|
ButtonGroup = "000_drawing", //mxd
|
|
AllowCopyPaste = false,
|
|
Volatile = true,
|
|
Optional = false)]
|
|
|
|
public class DrawCurveMode : DrawGeometryMode
|
|
{
|
|
#region ================== Variables
|
|
|
|
private readonly HintLabel hintlabel;
|
|
private Curve curve;
|
|
private int segmentlength;
|
|
private const int MIN_SEGMENT_LENGTH = 16;
|
|
private const int MAX_SEGMENT_LENGTH = 4096; //just some arbitrary number
|
|
|
|
// Interface
|
|
private DrawCurveOptionsPanel panel;
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor/Disposer
|
|
|
|
public DrawCurveMode()
|
|
{
|
|
hintlabel = new HintLabel(General.Colors.InfoLine);
|
|
labeluseoffset = false;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
// Not already disposed?
|
|
if(!isdisposed)
|
|
{
|
|
// Clean up
|
|
if(hintlabel != null) hintlabel.Dispose();
|
|
|
|
// Done
|
|
base.Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
protected override void Update()
|
|
{
|
|
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;
|
|
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
|
|
|
|
DrawnVertex curp = GetCurrentPosition();
|
|
float vsize = (renderer.VertexSize + 1.0f) / renderer.Scale;
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Render drawing lines
|
|
if(renderer.StartOverlay(true))
|
|
{
|
|
// Go for all points to draw lines
|
|
if(points.Count > 0)
|
|
{
|
|
//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);
|
|
|
|
// Render lines
|
|
for(int i = 1; i < curve.Shape.Count; i++)
|
|
{
|
|
// Determine line color
|
|
PixelColor c = snaptonearest ? stitchcolor : losecolor;
|
|
|
|
// Render line
|
|
renderer.RenderLine(curve.Shape[i - 1], curve.Shape[i], LINE_THICKNESS, c, true);
|
|
}
|
|
|
|
//render "inactive" vertices
|
|
for(int i = 1; i < curve.Shape.Count - 1; i++)
|
|
{
|
|
// Determine vertex color
|
|
PixelColor c = !snaptonearest ? stitchcolor : losecolor;
|
|
|
|
// Render vertex
|
|
renderer.RenderRectangleFilled(new RectangleF(curve.Shape[i].x - vsize, curve.Shape[i].y - vsize, vsize * 2.0f, vsize * 2.0f), c, true);
|
|
}
|
|
}
|
|
|
|
if(points.Count > 0)
|
|
{
|
|
// Render vertices
|
|
for(int i = 0; i < points.Count; i++)
|
|
{
|
|
// Determine vertex color
|
|
PixelColor c = points[i].stitch ? stitchcolor : losecolor;
|
|
|
|
// Render vertex
|
|
renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), c, true);
|
|
}
|
|
}
|
|
|
|
// Determine point color
|
|
PixelColor color = snaptonearest ? stitchcolor : losecolor;
|
|
|
|
// Render vertex at cursor
|
|
renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
|
|
|
|
// Render labels
|
|
renderer.RenderText(labels.ToArray());
|
|
|
|
//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);
|
|
|
|
// 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()
|
|
{
|
|
Cursor.Current = Cursors.AppStarting;
|
|
General.Settings.FindDefaultDrawSettings();
|
|
|
|
// When points have been drawn
|
|
if(points.Count > 0)
|
|
{
|
|
// 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",
|
|
"awesome", "accurate", "adorable", "adventurous", "attractive", "cute",
|
|
"elegant", "glamorous", "gorgeous", "handsome", "magnificent", "unusual",
|
|
"outstanding", "mysterious", "amusing", "charming", "fantastic", "jolly"
|
|
};
|
|
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.");
|
|
|
|
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;
|
|
|
|
for(int i = 0; i < lastpoint; i++)
|
|
{
|
|
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++)
|
|
{
|
|
DrawnVertex dv = new DrawnVertex();
|
|
dv.pos = curve.Segments[i].Points[c];
|
|
dv.stitch = stitch;
|
|
dv.stitchline = stitchline;
|
|
verts.Add(dv);
|
|
}
|
|
}
|
|
|
|
// Add the last point
|
|
DrawnVertex end = new DrawnVertex();
|
|
end.pos = curve.Segments[lastpoint - 1].End;
|
|
end.stitch = verts[verts.Count - 1].stitch;
|
|
end.stitchline = verts[verts.Count - 1].stitchline;
|
|
verts.Add(end);
|
|
}
|
|
else
|
|
{
|
|
verts = points;
|
|
}
|
|
|
|
// Make the drawing
|
|
if(Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
|
|
{
|
|
// Snap to map format accuracy
|
|
General.Map.Map.SnapAllToAccuracy();
|
|
|
|
// Clear selection
|
|
General.Map.Map.ClearAllSelected();
|
|
|
|
// Update cached values
|
|
General.Map.Map.Update();
|
|
|
|
//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);
|
|
|
|
// Update the used textures
|
|
General.Map.Data.UpdateUsedTextures();
|
|
|
|
//mxd
|
|
General.Map.Renderer2D.UpdateExtraFloorFlag();
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
// Done
|
|
Cursor.Current = Cursors.Default;
|
|
|
|
if(continuousdrawing)
|
|
{
|
|
// Reset settings
|
|
points.Clear();
|
|
labels.Clear();
|
|
drawingautoclosed = false;
|
|
|
|
// 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
|
|
|
|
[BeginAction("increasesubdivlevel")]
|
|
protected virtual void IncreaseSubdivLevel()
|
|
{
|
|
if(segmentlength < MAX_SEGMENT_LENGTH)
|
|
{
|
|
int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
|
|
segmentlength += increment;
|
|
|
|
if(segmentlength > MAX_SEGMENT_LENGTH) segmentlength = MAX_SEGMENT_LENGTH;
|
|
panel.SegmentLength = segmentlength;
|
|
Update();
|
|
}
|
|
}
|
|
|
|
[BeginAction("decreasesubdivlevel")]
|
|
protected virtual void DecreaseSubdivLevel()
|
|
{
|
|
if(segmentlength > MIN_SEGMENT_LENGTH)
|
|
{
|
|
int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
|
|
segmentlength -= increment;
|
|
|
|
if(segmentlength < MIN_SEGMENT_LENGTH) segmentlength = MIN_SEGMENT_LENGTH;
|
|
panel.SegmentLength = segmentlength;
|
|
Update();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|