Skip to content

Commit ff10a80

Browse files
committed
Update GD Paint demo
1 parent 704ebee commit ff10a80

File tree

5 files changed

+242
-181
lines changed

5 files changed

+242
-181
lines changed

2d/gd_paint/PaintControl.gd

Lines changed: 94 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,143 @@
11
extends 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.
419
var TL_node
520

621
# A list to hold all of the dictionaries that make up each brush.
722
var 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.
1126
var is_mouse_in_drawing_area = false
1227
var last_mouse_pos = Vector2()
1328
var 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).
1833
var undo_set = false
1934
var 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
3638
var 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

4846
func _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

5452
func _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

104102
func 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

118116
func 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

201199
func _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

245236
func 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-

2d/gd_paint/PaintTools.png.import

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/PaintTools.png-636e86a6d210b52282c946752bbcc6f1.stex"
6+
metadata={
7+
"vram_texture": false
8+
}
9+
10+
[deps]
11+
12+
source_file="res://PaintTools.png"
13+
dest_files=[ "res://.import/PaintTools.png-636e86a6d210b52282c946752bbcc6f1.stex" ]
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/bptc_ldr=0
21+
compress/normal_map=0
22+
flags/repeat=0
23+
flags/filter=true
24+
flags/mipmaps=false
25+
flags/anisotropic=false
26+
flags/srgb=2
27+
process/fix_alpha_border=true
28+
process/premult_alpha=false
29+
process/HDR_as_SRGB=false
30+
process/invert_color=false
31+
stream=false
32+
size_limit=0
33+
detect_3d=true
34+
svg/scale=1.0

0 commit comments

Comments
 (0)