/* Copyright (c) 2019 Flairieve Copyright (c) 2020-2022 cobrapitz Copyright (c) 2022 Péter Magyar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "paint_canvas.h" #include "paint_canvas_outline.h" #include "paint_visual_grid.h" #include "scene/gui/control.h" #include "scene/gui/texture_rect.h" #include "paint_canvas_layer.h" void PaintCanvas::_enter_tree() { /* #------------------------------- # Set nodes #------------------------------- canvas = find_node("Canvas") grid = find_node("Grid") big_grid = find_node("BigGrid") canvas_layers = find_node("CanvasLayers") #------------------------------- # 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 active_layer = add_new_layer("Layer1") preview_layer = add_new_layer("Preview") tool_layer = add_new_layer("Tool") set_process(true) */ } void PaintCanvas::_process(float delta) { /* if not is_visible_in_tree(): return var mouse_position = get_local_mouse_position() var rect = Rect2(Vector2(0, 0), rect_size) mouse_in_region = rect.has_point(mouse_position) */ } void PaintCanvas::_draw() { /* for layer in layers: layer.update_texture() preview_layer.update_texture() tool_layer.update_texture() */ } int PaintCanvas::get_pixel_size() const { return _pixel_size; } void PaintCanvas::set_pixel_size(const int size) { /* pixel_size = size set_grid_size(grid_size) set_big_grid_size(big_grid_size) set_canvas_width(canvas_width) set_canvas_height(canvas_height) */ } int PaintCanvas::get_grid_size() const { return _grid_size; } void PaintCanvas::set_grid_size(const int size) { /* grid_size = size if not find_node("Grid"): return find_node("Grid").size = size * pixel_size */ } int PaintCanvas::get_big_grid_size() const { return _big_grid_size; } void PaintCanvas::set_big_grid_size(const int size) { /* big_grid_size = size if not find_node("BigGrid"): return find_node("BigGrid").size = size * pixel_size */ } int PaintCanvas::get_canvas_width() const { return _canvas_width; } void PaintCanvas::set_canvas_width(const int val) { /* canvas_width = val rect_size.x = canvas_width * pixel_size */ } int PaintCanvas::get_canvas_height() const { return _canvas_height; } void PaintCanvas::set_canvas_height(const int val) { /* canvas_height = val rect_size.y = canvas_height * pixel_size */ } void PaintCanvas::toggle_alpha_locked(const String &layer_name) { /* var layer = find_layer_by_name(layer_name) layer.toggle_alpha_locked() */ } bool PaintCanvas::is_alpha_locked() { /* return active_layer.alpha_locked */ return false; } Rect2 PaintCanvas::get_content_margin() { /* var rect = Rect2(999999, 999999, -999999, -999999) preview_layer.image.get_used_rect() for layer in layers: var r = layer.image.get_used_rect() if r.position.x < rect.position.x: rect.position.x = r.position.x if r.position.y < rect.position.y: rect.position.y = r.position.y if r.size.x > rect.size.x: rect.size.x = r.size.x if r.size.y > rect.size.y: rect.size.y = r.size.y return rect */ return Rect2(); } void PaintCanvas::crop_to_content() { /* var rect = get_content_margin() #print(rect) for layer in layers: layer.image # set_canvas_width(rect.size.x) # set_canvas_height(rect.size.x) # preview_layer.resize(width, height) # tool_layer.resize(width, height) # for layer in layers: # layer.resize(width, height) */ } Node *PaintCanvas::get_active_layer() { /* return active_layer */ return nullptr; } Node *PaintCanvas::get_preview_layer() { /* return preview_layer */ return nullptr; } void PaintCanvas::clear_active_layer() { /* active_layer.clear() */ } void PaintCanvas::clear_preview_layer() { /* preview_layer.clear() */ } void PaintCanvas::clear_layer(const String &layer_name) { /* for layer in layers: if layer.name == layer_name: layer.clear() break */ } Node *PaintCanvas::remove_layer(const String &layer_name) { /* # change current layer if the active layer is removed 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 or layer == active_layer or layer == tool_layer: continue active_layer = layer break layers.erase(del_layer) return active_layer */ return nullptr; } Node *PaintCanvas::add_new_layer(const String &layer_name) { /* for layer in layers: if layer.name == layer_name: return var layer = GELayer.new() layer.name = layer_name if layer_name == "Preview": layer.create($PreviewLayer, canvas_width, canvas_height) elif layer_name == "Tool": layer.create($ToolPreviewLayer, canvas_width, canvas_height) else: var texture_rect = TextureRect.new() texture_rect.name = layer_name canvas_layers.add_child(texture_rect, true) texture_rect.expand = true texture_rect.anchor_right = 1 texture_rect.anchor_bottom = 1 texture_rect.margin_right = 0 texture_rect.margin_bottom = 0 texture_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE layer.create(texture_rect, canvas_width, canvas_height) layers.append(layer) return layer */ return nullptr; } Node *PaintCanvas::duplicate_layer(const String &layer_name, const String &new_layer_name) { /* for layer in layers: if layer.name == new_layer_name: return var dup_layer :GELayer = find_layer_by_name(layer_name) var layer :GELayer = add_new_layer(new_layer_name) layer.image.copy_from(dup_layer.image) return layer */ return nullptr; } void PaintCanvas::toggle_layer_visibility(const String &layer_name) { /* for layer in layers: if layer.name == layer_name: layer.visible = not layer.visible */ } Node *PaintCanvas::find_layer_by_name(const String &layer_name) { /* for layer in layers: if layer.name == layer_name: return layer return null */ return nullptr; } void PaintCanvas::toggle_lock_layer(const String &layer_name) { /* find_layer_by_name(layer_name).toggle_lock() */ } bool PaintCanvas::is_active_layer_locked() { /* return active_layer.locked */ return false; } void PaintCanvas::move_layer_forward(const String &layer_name) { /* var layer = find_layer_by_name(layer_name).texture_rect_ref var new_idx = max(layer.get_index() - 1, 0) canvas_layers.move_child(layer, new_idx) */ } void PaintCanvas::move_layer_back(const String &layer_name) { /* var layer = find_layer_by_name(layer_name).texture_rect_ref canvas_layers.move_child(layer, layer.get_index() + 1) */ } void PaintCanvas::select_layer(const String &layer_name) { /* active_layer = find_layer_by_name(layer_name) */ } void PaintCanvas::_on_mouse_entered() { /* mouse_on_top = true */ } void PaintCanvas::_on_mouse_exited() { /* mouse_on_top = false */ } bool PaintCanvas::is_inside_canvas(const int x, const int y) { /* if x < 0 or y < 0: return false if x >= canvas_width or y >= canvas_height: return false return true */ return false; } //Note: Arrays are always passed by reference. To get a copy of an array which // can be modified independently of the original array, use duplicate. // (https://docs.godotengine.org/en/stable/classes/class_array.html) void PaintCanvas::set_pixel_arr(const Array &pixels, const Color &color) { /* for pixel in pixels: _set_pixel(active_layer, pixel.x, pixel.y, color) */ } void PaintCanvas::set_pixel_v(const Vector2 &pos, const Color &color) { /* set_pixel(pos.x, pos.y, color) */ } void PaintCanvas::set_pixel(const int x, const int y, const Color &color) { /* _set_pixel(active_layer, x, y, color) */ } void PaintCanvas::_set_pixel_v(PaintCanvasLayer *layer, const Vector2 &v, const Color &color) { /* _set_pixel(layer, v.x, v.y, color) */ } void PaintCanvas::_set_pixel(PaintCanvasLayer *layer, const int x, const int y, const Color &color) { /* if not is_inside_canvas(x, y): return layer.set_pixel(x, y, color) */ } Color PaintCanvas::get_pixel_v(const Vector2 &pos) { /* return get_pixel(pos.x, pos.y) */ return Color(); } Color PaintCanvas::get_pixel(const int x, const int y) { /* if active_layer: return active_layer.get_pixel(x, y) return null */ return Color(); } void PaintCanvas::set_preview_pixel_v(const Vector2 &pos, const Color &color) { /* set_preview_pixel(pos.x, pos.y, color) */ } void PaintCanvas::set_preview_pixel(const int x, const int y, const Color &color) { /* if not is_inside_canvas(x, y): return preview_layer.set_pixel(x, y, color) */ } Color PaintCanvas::get_preview_pixel_v(const Vector2 &pos) { /* return get_preview_pixel(pos.x, pos.y) */ return Color(); } Color PaintCanvas::get_preview_pixel(const int x, const int y) { /* if not preview_layer: return null return preview_layer.get_pixel(x, y) */ return Color(); } void PaintCanvas::toggle_grid() { /* $Grid.visible = not $Grid.visible */ } void PaintCanvas::show_grid() { /* $Grid.show() */ } void PaintCanvas::hide_grid() { /* $Grid.hide() */ } Array PaintCanvas::select_color(const int x, const int y) { /* print("???") var same_color_pixels = [] var color = get_pixel(x, y) for x in range(active_layer.layer_width): for y in range(active_layer.layer_height): var pixel_color = active_layer.get_pixel(x, y) if pixel_color == color: same_color_pixels.append(color) return same_color_pixels */ return Array(); } Array PaintCanvas::select_same_color(const int x, const int y) { /* return get_neighbouring_pixels(x, y) */ return Array(); } // returns array of Vector2 // yoinked from // https://www.geeksforgeeks.org/flood-fill-algorithm-implement-fill-paint/ Array PaintCanvas::get_neighbouring_pixels(const int pos_x, const int pos_y) { /* var pixels = [] var to_check_queue = [] var checked_queue = [] to_check_queue.append(GEUtils.to_1D(pos_x, pos_y, canvas_width)) var color = get_pixel(pos_x, pos_y) 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 # add to result pixels.append(p) # check neighbours var x = p.x - 1 var y = p.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 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 is_inside_canvas(x, y): idx = GEUtils.to_1D(x, y, canvas_width) to_check_queue.append(idx) y = p.y + 1 if is_inside_canvas(x, y): idx = GEUtils.to_1D(x, y, canvas_width) to_check_queue.append(idx) return pixels */ return Array(); } void PaintCanvas::resize(const int width, const int height) { /* if width < 0: width = 1 if height < 0: height = 1 set_canvas_width(width) set_canvas_height(height) preview_layer.resize(width, height) tool_layer.resize(width, height) for layer in layers: layer.resize(width, height) */ } PaintCanvas::PaintCanvas() { big_grid = nullptr; _pixel_size = 16; _canvas_width = 48; _canvas_height = 28; _grid_size = 16; _big_grid_size = 10; _can_draw = true; symmetry_x = false; symmetry_y = false; mouse_in_region = false; mouse_on_top = false; canvas_background_rect = memnew(TextureRect); //canvas_background_rect->set_texture();//res://addons/Godoxel/assets/grid.png canvas_background_rect->set_expand(true); canvas_background_rect->set_stretch_mode(TextureRect::STRETCH_TILE); add_child(canvas_background_rect); canvas_layers = memnew(Control); canvas_layers->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); add_child(canvas_layers); preview_layer_rect = memnew(TextureRect); preview_layer_rect->set_expand(true); preview_layer_rect->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); add_child(preview_layer_rect); tool_preview_layer_rect = memnew(TextureRect); tool_preview_layer_rect->set_expand(true); tool_preview_layer_rect->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); add_child(tool_preview_layer_rect); grid = memnew(PaintVisualGrid); grid->color = Color(1, 1, 1, 1); grid->size = 4; grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); add_child(grid); canvas_outline = memnew(PaintCanvasOutline); canvas_outline->color = Color(0, 1, 0, 1); canvas_outline->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); add_child(canvas_outline); } PaintCanvas::~PaintCanvas() { } void PaintCanvas::_bind_methods() { }