From 24d1de96b1c1c1c889a204229338723bfaafd5a0 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Tue, 1 Mar 2022 23:03:00 +0500 Subject: [PATCH 1/6] add limit change with brush --- BaseTool.gd | 145 ++++++++++++++ Draw.gd | 567 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 712 insertions(+) create mode 100644 BaseTool.gd create mode 100644 Draw.gd diff --git a/BaseTool.gd b/BaseTool.gd new file mode 100644 index 000000000000..825c0aa953b0 --- /dev/null +++ b/BaseTool.gd @@ -0,0 +1,145 @@ +class_name BaseTool +extends VBoxContainer + +var is_moving = false +var kname: String +var tool_slot = null # Tools.Slot, can't have static typing due to cyclic errors +var cursor_text := "" + +var _cursor := Vector2.INF + +var _draw_cache: PoolVector2Array = [] # for storing already drawn pixels + + +func _ready() -> void: + kname = name.replace(" ", "_").to_lower() + $Label.text = tool_slot.name + + load_config() + + +func save_config() -> void: + var config := get_config() + Global.config_cache.set_value(tool_slot.kname, kname, config) + + +func load_config() -> void: + var value = Global.config_cache.get_value(tool_slot.kname, kname, {}) + set_config(value) + update_config() + + +func get_config() -> Dictionary: + return {} + + +func set_config(_config: Dictionary) -> void: + pass + + +func update_config() -> void: + pass + + +func draw_start(_position: Vector2) -> void: + _draw_cache = [] + is_moving = true + + +func draw_move(position: Vector2) -> void: + # This can happen if the user switches between tools with a shortcut + # while using another tool + if !is_moving: + draw_start(position) + + +func draw_end(_position: Vector2) -> void: + is_moving = false + _draw_cache = [] + + +func cursor_move(position: Vector2) -> void: + _cursor = position + + +func draw_indicator() -> void: + var rect := Rect2(_cursor, Vector2.ONE) + Global.canvas.indicators.draw_rect(rect, Color.blue, false) + + +func draw_preview() -> void: + pass + + +func _get_draw_rect() -> Rect2: + if Global.current_project.has_selection: + return Global.current_project.get_selection_rectangle() + else: + return Global.current_project.tile_mode_rects[Global.TileMode.NONE] + + +func _get_draw_image() -> Image: + var project: Project = Global.current_project + return project.frames[project.current_frame].cels[project.current_layer].image + + +func _get_selected_draw_images() -> Array: # Array of Images + var images := [] + var project: Project = Global.current_project + for cel_index in project.selected_cels: + var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]] + if project.layers[cel_index[1]].can_layer_get_drawn(): + images.append(cel.image) + return images + + +func _flip_rect(rect: Rect2, size: Vector2, horizontal: bool, vertical: bool) -> Rect2: + var result := rect + if horizontal: + result.position.x = size.x - rect.end.x + result.end.x = size.x - rect.position.x + if vertical: + result.position.y = size.y - rect.end.y + result.end.y = size.y - rect.position.y + return result.abs() + + +func _create_polylines(bitmap: BitMap) -> Array: + var lines := [] + var size := bitmap.get_size() + for y in size.y: + for x in size.x: + var p := Vector2(x, y) + if not bitmap.get_bit(p): + continue + if x <= 0 or not bitmap.get_bit(p - Vector2(1, 0)): + _add_polylines_segment(lines, p, p + Vector2(0, 1)) + if y <= 0 or not bitmap.get_bit(p - Vector2(0, 1)): + _add_polylines_segment(lines, p, p + Vector2(1, 0)) + if x + 1 >= size.x or not bitmap.get_bit(p + Vector2(1, 0)): + _add_polylines_segment(lines, p + Vector2(1, 0), p + Vector2(1, 1)) + if y + 1 >= size.y or not bitmap.get_bit(p + Vector2(0, 1)): + _add_polylines_segment(lines, p + Vector2(0, 1), p + Vector2(1, 1)) + return lines + + +func _add_polylines_segment(lines: Array, start: Vector2, end: Vector2) -> void: + for line in lines: + if line[0] == start: + line.insert(0, end) + return + if line[0] == end: + line.insert(0, start) + return + if line[line.size() - 1] == start: + line.append(end) + return + if line[line.size() - 1] == end: + line.append(start) + return + lines.append([start, end]) + + +func _exit_tree() -> void: + if is_moving: + draw_end(Global.canvas.current_pixel.floor()) diff --git a/Draw.gd b/Draw.gd new file mode 100644 index 000000000000..6bca917e21d4 --- /dev/null +++ b/Draw.gd @@ -0,0 +1,567 @@ +extends BaseTool + +var _brush := Brushes.get_default_brush() +var _brush_size := 1 +var _brush_interpolate := 0 +var _brush_image := Image.new() +var _brush_texture := ImageTexture.new() +var _strength := 1.0 +var _picking_color := false + +var _undo_data := {} +var _drawer := Drawer.new() +var _mask := PoolByteArray() +var _mirror_brushes := {} + +var _draw_line := false +var _line_start := Vector2.ZERO +var _line_end := Vector2.ZERO + +var _indicator := BitMap.new() +var _polylines := [] +var _line_polylines := [] + + +func _ready() -> void: + Tools.connect("color_changed", self, "_on_Color_changed") + Global.brushes_popup.connect("brush_removed", self, "_on_Brush_removed") + + +func _on_BrushType_pressed() -> void: + if not Global.brushes_popup.is_connected("brush_selected", self, "_on_Brush_selected"): + Global.brushes_popup.connect( + "brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT + ) + Global.brushes_popup.popup(Rect2($Brush/Type.rect_global_position, Vector2(226, 72))) + + +func _on_Brush_selected(brush: Brushes.Brush) -> void: + _brush = brush + update_brush() + save_config() + + +func _on_BrushSize_value_changed(value: float) -> void: + _brush_size = int(value) + update_config() + save_config() + + +func _on_InterpolateFactor_value_changed(value: float) -> void: + _brush_interpolate = int(value) + update_config() + save_config() + + +func _on_Color_changed(_color: Color, _button: int) -> void: + update_brush() + + +func _on_Brush_removed(brush: Brushes.Brush) -> void: + if brush == _brush: + _brush = Brushes.get_default_brush() + update_brush() + save_config() + + +func get_config() -> Dictionary: + return { + "brush_type": _brush.type, + "brush_index": _brush.index, + "brush_size": _brush_size, + "brush_interpolate": _brush_interpolate, + } + + +func set_config(config: Dictionary) -> void: + var type = config.get("brush_type", _brush.type) + var index = config.get("brush_index", _brush.index) + _brush = Global.brushes_popup.get_brush(type, index) + _brush_size = config.get("brush_size", _brush_size) + _brush_interpolate = config.get("brush_interpolate", _brush_interpolate) + + +func update_config() -> void: + $Brush/Size.value = _brush_size + $BrushSize.value = _brush_size + $ColorInterpolation/Factor.value = _brush_interpolate + $ColorInterpolation/Slider.value = _brush_interpolate + update_brush() + + +func update_brush() -> void: + match _brush.type: + Brushes.PIXEL: + _brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0) + Brushes.CIRCLE: + _brush_texture.create_from_image(load("res://assets/graphics/circle_9x9.png"), 0) + Brushes.FILLED_CIRCLE: + _brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0) + Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM: + if _brush.random.size() <= 1: + _brush_image = _create_blended_brush_image(_brush.image) + else: + var random = randi() % _brush.random.size() + _brush_image = _create_blended_brush_image(_brush.random[random]) + _brush_texture.create_from_image(_brush_image, 0) + update_mirror_brush() + _indicator = _create_brush_indicator() + _polylines = _create_polylines(_indicator) + $Brush/Type/Texture.texture = _brush_texture + $ColorInterpolation.visible = _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM] + + +func update_random_image() -> void: + if _brush.type != Brushes.RANDOM_FILE: + return + var random = randi() % _brush.random.size() + _brush_image = _create_blended_brush_image(_brush.random[random]) + _brush_texture.create_from_image(_brush_image, 0) + _indicator = _create_brush_indicator() + update_mirror_brush() + + +func update_mirror_brush() -> void: + _mirror_brushes.x = _brush_image.duplicate() + _mirror_brushes.x.flip_x() + _mirror_brushes.y = _brush_image.duplicate() + _mirror_brushes.y.flip_y() + _mirror_brushes.xy = _mirror_brushes.x.duplicate() + _mirror_brushes.xy.flip_y() + + +func update_mask(can_skip := true) -> void: + if can_skip and Global.pressure_sensitivity_mode == Global.PressureSensitivity.NONE: + if _mask: + _mask = PoolByteArray() + return + var size: Vector2 = Global.current_project.size + # Faster than zeroing PoolByteArray directly. + # See: https://github.com/Orama-Interactive/Pixelorama/pull/439 + var nulled_array := [] + nulled_array.resize(size.x * size.y) + _mask = PoolByteArray(nulled_array) + + +func update_line_polylines(start: Vector2, end: Vector2) -> void: + var indicator := _create_line_indicator(_indicator, start, end) + _line_polylines = _create_polylines(indicator) + + +func prepare_undo(action: String) -> void: + var project: Project = Global.current_project + _undo_data = _get_undo_data() + project.undo_redo.create_action(action) + + +func commit_undo() -> void: + var redo_data := _get_undo_data() + var project: Project = Global.current_project + var frame := -1 + var layer := -1 + if Global.animation_timer.is_stopped() and project.selected_cels.size() == 1: + frame = project.current_frame + layer = project.current_layer + + project.undos += 1 + for image in redo_data: + project.undo_redo.add_do_property(image, "data", redo_data[image]) + image.unlock() + for image in _undo_data: + project.undo_redo.add_undo_property(image, "data", _undo_data[image]) + project.undo_redo.add_do_method(Global, "undo_or_redo", false, frame, layer) + project.undo_redo.add_undo_method(Global, "undo_or_redo", true, frame, layer) + project.undo_redo.commit_action() + + _undo_data.clear() + + +func draw_tool(position: Vector2) -> void: + if !Global.current_project.layers[Global.current_project.current_layer].can_layer_get_drawn(): + return + var strength := _strength + if Global.pressure_sensitivity_mode == Global.PressureSensitivity.ALPHA: + strength *= Tools.pen_pressure + + _drawer.pixel_perfect = Tools.pixel_perfect if _brush_size == 1 else false + _drawer.horizontal_mirror = Tools.horizontal_mirror + _drawer.vertical_mirror = Tools.vertical_mirror + _drawer.color_op.strength = strength + + match _brush.type: + Brushes.PIXEL: + draw_tool_pixel(position) + Brushes.CIRCLE: + draw_tool_circle(position, false) + Brushes.FILLED_CIRCLE: + draw_tool_circle(position, true) + _: + draw_tool_brush(position) + + +# Bresenham's Algorithm +# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency +func draw_fill_gap(start: Vector2, end: Vector2) -> void: + var dx := int(abs(end.x - start.x)) + var dy := int(-abs(end.y - start.y)) + var err := dx + dy + var e2 := err << 1 + var sx = 1 if start.x < end.x else -1 + var sy = 1 if start.y < end.y else -1 + var x = start.x + var y = start.y + while !(x == end.x && y == end.y): + e2 = err << 1 + if e2 >= dy: + err += dy + x += sx + if e2 <= dx: + err += dx + y += sy + draw_tool(Vector2(x, y)) + + +func draw_tool_pixel(position: Vector2) -> void: + var start := position - Vector2.ONE * (_brush_size >> 1) + var end := start + Vector2.ONE * _brush_size + for y in range(start.y, end.y): + for x in range(start.x, end.x): + _set_pixel(Vector2(x, y)) + + +# Algorithm based on http://members.chello.at/easyfilter/bresenham.html +func draw_tool_circle(position: Vector2, fill := false) -> void: + var r := _brush_size + var x := -r + var y := 0 + var err := 2 - r * 2 + var draw := true + if fill: + _set_pixel(position) + while x < 0: + if draw: + for i in range(1 if fill else -x, -x + 1): + _set_pixel(position + Vector2(-i, y)) + _set_pixel(position + Vector2(-y, -i)) + _set_pixel(position + Vector2(i, -y)) + _set_pixel(position + Vector2(y, i)) + draw = not fill + r = err + if r <= y: + y += 1 + err += y * 2 + 1 + draw = true + if r > x || err > y: + x += 1 + err += x * 2 + 1 + + +func draw_tool_brush(position: Vector2) -> void: + var project: Project = Global.current_project + + if project.tile_mode and project.get_tile_mode_rect().has_point(position): + position = position.posmodv(project.size) + + var size := _brush_image.get_size() + var dst := position - (size / 2).floor() + var dst_rect := Rect2(dst, size) + var draw_rect := _get_draw_rect() + dst_rect = dst_rect.clip(draw_rect) + if dst_rect.size == Vector2.ZERO: + return + var src_rect := Rect2(dst_rect.position - dst, dst_rect.size) + dst = dst_rect.position + var brush_image: Image = remove_unselected_parts_of_brush(_brush_image, dst) + _draw_brush_image(brush_image, src_rect, dst) + + # Handle Mirroring + var mirror_x = (project.x_symmetry_point + 1) - dst.x - src_rect.size.x + var mirror_y = (project.y_symmetry_point + 1) - dst.y - src_rect.size.y + + if Tools.horizontal_mirror: + var x_dst := Vector2(mirror_x, dst.y) + var mirror_brush_x: Image = remove_unselected_parts_of_brush(_mirror_brushes.x, x_dst) + _draw_brush_image(mirror_brush_x, _flip_rect(src_rect, size, true, false), x_dst) + if Tools.vertical_mirror: + var xy_dst := Vector2(mirror_x, mirror_y) + var mirror_brush_xy: Image = remove_unselected_parts_of_brush( + _mirror_brushes.xy, xy_dst + ) + _draw_brush_image(mirror_brush_xy, _flip_rect(src_rect, size, true, true), xy_dst) + if Tools.vertical_mirror: + var y_dst := Vector2(dst.x, mirror_y) + var mirror_brush_y: Image = remove_unselected_parts_of_brush(_mirror_brushes.y, y_dst) + _draw_brush_image(mirror_brush_y, _flip_rect(src_rect, size, false, true), y_dst) + + +func remove_unselected_parts_of_brush(brush: Image, dst: Vector2) -> Image: + var project: Project = Global.current_project + if !project.has_selection: + return brush + var size := brush.get_size() + var new_brush := Image.new() + new_brush.copy_from(brush) + + new_brush.lock() + for x in size.x: + for y in size.y: + var pos := Vector2(x, y) + dst + if !project.selection_bitmap.get_bit(pos): + new_brush.set_pixel(x, y, Color(0)) + new_brush.unlock() + return new_brush + + +func draw_indicator() -> void: + draw_indicator_at(_cursor, Vector2.ZERO, Color.blue) + if ( + Global.current_project.tile_mode + and Global.current_project.get_tile_mode_rect().has_point(_cursor) + ): + var tile := _line_start if _draw_line else _cursor + if not Global.current_project.tile_mode_rects[Global.TileMode.NONE].has_point(tile): + var offset := tile - tile.posmodv(Global.current_project.size) + draw_indicator_at(_cursor, offset, Color.green) + + +func draw_indicator_at(position: Vector2, offset: Vector2, color: Color) -> void: + var canvas = Global.canvas.indicators + if _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM] and not _draw_line: + position -= (_brush_image.get_size() / 2).floor() + position -= offset + canvas.draw_texture(_brush_texture, position) + else: + if _draw_line: + position.x = _line_end.x if _line_end.x < _line_start.x else _line_start.x + position.y = _line_end.y if _line_end.y < _line_start.y else _line_start.y + position -= (_indicator.get_size() / 2).floor() + position -= offset + canvas.draw_set_transform(position, canvas.rotation, canvas.scale) + var polylines := _line_polylines if _draw_line else _polylines + for line in polylines: + var pool := PoolVector2Array(line) + canvas.draw_polyline(pool, color) + canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale) + + +func _set_pixel(position: Vector2, ignore_mirroring := false) -> void: + if position in _draw_cache: + return + var cache_limit: int = (_brush_size * _brush_size) * 3 # This equation seems the best match + if _draw_cache.size() > cache_limit: + _draw_cache = [] + _draw_cache.append(position) # Store the position of pixel + + var project: Project = Global.current_project + if project.tile_mode and project.get_tile_mode_rect().has_point(position): + position = position.posmodv(project.size) + + if !project.can_pixel_get_drawn(position): + return + + var images := _get_selected_draw_images() + var i := int(position.x + position.y * project.size.x) + if _mask.size() >= i + 1: + if _mask[i] < Tools.pen_pressure: + _mask[i] = Tools.pen_pressure + for image in images: + _drawer.set_pixel(image, position, tool_slot.color, ignore_mirroring) + else: + for image in images: + _drawer.set_pixel(image, position, tool_slot.color, ignore_mirroring) + + +func _draw_brush_image(_image: Image, _src_rect: Rect2, _dst: Vector2) -> void: + pass + + +func _create_blended_brush_image(image: Image) -> Image: + var size := image.get_size() * _brush_size + var brush := Image.new() + brush.copy_from(image) + brush = _blend_image(brush, tool_slot.color, _brush_interpolate / 100.0) + brush.resize(size.x, size.y, Image.INTERPOLATE_NEAREST) + return brush + + +func _blend_image(image: Image, color: Color, factor: float) -> Image: + var size := image.get_size() + image.lock() + for y in size.y: + for x in size.x: + var color_old := image.get_pixel(x, y) + if color_old.a > 0: + var color_new := color_old.linear_interpolate(color, factor) + color_new.a = color_old.a + image.set_pixel(x, y, color_new) + image.unlock() + return image + + +func _create_brush_indicator() -> BitMap: + match _brush.type: + Brushes.PIXEL: + return _create_pixel_indicator(_brush_size) + Brushes.CIRCLE: + return _create_circle_indicator(_brush_size, false) + Brushes.FILLED_CIRCLE: + return _create_circle_indicator(_brush_size, true) + _: + return _create_image_indicator(_brush_image) + + +func _create_image_indicator(image: Image) -> BitMap: + var bitmap := BitMap.new() + bitmap.create_from_image_alpha(image, 0.0) + return bitmap + + +func _create_pixel_indicator(size: int) -> BitMap: + var bitmap := BitMap.new() + bitmap.create(Vector2.ONE * size) + bitmap.set_bit_rect(Rect2(Vector2.ZERO, Vector2.ONE * size), true) + return bitmap + + +func _create_circle_indicator(size: int, fill := false) -> BitMap: + var bitmap := BitMap.new() + bitmap.create(Vector2.ONE * (size * 2 + 1)) + var position := Vector2(size, size) + + var r := size + var x := -r + var y := 0 + var err := 2 - r * 2 + var draw := true + if fill: + bitmap.set_bit(position, true) + while x < 0: + if draw: + for i in range(1 if fill else -x, -x + 1): + bitmap.set_bit(position + Vector2(-i, y), true) + bitmap.set_bit(position + Vector2(-y, -i), true) + bitmap.set_bit(position + Vector2(i, -y), true) + bitmap.set_bit(position + Vector2(y, i), true) + draw = not fill + r = err + if r <= y: + y += 1 + err += y * 2 + 1 + draw = true + if r > x || err > y: + x += 1 + err += x * 2 + 1 + return bitmap + + +func _create_line_indicator(indicator: BitMap, start: Vector2, end: Vector2) -> BitMap: + var bitmap := BitMap.new() + var size := (end - start).abs() + indicator.get_size() + bitmap.create(size) + + var offset := (indicator.get_size() / 2).floor() + var diff := end - start + start.x = -diff.x if diff.x < 0 else 0.0 + end.x = 0.0 if diff.x < 0 else diff.x + start.y = -diff.y if diff.y < 0 else 0.0 + end.y = 0.0 if diff.y < 0 else diff.y + start += offset + end += offset + + var dx := int(abs(end.x - start.x)) + var dy := int(-abs(end.y - start.y)) + var err := dx + dy + var e2 := err << 1 + var sx = 1 if start.x < end.x else -1 + var sy = 1 if start.y < end.y else -1 + var x = start.x + var y = start.y + while !(x == end.x && y == end.y): + _blit_indicator(bitmap, indicator, Vector2(x, y)) + e2 = err << 1 + if e2 >= dy: + err += dy + x += sx + if e2 <= dx: + err += dx + y += sy + _blit_indicator(bitmap, indicator, Vector2(x, y)) + return bitmap + + +func _blit_indicator(dst: BitMap, indicator: BitMap, position: Vector2) -> void: + var rect := Rect2(Vector2.ZERO, dst.get_size()) + var size := indicator.get_size() + position -= (size / 2).floor() + for y in size.y: + for x in size.x: + var pos := Vector2(x, y) + var bit := indicator.get_bit(pos) + pos += position + if bit and rect.has_point(pos): + dst.set_bit(pos, bit) + + +func _line_angle_constraint(start: Vector2, end: Vector2) -> Dictionary: + var result := {} + var angle := rad2deg(end.angle_to_point(start)) + var distance := start.distance_to(end) + if Tools.control: + if Tools.pixel_perfect: + angle = stepify(angle, 22.5) + if step_decimals(angle) != 0: + var diff := end - start + var v := Vector2(2, 1) if abs(diff.x) > abs(diff.y) else Vector2(1, 2) + var p := diff.project(diff.sign() * v).abs().round() + var f := p.y if abs(diff.x) > abs(diff.y) else p.x + end = start + diff.sign() * v * f - diff.sign() + angle = rad2deg(atan2(sign(diff.y) * v.y, sign(diff.x) * v.x)) + else: + end = start + Vector2.RIGHT.rotated(deg2rad(angle)) * distance + else: + angle = stepify(angle, 15) + end = start + Vector2.RIGHT.rotated(deg2rad(angle)) * distance + angle *= -1 + angle += 360 if angle < 0 else 0 + result.text = str(stepify(angle, 0.01)) + "°" + result.position = end.round() + return result + + +func _get_undo_data() -> Dictionary: + var data := {} + var project: Project = Global.current_project + var cels := [] # Array of Cels + if Global.animation_timer.is_stopped(): + for cel_index in project.selected_cels: + cels.append(project.frames[cel_index[0]].cels[cel_index[1]]) + else: + for frame in project.frames: + var cel: Cel = frame.cels[project.current_layer] + cels.append(cel) + for cel in cels: + var image: Image = cel.image + image.unlock() + data[image] = image.data + image.lock() + return data + + +func _pick_color(position: Vector2) -> void: + var project: Project = Global.current_project + if project.tile_mode and project.get_tile_mode_rect().has_point(position): + position = position.posmodv(project.size) + + if position.x < 0 or position.y < 0: + return + + var image := Image.new() + image.copy_from(_get_draw_image()) + if position.x > image.get_width() - 1 or position.y > image.get_height() - 1: + return + + image.lock() + var color := image.get_pixelv(position) + image.unlock() + var button := BUTTON_LEFT if Tools._slots[BUTTON_LEFT].tool_node == self else BUTTON_RIGHT + Tools.assign_color(color, button, false) From a5aacfb8d4d724e7b260af8502d34784884aa994 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Tue, 1 Mar 2022 23:05:46 +0500 Subject: [PATCH 2/6] Delete Draw.gd --- Draw.gd | 567 -------------------------------------------------------- 1 file changed, 567 deletions(-) delete mode 100644 Draw.gd diff --git a/Draw.gd b/Draw.gd deleted file mode 100644 index 6bca917e21d4..000000000000 --- a/Draw.gd +++ /dev/null @@ -1,567 +0,0 @@ -extends BaseTool - -var _brush := Brushes.get_default_brush() -var _brush_size := 1 -var _brush_interpolate := 0 -var _brush_image := Image.new() -var _brush_texture := ImageTexture.new() -var _strength := 1.0 -var _picking_color := false - -var _undo_data := {} -var _drawer := Drawer.new() -var _mask := PoolByteArray() -var _mirror_brushes := {} - -var _draw_line := false -var _line_start := Vector2.ZERO -var _line_end := Vector2.ZERO - -var _indicator := BitMap.new() -var _polylines := [] -var _line_polylines := [] - - -func _ready() -> void: - Tools.connect("color_changed", self, "_on_Color_changed") - Global.brushes_popup.connect("brush_removed", self, "_on_Brush_removed") - - -func _on_BrushType_pressed() -> void: - if not Global.brushes_popup.is_connected("brush_selected", self, "_on_Brush_selected"): - Global.brushes_popup.connect( - "brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT - ) - Global.brushes_popup.popup(Rect2($Brush/Type.rect_global_position, Vector2(226, 72))) - - -func _on_Brush_selected(brush: Brushes.Brush) -> void: - _brush = brush - update_brush() - save_config() - - -func _on_BrushSize_value_changed(value: float) -> void: - _brush_size = int(value) - update_config() - save_config() - - -func _on_InterpolateFactor_value_changed(value: float) -> void: - _brush_interpolate = int(value) - update_config() - save_config() - - -func _on_Color_changed(_color: Color, _button: int) -> void: - update_brush() - - -func _on_Brush_removed(brush: Brushes.Brush) -> void: - if brush == _brush: - _brush = Brushes.get_default_brush() - update_brush() - save_config() - - -func get_config() -> Dictionary: - return { - "brush_type": _brush.type, - "brush_index": _brush.index, - "brush_size": _brush_size, - "brush_interpolate": _brush_interpolate, - } - - -func set_config(config: Dictionary) -> void: - var type = config.get("brush_type", _brush.type) - var index = config.get("brush_index", _brush.index) - _brush = Global.brushes_popup.get_brush(type, index) - _brush_size = config.get("brush_size", _brush_size) - _brush_interpolate = config.get("brush_interpolate", _brush_interpolate) - - -func update_config() -> void: - $Brush/Size.value = _brush_size - $BrushSize.value = _brush_size - $ColorInterpolation/Factor.value = _brush_interpolate - $ColorInterpolation/Slider.value = _brush_interpolate - update_brush() - - -func update_brush() -> void: - match _brush.type: - Brushes.PIXEL: - _brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0) - Brushes.CIRCLE: - _brush_texture.create_from_image(load("res://assets/graphics/circle_9x9.png"), 0) - Brushes.FILLED_CIRCLE: - _brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0) - Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM: - if _brush.random.size() <= 1: - _brush_image = _create_blended_brush_image(_brush.image) - else: - var random = randi() % _brush.random.size() - _brush_image = _create_blended_brush_image(_brush.random[random]) - _brush_texture.create_from_image(_brush_image, 0) - update_mirror_brush() - _indicator = _create_brush_indicator() - _polylines = _create_polylines(_indicator) - $Brush/Type/Texture.texture = _brush_texture - $ColorInterpolation.visible = _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM] - - -func update_random_image() -> void: - if _brush.type != Brushes.RANDOM_FILE: - return - var random = randi() % _brush.random.size() - _brush_image = _create_blended_brush_image(_brush.random[random]) - _brush_texture.create_from_image(_brush_image, 0) - _indicator = _create_brush_indicator() - update_mirror_brush() - - -func update_mirror_brush() -> void: - _mirror_brushes.x = _brush_image.duplicate() - _mirror_brushes.x.flip_x() - _mirror_brushes.y = _brush_image.duplicate() - _mirror_brushes.y.flip_y() - _mirror_brushes.xy = _mirror_brushes.x.duplicate() - _mirror_brushes.xy.flip_y() - - -func update_mask(can_skip := true) -> void: - if can_skip and Global.pressure_sensitivity_mode == Global.PressureSensitivity.NONE: - if _mask: - _mask = PoolByteArray() - return - var size: Vector2 = Global.current_project.size - # Faster than zeroing PoolByteArray directly. - # See: https://github.com/Orama-Interactive/Pixelorama/pull/439 - var nulled_array := [] - nulled_array.resize(size.x * size.y) - _mask = PoolByteArray(nulled_array) - - -func update_line_polylines(start: Vector2, end: Vector2) -> void: - var indicator := _create_line_indicator(_indicator, start, end) - _line_polylines = _create_polylines(indicator) - - -func prepare_undo(action: String) -> void: - var project: Project = Global.current_project - _undo_data = _get_undo_data() - project.undo_redo.create_action(action) - - -func commit_undo() -> void: - var redo_data := _get_undo_data() - var project: Project = Global.current_project - var frame := -1 - var layer := -1 - if Global.animation_timer.is_stopped() and project.selected_cels.size() == 1: - frame = project.current_frame - layer = project.current_layer - - project.undos += 1 - for image in redo_data: - project.undo_redo.add_do_property(image, "data", redo_data[image]) - image.unlock() - for image in _undo_data: - project.undo_redo.add_undo_property(image, "data", _undo_data[image]) - project.undo_redo.add_do_method(Global, "undo_or_redo", false, frame, layer) - project.undo_redo.add_undo_method(Global, "undo_or_redo", true, frame, layer) - project.undo_redo.commit_action() - - _undo_data.clear() - - -func draw_tool(position: Vector2) -> void: - if !Global.current_project.layers[Global.current_project.current_layer].can_layer_get_drawn(): - return - var strength := _strength - if Global.pressure_sensitivity_mode == Global.PressureSensitivity.ALPHA: - strength *= Tools.pen_pressure - - _drawer.pixel_perfect = Tools.pixel_perfect if _brush_size == 1 else false - _drawer.horizontal_mirror = Tools.horizontal_mirror - _drawer.vertical_mirror = Tools.vertical_mirror - _drawer.color_op.strength = strength - - match _brush.type: - Brushes.PIXEL: - draw_tool_pixel(position) - Brushes.CIRCLE: - draw_tool_circle(position, false) - Brushes.FILLED_CIRCLE: - draw_tool_circle(position, true) - _: - draw_tool_brush(position) - - -# Bresenham's Algorithm -# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency -func draw_fill_gap(start: Vector2, end: Vector2) -> void: - var dx := int(abs(end.x - start.x)) - var dy := int(-abs(end.y - start.y)) - var err := dx + dy - var e2 := err << 1 - var sx = 1 if start.x < end.x else -1 - var sy = 1 if start.y < end.y else -1 - var x = start.x - var y = start.y - while !(x == end.x && y == end.y): - e2 = err << 1 - if e2 >= dy: - err += dy - x += sx - if e2 <= dx: - err += dx - y += sy - draw_tool(Vector2(x, y)) - - -func draw_tool_pixel(position: Vector2) -> void: - var start := position - Vector2.ONE * (_brush_size >> 1) - var end := start + Vector2.ONE * _brush_size - for y in range(start.y, end.y): - for x in range(start.x, end.x): - _set_pixel(Vector2(x, y)) - - -# Algorithm based on http://members.chello.at/easyfilter/bresenham.html -func draw_tool_circle(position: Vector2, fill := false) -> void: - var r := _brush_size - var x := -r - var y := 0 - var err := 2 - r * 2 - var draw := true - if fill: - _set_pixel(position) - while x < 0: - if draw: - for i in range(1 if fill else -x, -x + 1): - _set_pixel(position + Vector2(-i, y)) - _set_pixel(position + Vector2(-y, -i)) - _set_pixel(position + Vector2(i, -y)) - _set_pixel(position + Vector2(y, i)) - draw = not fill - r = err - if r <= y: - y += 1 - err += y * 2 + 1 - draw = true - if r > x || err > y: - x += 1 - err += x * 2 + 1 - - -func draw_tool_brush(position: Vector2) -> void: - var project: Project = Global.current_project - - if project.tile_mode and project.get_tile_mode_rect().has_point(position): - position = position.posmodv(project.size) - - var size := _brush_image.get_size() - var dst := position - (size / 2).floor() - var dst_rect := Rect2(dst, size) - var draw_rect := _get_draw_rect() - dst_rect = dst_rect.clip(draw_rect) - if dst_rect.size == Vector2.ZERO: - return - var src_rect := Rect2(dst_rect.position - dst, dst_rect.size) - dst = dst_rect.position - var brush_image: Image = remove_unselected_parts_of_brush(_brush_image, dst) - _draw_brush_image(brush_image, src_rect, dst) - - # Handle Mirroring - var mirror_x = (project.x_symmetry_point + 1) - dst.x - src_rect.size.x - var mirror_y = (project.y_symmetry_point + 1) - dst.y - src_rect.size.y - - if Tools.horizontal_mirror: - var x_dst := Vector2(mirror_x, dst.y) - var mirror_brush_x: Image = remove_unselected_parts_of_brush(_mirror_brushes.x, x_dst) - _draw_brush_image(mirror_brush_x, _flip_rect(src_rect, size, true, false), x_dst) - if Tools.vertical_mirror: - var xy_dst := Vector2(mirror_x, mirror_y) - var mirror_brush_xy: Image = remove_unselected_parts_of_brush( - _mirror_brushes.xy, xy_dst - ) - _draw_brush_image(mirror_brush_xy, _flip_rect(src_rect, size, true, true), xy_dst) - if Tools.vertical_mirror: - var y_dst := Vector2(dst.x, mirror_y) - var mirror_brush_y: Image = remove_unselected_parts_of_brush(_mirror_brushes.y, y_dst) - _draw_brush_image(mirror_brush_y, _flip_rect(src_rect, size, false, true), y_dst) - - -func remove_unselected_parts_of_brush(brush: Image, dst: Vector2) -> Image: - var project: Project = Global.current_project - if !project.has_selection: - return brush - var size := brush.get_size() - var new_brush := Image.new() - new_brush.copy_from(brush) - - new_brush.lock() - for x in size.x: - for y in size.y: - var pos := Vector2(x, y) + dst - if !project.selection_bitmap.get_bit(pos): - new_brush.set_pixel(x, y, Color(0)) - new_brush.unlock() - return new_brush - - -func draw_indicator() -> void: - draw_indicator_at(_cursor, Vector2.ZERO, Color.blue) - if ( - Global.current_project.tile_mode - and Global.current_project.get_tile_mode_rect().has_point(_cursor) - ): - var tile := _line_start if _draw_line else _cursor - if not Global.current_project.tile_mode_rects[Global.TileMode.NONE].has_point(tile): - var offset := tile - tile.posmodv(Global.current_project.size) - draw_indicator_at(_cursor, offset, Color.green) - - -func draw_indicator_at(position: Vector2, offset: Vector2, color: Color) -> void: - var canvas = Global.canvas.indicators - if _brush.type in [Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM] and not _draw_line: - position -= (_brush_image.get_size() / 2).floor() - position -= offset - canvas.draw_texture(_brush_texture, position) - else: - if _draw_line: - position.x = _line_end.x if _line_end.x < _line_start.x else _line_start.x - position.y = _line_end.y if _line_end.y < _line_start.y else _line_start.y - position -= (_indicator.get_size() / 2).floor() - position -= offset - canvas.draw_set_transform(position, canvas.rotation, canvas.scale) - var polylines := _line_polylines if _draw_line else _polylines - for line in polylines: - var pool := PoolVector2Array(line) - canvas.draw_polyline(pool, color) - canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale) - - -func _set_pixel(position: Vector2, ignore_mirroring := false) -> void: - if position in _draw_cache: - return - var cache_limit: int = (_brush_size * _brush_size) * 3 # This equation seems the best match - if _draw_cache.size() > cache_limit: - _draw_cache = [] - _draw_cache.append(position) # Store the position of pixel - - var project: Project = Global.current_project - if project.tile_mode and project.get_tile_mode_rect().has_point(position): - position = position.posmodv(project.size) - - if !project.can_pixel_get_drawn(position): - return - - var images := _get_selected_draw_images() - var i := int(position.x + position.y * project.size.x) - if _mask.size() >= i + 1: - if _mask[i] < Tools.pen_pressure: - _mask[i] = Tools.pen_pressure - for image in images: - _drawer.set_pixel(image, position, tool_slot.color, ignore_mirroring) - else: - for image in images: - _drawer.set_pixel(image, position, tool_slot.color, ignore_mirroring) - - -func _draw_brush_image(_image: Image, _src_rect: Rect2, _dst: Vector2) -> void: - pass - - -func _create_blended_brush_image(image: Image) -> Image: - var size := image.get_size() * _brush_size - var brush := Image.new() - brush.copy_from(image) - brush = _blend_image(brush, tool_slot.color, _brush_interpolate / 100.0) - brush.resize(size.x, size.y, Image.INTERPOLATE_NEAREST) - return brush - - -func _blend_image(image: Image, color: Color, factor: float) -> Image: - var size := image.get_size() - image.lock() - for y in size.y: - for x in size.x: - var color_old := image.get_pixel(x, y) - if color_old.a > 0: - var color_new := color_old.linear_interpolate(color, factor) - color_new.a = color_old.a - image.set_pixel(x, y, color_new) - image.unlock() - return image - - -func _create_brush_indicator() -> BitMap: - match _brush.type: - Brushes.PIXEL: - return _create_pixel_indicator(_brush_size) - Brushes.CIRCLE: - return _create_circle_indicator(_brush_size, false) - Brushes.FILLED_CIRCLE: - return _create_circle_indicator(_brush_size, true) - _: - return _create_image_indicator(_brush_image) - - -func _create_image_indicator(image: Image) -> BitMap: - var bitmap := BitMap.new() - bitmap.create_from_image_alpha(image, 0.0) - return bitmap - - -func _create_pixel_indicator(size: int) -> BitMap: - var bitmap := BitMap.new() - bitmap.create(Vector2.ONE * size) - bitmap.set_bit_rect(Rect2(Vector2.ZERO, Vector2.ONE * size), true) - return bitmap - - -func _create_circle_indicator(size: int, fill := false) -> BitMap: - var bitmap := BitMap.new() - bitmap.create(Vector2.ONE * (size * 2 + 1)) - var position := Vector2(size, size) - - var r := size - var x := -r - var y := 0 - var err := 2 - r * 2 - var draw := true - if fill: - bitmap.set_bit(position, true) - while x < 0: - if draw: - for i in range(1 if fill else -x, -x + 1): - bitmap.set_bit(position + Vector2(-i, y), true) - bitmap.set_bit(position + Vector2(-y, -i), true) - bitmap.set_bit(position + Vector2(i, -y), true) - bitmap.set_bit(position + Vector2(y, i), true) - draw = not fill - r = err - if r <= y: - y += 1 - err += y * 2 + 1 - draw = true - if r > x || err > y: - x += 1 - err += x * 2 + 1 - return bitmap - - -func _create_line_indicator(indicator: BitMap, start: Vector2, end: Vector2) -> BitMap: - var bitmap := BitMap.new() - var size := (end - start).abs() + indicator.get_size() - bitmap.create(size) - - var offset := (indicator.get_size() / 2).floor() - var diff := end - start - start.x = -diff.x if diff.x < 0 else 0.0 - end.x = 0.0 if diff.x < 0 else diff.x - start.y = -diff.y if diff.y < 0 else 0.0 - end.y = 0.0 if diff.y < 0 else diff.y - start += offset - end += offset - - var dx := int(abs(end.x - start.x)) - var dy := int(-abs(end.y - start.y)) - var err := dx + dy - var e2 := err << 1 - var sx = 1 if start.x < end.x else -1 - var sy = 1 if start.y < end.y else -1 - var x = start.x - var y = start.y - while !(x == end.x && y == end.y): - _blit_indicator(bitmap, indicator, Vector2(x, y)) - e2 = err << 1 - if e2 >= dy: - err += dy - x += sx - if e2 <= dx: - err += dx - y += sy - _blit_indicator(bitmap, indicator, Vector2(x, y)) - return bitmap - - -func _blit_indicator(dst: BitMap, indicator: BitMap, position: Vector2) -> void: - var rect := Rect2(Vector2.ZERO, dst.get_size()) - var size := indicator.get_size() - position -= (size / 2).floor() - for y in size.y: - for x in size.x: - var pos := Vector2(x, y) - var bit := indicator.get_bit(pos) - pos += position - if bit and rect.has_point(pos): - dst.set_bit(pos, bit) - - -func _line_angle_constraint(start: Vector2, end: Vector2) -> Dictionary: - var result := {} - var angle := rad2deg(end.angle_to_point(start)) - var distance := start.distance_to(end) - if Tools.control: - if Tools.pixel_perfect: - angle = stepify(angle, 22.5) - if step_decimals(angle) != 0: - var diff := end - start - var v := Vector2(2, 1) if abs(diff.x) > abs(diff.y) else Vector2(1, 2) - var p := diff.project(diff.sign() * v).abs().round() - var f := p.y if abs(diff.x) > abs(diff.y) else p.x - end = start + diff.sign() * v * f - diff.sign() - angle = rad2deg(atan2(sign(diff.y) * v.y, sign(diff.x) * v.x)) - else: - end = start + Vector2.RIGHT.rotated(deg2rad(angle)) * distance - else: - angle = stepify(angle, 15) - end = start + Vector2.RIGHT.rotated(deg2rad(angle)) * distance - angle *= -1 - angle += 360 if angle < 0 else 0 - result.text = str(stepify(angle, 0.01)) + "°" - result.position = end.round() - return result - - -func _get_undo_data() -> Dictionary: - var data := {} - var project: Project = Global.current_project - var cels := [] # Array of Cels - if Global.animation_timer.is_stopped(): - for cel_index in project.selected_cels: - cels.append(project.frames[cel_index[0]].cels[cel_index[1]]) - else: - for frame in project.frames: - var cel: Cel = frame.cels[project.current_layer] - cels.append(cel) - for cel in cels: - var image: Image = cel.image - image.unlock() - data[image] = image.data - image.lock() - return data - - -func _pick_color(position: Vector2) -> void: - var project: Project = Global.current_project - if project.tile_mode and project.get_tile_mode_rect().has_point(position): - position = position.posmodv(project.size) - - if position.x < 0 or position.y < 0: - return - - var image := Image.new() - image.copy_from(_get_draw_image()) - if position.x > image.get_width() - 1 or position.y > image.get_height() - 1: - return - - image.lock() - var color := image.get_pixelv(position) - image.unlock() - var button := BUTTON_LEFT if Tools._slots[BUTTON_LEFT].tool_node == self else BUTTON_RIGHT - Tools.assign_color(color, button, false) From c6ce9223fbf2663a7767cd3e4b3bfdded23faa45 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Tue, 1 Mar 2022 23:06:01 +0500 Subject: [PATCH 3/6] Delete BaseTool.gd --- BaseTool.gd | 145 ---------------------------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 BaseTool.gd diff --git a/BaseTool.gd b/BaseTool.gd deleted file mode 100644 index 825c0aa953b0..000000000000 --- a/BaseTool.gd +++ /dev/null @@ -1,145 +0,0 @@ -class_name BaseTool -extends VBoxContainer - -var is_moving = false -var kname: String -var tool_slot = null # Tools.Slot, can't have static typing due to cyclic errors -var cursor_text := "" - -var _cursor := Vector2.INF - -var _draw_cache: PoolVector2Array = [] # for storing already drawn pixels - - -func _ready() -> void: - kname = name.replace(" ", "_").to_lower() - $Label.text = tool_slot.name - - load_config() - - -func save_config() -> void: - var config := get_config() - Global.config_cache.set_value(tool_slot.kname, kname, config) - - -func load_config() -> void: - var value = Global.config_cache.get_value(tool_slot.kname, kname, {}) - set_config(value) - update_config() - - -func get_config() -> Dictionary: - return {} - - -func set_config(_config: Dictionary) -> void: - pass - - -func update_config() -> void: - pass - - -func draw_start(_position: Vector2) -> void: - _draw_cache = [] - is_moving = true - - -func draw_move(position: Vector2) -> void: - # This can happen if the user switches between tools with a shortcut - # while using another tool - if !is_moving: - draw_start(position) - - -func draw_end(_position: Vector2) -> void: - is_moving = false - _draw_cache = [] - - -func cursor_move(position: Vector2) -> void: - _cursor = position - - -func draw_indicator() -> void: - var rect := Rect2(_cursor, Vector2.ONE) - Global.canvas.indicators.draw_rect(rect, Color.blue, false) - - -func draw_preview() -> void: - pass - - -func _get_draw_rect() -> Rect2: - if Global.current_project.has_selection: - return Global.current_project.get_selection_rectangle() - else: - return Global.current_project.tile_mode_rects[Global.TileMode.NONE] - - -func _get_draw_image() -> Image: - var project: Project = Global.current_project - return project.frames[project.current_frame].cels[project.current_layer].image - - -func _get_selected_draw_images() -> Array: # Array of Images - var images := [] - var project: Project = Global.current_project - for cel_index in project.selected_cels: - var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]] - if project.layers[cel_index[1]].can_layer_get_drawn(): - images.append(cel.image) - return images - - -func _flip_rect(rect: Rect2, size: Vector2, horizontal: bool, vertical: bool) -> Rect2: - var result := rect - if horizontal: - result.position.x = size.x - rect.end.x - result.end.x = size.x - rect.position.x - if vertical: - result.position.y = size.y - rect.end.y - result.end.y = size.y - rect.position.y - return result.abs() - - -func _create_polylines(bitmap: BitMap) -> Array: - var lines := [] - var size := bitmap.get_size() - for y in size.y: - for x in size.x: - var p := Vector2(x, y) - if not bitmap.get_bit(p): - continue - if x <= 0 or not bitmap.get_bit(p - Vector2(1, 0)): - _add_polylines_segment(lines, p, p + Vector2(0, 1)) - if y <= 0 or not bitmap.get_bit(p - Vector2(0, 1)): - _add_polylines_segment(lines, p, p + Vector2(1, 0)) - if x + 1 >= size.x or not bitmap.get_bit(p + Vector2(1, 0)): - _add_polylines_segment(lines, p + Vector2(1, 0), p + Vector2(1, 1)) - if y + 1 >= size.y or not bitmap.get_bit(p + Vector2(0, 1)): - _add_polylines_segment(lines, p + Vector2(0, 1), p + Vector2(1, 1)) - return lines - - -func _add_polylines_segment(lines: Array, start: Vector2, end: Vector2) -> void: - for line in lines: - if line[0] == start: - line.insert(0, end) - return - if line[0] == end: - line.insert(0, start) - return - if line[line.size() - 1] == start: - line.append(end) - return - if line[line.size() - 1] == end: - line.append(start) - return - lines.append([start, end]) - - -func _exit_tree() -> void: - if is_moving: - draw_end(Global.canvas.current_pixel.floor()) From 95f506b244654dca597cb6f6fb274773bd0e0699 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Sun, 17 Apr 2022 13:01:51 +0500 Subject: [PATCH 4/6] Some improvements 1) A Smarter Placement of "brushes_popup" 2) A Different Convention for image brushes (100 % instead of 1px) --- src/Tools/Draw.gd | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Tools/Draw.gd b/src/Tools/Draw.gd index c332c146556d..bcebcf01e19e 100644 --- a/src/Tools/Draw.gd +++ b/src/Tools/Draw.gd @@ -33,7 +33,20 @@ func _on_BrushType_pressed() -> void: Global.brushes_popup.connect( "brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT ) - Global.brushes_popup.popup(Rect2($Brush/Type.rect_global_position, Vector2(226, 72))) + # Now we set position and tab allignment considering certain conditions + var _size := Vector2(226, 72) + var _popup_position: Vector2 = $Brush/Type.rect_global_position + var _end_point: float = Global.shrink * (_popup_position.x + _size.x) - OS.get_screen_size().x + if _end_point <= 72 and _end_point > 0: # Some space left "Leftward" + _popup_position -= Vector2(_size.x/2.0 - 48, -32) + Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_CENTER + elif _end_point >= 72: # No space left "Leftward" + _popup_position -= Vector2(_size.x/2.0 + 16, -32) + Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_RIGHT + else: + _popup_position -= Vector2(0, -32) # Plenty of space left "Leftward" + Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_LEFT + Global.brushes_popup.popup(Rect2(_popup_position, _size)) func _on_Brush_selected(brush: Brushes.Brush) -> void: @@ -92,6 +105,7 @@ func update_config() -> void: func update_brush() -> void: + $Brush/Size.suffix = "px" # Assume we are using default brushes match _brush.type: Brushes.PIXEL: _brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0) @@ -100,6 +114,7 @@ func update_brush() -> void: Brushes.FILLED_CIRCLE: _brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0) Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM: + $Brush/Size.suffix = "00 %" # It's an image so a different size convention is used if _brush.random.size() <= 1: _brush_image = _create_blended_brush_image(_brush.image) else: From 6fe290f8275fdbda50e16dcc07ec9d11ad894f90 Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Sun, 17 Apr 2022 13:21:01 +0500 Subject: [PATCH 5/6] Formatting --- src/Tools/Draw.gd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Tools/Draw.gd b/src/Tools/Draw.gd index bcebcf01e19e..3ca781709eb6 100644 --- a/src/Tools/Draw.gd +++ b/src/Tools/Draw.gd @@ -34,14 +34,14 @@ func _on_BrushType_pressed() -> void: "brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT ) # Now we set position and tab allignment considering certain conditions - var _size := Vector2(226, 72) + var _size := Vector2(226, 72) var _popup_position: Vector2 = $Brush/Type.rect_global_position var _end_point: float = Global.shrink * (_popup_position.x + _size.x) - OS.get_screen_size().x if _end_point <= 72 and _end_point > 0: # Some space left "Leftward" - _popup_position -= Vector2(_size.x/2.0 - 48, -32) + _popup_position -= Vector2(_size.x / 2.0 - 48, -32) Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_CENTER - elif _end_point >= 72: # No space left "Leftward" - _popup_position -= Vector2(_size.x/2.0 + 16, -32) + elif _end_point >= 72: # No space left "Leftward" + _popup_position -= Vector2(_size.x / 2.0 + 16, -32) Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_RIGHT else: _popup_position -= Vector2(0, -32) # Plenty of space left "Leftward" @@ -105,7 +105,7 @@ func update_config() -> void: func update_brush() -> void: - $Brush/Size.suffix = "px" # Assume we are using default brushes + $Brush/Size.suffix = "px" # Assume we are using default brushes match _brush.type: Brushes.PIXEL: _brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0) @@ -114,7 +114,7 @@ func update_brush() -> void: Brushes.FILLED_CIRCLE: _brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0) Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM: - $Brush/Size.suffix = "00 %" # It's an image so a different size convention is used + $Brush/Size.suffix = "00 %" # It's an image so a different size convention is used if _brush.random.size() <= 1: _brush_image = _create_blended_brush_image(_brush.image) else: From cd222a9a0cdde144fae1aa90ea623955cc1092ee Mon Sep 17 00:00:00 2001 From: Variable <77773850+Variable-ind@users.noreply.github.com> Date: Sun, 17 Apr 2022 14:01:01 +0500 Subject: [PATCH 6/6] some more formatting --- src/Tools/Draw.gd | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Tools/Draw.gd b/src/Tools/Draw.gd index 3ca781709eb6..817453c5d658 100644 --- a/src/Tools/Draw.gd +++ b/src/Tools/Draw.gd @@ -34,19 +34,19 @@ func _on_BrushType_pressed() -> void: "brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT ) # Now we set position and tab allignment considering certain conditions - var _size := Vector2(226, 72) - var _popup_position: Vector2 = $Brush/Type.rect_global_position - var _end_point: float = Global.shrink * (_popup_position.x + _size.x) - OS.get_screen_size().x - if _end_point <= 72 and _end_point > 0: # Some space left "Leftward" - _popup_position -= Vector2(_size.x / 2.0 - 48, -32) + var pop_size := Vector2(226, 72) + var pop_position: Vector2 = $Brush/Type.rect_global_position + var off_limit: float = Global.shrink * (pop_position.x + pop_size.x) - OS.get_window_size().x + if off_limit <= 72 and off_limit > 0: # Some space left "Leftward" + pop_position -= Vector2(pop_size.x / 2.0 - 48, -32) Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_CENTER - elif _end_point >= 72: # No space left "Leftward" - _popup_position -= Vector2(_size.x / 2.0 + 16, -32) + elif off_limit >= 72: # No space left "Leftward" + pop_position -= Vector2(pop_size.x / 2.0 + 16, -32) Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_RIGHT else: - _popup_position -= Vector2(0, -32) # Plenty of space left "Leftward" + pop_position -= Vector2(0, -32) # Plenty of space left "Leftward" Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_LEFT - Global.brushes_popup.popup(Rect2(_popup_position, _size)) + Global.brushes_popup.popup(Rect2(pop_position, pop_size)) func _on_Brush_selected(brush: Brushes.Brush) -> void: