diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index 99b1c2511..bc90882c9 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -33,6 +33,9 @@ {"name":"d3d_modifier","order":6,"path":"folders/nodes/data/3D/d3d_modifier.yy",}, {"name":"d3d_particle","order":7,"path":"folders/nodes/data/3D/d3d_particle.yy",}, {"name":"animation","order":13,"path":"folders/nodes/data/animation.yy",}, + {"name":"canvas","order":30,"path":"folders/nodes/data/canvas.yy",}, + {"name":"tools","order":5,"path":"folders/nodes/data/canvas/tools.yy",}, + {"name":"util","order":7,"path":"folders/nodes/data/canvas/util.yy",}, {"name":"compose","order":14,"path":"folders/nodes/data/compose.yy",}, {"name":"dynasurf","order":15,"path":"folders/nodes/data/dynasurf.yy",}, {"name":"filter","order":16,"path":"folders/nodes/data/filter.yy",}, @@ -252,6 +255,8 @@ {"name":"__background_set_element","order":3,"path":"scripts/__background_set_element/__background_set_element.yy",}, {"name":"__bbox","order":5,"path":"scripts/__bbox/__bbox.yy",}, {"name":"__bone","order":2,"path":"scripts/__bone/__bone.yy",}, + {"name":"__canvas_brush","order":2,"path":"scripts/__canvas_brush/__canvas_brush.yy",}, + {"name":"__canvas_tool","order":1,"path":"scripts/__canvas_tool/__canvas_tool.yy",}, {"name":"__d3d_gizmo","order":2,"path":"scripts/__d3d_gizmo/__d3d_gizmo.yy",}, {"name":"__d3d11_cbuffer","order":1,"path":"scripts/__d3d11_cbuffer/__d3d11_cbuffer.yy",}, {"name":"__d3d11_shader","order":2,"path":"scripts/__d3d11_shader/__d3d11_shader.yy",}, @@ -340,6 +345,17 @@ {"name":"buttonGroup","order":3,"path":"scripts/buttonGroup/buttonGroup.yy",}, {"name":"buttonPalette","order":4,"path":"scripts/buttonPalette/buttonPalette.yy",}, {"name":"byte_writer","order":8,"path":"scripts/byte_writer/byte_writer.yy",}, + {"name":"canvas_fix_points","order":1,"path":"scripts/canvas_fix_points/canvas_fix_points.yy",}, + {"name":"canvas_flood_fill_functions","order":2,"path":"scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.yy",}, + {"name":"canvas_freeform","order":3,"path":"scripts/canvas_freeform/canvas_freeform.yy",}, + {"name":"canvas_magic_selection_functions","order":4,"path":"scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.yy",}, + {"name":"canvas_tool_brush_shape","order":3,"path":"scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.yy",}, + {"name":"canvas_tool_draw_freeform","order":5,"path":"scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.yy",}, + {"name":"canvas_tool_fill","order":4,"path":"scripts/canvas_tool_fill/canvas_tool_fill.yy",}, + {"name":"canvas_tool_selection_freeform","order":8,"path":"scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.yy",}, + {"name":"canvas_tool_selection_magic","order":9,"path":"scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.yy",}, + {"name":"canvas_tool_selection_shape","order":6,"path":"scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.yy",}, + {"name":"canvas_tool_selection","order":7,"path":"scripts/canvas_tool_selection/canvas_tool_selection.yy",}, {"name":"checkboxActive","order":11,"path":"scripts/checkboxActive/checkboxActive.yy",}, {"name":"checkboxGroup","order":6,"path":"scripts/checkboxGroup/checkboxGroup.yy",}, {"name":"collection_data","order":9,"path":"scripts/collection_data/collection_data.yy",}, @@ -643,7 +659,6 @@ {"name":"node_cache_base","order":18,"path":"scripts/node_cache_base/node_cache_base.yy",}, {"name":"node_cache","order":9,"path":"scripts/node_cache/node_cache.yy",}, {"name":"node_camera","order":3,"path":"scripts/node_camera/node_camera.yy",}, - {"name":"node_canvas","order":17,"path":"scripts/node_canvas/node_canvas.yy",}, {"name":"node_caustic","order":1,"path":"scripts/node_caustic/node_caustic.yy",}, {"name":"node_cellular","order":2,"path":"scripts/node_cellular/node_cellular.yy",}, {"name":"node_chromatic_aberration","order":3,"path":"scripts/node_chromatic_aberration/node_chromatic_aberration.yy",}, @@ -1303,6 +1318,7 @@ {"name":"sh_flip","order":7,"path":"shaders/sh_flip/sh_flip.yy",}, {"name":"sh_flood_fill_it","order":1,"path":"shaders/sh_flood_fill_it/sh_flood_fill_it.yy",}, {"name":"sh_flood_fill_replace","order":2,"path":"shaders/sh_flood_fill_replace/sh_flood_fill_replace.yy",}, + {"name":"sh_freeform_fill_cleanup","order":2,"path":"shaders/sh_freeform_fill_cleanup/sh_freeform_fill_cleanup.yy",}, {"name":"sh_freeform_fill_pass2","order":1,"path":"shaders/sh_freeform_fill_pass2/sh_freeform_fill_pass2.yy",}, {"name":"sh_FXAA","order":29,"path":"shaders/sh_FXAA/sh_FXAA.yy",}, {"name":"sh_gamma_map","order":38,"path":"shaders/sh_gamma_map/sh_gamma_map.yy",}, @@ -1444,7 +1460,7 @@ {"name":"sh_widget_rotator_range","order":5,"path":"shaders/sh_widget_rotator_range/sh_widget_rotator_range.yy",}, {"name":"sh_widget_rotator","order":4,"path":"shaders/sh_widget_rotator/sh_widget_rotator.yy",}, {"name":"sh_zigzag","order":2,"path":"shaders/sh_zigzag/sh_zigzag.yy",}, - {"name":"sh_freeform_fill_cleanup","order":2,"path":"shaders/sh_freeform_fill_cleanup/sh_freeform_fill_cleanup.yy",}, + {"name":"sh_canvas_mask","order":10,"path":"shaders/sh_canvas_mask/sh_canvas_mask.yy",}, {"name":"credit_badge_popular","order":2,"path":"sprites/credit_badge_popular/credit_badge_popular.yy",}, {"name":"credit_badge_value","order":1,"path":"sprites/credit_badge_value/credit_badge_value.yy",}, {"name":"s_biterator_b_grey_long","order":7,"path":"sprites/s_biterator_b_grey_long/s_biterator_b_grey_long.yy",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index b0b98772e..3218029f4 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -129,6 +129,9 @@ {"$GMFolder":"","%Name":"d3d_modifier","folderPath":"folders/nodes/data/3D/d3d_modifier.yy","name":"d3d_modifier","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"d3d_particle","folderPath":"folders/nodes/data/3D/d3d_particle.yy","name":"d3d_particle","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"animation","folderPath":"folders/nodes/data/animation.yy","name":"animation","resourceType":"GMFolder","resourceVersion":"2.0",}, + {"$GMFolder":"","%Name":"canvas","folderPath":"folders/nodes/data/canvas.yy","name":"canvas","resourceType":"GMFolder","resourceVersion":"2.0",}, + {"$GMFolder":"","%Name":"tools","folderPath":"folders/nodes/data/canvas/tools.yy","name":"tools","resourceType":"GMFolder","resourceVersion":"2.0",}, + {"$GMFolder":"","%Name":"util","folderPath":"folders/nodes/data/canvas/util.yy","name":"util","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"compose","folderPath":"folders/nodes/data/compose.yy","name":"compose","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"armature","folderPath":"folders/nodes/data/compose/armature.yy","name":"armature","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"dynasurf","folderPath":"folders/nodes/data/dynasurf.yy","name":"dynasurf","resourceType":"GMFolder","resourceVersion":"2.0",}, @@ -589,6 +592,8 @@ {"id":{"name":"__background_set_element","path":"scripts/__background_set_element/__background_set_element.yy",},}, {"id":{"name":"__bbox","path":"scripts/__bbox/__bbox.yy",},}, {"id":{"name":"__bone","path":"scripts/__bone/__bone.yy",},}, + {"id":{"name":"__canvas_brush","path":"scripts/__canvas_brush/__canvas_brush.yy",},}, + {"id":{"name":"__canvas_tool","path":"scripts/__canvas_tool/__canvas_tool.yy",},}, {"id":{"name":"__d3d_gizmo","path":"scripts/__d3d_gizmo/__d3d_gizmo.yy",},}, {"id":{"name":"__d3d11_cbuffer","path":"scripts/__d3d11_cbuffer/__d3d11_cbuffer.yy",},}, {"id":{"name":"__d3d11_shader","path":"scripts/__d3d11_shader/__d3d11_shader.yy",},}, @@ -698,6 +703,19 @@ {"id":{"name":"buttonPalette","path":"scripts/buttonPalette/buttonPalette.yy",},}, {"id":{"name":"byte_reader","path":"scripts/byte_reader/byte_reader.yy",},}, {"id":{"name":"byte_writer","path":"scripts/byte_writer/byte_writer.yy",},}, + {"id":{"name":"canvas_draw_functions","path":"scripts/canvas_draw_functions/canvas_draw_functions.yy",},}, + {"id":{"name":"canvas_fix_points","path":"scripts/canvas_fix_points/canvas_fix_points.yy",},}, + {"id":{"name":"canvas_flood_fill_functions","path":"scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.yy",},}, + {"id":{"name":"canvas_freeform","path":"scripts/canvas_freeform/canvas_freeform.yy",},}, + {"id":{"name":"canvas_magic_selection_functions","path":"scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.yy",},}, + {"id":{"name":"canvas_tool_brush_shape","path":"scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.yy",},}, + {"id":{"name":"canvas_tool_brush","path":"scripts/canvas_tool_brush/canvas_tool_brush.yy",},}, + {"id":{"name":"canvas_tool_draw_freeform","path":"scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.yy",},}, + {"id":{"name":"canvas_tool_fill","path":"scripts/canvas_tool_fill/canvas_tool_fill.yy",},}, + {"id":{"name":"canvas_tool_selection_freeform","path":"scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.yy",},}, + {"id":{"name":"canvas_tool_selection_magic","path":"scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.yy",},}, + {"id":{"name":"canvas_tool_selection_shape","path":"scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.yy",},}, + {"id":{"name":"canvas_tool_selection","path":"scripts/canvas_tool_selection/canvas_tool_selection.yy",},}, {"id":{"name":"checkbox","path":"scripts/checkbox/checkbox.yy",},}, {"id":{"name":"checkboxActive","path":"scripts/checkboxActive/checkboxActive.yy",},}, {"id":{"name":"checkboxGroup","path":"scripts/checkboxGroup/checkboxGroup.yy",},}, @@ -1816,6 +1834,7 @@ {"id":{"name":"sh_flood_fill_replace","path":"shaders/sh_flood_fill_replace/sh_flood_fill_replace.yy",},}, {"id":{"name":"sh_flood_fill_thres","path":"shaders/sh_flood_fill_thres/sh_flood_fill_thres.yy",},}, {"id":{"name":"sh_fluid_bleach","path":"shaders/sh_fluid_bleach/sh_fluid_bleach.yy",},}, + {"id":{"name":"sh_freeform_fill_cleanup","path":"shaders/sh_freeform_fill_cleanup/sh_freeform_fill_cleanup.yy",},}, {"id":{"name":"sh_freeform_fill_pass1","path":"shaders/sh_freeform_fill_pass1/sh_freeform_fill_pass1.yy",},}, {"id":{"name":"sh_freeform_fill_pass2","path":"shaders/sh_freeform_fill_pass2/sh_freeform_fill_pass2.yy",},}, {"id":{"name":"sh_FXAA","path":"shaders/sh_FXAA/sh_FXAA.yy",},}, @@ -1981,7 +2000,7 @@ {"id":{"name":"sh_widget_rotator_range","path":"shaders/sh_widget_rotator_range/sh_widget_rotator_range.yy",},}, {"id":{"name":"sh_widget_rotator","path":"shaders/sh_widget_rotator/sh_widget_rotator.yy",},}, {"id":{"name":"sh_zigzag","path":"shaders/sh_zigzag/sh_zigzag.yy",},}, - {"id":{"name":"sh_freeform_fill_cleanup","path":"shaders/sh_freeform_fill_cleanup/sh_freeform_fill_cleanup.yy",},}, + {"id":{"name":"sh_canvas_mask","path":"shaders/sh_canvas_mask/sh_canvas_mask.yy",},}, {"id":{"name":"credit_badge_popular","path":"sprites/credit_badge_popular/credit_badge_popular.yy",},}, {"id":{"name":"credit_badge_value","path":"sprites/credit_badge_value/credit_badge_value.yy",},}, {"id":{"name":"node_credit","path":"sprites/node_credit/node_credit.yy",},}, diff --git a/datafiles/data/Theme.zip b/datafiles/data/Theme.zip index bb0d85242..a1fcec56f 100644 Binary files a/datafiles/data/Theme.zip and b/datafiles/data/Theme.zip differ diff --git a/objects/o_dialog_palette/Create_0.gml b/objects/o_dialog_palette/Create_0.gml index 011150f5c..8e6807527 100644 --- a/objects/o_dialog_palette/Create_0.gml +++ b/objects/o_dialog_palette/Create_0.gml @@ -99,6 +99,9 @@ event_inherited(); hovering = pal; menuCall("palette_window_preset_menu",,, [ + menuItem(__txtx("palette_editor_set_default", "Set as default"), function() { + DEF_PALETTE = array_clone(hovering.palette); + }), menuItem(__txtx("palette_editor_delete", "Delete palette"), function() { file_delete(hovering.path); __initPalette(); diff --git a/objects/o_main/Draw_64.gml b/objects/o_main/Draw_64.gml index a17dac439..975ddbf3e 100644 --- a/objects/o_main/Draw_64.gml +++ b/objects/o_main/Draw_64.gml @@ -60,7 +60,7 @@ draw_clear(COLORS.bg); winManDraw(); #endregion -if(APP_SURF_OVERRIDE) { +if(APP_SURF_OVERRIDE) { #region surface_reset_target(); draw_surface(POST_APP_SURF, 0, 0); @@ -71,4 +71,4 @@ if(APP_SURF_OVERRIDE) { surface_set_target(POST_APP_SURF); draw_surface(APP_SURF, 0, 0); surface_reset_target(); -} \ No newline at end of file +} #endregion \ No newline at end of file diff --git a/scripts/__canvas_brush/__canvas_brush.gml b/scripts/__canvas_brush/__canvas_brush.gml new file mode 100644 index 000000000..37a431b37 --- /dev/null +++ b/scripts/__canvas_brush/__canvas_brush.gml @@ -0,0 +1,82 @@ +function canvas_brush() constructor { + brush_sizing = false; + brush_sizing_s = 0; + brush_sizing_mx = 0; + brush_sizing_my = 0; + brush_sizing_dx = 0; + brush_sizing_dy = 0; + + brush_surface = noone; + brush_size = 1; + brush_dist_min = 1; + brush_dist_max = 1; + brush_direction = 0; + brush_rand_dir = [ 0, 0, 0, 0, 0 ]; + brush_seed = irandom_range(100000, 999999); + brush_next_dist = 0; + + mouse_pre_dir_x = undefined; + mouse_pre_dir_y = undefined; + + node = noone; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + var _brushSurf = node.getInputData(6); + var _brushDist = node.getInputData(15); + var _brushRotD = node.getInputData(16); + var _brushRotR = node.getInputData(17); + + var attr = node.tool_attribute; + var _col = attr.color; + var _siz = attr.size; + + brush_size = _siz; + + if(brush_size = PEN_USE && attr.pressure) + brush_size = round(lerp(attr.pressure_size[0], attr.pressure_size[1], power(PEN_PRESSURE / 1024, 2))); + + brush_dist_min = max(1, _brushDist[0]); + brush_dist_max = max(1, _brushDist[1]); + brush_surface = is_surface(_brushSurf)? _brushSurf : noone; + + if(!_brushRotD) + brush_direction = 0; + + else if(mouse_pre_dir_x == undefined) { + mouse_pre_dir_x = _mx; + mouse_pre_dir_y = _my; + + } else if(point_distance(mouse_pre_dir_x, mouse_pre_dir_y, _mx, _my) > _s) { + brush_direction = point_direction(mouse_pre_dir_x, mouse_pre_dir_y, _mx, _my); + mouse_pre_dir_x = _mx; + mouse_pre_dir_y = _my; + } + + brush_rand_dir = _brushRotR; + } + + function sizing(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + var attr = node.tool_attribute; + var _siz = attr.size; + + if(brush_sizing) { + var s = brush_sizing_s + (_mx - brush_sizing_mx) / 16; + s = max(1, s); + attr.size = s; + + if(mouse_release(mb_right)) + brush_sizing = false; + + } else if(mouse_press(mb_right, active) && key_mod_press(SHIFT) && brush_surface == noone) { + + brush_sizing = true; + brush_sizing_s = _siz; + brush_sizing_mx = _mx; + brush_sizing_my = _my; + + brush_sizing_dx = round((_mx - _x) / _s - 0.5); + brush_sizing_dy = round((_my - _y) / _s - 0.5); + } + } +} \ No newline at end of file diff --git a/scripts/__canvas_brush/__canvas_brush.yy b/scripts/__canvas_brush/__canvas_brush.yy new file mode 100644 index 000000000..fb76b0a14 --- /dev/null +++ b/scripts/__canvas_brush/__canvas_brush.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"__canvas_brush", + "isCompatibility":false, + "isDnD":false, + "name":"__canvas_brush", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/__canvas_tool/__canvas_tool.gml b/scripts/__canvas_tool/__canvas_tool.gml new file mode 100644 index 000000000..a0cd59bfb --- /dev/null +++ b/scripts/__canvas_tool/__canvas_tool.gml @@ -0,0 +1,30 @@ +function canvas_tool() constructor { + + node = noone; + relative = false; + + relative_position = [ 0, 0 ]; + drawing_surface = noone; + _canvas_surface = noone; + apply_draw_surface = noone; + + brush_resizable = false; + mouse_holding = false; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + } + + function drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + } + + function drawPostOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + } + +} \ No newline at end of file diff --git a/scripts/__canvas_tool/__canvas_tool.yy b/scripts/__canvas_tool/__canvas_tool.yy new file mode 100644 index 000000000..f7ff37bdc --- /dev/null +++ b/scripts/__canvas_tool/__canvas_tool.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"__canvas_tool", + "isCompatibility":false, + "isDnD":false, + "name":"__canvas_tool", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_draw_functions/canvas_draw_functions.gml b/scripts/canvas_draw_functions/canvas_draw_functions.gml new file mode 100644 index 000000000..7f56e2201 --- /dev/null +++ b/scripts/canvas_draw_functions/canvas_draw_functions.gml @@ -0,0 +1,159 @@ +function canvas_draw_point_size(brush, _x, _y, _draw = false) { #region + if(brush.brush_surface == noone) { + + if(brush.brush_size <= 1) + draw_point(_x, _y); + + else if(brush.brush_size < global.FIX_POINTS_AMOUNT) { + var fx = global.FIX_POINTS[brush.brush_size]; + for( var i = 0, n = array_length(fx); i < n; i++ ) + draw_point(_x + fx[i][0], _y + fx[i][1]); + + } else + draw_circle_prec(_x, _y, brush.brush_size / 2, 0); + + } else { + var _sw = surface_get_width_safe(brush.brush_surface); + var _sh = surface_get_height_safe(brush.brush_surface); + var _r = brush.brush_direction + angle_random_eval(brush.brush_rand_dir, brush.brush_seed); + var _p = point_rotate(-_sw / 2, -_sh / 2, 0, 0, _r); + + draw_surface_ext_safe(brush.brush_surface, _x + _p[0], _y + _p[1], 1, 1, _r, draw_get_color(), draw_get_alpha()); + + if(_draw) brush.brush_seed = irandom_range(100000, 999999); + } +} #endregion + +function canvas_draw_line_size(brush, _x0, _y0, _x1, _y1, _draw = false) { #region + + if(brush.brush_surface == noone) { + + if(brush.brush_size < global.FIX_POINTS_AMOUNT) { + if(_x1 > _x0) _x0--; + if(_y1 > _y0) _y0--; + if(_y1 < _y0) _y1--; + if(_x1 < _x0) _x1--; + } + + if(brush.brush_size == 1) { + draw_line(_x0, _y0, _x1, _y1); + + } else if(brush.brush_size < global.FIX_POINTS_AMOUNT) { + + var fx = global.FIX_POINTS[brush.brush_size]; + for( var i = 0, n = array_length(fx); i < n; i++ ) + draw_line(_x0 + fx[i][0], _y0 + fx[i][1], _x1 + fx[i][0], _y1 + fx[i][1]); + + } else + draw_line_width(_x0, _y0, _x1, _y1, brush.brush_size); + + } else { + var diss = point_distance(_x0, _y0, _x1, _y1); + var dirr = point_direction(_x0, _y0, _x1, _y1); + var st_x = lengthdir_x(1, dirr); + var st_y = lengthdir_y(1, dirr); + + var _i = _draw? brush.brush_next_dist : 0; + var _dst = diss; + + if(_i < diss) { + while(_i < diss) { + var _px = _x0 + st_x * _i; + var _py = _y0 + st_y * _i; + + canvas_draw_point_size(brush, _px, _py, _draw); + + brush.brush_next_dist = random_range(brush.brush_dist_min, brush.brush_dist_max); + _i += brush.brush_next_dist; + _dst -= brush.brush_next_dist; + } + + brush.brush_next_dist -= _dst; + } else + brush.brush_next_dist -= diss; + + if(brush.brush_dist_min == brush.brush_dist_max && brush.brush_dist_min == 1) + canvas_draw_point_size(brush, _x1, _y1, _draw); + } +} #endregion + +function canvas_draw_rect_size(brush, _x0, _y0, _x1, _y1, _fill) { #region + if(_x0 == _x1 && _y0 == _y1) { + canvas_draw_point_size(brush, _x0, _y0); + return; + + } else if(_x0 == _x1) { + canvas_draw_point_size(brush, _x0, _y0); + canvas_draw_point_size(brush, _x1, _y1); + canvas_draw_line_size(brush, _x0, _y0, _x0, _y1); + return; + + } else if(_y0 == _y1) { + canvas_draw_point_size(brush, _x0, _y0); + canvas_draw_point_size(brush, _x1, _y1); + canvas_draw_line_size(brush, _x0, _y0, _x1, _y0); + return; + } + + var _min_x = min(_x0, _x1); + var _max_x = max(_x0, _x1); + var _min_y = min(_y0, _y1); + var _may_y = max(_y0, _y1); + + if(_fill) draw_rectangle(_min_x, _min_y, _max_x, _may_y, 0); + + if(brush.brush_size == 1 && brush.brush_surface == noone) + draw_rectangle(_min_x + 1, _min_y + 1, _max_x - 1, _may_y - 1, 1); + else { + canvas_draw_line_size(brush, _min_x, _min_y, _max_x, _min_y); + canvas_draw_line_size(brush, _min_x, _min_y, _min_x, _may_y); + canvas_draw_line_size(brush, _max_x, _may_y, _max_x, _min_y); + canvas_draw_line_size(brush, _max_x, _may_y, _min_x, _may_y); + } +} #endregion + +function canvas_draw_ellp_size(brush, _x0, _y0, _x1, _y1, _fill) { #region + if(_x0 == _x1 && _y0 == _y1) { + canvas_draw_point_size(brush, _x0, _y0); + return; + + } else if(_x0 == _x1) { + canvas_draw_point_size(brush, _x0, _y0); + canvas_draw_point_size(brush, _x1, _y1); + canvas_draw_line_size(brush, _x0, _y0, _x0, _y1); + return; + + } else if(_y0 == _y1) { + canvas_draw_point_size(brush, _x0, _y0); + canvas_draw_point_size(brush, _x1, _y1); + canvas_draw_line_size(brush, _x0, _y0, _x1, _y0); + return; + } + + var _min_x = min(_x0, _x1) - 1; + var _max_x = max(_x0, _x1); + var _min_y = min(_y0, _y1) - 1; + var _max_y = max(_y0, _y1); + + if(_fill) { + draw_set_circle_precision(64); + draw_ellipse(_min_x, _min_y, _max_x, _max_y, 0); + } + + var samp = 64; + var cx = (_min_x + _max_x) / 2; + var cy = (_min_y + _max_y) / 2; + var rx = abs(_x0 - _x1) / 2; + var ry = abs(_y0 - _y1) / 2; + + var ox, oy, nx, ny; + for( var i = 0; i <= samp; i++ ) { + nx = round(cx + lengthdir_x(rx, 360 / samp * i)); + ny = round(cy + lengthdir_y(ry, 360 / samp * i)); + + if(i) canvas_draw_line_size(brush, ox, oy, nx, ny); + + ox = nx; + oy = ny; + } +} #endregion diff --git a/scripts/canvas_draw_functions/canvas_draw_functions.yy b/scripts/canvas_draw_functions/canvas_draw_functions.yy new file mode 100644 index 000000000..984f09c0a --- /dev/null +++ b/scripts/canvas_draw_functions/canvas_draw_functions.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_draw_functions", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_draw_functions", + "parent":{ + "name":"util", + "path":"folders/nodes/data/canvas/util.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_fix_points/canvas_fix_points.gml b/scripts/canvas_fix_points/canvas_fix_points.gml new file mode 100644 index 000000000..f4b76b35a --- /dev/null +++ b/scripts/canvas_fix_points/canvas_fix_points.gml @@ -0,0 +1,33 @@ + +#region fix size points + global.FIX_POINTS = []; + + global.FIX_POINTS[0] = []; + global.FIX_POINTS[1] = []; + global.FIX_POINTS[2] = [[ 0, 0 ], [ 1, 0 ], [ 0, 1 ], [ 1, 1 ]]; + global.FIX_POINTS[3] = [[ 0, 0 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ], [ 0, 1 ]]; + global.FIX_POINTS[4] = [[ 0, 0 ], [ -1, 0 ], [ 0, -1 ], [ -1, -1 ], [ -2, -1 ], [ -2, 0 ], [ -1, -2 ], [ 0, -2 ], [ 1, -1 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ]]; + global.FIX_POINTS[5] = [ + [ 0, 0 ], + [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], + [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ 2, 1 ], + ]; + global.FIX_POINTS[6] = [ + [ 0, 0 ], + [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], + [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ -2, -2 ], + [ -1, -3 ], [ 0, -3 ], [ -3, -1 ], [ -3, 0 ], + ]; + global.FIX_POINTS[7] = [ + [ 0, 0 ], + [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], + [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ 2, 1 ], [ -2, -2 ], [ 2, -2 ], [ -2, 2 ], [ 2, 2 ], + [ -1, -3 ], [ 0, -3 ], [ 1, -3 ], [ -1, 3 ], [ 0, 3 ], [ 1, 3 ], [ -3, -1 ], [ -3, 0 ], [ -3, 1 ], [ 3, -1 ], [ 3, 0 ], [ 3, 1 ], + ]; + + global.FIX_POINTS[8] = array_append(variable_clone(global.FIX_POINTS[7]), [ [-4, -2], [-4, -1], [-4, 0], [-4, 1], [-3, -3], [-3, -2], [-3, 2], [-2, -4], [-2, -3], [-2, 3], [-1, -4], [0, -4], [1, -4], [2, -3], [3, -2] ]); + global.FIX_POINTS[9] = array_append(variable_clone(global.FIX_POINTS[7]), [ [-4, -1], [-4, 0], [-4, 1], [-3, -2], [-3, -2], [-3, 2], [-2, -3], [-2, 3], [-1, -4], [-1, 4], [0, -4], [0, 4], [1, -4], [1, 4], [2, -3], [2, 3], [3, -2], [3, 2], [4, -1], [4, 0], [4, 1] ]); + + global.FIX_POINTS_AMOUNT = array_length(global.FIX_POINTS); +#endregion + \ No newline at end of file diff --git a/scripts/canvas_fix_points/canvas_fix_points.yy b/scripts/canvas_fix_points/canvas_fix_points.yy new file mode 100644 index 000000000..965274c49 --- /dev/null +++ b/scripts/canvas_fix_points/canvas_fix_points.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_fix_points", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_fix_points", + "parent":{ + "name":"util", + "path":"folders/nodes/data/canvas/util.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.gml b/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.gml new file mode 100644 index 000000000..d8117758f --- /dev/null +++ b/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.gml @@ -0,0 +1,104 @@ +function _ff_getPixel(_x, _y) { return buffer_read_at(_ff_buff, (_y * _ff_w + _x) * 4, buffer_u32); } + +function canvas_ff_fillable(colorBase, colorFill, _x, _y, _thres) { #region + var c = _ff_getPixel(_x, _y); + var d = color_diff(colorBase, c, true, true); + return d <= _thres && c != colorFill; +} #endregion + +function canvas_flood_fill_scanline(_surf, _x, _y, _thres, _corner = false) { #region + var colorFill = tool_attribute.color; + var colorBase = surface_getpixel_ext(_surf, _x, _y); + + if(colorFill == colorBase) return; //Clicking on the same color as the fill color + + var _c = tool_attribute.color; + draw_set_color(_c); + + _ff_w = surface_get_width(_surf); + _ff_h = surface_get_height(_surf); + _ff_buff = buffer_create(_ff_w * _ff_h * 4, buffer_fixed, 4); + buffer_get_surface(_ff_buff, _surf, 0); + + var x1, y1, x_start; + var spanAbove, spanBelow; + var thr = _thres * _thres; + + var queue = ds_queue_create(); + ds_queue_enqueue(queue, [_x, _y]); + + while(!ds_queue_empty(queue)) { + var pos = ds_queue_dequeue(queue); + x1 = pos[0]; + y1 = pos[1]; + + if(_ff_getPixel(x1, y1) == colorFill) continue; //Color in queue is already filled + + while(x1 > 0 && canvas_ff_fillable(colorBase, colorFill, x1 - 1, y1, thr)) //Move to the leftmost connected pixel in the same row. + x1--; + x_start = x1; + + spanAbove = false; + spanBelow = false; + + while(x1 < surface_w && canvas_ff_fillable(colorBase, colorFill, x1, y1, thr)) { + draw_point(x1, y1); + buffer_seek(_ff_buff, buffer_seek_start, (y1 * _ff_w + x1) * 4) + buffer_write(_ff_buff, buffer_u32, _c); + + if(y1 > 0) { + if(_corner && x1 > 0 && canvas_ff_fillable(colorBase, colorFill, x1 - 1, y1 - 1, thr)) //Check top left pixel + ds_queue_enqueue(queue, [x1 - 1, y1 - 1]); + + if(canvas_ff_fillable(colorBase, colorFill, x1, y1 - 1, thr)) //Check top pixel + ds_queue_enqueue(queue, [x1, y1 - 1]); + } + + if(y1 < surface_h - 1) { + if(_corner && x1 > 0 && canvas_ff_fillable(colorBase, colorFill, x1 - 1, y1 + 1, thr)) //Check bottom left pixel + ds_queue_enqueue(queue, [x1 - 1, y1 + 1]); + + if(canvas_ff_fillable(colorBase, colorFill, x1, y1 + 1, thr)) //Check bottom pixel + ds_queue_enqueue(queue, [x1, y1 + 1]); + } + + if(_corner && x1 < surface_w - 1) { + if(y1 > 0 && canvas_ff_fillable(colorBase, colorFill, x1 + 1, y1 - 1, thr)) //Check top right pixel + ds_queue_enqueue(queue, [x1 + 1, y1 - 1]); + + if(y1 < surface_h - 1 && canvas_ff_fillable(colorBase, colorFill, x1 + 1, y1 + 1, thr)) //Check bottom right pixel + ds_queue_enqueue(queue, [x1 + 1, y1 + 1]); + } + + x1++; + } + } + + draw_set_alpha(1); + buffer_delete(_ff_buff); +} #endregion + +function canvas_fill(_x, _y, _surf, _thres) { #region + var _alp = _color_get_alpha(tool_attribute.color); + + var w = surface_get_width_safe(_surf); + var h = surface_get_height_safe(_surf); + + var _c1 = surface_getpixel_ext(_surf, _x, _y); + var thr = _thres * _thres; + + draw_set_alpha(_alp); + for( var i = 0; i < w; i++ ) { + for( var j = 0; j < h; j++ ) { + if(i == _x && j == _y) { + draw_point(i, j); + continue; + } + + var _c2 = surface_getpixel_ext(_surf, i, j); + if(color_diff(_c1, _c2, true) <= thr) + draw_point(i, j); + } + } + draw_set_alpha(1); +} #endregion diff --git a/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.yy b/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.yy new file mode 100644 index 000000000..389e10f1d --- /dev/null +++ b/scripts/canvas_flood_fill_functions/canvas_flood_fill_functions.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_flood_fill_functions", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_flood_fill_functions", + "parent":{ + "name":"util", + "path":"folders/nodes/data/canvas/util.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_freeform/canvas_freeform.gml b/scripts/canvas_freeform/canvas_freeform.gml new file mode 100644 index 000000000..da3dac4d7 --- /dev/null +++ b/scripts/canvas_freeform/canvas_freeform.gml @@ -0,0 +1,71 @@ +function canvas_freeform_step(active, _x, _y, _s, _mx, _my, _draw) { #region + var _dim = attributes.dimension; + + var _mmx = (_mx - _x) / _s; + var _mmy = (_my - _y) / _s; + + if(mouse_holding) { + if(abs(_mmx - mouse_pre_x) + abs(_mmy - mouse_pre_y) >= 1) { + + if(_draw) { + surface_set_target(drawing_surface); + canvas_draw_line_size(brush, round(mouse_pre_x - 0.5), round(mouse_pre_y - 0.5), round(_mmx - 0.5), round(_mmy - 0.5), true); + surface_reset_target(); + } + + mouse_pre_x = _mmx; + mouse_pre_y = _mmy; + + array_push(freeform_shape, new __vec2(_mmx, _mmy) ); + } + + if(mouse_release(mb_left)) { + + surface_set_target(drawing_surface); + canvas_draw_line_size(brush, _mmx, _mmy, freeform_shape[0].x, freeform_shape[0].y, true); + surface_reset_target(); + + if(array_length(freeform_shape) > 3) { + var _triangles = polygon_triangulate(freeform_shape, 1); + + var temp_surface = surface_create(_dim[0], _dim[1]); + + surface_set_target(temp_surface); + DRAW_CLEAR + + draw_primitive_begin(pr_trianglelist); + for( var i = 0, n = array_length(_triangles); i < n; i++ ) { + var p0 = _triangles[i][0]; + var p1 = _triangles[i][1]; + var p2 = _triangles[i][2]; + + draw_vertex(round(p0.x), round(p0.y)); + draw_vertex(round(p1.x), round(p1.y)); + draw_vertex(round(p2.x), round(p2.y)); + } + draw_primitive_end(); + draw_surface(drawing_surface, 0, 0); + surface_reset_target(); + + surface_set_shader(drawing_surface, sh_freeform_fill_cleanup); + shader_set_f("dimension", _dim); + + draw_surface_ext(temp_surface, 0, 0, 1, 1, 0, draw_get_color(), draw_get_alpha()); + surface_reset_shader(); + + surface_free(temp_surface); + } + + mouse_holding = false; + } + + } else if(mouse_press(mb_left, active)) { + mouse_pre_x = _mmx; + mouse_pre_y = _mmy; + + mouse_holding = true; + freeform_shape = [ new __vec2(_mmx, _mmy) ]; + + surface_clear(drawing_surface); + } +} #endregion \ No newline at end of file diff --git a/scripts/canvas_freeform/canvas_freeform.yy b/scripts/canvas_freeform/canvas_freeform.yy new file mode 100644 index 000000000..adbb92a29 --- /dev/null +++ b/scripts/canvas_freeform/canvas_freeform.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_freeform", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_freeform", + "parent":{ + "name":"util", + "path":"folders/nodes/data/canvas/util.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.gml b/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.gml new file mode 100644 index 000000000..adb5128c9 --- /dev/null +++ b/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.gml @@ -0,0 +1,94 @@ + +function canvas_ms_fillable(colorBase, colorFill, _x, _y, _thres) { #region + var c = _ff_getPixel(_x, _y); + var d = color_diff(colorBase, c, true, true); + return d <= _thres; +} #endregion + +function canvas_magic_selection_scanline(_surf, _x, _y, _thres, _corner = false) { #region + + var colorBase = surface_getpixel_ext(_surf, _x, _y); + var colorFill = colorBase; + + var x1, y1, x_start; + var spanAbove, spanBelow; + var thr = _thres * _thres; + + _ff_w = surface_get_width(_surf); + _ff_h = surface_get_height(_surf); + _ff_buff = buffer_create(_ff_w * _ff_h * 4, buffer_fixed, 4); + buffer_get_surface(_ff_buff, _surf, 0); + + var queue = ds_queue_create(); + ds_queue_enqueue(queue, [_x, _y]); + + var sel_x0 = surface_w; + var sel_y0 = surface_h; + var sel_x1 = 0; + var sel_y1 = 0; + + var _arr = array_create(surface_w * surface_h, 0); + + draw_set_color(c_white); + while(!ds_queue_empty(queue)) { + var pos = ds_queue_dequeue(queue); + x1 = pos[0]; + y1 = pos[1]; + + if(_arr[y1 * surface_w + x1] == 1) continue; //Color in queue is already filled + + while(x1 > 0 && canvas_ms_fillable(colorBase, colorFill, x1 - 1, y1, thr)) //Move to the leftmost connected pixel in the same row. + x1--; + x_start = x1; + + spanAbove = false; + spanBelow = false; + + //print($"Searching {x1}, {y1} | {canvas_ms_fillable(colorBase, colorFill, x1, y1, thr)}"); + + while(x1 < surface_w && canvas_ms_fillable(colorBase, colorFill, x1, y1, thr)) { + draw_point(x1, y1); + + if(_arr[y1 * surface_w + x1] == 1) continue; + _arr[y1 * surface_w + x1] = 1; + + sel_x0 = min(sel_x0, x1); + sel_y0 = min(sel_y0, y1); + sel_x1 = max(sel_x1, x1); + sel_y1 = max(sel_y1, y1); + + //print($"> Filling {x1}, {y1}: {canvas_get_color_buffer(x1, y1)}"); + + if(y1 > 0) { + if(_corner && x1 > 0 && canvas_ms_fillable(colorBase, colorFill, x1 - 1, y1 - 1, thr)) //Check top left pixel + ds_queue_enqueue(queue, [x1 - 1, y1 - 1]); + + if(canvas_ms_fillable(colorBase, colorFill, x1, y1 - 1, thr)) //Check top pixel + ds_queue_enqueue(queue, [x1, y1 - 1]); + } + + if(y1 < surface_h - 1) { + if(_corner && x1 > 0 && canvas_ms_fillable(colorBase, colorFill, x1 - 1, y1 + 1, thr)) //Check bottom left pixel + ds_queue_enqueue(queue, [x1 - 1, y1 + 1]); + + if(canvas_ms_fillable(colorBase, colorFill, x1, y1 + 1, thr)) //Check bottom pixel + ds_queue_enqueue(queue, [x1, y1 + 1]); + } + + if(_corner && x1 < surface_w - 1) { + if(y1 > 0 && canvas_ms_fillable(colorBase, colorFill, x1 + 1, y1 - 1, thr)) //Check top right pixel + ds_queue_enqueue(queue, [x1 + 1, y1 - 1]); + + if(y1 < surface_h - 1 && canvas_ms_fillable(colorBase, colorFill, x1 + 1, y1 + 1, thr)) //Check bottom right pixel + ds_queue_enqueue(queue, [x1 + 1, y1 + 1]); + } + + x1++; + } + } + + ds_queue_destroy(queue); + buffer_delete(_ff_buff); + + return [ sel_x0, sel_y0, sel_x1, sel_y1 ]; +} #endregion \ No newline at end of file diff --git a/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.yy b/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.yy new file mode 100644 index 000000000..1178e6af2 --- /dev/null +++ b/scripts/canvas_magic_selection_functions/canvas_magic_selection_functions.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_magic_selection_functions", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_magic_selection_functions", + "parent":{ + "name":"util", + "path":"folders/nodes/data/canvas/util.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_brush/canvas_tool_brush.gml b/scripts/canvas_tool_brush/canvas_tool_brush.gml new file mode 100644 index 000000000..82214d09b --- /dev/null +++ b/scripts/canvas_tool_brush/canvas_tool_brush.gml @@ -0,0 +1,86 @@ +function canvas_tool_brush(brush, eraser = false) : canvas_tool() constructor { + self.brush = brush; + isEraser = eraser; + + brush_resizable = true; + + mouse_cur_x = 0; + mouse_cur_y = 0; + mouse_pre_x = 0; + mouse_pre_y = 0; + mouse_pre_draw_x = undefined; + mouse_pre_draw_y = undefined; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT) && key_mod_press(CTRL)) { + var aa = point_direction(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); + var dd = point_distance(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); + var _a = round(aa / 45) * 45; + dd = dd * cos(degtorad(_a - aa)); + + mouse_cur_x = mouse_pre_draw_x + lengthdir_x(dd, _a); + mouse_cur_y = mouse_pre_draw_y + lengthdir_y(dd, _a); + } + + if(mouse_press(mb_left, active)) { + brush_next_dist = 0; + + surface_set_shader(drawing_surface, noone); + canvas_draw_point_size(brush, mouse_cur_x, mouse_cur_y, true); + surface_reset_shader(); + + mouse_holding = true; + if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT)) { ///////////////// shift line + surface_set_shader(drawing_surface, noone, true, BLEND.alpha); + brush_next_dist = 0; + canvas_draw_line_size(brush, mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y, true); + surface_reset_shader(); + mouse_holding = false; + + apply_draw_surface(); + } + + mouse_pre_draw_x = mouse_cur_x; + mouse_pre_draw_y = mouse_cur_y; + } + + if(mouse_holding) { + var _move = mouse_pre_draw_x != mouse_cur_x || mouse_pre_draw_y != mouse_cur_y; + var _1stp = brush.brush_dist_min == brush.brush_dist_max && brush.brush_dist_min == 1; + + if(_move || !_1stp) { + surface_set_shader(drawing_surface, noone, false, BLEND.alpha); + if(_1stp) canvas_draw_point_size(brush, mouse_cur_x, mouse_cur_y, true); + canvas_draw_line_size(brush, mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y, true); + surface_reset_shader(); + } + + mouse_pre_draw_x = mouse_cur_x; + mouse_pre_draw_y = mouse_cur_y; + + if(mouse_release(mb_left)) { + mouse_holding = false; + apply_draw_surface(); + } + } + + BLEND_NORMAL; + + mouse_pre_x = mouse_cur_x; + mouse_pre_y = mouse_cur_y; + + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + if(isEraser) draw_set_color(c_white); + + if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT)) + canvas_draw_line_size(brush, mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); + else + canvas_draw_point_size(brush, mouse_cur_x, mouse_cur_y); + } +} \ No newline at end of file diff --git a/scripts/canvas_tool_brush/canvas_tool_brush.yy b/scripts/canvas_tool_brush/canvas_tool_brush.yy new file mode 100644 index 000000000..3dae6d0ab --- /dev/null +++ b/scripts/canvas_tool_brush/canvas_tool_brush.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_brush", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_brush", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.gml b/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.gml new file mode 100644 index 000000000..bbd020882 --- /dev/null +++ b/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.gml @@ -0,0 +1,73 @@ +enum CANVAS_TOOL_SHAPE { + rectangle, + ellipse +} + +function canvas_tool_shape(brush, shape) : canvas_tool() constructor { + self.brush = brush; + self.shape = shape; + self.fill = false; + + brush_resizable = true; + mouse_holding = false; + + mouse_cur_x = 0; + mouse_cur_y = 0; + mouse_pre_x = 0; + mouse_pre_y = 0; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + if(mouse_holding && key_mod_press(SHIFT)) { + var ww = mouse_cur_x - mouse_pre_x; + var hh = mouse_cur_y - mouse_pre_y; + var ss = max(abs(ww), abs(hh)); + + mouse_cur_x = mouse_pre_x + ss * sign(ww); + mouse_cur_y = mouse_pre_y + ss * sign(hh); + } + + if(mouse_holding) { + + surface_set_shader(drawing_surface, noone); + + if(shape == CANVAS_TOOL_SHAPE.rectangle) + canvas_draw_rect_size(brush, mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, fill); + + else if(shape == CANVAS_TOOL_SHAPE.ellipse) + canvas_draw_ellp_size(brush, mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, fill); + + surface_reset_shader(); + + if(mouse_release(mb_left)) { + apply_draw_surface(); + mouse_holding = false; + } + + } else if(mouse_press(mb_left, active)) { + mouse_pre_x = mouse_cur_x; + mouse_pre_y = mouse_cur_y; + + mouse_holding = true; + } + + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + if(!mouse_holding) { + canvas_draw_point_size(brush, mouse_cur_x, mouse_cur_y); + return; + } + + if(shape == CANVAS_TOOL_SHAPE.rectangle) + canvas_draw_rect_size(brush, mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, fill); + + if(shape == CANVAS_TOOL_SHAPE.ellipse) + canvas_draw_ellp_size(brush, mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, fill); + } + +} \ No newline at end of file diff --git a/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.yy b/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.yy new file mode 100644 index 000000000..e46509fd0 --- /dev/null +++ b/scripts/canvas_tool_brush_shape/canvas_tool_brush_shape.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_brush_shape", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_brush_shape", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.gml b/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.gml new file mode 100644 index 000000000..552969d95 --- /dev/null +++ b/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.gml @@ -0,0 +1,30 @@ +function canvas_tool_draw_freeform(brush) : canvas_tool() constructor { + self.brush = brush; + + brush_resizable = true; + + mouse_cur_x = 0; + mouse_cur_y = 0; + mouse_pre_x = 0; + mouse_pre_y = 0; + + freeform_shape = []; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + attributes = node.attributes; + + canvas_freeform_step(active, _x, _y, _s, _mx, _my, true); + + if(mouse_release(mb_left)) + apply_draw_surface(); + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + canvas_draw_point_size(brush, mouse_cur_x, mouse_cur_y); + } + +} \ No newline at end of file diff --git a/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.yy b/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.yy new file mode 100644 index 000000000..3896d088c --- /dev/null +++ b/scripts/canvas_tool_draw_freeform/canvas_tool_draw_freeform.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_draw_freeform", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_draw_freeform", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_fill/canvas_tool_fill.gml b/scripts/canvas_tool_fill/canvas_tool_fill.gml new file mode 100644 index 000000000..fe7dac2dc --- /dev/null +++ b/scripts/canvas_tool_fill/canvas_tool_fill.gml @@ -0,0 +1,37 @@ +function canvas_tool_fill(toolAttr) : canvas_tool() constructor { + self.tool_attribute = toolAttr; + + relative = true; + + mouse_cur_x = 0; + mouse_cur_y = 0; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + var _thr = tool_attribute.thres; + var _fill_type = tool_attribute.fill8; + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + surface_w = surface_get_width(_canvas_surface); + surface_h = surface_get_height(_canvas_surface); + + if(mouse_press(mb_left, active) && point_in_rectangle(mouse_cur_x, mouse_cur_y, 0, 0, surface_w - 1, surface_h - 1)) { + node.storeAction(); + + surface_set_target(_canvas_surface); + switch(_fill_type) { + case 0 : canvas_flood_fill_scanline(_canvas_surface, mouse_cur_x, mouse_cur_y, _thr, false); break; + case 1 : canvas_flood_fill_scanline(_canvas_surface, mouse_cur_x, mouse_cur_y, _thr, true); break; + } + surface_reset_target(); + + node.surface_store_buffer(); + } + + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + } +} \ No newline at end of file diff --git a/scripts/canvas_tool_fill/canvas_tool_fill.yy b/scripts/canvas_tool_fill/canvas_tool_fill.yy new file mode 100644 index 000000000..046b660c6 --- /dev/null +++ b/scripts/canvas_tool_fill/canvas_tool_fill.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_fill", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_fill", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection/canvas_tool_selection.gml b/scripts/canvas_tool_selection/canvas_tool_selection.gml new file mode 100644 index 000000000..5e3d1d1b1 --- /dev/null +++ b/scripts/canvas_tool_selection/canvas_tool_selection.gml @@ -0,0 +1,154 @@ +function canvas_tool_selection(selector = noone) : canvas_tool() constructor { + + self.selector = selector; + + selection_surface = surface_create_empty(1, 1); + selection_mask = surface_create_empty(1, 1); + selection_position = [ 0, 0 ]; + + is_selecting = false; + is_selected = false; + is_select_drag = false; + + selection_sx = 0; + selection_sy = 0; + selection_mx = 0; + selection_my = 0; + + mouse_cur_x = 0; + mouse_cur_y = 0; + mouse_pre_x = 0; + mouse_pre_y = 0; + + function createSelection(_mask, sel_x0, sel_y0, sel_w, sel_h) { + + is_selecting = false; + + if(sel_w == 1 && sel_h == 1) return; + is_selected = true; + + selection_surface = surface_create(sel_w, sel_h); + selection_mask = surface_create(sel_w, sel_h); + + surface_set_target(selection_surface); + DRAW_CLEAR + draw_surface_safe(_canvas_surface, -sel_x0, -sel_y0); + + BLEND_MULTIPLY + draw_surface_safe(_mask, 0, 0); + BLEND_NORMAL + surface_reset_target(); + + surface_set_target(selection_mask); + DRAW_CLEAR + draw_surface_safe(_mask, 0, 0); + surface_reset_target(); + + node.storeAction(); + surface_set_target(_canvas_surface); + gpu_set_blendmode(bm_subtract); + draw_surface_safe(selection_surface, sel_x0, sel_y0); + gpu_set_blendmode(bm_normal); + surface_reset_target(); + + node.surface_store_buffer(); + + selection_position = [ sel_x0, sel_y0 ]; + } + + function copySelection() { + var s = surface_encode(selection_surface); + clipboard_set_text(s); + } + + function apply() { + surface_set_target(_canvas_surface); + BLEND_ALPHA + draw_surface_safe(selection_surface, selection_position[0], selection_position[1]); + BLEND_NORMAL + surface_reset_target(); + + node.surface_store_buffer(); + surface_free(selection_surface); + } + + function onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + if(!is_surface(selection_surface)) { + is_selected = false; + return; + } + + if(is_select_drag) { + var px = selection_sx + (mouse_cur_x - selection_mx); + var py = selection_sy + (mouse_cur_y - selection_my); + + selection_position[0] = px; + selection_position[1] = py; + + if(mouse_release(mb_left)) + is_select_drag = false; + } + + if(mouse_press(mb_left, active)) { + var pos_x = selection_position[0]; + var pos_y = selection_position[1]; + var sel_w = surface_get_width_safe(selection_surface); + var sel_h = surface_get_height_safe(selection_surface); + + if(point_in_rectangle(mouse_cur_x, mouse_cur_y, pos_x, pos_y, pos_x + sel_w, pos_y + sel_h)) { + is_select_drag = true; + selection_sx = pos_x; + selection_sy = pos_y; + selection_mx = mouse_cur_x; + selection_my = mouse_cur_y; + } else { + is_selected = false; + apply(); + } + } + + if(key_press(vk_delete)) { + is_selected = false; + surface_free(selection_surface); + } + + if(key_press(ord("C"), MOD_KEY.ctrl)) copySelection(); + } + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + if(is_selected) { onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); return; } + else if(is_surface(selection_surface)) { apply(); } + } + + function drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + if(is_selected) + draw_surface_safe(selection_surface, selection_position[0], selection_position[1]); + + else if(is_selecting) { + var sel_x0 = min(selection_sx, mouse_cur_x); + var sel_y0 = min(selection_sy, mouse_cur_y); + draw_surface_safe(selection_mask, sel_x0, sel_y0); + } + } + + function drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + if(!is_selected) return; + + var pos_x = _x + selection_position[0] * _s; + var pos_y = _y + selection_position[1] * _s; + var sel_w = surface_get_width_safe(selection_surface) * _s; + var sel_h = surface_get_height_safe(selection_surface) * _s; + + draw_surface_ext_safe(selection_surface, pos_x, pos_y, _s, _s, 0, c_white, 1); + + draw_set_color(c_black); + draw_rectangle(pos_x, pos_y, pos_x + sel_w, pos_y + sel_h, true); + + draw_set_color(c_white); + draw_rectangle_dashed(pos_x, pos_y, pos_x + sel_w, pos_y + sel_h, true, 6, current_time / 100); + } +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection/canvas_tool_selection.yy b/scripts/canvas_tool_selection/canvas_tool_selection.yy new file mode 100644 index 000000000..a0bc1b633 --- /dev/null +++ b/scripts/canvas_tool_selection/canvas_tool_selection.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_selection", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_selection", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.gml b/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.gml new file mode 100644 index 000000000..ade972be5 --- /dev/null +++ b/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.gml @@ -0,0 +1,89 @@ +function canvas_tool_selection_freeform(selector, brush) : canvas_tool_selection(selector) constructor { + + self.brush = brush; + + mouse_pre_x = 0; + mouse_pre_y = 0; + freeform_shape = []; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + attributes = node.attributes; + var _dim = attributes.dimension; + + if(is_selected) { onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); return; } + + if(mouse_press(mb_left, active)) { + is_selecting = true; + selection_sx = mouse_cur_x; + selection_sy = mouse_cur_y; + + surface_free_safe(selection_mask); + } + + if(is_selecting) { + var sel_x0, sel_y0, sel_x1, sel_y1; + var sel_w = 1, sel_h = 1; + + draw_set_color(c_white); + canvas_freeform_step(active, _x, _y, _s, _mx, _my, false); + + if(mouse_release(mb_left)) { + is_selecting = false; + + sel_x0 = _dim[0]; + sel_y0 = _dim[1]; + sel_x1 = 0; + sel_y1 = 0; + + for( var i = 0, n = array_length(freeform_shape); i < n; i++ ) { + var _f = freeform_shape[i]; + + sel_x0 = min(sel_x0, round(_f.x - 0.5)); + sel_y0 = min(sel_y0, round(_f.y - 0.5)); + sel_x1 = max(sel_x1, round(_f.x - 0.5)); + sel_y1 = max(sel_y1, round(_f.y - 0.5)); + } + + sel_w = sel_x1 - sel_x0 + 1; + sel_h = sel_y1 - sel_y0 + 1; + + if(sel_w > 1 && sel_h > 1) { + selection_mask = surface_verify(selection_mask, sel_w, sel_h); + surface_set_target(selection_mask); + DRAW_CLEAR + draw_surface(drawing_surface, -sel_x0, -sel_y0); + surface_reset_target(); + } + + surface_clear(drawing_surface); + + selector.createSelection(selection_mask, sel_x0, sel_y0, sel_w, sel_h); + surface_free_safe(selection_mask); + } + + } + } + + function drawPostOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + if(!is_selecting) return; + + var ox, oy, nx, ny; + + draw_set_color(c_white); + + for( var i = 0, n = array_length(freeform_shape); i < n; i++ ) { + nx = _x + freeform_shape[i].x * _s; + ny = _y + freeform_shape[i].y * _s; + + if(i) draw_line(ox, oy, nx, ny); + + ox = nx; + oy = ny; + } + } + +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.yy b/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.yy new file mode 100644 index 000000000..973be8212 --- /dev/null +++ b/scripts/canvas_tool_selection_freeform/canvas_tool_selection_freeform.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_selection_freeform", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_selection_freeform", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.gml b/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.gml new file mode 100644 index 000000000..0b3e772a6 --- /dev/null +++ b/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.gml @@ -0,0 +1,60 @@ +function canvas_tool_selection_magic(selector, toolAttr) : canvas_tool_selection(selector) constructor { + + self.tool_attribute = toolAttr; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + if(is_selected) { onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); return; } + + var _thr = tool_attribute.thres; + var _fill_type = tool_attribute.fill8; + + if(!selector.is_selected && mouse_press(mb_left, active)) { + + canvas_buffer = node.canvas_buffer; + preview_index = node.preview_index; + + surface_w = surface_get_width(_canvas_surface); + surface_h = surface_get_height(_canvas_surface); + + if(point_in_rectangle(mouse_cur_x, mouse_cur_y, 0, 0, surface_w - 1, surface_h - 1)) { + var bb = [ 0, 0, surface_w, surface_h ]; + + var _temp_surface = surface_create(surface_w, surface_h); + draw_set_color(c_white); + surface_set_target(_temp_surface); + DRAW_CLEAR + + switch(_fill_type) { + case 0 : bb = canvas_magic_selection_scanline(_canvas_surface, mouse_cur_x, mouse_cur_y, _thr, false); break; + case 1 : bb = canvas_magic_selection_scanline(_canvas_surface, mouse_cur_x, mouse_cur_y, _thr, true); break; + } + + surface_reset_target(); + + var sel_x0 = bb[0]; + var sel_y0 = bb[1]; + var sel_x1 = bb[2]; + var sel_y1 = bb[3]; + var sel_w = 1, sel_h = 1; + + sel_w = sel_x1 - sel_x0 + 1; + sel_h = sel_y1 - sel_y0 + 1; + + selection_mask = surface_verify(selection_mask, sel_w, sel_h); + surface_set_target(selection_mask); + DRAW_CLEAR + draw_surface(_temp_surface, -sel_x0, -sel_y0); + surface_reset_target(); + surface_free(_temp_surface); + + selector.createSelection(selection_mask, sel_x0, sel_y0, sel_w, sel_h); + surface_free_safe(selection_mask); + } + } + } + +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.yy b/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.yy new file mode 100644 index 000000000..e76772894 --- /dev/null +++ b/scripts/canvas_tool_selection_magic/canvas_tool_selection_magic.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_selection_magic", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_selection_magic", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.gml b/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.gml new file mode 100644 index 000000000..97cd3c52e --- /dev/null +++ b/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.gml @@ -0,0 +1,54 @@ +function canvas_tool_selection_shape(selector, shape) : canvas_tool_selection(selector) constructor { + + self.shape = shape; + + function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + + mouse_cur_x = round((_mx - _x) / _s - 0.5); + mouse_cur_y = round((_my - _y) / _s - 0.5); + + if(is_selected) { onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); return; } + + if(is_selecting) { + var sel_x0, sel_y0, sel_x1, sel_y1; + var sel_w = 1, sel_h = 1; + + sel_x0 = min(selection_sx, mouse_cur_x); + sel_y0 = min(selection_sy, mouse_cur_y); + sel_x1 = max(selection_sx, mouse_cur_x); + sel_y1 = max(selection_sy, mouse_cur_y); + + sel_w = sel_x1 - sel_x0 + 1; + sel_h = sel_y1 - sel_y0 + 1; + + selection_mask = surface_verify(selection_mask, sel_w, sel_h); + surface_set_target(selection_mask); + DRAW_CLEAR + draw_set_color(c_white); + + if(shape == CANVAS_TOOL_SHAPE.rectangle) + draw_rectangle(0, 0, sel_w, sel_h, false); + + else if(shape == CANVAS_TOOL_SHAPE.ellipse) { + draw_set_circle_precision(32); + draw_ellipse(0, 0, sel_w - 1, sel_h - 1, false); + } + + surface_reset_target(); + + if(mouse_release(mb_left)) { + is_selecting = false; + selector.createSelection(selection_mask, sel_x0, sel_y0, sel_w, sel_h); + surface_free_safe(selection_mask); + } + + } else if(!selector.is_selected && mouse_press(mb_left, active)) { + is_selecting = true; + selection_sx = mouse_cur_x; + selection_sy = mouse_cur_y; + + surface_free_safe(selection_mask); + } + } + +} \ No newline at end of file diff --git a/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.yy b/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.yy new file mode 100644 index 000000000..5ba2c97e3 --- /dev/null +++ b/scripts/canvas_tool_selection_shape/canvas_tool_selection_shape.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"canvas_tool_selection_shape", + "isCompatibility":false, + "isDnD":false, + "name":"canvas_tool_selection_shape", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/scripts/color_function/color_function.gml b/scripts/color_function/color_function.gml index 636b88e7f..580c1ff1b 100644 --- a/scripts/color_function/color_function.gml +++ b/scripts/color_function/color_function.gml @@ -174,8 +174,8 @@ function color_diff(c1, c2, fast = false, alpha = false) { #region _c2_g = _c2_g / 255 * _c2_a; _c2_b = _c2_b / 255 * _c2_a; - if(fast) return abs(_c1_r - _c2_r) + abs(_c1_g - _c2_g) + abs(_c1_b - _c2_b) + abs(_c1_a - _c2_a); - return sqrt(sqr(_c1_r - _c2_r) + sqr(_c1_g - _c2_g) + sqr(_c1_b - _c2_b) + sqr(_c1_a - _c2_a)); + if(fast) return (abs(_c1_r - _c2_r) + abs(_c1_g - _c2_g) + abs(_c1_b - _c2_b)) / 3; + return sqrt(sqr(_c1_r - _c2_r) + sqr(_c1_g - _c2_g) + sqr(_c1_b - _c2_b)); } #endregion #region merge diff --git a/scripts/color_loader/color_loader.gml b/scripts/color_loader/color_loader.gml index 613db8f2d..7dc3b8a10 100644 --- a/scripts/color_loader/color_loader.gml +++ b/scripts/color_loader/color_loader.gml @@ -1,9 +1,13 @@ #region colors globalvar CDEF, COLORS, THEME_VALUE; + globalvar COLORS_GLOBAL_GET, COLORS_GLOBAL_SET; CDEF = new ThemeColorDef(); COLORS = new ThemeColor(); THEME_VALUE = new ThemeValue(); + + COLORS_GLOBAL_GET = noone; + COLORS_GLOBAL_SET = noone; #endregion function loadColor(theme = "default") { #region diff --git a/scripts/globals/globals.gml b/scripts/globals/globals.gml index 2d90699de..c43a9c3e1 100644 --- a/scripts/globals/globals.gml +++ b/scripts/globals/globals.gml @@ -189,6 +189,11 @@ function global_project_close() { CALL("project_close"); PANEL_GRAPH.close(); } function global_theme_reload() { CALL("theme_reload"); loadGraphic(PREFERENCES.theme); resetPanel(); } + + function reset_global_getset() { + COLORS_GLOBAL_GET = noone; + COLORS_GLOBAL_SET = noone; + } #endregion #region debug diff --git a/scripts/hotkey_data/hotkey_data.gml b/scripts/hotkey_data/hotkey_data.gml index 34dbd3206..3ef3be3d9 100644 --- a/scripts/hotkey_data/hotkey_data.gml +++ b/scripts/hotkey_data/hotkey_data.gml @@ -3,11 +3,13 @@ HOTKEYS_CUSTOM = { "Node_Canvas": { "Selection": new hotkeySimple("S"), + "Magic Selection": new hotkeySimple("W"), "Pencil": new hotkeySimple("B"), "Eraser": new hotkeySimple("E"), "Rectangle": new hotkeySimple("N"), "Ellipse": new hotkeySimple("M"), "Fill": new hotkeySimple("F"), + "Freeform": new hotkeySimple("Q"), }, "Node_Mesh_Warp": { "Edit control point": new hotkeySimple("V"), diff --git a/scripts/key_press/key_press.gml b/scripts/key_press/key_press.gml index 4dde7f93e..efc20270e 100644 --- a/scripts/key_press/key_press.gml +++ b/scripts/key_press/key_press.gml @@ -143,7 +143,7 @@ enum MOD_KEY { alt = 4 } -function key_press(_key, _mod) { +function key_press(_key, _mod = MOD_KEY.none) { if(WIDGET_CURRENT) return false; if(_mod == MOD_KEY.none && _key == 0) return false; diff --git a/scripts/node_canvas/node_canvas.gml b/scripts/node_canvas/node_canvas.gml index 49a733fc6..2c2732260 100644 --- a/scripts/node_canvas/node_canvas.gml +++ b/scripts/node_canvas/node_canvas.gml @@ -181,47 +181,8 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor preview_draw_surface = surface_create_empty(1, 1); _preview_draw_surface = surface_create_empty(1, 1); - is_selecting = false; - is_selected = false; - is_select_drag = false; - selection_surface = surface_create_empty(1, 1); - selection_mask = surface_create_empty(1, 1); - selection_position = [ 0, 0 ]; - selection_sx = 0; - selection_sy = 0; - selection_mx = 0; - selection_my = 0; - - mouse_cur_x = 0; - mouse_cur_y = 0; - mouse_pre_x = 0; - mouse_pre_y = 0; - mouse_pre_draw_x = undefined; - mouse_pre_draw_y = undefined; - mouse_pre_dir_x = undefined; - mouse_pre_dir_y = undefined; - - mouse_holding = false; - - brush_sizing = false; - brush_sizing_s = 0; - brush_sizing_mx = 0; - brush_sizing_my = 0; - brush_sizing_dx = 0; - brush_sizing_dy = 0; - - brush_surface = noone; - brush_size = 1; - brush_dist_min = 1; - brush_dist_max = 1; - brush_direction = 0; - brush_rand_dir = [ 0, 0, 0, 0, 0 ]; - brush_seed = irandom_range(100000, 999999); - brush_next_dist = 0; - - freeform_shape = []; - - draw_stack = ds_list_create(); + draw_stack = ds_list_create(); + brush = new canvas_brush(); #endregion #region ++++ tools ++++ @@ -252,61 +213,53 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor tools = [ new NodeTool( "Selection", [ THEME.canvas_tools_selection_rectangle, THEME.canvas_tools_selection_circle, THEME.canvas_tools_freeform_selection ]), + new NodeTool( "Magic Selection", THEME.canvas_tools_magic_selection ) + .setSetting(tool_thrs) + .setSetting(tool_fil8), + new NodeTool( "Pencil", THEME.canvas_tools_pencil) - .setSetting(tool_size), + .setSetting(tool_size), new NodeTool( "Eraser", THEME.canvas_tools_eraser) - .setSetting(tool_size), + .setSetting(tool_size), new NodeTool( "Rectangle", [ THEME.canvas_tools_rect, THEME.canvas_tools_rect_fill ]) - .setSetting(tool_size), + .setSetting(tool_size), new NodeTool( "Ellipse", [ THEME.canvas_tools_ellip, THEME.canvas_tools_ellip_fill ]) - .setSetting(tool_size), + .setSetting(tool_size), - new NodeTool( "Freefrom", THEME.canvas_tools_freeform) - .setSetting(tool_size), + new NodeTool( "Freeform", THEME.canvas_tools_freeform) + .setSetting(tool_size), new NodeTool( "Fill", THEME.canvas_tools_bucket) - .setSetting(tool_thrs) - .setSetting(tool_fil8), - ]; - #endregion - - #region fix size points - fix_points = []; - - fix_points[0] = []; - fix_points[1] = []; - fix_points[2] = [[ 0, 0 ], [ 1, 0 ], [ 0, 1 ], [ 1, 1 ]]; - fix_points[3] = [[ 0, 0 ], [ -1, 0 ], [ 0, -1 ], [ 1, 0 ], [ 0, 1 ]]; - fix_points[4] = [[ 0, 0 ], [ -1, 0 ], [ 0, -1 ], [ -1, -1 ], [ -2, -1 ], [ -2, 0 ], [ -1, -2 ], [ 0, -2 ], [ 1, -1 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ]]; - fix_points[5] = [ - [ 0, 0 ], - [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], - [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ 2, 1 ], - ]; - fix_points[6] = [ - [ 0, 0 ], - [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], - [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ -2, -2 ], - [ -1, -3 ], [ 0, -3 ], [ -3, -1 ], [ -3, 0 ], - ]; - fix_points[7] = [ - [ 0, 0 ], - [ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ -1, 0 ], [ 1, 0 ], [ -1, 1 ], [ 0, 1 ], [ 1, 1 ], - [ -1, -2 ], [ 0, -2 ], [ 1, -2 ], [ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ -2, -1 ], [ -2, 0 ], [ -2, 1 ], [ 2, -1 ], [ 2, 0 ], [ 2, 1 ], [ -2, -2 ], [ 2, -2 ], [ -2, 2 ], [ 2, 2 ], - [ -1, -3 ], [ 0, -3 ], [ 1, -3 ], [ -1, 3 ], [ 0, 3 ], [ 1, 3 ], [ -3, -1 ], [ -3, 0 ], [ -3, 1 ], [ 3, -1 ], [ 3, 0 ], [ 3, 1 ], + .setSetting(tool_thrs) + .setSetting(tool_fil8), ]; - fix_points[8] = array_append(variable_clone(fix_points[7]), [ [-4, -2], [-4, -1], [-4, 0], [-4, 1], [-3, -3], [-3, -2], [-3, 2], [-2, -4], [-2, -3], [-2, 3], [-1, -4], [0, -4], [1, -4], [2, -3], [3, -2] ]); - fix_points[9] = array_append(variable_clone(fix_points[7]), [ [-4, -1], [-4, 0], [-4, 1], [-3, -2], [-3, -2], [-3, 2], [-2, -3], [-2, 3], [-1, -4], [-1, 4], [0, -4], [0, 4], [1, -4], [1, 4], [2, -3], [2, 3], [3, -2], [3, 2], [4, -1], [4, 0], [4, 1] ]); + tool_selection = new canvas_tool_selection(); - fix_points_amount = array_length(fix_points); + tool_brush = new canvas_tool_brush(brush, false); + tool_eraser = new canvas_tool_brush(brush, true); + tool_rectangle = new canvas_tool_shape(brush, CANVAS_TOOL_SHAPE.rectangle); + tool_ellipse = new canvas_tool_shape(brush, CANVAS_TOOL_SHAPE.ellipse); + tool_fill = new canvas_tool_fill(tool_attribute); + tool_freeform = new canvas_tool_draw_freeform(brush); + + tool_sel_rectangle = new canvas_tool_selection_shape(tool_selection, CANVAS_TOOL_SHAPE.rectangle); + tool_sel_ellipse = new canvas_tool_selection_shape(tool_selection, CANVAS_TOOL_SHAPE.ellipse); + tool_sel_freeform = new canvas_tool_selection_freeform(tool_selection, brush); + tool_sel_magic = new canvas_tool_selection_magic(tool_selection, tool_attribute); + + //rightTools = [ + // new NodeTool( "Selection", THEME.canvas_tools_selection_rectangle ), + //]; #endregion function setToolColor(color) { tool_attribute.color = color; } + function getToolColor() { return tool_attribute.color; } + static drawTools = function(_mx, _my, xx, yy, tool_size, hover, focus) { #region var _sx0 = xx - tool_size / 2; var _sx1 = xx + tool_size / 2; @@ -428,12 +381,10 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor var cDep = attrDepth(); var _canvas_surface = getCanvasSurface(index); - //print($"Applying surface {index} - {_canvas_surface} [{is_surface(_canvas_surface)}]"); - if(!is_surface(_canvas_surface)) { // recover surface - //print($"recovering surface from buffer {random(1)}"); - + if(!is_surface(_canvas_surface)) { // recover surface from bufffer in case of VRAM refresh setCanvasSurface(surface_create_from_buffer(_dim[0], _dim[1], canvas_buffer[index]), index); + } else if(surface_get_width_safe(_canvas_surface) != _dim[0] || surface_get_height_safe(_canvas_surface) != _dim[1]) { // resize surface var _cbuff = array_safe_get_fast(canvas_buffer, index); if(buffer_exists(_cbuff)) buffer_delete(_cbuff); @@ -469,757 +420,155 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor function apply_draw_surface() { #region var _alp = _color_get_alpha(tool_attribute.color); + var _can = getCanvasSurface(); + var _drw = drawing_surface; storeAction(); - surface_set_target(getCanvasSurface()); + if(tool_selection.is_selected) { + var _tmp = surface_create(surface_get_width(tool_selection.selection_mask), surface_get_height(tool_selection.selection_mask)); + + surface_set_target(_tmp); + DRAW_CLEAR + + draw_surface(drawing_surface, -tool_selection.selection_position[0], -tool_selection.selection_position[1]); + + BLEND_MULTIPLY + draw_surface(tool_selection.selection_mask, 0, 0); + BLEND_NORMAL + surface_reset_target(); + + _can = tool_selection.selection_surface; + _drw = _tmp; + } + + surface_set_target(_can); BLEND_ALPHA if(isUsingTool("Eraser")) { gpu_set_blendmode(bm_subtract); if(tool_attribute.channel[3]) gpu_set_colorwriteenable(false, false, false, true); } - draw_surface_ext_safe(drawing_surface, 0, 0, 1, 1, 0, c_white, _alp); + draw_surface_ext_safe(_drw, 0, 0, 1, 1, 0, c_white, _alp); gpu_set_colorwriteenable(tool_attribute.channel[0], tool_attribute.channel[1], tool_attribute.channel[2], tool_attribute.channel[3]); surface_reset_target(); - + + surface_store_buffer(); + surface_clear(drawing_surface); BLEND_NORMAL; - surface_store_buffer(); - } #endregion - - function draw_point_size(_x, _y, _draw = false) { #region - if(brush_surface == noone) { - - if(brush_size <= 1) - draw_point(_x, _y); - - else if(brush_size < fix_points_amount) { - var fx = fix_points[brush_size]; - for( var i = 0, n = array_length(fx); i < n; i++ ) - draw_point(_x + fx[i][0], _y + fx[i][1]); - - } else - draw_circle_prec(_x, _y, brush_size / 2, 0); - - } else { - var _sw = surface_get_width_safe(brush_surface); - var _sh = surface_get_height_safe(brush_surface); - var _r = brush_direction + angle_random_eval(brush_rand_dir, brush_seed); - var _p = point_rotate(-_sw / 2, -_sh / 2, 0, 0, _r); - - draw_surface_ext_safe(brush_surface, _x + _p[0], _y + _p[1], 1, 1, _r, draw_get_color(), draw_get_alpha()); - - if(_draw) brush_seed = irandom_range(100000, 999999); - } - } #endregion - - function draw_line_size(_x0, _y0, _x1, _y1, _draw = false) { #region - - if(brush_surface == noone) { - - if(brush_size < fix_points_amount) { - if(_x1 > _x0) _x0--; - if(_y1 > _y0) _y0--; - if(_y1 < _y0) _y1--; - if(_x1 < _x0) _x1--; - } - - if(brush_size == 1) { - draw_line(_x0, _y0, _x1, _y1); - - } else if(brush_size < fix_points_amount) { - - var fx = fix_points[brush_size]; - for( var i = 0, n = array_length(fx); i < n; i++ ) - draw_line(_x0 + fx[i][0], _y0 + fx[i][1], _x1 + fx[i][0], _y1 + fx[i][1]); - - } else - draw_line_width(_x0, _y0, _x1, _y1, brush_size); - - } else { - var diss = point_distance(_x0, _y0, _x1, _y1); - var dirr = point_direction(_x0, _y0, _x1, _y1); - var st_x = lengthdir_x(1, dirr); - var st_y = lengthdir_y(1, dirr); - - var _i = _draw? brush_next_dist : 0; - var _dst = diss; - - if(_i < diss) { - while(_i < diss) { - var _px = _x0 + st_x * _i; - var _py = _y0 + st_y * _i; - - draw_point_size(_px, _py, _draw); - - brush_next_dist = random_range(brush_dist_min, brush_dist_max); - _i += brush_next_dist; - _dst -= brush_next_dist; - } - - brush_next_dist -= _dst; - } else - brush_next_dist -= diss; - - if(brush_dist_min == brush_dist_max && brush_dist_min == 1) - draw_point_size(_x1, _y1, _draw); - } - } #endregion - - function draw_rect_size(_x0, _y0, _x1, _y1, _fill) { #region - if(_x0 == _x1 && _y0 == _y1) { - draw_point_size(_x0, _y0); - return; - } else if(_x0 == _x1) { - draw_point_size(_x0, _y0); - draw_point_size(_x1, _y1); - draw_line_size(_x0, _y0, _x0, _y1); - return; - } else if(_y0 == _y1) { - draw_point_size(_x0, _y0); - draw_point_size(_x1, _y1); - draw_line_size(_x0, _y0, _x1, _y0); - return; - } - - var _min_x = min(_x0, _x1); - var _max_x = max(_x0, _x1); - var _min_y = min(_y0, _y1); - var _may_y = max(_y0, _y1); - - if(_fill) draw_rectangle(_min_x, _min_y, _max_x, _may_y, 0); - - if(brush_size == 1 && brush_surface == noone) - draw_rectangle(_min_x + 1, _min_y + 1, _max_x - 1, _may_y - 1, 1); - else { - draw_set_color(c_red); draw_line_size(_min_x, _min_y, _max_x, _min_y); - draw_set_color(c_blue); draw_line_size(_min_x, _min_y, _min_x, _may_y); - draw_set_color(c_green); draw_line_size(_max_x, _may_y, _max_x, _min_y); - draw_set_color(c_yellow); draw_line_size(_max_x, _may_y, _min_x, _may_y); - } - } #endregion - - function draw_ellp_size(_x0, _y0, _x1, _y1, _fill) { #region - if(_x0 == _x1 && _y0 == _y1) { - draw_point_size(_x0, _y0); - return; - } else if(_x0 == _x1) { - draw_point_size(_x0, _y0); - draw_point_size(_x1, _y1); - draw_line_size(_x0, _y0, _x0, _y1); - return; - } else if(_y0 == _y1) { - draw_point_size(_x0, _y0); - draw_point_size(_x1, _y1); - draw_line_size(_x0, _y0, _x1, _y0); - return; - } - - var _min_x = min(_x0, _x1) - 1; - var _max_x = max(_x0, _x1); - var _min_y = min(_y0, _y1) - 1; - var _max_y = max(_y0, _y1); - - if(_fill) draw_ellipse(_min_x, _min_y, _max_x, _max_y, 0); - - var samp = 64; - var cx = (_min_x + _max_x) / 2; - var cy = (_min_y + _max_y) / 2; - var rx = abs(_x0 - _x1) / 2; - var ry = abs(_y0 - _y1) / 2; - - var ox, oy, nx, ny; - for( var i = 0; i <= samp; i++ ) { - nx = cx + lengthdir_x(rx, 360 / samp * i); - ny = cy + lengthdir_y(ry, 360 / samp * i); - - if(i) draw_line_size(ox, oy, nx, ny); - - ox = nx; - oy = ny; - } - } #endregion - - function get_color_buffer(_x, _y) { #region - var _cbuffer = canvas_buffer[preview_index]; - var pos = (surface_w * _y + _x) * 4; - if(pos >= buffer_get_size(_cbuffer)) { - print("Error buffer overflow " + string(pos) + "/" + string(buffer_get_size(_cbuffer))); - return 0; - } - - buffer_seek(_cbuffer, buffer_seek_start, pos); - var c = buffer_read(_cbuffer, buffer_u32); - - return c; - } #endregion - - function ff_fillable(colorBase, colorFill, _x, _y, _thres) { #region - var d = color_diff(colorBase, get_color_buffer(_x, _y), true, true); - return d <= _thres && d != colorFill; - } #endregion - - function flood_fill_scanline(_x, _y, _surf, _thres, _corner = false) { #region - var colorFill = draw_get_color() + (255 << 24); - var colorBase = get_color_buffer(_x, _y); - - if(colorFill == colorBase) return; //Clicking on the same color as the fill color - - var _alp = _color_get_alpha(tool_attribute.color); - draw_set_alpha(_alp); - - var x1, y1, x_start; - var spanAbove, spanBelow; - var thr = _thres * _thres; - - var queue = ds_queue_create(); - ds_queue_enqueue(queue, [_x, _y]); - - while(!ds_queue_empty(queue)) { - var pos = ds_queue_dequeue(queue); - x1 = pos[0]; - y1 = pos[1]; - - var colorCurr = get_color_buffer(x1, y1); - //print($"Searching {x1}, {y1}: {colorCurr}"); - - if(colorCurr == colorFill) continue; //Color in queue is already filled - - while(x1 > 0 && ff_fillable(colorBase, colorFill, x1 - 1, y1, thr)) //Move to the leftmost connected pixel in the same row. - x1--; - x_start = x1; - - spanAbove = false; - spanBelow = false; - - while(x1 < surface_w && ff_fillable(colorBase, colorFill, x1, y1, thr)) { - draw_point(x1, y1); - - var _cbuffer = canvas_buffer[preview_index]; - buffer_seek(_cbuffer, buffer_seek_start, (surface_w * y1 + x1) * 4); - buffer_write(_cbuffer, buffer_u32, colorFill); - - //print($"> Filling {x1}, {y1}: {get_color_buffer(x1, y1)}"); - - if(y1 > 0) { - if(_corner && x1 > 0 && ff_fillable(colorBase, colorFill, x1 - 1, y1 - 1, thr)) //Check top left pixel - ds_queue_enqueue(queue, [x1 - 1, y1 - 1]); - - if(ff_fillable(colorBase, colorFill, x1, y1 - 1, thr)) //Check top pixel - ds_queue_enqueue(queue, [x1, y1 - 1]); - } - - if(y1 < surface_h - 1) { - if(_corner && x1 > 0 && ff_fillable(colorBase, colorFill, x1 - 1, y1 + 1, thr)) //Check bottom left pixel - ds_queue_enqueue(queue, [x1 - 1, y1 + 1]); - - if(ff_fillable(colorBase, colorFill, x1, y1 + 1, thr)) //Check bottom pixel - ds_queue_enqueue(queue, [x1, y1 + 1]); - } - - if(_corner && x1 < surface_w - 1) { - if(y1 > 0 && ff_fillable(colorBase, colorFill, x1 + 1, y1 - 1, thr)) //Check top right pixel - ds_queue_enqueue(queue, [x1 + 1, y1 - 1]); - - if(y1 < surface_h - 1 && ff_fillable(colorBase, colorFill, x1 + 1, y1 + 1, thr)) //Check bottom right pixel - ds_queue_enqueue(queue, [x1 + 1, y1 + 1]); - } - - x1++; - } - } - - draw_set_alpha(1); - } #endregion - - function canvas_fill(_x, _y, _surf, _thres) { #region - var _alp = _color_get_alpha(tool_attribute.color); - - var w = surface_get_width_safe(_surf); - var h = surface_get_height_safe(_surf); - - var _c1 = get_color_buffer(_x, _y); - var thr = _thres * _thres; - - draw_set_alpha(_alp); - for( var i = 0; i < w; i++ ) { - for( var j = 0; j < h; j++ ) { - if(i == _x && j == _y) { - draw_point(i, j); - continue; - } - - var _c2 = get_color_buffer(i, j); - if(color_diff(_c1, _c2, true) <= thr) - draw_point(i, j); - } - } - draw_set_alpha(1); - } #endregion - - function freeform_step(active, _x, _y, _s, _mx, _my, _draw) { #region - var _dim = attributes.dimension; - - var _mmx = (_mx - _x) / _s; - var _mmy = (_my - _y) / _s; - brush_size = 1; - - if(mouse_holding) { - if(abs(_mmx - mouse_pre_x) + abs(_mmy - mouse_pre_y) >= 1) { - - if(_draw) { - surface_set_target(drawing_surface); - draw_line_size(round(mouse_pre_x - 0.5), round(mouse_pre_y - 0.5), round(_mmx - 0.5), round(_mmy - 0.5), true); - surface_reset_target(); - } - - mouse_pre_x = _mmx; - mouse_pre_y = _mmy; - - array_push(freeform_shape, new __vec2(_mmx, _mmy) ); - } - - if(mouse_release(mb_left)) { - - surface_set_target(drawing_surface); - draw_line_size(_mmx, _mmy, freeform_shape[0].x, freeform_shape[0].y, true); - surface_reset_target(); - - if(array_length(freeform_shape) > 3) { - var _triangles = polygon_triangulate(freeform_shape, 1); - - temp_surface[0] = surface_verify(temp_surface[0], _dim[0], _dim[1]); - - surface_set_target(temp_surface[0]); - draw_primitive_begin(pr_trianglelist); - for( var i = 0, n = array_length(_triangles); i < n; i++ ) { - var p0 = _triangles[i][0]; - var p1 = _triangles[i][1]; - var p2 = _triangles[i][2]; - - draw_vertex(round(p0.x), round(p0.y)); - draw_vertex(round(p1.x), round(p1.y)); - draw_vertex(round(p2.x), round(p2.y)); - } - draw_primitive_end(); - draw_surface(drawing_surface, 0, 0); - surface_reset_target(); - - surface_set_shader(drawing_surface, sh_freeform_fill_cleanup); - shader_set_f("dimension", _dim); - - draw_surface_ext(temp_surface[0], 0, 0, 1, 1, 0, draw_get_color(), draw_get_alpha()); - surface_reset_shader(); - } - - mouse_holding = false; - } - - } else if(mouse_press(mb_left, active)) { - mouse_pre_x = _mmx; - mouse_pre_y = _mmy; - - mouse_holding = true; - freeform_shape = [ new __vec2(_mmx, _mmy) ]; - - surface_clear(drawing_surface); - } + if(tool_selection.is_selected) surface_free(_tmp); } #endregion static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region if(instance_exists(o_dialog_color_picker)) return; - mouse_cur_x = round((_mx - _x) / _s - 0.5); - mouse_cur_y = round((_my - _y) / _s - 0.5); + COLORS_GLOBAL_GET = getToolColor; + COLORS_GLOBAL_SET = setToolColor; - var _dim = attributes.dimension; - var _col = tool_attribute.color; - var _siz = tool_attribute.size; - var _thr = tool_attribute.thres; - var _fill_type = tool_attribute.fill8; + brush.node = self; + brush.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); - var _prev = getInputData(5); - var _brushSurf = getInputData(6); - var _brushDist = getInputData(15); - var _brushRotD = getInputData(16); - var _brushRotR = getInputData(17); - - var _applySelection = false; - - if(PEN_USE && tool_attribute.pressure) - brush_size = round(lerp(tool_attribute.pressure_size[0], tool_attribute.pressure_size[1], power(PEN_PRESSURE / 1024, 2))); - else - brush_size = _siz; - - brush_dist_min = max(1, _brushDist[0]); - brush_dist_max = max(1, _brushDist[1]); - brush_surface = is_surface(_brushSurf)? _brushSurf : noone; - if(!_brushRotD) - brush_direction = 0; - else if(mouse_pre_dir_x == undefined) { - mouse_pre_dir_x = _mx; - mouse_pre_dir_y = _my; - } else if(point_distance(mouse_pre_dir_x, mouse_pre_dir_y, _mx, _my) > _s) { - brush_direction = point_direction(mouse_pre_dir_x, mouse_pre_dir_y, _mx, _my); - mouse_pre_dir_x = _mx; - mouse_pre_dir_y = _my; - } - - brush_rand_dir = _brushRotR; - - #region color selector - if(active && key_mod_press(ALT)) { - var dialog = instance_create(0, 0, o_dialog_color_picker); - dialog.onApply = setToolColor; - dialog.def_c = _col; - } - #endregion - - var _canvas_surface = getCanvasSurface(); - - if(!surface_exists(_canvas_surface)) return; - - var _surf_w = surface_get_width_safe(_canvas_surface); - var _surf_h = surface_get_height_safe(_canvas_surface); - - #region drawing surface review - _drawing_surface = surface_verify(_drawing_surface, _surf_w, _surf_h); - surface_set_target(_drawing_surface); - DRAW_CLEAR - draw_surface_safe(drawing_surface); - surface_reset_target(); - #endregion - - if(!isUsingTool("Selection") && is_surface(selection_surface)) { #region - var pos_x = selection_position[0]; - var pos_y = selection_position[1]; - - surface_set_target(_canvas_surface); - BLEND_ALPHA - draw_surface_safe(selection_surface, pos_x, pos_y); - BLEND_NORMAL - surface_reset_target(); - - surface_store_buffer(); - surface_free(selection_surface); + if(active && key_mod_press(ALT)) { #region color selector + var dialog = instance_create(0, 0, o_dialog_color_picker); + dialog.onApply = setToolColor; + dialog.def_c = tool_attribute.color; } #endregion - draw_set_color(_col); + var _canvas_surface = getCanvasSurface(); + if(!surface_exists(_canvas_surface)) return; - if(!isUsingTool("Selection")) gpu_set_colorwriteenable(tool_attribute.channel[0], tool_attribute.channel[1], tool_attribute.channel[2], tool_attribute.channel[3]); - - var _tool_resizable = false; - - if(isUsingTool("Selection")) { #region + var _dim = attributes.dimension; + _drawing_surface = surface_verify(_drawing_surface, _dim[0], _dim[1]); + drawing_surface = surface_verify( drawing_surface, _dim[0], _dim[1], attrDepth()); - if(is_selected) { #region selected - if(!is_surface(selection_surface)) { - is_selected = false; - } else { - if(is_select_drag) { - var px = selection_sx + (mouse_cur_x - selection_mx); - var py = selection_sy + (mouse_cur_y - selection_my); - - selection_position[0] = px; - selection_position[1] = py; - - if(mouse_release(mb_left)) - is_select_drag = false; - } + surface_set_target(_drawing_surface); + DRAW_CLEAR + draw_surface_safe(drawing_surface); + surface_reset_target(); + + #region selection + tool_selection.node = self; + tool_selection.drawing_surface = drawing_surface; + tool_selection._canvas_surface = _canvas_surface; + tool_selection.apply_draw_surface = apply_draw_surface; + #endregion + + #region tool + var _tool = noone; + var _currTool = PANEL_PREVIEW.tool_current; + + if(_currTool != noone) { + switch(_currTool.getName()) { + case "Pencil" : _tool = tool_brush; break; + case "Eraser" : _tool = tool_eraser; break; + case "Fill" : _tool = tool_fill; break; + case "Freeform" : _tool = tool_freeform; break; - if(mouse_press(mb_left, active)) { - var pos_x = selection_position[0]; - var pos_y = selection_position[1]; - var sel_w = surface_get_width_safe(selection_surface); - var sel_h = surface_get_height_safe(selection_surface); - - if(point_in_rectangle(mouse_cur_x, mouse_cur_y, pos_x, pos_y, pos_x + sel_w, pos_y + sel_h)) { - is_select_drag = true; - selection_sx = pos_x; - selection_sy = pos_y; - selection_mx = mouse_cur_x; - selection_my = mouse_cur_y; - } else { - is_selected = false; - - surface_set_target(_canvas_surface); - BLEND_ALPHA - draw_surface_safe(selection_surface, pos_x, pos_y); - BLEND_NORMAL - surface_reset_target(); - - surface_store_buffer(); - _applySelection = true; + case "Rectangle" : + _tool = tool_rectangle; + _tool.fill = _currTool.selecting == 1; + break; + + case "Ellipse" : + _tool = tool_ellipse; + _tool.fill = _currTool.selecting == 1; + break; + + case "Selection" : + switch(_currTool.selecting) { + case 0 : _tool = tool_sel_rectangle; break; + case 1 : _tool = tool_sel_ellipse; break; + case 2 : _tool = tool_sel_freeform; break; } - } - } - } else { #region selection - - if(isUsingTool("Selection", 2) && mouse_press(mb_left, active)) { - is_selecting = true; - surface_free_safe(selection_mask); - } - - if(is_selecting) { - var sel_x0, sel_y0, sel_x1, sel_y1; - var sel_w = 1, sel_h = 1; - - if(isUsingTool("Selection", 2)) { #region freeform - freeform_step(active, _x, _y, _s, _mx, _my, false); - - if(mouse_release(mb_left)) { - is_selecting = false; - - sel_x0 = _dim[0]; - sel_y0 = _dim[1]; - sel_x1 = 0; - sel_y1 = 0; - - for( var i = 0, n = array_length(freeform_shape); i < n; i++ ) { - var _f = freeform_shape[i]; - - sel_x0 = min(sel_x0, round(_f.x - 0.5)); - sel_y0 = min(sel_y0, round(_f.y - 0.5)); - sel_x1 = max(sel_x1, round(_f.x - 0.5)); - sel_y1 = max(sel_y1, round(_f.y - 0.5)); - } - - sel_w = sel_x1 - sel_x0 + 1; - sel_h = sel_y1 - sel_y0 + 1; - - if(sel_w > 1 && sel_h > 1) { - selection_mask = surface_verify(selection_mask, sel_w, sel_h); - surface_set_target(selection_mask); - DRAW_CLEAR - draw_surface(drawing_surface, -sel_x0, -sel_y0); - surface_reset_target(); - } - - surface_clear(drawing_surface); - } - #endregion - - } else { #region shape - sel_x0 = min(selection_sx, mouse_cur_x); - sel_y0 = min(selection_sy, mouse_cur_y); - sel_x1 = max(selection_sx, mouse_cur_x); - sel_y1 = max(selection_sy, mouse_cur_y); - - sel_w = sel_x1 - sel_x0 + 1; - sel_h = sel_y1 - sel_y0 + 1; - - selection_mask = surface_verify(selection_mask, sel_w, sel_h); - surface_set_target(selection_mask); - DRAW_CLEAR - draw_set_color(c_white); - if(isUsingTool("Selection", 0)) - draw_rectangle(0, 0, sel_w, sel_h, false); - - else if(isUsingTool("Selection", 1)) { - draw_set_circle_precision(32); - draw_ellipse(0, 0, sel_w - 1, sel_h - 1, false); - } - surface_reset_target(); - #endregion - } - - if(mouse_release(mb_left)) is_selecting = false; - - if(mouse_release(mb_left) && sel_w > 1 && sel_h > 1) { - is_selected = true; - selection_surface = surface_create(sel_w, sel_h); - surface_set_target(selection_surface); - DRAW_CLEAR - draw_surface_safe(_canvas_surface, -sel_x0, -sel_y0); - - BLEND_MULTIPLY - draw_surface_safe(selection_mask, 0, 0); - BLEND_NORMAL - surface_reset_target(); - - storeAction(); - surface_set_target(_canvas_surface); - gpu_set_blendmode(bm_subtract); - draw_surface_safe(selection_surface, sel_x0, sel_y0); - gpu_set_blendmode(bm_normal); - surface_reset_target(); + if(tool_selection.is_selected) tool_selection.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); + break; - surface_store_buffer(); + case "Magic Selection" : + _tool = tool_sel_magic; - selection_position = [ sel_x0, sel_y0 ]; - } - - } else { - if(mouse_press(mb_left, active)) { - is_selecting = true; - selection_sx = mouse_cur_x; - selection_sy = mouse_cur_y; - - surface_free_safe(selection_mask); - } - } - } #endregion - - #endregion - } else if(isUsingTool("Pencil") || isUsingTool("Eraser")) { #region - - if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT) && key_mod_press(CTRL)) { - var aa = point_direction(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); - var dd = point_distance(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); - var _a = round(aa / 45) * 45; - dd = dd * cos(degtorad(_a - aa)); - - mouse_cur_x = mouse_pre_draw_x + lengthdir_x(dd, _a); - mouse_cur_y = mouse_pre_draw_y + lengthdir_y(dd, _a); - } - - if(mouse_press(mb_left, active)) { - brush_next_dist = 0; - drawing_surface = surface_verify(drawing_surface, _dim[0], _dim[1], attrDepth()); - - surface_set_shader(drawing_surface, noone); - draw_point_size(mouse_cur_x, mouse_cur_y, true); - surface_reset_shader(); - - mouse_holding = true; - if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT)) { ///////////////// shift line - surface_set_shader(drawing_surface, noone, true, BLEND.alpha); - brush_next_dist = 0; - draw_line_size(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y, true); - surface_reset_shader(); - mouse_holding = false; - - apply_draw_surface(); - } - - mouse_pre_draw_x = mouse_cur_x; - mouse_pre_draw_y = mouse_cur_y; - } - - if(mouse_holding) { - var _move = mouse_pre_draw_x != mouse_cur_x || mouse_pre_draw_y != mouse_cur_y; - var _1stp = brush_dist_min == brush_dist_max && brush_dist_min == 1; - - if(_move || !_1stp) { - surface_set_shader(drawing_surface, noone, false, BLEND.alpha); - if(_1stp) draw_point_size(mouse_cur_x, mouse_cur_y, true); - draw_line_size(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y, true); - surface_reset_shader(); - } - - mouse_pre_draw_x = mouse_cur_x; - mouse_pre_draw_y = mouse_cur_y; - - if(mouse_release(mb_left)) { - mouse_holding = false; - apply_draw_surface(); - } - } - - BLEND_NORMAL; - - mouse_pre_x = mouse_cur_x; - mouse_pre_y = mouse_cur_y; - - _tool_resizable = true; - - #endregion - } else if(isUsingTool("Rectangle") || isUsingTool("Ellipse")) { #region - - if(mouse_holding && key_mod_press(SHIFT)) { - var ww = mouse_cur_x - mouse_pre_x; - var hh = mouse_cur_y - mouse_pre_y; - var ss = max(abs(ww), abs(hh)); - - mouse_cur_x = mouse_pre_x + ss * sign(ww); - mouse_cur_y = mouse_pre_y + ss * sign(hh); - } - - if(mouse_holding) { - drawing_surface = surface_verify(drawing_surface, _dim[0], _dim[1], attrDepth()); - - surface_set_shader(drawing_surface, noone); - if(isUsingTool("Rectangle")) - draw_rect_size(mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, isUsingTool("Rectangle", 1)); - else if(isUsingTool("Ellipse")) - draw_ellp_size(mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, isUsingTool("Ellipse", 1)); - surface_reset_shader(); - - if(mouse_release(mb_left)) { - apply_draw_surface(); - mouse_holding = false; - } - } else if(mouse_press(mb_left, active)) { - mouse_pre_x = mouse_cur_x; - mouse_pre_y = mouse_cur_y; - - mouse_holding = true; - } - - _tool_resizable = true; - - #endregion - } else if(isUsingTool("Freefrom")) { #region - freeform_step(active, _x, _y, _s, _mx, _my, true); - - if(mouse_release(mb_left)) - apply_draw_surface(); - - #endregion - } else if(isUsingTool("Fill") || (DRAGGING && DRAGGING.type == "Color")) { #region - - var fill = DRAGGING? mouse_release(mb_left, active) : mouse_press(mb_left, active); - - if(fill && point_in_rectangle(mouse_cur_x, mouse_cur_y, 0, 0, _surf_w - 1, _surf_h - 1)) { - storeAction(); - surface_set_target(_canvas_surface); - if(DRAGGING) draw_set_color(DRAGGING.data); - switch(_fill_type) { - case 0 : - flood_fill_scanline(mouse_cur_x, mouse_cur_y, _canvas_surface, _thr, false); + if(tool_selection.is_selected) tool_selection.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); break; - case 1 : - flood_fill_scanline(mouse_cur_x, mouse_cur_y, _canvas_surface, _thr, true); - break; - case 2 : - canvas_fill(mouse_cur_x, mouse_cur_y, _canvas_surface, _thr); - break; - } - surface_store_buffer(); - surface_reset_target(); + + } } - #endregion - } - if(_tool_resizable) { #region tools size - if(hover && key_mod_press(CTRL)) { - if(mouse_wheel_down()) tool_attribute.size = max( 1, tool_attribute.size - 1); - if(mouse_wheel_up()) tool_attribute.size = min(64, tool_attribute.size + 1); - } + draw_set_color(tool_attribute.color); + gpu_set_colorwriteenable(tool_attribute.channel[0], tool_attribute.channel[1], tool_attribute.channel[2], tool_attribute.channel[3]); + + if(_tool) { #region tool step - if(brush_sizing) { - var s = brush_sizing_s + (_mx - brush_sizing_mx) / 16; - s = max(1, s); - tool_attribute.size = s; + _tool.drawing_surface = drawing_surface; + _tool._canvas_surface = _canvas_surface; + + _tool.apply_draw_surface = apply_draw_surface; + _tool.brush = brush; + + _tool.node = self; + + if(_tool.relative && tool_selection.is_selected) { + _tool._canvas_surface = tool_selection.selection_surface; + var _px = tool_selection.selection_position[0]; + var _py = tool_selection.selection_position[1]; + var _rx = _x + _px * _s; + var _ry = _y + _py * _s; - if(mouse_release(mb_right)) - brush_sizing = false; - - } else if(mouse_press(mb_right, active) && key_mod_press(SHIFT) && brush_surface == noone) { + _tool.step(hover, active, _rx, _ry, _s, _mx, _my, _snx, _sny); + } else + _tool.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); + + if(_tool.brush_resizable) { + if(hover && key_mod_press(CTRL)) { + if(mouse_wheel_down()) tool_attribute.size = max( 1, tool_attribute.size - 1); + if(mouse_wheel_up()) tool_attribute.size = min(64, tool_attribute.size + 1); + } - brush_sizing = true; - brush_sizing_s = _siz; - brush_sizing_mx = _mx; - brush_sizing_my = _my; - - brush_sizing_dx = mouse_cur_x; - brush_sizing_dy = mouse_cur_y; - } + brush.sizing(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); + } } #endregion @@ -1227,89 +576,35 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor gpu_set_colorwriteenable(true, true, true, true); #region preview - var _bg = getInputData(8); - var _bga = getInputData(9); - var _bgr = getInputData(10); - var _alp = _color_get_alpha(_col); - - var __s = surface_get_target(); + var _alp = _color_get_alpha(tool_attribute.color); + var __s = surface_get_target(); prev_surface = surface_verify(prev_surface, _dim[0], _dim[1]); preview_draw_surface = surface_verify(preview_draw_surface, _dim[0], _dim[1]); _preview_draw_surface = surface_verify(_preview_draw_surface, surface_get_width_safe(__s), surface_get_height_safe(__s)); + if(tool_selection.is_selected) tool_selection.drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); + surface_set_shader(preview_draw_surface, noone,, BLEND.alpha); + if(tool_selection.is_selected) tool_selection.drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); draw_surface_safe(_drawing_surface, 0, 0); - draw_set_color(_col); - if(isUsingTool("Selection")) { - if(is_selected || _applySelection) - draw_surface_safe(selection_surface, selection_position[0], selection_position[1]); - - else if(is_selecting) { - var sel_x0 = min(selection_sx, mouse_cur_x); - var sel_y0 = min(selection_sy, mouse_cur_y); - draw_surface_safe(selection_mask, sel_x0, sel_y0); - } - - if(_applySelection) surface_free(selection_surface); - - } else if(isUsingTool("Pencil") || isUsingTool("Eraser")) { - if(isUsingTool("Eraser")) draw_set_color(c_white); - - if(brush_sizing) { - draw_point_size(brush_sizing_dx, brush_sizing_dy); - } else { - if(mouse_pre_draw_x != undefined && mouse_pre_draw_y != undefined && key_mod_press(SHIFT)) - draw_line_size(mouse_pre_draw_x, mouse_pre_draw_y, mouse_cur_x, mouse_cur_y); - else - draw_point_size(mouse_cur_x, mouse_cur_y); - } - - } else if(isUsingTool("Rectangle")) { - if(brush_sizing) - draw_point_size(brush_sizing_dx, brush_sizing_dy); - else if(mouse_holding) - draw_rect_size(mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, isUsingTool("Rectangle", 1)); - else - draw_point_size(mouse_cur_x, mouse_cur_y); - - } else if(isUsingTool("Ellipse")) { - if(brush_sizing) - draw_point_size(brush_sizing_dx, brush_sizing_dy); - else if(mouse_holding) - draw_ellp_size(mouse_pre_x, mouse_pre_y, mouse_cur_x, mouse_cur_y, isUsingTool("Ellipse", 1)); - else - draw_point_size(mouse_cur_x, mouse_cur_y); - - } else if(isUsingTool("Freefrom")) { - draw_point_size(mouse_cur_x, mouse_cur_y); - } + draw_set_color(tool_attribute.color); + if(brush.brush_sizing) + canvas_draw_point_size(brush, brush.brush_sizing_dx, brush.brush_sizing_dy); + else if(_tool) + _tool.drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); + surface_reset_shader(); - if(isUsingTool()) { - var _drawSelection = isUsingTool("Selection") && is_selected; + if(_tool) { + _tool.drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); - if(_drawSelection) { #region - var pos_x = _x + selection_position[0] * _s; - var pos_y = _y + selection_position[1] * _s; - var sel_w = surface_get_width_safe(selection_surface) * _s; - var sel_h = surface_get_height_safe(selection_surface) * _s; - - draw_surface_ext_safe(selection_surface, pos_x, pos_y, _s, _s, 0, c_white, 1); - - draw_set_color(c_black); - draw_rectangle(pos_x, pos_y, pos_x + sel_w, pos_y + sel_h, true); - - draw_set_color(c_white); - draw_rectangle_dashed(pos_x, pos_y, pos_x + sel_w, pos_y + sel_h, true, 6, current_time / 100); - } #endregion - - if(!isUsingTool("Selection") && (active || mouse_holding)) { #region + if(!is_instanceof(_tool, canvas_tool_selection) && (active || _tool.mouse_holding)) { gpu_set_colorwriteenable(tool_attribute.channel[0], tool_attribute.channel[1], tool_attribute.channel[2], tool_attribute.channel[3]); draw_surface_ext_safe(preview_draw_surface, _x, _y, _s, _s, 0, isUsingTool("Eraser")? c_red : c_white, isUsingTool("Eraser")? 0.2 : _alp); gpu_set_colorwriteenable(true, true, true, true); - } #endregion + } surface_set_target(_preview_draw_surface); DRAW_CLEAR @@ -1321,21 +616,7 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor draw_surface_ext_safe(_preview_draw_surface, 0, 0, 1, 1, 0, c_white, 1); shader_reset(); - if(isUsingTool("Selection", 2) && mouse_holding) { #region - var ox, oy, nx, ny; - - draw_set_color(c_white); - - for( var i = 0, n = array_length(freeform_shape); i < n; i++ ) { - nx = _x + freeform_shape[i].x * _s; - ny = _y + freeform_shape[i].y * _s; - - if(i) draw_line(ox, oy, nx, ny); - - ox = nx; - oy = ny; - } - } #endregion + _tool.drawPostOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); } #endregion @@ -1346,9 +627,24 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor draw_set_color(COLORS.panel_preview_surface_outline); draw_rectangle(_x0, _y0, _x1 - 1, _y1 - 1, true); + draw_set_alpha(1); previewing = 1; - draw_set_alpha(1); + + if((_tool == noone || !_tool.mouse_holding) && key_press(ord("V"), MOD_KEY.ctrl)) { #region + var _str = json_try_parse(clipboard_get_text(), noone); + print(clipboard_get_text()) + + if(is_struct(_str) && struct_has(_str, "buffer")) { + var _surf = surface_decode(_str); + + if(is_surface(_surf)) { + tool_selection.selection_surface = _surf; + tool_selection.is_selected = true; + tool_selection.selection_position = [ 0, 0 ]; + } + } + } #endregion } #endregion static step = function() { #region diff --git a/scripts/node_canvas/node_canvas.yy b/scripts/node_canvas/node_canvas.yy index 66fcd2e5e..0d179141c 100644 --- a/scripts/node_canvas/node_canvas.yy +++ b/scripts/node_canvas/node_canvas.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"node_canvas", "parent":{ - "name":"io", - "path":"folders/nodes/data/io.yy", + "name":"canvas", + "path":"folders/nodes/data/canvas.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/node_data/node_data.gml b/scripts/node_data/node_data.gml index 490fb6c72..5922ee6ae 100644 --- a/scripts/node_data/node_data.gml +++ b/scripts/node_data/node_data.gml @@ -268,6 +268,7 @@ function Node(_x, _y, _group = noone) : __Node_Base(_x, _y) constructor { #region ---- tools ---- tools = -1; + rightTools = -1; isTool = false; tool_settings = []; tool_attribute = {}; diff --git a/scripts/panel_color/panel_color.gml b/scripts/panel_color/panel_color.gml index 84ed2031c..6a2988210 100644 --- a/scripts/panel_color/panel_color.gml +++ b/scripts/panel_color/panel_color.gml @@ -5,9 +5,7 @@ enum COLOR_SELECTOR_MODE { function Panel_Color() : PanelContent() constructor { title = __txt("Color"); - showHeader = false; - title_height = 64; - padding = 24; + padding = 8; w = ui(320); h = ui(320); @@ -29,6 +27,9 @@ function Panel_Color() : PanelContent() constructor { hue = color_get_hue(color) / 255; sat = color_get_saturation(color) / 255; val = color_get_value(color) / 255; + + if(COLORS_GLOBAL_SET != noone) + COLORS_GLOBAL_SET(color); } static setHSV = function(h = hue, s = sat, v = val) { @@ -37,25 +38,31 @@ function Panel_Color() : PanelContent() constructor { val = v; color = make_color_hsv(h * 255, s * 255, v * 255); + + if(COLORS_GLOBAL_SET != noone) + COLORS_GLOBAL_SET(color); } setHSV(); function drawContent(panel) { draw_clear_alpha(COLORS.panel_bg_clear, 0); - PANEL_PADDING - PANEL_TITLE var px = ui(padding); - var py = ui(title_height); + var py = ui(padding); var pw = w - ui(padding + padding); - var ph = h - ui(title_height + padding); + var ph = h - ui(padding + padding); draw_sprite_stretched(THEME.ui_panel_bg, 1, px - ui(8), py - ui(8), pw + ui(16), ph + ui(16)); + if(COLORS_GLOBAL_GET != noone) { + var c = COLORS_GLOBAL_GET(); + if(c != color) setColor(c); + } + var cont_x = ui(padding); - var cont_y = ui(title_height); + var cont_y = ui(padding); var cont_w = w - ui(padding + padding + ui(16 + 8)); - var cont_h = h - ui(title_height + padding + ui(24 + 8)); + var cont_h = h - ui(padding + padding + ui(24 + 8)); shader_set(sh_color_select_content); shader_set_i("mode", mode); @@ -64,7 +71,7 @@ function Panel_Color() : PanelContent() constructor { draw_sprite_stretched(s_fx_pixel, 0, cont_x, cont_y, cont_w, cont_h); var sel_x = cont_x + cont_w + ui(8); - var sel_y = ui(title_height); + var sel_y = ui(padding); var sel_w = ui(16); var sel_h = cont_h; @@ -115,6 +122,7 @@ function Panel_Color() : PanelContent() constructor { var cy = cont_y + (1 - val) * cont_h - ui(6); draw_sprite_stretched_ext(s_ui_base_white, 0, sel_x - ui(3), hy - ui(6), ui(16 + 6), ui(10), make_color_hsv(hue * 255, 255, 255), 1); draw_sprite_stretched_ext(s_ui_base_white, 0, cx, cy, ui(12), ui(12), color, 1); + } else if(mode == 1) { var vy = sel_y + (1 - val) * sel_h; var cx = cont_x + hue * cont_w - ui(6); @@ -137,11 +145,17 @@ function Panel_Color() : PanelContent() constructor { draw_sprite_stretched_ext(THEME.ui_panel_active, 0, cx, cy, ui(24), ui(24), c_white, 1); if(mouse_press(mb_left, pFOCUS)) { array_insert(colors, 0, color); - DRAGGING = { - type: "Color", - data: color + + if(COLORS_GLOBAL_SET != noone) { + COLORS_GLOBAL_SET(color); + + } else { + DRAGGING = { + type: "Color", + data: color + } + MESSAGE = DRAGGING; } - MESSAGE = DRAGGING; } } continue; @@ -159,14 +173,6 @@ function Panel_Color() : PanelContent() constructor { } } - var bx = w - ui(32 + 16); - var by = title_height / 2 - ui(16 + !in_dialog * 2); - - if(buttonInstant(THEME.button_hide, bx, by, ui(32), ui(32), [mx, my], pFOCUS, pHOVER, __txt("Mode"), THEME.color_wheel,, c_white) == 2) - mode = !mode; - - bx -= ui(32); - if(DRAGGING && DRAGGING.type == "Color" && pHOVER) { draw_sprite_stretched_ext(THEME.ui_panel_active, 0, 2, 2, w - 4, h - 4, COLORS._main_value_positive, 1); if(mouse_release(mb_left)) diff --git a/scripts/panel_palette/panel_palette.gml b/scripts/panel_palette/panel_palette.gml index 1f9f7bb35..879e18ea2 100644 --- a/scripts/panel_palette/panel_palette.gml +++ b/scripts/panel_palette/panel_palette.gml @@ -1,8 +1,6 @@ function Panel_Palette() : PanelContent() constructor { title = __txt("Palettes"); - showHeader = false; - title_height = 64; - padding = 24; + padding = 8; w = ui(320); h = ui(480); @@ -14,10 +12,10 @@ function Panel_Palette() : PanelContent() constructor { function onResize() { PANEL_PADDING - sp_palettes.resize(w - ui(padding + padding), h - ui(title_height + padding)); + sp_palettes.resize(w - ui(padding + padding), h - ui(padding + padding)); } - sp_palettes = new scrollPane(w - ui(padding + padding), h - ui(title_height + padding), function(_y, _m) { + sp_palettes = new scrollPane(w - ui(padding + padding), h - ui(padding + padding), function(_y, _m) { draw_clear_alpha(COLORS.panel_bg_clear, 0); var ww = sp_palettes.surface_w; var hh = ui(28); @@ -48,28 +46,56 @@ function Panel_Palette() : PanelContent() constructor { draw_text(ui(10), yy + ui(2), preset.name); drawPaletteGrid(preset.palette, ui(10), yy + ui(24), ww - ui(20), _gs); - if(isHover && mouse_press(mb_left, pFOCUS)) { - if(point_in_rectangle(_m[0], _m[1], ui(10), yy + ui(24), ww - ui(10), yy + ui(24) + _height)) { - var m_ax = _m[0] - ui(10); - var m_ay = _m[1] - (yy + ui(24)); + if(isHover) { + if(mouse_press(mb_left, pFOCUS)) { + if(point_in_rectangle(_m[0], _m[1], ui(10), yy + ui(24), ww - ui(10), yy + ui(24) + _height)) { + var m_ax = _m[0] - ui(10); + var m_ay = _m[1] - (yy + ui(24)); - var m_gx = floor(m_ax / _gs); - var m_gy = floor(m_ay / _gs); + var m_gx = floor(m_ax / _gs); + var m_gy = floor(m_ay / _gs); - var _index = m_gy * col + m_gx; - if(_index < pre_amo && _index >= 0) { + var _index = m_gy * col + m_gx; + if(_index < pre_amo && _index >= 0) { + if(COLORS_GLOBAL_SET != noone) { + COLORS_GLOBAL_SET(array_safe_get_fast(preset.palette, _index)); + + } else { + DRAGGING = { + type: "Color", + data: array_safe_get_fast(preset.palette, _index) + } + MESSAGE = DRAGGING; + } + } + } else if(point_in_rectangle(_m[0], _m[1], ui(10), yy, ww - ui(10), yy + ui(24))) { DRAGGING = { - type: "Color", - data: array_safe_get_fast(preset.palette, _index) + type: "Palette", + data: preset.palette } MESSAGE = DRAGGING; } - } else if(point_in_rectangle(_m[0], _m[1], ui(10), yy, ww - ui(10), yy + ui(24))) { - DRAGGING = { - type: "Palette", - data: preset.palette - } - MESSAGE = DRAGGING; + } + + if(mouse_press(mb_right, pFOCUS)) { + hovering = preset; + + menuCall("palette_window_preset_menu",,, [ + menuItem(__txt("Refresh"), function() { + __initPalette(); + }), + menuItem(__txtx("palette_change_preview_size", "Change preview size"), function() { + view_mode = (view_mode + 1) % 3; + }), + -1, + menuItem(__txtx("palette_editor_set_default", "Set as default"), function() { + DEF_PALETTE = array_clone(hovering.palette); + }), + menuItem(__txtx("palette_editor_delete", "Delete palette"), function() { + file_delete(hovering.path); + __initPalette(); + }), + ]); } } @@ -82,27 +108,16 @@ function Panel_Palette() : PanelContent() constructor { function drawContent(panel) { draw_clear_alpha(COLORS.panel_bg_clear, 0); - PANEL_PADDING - PANEL_TITLE var px = ui(padding); - var py = ui(title_height); + var py = ui(padding); var pw = w - ui(padding + padding); - var ph = h - ui(title_height + padding); + var ph = h - ui(padding + padding); draw_sprite_stretched(THEME.ui_panel_bg, 1, px - ui(8), py - ui(8), pw + ui(16), ph + ui(16)); sp_palettes.setFocusHover(pFOCUS, pHOVER); sp_palettes.draw(px, py, mx - px, my - py); - var bx = w - ui(32 + 16); - var by = title_height / 2 - ui(16 + !in_dialog * 2); - - if(buttonInstant(THEME.button_hide, bx, by, ui(32), ui(32), [mx, my], pFOCUS, pHOVER, __txt("Refresh"), THEME.refresh_icon, 1, COLORS._main_icon) == 2) - __initPalette(); - - bx -= ui(32) - if(buttonInstant(THEME.button_hide, bx, by, ui(32), ui(32), [mx, my], pFOCUS, pHOVER, __txtx("palette_change_preview_size", "Change preview size"), THEME.icon_visibility, 1, COLORS._main_icon) == 2) - view_mode = (view_mode + 1) % 3; } } \ No newline at end of file diff --git a/scripts/panel_preview/panel_preview.gml b/scripts/panel_preview/panel_preview.gml index aa28cdd7f..9eacf9b0b 100644 --- a/scripts/panel_preview/panel_preview.gml +++ b/scripts/panel_preview/panel_preview.gml @@ -1188,6 +1188,8 @@ function Panel_Preview() : PanelContent() constructor { overlayHover &= !key_mod_press(CTRL); var params = { w, h, toolbar_height }; + reset_global_getset(); + if(_node.is_3D) { if(key_mod_press(CTRL) || d3_tool_snap) { _snx = d3_tool_snap_position; @@ -1324,6 +1326,57 @@ function Panel_Preview() : PanelContent() constructor { if(mouse_wheel_up()) tool_y_to = clamp(tool_y_to + ui(64) * SCROLL_SPEED, -tool_y_max, 0); if(mouse_wheel_down()) tool_y_to = clamp(tool_y_to - ui(64) * SCROLL_SPEED, -tool_y_max, 0); } + + if(_node.rightTools != -1) { + var _tbx = w - toolbar_width; + var xx = _tbx + ui(1) + toolbar_width / 2; + var yy = ui(34) + tool_size / 2 + tool_y; + + var _sw = -toolbar_width / sprite_get_width(THEME.tool_side); + var _sh = h - toolbar_height - ui(32) / sprite_get_height(THEME.tool_side); + + draw_sprite_ext(THEME.tool_side, 1, w + 1, ui(32), _sw, _sh, 0, c_white, aa); + + var thov = pHOVER && point_in_rectangle(mx, my, _tbx, toolbar_height, w, h - toolbar_height); + if(thov) canvas_hover = false; + + for(var i = 0; i < array_length(_node.rightTools); i++) { #region iterate each tools + var tool = _node.rightTools[i]; + var _x0 = xx - tool_size / 2; + var _y0 = yy - tool_size / 2; + var _x1 = xx + tool_size / 2; + var _y1 = yy + tool_size / 2; + + if(thov && point_in_rectangle(_mx, _my, _x0, _y0 + 1, _x1, _y1 - 1)) + tool_hovering = tool; + + if(tool_hovering == tool) { + draw_sprite_stretched(THEME.button_hide, 1, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2); + TOOLTIP = tool.getDisplayName(); + + if(mouse_press(mb_left, pFOCUS)) + tool.toggle(); + } + + if(pFOCUS && WIDGET_CURRENT == noone) { + var _key = tool.checkHotkey(); + + if(_key != "" && keyboard_check_pressed(ord(_key))) + tool.toggleKeyboard(); + } + + if(tool_current == tool) { + draw_sprite_stretched_ext(THEME.button_hide, 2, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS.panel_preview_grid, 1); + draw_sprite_stretched_ext(THEME.button_hide, 3, _x0 + pd, _y0 + pd, tool_size - pd * 2, tool_size - pd * 2, COLORS._main_accent, 1); + } + + draw_sprite_colored(tool.spr, 0, xx, yy); + + yy += tool_size; + } #endregion + + + } } #endregion function drawToolBar(_tool) { #region diff --git a/scripts/surface_functions/surface_functions.gml b/scripts/surface_functions/surface_functions.gml index 3abd6d770..a9be1fd96 100644 --- a/scripts/surface_functions/surface_functions.gml +++ b/scripts/surface_functions/surface_functions.gml @@ -557,17 +557,18 @@ return _arr; } #endregion - function surface_encode(surface) { #region - if(!is_real(surface)) return ""; - if(!surface_exists(surface)) return ""; + function surface_encode(surface, stringify = true) { #region + if(!is_surface(surface)) return ""; var buff = buffer_create(surface_get_width_safe(surface) * surface_get_height_safe(surface) * 4, buffer_fixed, 1); + buffer_get_surface(buff, surface, 0); var comp = buffer_compress(buff, 0, buffer_get_size(buff)); - var enc = buffer_base64_encode(comp, 0, buffer_get_size(comp)); + var enc = buffer_base64_encode(comp, 0, buffer_get_size(comp)); + var str = { width: surface_get_width_safe(surface), height: surface_get_height_safe(surface), buffer: enc }; buffer_delete(buff); - var str = { width: surface_get_width_safe(surface), height: surface_get_height_safe(surface), buffer: enc }; - return json_stringify(str); + + return stringify? json_stringify(str) : str; } #endregion function surface_decode(struct) { #region diff --git a/shaders/sh_canvas_mask/sh_canvas_mask.fsh b/shaders/sh_canvas_mask/sh_canvas_mask.fsh new file mode 100644 index 000000000..6ee320012 --- /dev/null +++ b/shaders/sh_canvas_mask/sh_canvas_mask.fsh @@ -0,0 +1,12 @@ +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +uniform sampler2D drawSurface; +uniform sampler2D maskSurface; + +void main() { + vec4 drw = texture2D( drawSurface, v_vTexcoord ); + vec4 msk = texture2D( maskSurface, v_vTexcoord ); + + gl_FragColor = msk.a > 0.5? drw : texture2D( gm_BaseTexture, v_vTexcoord ); +} diff --git a/shaders/sh_canvas_mask/sh_canvas_mask.vsh b/shaders/sh_canvas_mask/sh_canvas_mask.vsh new file mode 100644 index 000000000..3900c20f4 --- /dev/null +++ b/shaders/sh_canvas_mask/sh_canvas_mask.vsh @@ -0,0 +1,19 @@ +// +// Simple passthrough vertex shader +// +attribute vec3 in_Position; // (x,y,z) +//attribute vec3 in_Normal; // (x,y,z) unused in this shader. +attribute vec4 in_Colour; // (r,g,b,a) +attribute vec2 in_TextureCoord; // (u,v) + +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +void main() +{ + vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0); + gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos; + + v_vColour = in_Colour; + v_vTexcoord = in_TextureCoord; +} diff --git a/shaders/sh_canvas_mask/sh_canvas_mask.yy b/shaders/sh_canvas_mask/sh_canvas_mask.yy new file mode 100644 index 000000000..8c3c0f4fa --- /dev/null +++ b/shaders/sh_canvas_mask/sh_canvas_mask.yy @@ -0,0 +1,12 @@ +{ + "$GMShader":"", + "%Name":"sh_canvas_mask", + "name":"sh_canvas_mask", + "parent":{ + "name":"tools", + "path":"folders/nodes/data/canvas/tools.yy", + }, + "resourceType":"GMShader", + "resourceVersion":"2.0", + "type":1, +} \ No newline at end of file