From dcaf0a525dd0df6783ee0681464dbac7714f8afa Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Wed, 17 Jun 2020 22:22:00 +0200 Subject: [PATCH] Added feature to export the selected sectors as an image --- .../Plugins/BuilderModes/BuilderModes.csproj | 10 + .../BuilderModes/General/BuilderPlug.cs | 32 +++ .../Plugins/BuilderModes/IO/ImageExporter.cs | 155 +++++++++++++ .../ImageExportSettingsForm.Designer.cs | 205 ++++++++++++++++++ .../Interface/ImageExportSettingsForm.cs | 149 +++++++++++++ .../Interface/ImageExportSettingsForm.resx | 123 +++++++++++ .../Interface/MenusForm.Designer.cs | 16 +- .../BuilderModes/Resources/Actions.cfg | 10 + 8 files changed, 698 insertions(+), 2 deletions(-) create mode 100644 Source/Plugins/BuilderModes/IO/ImageExporter.cs create mode 100644 Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs create mode 100644 Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs create mode 100644 Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.resx diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index 0d76312..180c7a9 100644 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -146,6 +146,12 @@ FindReplaceForm.cs + + Form + + + ImageExportSettingsForm.cs + Form @@ -200,6 +206,7 @@ VertexSlopeAssistTagForm.cs + True True @@ -239,6 +246,9 @@ VertexSlopeAssistTagForm.cs + + + ImageExportSettingsForm.cs diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs index 475b099..c67237e 100644 --- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs +++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs @@ -875,6 +875,38 @@ namespace CodeImp.DoomBuilder.BuilderModes } } + [BeginAction("exporttoimage")] + private void ExportToImage() + { + // Convert geometry selection to sectors + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + // Get sectors + ICollection sectors = General.Map.Map.SelectedSectorsCount == 0 ? General.Map.Map.Sectors : General.Map.Map.GetSelectedSectors(true); + if (sectors.Count == 0) + { + General.Interface.DisplayStatus(StatusType.Warning, "Image export failed. Map has no sectors!"); + return; + } + + ImageExporter exporter = new ImageExporter(); + + ImageExportSettingsForm form = new ImageExportSettingsForm(); + if (form.ShowDialog() == DialogResult.OK) + { + ImageExportSettings settings = new ImageExportSettings(Path.GetFileName(form.FilePath), Path.GetDirectoryName(form.FilePath), form.Floor, form.GetPixelFormat(), form.GetImageFormat()); + + try + { + exporter.Export(sectors, settings); + } + catch(ArgumentException e) // Happens if there's not enough consecutive memory so create the file + { + MessageBox.Show("Exporting failed. There's likely not enough consecutive free memory to create the image. Try a lower color depth or file format", "Export failed", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/IO/ImageExporter.cs b/Source/Plugins/BuilderModes/IO/ImageExporter.cs new file mode 100644 index 0000000..ebdfe5f --- /dev/null +++ b/Source/Plugins/BuilderModes/IO/ImageExporter.cs @@ -0,0 +1,155 @@ +#region ================== Copyright (c) 2020 Boris Iwanski + +/* + * This program is free software: you can redistribute it and/or modify + * + * it under the terms of the GNU General Public License as published by + * + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.If not, see. + */ + +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.IO; +using System.Linq; +using System.Text; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using System.Diagnostics; + +namespace CodeImp.DoomBuilder.BuilderModes.IO +{ + internal struct ImageExportSettings + { + public string Name; + public string Path; + public bool Floor; + public PixelFormat PixelFormat; + public ImageFormat ImageFormat; + + public ImageExportSettings(string name, string path, bool floor, PixelFormat pformat, ImageFormat iformat) + { + Name = name; + Path = path; + Floor = floor; + PixelFormat = pformat; + ImageFormat = iformat; + } + } + + internal class ImageExporter + { + public void Export(ICollection sectors, ImageExportSettings settings) + { + Bitmap bitmap; + Vector2D offset = new Vector2D(float.MaxValue, float.MinValue); + Vector2D size = new Vector2D(float.MinValue, float.MaxValue); + + HashSet vertices = new HashSet(); + + // Find the top left and bottom right corners of the selection + foreach(Sector s in sectors) + { + foreach (Sidedef sd in s.Sidedefs) + { + foreach (Vertex v in new Vertex[] { sd.Line.Start, sd.Line.End }) + { + if (v.Position.x < offset.x) + offset.x = v.Position.x; + + if (v.Position.x > size.x) + size.x = v.Position.x; + + if (v.Position.y > offset.y) + offset.y = v.Position.y; + + if (v.Position.y < size.y) + size.y = v.Position.y; + } + } + } + + // Right now "size" is the bottom right corener of the selection, so subtract the offset + // (top left corner of the selection). y will always be negative, so make it positive + size -= offset; + size.y *= -1.0f; + + bitmap = new Bitmap((int)size.x, (int)size.y, settings.PixelFormat); + + Graphics g = Graphics.FromImage(bitmap); + g.Clear(Color.Black); // If we don't clear to black we'll see seams where the sectors touch, due to the AA + g.InterpolationMode = InterpolationMode.HighQualityBilinear; + g.CompositingQuality = CompositingQuality.HighQuality; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.SmoothingMode = SmoothingMode.AntiAlias; // Without AA the sector edges will be quite rough + + foreach (Sector s in sectors) + { + GraphicsPath p = new GraphicsPath(); + float rotation = (float)s.Fields.GetValue("rotationfloor", 0.0); + + // If a sector is rotated any offset is on the rotated axes. But we need to offset by + // map coordinates. We'll use this vector to compute that offset + Vector2D rotationvector = Vector2D.FromAngle(Angle2D.DegToRad(rotation) + Angle2D.PIHALF); + + // Sectors are triangulated, so draw every triangle + for (int i = 0; i < s.Triangles.Vertices.Count / 3; i++) + { + // The GDI image has the 0/0 coordinate in the top left, so invert the y component + Vector2D v1 = s.Triangles.Vertices[i * 3] - offset; v1.y *= -1.0f; + Vector2D v2 = s.Triangles.Vertices[i * 3 + 1] - offset; v2.y *= -1.0f; + Vector2D v3 = s.Triangles.Vertices[i * 3 + 2] - offset; v3.y *= -1.0f; + + p.AddLine((float)v1.x, (float)v1.y, (float)v2.x, (float)v2.y); + p.AddLine((float)v2.x, (float)v2.y, (float)v3.x, (float)v3.y); + p.CloseFigure(); + } + + Bitmap texture; + + if(settings.Floor) + texture = General.Map.Data.GetFlatImage(s.FloorTexture).GetBitmap(); + else + texture = General.Map.Data.GetFlatImage(s.CeilTexture).GetBitmap(); + + Vector2D textureoffset = new Vector2D(); + textureoffset.x = s.Fields.GetValue("xpanningfloor", 0.0f); + textureoffset.y = s.Fields.GetValue("ypanningfloor", 0.0f); + + // Create the transformation matrix + Matrix matrix = new Matrix(); + matrix.Rotate(rotation); + matrix.Translate((float)(-offset.x * rotationvector.x), (float)(offset.x * rotationvector.y)); // Left/right offset from the map origin + matrix.Translate((float)(offset.y * rotationvector.y), (float)(offset.y * rotationvector.x)); // Up/down offset from the map origin + matrix.Translate(-(float)textureoffset.x, -(float)textureoffset.y); // Texture offset + + // Create the texture brush and apply the matrix + TextureBrush t = new TextureBrush(texture); + t.Transform = matrix; + + // Draw the islands of the sector + g.FillPath(t, p); + + } + + // Finally save the image + bitmap.Save(Path.Combine(settings.Path, settings.Name), settings.ImageFormat); + } + } +} diff --git a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs new file mode 100644 index 0000000..fb9165d --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs @@ -0,0 +1,205 @@ +namespace CodeImp.DoomBuilder.BuilderModes.Interface +{ + partial class ImageExportSettingsForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tbExportPath = new System.Windows.Forms.TextBox(); + this.browse = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.cancel = new System.Windows.Forms.Button(); + this.export = new System.Windows.Forms.Button(); + this.saveFileDialog = new System.Windows.Forms.SaveFileDialog(); + this.cbImageFormat = new System.Windows.Forms.ComboBox(); + this.cbPixelFormat = new System.Windows.Forms.ComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.rbFloor = new System.Windows.Forms.RadioButton(); + this.rbCeiling = new System.Windows.Forms.RadioButton(); + this.SuspendLayout(); + // + // tbExportPath + // + this.tbExportPath.Location = new System.Drawing.Point(50, 9); + this.tbExportPath.Name = "tbExportPath"; + this.tbExportPath.Size = new System.Drawing.Size(344, 20); + this.tbExportPath.TabIndex = 2; + // + // browse + // + this.browse.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Folder; + this.browse.Location = new System.Drawing.Point(400, 7); + this.browse.Name = "browse"; + this.browse.Size = new System.Drawing.Size(30, 24); + this.browse.TabIndex = 3; + this.browse.UseVisualStyleBackColor = true; + this.browse.Click += new System.EventHandler(this.browse_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 12); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(32, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Path:"; + // + // cancel + // + this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancel.Location = new System.Drawing.Point(360, 110); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(75, 23); + this.cancel.TabIndex = 7; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + this.cancel.Click += new System.EventHandler(this.cancel_Click); + // + // export + // + this.export.Location = new System.Drawing.Point(279, 110); + this.export.Name = "export"; + this.export.Size = new System.Drawing.Size(75, 23); + this.export.TabIndex = 6; + this.export.Text = "Export"; + this.export.UseVisualStyleBackColor = true; + this.export.Click += new System.EventHandler(this.export_Click); + // + // saveFileDialog + // + this.saveFileDialog.Filter = "PNG (*.png)|*.png|JPEG (*.jpg)|*.jpg|All files (*.*)|*.*"; + // + // cbImageFormat + // + this.cbImageFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbImageFormat.FormattingEnabled = true; + this.cbImageFormat.Items.AddRange(new object[] { + "PNG", + "JPG"}); + this.cbImageFormat.Location = new System.Drawing.Point(102, 35); + this.cbImageFormat.Name = "cbImageFormat"; + this.cbImageFormat.Size = new System.Drawing.Size(71, 21); + this.cbImageFormat.TabIndex = 8; + this.cbImageFormat.SelectedIndexChanged += new System.EventHandler(this.cbImageFormat_SelectedIndexChanged); + // + // cbPixelFormat + // + this.cbPixelFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbPixelFormat.FormattingEnabled = true; + this.cbPixelFormat.Items.AddRange(new object[] { + "32 bit", + "24 bit", + "16 bit"}); + this.cbPixelFormat.Location = new System.Drawing.Point(102, 62); + this.cbPixelFormat.Name = "cbPixelFormat"; + this.cbPixelFormat.Size = new System.Drawing.Size(71, 21); + this.cbPixelFormat.TabIndex = 9; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 38); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(71, 13); + this.label2.TabIndex = 10; + this.label2.Text = "Image format:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 65); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(64, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Color depth:"; + // + // rbFloor + // + this.rbFloor.AutoSize = true; + this.rbFloor.Checked = true; + this.rbFloor.Location = new System.Drawing.Point(227, 38); + this.rbFloor.Name = "rbFloor"; + this.rbFloor.Size = new System.Drawing.Size(48, 17); + this.rbFloor.TabIndex = 12; + this.rbFloor.TabStop = true; + this.rbFloor.Text = "Floor"; + this.rbFloor.UseVisualStyleBackColor = true; + // + // rbCeiling + // + this.rbCeiling.AutoSize = true; + this.rbCeiling.Location = new System.Drawing.Point(227, 60); + this.rbCeiling.Name = "rbCeiling"; + this.rbCeiling.Size = new System.Drawing.Size(56, 17); + this.rbCeiling.TabIndex = 13; + this.rbCeiling.Text = "Ceiling"; + this.rbCeiling.UseVisualStyleBackColor = true; + // + // ImageExportSettingsForm + // + this.AcceptButton = this.export; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; + this.ClientSize = new System.Drawing.Size(447, 145); + this.Controls.Add(this.rbCeiling); + this.Controls.Add(this.rbFloor); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.cbPixelFormat); + this.Controls.Add(this.cbImageFormat); + this.Controls.Add(this.cancel); + this.Controls.Add(this.export); + this.Controls.Add(this.label1); + this.Controls.Add(this.browse); + this.Controls.Add(this.tbExportPath); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ImageExportSettingsForm"; + this.Text = "Image export settings"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button browse; + private System.Windows.Forms.TextBox tbExportPath; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.Button export; + private System.Windows.Forms.SaveFileDialog saveFileDialog; + private System.Windows.Forms.ComboBox cbImageFormat; + private System.Windows.Forms.ComboBox cbPixelFormat; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.RadioButton rbFloor; + private System.Windows.Forms.RadioButton rbCeiling; + } +} \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs new file mode 100644 index 0000000..705ad2d --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs @@ -0,0 +1,149 @@ +#region ================== Copyright (c) 2020 Boris Iwanski + +/* + * This program is free software: you can redistribute it and/or modify + * + * it under the terms of the GNU General Public License as published by + * + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.If not, see. + */ + +#endregion + +using System; +using System.Drawing.Imaging; +using System.IO; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.BuilderModes.Interface +{ + public partial class ImageExportSettingsForm : Form + { + #region ================== Properties + + public string FilePath { get { return tbExportPath.Text.Trim(); } } + public bool Floor { get { return rbFloor.Checked; } } + + #endregion + + + #region ================== Constructor + + public ImageExportSettingsForm() + { + InitializeComponent(); + + cbImageFormat.SelectedIndex = 0; + cbPixelFormat.SelectedIndex = 0; + + string name = Path.GetFileNameWithoutExtension(General.Map.FileTitle) + "_" + General.Map.Options.LevelName + "_" + Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); + + if (string.IsNullOrEmpty(General.Map.FilePathName)) + { + saveFileDialog.FileName = name; + } + else + { + saveFileDialog.InitialDirectory = Path.GetDirectoryName(General.Map.FilePathName); + saveFileDialog.FileName = Path.GetDirectoryName(General.Map.FilePathName) + Path.DirectorySeparatorChar + name + ".png"; + tbExportPath.Text = saveFileDialog.FileName; + } + } + + #endregion + + #region ================== Methods + + public ImageFormat GetImageFormat() + { + switch(cbImageFormat.SelectedIndex) + { + case 1: // JPG + return ImageFormat.Jpeg; + default: // PNG + return ImageFormat.Png; + } + } + + public PixelFormat GetPixelFormat() + { + switch(cbPixelFormat.SelectedIndex) + { + case 1: // 24 bit + return PixelFormat.Format24bppRgb; + case 2: // 16 bit + return PixelFormat.Format16bppRgb555; + default: // 32 bit + return PixelFormat.Format32bppArgb; + } + } + + private void browse_Click(object sender, EventArgs e) + { + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + tbExportPath.Text = saveFileDialog.FileName; + + string extension = Path.GetExtension(saveFileDialog.FileName); + + switch(extension) + { + case ".jpg": + cbImageFormat.SelectedIndex = 1; + break; + default: + cbImageFormat.SelectedIndex = 0; + break; + } + } + } + + #endregion + + private void cancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void export_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void cbImageFormat_SelectedIndexChanged(object sender, EventArgs e) + { + string newextension = ""; + + switch (cbImageFormat.SelectedIndex) + { + case 1: // JPG + newextension = ".jpg"; + break; + default: // PNG + newextension = ".png"; + break; + } + + tbExportPath.Text = Path.ChangeExtension(tbExportPath.Text, newextension); + } + } +} diff --git a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.resx b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.resx new file mode 100644 index 0000000..5e7f0a6 --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/MenusForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/MenusForm.Designer.cs index 6ff53db..314c0f3 100644 --- a/Source/Plugins/BuilderModes/Interface/MenusForm.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/MenusForm.Designer.cs @@ -129,6 +129,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.itempastepropsoptions = new System.Windows.Forms.ToolStripMenuItem(); this.alignsectorlinedefsitem = new System.Windows.Forms.ToolStripMenuItem(); this.alignlinedefsitem = new System.Windows.Forms.ToolStripMenuItem(); + this.selectionToImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menustrip.SuspendLayout(); this.manualstrip.SuspendLayout(); this.fileMenuStrip.SuspendLayout(); @@ -583,6 +584,15 @@ namespace CodeImp.DoomBuilder.BuilderModes this.selectSimilarThingsItem.Text = "Select Similar..."; this.selectSimilarThingsItem.Click += new System.EventHandler(this.InvokeTaggedAction); // + // selectionToImageToolStripMenuItem + // + this.selectionToImageToolStripMenuItem.Name = "selectionToImageToolStripMenuItem"; + this.selectionToImageToolStripMenuItem.Size = new System.Drawing.Size(226, 22); + this.selectionToImageToolStripMenuItem.Tag = "exporttoimage"; + this.selectionToImageToolStripMenuItem.Text = "Selection to image"; + this.selectionToImageToolStripMenuItem.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // // vertsmenu // this.vertsmenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -1026,9 +1036,10 @@ namespace CodeImp.DoomBuilder.BuilderModes // exportStripMenuItem // this.exportStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem5}); + this.toolStripMenuItem5, + this.selectionToImageToolStripMenuItem}); this.exportStripMenuItem.Name = "exportStripMenuItem"; - this.exportStripMenuItem.Size = new System.Drawing.Size(52, 20); + this.exportStripMenuItem.Size = new System.Drawing.Size(53, 20); this.exportStripMenuItem.Text = "Export"; // // toolStripMenuItem5 @@ -1229,5 +1240,6 @@ namespace CodeImp.DoomBuilder.BuilderModes private System.Windows.Forms.ToolStripMenuItem vertexSlopeAssistT; private System.Windows.Forms.ToolStripMenuItem alignsectorlinedefsitem; private System.Windows.Forms.ToolStripMenuItem alignlinedefsitem; + private System.Windows.Forms.ToolStripMenuItem selectionToImageToolStripMenuItem; } } \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Resources/Actions.cfg b/Source/Plugins/BuilderModes/Resources/Actions.cfg index c1d5401..18bf749 100644 --- a/Source/Plugins/BuilderModes/Resources/Actions.cfg +++ b/Source/Plugins/BuilderModes/Resources/Actions.cfg @@ -1683,6 +1683,16 @@ exporttoobj allowscroll = false; } +exporttoimage +{ + title = "Export to image"; + category = "tools"; + description = "Exports selected sectors (or the whole map if no sectors selected) to an image"; + allowkeys = true; + allowmouse = false; + allowscroll = false; +} + flooralignmode { title = "Floor Align Mode";