11extends Control
22
3- # The TL position of the canvas
3+ # A constant for whether or not we're needing to undo a shape.
4+ const UNDO_MODE_SHAPE = - 2
5+ # A constant for whether or not we can undo.
6+ const UNDO_NONE = - 1
7+ # How large is the image (it's actually the size of DrawingAreaBG, because that's our background canvas).
8+ const IMAGE_SIZE = Vector2 (930 , 720 )
9+
10+ # Enums for the various modes and brush shapes that can be applied.
11+ enum BrushModes {
12+ PENCIL , ERASER , CIRCLE_SHAPE , RECTANGLE_SHAPE
13+ }
14+ enum BrushShapes {
15+ RECTANGLE , CIRCLE
16+ }
17+
18+ # The top-left position of the canvas.
419var TL_node
520
621# A list to hold all of the dictionaries that make up each brush.
722var brush_data_list = []
823
924# A boolean to hold whether or not the mouse is inside the drawing area, the mouse position last _process call
10- # and the position of the mouse when the left mouse button was pressed
25+ # and the position of the mouse when the left mouse button was pressed.
1126var is_mouse_in_drawing_area = false
1227var last_mouse_pos = Vector2 ()
1328var mouse_click_start_pos = null
1429
1530# A boolean to tell whether we've set undo_elements_list_num, which holds the size of draw_elements_list
1631# before a new stroke is added (unless the current brush mode is 'rectangle shape' or 'circle shape', in
17- # which case we do things a litte differently. See the undo_stroke function for more details)
32+ # which case we do things a litte differently. See the undo_stroke function for more details).
1833var undo_set = false
1934var undo_element_list_num = - 1
2035
21- # A constant for whether or not we're needing to undo a shape
22- const UNDO_MODE_SHAPE = - 2
23- # A constant for whether or not we can undo
24- const UNDO_NONE = - 1
25-
26- # Enums for the various modes and brush shapes that can be applied
27- enum BRUSH_MODES {
28- pencil , eraser , circle_shape , rectangle_shape
29- }
30- enum BRUSH_SHAPES {
31- rectangle , circle
32- }
33-
34- # The current brush settings: The mode, size, color, and shape we have currently selected
35- var brush_mode = BRUSH_MODES .pencil
36+ # The current brush settings: The mode, size, color, and shape we have currently selected.
37+ var brush_mode = BrushModes .PENCIL
3638var brush_size = 32
37- var brush_color = Color ( 1 , 1 , 1 , 1 )
38- var brush_shape = BRUSH_SHAPES . circle ;
39+ var brush_color = Color . black
40+ var brush_shape = BrushShapes . CIRCLE ;
3941
4042# The color of the background. We need this for the eraser (see the how we handle the eraser
41- # in the _draw function for more details)
42- var bg_color = Color (1 , 1 , 1 , 1 )
43-
44- # How large is the image (it's actually the size of DrawingAreaBG, because that's our background canvas)
45- const IMAGE_SIZE = Vector2 (930 , 720 )
46-
43+ # in the _draw function for more details).
44+ var bg_color = Color .white
4745
4846func _ready ():
49- # Get the top left position node. We need this to find out whether or not the mouse is inside the canvas
47+ # Get the top left position node. We need this to find out whether or not the mouse is inside the canvas.
5048 TL_node = get_node ("TLPos" )
5149 set_process (true )
5250
5351
5452func _process (_delta ):
5553 var mouse_pos = get_viewport ().get_mouse_position ()
5654
57- # Check if the mouse is currently inside the canvas/drawing-area
55+ # Check if the mouse is currently inside the canvas/drawing-area.
5856 is_mouse_in_drawing_area = false
5957 if mouse_pos .x > TL_node .global_position .x :
6058 if mouse_pos .y > TL_node .global_position .y :
6159 is_mouse_in_drawing_area = true
6260
6361 if Input .is_mouse_button_pressed (BUTTON_LEFT ):
64- # If we do not have a position for when the mouse was first clicked, then this most
62+ # If we do not have a position for when the mouse was first clicked, then this must
6563 # be the first time is_mouse_button_pressed has been called since the mouse button was
66- # released, so we need to store the position
64+ # released, so we need to store the position.
6765 if mouse_click_start_pos == null :
6866 mouse_click_start_pos = mouse_pos
6967
70- # If the mouse is inside the canvas and the mouse is 1px away from the position of the mouse last _process call
68+ # If the mouse is inside the canvas and the mouse is 1px away from the position of the mouse last _process call.
7169 if check_if_mouse_is_inside_canvas ():
7270 if mouse_pos .distance_to (last_mouse_pos ) >= 1 :
73- # If we are in pencil or eraser mode, then we need to draw
74- if brush_mode == BRUSH_MODES . pencil or brush_mode == BRUSH_MODES . eraser :
71+ # If we are in pencil or eraser mode, then we need to draw.
72+ if brush_mode == BrushModes . PENCIL or brush_mode == BrushModes . ERASER :
7573 # If undo has not been set, meaning we've started a new stroke, then store the size of the
76- # draw_elements_list so we can undo from this point in time
74+ # draw_elements_list so we can undo from this point in time.
7775 if undo_set == false :
7876 undo_set = true
7977 undo_element_list_num = brush_data_list .size ()
80- # Add the brush object to draw_elements_array
78+ # Add the brush object to draw_elements_array.
8179 add_brush (mouse_pos , brush_mode )
8280
8381 else :
84- # We've finished our stroke, so we can set a new undo (if a new storke is made)
82+ # We've finished our stroke, so we can set a new undo (if a new storke is made).
8583 undo_set = false
8684
87- # If the mouse is inside the canvas
85+ # If the mouse is inside the canvas.
8886 if check_if_mouse_is_inside_canvas ():
8987 # If we're using either the circle shape mode, or the rectangle shape mode, then
90- # add the brush object to draw_elements_array
91- if brush_mode == BRUSH_MODES . circle_shape or brush_mode == BRUSH_MODES . rectangle_shape :
88+ # add the brush object to draw_elements_array.
89+ if brush_mode == BrushModes . CIRCLE_SHAPE or brush_mode == BrushModes . RECTANGLE_SHAPE :
9290 add_brush (mouse_pos , brush_mode )
9391 # We handle undo's differently than either pencil or eraser mode, so we need to set undo
94- # element_list_num to -2 so we can tell if we need to undo a shape. See undo_stroke for details
92+ # element_list_num to -2 so we can tell if we need to undo a shape. See undo_stroke for details.
9593 undo_element_list_num = UNDO_MODE_SHAPE
9694 # Since we've released the left mouse, we need to get a new mouse_click_start_pos next time
9795 # is_mouse_button_pressed is true.
9896 mouse_click_start_pos = null
9997
100- # Store mouse_pos as last_mouse_pos now that we're done with _process
98+ # Store mouse_pos as last_mouse_pos now that we're done with _process.
10199 last_mouse_pos = mouse_pos
102100
103101
104102func check_if_mouse_is_inside_canvas ():
105- # Make sure we have a mouse click starting position
103+ # Make sure we have a mouse click starting position.
106104 if mouse_click_start_pos != null :
107105 # Make sure the mouse click starting position is inside the canvas.
108106 # This is so if we start out click outside the canvas (say chosing a color from the color picker)
109- # and then move our mouse back into the canvas, it won't start painting
107+ # and then move our mouse back into the canvas, it won't start painting.
110108 if mouse_click_start_pos .x > TL_node .global_position .x :
111109 if mouse_click_start_pos .y > TL_node .global_position .y :
112- # Make sure the current mouse position is inside the canvas
110+ # Make sure the current mouse position is inside the canvas.
113111 if is_mouse_in_drawing_area == true :
114112 return true
115113 return false
116114
117115
118116func undo_stroke ():
119- # Only undo a stroke if we have one
117+ # Only undo a stroke if we have one.
120118 if undo_element_list_num == UNDO_NONE :
121119 return
122120
123- # If we are undoing a shape, then we can just remove the latest brush
121+ # If we are undoing a shape, then we can just remove the latest brush.
124122 if undo_element_list_num == UNDO_MODE_SHAPE :
125123 if brush_data_list .size () > 0 :
126124 brush_data_list .remove (brush_data_list .size () - 1 )
127125
128- # Now that we've undone a shape, we cannot undo again until another stoke is added
126+ # Now that we've undone a shape, we cannot undo again until another stoke is added.
129127 undo_element_list_num = UNDO_NONE
130128 # NOTE: if we only had shape brushes, then we could remove the above line and could let the user
131- # undo until we have a empty element list
129+ # undo until we have a empty element list.
132130
133131 # Otherwise we're removing a either a pencil stroke or a eraser stroke.
134132 else :
135- # Figure out how many elements/brushes we've added in the last stroke
133+ # Figure out how many elements/brushes we've added in the last stroke.
136134 var elements_to_remove = brush_data_list .size () - undo_element_list_num
137- # Remove all of the elements we've added this in the last stroke
135+ # Remove all of the elements we've added this in the last stroke.
138136 # warning-ignore:unused_variable
139137 for elment_num in range (0 , elements_to_remove ):
140138 brush_data_list .pop_back ()
141139
142- # Now that we've undone a stoke, we cannot undo again until another stoke is added
140+ # Now that we've undone a stoke, we cannot undo again until another stoke is added.
143141 undo_element_list_num = UNDO_NONE
144142
145143 # Redraw the brushes
@@ -159,101 +157,93 @@ func add_brush(mouse_pos, type):
159157 new_brush .brush_color = brush_color
160158
161159 # If the new bursh is a rectangle shape, we need to calculate the top left corner of the rectangle and the
162- # bottom right corner of the rectangle
163- if type == BRUSH_MODES . rectangle_shape :
160+ # bottom right corner of the rectangle.
161+ if type == BrushModes . RECTANGLE_SHAPE :
164162 var TL_pos = Vector2 ()
165163 var BR_pos = Vector2 ()
166164
167- # Figure out the left and right positions of the corners and assign them to the proper variable
165+ # Figure out the left and right positions of the corners and assign them to the proper variable.
168166 if mouse_pos .x < mouse_click_start_pos .x :
169167 TL_pos .x = mouse_pos .x
170168 BR_pos .x = mouse_click_start_pos .x
171169 else :
172170 TL_pos .x = mouse_click_start_pos .x
173171 BR_pos .x = mouse_pos .x
174172
175- # Figure out the top and bottom positions of the corners and assign them to the proper variable
173+ # Figure out the top and bottom positions of the corners and assign them to the proper variable.
176174 if mouse_pos .y < mouse_click_start_pos .y :
177175 TL_pos .y = mouse_pos .y
178176 BR_pos .y = mouse_click_start_pos .y
179177 else :
180178 TL_pos .y = mouse_click_start_pos .y
181179 BR_pos .y = mouse_pos .y
182180
183- # Assign the positions to the brush
181+ # Assign the positions to the brush.
184182 new_brush .brush_pos = TL_pos
185183 new_brush .brush_shape_rect_pos_BR = BR_pos
186184
187- # If the brush isa circle shape, then we need to calculate the radius of the circle
188- if type == BRUSH_MODES . circle_shape :
189- # Get the center point inbetween the mouse position and the position of the mouse when we clicked
185+ # If the brush isa circle shape, then we need to calculate the radius of the circle.
186+ if type == BrushModes . CIRCLE_SHAPE :
187+ # Get the center point inbetween the mouse position and the position of the mouse when we clicked.
190188 var center_pos = Vector2 ((mouse_pos .x + mouse_click_start_pos .x ) / 2 , (mouse_pos .y + mouse_click_start_pos .y ) / 2 )
191189 # Assign the brush position to the center point, and calculate the radius of the circle using the distance from
192- # the center to the top/bottom positon of the mouse
190+ # the center to the top/bottom positon of the mouse.
193191 new_brush .brush_pos = center_pos
194192 new_brush .brush_shape_circle_radius = center_pos .distance_to (Vector2 (center_pos .x , mouse_pos .y ))
195193
196- # Add the brush and update/draw all of the brushes
194+ # Add the brush and update/draw all of the brushes.
197195 brush_data_list .append (new_brush )
198196 update ()
199197
200198
201199func _draw ():
202- # Go through all of the brushes in brush_data_list
200+ # Go through all of the brushes in brush_data_list.
203201 for brush in brush_data_list :
204-
205- # If the brush is a pencil
206- if brush .brush_type == BRUSH_MODES .pencil :
207- # If the brush shape is a rectangle, then we need to make a Rect2 so we can use draw_rect.
208- # Draw_rect draws a rectagle at the top left corner, using the scale for the size.
209- # So we offset the position by half of the brush size so the rectangle's center is at mouse position
210- if brush .brush_shape == BRUSH_SHAPES .rectangle :
211- var rect = Rect2 (brush .brush_pos - Vector2 (brush .brush_size / 2 , brush .brush_size / 2 ), Vector2 (brush .brush_size , brush .brush_size ))
202+ match brush .brush_type :
203+ BrushModes .PENCIL :
204+ # If the brush shape is a rectangle, then we need to make a Rect2 so we can use draw_rect.
205+ # Draw_rect draws a rectagle at the top left corner, using the scale for the size.
206+ # So we offset the position by half of the brush size so the rectangle's center is at mouse position.
207+ if brush .brush_shape == BrushShapes .RECTANGLE :
208+ var rect = Rect2 (brush .brush_pos - Vector2 (brush .brush_size / 2 , brush .brush_size / 2 ), Vector2 (brush .brush_size , brush .brush_size ))
209+ draw_rect (rect , brush .brush_color )
210+ # If the brush shape is a circle, then we draw a circle at the mouse position,
211+ # making the radius half of brush size (so the circle is brush size pixels in diameter).
212+ elif brush .brush_shape == BrushShapes .CIRCLE :
213+ draw_circle (brush .brush_pos , brush .brush_size / 2 , brush .brush_color )
214+ BrushModes .ERASER :
215+ # NOTE: this is a really cheap way of erasing that isn't really erasing!
216+ # However, this gives similar results in a fairy simple way!
217+
218+ # Erasing works exactly the same was as pencil does for both the rectangle shape and the circle shape,
219+ # but instead of using brush.brush_color, we instead use bg_color instead.
220+ if brush .brush_shape == BrushShapes .RECTANGLE :
221+ var rect = Rect2 (brush .brush_pos - Vector2 (brush .brush_size / 2 , brush .brush_size / 2 ), Vector2 (brush .brush_size , brush .brush_size ))
222+ draw_rect (rect , bg_color )
223+ elif brush .brush_shape == BrushShapes .CIRCLE :
224+ draw_circle (brush .brush_pos , brush .brush_size / 2 , bg_color )
225+ BrushModes .RECTANGLE_SHAPE :
226+ # We make a Rect2 with the postion at the top left. To get the size we take the bottom right position
227+ # and subtract the top left corner's position.
228+ var rect = Rect2 (brush .brush_pos , brush .brush_shape_rect_pos_BR - brush .brush_pos )
212229 draw_rect (rect , brush .brush_color )
213- # If the brush shape is a circle, then we draw a circle at the mouse position,
214- # making the radius half of brush size (so the circle is brush size pixels in diameter)
215- elif brush .brush_shape == BRUSH_SHAPES .circle :
216- draw_circle (brush .brush_pos , brush .brush_size / 2 , brush .brush_color )
217-
218- # If the brush is a eraser
219- elif brush .brush_type == BRUSH_MODES .eraser :
220- # NOTE: this is a really cheap way of erasing that isn't really erasing!
221- # However, this gives similar results in a fairy simple way!
222-
223- # Erasing works exactly the same was as pencil does for both the rectangle shape and the circle shape,
224- # but instead of using brush.brush_color, we instead use bg_color instead.
225- if brush .brush_shape == BRUSH_SHAPES .rectangle :
226- var rect = Rect2 (brush .brush_pos - Vector2 (brush .brush_size / 2 , brush .brush_size / 2 ), Vector2 (brush .brush_size , brush .brush_size ))
227- draw_rect (rect , bg_color )
228- elif brush .brush_shape == BRUSH_SHAPES .circle :
229- draw_circle (brush .brush_pos , brush .brush_size / 2 , bg_color )
230-
231- # If the brush is a rectangle shape
232- elif brush .brush_type == BRUSH_MODES .rectangle_shape :
233- # We make a Rect2 with the postion at the top left. To get the size we take the bottom right position
234- # and subtract the top left corner's position
235- var rect = Rect2 (brush .brush_pos , brush .brush_shape_rect_pos_BR - brush .brush_pos )
236- draw_rect (rect , brush .brush_color )
237-
238- # If the brush is a circle shape
239- elif brush .brush_type == BRUSH_MODES .circle_shape :
240- # We simply draw a circle using stored in brush
241- draw_circle (brush .brush_pos , brush .brush_shape_circle_radius , brush .brush_color )
230+ BrushModes .CIRCLE_SHAPE :
231+ # We simply draw a circle using stored in brush.
232+ draw_circle (brush .brush_pos , brush .brush_shape_circle_radius , brush .brush_color )
242233
243234
244235
245236func save_picture (path ):
246- # Wait a couple frames so the save dialog isn't in the way
237+ # Wait a couple frames so the save dialog isn't in the way.
247238 yield (get_tree (), "idle_frame" )
248239 yield (get_tree (), "idle_frame" )
249240
250- # Get the viewport image
241+ # Get the viewport image.
251242 var img = get_viewport ().get_texture ().get_data ()
252243 # Crop the image so we only have canvas area.
253244 var cropped_image = img .get_rect (Rect2 (TL_node .global_position , IMAGE_SIZE ))
254- # Flip the image on the Y-axis (it's flipped upside down by default)
245+ # Flip the image on the Y-axis (it's flipped upside down by default).
255246 cropped_image .flip_y ()
256247
257- # Save the image with the passed in path we got from the save dialog
248+ # Save the image with the passed in path we got from the save dialog.
258249 cropped_image .save_png (path )
259-
0 commit comments