diff --git a/addons/graphics_editor/Brush.gd b/addons/graphics_editor/BrushPrefabs.gd similarity index 100% rename from addons/graphics_editor/Brush.gd rename to addons/graphics_editor/BrushPrefabs.gd diff --git a/addons/graphics_editor/Canvas.gd b/addons/graphics_editor/Canvas.gd index c51a9d4..ee1f9fe 100644 --- a/addons/graphics_editor/Canvas.gd +++ b/addons/graphics_editor/Canvas.gd @@ -12,7 +12,7 @@ export var can_draw = true var mouse_in_region var mouse_on_top -var layers = {} # Key: layer_name, val: GELayer +var layers : Array = [] # Key: layer_name, val: GELayer var active_layer: GELayer var preview_layer: GELayer @@ -31,24 +31,20 @@ func _enter_tree(): grid = find_node("Grid") big_grid = find_node("BigGrid") - #------------------------------- # setup layers and canvas #------------------------------- connect("mouse_entered", self, "_on_mouse_entered") connect("mouse_exited", self, "_on_mouse_exited") - #------------------------------- # setup layers and canvas #------------------------------- #canvas_size = Vector2(int(rect_size.x / grid_size), int(rect_size.y / grid_size)) #pixel_size = canvas_size - preview_layer = add_new_layer("Preview") active_layer = add_new_layer("Layer1") - - active_layer.set_pixel(10, 10, Color.blue) + preview_layer = add_new_layer("Preview") set_process(true) @@ -63,13 +59,21 @@ func _process(delta): func _draw(): - for layer_name in layers: - var layer = layers[layer_name] + for layer in layers: + if not layer.visible: + continue var idx = 0 for color in layer.pixels: var p = GEUtils.to_2D(idx, canvas_width) draw_rect(Rect2(p.x * pixel_size, p.y * pixel_size, pixel_size, pixel_size), color) idx += 1 + + var idx = 0 + for color in preview_layer.pixels: + var p = GEUtils.to_2D(idx, canvas_width) + draw_rect(Rect2(p.x * pixel_size, p.y * pixel_size, pixel_size, pixel_size), color) + idx += 1 + #------------------------------- @@ -121,62 +125,107 @@ func get_preview_layer(): func clear_active_layer(): - clear_layer(active_layer.name) + active_layer.clear() func clear_preview_layer(): - clear_layer(preview_layer.name) + preview_layer.clear() func clear_layer(layer_name: String): for layer in layers: - layer.pixels.clear() + if layer.name == layer_name: + layer.clear() + break func remove_layer(layer_name: String): - if not layer_name in layers: - return null - # change current layer if the active layer is removed - if active_layer.name == layer_name: + var del_layer = find_layer_by_name(layer_name) + del_layer.clear() + if del_layer == active_layer: for layer in layers: - if layer == preview_layer: + if layer == preview_layer or layer == active_layer: continue active_layer = layer break - - find_node("Layers").remove_child(layers[layer_name]) - layers[layer_name].queue_free() - layers.erase(layer_name) - - # return new active layer ? + layers.erase(del_layer) return active_layer -func add_new_layer(layer_name): - if layer_name in layers: - return +func add_new_layer(layer_name: String): + for layer in layers: + if layer.name == layer_name: + return var layer = GELayer.new() layer.name = layer_name layer.resize(canvas_width, canvas_height) - layers[layer_name] = layer - return layers[layer_name] + if layer_name != "Preview": + layers.append(layer) + return layer func duplicate_layer(layer_name: String, new_layer_name: String): - if not layer_name in layers or new_layer_name in layers: - return - var layer = add_new_layer(new_layer_name) - layer.pixels = layers[layer_name].pixels.duplicate() + for layer in layers: + if layer.name == new_layer_name: + return + + var dup_layer + for layer in layers: + if layer.name == layer_name: + dup_layer = layer + break + + var layer :GELayer = add_new_layer(new_layer_name) + layer.pixels = dup_layer.pixels.duplicate() + layer.name = new_layer_name return layer func toggle_layer_visibility(layer_name: String): - if not layer_name in layers: - return - layers[layer_name].visible = not layers[layer_name].visible + for layer in layers: + if layer.name == layer_name: + layer.visible = not layer.visible +func find_layer_by_name(layer_name: String): + for layer in layers: + if layer.name == layer_name: + return layer + return null + + +func move_layer_forward(layer_name: String): + var remove_pos = -1 + var layer + for i in range(layers.size()): + if layers[i].name == layer_name: + remove_pos = i + layer = layers[i] + print("from: ", i) + break + layers.erase(layer) + print("forw to: ", max(remove_pos - 1, 0)) + layers.insert(max(remove_pos - 1, 0), layer) + + +func move_layer_back(layer_name: String): + var remove_pos = -1 + var layer + for i in range(layers.size()): + if layers[i].name == layer_name: + remove_pos = i + layer = layers[i] + print("from: ", i) + break + layers.erase(layer) + print("back to: ", min(remove_pos + 1, layers.size())) + layers.insert(min(remove_pos + 1, layers.size()), layer) + + +func select_layer(layer_name: String): + active_layer = find_layer_by_name(layer_name) + #------------------------------- # Check @@ -235,7 +284,30 @@ func get_pixel(x: int, y: int): if active_layer: if active_layer.pixels.size() <= idx: return null - return active_layer.pixels[idx] + return active_layer.pixels[idx] + return null + + +func set_preview_pixel_v(pos: Vector2, color: Color): + set_preview_pixel(pos.x, pos.y, color) + + +func set_preview_pixel(x:int, y: int, color: Color): + if not is_inside_canvas(x, y): + return + preview_layer.set_pixel(x, y, color) + + +func get_preview_pixel_v(pos: Vector2): + return get_preview_pixel(pos.x, pos.y) + + +func get_preview_pixel(x: int, y: int): + var idx = GEUtils.to_1D(x, y, canvas_width) + if preview_layer: + if preview_layer.pixels.size() <= idx: + return null + return preview_layer.pixels[idx] #------------------------------- @@ -252,7 +324,7 @@ func select_color(x, y): return same_color_pixels -func select_neighbouring_color(x, y): +func select_same_color(x, y): return get_neighbouring_pixels(x, y) @@ -262,14 +334,21 @@ func select_neighbouring_color(x, y): func get_neighbouring_pixels(pos_x: int, pos_y: int) -> Array: var pixels = [] - var check_queue = [] + var to_check_queue = [] + var checked_queue = [] - check_queue.append(Vector2(pos_x, pos_y)) + to_check_queue.append(GEUtils.to_1D(pos_x, pos_y, canvas_width)) var color = get_pixel(pos_x, pos_y) - while not check_queue.empty(): - var p = check_queue.pop_front() + while not to_check_queue.empty(): + var idx = to_check_queue.pop_front() + var p = GEUtils.to_2D(idx, canvas_width) + + if idx in checked_queue: + continue + + checked_queue.append(idx) if get_pixel(p.x, p.y) != color: continue @@ -280,22 +359,25 @@ func get_neighbouring_pixels(pos_x: int, pos_y: int) -> Array: # check neighbours var x = p.x - 1 var y = p.y - - if not p in pixels and is_inside_canvas(x, y): - check_queue.append(Vector2(x, y)) + if is_inside_canvas(x, y): + idx = GEUtils.to_1D(x, y, canvas_width) + to_check_queue.append(idx) x = p.x + 1 - if not p in pixels and is_inside_canvas(x, y): - check_queue.append(Vector2(x, y)) + if is_inside_canvas(x, y): + idx = GEUtils.to_1D(x, y, canvas_width) + to_check_queue.append(idx) x = p.x y = p.y - 1 - if not p in pixels and is_inside_canvas(x, y): - check_queue.append(Vector2(x, y)) + if is_inside_canvas(x, y): + idx = GEUtils.to_1D(x, y, canvas_width) + to_check_queue.append(idx) y = p.y + 1 - if not p in pixels and is_inside_canvas(x, y): - check_queue.append(Vector2(x, y)) + if is_inside_canvas(x, y): + idx = GEUtils.to_1D(x, y, canvas_width) + to_check_queue.append(idx) return pixels diff --git a/addons/graphics_editor/Editor.gd b/addons/graphics_editor/Editor.gd index 76a088f..e0596bb 100644 --- a/addons/graphics_editor/Editor.gd +++ b/addons/graphics_editor/Editor.gd @@ -14,8 +14,9 @@ enum Tools { CUT, } +var layer_buttons: Control var paint_canvas_container_node -var paint_canvas +var paint_canvas: GECanvas var grids_node var colors_grid var selected_color = Color(1, 1, 1, 1) @@ -34,7 +35,10 @@ var _total_added_layers = 1 var selected_brush_prefab = 0 var _last_drawn_pixel = Vector2.ZERO var _last_preview_draw_cell_pos = Vector2.ZERO -var _selection = [] + +var _selection_cells = [] +var _selection_colors = [] + var _just_cut = false var _show_cut = false var _cut_pos = Vector2.ZERO @@ -44,9 +48,6 @@ var _actions_history = [] # for undo var _redo_history = [] var _current_action -enum Action { - PAINT, -} func _enter_tree(): @@ -58,7 +59,8 @@ func _enter_tree(): selected_color = find_node("ColorPicker").color colors_grid = find_node("Colors") paint_canvas = get_node("Panel/VBoxContainer/HBoxContainer/PaintCanvasContainer/Canvas") - print(paint_canvas) + layer_buttons = find_node("LayerButtons") + set_process(true) #-------------------- @@ -73,6 +75,8 @@ func _enter_tree(): func _ready(): set_brush(Tools.PAINT) + _layer_button_ref[layer_buttons.get_child(0).name] = layer_buttons.get_child(0) #ugly + _connect_layer_buttons() func _input(event): @@ -81,6 +85,15 @@ func _input(event): elif Input.is_key_pressed(KEY_Y): print("Y") + if (paint_canvas.mouse_in_region and paint_canvas.mouse_on_top): + match brush_mode: + Tools.BUCKET: + if _current_action == null: + _current_action = get_action() + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if event.pressed: + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) var brush_mode @@ -141,31 +154,38 @@ func _process(delta): last_cell_color = cell_color +func _reset_cut_tool(): + _just_cut = false + _show_cut = false + _selection_cells.clear() + _selection_colors.clear() + + func _handle_cut(): if Input.is_mouse_button_pressed(BUTTON_RIGHT): - _just_cut = false - _show_cut = false paint_canvas.clear_preview_layer() - brush_mode = _previous_tool - _selection = [] + _reset_cut_tool() + set_brush(_previous_tool) return -# if Input.is_mouse_button_pressed(BUTTON_LEFT): -# for pixel_pos in paint_canvas.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position): -# for pixel in _selection: -# var pos = pixel[0] -# pos -= _cut_pos -# pos += pixel_pos -# paint_canvas.set_pixel_v(pos, pixel[1]) + if Input.is_mouse_button_pressed(BUTTON_LEFT): + for pixel_pos in GEUtils.get_pixels_in_line(cell_mouse_position, last_cell_mouse_position): + for idx in range(_selection_cells.size()): + var pixel = _selection_cells[idx] + var color = _selection_colors[idx] + pixel -= _cut_pos + pixel += pixel_pos + paint_canvas.set_pixel_v(pixel, color) else: if _last_preview_draw_cell_pos == cell_mouse_position: return paint_canvas.clear_preview_layer() - for pixel in _selection: - var pos = pixel[0] - pos -= _cut_pos - pos += cell_mouse_position - paint_canvas.set_pixel_v(pos, pixel[1]) + for idx in range(_selection_cells.size()): + var pixel = _selection_cells[idx] + var color = _selection_colors[idx] + pixel -= _cut_pos + pixel += cell_mouse_position + paint_canvas.set_preview_pixel_v(pixel, color) _last_preview_draw_cell_pos = cell_mouse_position @@ -175,10 +195,6 @@ func brush_process(): return if Input.is_mouse_button_pressed(BUTTON_LEFT): -# var arr = GEUtils.get_pixels_in_line(cell_mouse_position, last_cell_mouse_position) -# paint_canvas.set_pixel_arr(arr, selected_color) - - if _current_action == null: _current_action = get_action() @@ -187,172 +203,34 @@ func brush_process(): do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.BRUSH: do_action([cell_mouse_position, last_cell_mouse_position, selected_color, selected_brush_prefab]) - return - else: - if _current_action and _current_action.can_commit(): - commit_action() - - return - if Input.is_mouse_button_pressed(BUTTON_LEFT): - match brush_mode: - Tools.PAINT: - paint_canvas.set_pixel_arr(GEUtils.get_pixels_in_line(cell_mouse_position, last_cell_mouse_position), selected_color) - Tools.BRUSH: - for pixel_pos in GEUtils.get_pixels_in_line(cell_mouse_position, last_cell_mouse_position): - for off in BrushPrefabs.list[selected_brush_prefab]: - paint_canvas.set_pixel_v(pixel_pos + off, selected_color) Tools.LINE: - if _left_mouse_pressed_start_pos == Vector2.ZERO: - _left_mouse_pressed_start_pos = cell_mouse_position - paint_canvas.clear_preview_layer() - paint_canvas.set_pixels_from_line( - cell_mouse_position, _left_mouse_pressed_start_pos, selected_color) - + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.RECT: - if _left_mouse_pressed_start_pos == Vector2.ZERO: - _left_mouse_pressed_start_pos = cell_mouse_position - paint_canvas.clear_preview_layer() - - var p = _left_mouse_pressed_start_pos - var s = cell_mouse_position - _left_mouse_pressed_start_pos - - paint_canvas.set_pixels_from_line( - p, p + Vector2(s.x, 0), selected_color) - paint_canvas.set_pixels_from_line( - p, p + Vector2(0, s.y), selected_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(0, -s.y), selected_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(-s.x, 0), selected_color) - + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.DARKEN: - var pixels = paint_canvas.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position) - var val = 0.9 - for pixel in pixels: - if _last_drawn_pixel == pixel: - continue - _last_drawn_pixel = pixel - - var new_color = paint_canvas.get_pixel_cell_color(pixel.x, pixel.y) - new_color.r *= val - new_color.g *= val - new_color.b *= val - paint_canvas.set_pixel_v(pixel, new_color) - + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.BRIGHTEN: - var pixels = paint_canvas.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position) - var val = 1.1 - for pixel in pixels: - if _last_drawn_pixel == pixel: - continue - _last_drawn_pixel = pixel - - var new_color = paint_canvas.get_pixel_cell_color(pixel.x, pixel.y) - new_color.r *= val - new_color.g *= val - new_color.b *= val - paint_canvas.set_pixel_v(pixel, new_color) - + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.COLORPICKER: - change_color(paint_canvas.get_pixel_cell_color(cell_mouse_position.x, cell_mouse_position.y)) - + change_color(paint_canvas.get_pixel(cell_mouse_position.x, cell_mouse_position.y)) Tools.CUT: - if _left_mouse_pressed_start_pos == Vector2.ZERO: - _left_mouse_pressed_start_pos = cell_mouse_position - paint_canvas.clear_preview_layer() - - var p = _left_mouse_pressed_start_pos - var s = cell_mouse_position - _left_mouse_pressed_start_pos - - var selection_color = Color(0.8, 0.8, 0.8, 0.5) - - paint_canvas.set_pixels_from_line( - p, p + Vector2(s.x, 0), selection_color) - paint_canvas.set_pixels_from_line( - p, p + Vector2(0, s.y), selection_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(0, -s.y), selection_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(-s.x, 0), selection_color) - - Tools.BUCKET: - paint_canvas.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, selected_color) + do_action([cell_mouse_position, last_cell_mouse_position, selected_color]) Tools.RAINBOW: - paint_canvas.set_random_pixels_from_line(cell_mouse_position, last_cell_mouse_position) - _: - print("no brush selected") -# paint_canvas.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, selected_color) - + do_action([cell_mouse_position, last_cell_mouse_position]) else: if _current_action and _current_action.can_commit(): commit_action() if Input.is_mouse_button_pressed(BUTTON_RIGHT): return + if _current_action == null: + _current_action = get_action() match brush_mode: Tools.PAINT: - paint_canvas.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0)) -# Tools.BUCKET: -# paint_canvas.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, Color(0, 0, 0, 0)) + do_action([cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0)]) Tools.BRUSH: - for pixel_pos in paint_canvas.get_pixels_from_line(cell_mouse_position, last_cell_mouse_position): - for off in BrushPrefabs.list[selected_brush_prefab]: - paint_canvas.set_pixel_v(pixel_pos + off, Color(0, 0, 0, 0)) - Tools.RAINBOW: - paint_canvas.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0)) - _: - paint_canvas.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0)) - - if not Input.is_mouse_button_pressed(BUTTON_LEFT): - match brush_mode: - Tools.LINE: - paint_canvas.clear_preview_layer() - paint_canvas.set_pixels_from_line( - cell_mouse_position, _left_mouse_pressed_start_pos, selected_color) - _left_mouse_pressed_start_pos = Vector2.ZERO - - Tools.RECT: - paint_canvas.clear_preview_layer() - - var p = _left_mouse_pressed_start_pos - var s = cell_mouse_position - _left_mouse_pressed_start_pos - - paint_canvas.set_pixels_from_line( - p, p + Vector2(s.x, 0), selected_color) - paint_canvas.set_pixels_from_line( - p, p + Vector2(0, s.y), selected_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(0, -s.y), selected_color) - paint_canvas.set_pixels_from_line( - p + s, p + s + Vector2(-s.x, 0), selected_color) - _left_mouse_pressed_start_pos = Vector2.ZERO - - Tools.CUT: - paint_canvas.clear_preview_layer() - - var p = _left_mouse_pressed_start_pos - var s = cell_mouse_position - _left_mouse_pressed_start_pos - _cut_pos = p + s / 2 - _cut_size = s - - for x in range(abs(s.x)+1): - for y in range(abs(s.y)+1): - var px = x - var py = y - if s.x < 0: - px *= -1 - if s.y < 0: - py *= -1 - - var pos = p + Vector2(px, py) - var color = paint_canvas.get_pixel_cell_color(pos.x, pos.y) - if color.a == 0: - continue - _selection.append([pos, color]) - paint_canvas.set_pixel_v(pos, Color.transparent) - _left_mouse_pressed_start_pos = Vector2.ZERO - _just_cut = true + do_action([cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0), selected_brush_prefab]) func update_text_info(): @@ -379,10 +257,6 @@ func update_text_info(): find_node("DebugTextDisplay").display_text(text) -func select_layer(layer_name: String): - print("select layer: ", layer_name) - - func _on_Save_pressed(): get_node("SaveFileDialog").show() @@ -404,10 +278,22 @@ func commit_action(): return print("commit action") - _current_action.commit_action(paint_canvas) + var commit_data = _current_action.commit_action(paint_canvas) var action = get_action() action.action_data = _current_action.action_data.duplicate(true) + _actions_history.push_back(action) + + match brush_mode: + Tools.CUT: + if _just_cut: + continue + _cut_pos = _current_action.mouse_start_pos + _cut_size = _current_action.mouse_end_pos - _current_action.mouse_start_pos + _selection_cells = _current_action.action_data.do.cells.duplicate() + _selection_colors = _current_action.action_data.do.colors.duplicate() + _just_cut = true + _current_action = null return action.action_data = _current_action.action_data @@ -435,6 +321,20 @@ func get_action(): return GEPencil.new() Tools.BRUSH: return GEBrush.new() + Tools.LINE: + return GELine.new() + Tools.RAINBOW: + return GERainbow.new() + Tools.BUCKET: + return GEBucket.new() + Tools.RECT: + return GERect.new() + Tools.DARKEN: + return GEDarken.new() + Tools.BRIGHTEN: + return GEBrighten.new() + Tools.CUT: + return GECut.new() _: print("no tool!") return null @@ -449,6 +349,14 @@ func set_brush(new_mode): return _previous_tool = brush_mode brush_mode = new_mode + + match _previous_tool: + Tools.CUT: + paint_canvas.clear_preview_layer() + _just_cut = false + Tools.BUCKET: + _current_action = null + print("Selected: ", Tools.keys()[brush_mode]) func change_color(new_color): @@ -463,11 +371,11 @@ func _on_ColorPicker_color_changed(color): func _on_PaintTool_pressed(): - brush_mode = Tools.PAINT + set_brush(Tools.PAINT) func _on_BucketTool_pressed(): - brush_mode = Tools.BUCKET + set_brush(Tools.BUCKET) func _on_RainbowTool_pressed(): @@ -514,91 +422,97 @@ func _on_Editor_visibility_changed(): pause_mode = not visible -func _connect_layer_buttons(): - for layer_btn in get_tree().get_nodes_in_group("layer"): - if layer_btn.is_connected("pressed", self, "select_layer"): - continue - layer_btn.connect("pressed", self, "select_layer", [get_layer_by_button_name(layer_btn.name)]) - layer_btn.find_node("Visible").connect("pressed", self, "toggle_layer_visibility", - [layer_btn.find_node("Visible"), get_layer_by_button_name(layer_btn.name)]) - layer_btn.find_node("Up").connect("pressed", self, "move_up", [layer_btn]) - layer_btn.find_node("Down").connect("pressed", self, "move_down", [layer_btn]) - +#--------------------------------------- +# Layer +#--------------------------------------- func toggle_layer_visibility(button, layer_name: String): print("toggling: ", layer_name) - print(paint_canvas.layers.keys()) paint_canvas.toggle_layer_visibility(layer_name) +func select_layer(layer_name: String): + print("select layer: ", layer_name) + paint_canvas.select_layer(layer_name) + + func add_new_layer(): - var layers = get_tree().get_nodes_in_group("layer") - var new_layer = layers.back().duplicate() - find_node("Layers").add_child_below_node(layers.back(), new_layer, true) + var new_layer = layer_buttons.get_child(0).duplicate() + layer_buttons.add_child_below_node(layer_buttons.get_child(layer_buttons.get_child_count() - 1), new_layer, true) _total_added_layers += 1 new_layer.text = "Layer " + str(_total_added_layers) - var new_layer_name = paint_canvas.add_new_layer(new_layer.name) + var layer: GELayer = paint_canvas.add_new_layer(new_layer.name) - _layer_button_ref[new_layer_name] = new_layer + _layer_button_ref[new_layer.name] = new_layer _connect_layer_buttons() - print("added layer: ", new_layer_name, "(total:", layers.size(), ")") + print("added layer: ", layer.name) func remove_active_layer(): - if _layer_button_ref.size() < 2: + if layer_buttons.get_child_count() <= 1: return + var layer_name = paint_canvas.active_layer.name + paint_canvas.remove_layer(layer_name) + layer_buttons.remove_child(_layer_button_ref[layer_name]) + _layer_button_ref[layer_name].queue_free() + _layer_button_ref.erase(layer_name) - _layer_button_ref[paint_canvas.active_layer].get_parent().remove_child(_layer_button_ref[paint_canvas.active_layer]) - _layer_button_ref[paint_canvas.active_layer].queue_free() - _layer_button_ref.erase(paint_canvas.active_layer) - paint_canvas.remove_layer(paint_canvas.active_layer) func duplicate_active_layer(): # copy the last layer button (or the initial one) - var layer_buttons = get_tree().get_nodes_in_group("layer") - var new_layer_button = layer_buttons.back().duplicate() - find_node("Layers").add_child_below_node(layer_buttons.back(), new_layer_button, true) + + var new_layer_button = layer_buttons.get_child(0).duplicate() + layer_buttons.add_child_below_node( + layer_buttons.get_child(layer_buttons.get_child_count() - 1), new_layer_button, true) _total_added_layers += 1 # for keeping track... new_layer_button.text = "Layer " + str(_total_added_layers) - var new_layer_name = paint_canvas.duplicate_layer(paint_canvas.active_layer, new_layer_button.name) + var new_layer = paint_canvas.duplicate_layer(paint_canvas.active_layer.name, new_layer_button.name) - _layer_button_ref[new_layer_name] = new_layer_button + _layer_button_ref[new_layer.name] = new_layer_button - _connect_layer_buttons() + new_layer_button.disconnect("pressed", self, "select_layer") + new_layer_button.find_node("Visible").disconnect("pressed", self, "toggle_layer_visibility") + new_layer_button.find_node("Up").disconnect("pressed", self, "move_down") + new_layer_button.find_node("Down").disconnect("pressed", self, "move_up") - print("added layer: ", new_layer_name, " (total:", layer_buttons.size(), ")") + new_layer_button.connect("pressed", self, "select_layer", [new_layer_button.name]) + new_layer_button.find_node("Visible").connect("pressed", self, "toggle_layer_visibility", + [new_layer_button.find_node("Visible"), new_layer_button.name]) + new_layer_button.find_node("Up").connect("pressed", self, "move_down", [new_layer_button]) + new_layer_button.find_node("Down").connect("pressed", self, "move_up", [new_layer_button]) + + print("added layer: ", new_layer.name, " (total:", layer_buttons.size(), ")") -func get_layer_by_button_name(button_name: String): - for layer_name in _layer_button_ref: - var button = _layer_button_ref[layer_name] - if button.name == button_name: - return layer_name - return null +func move_up(layer_btn): + var new_idx = min(layer_btn.get_index() + 1, layer_buttons.get_child_count()) + print("move_down: ", layer_btn.name, " from ", layer_btn.get_index(), " to ", new_idx) + layer_buttons.move_child(layer_btn, new_idx) + paint_canvas.move_layer_back(layer_btn.name) -func move_down(layer_btn, button_name: String): - print("move_up: ", button_name) - var layer_name = get_layer_by_button_name(button_name) - var chunk_node = paint_canvas.layers[layer_name].chunks - chunk_node.get_parent().move_child(chunk_node, max(chunk_node.get_index() + 1, 0)) - layer_btn.get_parent().move_child(layer_btn, max(layer_btn.get_index() + 1, 0)) +func move_down(layer_btn): + var new_idx = max(layer_btn.get_index() - 1, 0) + print("move_up: ", layer_btn.name, " from ", layer_btn.get_index(), " to ", new_idx) + layer_buttons.move_child(layer_btn, new_idx) + paint_canvas.move_layer_forward(layer_btn.name) -func move_up(layer_btn, button_name: String): - print("move_up: ", button_name) - var layer_name = get_layer_by_button_name(button_name) - var chunk_node = paint_canvas.layers[layer_name].chunks - chunk_node.get_parent().move_child(chunk_node, - min(chunk_node.get_index() - 1, chunk_node.get_parent().get_child_count() - 1)) - layer_btn.get_parent().move_child(layer_btn, - min(layer_btn.get_index() - 1, layer_btn.get_parent().get_child_count() - 1)) +func _connect_layer_buttons(): + for layer_btn in layer_buttons.get_children(): + if layer_btn.is_connected("pressed", self, "select_layer"): + continue + layer_btn.connect("pressed", self, "select_layer", [layer_btn.name]) + layer_btn.find_node("Visible").connect("pressed", self, "toggle_layer_visibility", + [layer_btn.find_node("Visible"), layer_btn.name]) + layer_btn.find_node("Up").connect("pressed", self, "move_down", [layer_btn]) + layer_btn.find_node("Down").connect("pressed", self, "move_up", [layer_btn]) func _on_Button_pressed(): diff --git a/addons/graphics_editor/Editor.tscn b/addons/graphics_editor/Editor.tscn index 7f4d5ee..5708ed2 100644 --- a/addons/graphics_editor/Editor.tscn +++ b/addons/graphics_editor/Editor.tscn @@ -26,76 +26,76 @@ corner_radius_bottom_right = 2 corner_radius_bottom_left = 2 [sub_resource type="StyleBoxFlat" id=27] -bg_color = Color( 0.213659, 0.765351, 0.325763, 1 ) +bg_color = Color( 0.103793, 0.952543, 0.558178, 1 ) [sub_resource type="StyleBoxFlat" id=28] -bg_color = Color( 0.176073, 0.806619, 0.967443, 1 ) +bg_color = Color( 0.68094, 0.136103, 0.784658, 1 ) [sub_resource type="StyleBoxFlat" id=29] -bg_color = Color( 0.46115, 0.389032, 0.649624, 1 ) +bg_color = Color( 0.565245, 0.950216, 0.525136, 1 ) [sub_resource type="StyleBoxFlat" id=30] -bg_color = Color( 0.415833, 0.965657, 0.678807, 1 ) +bg_color = Color( 0.840295, 0.689674, 0.146119, 1 ) [sub_resource type="StyleBoxFlat" id=31] -bg_color = Color( 0.95106, 0.531613, 0.0362836, 1 ) +bg_color = Color( 0.170796, 0.863757, 0.940376, 1 ) [sub_resource type="StyleBoxFlat" id=32] -bg_color = Color( 0.414718, 0.156676, 0.927291, 1 ) +bg_color = Color( 0.989842, 0.167318, 0.759568, 1 ) [sub_resource type="StyleBoxFlat" id=33] -bg_color = Color( 0.904518, 0.341891, 0.208397, 1 ) +bg_color = Color( 0.424938, 0.286666, 0.207677, 1 ) [sub_resource type="StyleBoxFlat" id=34] -bg_color = Color( 0.532053, 0.87726, 0.342851, 1 ) +bg_color = Color( 0.470532, 0.276365, 0.490264, 1 ) [sub_resource type="StyleBoxFlat" id=35] -bg_color = Color( 0.933623, 0.443817, 0.855431, 1 ) +bg_color = Color( 0.479465, 0.612879, 0.603754, 1 ) [sub_resource type="StyleBoxFlat" id=36] -bg_color = Color( 0.79689, 0.333745, 0.615167, 1 ) +bg_color = Color( 0.66582, 0.937007, 0.078631, 1 ) [sub_resource type="StyleBoxFlat" id=37] -bg_color = Color( 0.399027, 0.806071, 0.516829, 1 ) +bg_color = Color( 0.969678, 0.463082, 0.741374, 1 ) [sub_resource type="StyleBoxFlat" id=38] -bg_color = Color( 0.513829, 0.820974, 0.0806655, 1 ) +bg_color = Color( 0.748974, 0.911029, 0.0970848, 1 ) [sub_resource type="StyleBoxFlat" id=39] -bg_color = Color( 0.576046, 0.303465, 0.354421, 1 ) +bg_color = Color( 0.0446367, 0.149028, 0.965347, 1 ) [sub_resource type="StyleBoxFlat" id=40] -bg_color = Color( 0.0409532, 0.831937, 0.447566, 1 ) +bg_color = Color( 0.652305, 0.82955, 0.449331, 1 ) [sub_resource type="StyleBoxFlat" id=41] -bg_color = Color( 0.641815, 0.654958, 0.623856, 1 ) +bg_color = Color( 0.858449, 0.143876, 0.556734, 1 ) [sub_resource type="StyleBoxFlat" id=42] -bg_color = Color( 0.16782, 0.641056, 0.625732, 1 ) +bg_color = Color( 0.885448, 0.997685, 0.776802, 1 ) [sub_resource type="StyleBoxFlat" id=43] -bg_color = Color( 0.797095, 0.50587, 0.280019, 1 ) +bg_color = Color( 0.404004, 0.65451, 0.498103, 1 ) [sub_resource type="StyleBoxFlat" id=44] -bg_color = Color( 0.691959, 0.511673, 0.985569, 1 ) +bg_color = Color( 0.0711977, 0.735235, 0.953192, 1 ) [sub_resource type="StyleBoxFlat" id=45] -bg_color = Color( 0.610537, 0.592647, 0.539142, 1 ) +bg_color = Color( 0.696129, 0.303368, 0.559114, 1 ) [sub_resource type="StyleBoxFlat" id=46] -bg_color = Color( 0.263664, 0.636201, 0.25046, 1 ) +bg_color = Color( 0.16818, 0.0828524, 0.104581, 1 ) [sub_resource type="StyleBoxFlat" id=47] -bg_color = Color( 0.49156, 0.696528, 0.836079, 1 ) +bg_color = Color( 0.388226, 0.400829, 0.895155, 1 ) [sub_resource type="StyleBoxFlat" id=48] -bg_color = Color( 0.402661, 0.715784, 0.995676, 1 ) +bg_color = Color( 0.381586, 0.871279, 0.0388422, 1 ) [sub_resource type="StyleBoxFlat" id=49] -bg_color = Color( 0.694132, 0.532637, 0.466888, 1 ) +bg_color = Color( 0.0975624, 0.683663, 0.768315, 1 ) [sub_resource type="StyleBoxFlat" id=50] -bg_color = Color( 0.120597, 0.37573, 0.24552, 1 ) +bg_color = Color( 0.125084, 0.498048, 0.0623495, 1 ) [sub_resource type="StyleBoxFlat" id=26] bg_color = Color( 0.156863, 0.156863, 0.156863, 1 ) @@ -702,23 +702,30 @@ margin_right = 114.0 margin_bottom = 501.0 size_flags_vertical = 3 -[node name="Layers" type="VBoxContainer" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control"] +[node name="VBoxContainer" type="VBoxContainer" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control"] margin_right = 114.0 margin_bottom = 67.0 size_flags_horizontal = 3 size_flags_vertical = 3 + +[node name="LayerButtons" type="VBoxContainer" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/VBoxContainer"] +margin_right = 114.0 +margin_bottom = 38.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 __meta__ = { "_edit_use_anchors_": false } -[node name="Layer1" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/Layers" instance=ExtResource( 12 )] +[node name="Layer1" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/VBoxContainer/LayerButtons" instance=ExtResource( 12 )] margin_bottom = 32.0 -[node name="Button" type="Button" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/Layers"] -margin_top = 36.0 +[node name="Button" type="Button" parent="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/VBoxContainer"] +margin_top = 42.0 margin_right = 114.0 -margin_bottom = 61.0 +margin_bottom = 67.0 rect_min_size = Vector2( 0, 25 ) +size_flags_horizontal = 3 text = "+" __meta__ = { "_edit_use_anchors_": false @@ -736,7 +743,7 @@ custom_styles/panel = SubResource( 26 ) anchor_right = 1.0 anchor_bottom = 1.0 text = "FPS 60 Mouse Position (0, 0) Canvas Mouse Position (0, 0) Canvas Position (0, 0) -Cell Position (0, 0) Cell Color 0,0,0,0 Cell Region (0, 0) Cell Position (0, 0) " +Cell Position (0, 0) Cell Color 0,0,0,0 " scroll_active = false script = ExtResource( 11 ) __meta__ = { @@ -777,7 +784,7 @@ mouse_filter = 1 [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Tools/ColorPickerTool" to="." method="_on_ColorPickerTool_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Tools/CutTool" to="." method="_on_CutTool_pressed"] [connection signal="color_changed" from="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Tools/ColorPicker" to="." method="_on_ColorPicker_color_changed"] -[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/Layers/Button" to="." method="_on_Button_pressed"] +[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer/ScrollContainer/ToolMenu/Control/VBoxContainer/Button" to="." method="_on_Button_pressed"] [connection signal="about_to_show" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_about_to_show"] [connection signal="confirmed" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_confirmed"] [connection signal="file_selected" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_file_selected"] diff --git a/addons/graphics_editor/Layer.gd b/addons/graphics_editor/Layer.gd index 84ecde3..3c236e3 100644 --- a/addons/graphics_editor/Layer.gd +++ b/addons/graphics_editor/Layer.gd @@ -5,6 +5,7 @@ class_name GELayer var name var pixels # array of pixels (colors), idx repressents x and y var layer_width +var visible = true func _init(): @@ -25,3 +26,9 @@ func set_pixel(x, y, color): func get_pixel(x: int, y: int): return pixels[x + y * layer_width] + + +func clear(): + for idx in range(pixels.size()): + if pixels[idx] != Color.transparent: + pixels[idx] = Color.transparent diff --git a/addons/graphics_editor/LayerButton.tscn b/addons/graphics_editor/LayerButton.tscn index 015d8eb..6be73c4 100644 --- a/addons/graphics_editor/LayerButton.tscn +++ b/addons/graphics_editor/LayerButton.tscn @@ -9,7 +9,7 @@ bg_color = Color( 0.25098, 0.25098, 0.25098, 1 ) [node name="Layer1" type="Button" groups=[ -"layer", +"layer_button", ]] margin_right = 114.0 margin_bottom = 20.0 diff --git a/addons/graphics_editor/SaveFileDialog.gd b/addons/graphics_editor/SaveFileDialog.gd index cd7872f..b7f70e2 100644 --- a/addons/graphics_editor/SaveFileDialog.gd +++ b/addons/graphics_editor/SaveFileDialog.gd @@ -36,8 +36,7 @@ func save_file(): image.create(canvas.canvas_width, canvas.canvas_height, true, Image.FORMAT_RGBA8) image.lock() - for layer_name in canvas.layers: - var layer = canvas.layers[layer_name] + for layer in canvas.layers: var idx = 0 for color in layer.pixels: var pos = GEUtils.to_2D(idx, canvas.canvas_width) diff --git a/addons/graphics_editor/Util.gd b/addons/graphics_editor/Util.gd index d5c90e0..9840120 100644 --- a/addons/graphics_editor/Util.gd +++ b/addons/graphics_editor/Util.gd @@ -37,7 +37,7 @@ static func to_1D(x, y, w) -> int: static func to_2D(idx, w) -> Vector2: var p = Vector2() - p.x = idx % int(w) + p.x = int(idx) % int(w) p.y = int(idx / w) return p diff --git a/addons/graphics_editor/actions/Action.gd b/addons/graphics_editor/actions/Action.gd index f3e84a5..4b86450 100644 --- a/addons/graphics_editor/actions/Action.gd +++ b/addons/graphics_editor/actions/Action.gd @@ -8,14 +8,30 @@ var action_data = {} func _init(): action_data["do"] = {} action_data["undo"] = {} + action_data["preview"] = {} func do_action(canvas, data: Array): - print("NO IMPL do_action") + if not "cells" in action_data.do: + action_data.do["cells"] = [] + action_data.do["colors"] = [] + + if not "cells" in action_data.undo: + action_data.undo["cells"] = [] + action_data.undo["colors"] = [] + + if not "cells" in action_data.preview: + action_data.preview["cells"] = [] + action_data.preview["colors"] = [] + + if "layer" in action_data.do: + action_data.do["layer"] = canvas.active_layer + action_data.undo["layer"] = canvas.active_layer func commit_action(canvas): print("NO IMPL commit_action ") + return [] func undo_action(canvas): diff --git a/addons/graphics_editor/actions/Brighten.gd b/addons/graphics_editor/actions/Brighten.gd new file mode 100644 index 0000000..8a62b58 --- /dev/null +++ b/addons/graphics_editor/actions/Brighten.gd @@ -0,0 +1,43 @@ +extends GEAction +class_name GEBrighten + + +const brighten_color = 0.1 + + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + var pixels = GEUtils.get_pixels_in_line(data[0], data[1]) + for pixel in pixels: + if pixel in action_data.undo.cells: + var brightened_color = canvas.get_pixel_v(pixel).lightened(0.1) + canvas.set_pixel_v(pixel, brightened_color) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(brightened_color) + continue + + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) + action_data.undo.cells.append(pixel) + var brightened_color = canvas.get_pixel_v(pixel).lightened(0.1) + canvas.set_pixel_v(pixel, brightened_color) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(brightened_color) + + +func commit_action(canvas): + var cells = action_data.do.cells + var colors = action_data.do.colors + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Brush.gd b/addons/graphics_editor/actions/Brush.gd index 81a2487..2bbd9cc 100644 --- a/addons/graphics_editor/actions/Brush.gd +++ b/addons/graphics_editor/actions/Brush.gd @@ -3,17 +3,7 @@ class_name GEBrush func do_action(canvas: GECanvas, data: Array): - if not "cells" in action_data.do: - action_data.do["cells"] = [] - action_data.do["colors"] = [] - - if not "cells" in action_data.undo: - action_data.undo["cells"] = [] - action_data.undo["colors"] = [] - - if "layer" in action_data.do: - action_data.do["layer"] = canvas.active_layer - action_data.undo["layer"] = canvas.active_layer + .do_action(canvas, data) for pixel in GEUtils.get_pixels_in_line(data[0], data[1]): for off in BrushPrefabs.list[data[3]]: @@ -34,6 +24,7 @@ func do_action(canvas: GECanvas, data: Array): func commit_action(canvas): var cells = action_data.do.cells var colors = action_data.do.colors + return [] func undo_action(canvas): diff --git a/addons/graphics_editor/actions/Bucket.gd b/addons/graphics_editor/actions/Bucket.gd new file mode 100644 index 0000000..a8cf5cf --- /dev/null +++ b/addons/graphics_editor/actions/Bucket.gd @@ -0,0 +1,39 @@ +extends GEAction +class_name GEBucket + + + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + if canvas.get_pixel_v(data[0]) == data[2]: + return + var pixels = canvas.select_same_color(data[0].x, data[0].y) + + for pixel in pixels: + if pixel in action_data.undo.cells: + continue + + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) + action_data.undo.cells.append(pixel) + + canvas.set_pixel_v(pixel, data[2]) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(data[2]) + + +func commit_action(canvas): + var cells = action_data.preview.cells + var colors = action_data.preview.colors + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Cut.gd b/addons/graphics_editor/actions/Cut.gd new file mode 100644 index 0000000..5d38c06 --- /dev/null +++ b/addons/graphics_editor/actions/Cut.gd @@ -0,0 +1,70 @@ +extends GEAction +class_name GECut + +const selection_color = Color(0.8, 0.8, 0.8, 0.5) +var mouse_start_pos = null +var mouse_end_pos = null + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + if not mouse_start_pos: + mouse_start_pos = data[0] + mouse_end_pos = data[0] + + action_data.preview.cells.clear() + action_data.preview.colors.clear() + canvas.clear_preview_layer() + + var p = mouse_start_pos + var s = mouse_end_pos - mouse_start_pos + + var pixels = GEUtils.get_pixels_in_line(p, p + Vector2(s.x, 0)) + pixels += GEUtils.get_pixels_in_line(p, p + Vector2(0, s.y)) + pixels += GEUtils.get_pixels_in_line(p + s, p + s + Vector2(0, -s.y)) + pixels += GEUtils.get_pixels_in_line(p + s, p + s + Vector2(-s.x, 0)) + + for pixel in pixels: + canvas.set_preview_pixel_v(pixel, selection_color) + action_data.preview.cells.append(pixel) + action_data.preview.colors.append(selection_color) + + +func commit_action(canvas): + canvas.clear_preview_layer() + var p = mouse_start_pos + var s = mouse_end_pos - mouse_start_pos + + for x in range(abs(s.x)+1): + for y in range(abs(s.y)+1): + var px = x + var py = y + if s.x < 0: + px *= -1 + if s.y < 0: + py *= -1 + + var pos = p + Vector2(px, py) + var color = canvas.get_pixel(pos.x, pos.y) + + if color == Color.transparent: + continue + + action_data.do.cells.append(pos) + action_data.do.colors.append(canvas.get_pixel_v(pos)) + + canvas.set_pixel_v(pos, Color.transparent) + + action_data.undo.cells.append(pos) + action_data.undo.colors.append(Color.transparent) + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Darken.gd b/addons/graphics_editor/actions/Darken.gd new file mode 100644 index 0000000..72e3ea5 --- /dev/null +++ b/addons/graphics_editor/actions/Darken.gd @@ -0,0 +1,42 @@ +extends GEAction +class_name GEDarken + +const dark_factor = 0.1 + + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + var pixels = GEUtils.get_pixels_in_line(data[0], data[1]) + for pixel in pixels: + if pixel in action_data.undo.cells: + var darkened_color = canvas.get_pixel_v(pixel).darkened(dark_factor) + canvas.set_pixel_v(pixel, darkened_color) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(darkened_color) + continue + + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) + action_data.undo.cells.append(pixel) + var darkened_color = canvas.get_pixel_v(pixel).darkened(dark_factor) + canvas.set_pixel_v(pixel, darkened_color) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(darkened_color) + + +func commit_action(canvas): + var cells = action_data.do.cells + var colors = action_data.do.colors + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Line.gd b/addons/graphics_editor/actions/Line.gd new file mode 100644 index 0000000..27b0c3c --- /dev/null +++ b/addons/graphics_editor/actions/Line.gd @@ -0,0 +1,47 @@ +extends GEAction +class_name GELine + + +var mouse_start_pos = null + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + if mouse_start_pos == null: + mouse_start_pos = data[0] + + action_data.preview.cells.clear() + action_data.preview.colors.clear() + canvas.clear_preview_layer() + + var pixels = GEUtils.get_pixels_in_line(data[0], mouse_start_pos) + for pixel in pixels: + canvas.set_preview_pixel_v(pixel, data[2]) + action_data.preview.cells.append(pixel) + action_data.preview.colors.append(data[2]) + + +func commit_action(canvas): + canvas.clear_preview_layer() + var cells = action_data.preview.cells + var colors = action_data.preview.colors + for idx in range(cells.size()): + action_data.undo.cells.append(cells[idx]) + action_data.undo.colors.append(canvas.get_pixel_v(cells[idx])) + + canvas.set_pixel_v(cells[idx], colors[idx]) + + action_data.do.cells.append(cells[idx]) + action_data.do.colors.append(colors[idx]) + mouse_start_pos = null + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Pencil.gd b/addons/graphics_editor/actions/Pencil.gd index 27dc1e5..5e45fe4 100644 --- a/addons/graphics_editor/actions/Pencil.gd +++ b/addons/graphics_editor/actions/Pencil.gd @@ -3,31 +3,26 @@ class_name GEPencil func do_action(canvas, data: Array): - if not "cells" in action_data.do: - action_data.do["cells"] = [] - action_data.do["colors"] = [] - - if not "cells" in action_data.undo: - action_data.undo["cells"] = [] - action_data.undo["colors"] = [] - - if "layer" in action_data.do: - action_data.do["layer"] = canvas.active_layer - action_data.undo["layer"] = canvas.active_layer + .do_action(canvas, data) var pixels = GEUtils.get_pixels_in_line(data[0], data[1]) for pixel in pixels: - canvas.set_pixel_v(pixel, data[2]) - action_data.do.cells.append(pixel) + if pixel in action_data.undo.cells: + continue + + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) action_data.undo.cells.append(pixel) + + canvas.set_pixel_v(pixel, data[2]) + action_data.do.cells.append(pixel) action_data.do.colors.append(data[2]) - action_data.undo.colors.append(Color.transparent) func commit_action(canvas): var cells = action_data.do.cells var colors = action_data.do.colors + return [] func undo_action(canvas): diff --git a/addons/graphics_editor/actions/Rainbow.gd b/addons/graphics_editor/actions/Rainbow.gd new file mode 100644 index 0000000..0341a49 --- /dev/null +++ b/addons/graphics_editor/actions/Rainbow.gd @@ -0,0 +1,45 @@ +extends GEAction +class_name GERainbow + + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + var pixels = GEUtils.get_pixels_in_line(data[0], data[1]) + for pixel in pixels: + if pixel in action_data.undo.cells: + var color = GEUtils.random_color() + canvas.set_pixel_v(pixel, color) + + var idx = action_data.do.cells.find(pixel) + action_data.do.cells.remove(idx) + action_data.do.colors.remove(idx) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(color) + continue + + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) + action_data.undo.cells.append(pixel) + + var color = GEUtils.random_color() + canvas.set_pixel_v(pixel, color) + + action_data.do.cells.append(pixel) + action_data.do.colors.append(color) + + +func commit_action(canvas): + var cells = action_data.do.cells + var colors = action_data.do.colors + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/addons/graphics_editor/actions/Rect.gd b/addons/graphics_editor/actions/Rect.gd new file mode 100644 index 0000000..701e86c --- /dev/null +++ b/addons/graphics_editor/actions/Rect.gd @@ -0,0 +1,57 @@ +extends GEAction +class_name GERect + + +var mouse_start_pos = null + +func do_action(canvas, data: Array): + .do_action(canvas, data) + + if mouse_start_pos == null: + mouse_start_pos = data[0] + print("init:", mouse_start_pos) + + + action_data.undo.cells.clear() + action_data.undo.colors.clear() + action_data.preview.cells.clear() + action_data.preview.colors.clear() + canvas.clear_preview_layer() + + var p = mouse_start_pos + var s = data[0] - mouse_start_pos + var pixels = GEUtils.get_pixels_in_line(p, p + Vector2(s.x, 0)) + pixels += GEUtils.get_pixels_in_line(p, p + Vector2(0, s.y)) + pixels += GEUtils.get_pixels_in_line(p + s, p + s + Vector2(0, -s.y)) + pixels += GEUtils.get_pixels_in_line(p + s, p + s + Vector2(-s.x, 0)) + + for pixel in pixels: + canvas.set_preview_pixel_v(pixel, data[2]) + action_data.undo.cells.append(pixel) + action_data.undo.colors.append(canvas.get_pixel_v(pixel)) + action_data.preview.cells.append(pixel) + action_data.preview.colors.append(data[2]) + + +func commit_action(canvas): + canvas.clear_preview_layer() + var cells = action_data.preview.cells + var colors = action_data.preview.colors + for idx in range(cells.size()): + + canvas.set_pixel_v(cells[idx], colors[idx]) + + action_data.do.cells.append(cells[idx]) + action_data.do.colors.append(colors[idx]) + mouse_start_pos = null + return [] + + +func undo_action(canvas): + var cells = action_data.undo.cells + var colors = action_data.undo.colors + for idx in range(cells.size()): + canvas.set_pixel_v(cells[idx], colors[idx]) + + + diff --git a/project.godot b/project.godot index e64bf66..62a1385 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ _global_script_classes=[ { "base": "Reference", "class": "BrushPrefabs", "language": "GDScript", -"path": "res://addons/graphics_editor/Brush.gd" +"path": "res://addons/graphics_editor/BrushPrefabs.gd" }, { "base": "Node", "class": "GEAction", @@ -20,25 +20,60 @@ _global_script_classes=[ { "path": "res://addons/graphics_editor/actions/Action.gd" }, { "base": "GEAction", +"class": "GEBrighten", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Brighten.gd" +}, { +"base": "GEAction", "class": "GEBrush", "language": "GDScript", "path": "res://addons/graphics_editor/actions/Brush.gd" }, { +"base": "GEAction", +"class": "GEBucket", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Bucket.gd" +}, { "base": "Control", "class": "GECanvas", "language": "GDScript", "path": "res://addons/graphics_editor/Canvas.gd" }, { +"base": "GEAction", +"class": "GECut", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Cut.gd" +}, { +"base": "GEAction", +"class": "GEDarken", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Darken.gd" +}, { "base": "Reference", "class": "GELayer", "language": "GDScript", "path": "res://addons/graphics_editor/Layer.gd" }, { "base": "GEAction", +"class": "GELine", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Line.gd" +}, { +"base": "GEAction", "class": "GEPencil", "language": "GDScript", "path": "res://addons/graphics_editor/actions/Pencil.gd" }, { +"base": "GEAction", +"class": "GERainbow", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Rainbow.gd" +}, { +"base": "GEAction", +"class": "GERect", +"language": "GDScript", +"path": "res://addons/graphics_editor/actions/Rect.gd" +}, { "base": "Node", "class": "GEUtils", "language": "GDScript", @@ -47,10 +82,17 @@ _global_script_classes=[ { _global_script_class_icons={ "BrushPrefabs": "", "GEAction": "", +"GEBrighten": "", "GEBrush": "", +"GEBucket": "", "GECanvas": "", +"GECut": "", +"GEDarken": "", "GELayer": "", +"GELine": "", "GEPencil": "", +"GERainbow": "", +"GERect": "", "GEUtils": "" } @@ -59,12 +101,6 @@ _global_script_class_icons={ config/name="TestGDNative" config/icon="res://icon.png" -[autoload] - -Gdtest="*res://gdtest.gdns" -IconLoader="*res://addons/file-editor/scripts/IconLoader.gd" -LastOpenedFiles="*res://addons/file-editor/scripts/LastOpenedFiles.gd" - [editor_plugins] enabled=PoolStringArray( "godot-plugin-refresher", "graphics_editor" )