diff --git a/modules/paint/nodes/paint_node.cpp b/modules/paint/nodes/paint_node.cpp index c7d71466f..ebcd7eb9a 100644 --- a/modules/paint/nodes/paint_node.cpp +++ b/modules/paint/nodes/paint_node.cpp @@ -27,12 +27,37 @@ void PaintNode::set_draw_outline(const bool val) { update(); } -void PaintNode::save_image() { +Ref PaintNode::save_image() { _propagate_notification_project_pre_save(); - call("_save_image"); + Ref img = call("_save_image"); _propagate_notification_project_post_save(); + + return img; } -void PaintNode::_save_image() { +Ref PaintNode::_save_image() { + Ref image; + image.instance(); + + Vector2i size = get_size(); + + if (size.x <= 0 || size.y <= 0) { + return image; + } + + image->create(size.x, size.y, false, Image::FORMAT_RGBA8); + + for (int i = 0; i < get_child_count(); ++i) { + PaintNode *pn = Object::cast_to(get_child(i)); + + if (pn && pn->is_visible()) { + //dont apply own transform + save_evaluate_paint_node(pn, Transform2D(), image); + } + } + + save_paint_node(this, Transform2D(), image); + + return image; } Ref PaintNode::get_save_image() { @@ -42,6 +67,60 @@ Ref PaintNode::_get_save_image() { return Ref(); } +void PaintNode::save_evaluate_paint_node(PaintNode *node, Transform2D transform, Ref image) { + ERR_FAIL_COND(!node); + ERR_FAIL_COND(!image.is_valid()); + + Transform2D currtf = transform * node->get_transform(); + + for (int i = 0; i < node->get_child_count(); ++i) { + PaintNode *pn = Object::cast_to(node->get_child(i)); + + if (pn && pn->is_visible()) { + save_evaluate_paint_node(pn, currtf, image); + } + } + + save_paint_node(node, currtf, image); +} + +void PaintNode::save_paint_node(PaintNode *node, Transform2D transform, Ref image) { + ERR_FAIL_COND(!node); + ERR_FAIL_COND(!image.is_valid()); + + Ref save_image = node->get_save_image(); + + if (!save_image.is_valid() || save_image->empty()) { + return; + } + + Vector2i save_image_size = save_image->get_size(); + Vector2i image_size = image->get_size(); + + save_image->lock(); + image->lock(); + + //should return early eventually via a simple overlap check here + + for (int x = 0; x < save_image_size.x; ++x) { + for (int y = 0; y < save_image_size.y; ++y) { + Vector2i npos = transform.xform(Vector2(x, y)); + + if (npos.x < 0 || npos.y < 0 || npos.x >= image_size.x || npos.y >= image_size.y) { + continue; + } + + Color sic = save_image->get_pixel(x, y); + Color oic = image->get_pixel(npos.x, npos.y); + + image->set_pixel(npos.x, npos.y, oic.blend(sic)); + } + } + + image->unlock(); + save_image->unlock(); +} + PoolVector2iArray PaintNode::util_get_pixels_in_line(const Vector2i &from, const Vector2i &to) { return PaintUtilities::get_pixels_in_line(from, to); } @@ -203,11 +282,11 @@ void PaintNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_draw_outline", "val"), &PaintNode::set_draw_outline); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_outline"), "set_draw_outline", "get_draw_outline"); - BIND_VMETHOD(MethodInfo("_save_image")); + BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "r", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "_save_image")); ClassDB::bind_method(D_METHOD("save_image"), &PaintNode::save_image); ClassDB::bind_method(D_METHOD("_save_image"), &PaintNode::_save_image); - BIND_VMETHOD(MethodInfo("_get_save_image")); + BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "r", PROPERTY_HINT_RESOURCE_TYPE, "Image"), "_get_save_image")); ClassDB::bind_method(D_METHOD("get_save_image"), &PaintNode::get_save_image); ClassDB::bind_method(D_METHOD("_get_save_image"), &PaintNode::_get_save_image); diff --git a/modules/paint/nodes/paint_node.h b/modules/paint/nodes/paint_node.h index 011e9ecf4..caaa45325 100644 --- a/modules/paint/nodes/paint_node.h +++ b/modules/paint/nodes/paint_node.h @@ -23,12 +23,16 @@ public: bool get_draw_outline(); void set_draw_outline(const bool val); - void save_image(); - virtual void _save_image(); + //TODO rename to render image, and get rendered image! + Ref save_image(); + virtual Ref _save_image(); Ref get_save_image(); virtual Ref _get_save_image(); + void save_evaluate_paint_node(PaintNode *node, Transform2D transform, Ref image); + void save_paint_node(PaintNode *node, Transform2D transform, Ref image); + PoolVector2iArray util_get_pixels_in_line(const Vector2i &from, const Vector2i &to); int util_to_1d_v(const Vector2i &p, int w); diff --git a/modules/paint/nodes/paint_project.cpp b/modules/paint/nodes/paint_project.cpp index 23b3b139f..3ba5e407e 100644 --- a/modules/paint/nodes/paint_project.cpp +++ b/modules/paint/nodes/paint_project.cpp @@ -65,12 +65,14 @@ void PaintProject::set_colors_as_default() { } } -void PaintProject::_save_image() { +void PaintProject::save_image_to_file() { ERR_FAIL_COND(_save_file_name.empty()); - //create image - //collect and merge in all images returned by _get_save_image() in each PaintNode child - //save image + Ref img = save_image(); + + ERR_FAIL_COND(!img.is_valid()); + + img->save_png("res://" + _save_file_name); } void PaintProject::add_paint_canvas_backgorund() { @@ -117,7 +119,8 @@ void PaintProject::_bind_methods() { ClassDB::bind_method(D_METHOD("set_save_file_name", "size"), &PaintProject::set_save_file_name); ADD_PROPERTY(PropertyInfo(Variant::STRING, "save_file_name"), "set_save_file_name", "get_save_file_name"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "run_save_image", PROPERTY_HINT_BUTTON, "save_image"), "", ""); + ClassDB::bind_method(D_METHOD("save_image_to_file"), &PaintProject::save_image_to_file); + ADD_PROPERTY(PropertyInfo(Variant::NIL, "run_save_image", PROPERTY_HINT_BUTTON, "save_image_to_file"), "", ""); ClassDB::bind_method(D_METHOD("get_current_color"), &PaintProject::get_current_color); ClassDB::bind_method(D_METHOD("set_current_color", "size"), &PaintProject::set_current_color); diff --git a/modules/paint/nodes/paint_project.h b/modules/paint/nodes/paint_project.h index c13062857..1abd867cf 100644 --- a/modules/paint/nodes/paint_project.h +++ b/modules/paint/nodes/paint_project.h @@ -26,7 +26,7 @@ public: void set_colors_as_default(); - void _save_image(); + void save_image_to_file(); void add_paint_canvas_backgorund(); void add_paint_visual_grid();