Pixel-Composer/scripts/node_composite/node_composite.gml
2022-12-22 09:09:55 +07:00

508 lines
15 KiB
Plaintext

enum COMPOSE_OUTPUT_SCALING {
first,
largest,
constant
}
function Node_Composite(_x, _y, _group = -1) : Node_Processor(_x, _y, _group) constructor {
name = "Composite";
shader = sh_blend_normal_dim;
uniform_dim = shader_get_uniform(shader, "dimension");
uniform_pos = shader_get_uniform(shader, "position");
uniform_sca = shader_get_uniform(shader, "scale");
uniform_rot = shader_get_uniform(shader, "rotation");
uniform_for = shader_get_sampler_index(shader, "fore");
inputs[| 0] = nodeValue(0, "Padding", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [ 0, 0, 0, 0 ])
.setDisplay(VALUE_DISPLAY.padding);
inputs[| 1] = nodeValue(1, "Output dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, COMPOSE_OUTPUT_SCALING.first)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "First surface", "Largest surface", "Constant" ]);
inputs[| 2] = nodeValue(2, "Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, def_surf_size2)
.setDisplay(VALUE_DISPLAY.vector)
.setVisible(false);
input_fix_len = ds_list_size(inputs);
data_length = 4;
attributes[? "layer_visible"] = ds_list_create();
hold_visibility = true;
layer_dragging = noone;
layer_remove = -1;
layer_renderer = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) {
var amo = (ds_list_size(inputs) - input_fix_len) / data_length - 1;
var lh = 32;
var _h = 8 + max(1, amo) * (lh + 4) + 8;
layer_renderer.h = _h;
draw_sprite_stretched_ext(THEME.ui_panel_bg, 1, _x, _y, _w, _h, COLORS.node_composite_bg_blend, 1);
var _vis = attributes[? "layer_visible"];
var ly = _y + 8;
var ssh = lh - 6;
var hoverIndex = noone;
draw_set_color(COLORS.node_composite_separator);
draw_line(_x + 16, ly, _x + _w - 16, ly);
layer_remove = -1;
for(var i = 0; i < amo; i++) {
var ind = amo - i - 1;
var index = input_fix_len + ind * data_length;
var _surf = current_data[index + 0];
var _pos = current_data[index + 1];
var _bx = _x + _w - 24;
var _cy = ly + i * (lh + 4);
if(point_in_circle(_m[0], _m[1], _bx, _cy + lh / 2, 16)) {
draw_sprite_ui_uniform(THEME.icon_delete, 3, _bx, _cy + lh / 2, 1, COLORS._main_value_negative);
if(mouse_press(mb_left, _focus))
layer_remove = ind;
} else
draw_sprite_ui_uniform(THEME.icon_delete, 3, _bx, _cy + lh / 2, 1, COLORS._main_icon);
if(!is_surface(_surf)) continue;
var aa = (ind != layer_dragging || layer_dragging == noone)? 1 : 0.5;
var vis = _vis[| ind];
var hover = point_in_rectangle(_m[0], _m[1], _x, _cy, _x + _w, _cy + lh);
draw_set_color(COLORS.node_composite_separator);
draw_line(_x + 16, _cy + lh + 2, _x + _w - 16, _cy + lh + 2);
var _bx = _x + 24 * 2 + 8;
if(point_in_circle(_m[0], _m[1], _bx, _cy + lh / 2, 12)) {
draw_sprite_ui_uniform(THEME.junc_visible, vis, _bx, _cy + lh / 2, 1, c_white);
if(mouse_press(mb_left, _focus))
hold_visibility = !_vis[| ind];
if(mouse_click(mb_left, _focus) && _vis[| ind] != hold_visibility) {
_vis[| ind] = hold_visibility;
update();
}
} else
draw_sprite_ui_uniform(THEME.junc_visible, vis, _bx, _cy + lh / 2, 1, COLORS._main_icon);
draw_set_color(COLORS.node_composite_bg);
var _sx0 = _x + 24 * 3 + 8;
var _sx1 = _sx0 + ssh;
var _sy0 = _cy + 3;
var _sy1 = _sy0 + ssh;
draw_rectangle(_sx0, _sy0, _sx1, _sy1, true);
var _ssw = surface_get_width(_surf);
var _ssh = surface_get_height(_surf);
var _sss = min(ssh / _ssw, ssh / _ssh);
draw_surface_ext(_surf, _sx0, _sy0, _sss, _sss, 0, c_white, 1);
draw_set_text(f_p1, fa_left, fa_center, hover? COLORS._main_text : COLORS._main_text);
draw_set_alpha(aa);
draw_text(_sx1 + 12, _cy + lh / 2, inputs[| index].name);
draw_set_alpha(1);
if(_hover && point_in_rectangle(_m[0], _m[1], _x, _cy, _x + _w, _cy + lh)) {
hoverIndex = ind;
if(layer_dragging != noone) {
draw_set_color(COLORS._main_accent);
if(layer_dragging > ind)
draw_line_width(_x + 16, _cy + lh + 2, _x + _w - 16, _cy + lh + 2, 2);
else if(layer_dragging < ind)
draw_line_width(_x + 16, _cy - 2, _x + _w - 16, _cy - 2, 2);
}
}
if(layer_dragging == noone || layer_dragging == ind) {
var _bx = _x + 24;
if(point_in_circle(_m[0], _m[1], _bx, _cy + lh / 2, 16)) {
draw_sprite_ui_uniform(THEME.hamburger, 3, _bx, _cy + lh / 2, .75, c_white);
if(mouse_press(mb_left, _focus))
layer_dragging = ind;
} else
draw_sprite_ui_uniform(THEME.hamburger, 3, _bx, _cy + lh / 2, .75, COLORS._main_icon);
}
}
if(layer_dragging != noone && mouse_release(mb_left)) {
if(layer_dragging != hoverIndex && hoverIndex != noone) {
var index = input_fix_len + layer_dragging * data_length;
var targt = input_fix_len + hoverIndex * data_length;
var _vis = attributes[? "layer_visible"];
var ext = [];
var vis = _vis[| layer_dragging];
ds_list_delete(_vis, layer_dragging);
ds_list_insert(_vis, hoverIndex, vis);
for( var i = 0; i < data_length; i++ ) {
ext[i] = inputs[| index];
ds_list_delete(inputs, index);
//show_debug_message("remove: " + ext[i].name);
}
for( var i = 0; i < data_length; i++ ) {
ds_list_insert(inputs, targt + i, ext[i]);
//show_debug_message("place: " + ext[i].name + " at " + string(targt + i));
}
update();
}
layer_dragging = noone;
}
});
input_display_list = [
["Output", true], 0, 1, 2,
["Layers", false], layer_renderer,
["Surface", true],
];
input_display_list_len = array_length(input_display_list);
function deleteLayer(index) {
var idx = input_fix_len + index * data_length;
for( var i = 0; i < data_length; i++ ) {
ds_list_delete(inputs, idx);
array_remove(input_display_list, idx + i);
}
for( var i = input_display_list_len; i < array_length(input_display_list); i++ ) {
if(input_display_list[i] > idx)
input_display_list[i] = input_display_list[i] - data_length;
}
update();
}
function createNewSurface() {
var index = ds_list_size(inputs);
var _s = floor((index - input_fix_len) / data_length);
inputs[| index + 0] = nodeValue( index + 0, _s? ("Surface " + string(_s)) : "Background", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0);
inputs[| index + 1] = nodeValue( index + 1, "Position " + string(_s), self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector);
inputs[| index + 2] = nodeValue( index + 2, "Rotation " + string(_s), self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0 )
.setDisplay(VALUE_DISPLAY.rotation);
inputs[| index + 3] = nodeValue( index + 3, "Scale " + string(_s), self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1 ] )
.setDisplay(VALUE_DISPLAY.vector);
array_push(input_display_list, index + 0);
array_push(input_display_list, index + 1);
array_push(input_display_list, index + 2);
array_push(input_display_list, index + 3);
while(_s >= ds_list_size(attributes[? "layer_visible"])) {
ds_list_add(attributes[? "layer_visible"], true);
}
}
if(!LOADING && !APPENDING) createNewSurface();
function addFrom(_nodeFrom) {
inputs[| ds_list_size(inputs) - data_length].setFrom(_nodeFrom);
}
outputs[| 0] = nodeValue(0, "Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, PIXEL_SURFACE);
temp_surf = [ PIXEL_SURFACE, PIXEL_SURFACE ];
surf_dragging = -1;
input_dragging = -1;
drag_type = 0;
dragging_sx = 0;
dragging_sy = 0;
dragging_mx = 0;
dragging_my = 0;
rot_anc_x = 0;
rot_anc_y = 0;
overlay_w = 0;
overlay_h = 0;
static updateValueFrom = function(index) {
if(LOADING || APPENDING) return;
if(index + data_length >= ds_list_size(inputs))
createNewSurface();
}
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) {
var pad = inputs[| 0].getValue();
var ww = overlay_w;
var hh = overlay_h;
var x0 = _x + pad[2] * _s;
var x1 = _x + (ww - pad[0]) * _s;
var y0 = _y + pad[1] * _s;
var y1 = _y + (hh - pad[3]) * _s;
draw_set_color(COLORS._main_accent);
draw_line(x0, y0, x0, y1);
draw_line(x1, y0, x1, y1);
draw_line(x0, y0, x1, y0);
draw_line(x0, y1, x1, y1);
if(input_dragging > -1) {
if(drag_type == 0) {
var pos_x = value_snap(dragging_sx + (_mx - dragging_mx) / _s, _snx);
var pos_y = value_snap(dragging_sy + (_my - dragging_my) / _s, _sny);
if(inputs[| input_dragging].setValue([ pos_x, pos_y ]))
UNDO_HOLDING = true;
} else if(drag_type == 1) {
var aa = point_direction(rot_anc_x, rot_anc_y, _mx, _my);
var da = angle_difference(dragging_mx, aa);
var sa;
if(key_mod_press(CTRL))
sa = round((dragging_sx - da) / 15) * 15;
else
sa = dragging_sx - da;
if(inputs[| input_dragging].setValue(sa))
UNDO_HOLDING = true;
} else if(drag_type == 2) {
var _surf = inputs[| surf_dragging].getValue();
var _sw = surface_get_width(_surf);
var _sh = surface_get_width(_surf);
var sca_x = dragging_sx + (_mx - dragging_mx) / _s / _sw;
var sca_y = dragging_sy + (_my - dragging_my) / _s / _sh;
if(keyboard_check(vk_shift)) {
sca_x = min(sca_x, sca_y);
sca_y = min(sca_x, sca_y);
}
if(inputs[| input_dragging].setValue([ sca_x, sca_y ]))
UNDO_HOLDING = true;
}
if(mouse_release(mb_left)) {
input_dragging = -1;
UNDO_HOLDING = false;
}
}
var hovering = -1;
var hovering_type = 0;
var _vis = attributes[? "layer_visible"];
var amo = (ds_list_size(inputs) - input_fix_len) / data_length;
if(array_length(current_data) < input_fix_len + amo * data_length)
return;
for(var i = 0; i < amo; i++) {
var vis = _vis[| i];
if(!vis) continue;
var index = input_fix_len + i * data_length;
var _surf = current_data[index + 0];
var _pos = current_data[index + 1];
if(!_surf || is_array(_surf)) continue;
var _ww = surface_get_width(_surf);
var _hh = surface_get_height(_surf);
var _dx0 = _x + _pos[0] * _s;
var _dy0 = _y + _pos[1] * _s;
var _dx1 = _dx0 + _ww * _s;
var _dy1 = _dy0 + _hh * _s;
var _borcol = COLORS.node_composite_overlay_border;
var _rx = (_dx0 + _dx1) / 2;
var _ry = _dy0 - 16;
var _ri = 0;
var _sx = _dx1;
var _sy = _dy1;
var _si = 0;
if(point_in_circle(_mx, _my, _sx, _sy, 12)) {
hovering = index;
hovering_type = 2;
_si = 1;
} else if(point_in_rectangle(_mx, _my, _dx0, _dy0, _dx1, _dy1)) {
hovering = index;
hovering_type = 0;
} else if(point_in_circle(_mx, _my, _rx, _ry, 12)) {
hovering = index;
hovering_type = 1;
_ri = 1;
}
draw_sprite_ui_uniform(THEME.anchor_rotate, _ri, _rx, _ry);
draw_sprite_ui_uniform(THEME.anchor_scale, _si, _sx, _sy);
draw_set_color(_borcol);
draw_rectangle(_dx0, _dy0, _dx1, _dy1, true);
}
if(hovering != -1) {
var _surf = current_data[hovering];
var _pos = current_data[hovering + 1];
var _rot = current_data[hovering + 2];
var _sca = current_data[hovering + 3];
var _ww = surface_get_width(_surf);
var _hh = surface_get_height(_surf);
var _dx0 = _x + _pos[0] * _s;
var _dy0 = _y + _pos[1] * _s;
var _dx1 = _dx0 + _ww * _s;
var _dy1 = _dy0 + _hh * _s;
if(hovering_type == 0) {
draw_set_color(COLORS._main_accent);
draw_rectangle_border(_dx0, _dy0, _dx1, _dy1, 2);
if(mouse_press(mb_left, active)) {
surf_dragging = hovering;
input_dragging = hovering + 1;
drag_type = hovering_type;
dragging_sx = _pos[0];
dragging_sy = _pos[1];
dragging_mx = _mx;
dragging_my = _my;
}
} else if(hovering_type == 1) { //rot
if(mouse_press(mb_left, active)) {
surf_dragging = hovering;
input_dragging = hovering + 2;
drag_type = hovering_type;
dragging_sx = _rot;
rot_anc_x = _dx0 + _ww / 2 * _s;
rot_anc_y = _dy0 + _hh / 2 * _s;
dragging_mx = point_direction(rot_anc_x, rot_anc_y, _mx, _my);
}
} else if(hovering_type == 2) { //sca
if(mouse_press(mb_left, active)) {
surf_dragging = hovering;
input_dragging = hovering + 3;
drag_type = hovering_type;
dragging_sx = _sca[0];
dragging_sy = _sca[1];
dragging_mx = _mx;
dragging_my = _my;
}
}
}
if(layer_remove > -1) {
deleteLayer(layer_remove);
layer_remove = -1;
}
}
static process_data = function(_outSurf, _data, _output_index) {
if(array_length(_data) < 4) return _outSurf;
var _pad = _data[0];
var _dim_type = _data[1];
var _dim = _data[2];
var base = _data[3];
var ww = 0, hh = 0;
switch(_dim_type) {
case COMPOSE_OUTPUT_SCALING.first :
inputs[| 2].setVisible(false);
ww = surface_get_width(base);
hh = surface_get_height(base);
break;
case COMPOSE_OUTPUT_SCALING.largest :
inputs[| 2].setVisible(false);
for(var i = input_fix_len; i < array_length(_data) - data_length; i += data_length) {
var _s = _data[i];
ww = max(ww, surface_get_width(_s));
hh = max(hh, surface_get_height(_s));
}
break;
case COMPOSE_OUTPUT_SCALING.constant :
inputs[| 2].setVisible(true);
ww = _dim[0];
hh = _dim[1];
break;
}
ww += _pad[0] + _pad[2];
hh += _pad[1] + _pad[3];
overlay_w = ww;
overlay_h = hh;
if(is_surface(base))
surface_size_to(_outSurf, ww, hh);
for(var i = 0; i < 2; i++) {
if(!is_surface(temp_surf[i])) temp_surf[i] = surface_create_valid(surface_get_width(_outSurf), surface_get_height(_outSurf));
else surface_size_to(temp_surf[i], surface_get_width(_outSurf), surface_get_height(_outSurf));
surface_set_target(temp_surf[i]);
draw_clear_alpha(0, 0);
surface_reset_target();
}
var res_index = 0, bg = 0;
var imageAmo = (ds_list_size(inputs) - input_fix_len) / data_length;
var _vis = attributes[? "layer_visible"];
BLEND_OVERRIDE
for(var i = 0; i < imageAmo; i++) {
var vis = _vis[| i];
if(!vis) continue;
var startDataIndex = input_fix_len + i * data_length;
var _s = _data[startDataIndex + 0];
var _pos = _data[startDataIndex + 1];
var _rot = _data[startDataIndex + 2];
var _sca = _data[startDataIndex + 3];
if(!_s || is_array(_s)) continue;
surface_set_target(temp_surf[bg]);
shader_set(shader);
shader_set_uniform_f_array(uniform_dim, [ surface_get_width(_s) / ww, surface_get_height(_s) / hh ]);
shader_set_uniform_f_array(uniform_pos, [ _pos[0] / ww, _pos[1] / hh]);
shader_set_uniform_f_array(uniform_sca, _sca)
shader_set_uniform_f(uniform_rot, degtorad(_rot));
texture_set_stage(uniform_for, surface_get_texture(_s));
draw_surface_safe(temp_surf[!bg], 0, 0);
shader_reset();
surface_reset_target();
res_index = bg;
bg = !bg;
}
BLEND_NORMAL
surface_set_target(_outSurf);
draw_clear_alpha(0, 0);
BLEND_ADD
draw_surface_safe(temp_surf[res_index], 0, 0);
BLEND_NORMAL
surface_reset_target();
}
static postDeserialize = function() {
var _inputs = load_map[? "inputs"];
for(var i = input_fix_len; i < ds_list_size(_inputs); i += data_length)
createNewSurface();
}
static attributeSerialize = function() {
var att = ds_map_create();
ds_map_add_list(att, "layer_visible", ds_list_clone(attributes[? "layer_visible"]));
return att;
}
static attributeDeserialize = function(attr) {
if(ds_map_exists(attr, "layer_visible"))
attributes[? "layer_visible"] = ds_list_clone(attr[? "layer_visible"], true);
}
}