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 ]; selection_size = [ 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) { #region if(is_selected) apply(); else { createNewSelection(_mask, sel_x0, sel_y0, sel_w, sel_h); return; } if(key_mod_press(SHIFT)) modifySelection(_mask, sel_x0, sel_y0, sel_w, sel_h, true); else if(key_mod_press(ALT)) modifySelection(_mask, sel_x0, sel_y0, sel_w, sel_h, false); else createNewSelection(_mask, sel_x0, sel_y0, sel_w, sel_h); } #endregion function modifySelection(_mask, sel_x0, sel_y0, sel_w, sel_h, _add) { #region if(sel_w == 1 && sel_h == 1) return; var _x0, _y0, _x1, _y1; if(_add) { _x0 = min(sel_x0, selection_position[0]); _y0 = min(sel_y0, selection_position[1]); _x1 = max(sel_x0 + sel_w, selection_position[0] + selection_size[0]); _y1 = max(sel_y0 + sel_h, selection_position[1] + selection_size[1]); } else { var __nx0 = sel_x0; var __ny0 = sel_y0; var __nx1 = sel_x0 + sel_w; var __ny1 = sel_y0 + sel_h; _x0 = selection_position[0]; _y0 = selection_position[1]; _x1 = selection_position[0] + selection_size[0]; _y1 = selection_position[1] + selection_size[1]; if(__nx0 <= _x0 && __nx1 >= _x1) { if(__ny0 <= _y0) _y0 = max(_y0, __ny1); if(__ny1 >= _y1) _y1 = min(_y1, __ny0); } if(__ny0 <= _y0 && __ny1 >= _y1) { if(__nx0 <= _x0) _x0 = max(_x0, __nx1); if(__nx1 >= _x1) _x1 = min(_x1, __nx0); } } if(_x1 - _x0 <= 0 || _y1 - _y0 <= 0) return; var _ox = selection_position[0] - _x0; var _oy = selection_position[1] - _y0; var _nx = sel_x0 - _x0; var _ny = sel_y0 - _y0; var _nw = _x1 - _x0; var _nh = _y1 - _y0; var _selection_mask = surface_create(_nw, _nh); surface_set_target(_selection_mask); DRAW_CLEAR BLEND_OVERRIDE draw_surface_safe(selection_mask, _ox, _oy); if(_add) BLEND_ADD else BLEND_SUBTRACT draw_surface_safe(_mask, _nx, _ny); BLEND_NORMAL surface_reset_target(); createNewSelection(_selection_mask, _x0, _y0, _nw, _nh); surface_free(_selection_mask); } #endregion function createNewSelection(_mask, sel_x0, sel_y0, sel_w, sel_h) { #region if(sel_w == 1 && sel_h == 1) return; selection_surface = surface_verify(selection_surface, sel_w, sel_h); selection_mask = surface_verify(selection_mask, 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 ]; selection_size = [ sel_w, sel_h ]; is_selected = true; } #endregion function copySelection() { #region var s = surface_encode(selection_surface, false); s.position = selection_position; clipboard_set_text(json_stringify(s)); } #endregion function apply() { #region var _drawLay = node.tool_attribute.drawLayer; var _sw = surface_get_width(_canvas_surface); var _sh = surface_get_height(_canvas_surface); var _selectionSurf = surface_create(_sw, _sh); var _drawnSurface = surface_create(_sw, _sh); surface_set_shader(_selectionSurf, noone); draw_surface(selection_surface, selection_position[0], selection_position[1]); surface_reset_shader(); surface_set_shader(_drawnSurface, sh_canvas_apply_draw); shader_set_i("drawLayer", _drawLay); shader_set_i("eraser", 0); shader_set_f("channels", 1, 1, 1, 1); shader_set_f("alpha", 1); shader_set_surface("back", _canvas_surface); shader_set_surface("fore", _selectionSurf); draw_sprite_stretched(s_fx_pixel, 0, 0, 0, _sw, _sh); surface_reset_shader(); node.setCanvasSurface(_drawnSurface); surface_free(_canvas_surface); _canvas_surface = _drawnSurface; node.surface_store_buffer(); is_selected = false; } #endregion function onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region 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; } } if(key_press(vk_delete)) { is_selected = false; surface_free(selection_surface); } else if(key_press(vk_escape)) { apply(); } } #endregion function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region 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(); } } #endregion function onDrawMask(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) {} function drawMask(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region var sel_x0, sel_y0; if(is_selecting) { sel_x0 = min(selection_sx, mouse_cur_x); sel_y0 = min(selection_sy, mouse_cur_y); } else { sel_x0 = selection_position[0]; sel_y0 = selection_position[1]; } var _dx = _x + sel_x0 * _s; var _dy = _y + sel_y0 * _s; draw_surface_ext_safe(selection_mask, _dx, _dy, _s, _s); onDrawMask(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); } #endregion function drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region 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); } #endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function rotate90cw() { #region var _sw = surface_get_width(selection_surface); var _sh = surface_get_height(selection_surface); var _newS = surface_create(_sh, _sw); surface_set_shader(_newS, noone); draw_surface_ext(selection_surface, _sh, 0, 1, 1, -90, c_white, 1); surface_reset_shader(); surface_free(selection_surface); selection_surface = _newS; } #endregion function rotate90ccw() { #region var _sw = surface_get_width(selection_surface); var _sh = surface_get_height(selection_surface); var _newS = surface_create(_sh, _sw); surface_set_shader(_newS, noone); draw_surface_ext(selection_surface, 0, _sw, 1, 1, 90, c_white, 1); surface_reset_shader(); surface_free(selection_surface); selection_surface = _newS; } #endregion function flipH() { #region var _sw = surface_get_width(selection_surface); var _sh = surface_get_height(selection_surface); var _newS = surface_create(_sw, _sh); surface_set_shader(_newS, noone); draw_surface_ext(selection_surface, _sw, 0, -1, 1, 0, c_white, 1); surface_reset_shader(); surface_free(selection_surface); selection_surface = _newS; } #endregion function flipV() { #region var _sw = surface_get_width(selection_surface); var _sh = surface_get_height(selection_surface); var _newS = surface_create(_sw, _sh); surface_set_shader(_newS, noone); draw_surface_ext(selection_surface, 0, _sh, 1, -1, 0, c_white, 1); surface_reset_shader(); surface_free(selection_surface); selection_surface = _newS; } #endregion }