From 7c5beef670debc03828cd315a182cfb7d4a17037 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 10 Sep 2019 18:44:25 +0200 Subject: [PATCH] Smooth lines --- .../Drawable Frame/DrawableFrame.cs.meta | 2 +- Assets/Drawing/Drawable Frame/PencilTool.cs | 111 +++++++++++++++--- .../SetSpriteFromDrawableFrame.cs.meta | 2 +- Assets/Drawing/PencilColorFromButtonColor.cs | 2 +- Assets/Swap.cs | 6 + Assets/Swap.cs.meta | 11 ++ 6 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 Assets/Swap.cs create mode 100644 Assets/Swap.cs.meta diff --git a/Assets/Drawing/Drawable Frame/DrawableFrame.cs.meta b/Assets/Drawing/Drawable Frame/DrawableFrame.cs.meta index a6a210e..c04e23f 100644 --- a/Assets/Drawing/Drawable Frame/DrawableFrame.cs.meta +++ b/Assets/Drawing/Drawable Frame/DrawableFrame.cs.meta @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: 100 + executionOrder: -50 icon: {instanceID: 0} userData: assetBundleName: diff --git a/Assets/Drawing/Drawable Frame/PencilTool.cs b/Assets/Drawing/Drawable Frame/PencilTool.cs index a387574..9bdcb0f 100644 --- a/Assets/Drawing/Drawable Frame/PencilTool.cs +++ b/Assets/Drawing/Drawable Frame/PencilTool.cs @@ -4,8 +4,13 @@ using UnityEngine; public class PencilTool : DrawTool { - public Color color = Color.black; + public Color selectedColor = Color.black; public float size = 1f; + + protected Color[] colors; + + private Vector2Int? previousPixel; + private Vector2Int? pixel; protected Vector2Int? HoveredPixel() { Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition); @@ -19,31 +24,107 @@ public class PencilTool : DrawTool protected override void Start() { base.Start(); - InvokeRepeating("Apply", 0.05f, 0.05f); + colors = frame.texture.GetPixels(); } protected void Update() { - Color[] colors = frame.texture.GetPixels(); + previousPixel = pixel; if(Input.GetMouseButton(0)) { - Vector2Int? pixel = HoveredPixel(); + pixel = HoveredPixel(); if(pixel.HasValue) { - int x_start = Mathf.Clamp(Mathf.CeilToInt((float)pixel.Value.x - size), 0, frame.resolution.x); - int x_end = Mathf.Clamp(Mathf.CeilToInt((float)pixel.Value.x + size), 0, frame.resolution.x); - int y_start = Mathf.Clamp(Mathf.CeilToInt((float)pixel.Value.y - size), 0, frame.resolution.y); - int y_end = Mathf.Clamp(Mathf.CeilToInt((float)pixel.Value.y + size), 0, frame.resolution.y); - for(int x = x_start; x < x_end; x++) { - for(int y = y_start; y < y_end; y++) { - if(Vector2Int.Distance(new Vector2Int(x, y), pixel.Value) < size) { - colors[x + y*frame.resolution.x] = color; - } - } + if(previousPixel.HasValue) { + DrawBresenhamsThickLine(previousPixel.Value, pixel.Value, size, selectedColor); + } + else { + DrawFilledCircle(pixel.Value, size, selectedColor); + } + } + Apply(); + } + else { + pixel = null; + } + } + + protected void DrawPixel(int x, int y, Color color) { + if(x < 0 || x >= frame.resolution.x || y < 0 || y >= frame.resolution.y) return; + colors[x + y*frame.resolution.x] = color; + } + + protected void DrawCircleEightPoints(Vector2Int center, int x_radius, int y_radius, Color color) { + DrawPixel(center.x+x_radius, center.y+y_radius, color); + DrawPixel(center.x-x_radius, center.y+y_radius, color); + DrawPixel(center.x+x_radius, center.y-y_radius, color); + DrawPixel(center.x-x_radius, center.y-y_radius, color); + DrawPixel(center.x+y_radius, center.y+x_radius, color); + DrawPixel(center.x-y_radius, center.y+x_radius, color); + DrawPixel(center.x+y_radius, center.y-x_radius, color); + DrawPixel(center.x-y_radius, center.y-x_radius, color); + } + + // No idea on how does it work + // https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/ + protected void DrawBresenhamEmptyCircle(Vector2Int center, int radius, Color color) { + int x = 0; + int y = radius; + int d = 3 - 2 * radius; + DrawCircleEightPoints(center, x, y, color); + while(y >= x) { + x++; + if(d > 0) { + y--; + d = d + 4 * (x - y) + 10; + } + else { + d = d + 4 * x + 6; + } + DrawCircleEightPoints(center, x, y, color); + } + } + + protected void DrawFilledCircle(Vector2Int center, float radius, Color color) { + int x_start = Mathf.CeilToInt((float)center.x - radius); + int x_end = Mathf.CeilToInt((float)center.x + radius); + int y_start = Mathf.CeilToInt((float)center.y - radius); + int y_end = Mathf.CeilToInt((float)center.y + radius); + for(int x = x_start; x < x_end; x++) { + for(int y = y_start; y < y_end; y++) { + if(Vector2Int.Distance(new Vector2Int(x, y), center) < radius) { + DrawPixel(x, y, color); } } } - frame.texture.SetPixels(colors); + } + + // http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm + protected void DrawBresenhamsThickLine(Vector2Int start, Vector2Int end, float radius, Color color) { + int start_x = start.x, start_y = start.y, end_x = end.x, end_y = end.y; + bool steep = Mathf.Abs(end_y - start_y) > Mathf.Abs(end_x - start_x); + if (steep) { + Utils.Swap(ref start_x, ref start_y); + Utils.Swap(ref end_x, ref end_y); + } + if (start_x > end_x) { + Utils.Swap(ref start_x, ref end_x); + Utils.Swap(ref start_y, ref end_y); + } + int dX = (end_x - start_x), dY = Mathf.Abs(end_y - start_y), err = (dX / 2), ystep = (start_y < end_y ? 1 : -1), y = start_y; + + for (int x = start_x; x <= end_x; ++x) + { + if(steep) { + DrawFilledCircle(new Vector2Int(y, x), radius, color); + } + else { + DrawFilledCircle(new Vector2Int(x, y), radius, color); + } + err = err - dY; + if (err < 0) { y += ystep; err += dX; } + } } protected void Apply() { + frame.texture.SetPixels(colors); frame.texture.Apply(); } } diff --git a/Assets/Drawing/Drawable Frame/SetSpriteFromDrawableFrame.cs.meta b/Assets/Drawing/Drawable Frame/SetSpriteFromDrawableFrame.cs.meta index c0656de..0bac31e 100644 --- a/Assets/Drawing/Drawable Frame/SetSpriteFromDrawableFrame.cs.meta +++ b/Assets/Drawing/Drawable Frame/SetSpriteFromDrawableFrame.cs.meta @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: 200 + executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: diff --git a/Assets/Drawing/PencilColorFromButtonColor.cs b/Assets/Drawing/PencilColorFromButtonColor.cs index ff9996a..fe8dfe0 100644 --- a/Assets/Drawing/PencilColorFromButtonColor.cs +++ b/Assets/Drawing/PencilColorFromButtonColor.cs @@ -16,6 +16,6 @@ public class PencilColorFromButtonColor : MonoBehaviour public void OnClick() { - pencil.color = image.color; + pencil.selectedColor = image.color; } } diff --git a/Assets/Swap.cs b/Assets/Swap.cs new file mode 100644 index 0000000..57f717a --- /dev/null +++ b/Assets/Swap.cs @@ -0,0 +1,6 @@ + +public class Utils { + public static void Swap(ref T lhs, ref T rhs) { + T temp; temp = lhs; lhs = rhs; rhs = temp; + } +} diff --git a/Assets/Swap.cs.meta b/Assets/Swap.cs.meta new file mode 100644 index 0000000..4a03f46 --- /dev/null +++ b/Assets/Swap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12f494a09d5848e4c8843d84f864396e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: