diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs index 7713cf2d..df3779cf 100755 --- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs +++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs @@ -674,7 +674,7 @@ namespace CodeImp.DoomBuilder.BuilderModes ImageExportSettingsForm form = new ImageExportSettingsForm(); if (form.ShowDialog() == DialogResult.OK) { - ImageExportSettings settings = new ImageExportSettings(Path.GetDirectoryName(form.FilePath), Path.GetFileNameWithoutExtension(form.FilePath), Path.GetExtension(form.FilePath), form.Floor, form.Fullbright, form.Brightmap, form.Tiles, form.GetPixelFormat(), form.GetImageFormat()); + ImageExportSettings settings = new ImageExportSettings(Path.GetDirectoryName(form.FilePath), Path.GetFileNameWithoutExtension(form.FilePath), Path.GetExtension(form.FilePath), form.Floor, form.Fullbright, form.Brightmap, form.Tiles, form.ImageScale, form.GetPixelFormat(), form.GetImageFormat()); ImageExporter exporter = new ImageExporter(sectors, settings); string text = "The following images will be created:\n\n" + string.Join("\n", exporter.GetImageNames()); diff --git a/Source/Plugins/BuilderModes/IO/ImageExporter.cs b/Source/Plugins/BuilderModes/IO/ImageExporter.cs index 8237de56..e71e4dad 100644 --- a/Source/Plugins/BuilderModes/IO/ImageExporter.cs +++ b/Source/Plugins/BuilderModes/IO/ImageExporter.cs @@ -50,8 +50,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO public bool Tiles; public PixelFormat PixelFormat; public ImageFormat ImageFormat; + public float Scale; - public ImageExportSettings(string path, string name, string extension, bool floor, bool fullbright, bool brightmap, bool tiles, PixelFormat pformat, ImageFormat iformat) + public ImageExportSettings(string path, string name, string extension, bool floor, bool fullbright, bool brightmap, bool tiles, float scale, PixelFormat pformat, ImageFormat iformat) { Path = path; Name = name; @@ -62,6 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO Fullbright = fullbright; PixelFormat = pformat; ImageFormat = iformat; + Scale = scale; } } @@ -105,10 +107,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO GetSizeAndOffset(out size, out offset); // Use the same image for the normal texture and the brightmap because of memory concerns - using (Bitmap image = new Bitmap((int)size.x, (int)size.y, settings.PixelFormat)) + using (Bitmap image = new Bitmap((int)(size.x * settings.Scale), (int)(size.y * settings.Scale), settings.PixelFormat)) { // Normal texture image - CreateImage(image, offset, false); + CreateImage(image, offset, settings.Scale, false); if (settings.Tiles) SaveImageAsTiles(image); @@ -118,7 +120,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO // The brightmap if (settings.Brightmap) { - CreateImage(image, offset, true); + CreateImage(image, offset, settings.Scale, true); if (settings.Tiles) SaveImageAsTiles(image, "_brightmap"); @@ -135,7 +137,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO /// The offset of the selection in map space /// True if the image should be a brightmap, false if normally textured /// The image to be exported - private void CreateImage(Bitmap texturebitmap, Vector2D offset, bool asbrightmap) + private void CreateImage(Bitmap texturebitmap, Vector2D offset, float scale, bool asbrightmap) { Graphics gtexture = null; @@ -161,9 +163,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO 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.0; - Vector2D v2 = s.Triangles.Vertices[i * 3 + 1] - offset; v2.y *= -1.0; - Vector2D v3 = s.Triangles.Vertices[i * 3 + 2] - offset; v3.y *= -1.0; + Vector2D v1 = (s.Triangles.Vertices[i * 3] - offset) * scale; v1.y *= -1.0; + Vector2D v2 = (s.Triangles.Vertices[i * 3 + 1] - offset) * scale; v2.y *= -1.0; + Vector2D v3 = (s.Triangles.Vertices[i * 3 + 2] - offset) * scale; v3.y *= -1.0; gpath.AddLine((float)v1.x, (float)v1.y, (float)v2.x, (float)v2.y); gpath.AddLine((float)v2.x, (float)v2.y, (float)v3.x, (float)v3.y); @@ -188,11 +190,11 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO // but doesn't applie the color correction if we set UseColorCorrection to false first ImageData imagedata = General.Map.Data.GetFlatImage(s.FloorTexture); imagedata.UseColorCorrection = false; - brushtexture = imagedata.LocalGetBitmap(); + brushtexture = new Bitmap(imagedata.LocalGetBitmap()); imagedata.UseColorCorrection = true; - textureoffset.x = s.Fields.GetValue("xpanningfloor", 0.0); - textureoffset.y = s.Fields.GetValue("ypanningfloor", 0.0); + textureoffset.x = s.Fields.GetValue("xpanningfloor", 0.0) * scale; + textureoffset.y = s.Fields.GetValue("ypanningfloor", 0.0) * scale; // GZDoom uses bigger numbers for smaller scales (i.e. a scale of 2 will halve the size), so we need to change the scale texturescale.x = 1.0 / s.Fields.GetValue("xscalefloor", 1.0); @@ -204,11 +206,11 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO // but doesn't applie the color correction if we set UseColorCorrection to false first ImageData imagedata = General.Map.Data.GetFlatImage(s.CeilTexture); imagedata.UseColorCorrection = false; - brushtexture = imagedata.LocalGetBitmap(); + brushtexture = new Bitmap(imagedata.LocalGetBitmap()); imagedata.UseColorCorrection = true; - textureoffset.x = s.Fields.GetValue("xpanningceiling", 0.0); - textureoffset.y = s.Fields.GetValue("ypanningceiling", 0.0); + textureoffset.x = s.Fields.GetValue("xpanningceiling", 0.0) * scale; + textureoffset.y = s.Fields.GetValue("ypanningceiling", 0.0) * scale; // GZDoom uses bigger numbers for smaller scales (i.e. a scale of 2 will halve the size), so we need to change the scale texturescale.x = 1.0 / s.Fields.GetValue("xscaleceiling", 1.0); @@ -218,13 +220,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO // 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)(-offset.x*scale * rotationvector.x), (float)(offset.x*scale * rotationvector.y)); // Left/right offset from the map origin + matrix.Translate((float)(offset.y*scale * rotationvector.y), (float)(offset.y*scale * rotationvector.x)); // Up/down offset from the map origin matrix.Translate(-(float)textureoffset.x, -(float)textureoffset.y); // Texture offset matrix.Scale((float)texturescale.x, (float)texturescale.y); if (!settings.Fullbright) - AdjustBrightness(brushtexture, s.Brightness > 0 ? s.Brightness / 255.0f : 0.0f); + AdjustBrightness(ref brushtexture, s.Brightness > 0 ? s.Brightness / 255.0f : 0.0f); + + if (scale > 1.0f) + ResizeImage(ref brushtexture, brushtexture.Width * (int)scale, brushtexture.Height * (int)scale); // Create the texture brush and apply the matrix TextureBrush tbrush = new TextureBrush(brushtexture); @@ -367,7 +372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO /// /// The image to adjust /// Brightness between 0.0f and 1.0f - private void AdjustBrightness(Image image, float brightness) + private void AdjustBrightness(ref Bitmap image, float brightness) { // Make the ColorMatrix. float b = brightness; @@ -403,6 +408,40 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO image = bm; } + /// + /// Resize the image to the specified width and height. Taken from https://stackoverflow.com/a/24199315 (with some modifications) + /// + /// The image to resize. + /// The width to resize to. + /// The height to resize to. + /// The resized image. + private void ResizeImage(ref Bitmap image, int width, int height) + { + var destRect = new Rectangle(0, 0, width, height); + var destImage = new Bitmap(width, height); + + destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + + using (var graphics = Graphics.FromImage(destImage)) + { + graphics.CompositingMode = CompositingMode.SourceCopy; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + using (var wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); + } + } + + image.Dispose(); + + image = destImage; + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs index 88093ca2..b23fde0a 100644 --- a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.Designer.cs @@ -43,6 +43,8 @@ this.cbFullbright = new System.Windows.Forms.CheckBox(); this.cbBrightmap = new System.Windows.Forms.CheckBox(); this.cbTiles = new System.Windows.Forms.CheckBox(); + this.cbScale = new System.Windows.Forms.ComboBox(); + this.label4 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // tbExportPath @@ -194,6 +196,29 @@ this.cbTiles.Text = "Create 64x64 tiles"; this.cbTiles.UseVisualStyleBackColor = true; // + // cbScale + // + this.cbScale.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbScale.FormattingEnabled = true; + this.cbScale.Items.AddRange(new object[] { + "100%", + "200%", + "400%", + "800%"}); + this.cbScale.Location = new System.Drawing.Point(102, 89); + this.cbScale.Name = "cbScale"; + this.cbScale.Size = new System.Drawing.Size(71, 21); + this.cbScale.TabIndex = 17; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 92); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(37, 13); + this.label4.TabIndex = 18; + this.label4.Text = "Scale:"; + // // ImageExportSettingsForm // this.AcceptButton = this.export; @@ -201,6 +226,8 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.cancel; this.ClientSize = new System.Drawing.Size(447, 188); + this.Controls.Add(this.label4); + this.Controls.Add(this.cbScale); this.Controls.Add(this.cbTiles); this.Controls.Add(this.cbBrightmap); this.Controls.Add(this.cbFullbright); @@ -242,5 +269,7 @@ private System.Windows.Forms.CheckBox cbFullbright; private System.Windows.Forms.CheckBox cbBrightmap; private System.Windows.Forms.CheckBox cbTiles; + private System.Windows.Forms.ComboBox cbScale; + private System.Windows.Forms.Label label4; } } \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs index be639c7c..094b1036 100644 --- a/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs +++ b/Source/Plugins/BuilderModes/Interface/ImageExportSettingsForm.cs @@ -44,6 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface public bool Fullbright { get { return cbFullbright.Checked; } } public bool Brightmap { get { return cbBrightmap.Checked; } } public bool Tiles { get { return cbTiles.Checked; } } + public float ImageScale { get { return (float)Math.Pow(2, cbScale.SelectedIndex); } } #endregion @@ -73,6 +74,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface cbFullbright.Checked = General.Settings.ReadPluginSetting("imageexportfullbright", true); cbBrightmap.Checked = General.Settings.ReadPluginSetting("imageexportbrightmap", false); cbTiles.Checked = General.Settings.ReadPluginSetting("imageexporttiles", false); + cbScale.SelectedIndex = General.Settings.ReadPluginSetting("imageexportscale", 0); } #endregion @@ -133,9 +135,10 @@ namespace CodeImp.DoomBuilder.BuilderModes.Interface private void export_Click(object sender, EventArgs e) { - General.Settings.WritePluginSetting("imageexportfullbright", cbFullbright.Checked); - General.Settings.WritePluginSetting("imageexportbrightmap", cbBrightmap.Checked); - General.Settings.WritePluginSetting("imageexporttiles", cbTiles.Checked); + General.Settings.WritePluginSetting("imageexportfullbright", cbFullbright.Checked); + General.Settings.WritePluginSetting("imageexportbrightmap", cbBrightmap.Checked); + General.Settings.WritePluginSetting("imageexporttiles", cbTiles.Checked); + General.Settings.WritePluginSetting("imageexportscale", cbScale.SelectedIndex); this.DialogResult = DialogResult.OK; this.Close();