diff --git a/Background.png b/Background.png index 9bc2a0a..eeb9040 100644 Binary files a/Background.png and b/Background.png differ diff --git a/OpaqueBackground.png b/OpaqueBackground.png new file mode 100644 index 0000000..c5517d1 Binary files /dev/null and b/OpaqueBackground.png differ diff --git a/SpriteStacker/Form1.cs b/SpriteStacker/Form1.cs index dd95cbb..7c5b793 100644 --- a/SpriteStacker/Form1.cs +++ b/SpriteStacker/Form1.cs @@ -6,7 +6,9 @@ using System.Data; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; +using System.Drawing.Text; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -16,8 +18,10 @@ namespace SpriteStacker { public partial class Form1 : Form { + public static PrivateFontCollection pfc = new PrivateFontCollection(); public static Thread MainThread; public static bool running = true; + public static bool ValidLocation = true; Model model = new Model(Camera.CanvasWidth, Camera.CanvasHeight); public double LastFT = 0; public bool mouseLeftDown = false; @@ -50,9 +54,18 @@ namespace SpriteStacker Color.Beige, Color.Azure }); + private void initFont() + { + int fontLength = Resources.Monocraft.Length; + byte[] fontdata = Resources.Monocraft; + System.IntPtr data = Marshal.AllocCoTaskMem(fontLength); + Marshal.Copy(fontdata, 0, data, fontLength); + pfc.AddMemoryFont(data, fontLength); + } public Form1() { InitializeComponent(); + initFont(); ResizeDisplay(); MainThread = new Thread(mainThread); MainThread.SetApartmentState(ApartmentState.STA); @@ -70,9 +83,15 @@ namespace SpriteStacker public void mainThread() { LastFT = Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds; + double SecondCounter = Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds; while (running) { Display.Refresh(); + if (Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds - SecondCounter > 1000) + { + SecondCounter = Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds; + //model.DrawLayersToImages(); + } if (Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds - LastFT > 16) { LastFT = Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds; @@ -80,12 +99,12 @@ namespace SpriteStacker if(Rotate)Camera.Rotation++; if (mouseLeftDown) { - if(!palette.Bounds.Contains(MousePosition)) DrawBrush(new Voxel(Camera.SelectedColor)); + if(ValidLocation) DrawBrush(new Voxel(Camera.SelectedColor)); } if (mouseRightDown) { - if (!palette.Bounds.Contains(MousePosition)) DrawBrush(new Voxel(Color.Transparent)); + if (ValidLocation) DrawBrush(new Voxel(Color.Transparent)); } } } @@ -93,10 +112,19 @@ namespace SpriteStacker private void PaintDisplay(object sender, PaintEventArgs e) { e.Graphics.PixelOffsetMode = PixelOffsetMode.Half; - model.DrawSpriteStack(e.Graphics); + switch (Config.renderMode) + { + case RenderMode.Editing: + model.DrawSpriteStack(e.Graphics); + break; + case RenderMode.Rendering: + model.RenderModel(e.Graphics,Config.RenderResolution); + break; + + } palette.Draw(e.Graphics); e.Graphics.ResetTransform(); - + e.Graphics.DrawString(String.Format("Selected Brush: {0}\nLayer: {1}/{2}\nBrush Size: {3}\nBrush Intensity: {4}\nRender Type: {5}\nRender Resolution: {6}", Camera.type, Camera.SelectedLayer + 1, model.LayerImages.Count, Camera.BrushSize, Camera.SprayIntensity,Config.renderMode,Config.renderMode == RenderMode.Editing ? "N/A": Config.RenderResolution.ToString()), new Font(pfc.Families[0], Config.FontSize), Brushes.DarkSlateBlue, new Point(0, palette.Bounds.Bottom)); } private void ResizeDisplay() @@ -130,10 +158,12 @@ namespace SpriteStacker private void Reset() { model = new Model(Camera.CanvasWidth, Camera.CanvasHeight); + Camera.SelectedLayer = 0; } private void KeyDownEvent(object sender, KeyEventArgs e) { BrushType[] types = new BrushType[] { BrushType.Square, BrushType.Circle,BrushType.Spray }; + RenderMode[] RenderModes = new RenderMode[] {RenderMode.Editing, RenderMode.Rendering }; if (e.KeyCode == Keys.W) Camera.BrushY = Math.Min(Camera.BrushY + 1,model.Length); if (e.KeyCode == Keys.S) Camera.BrushY = Math.Max(Camera.BrushY -1, 0); if (e.KeyCode == Keys.A) Camera.BrushX = Math.Min(Camera.BrushX + 1, model.Width); @@ -146,8 +176,16 @@ namespace SpriteStacker if (e.KeyCode == Keys.H) Camera.ViewAngle -= 0.25f; if (e.KeyCode == Keys.D1) Config.BackgroundTile += 2; if (e.KeyCode == Keys.D2) Config.BackgroundTile -= 2; + if (e.KeyCode == Keys.D3) Config.RenderResolution += 1; + if (e.KeyCode == Keys.D4) Config.RenderResolution -= 1; if (e.KeyCode == Keys.R) Rotate = !Rotate; if (e.KeyCode == Keys.ShiftKey) Camera.EditMode = !Camera.EditMode; + if (e.KeyCode == Keys.ControlKey) + { + Config.RenderIndex++; + if (Config.RenderIndex >= RenderModes.Length) Config.RenderIndex = 0; + Config.renderMode = RenderModes[Config.RenderIndex]; + } if (e.KeyCode == Keys.Up) model.SetCurrentLayer(Camera.SelectedLayer + 1); if (e.KeyCode == Keys.Down) model.SetCurrentLayer(Math.Max(Camera.SelectedLayer - 1,0)); if (e.KeyCode == Keys.Delete) Reset(); @@ -181,8 +219,12 @@ namespace SpriteStacker { for (int j = 0; j < Camera.BrushSize; j++) { - int locx = Math.Min(Math.Max((Camera.BrushX + i - Camera.BrushSize / 2), 0), model.Width - 1); - int locy = Math.Min(Math.Max((Camera.BrushY + j - Camera.BrushSize / 2), 0), model.Length - 1); + int locx = (Camera.BrushX + i - Camera.BrushSize / 2); + int locy = (Camera.BrushY + j - Camera.BrushSize / 2); + if (locx < -4 || locx > model.Width + 4 || locy < -4 || locy > model.Length + 4) ValidLocation = false; + else ValidLocation = true; + locx = Math.Min(Math.Max(locx, 0), model.Width - 1); + locy = Math.Min(Math.Max(locy, 0), model.Length - 1); bool paintPixel = false; if (Camera.type == BrushType.Square) paintPixel = true; if (Camera.type == BrushType.Circle && Camera.isWithinCircle(i, j, (int)Math.Floor(Camera.BrushSize / 2.0), (int)(Camera.BrushSize / 2.0), (int)(Camera.BrushSize / 2.0))) @@ -196,7 +238,7 @@ namespace SpriteStacker if(paintPixel) model.SetData(Math.Min(locx, model.Width - 1), Math.Min(locy, model.Length - 1), Camera.SelectedLayer, voxel); } } - model.DrawLayersToImages(); + model.DrawSelectedLayerToImage(); } private void MouseMoveEvent(object sender, MouseEventArgs e) @@ -228,10 +270,14 @@ namespace SpriteStacker if (e.Button == MouseButtons.Left) { mouseLeftDown = false; + model.DrawLayersToImages(); + } if (e.Button == MouseButtons.Right) { mouseRightDown = false; + model.DrawLayersToImages(); + } } diff --git a/SpriteStacker/Model.cs b/SpriteStacker/Model.cs index d48eb40..2f60807 100644 --- a/SpriteStacker/Model.cs +++ b/SpriteStacker/Model.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Drawing.Imaging; using System.Linq; using System.Runtime.Versioning; using System.Text; @@ -10,10 +11,20 @@ using System.Windows.Forms; namespace SpriteStacker { + public enum RenderMode + { + Editing, + Rendering + } public static class Config { public static Color BasePlateColour = Color.FromArgb(255, 255, 255, 255); public static int BackgroundTile = 2; + public static List customFonts = new List(); + public static int FontSize = 16; + public static int RenderIndex = 0; + public static RenderMode renderMode = RenderMode.Editing; + public static int RenderResolution = 1; } public class ColourPalette { @@ -167,10 +178,12 @@ namespace SpriteStacker public int Width; public int Length; public List Bounds = new List(); + public Bitmap RenderedModel; public Model(int Width, int Length) { this.Width = Width; this.Length = Length; + RenderedModel = new Bitmap(Width * 2, Length * 2); AddLayer(); } public void SetCurrentLayer(int Layer) @@ -220,6 +233,61 @@ namespace SpriteStacker LayerImages.Add(new Bitmap(Width, Length)); ModelData.Add(new Voxel[Width,Length]); Bounds.Add(new Rectangle(new Point(-(int)(Width * Camera.scale) / 2, -(int)(Length * Camera.scale) / 2), new Size((int)(Width * Camera.scale), (int)(Length * Camera.scale)))); + Bitmap Render = new Bitmap(Width * 2, (Length + (int)(ModelData.Count * Camera.ViewAngle)) * 2); + } + public void RenderModel(Graphics R, int RenderResolution) + { + RenderResolution = Math.Max(RenderResolution, 1); + Bitmap Render = new Bitmap((Width * 2 * RenderResolution), (Length + (int)(ModelData.Count * Camera.ViewAngle)) * 2 * RenderResolution); + Graphics G = Graphics.FromImage(Render); + G.ResetTransform(); + G.TranslateTransform(Render.Width/2, Render.Height/2); + G.RotateTransform(Camera.Rotation); + float AngleScale = Camera.ViewAngle * RenderResolution; + G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; + G.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + G.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + float[][] colorMatrixElements = { + new float[] {0.0f, 0, 0, 0, 0},//R + new float[] {0, 0.0f, 0, 0, 0},//G + new float[] {0, 0, 0.0f, 0, 0},//B + new float[] {0, 0, 0, 0.8f, 0}, + new float[] {0.0f, 0.0f, 0.0f, 0f, 1}}; + + ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements); + ImageAttributes imageAttributes = new ImageAttributes(); + imageAttributes.SetColorMatrix( + colorMatrix, + ColorMatrixFlag.Default, + ColorAdjustType.Bitmap); + for (int i = 0; i < ModelData.Count; i++) + { + G.ResetTransform(); + G.TranslateTransform(Render.Width / 2 - ((i * RenderResolution / 1.25f) * (float)Math.Cos(Camera.Rotation * Math.PI / 180.0)), Render.Height / 2 - (((i / 1.25f) * (float)Math.Sin(Camera.Rotation * Math.PI / 180.0)) * AngleScale)); + G.RotateTransform(Camera.Rotation); + G.DrawImage(LayerImages[i], new Rectangle(-(LayerImages[i].Width / 2) * RenderResolution, -(LayerImages[i].Height / 2) * RenderResolution, LayerImages[i].Width * RenderResolution, LayerImages[i].Height * RenderResolution) + , 0, 0, LayerImages[i].Width, LayerImages[i].Height, GraphicsUnit.Pixel, imageAttributes); + } + for (int i = 0; i < ModelData.Count; i++) + { + G.ResetTransform(); + G.TranslateTransform(Render.Width / 2, Render.Height / 2 - (i * AngleScale)); + G.RotateTransform(Camera.Rotation); + G.DrawImage(LayerImages[i], new Rectangle(-(LayerImages[i].Width / 2) * RenderResolution, -(LayerImages[i].Height / 2) * RenderResolution, LayerImages[i].Width * RenderResolution, LayerImages[i].Height * RenderResolution)); + } + int X = Camera.LocX + Camera.Width / 2; + int Y = Camera.Height / 2 + Camera.LocY; + R.ResetTransform(); + R.TranslateTransform(X, Y); + R.RotateTransform(Camera.Rotation); + R.FillRectangle(new SolidBrush(Config.BasePlateColour), Bounds[0]); + int difference = Render.Height - Render.Width; + R.ResetTransform(); + R.TranslateTransform(X, Y); + R.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + R.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + R.DrawImage(Render,( -Render.Width / 2)/ RenderResolution * Camera.scale, (-(Render.Width + difference) / 2)/ RenderResolution * Camera.scale, Render.Width/ RenderResolution * Camera.scale, Render.Height/ RenderResolution * Camera.scale); + RenderedModel = Render; } public void DrawSpriteStack(Graphics G) { @@ -254,7 +322,7 @@ namespace SpriteStacker { G.ResetTransform(); G.TranslateTransform(X, Y); - TextureBrush TileBrush = new TextureBrush(Resources.Background); + TextureBrush TileBrush = new TextureBrush(Resources.OpaqueBackground); TileBrush.ScaleTransform((1 / 32.0f) * Camera.scale * (Config.BackgroundTile / 2), (1 / 32.0f) * Camera.scale * (Config.BackgroundTile / 2)); G.FillRectangle(TileBrush, Bounds[Camera.SelectedLayer]); G.DrawImage(LayerImages[Camera.SelectedLayer], Bounds[Camera.SelectedLayer]); @@ -263,6 +331,21 @@ namespace SpriteStacker } } + public void DrawSelectedLayerToImage() + { + Bitmap newImage = new Bitmap(Width, Length); + for (int x = 0; x < ModelData[Camera.SelectedLayer].GetLength(0); x++) + { + for (int y = 0; y < ModelData[Camera.SelectedLayer].GetLength(1); y++) + { + if (ModelData[Camera.SelectedLayer][x, y] != null) + { + newImage.SetPixel(x, y, ModelData[Camera.SelectedLayer][x, y].GetColor()); + } + } + } + LayerImages[Camera.SelectedLayer] = newImage; + } public void DrawLayersToImages() { for (int i = 0; i < ModelData.Count; i++) diff --git a/SpriteStacker/Properties/Resources.Designer.cs b/SpriteStacker/Properties/Resources.Designer.cs index 8ba549f..52225e1 100644 --- a/SpriteStacker/Properties/Resources.Designer.cs +++ b/SpriteStacker/Properties/Resources.Designer.cs @@ -329,5 +329,25 @@ namespace SpriteStacker.Properties { return ((System.Drawing.Bitmap)(obj)); } } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] Monocraft { + get { + object obj = ResourceManager.GetObject("Monocraft", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap OpaqueBackground { + get { + object obj = ResourceManager.GetObject("OpaqueBackground", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/SpriteStacker/Properties/Resources.resx b/SpriteStacker/Properties/Resources.resx index a659944..4071b25 100644 --- a/SpriteStacker/Properties/Resources.resx +++ b/SpriteStacker/Properties/Resources.resx @@ -121,6 +121,12 @@ ..\Resources\Background.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Monocraft.ttf;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\OpaqueBackground.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/SpriteStacker/Resources/Background.png b/SpriteStacker/Resources/Background.png index 9bc2a0a..eeb9040 100644 Binary files a/SpriteStacker/Resources/Background.png and b/SpriteStacker/Resources/Background.png differ diff --git a/SpriteStacker/Resources/Monocraft.ttf b/SpriteStacker/Resources/Monocraft.ttf new file mode 100644 index 0000000..4f65eb9 Binary files /dev/null and b/SpriteStacker/Resources/Monocraft.ttf differ diff --git a/SpriteStacker/Resources/OpaqueBackground.png b/SpriteStacker/Resources/OpaqueBackground.png new file mode 100644 index 0000000..c5517d1 Binary files /dev/null and b/SpriteStacker/Resources/OpaqueBackground.png differ diff --git a/SpriteStacker/SpriteStacker.csproj b/SpriteStacker/SpriteStacker.csproj index 6978a7d..2aecd93 100644 --- a/SpriteStacker/SpriteStacker.csproj +++ b/SpriteStacker/SpriteStacker.csproj @@ -77,6 +77,7 @@ Settings.settings True + @@ -159,6 +160,9 @@ + + +