Canvas node

This commit is contained in:
Tanasart 2024-04-13 19:14:42 +07:00
parent b1508ee21d
commit 6b6bda0576
12 changed files with 311 additions and 51 deletions

View file

@ -1126,6 +1126,7 @@
{"name":"safe_operation","order":6,"path":"scripts/safe_operation/safe_operation.yy",},
{"name":"sample_projects","order":6,"path":"scripts/sample_projects/sample_projects.yy",},
{"name":"save_function","order":1,"path":"scripts/save_function/save_function.yy",},
{"name":"canvas_tool_node","order":12,"path":"scripts/canvas_tool_node/canvas_tool_node.yy",},
{"name":"scrollBox","order":2,"path":"scripts/scrollBox/scrollBox.yy",},
{"name":"scrollPane","order":3,"path":"scripts/scrollPane/scrollPane.yy",},
{"name":"shell_functions","order":20,"path":"scripts/shell_functions/shell_functions.yy",},
@ -1220,6 +1221,7 @@
{"name":"sh_blur_zoom","order":12,"path":"shaders/sh_blur_zoom/sh_blur_zoom.yy",},
{"name":"sh_brush_outline","order":7,"path":"shaders/sh_brush_outline/sh_brush_outline.yy",},
{"name":"sh_bw","order":3,"path":"shaders/sh_bw/sh_bw.yy",},
{"name":"sh_canvas_apply_draw","order":3,"path":"shaders/sh_canvas_apply_draw/sh_canvas_apply_draw.yy",},
{"name":"sh_canvas_extrude","order":1,"path":"shaders/sh_canvas_extrude/sh_canvas_extrude.yy",},
{"name":"sh_canvas_inset","order":2,"path":"shaders/sh_canvas_inset/sh_canvas_inset.yy",},
{"name":"sh_cell_noise_crystal","order":1,"path":"shaders/sh_cell_noise_crystal/sh_cell_noise_crystal.yy",},
@ -1469,7 +1471,6 @@
{"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_canvas_apply_draw","order":3,"path":"shaders/sh_canvas_apply_draw/sh_canvas_apply_draw.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",},

View file

@ -1607,6 +1607,7 @@
{"id":{"name":"safe_operation","path":"scripts/safe_operation/safe_operation.yy",},},
{"id":{"name":"sample_projects","path":"scripts/sample_projects/sample_projects.yy",},},
{"id":{"name":"save_function","path":"scripts/save_function/save_function.yy",},},
{"id":{"name":"canvas_tool_node","path":"scripts/canvas_tool_node/canvas_tool_node.yy",},},
{"id":{"name":"scrollBox","path":"scripts/scrollBox/scrollBox.yy",},},
{"id":{"name":"scrollPane","path":"scripts/scrollPane/scrollPane.yy",},},
{"id":{"name":"shader_functions","path":"scripts/shader_functions/shader_functions.yy",},},
@ -1722,6 +1723,7 @@
{"id":{"name":"sh_brush_outline","path":"shaders/sh_brush_outline/sh_brush_outline.yy",},},
{"id":{"name":"sh_bw","path":"shaders/sh_bw/sh_bw.yy",},},
{"id":{"name":"sh_camera","path":"shaders/sh_camera/sh_camera.yy",},},
{"id":{"name":"sh_canvas_apply_draw","path":"shaders/sh_canvas_apply_draw/sh_canvas_apply_draw.yy",},},
{"id":{"name":"sh_canvas_extrude","path":"shaders/sh_canvas_extrude/sh_canvas_extrude.yy",},},
{"id":{"name":"sh_canvas_inset","path":"shaders/sh_canvas_inset/sh_canvas_inset.yy",},},
{"id":{"name":"sh_canvas_mask","path":"shaders/sh_canvas_mask/sh_canvas_mask.yy",},},
@ -2011,7 +2013,6 @@
{"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_canvas_apply_draw","path":"shaders/sh_canvas_apply_draw/sh_canvas_apply_draw.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",},},

View file

@ -128,6 +128,11 @@ event_inherited();
if(!_node) return;
if(is_instanceof(context, Node_Canvas)) {
context.nodeTool = new canvas_tool_node(context, _node);
return;
}
if(is_instanceof(_node, AddNodeItem)) {
_node.onClick({
node_called,

View file

@ -0,0 +1,133 @@
function canvas_tool_node(canvas, node) : canvas_tool() constructor {
self.canvas = canvas;
self.node = node;
override = true;
applySelection = canvas.tool_selection.is_selected;
destiSurface = applySelection? canvas.tool_selection.selection_surface : canvas._canvas_surface;
if(!is_surface(destiSurface)) {
canvas.nodeTool = noone;
return;
}
sw = surface_get_width(destiSurface);
sh = surface_get_height(destiSurface);
targetSurface = surface_create(sw, sh);
maskedSurface = surface_create(sw, sh);
surface_set_shader(targetSurface, noone);
draw_surface_safe(destiSurface);
surface_reset_shader();
static destroy = function() {
canvas.nodeTool = noone;
if(nodeObject != noone)
nodeObject.cleanUp();
surface_free(targetSurface);
surface_free(maskedSurface);
}
nodeObject = node.build(0, 0);
if(nodeObject == noone) {
destroy();
return;
}
inputJunction = noone;
outputJunction = noone;
for( var i = 0, n = ds_list_size(nodeObject.inputs); i < n; i++ ) {
var _in = nodeObject.inputs[| i];
if(_in.type == VALUE_TYPE.surface || _in.name == "Dimension") {
inputJunction = _in;
break;
}
}
for( var i = 0, n = ds_list_size(nodeObject.outputs); i < n; i++ ) {
var _in = nodeObject.outputs[| i];
if(_in.type == VALUE_TYPE.surface) {
outputJunction = _in;
break;
}
}
if(outputJunction == noone) {
destroy();
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
function apply() {
if(applySelection) {
surface_free(canvas.tool_selection.selection_surface);
canvas.tool_selection.selection_surface = maskedSurface;
canvas.tool_selection.apply();
} else {
canvas.storeAction();
canvas.setCanvasSurface(maskedSurface);
canvas.surface_store_buffer();
}
PANEL_PREVIEW.tool_current = noone;
canvas.nodeTool = noone;
surface_free_safe(targetSurface);
}
function step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) {
var _px, _py, _pw, _ph;
if(applySelection) {
_px = canvas.tool_selection.selection_position[0];
_py = canvas.tool_selection.selection_position[1];
_pw = canvas.tool_selection.selection_size[0];
_ph = canvas.tool_selection.selection_size[1];
} else {
_px = 0;
_py = 0;
_pw = canvas.attributes.dimension[0];
_ph = canvas.attributes.dimension[1];
}
var _dx = _x + _px * _s;
var _dy = _y + _py * _s;
if(inputJunction) {
if(inputJunction.type == VALUE_TYPE.surface)
inputJunction.setValue(targetSurface);
else if(inputJunction.name == "Dimension")
inputJunction.setValue([ sw, sh ]);
}
nodeObject.update();
var _surf = outputJunction.getValue();
if(applySelection) {
maskedSurface = surface_verify(maskedSurface, sw, sh);
surface_set_shader(maskedSurface);
draw_surface(_surf, 0, 0);
BLEND_MULTIPLY
draw_surface(canvas.tool_selection.selection_mask, 0, 0);
BLEND_NORMAL
surface_reset_shader();
} else
maskedSurface = _surf;
draw_surface_ext_safe(maskedSurface, _dx, _dy, _s, _s);
if(mouse_press(mb_left, active)) { apply(); MOUSE_BLOCK = true; }
else if(mouse_press(mb_right, active)) { destroy(); MOUSE_BLOCK = true; }
}
}

View file

@ -0,0 +1,13 @@
{
"$GMScript":"",
"%Name":"canvas_tool_node",
"isCompatibility":false,
"isDnD":false,
"name":"canvas_tool_node",
"parent":{
"name":"tools",
"path":"folders/nodes/data/canvas/tools.yy",
},
"resourceType":"GMScript",
"resourceVersion":"2.0",
}

View file

@ -5,6 +5,7 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
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;
@ -21,14 +22,112 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
mouse_pre_y = 0;
function createSelection(_mask, sel_x0, sel_y0, sel_w, sel_h) { #region
is_selecting = false;
if(is_selected)
apply();
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);
}
function modifySelection(_mask, sel_x0, sel_y0, sel_w, sel_h, _add) { #region
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);
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_surface = surface_create(_nw, _nh);
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();
surface_set_target(_selection_surface);
DRAW_CLEAR
draw_surface_safe(_canvas_surface, -_x0, -_y0);
BLEND_MULTIPLY
draw_surface_safe(_selection_mask, 0, 0);
BLEND_NORMAL
surface_reset_target();
surface_free(selection_surface);
surface_free(selection_mask);
selection_surface = _selection_surface;
selection_mask = _selection_mask;
node.storeAction();
surface_set_target(_canvas_surface);
gpu_set_blendmode(bm_subtract);
draw_surface_safe(selection_surface, _x0, _y0);
gpu_set_blendmode(bm_normal);
surface_reset_target();
node.surface_store_buffer();
selection_position = [ _x0, _y0 ];
selection_size = [ _nw, _nh ];
is_selected = true;
} #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
@ -43,7 +142,7 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
DRAW_CLEAR
draw_surface_safe(_mask, 0, 0);
surface_reset_target();
node.storeAction();
surface_set_target(_canvas_surface);
gpu_set_blendmode(bm_subtract);
@ -54,6 +153,8 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
node.surface_store_buffer();
selection_position = [ sel_x0, sel_y0 ];
selection_size = [ sel_w, sel_h ];
is_selected = true;
} #endregion
function copySelection() { #region
@ -66,33 +167,30 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
var _sw = surface_get_width(_canvas_surface);
var _sh = surface_get_height(_canvas_surface);
var _drawnSurface = surface_create(_sw, _sh);
var _selectionSurf = surface_create(_sw, _sh);
var _drawnSurface = surface_create(_sw, _sh);
surface_set_target(_drawnSurface);
DRAW_CLEAR
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", node.tool_attribute.channel);
shader_set_f("alpha", 1);
if(_drawLay == 0 || _drawLay == 2) {
BLEND_OVERRIDE
draw_surface(_canvas_surface, 0, 0);
BLEND_ALPHA
draw_surface_safe(selection_surface, selection_position[0], selection_position[1]);
BLEND_NORMAL
} else if(_drawLay == 1) {
BLEND_OVERRIDE
draw_surface_safe(selection_surface, selection_position[0], selection_position[1]);
BLEND_ALPHA
draw_surface(_canvas_surface, 0, 0);
BLEND_NORMAL
}
shader_set_surface("back", _canvas_surface);
shader_set_surface("fore", _selectionSurf);
surface_reset_target();
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();
surface_free(selection_surface);
is_selected = false;
} #endregion
@ -109,7 +207,7 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
selection_position[0] = px;
selection_position[1] = py;
if(mouse_release(mb_left))
is_select_drag = false;
}
@ -126,9 +224,6 @@ function canvas_tool_selection(selector = noone) : canvas_tool() constructor {
selection_sy = pos_y;
selection_mx = mouse_cur_x;
selection_my = mouse_cur_y;
} else {
is_selected = false;
apply();
}
}

View file

@ -16,7 +16,7 @@ function canvas_tool_selection_freeform(selector, brush) : canvas_tool_selection
if(is_selected) { onSelected(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); return; }
if(mouse_press(mb_left, active)) {
if(!selector.is_select_drag && mouse_press(mb_left, active)) {
is_selecting = true;
selection_sx = mouse_cur_x;
selection_sy = mouse_cur_y;

View file

@ -12,7 +12,7 @@ function canvas_tool_selection_magic(selector, toolAttr) : canvas_tool_selection
var _thr = tool_attribute.thres;
var _fill_type = tool_attribute.fill8;
if(!selector.is_selected && mouse_press(mb_left, active)) {
if(!selector.is_select_drag && mouse_press(mb_left, active)) {
canvas_buffer = node.canvas_buffer;
preview_index = node.preview_index;

View file

@ -42,7 +42,7 @@ function canvas_tool_selection_shape(selector, shape) : canvas_tool_selection(se
surface_free_safe(selection_mask);
}
} else if(!selector.is_selected && mouse_press(mb_left, active)) {
} else if(!selector.is_select_drag && mouse_press(mb_left, active)) {
is_selecting = true;
selection_sx = mouse_cur_x;
selection_sy = mouse_cur_y;

View file

@ -258,13 +258,21 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
#endregion
#region right tools
#region ++++ right tools ++++
__action_rotate_90_cw = method(self, function() { if(tool_selection.is_selected) tool_selection.rotate90cw() else canvas_action_rotate(-90); });
__action_rotate_90_ccw = method(self, function() { if(tool_selection.is_selected) tool_selection.rotate90ccw() else canvas_action_rotate( 90); });
__action_flip_h = method(self, function() { if(tool_selection.is_selected) tool_selection.flipH() else canvas_action_flip(1); });
__action_flip_v = method(self, function() { if(tool_selection.is_selected) tool_selection.flipV() else canvas_action_flip(0); });
__action_add_node = method(self, function(ctx) { dialogCall(o_dialog_add_node, mouse_mx + 8, mouse_my + 8, { context: ctx }); });
nodeTool = noone;
nodeToolPreview = new NodeTool( "Apply Node", THEME.canvas_resize, self ).setToolFn( __action_add_node );
rightTools_general = [
nodeToolPreview,
-1,
new NodeTool( "Resize Canvas", THEME.canvas_resize ).setToolObject( new canvas_tool_resize() ),
new NodeTool( [ "Rotate 90 CW", "Rotate 90 CCW" ],
@ -278,9 +286,9 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
rightTools_selection = [
new NodeTool( "Outline", THEME.canvas_tools_outline ).setToolObject( new canvas_tool_outline() ),
new NodeTool( [ "Inset", "Extrude" ],
[ THEME.canvas_tools_inset, THEME.canvas_tools_extrude ] )
.setToolObject( [ new canvas_tool_inset(), new canvas_tool_extrude() ] ),
new NodeTool( [ "Extrude", "Inset" ],
[ THEME.canvas_tools_extrude, THEME.canvas_tools_inset ] )
.setToolObject( [ new canvas_tool_extrude(), new canvas_tool_inset() ] ),
];
rightTools = rightTools_general;
@ -526,8 +534,8 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
brush.node = self;
brush.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
if(active && key_mod_press(ALT)) { #region color selector
var dialog = instance_create(0, 0, o_dialog_color_picker);
if(!tool_selection.is_selected && 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
@ -558,7 +566,10 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
array_append(rightTools, rightTools_selection);
}
if(_currTool != noone) {
if(nodeTool != noone)
_tool = nodeTool;
else if(_currTool != noone) {
_tool = _currTool.getToolObject();
switch(_currTool.getName()) {
@ -599,6 +610,7 @@ function Node_Canvas(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
if(is_instanceof(_tool, canvas_tool_selection) && tool_selection.is_selected) tool_selection.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
}
#endregion
if(_tool && _tool.override) {

View file

@ -1,5 +1,5 @@
function NodeTool(name, spr, context = instanceof(other)) constructor {
ctx = context;
ctx = context;
self.name = name;
self.spr = spr;
@ -19,11 +19,7 @@ function NodeTool(name, spr, context = instanceof(other)) constructor {
}
static setToolObject = function(toolObject) { self.toolObject = toolObject; return self; }
static setToolFn = function(toolFn, arguments = {}) {
self.toolFn = toolFn;
self.toolFnParam = arguments;
return self;
}
static setToolFn = function(toolFn) { self.toolFn = toolFn; return self; }
static getName = function(index = 0) { return is_array(name)? array_safe_get_fast(name, index, "") : name; }
@ -61,8 +57,8 @@ function NodeTool(name, spr, context = instanceof(other)) constructor {
static toggle = function(index = 0) {
if(toolFn != noone) {
if(subtools == 0) toolFn(toolFnParam);
else toolFn[index](toolFnParam);
if(subtools == 0) toolFn(ctx);
else toolFn[index](ctx);
return;
}

View file

@ -805,7 +805,11 @@ function Panel_Inspector() : PanelContent() constructor {
var _hh = ui(40);
_y += _hh;
if(inspectGroup >= 0) return drawNodeProperties(_y, _m, inspecting);
if(is_instanceof(inspecting, Node_Canvas) && inspecting.nodeTool != noone)
return drawNodeProperties(_y, _m, inspecting.nodeTool.nodeObject);
if(inspectGroup >= 0)
return drawNodeProperties(_y, _m, inspecting);
for( var i = 0, n = min(10, array_length(inspectings)); i < n; i++ ) {
if(i) {