This commit is contained in:
Tanasart 2022-12-23 10:45:52 +07:00
parent ed883543fe
commit 55e5ae283a
39 changed files with 778 additions and 251 deletions

View file

@ -265,6 +265,7 @@
{"id":{"name":"sh_gradient","path":"shaders/sh_gradient/sh_gradient.yy",},"order":17,},
{"id":{"name":"s_node_zigzag","path":"sprites/s_node_zigzag/s_node_zigzag.yy",},"order":18,},
{"id":{"name":"sh_glow","path":"shaders/sh_glow/sh_glow.yy",},"order":39,},
{"id":{"name":"sh_clean_shape","path":"shaders/sh_clean_shape/sh_clean_shape.yy",},"order":42,},
{"id":{"name":"sh_posterize","path":"shaders/sh_posterize/sh_posterize.yy",},"order":22,},
{"id":{"name":"s_node_mirror","path":"sprites/s_node_mirror/s_node_mirror.yy",},"order":3,},
{"id":{"name":"node_VFX_spawner","path":"scripts/node_VFX_spawner/node_VFX_spawner.yy",},"order":2,},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -14,10 +14,10 @@
if(fr <= ANIMATOR.real_frame + 1)
ANIMATOR.real_frame = fr;
if(round(ANIMATOR.real_frame) >= ANIMATOR.frames_total) {
if(ANIMATOR.playback == ANIMATOR_END.stop || ANIMATOR.stopOnEnd) {
if(ANIMATOR.playback == ANIMATOR_END.stop || ANIMATOR.rendering) {
ANIMATOR.setFrame(ANIMATOR.frames_total - 1);
ANIMATOR.is_playing = false;
ANIMATOR.stopOnEnd = false;
ANIMATOR.rendering = false;
} else
ANIMATOR.setFrame(0);
}
@ -28,6 +28,9 @@
var _c = ANIMATOR.current_frame;
ANIMATOR.current_frame = round(ANIMATOR.real_frame);
ANIMATOR.frame_progress = _c != ANIMATOR.current_frame;
//if(ANIMATOR.frame_progress)
// UPDATE = RENDER_TYPE.full;
#endregion
#region hotkey

View file

@ -99,3 +99,26 @@
if(keyboard_check_released(vk_alt))
ALT = KEYBOARD_STATUS.up;
#endregion
#region mouse wrap
MOUSE_WRAPPING = max(0, MOUSE_WRAPPING - 1);
if(MOUSE_WRAP) {
if(mouse_x < 0) {
window_mouse_set(window_get_width(), mouse_y);
MOUSE_WRAPPING = 2;
} else if(mouse_x > window_get_width()) {
window_mouse_set(0, mouse_y);
MOUSE_WRAPPING = 2;
}
if(mouse_y < 0) {
window_mouse_set(mouse_x, window_get_height());
MOUSE_WRAPPING = 2;
} else if(mouse_y > window_get_height()) {
window_mouse_set(mouse_x, 0);
MOUSE_WRAPPING = 2;
}
}
MOUSE_WRAP = false;
#endregion

View file

@ -1,7 +1,6 @@
/* Backup
function Node_VFX(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
name = "VFX";
auto_update = false;
use_cache = true;
inputs[| 0] = nodeValue(0, "Particle sprite", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0)

View file

@ -7,7 +7,7 @@
is_playing = false;
frame_progress = false;
stopOnEnd = false;
rendering = false;
playback = ANIMATOR_END.loop;
static setFrame = function(frame) {

View file

@ -12,6 +12,7 @@ function APPEND(_path) {
if(ds_map_exists(_map, "version")) {
var _v = _map[? "version"];
LOADING_VERSION = _v;
if(_v != SAVEFILE_VERSION) {
var warn = "File version mismatch : loading file verion " + string(_v) + " to Pixel Composer " + string(SAVEFILE_VERSION);
log_warning("FILE", warn)

View file

@ -1,6 +1,7 @@
#region save
globalvar LOADING, APPENDING, MODIFIED, CURRENT_PATH, READONLY, CONNECTION_CONFLICT, GLOBAL_SEED, ALWAYS_FULL;
globalvar LOADING, LOADING_VERSION, APPENDING, MODIFIED, CURRENT_PATH, READONLY, CONNECTION_CONFLICT, GLOBAL_SEED, ALWAYS_FULL;
LOADING = false;
LOADING_VERSION = 0;
APPENDING = false;
READONLY = false;
@ -21,7 +22,7 @@
globalvar VERSION, SAVEFILE_VERSION, VERSION_STRING;
VERSION = 1060;
SAVEFILE_VERSION = 1000;
SAVEFILE_VERSION = 1060;
VERSION_STRING = "1.0.6";
globalvar NODES, NODE_MAP, APPEND_MAP, HOTKEYS, HOTKEY_CONTEXT;

View file

@ -5,6 +5,7 @@ enum GRADIENT_INTER {
}
function draw_gradient(_x, _y, _w, _h, _grad, _int = GRADIENT_INTER.smooth) {
if(!ds_exists(_grad, ds_type_list)) return;
static RES = 48;
var _step = _w / RES;
var _ox, _oc;
@ -40,6 +41,7 @@ function draw_gradient(_x, _y, _w, _h, _grad, _int = GRADIENT_INTER.smooth) {
}
function gradient_eval(_gradient, _time, _int = GRADIENT_INTER.smooth) {
if(!ds_exists(_gradient, ds_type_list)) return c_white;
if(ds_list_size(_gradient) == 0) return c_white;
if(ds_list_size(_gradient) == 1) return _gradient[| 0].value;
@ -65,6 +67,8 @@ function gradient_eval(_gradient, _time, _int = GRADIENT_INTER.smooth) {
}
function gradient_add(_gradient, _addkey, _deleteDup) {
if(!ds_exists(_gradient, ds_type_list)) return;
if(ds_list_size(_gradient) == 0) {
ds_list_add(_gradient, _addkey);
return;

View file

@ -47,6 +47,7 @@ function LOAD_PATH(path, readonly = false) {
var _map = json_decode(load_str);
if(ds_map_exists(_map, "version")) {
var _v = _map[? "version"];
LOADING_VERSION = _v;
if(_v != SAVEFILE_VERSION) {
var warn = "File version mismatch : loading file verion " + string(_v) + " to Pixel Composer " + string(SAVEFILE_VERSION);
log_warning("LOAD", warn);
@ -141,9 +142,8 @@ function LOAD_PATH(path, readonly = false) {
while(++pass < 4 && !ds_queue_empty(CONNECTION_CONFLICT)) {
var size = ds_queue_size(CONNECTION_CONFLICT);
log_message("LOAD", "[Connect] " + string(size) + " Connection conflict(s) detected ( pass: " + string(pass) + " )");
repeat(size) {
repeat(size)
ds_queue_dequeue(CONNECTION_CONFLICT).connect();
}
Render();
}

View file

@ -9,3 +9,13 @@ function mouse_press(mouse, focus = true) {
function mouse_release(mouse, focus = true) {
return focus && mouse_check_button_released(mouse);
}
#region mouse global
globalvar MOUSE_WRAP, MOUSE_WRAPPING;
MOUSE_WRAP = false;
MOUSE_WRAPPING = false;
function setMouseWrap() {
MOUSE_WRAP = true;
}
#endregion

View file

@ -66,6 +66,9 @@ function Node_Collection(_x, _y, _group = -1) : Node(_x, _y, _group) constructor
default :
_node.group = group;
}
_node.x += x;
_node.y += y;
}
static clearCache = function() {
@ -74,15 +77,26 @@ function Node_Collection(_x, _y, _group = -1) : Node(_x, _y, _group) constructor
}
}
static inspectorGroupUpdate = function() {
for(var i = 0; i < ds_list_size(nodes); i++) {
var _node = nodes[| i];
if(_node.inspectorUpdate == noone) continue;
_node.inspectorUpdate();
}
}
static stepBegin = function() {
use_cache = false;
auto_update = true;
inspectorUpdate = noone;
array_safe_set(cache_result, ANIMATOR.current_frame, true);
for(var i = 0; i < ds_list_size(nodes); i++) {
var n = nodes[| i];
n.stepBegin();
auto_update &= n.auto_update;
if(n.inspectorUpdate != noone)
inspectorUpdate = inspectorGroupUpdate;
if(!n.use_cache) continue;
use_cache = true;

View file

@ -48,7 +48,6 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
preview_y = 0;
rendered = false;
auto_update = true;
update_on_frame = false;
render_time = 0;
@ -101,10 +100,12 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
MODIFIED = true;
}
static inspectorUpdate = noone;
static stepBegin = function() {
if(use_cache)
cacheArrayCheck();
var stack_push = false;
var willUpdate = false;
if(always_output) {
for(var i = 0; i < ds_list_size(outputs); i++) {
@ -117,10 +118,10 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
var _surf = val[j];
if(is_surface(_surf) && _surf != DEF_SURFACE)
continue;
stack_push = true;
willUpdate = true;
}
} else if(!is_surface(val) || val == DEF_SURFACE) {
stack_push = true;
willUpdate = true;
}
}
}
@ -130,11 +131,11 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
doUpdate();
for(var i = 0; i < ds_list_size(inputs); i++) {
if(inputs[| i].isAnimated())
stack_push = true;
willUpdate = true;
}
}
if(stack_push) {
if(willUpdate) {
setRenderStatus(false);
UPDATE |= RENDER_TYPE.partial;
}
@ -156,6 +157,7 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
setRenderStatus(true);
render_time = get_timer() - t;
} catch(exception) {
print(exception)
log_warning("RENDER", "Render error " + exception_print(exception));
}
}
@ -167,11 +169,10 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
for(var j = 0; j < ds_list_size(inputs); j++) {
var _in = inputs[| j];
if(_in.value_from) {
if(_in.value_from == noone) continue;
if (!_in.value_from.node.rendered)
return false;
}
}
return true;
}
@ -261,7 +262,7 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
draw_set_text(f_p1, fa_left, fa_center, cc);
if(!auto_update) icon = THEME.refresh_s;
if(inspectorUpdate != noone) icon = THEME.refresh_s;
var ts = clamp(power(_s, 0.5), 0.5, 1);
if(icon) {
draw_sprite_ui_uniform(icon, 0, xx + ui(12), yy + ui(10));
@ -567,6 +568,7 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
if(_to.value_from.node != self) continue;
_to.node.triggerRender();
if(_to.node.isUpdateReady()) {
ds_stack_push(RENDER_STACK, _to.node);
printIf(global.RENDER_LOG, " > Push " + _to.node.name + " node to stack");
@ -633,26 +635,30 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
}
static checkConnectGroup = function(_type = "group") {
var _y = y;
for(var i = 0; i < ds_list_size(inputs); i++) {
var _in = inputs[| i];
if(_in.value_from && _in.value_from.node.group != group) {
if(_in.value_from == noone) continue;
if(_in.value_from.node.group == group) continue;
var input_node = noone;
switch(_type) {
case "group" : input_node = new Node_Group_Input(x - w - 64, y, group); break;
case "loop" : input_node = new Node_Iterator_Input(x - w - 64, y, group); break;
case "group" : input_node = new Node_Group_Input(x - w - 64, _y, group); break;
case "loop" : input_node = new Node_Iterator_Input(x - w - 64, _y, group); break;
case "feedback" : input_node = new Node_Feedback_Input(x - w - 64, _y, group); break;
}
if(input_node == noone) continue;
input_node.inputs[| 2].setValue(_in.type);
input_node.inputs[| 0].setValue(_in.display_type);
ds_list_add(group.nodes, input_node);
input_node.inputs[| 2].setValue(_in.type);
input_node.inParent.setFrom(_in.value_from);
input_node.onValueUpdate(0);
_in.setFrom(input_node.outputs[| 0]);
_y += 64;
}
}
for(var i = 0; i < ds_list_size(outputs); i++) {
var _ou = outputs[| i];
for(var j = 0; j < ds_list_size(_ou.value_to); j++) {
@ -665,10 +671,10 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) constructor {
switch(_type) {
case "group" : output_node = new Node_Group_Output(x + w + 64, y, group); break;
case "loop" : output_node = new Node_Iterator_Output(x + w + 64, y, group); break;
case "feedback" : output_node = new Node_Feedback_Output(x + w + 64, y, group); break;
}
if(output_node == noone) continue;
ds_list_add(group.nodes, output_node);
_to.setFrom(output_node.outParent);
output_node.inputs[| 0].setFrom(_ou);

View file

@ -13,7 +13,6 @@ function Node_create_Export(_x, _y, _group = -1) {
function Node_Export(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
name = "Export";
auto_update = false;
previewable = false;
w = 96;
@ -51,10 +50,8 @@ function Node_Export(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
.setVisible(false);
inputs[| 8] = nodeValue(8, "Dithering", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false)
.setVisible(false);
inputs[| 9] = nodeValue(9, "Auto execute", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
input_display_list = [
9,
["Path", false], 0, 1, 2, 4,
["Format settings", false], 3,
["Gif settings", false], 5, 6, 7, 8,
@ -112,53 +109,6 @@ function Node_Export(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
PANEL_MENU.setNotiIcon(THEME.noti_icon_tick);
}
static step = function() {
auto_update = inputs[| 9].getValue();
var surf = inputs[| 0].getValue();
if(is_array(surf)) inputs[| 3].display_data = format_array;
else inputs[| 3].display_data = format_single;
var anim = inputs[| 3].getValue();
if(!anim) return;
if(!ANIMATOR.is_playing) {
playing = false;
return;
}
if(!ANIMATOR.frame_progress || !playing || ANIMATOR.current_frame <= -1)
return;
export();
if(ANIMATOR.current_frame < ANIMATOR.frames_total - 1)
return;
ANIMATOR.is_playing = false;
playing = false;
if(anim != 2)
return;
var path = inputs[| 1].getValue();
var suff = inputs[| 2].getValue();
var temp_path, target_path;
if(is_array(surf)) {
for(var i = 0; i < array_length(surf); i++) {
temp_path = "\"" + DIRECTORY + "temp\\" + string(i) + "\\" + "*.png\"";
if(is_array(path))
target_path = pathString(path[ safe_mod(i, array_length(path)) ], suff, i);
else
target_path = pathString(path, suff, i);
renderGif(temp_path, "\"" + target_path + "\"");
}
} else {
target_path = "\"" + pathString(path, suff) + "\"";
renderGif("\"" + DIRECTORY + "temp\\*.png\"", target_path);
}
}
static pathString = function(path, suff, index = 0) {
var form = inputs[| 3].getValue();
@ -288,7 +238,7 @@ function Node_Export(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
}
}
static update = function() {
static inspectorUpdate = function() {
if(LOADING || APPENDING) return;
var path = inputs[| 1].getValue();
@ -307,4 +257,50 @@ function Node_Export(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
} else
export();
}
static update = function() {
var surf = inputs[| 0].getValue();
if(is_array(surf)) inputs[| 3].display_data = format_array;
else inputs[| 3].display_data = format_single;
var anim = inputs[| 3].getValue();
if(!anim) return;
if(!ANIMATOR.is_playing) {
playing = false;
return;
}
if(!ANIMATOR.frame_progress || !playing || ANIMATOR.current_frame <= -1)
return;
export();
if(ANIMATOR.current_frame < ANIMATOR.frames_total - 1)
return;
ANIMATOR.is_playing = false;
playing = false;
if(anim != 2)
return;
var path = inputs[| 1].getValue();
var suff = inputs[| 2].getValue();
var temp_path, target_path;
if(is_array(surf)) {
for(var i = 0; i < array_length(surf); i++) {
temp_path = "\"" + DIRECTORY + "temp\\" + string(i) + "\\" + "*.png\"";
if(is_array(path))
target_path = pathString(path[ safe_mod(i, array_length(path)) ], suff, i);
else
target_path = pathString(path, suff, i);
renderGif(temp_path, "\"" + target_path + "\"");
}
} else {
target_path = "\"" + pathString(path, suff) + "\"";
renderGif("\"" + DIRECTORY + "temp\\*.png\"", target_path);
}
}
}

View file

@ -15,7 +15,7 @@ function Node_Feedback_Input(_x, _y, _group = -1) : Node_Group_Input(_x, _y, _gr
}
if(ANIMATOR.current_frame > 1 && _node_output != noone)
return [ _node_output.node.cache_value, inputs[| 2].getValue() ];
return [ _node_output.node.cache_value, inParent ];
if(inParent.value_from == noone)
return [ -1, VALUE_TYPE.any ];

View file

@ -4,7 +4,6 @@ function Node_Global(_x, _y) constructor {
y = _y;
use_cache = false;
auto_update = false;
inputs = ds_list_create();
outputs = ds_list_create();
input_display_list = -1;

View file

@ -11,9 +11,21 @@ function Node_Group_Input(_x, _y, _group = -1) : Node(_x, _y, _group) constructo
h = 32 + 24;
min_h = h;
display_list = [
/*Integer*/ [ "Default", "Range", "Rotation", "Rotation range", "Slider", "Slider range", "Padding", "Vector", "Vector range", "Area", "Enum button", "Menu scroll" ],
/*Float*/ [ "Default", "Range", "Rotation", "Rotation range", "Slider", "Slider range", "Padding", "Vector", "Vector range", "Area" ],
/*Boolean*/ [ "Default" ],
/*Color*/ [ "Default", "Gradient", "Palette" ],
/*Surface*/ [ "Default", ],
/*Path*/ [ "Default", ],
/*Curve*/ [ "Default", ],
/*Text*/ [ "Default", ],
/*Object*/ [ "Default", ],
/*Any*/ [ "Default", ],
]
inputs[| 0] = nodeValue(0, "Display type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Default", "Range", "Enum Scroll", "Enum Button", "Rotation", "Rotation range",
"Slider", "Slider range", "Gradient", "Palette", "Padding", "Vector", "Vector range", "Area", "Curve" ]);
.setDisplay(VALUE_DISPLAY.enum_scroll, display_list[0]);
inputs[| 1] = nodeValue(1, "Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [0, 1])
.setDisplay(VALUE_DISPLAY.vector)
@ -54,47 +66,45 @@ function Node_Group_Input(_x, _y, _group = -1) : Node(_x, _y, _group) constructo
if(_to.value_from == _o)
_to.removeFrom();
}
inputs[| 0].editWidget.data_list = display_list[_val_type];
inputs[| 0].setValue(0);
_dtype = 0;
}
_dtype = display_list[_val_type][_dtype];
inParent.type = _val_type;
outputs[| 0].type = _val_type;
var _val = inParent.getValue();
switch(_dtype) {
case VALUE_DISPLAY.range :
case VALUE_DISPLAY.slider :
inParent.setDisplay(_dtype, [_range[0], _range[1], 0.01]);
break;
case "Range" : inParent.setDisplay(VALUE_DISPLAY.range, [_range[0], _range[1], 0.01]); break;
case VALUE_DISPLAY.slider_range :
inParent.setDisplay(_dtype, [_range[0], _range[1], 0.01]);
break;
case "Slider" : inParent.setDisplay(VALUE_DISPLAY.slider, [_range[0], _range[1], 0.01]); break;
case "Slider range" : inParent.setDisplay(VALUE_DISPLAY.slider_range, [_range[0], _range[1], 0.01]); break;
case VALUE_DISPLAY.rotation_range :
case "Rotation" : inParent.setDisplay(VALUE_DISPLAY.rotation); break;
case "Rotation range" :
if(!is_array(_val) || array_length(_val) != 2)
inParent.animator = new valueAnimator([0, 0], inParent);
inParent.setDisplay(_dtype);
inParent.setDisplay(VALUE_DISPLAY.rotation_range);
break;
case VALUE_DISPLAY.enum_button :
case VALUE_DISPLAY.enum_scroll :
inParent.setDisplay(_dtype, string_splice(_enum_label, ","));
break;
case VALUE_DISPLAY.padding :
case "Padding" :
if(!is_array(_val) || array_length(_val) != 4)
inParent.animator = new valueAnimator([0, 0, 0, 0], inParent);
inParent.setDisplay(_dtype);
inParent.setDisplay(VALUE_DISPLAY.padding);
break;
case VALUE_DISPLAY.area :
case "Area" :
if(!is_array(_val) || array_length(_val) != 5)
inParent.animator = new valueAnimator([0, 0, 0, 0, 5], inParent);
inParent.setDisplay(_dtype);
inParent.setDisplay(VALUE_DISPLAY.area);
break;
case VALUE_DISPLAY.vector :
case VALUE_DISPLAY.vector_range :
case "Vector" :
case "Vector range" :
switch(_vec_size) {
case 0 :
if(!is_array(_val) || array_length(_val) != 2)
@ -109,19 +119,21 @@ function Node_Group_Input(_x, _y, _group = -1) : Node(_x, _y, _group) constructo
inParent.animator = new valueAnimator([0, 0, 0, 0], inParent);
break;
}
inParent.setDisplay(_dtype);
if(_dtype == "Vector") inParent.setDisplay(VALUE_DISPLAY.vector);
else if(_dtype == "Vector range") inParent.setDisplay(VALUE_DISPLAY.vector_range);
break;
case VALUE_DISPLAY.palette :
case "Enum button" : inParent.setDisplay(VALUE_DISPLAY.enum_button, string_splice(_enum_label, ",")); break;
case "Menu scroll" : inParent.setDisplay(VALUE_DISPLAY.enum_scroll, string_splice(_enum_label, ",")); break;
case "Palette" :
if(!is_array(_val))
inParent.animator = new valueAnimator([c_black], inParent);
inParent.setDisplay(_dtype);
inParent.setDisplay(VALUE_DISPLAY.palette);
break;
default :
inParent.setDisplay(_dtype);
break;
case "Gradient": inParent.setDisplay(VALUE_DISPLAY.gradient); break;
default: inParent.setDisplay(VALUE_DISPLAY._default); break;
}
if(index == 5)
@ -167,23 +179,25 @@ function Node_Group_Input(_x, _y, _group = -1) : Node(_x, _y, _group) constructo
if(is_undefined(inParent)) return;
var _dtype = inputs[| 0].getValue();
var _data = inputs[| 2].getValue();
_dtype = display_list[_data][_dtype];
inputs[| 1].setVisible(false);
inputs[| 3].setVisible(false);
inputs[| 4].setVisible(false);
switch(_dtype) {
case VALUE_DISPLAY.range :
case VALUE_DISPLAY.slider :
case VALUE_DISPLAY.slider_range :
case "Range" :
case "Slider" :
case "Slider range" :
inputs[| 1].setVisible(true);
break;
case VALUE_DISPLAY.enum_button :
case VALUE_DISPLAY.enum_scroll :
case "Enum button" :
case "Menu scroll" :
inputs[| 3].setVisible(true);
break;
case VALUE_DISPLAY.vector :
case VALUE_DISPLAY.vector_range :
case "Vector" :
case "Vector range" :
inputs[| 4].setVisible(true);
break;
}
@ -193,15 +207,41 @@ function Node_Group_Input(_x, _y, _group = -1) : Node(_x, _y, _group) constructo
createInput(false);
var _inputs = load_map[? "inputs"];
inputs[| 5].applyDeserialize(_inputs[| 5], load_scale);
inputs[| 2].applyDeserialize(_inputs[| 2], load_scale);
onValueUpdate(2);
}
static applyDeserialize = function() {
var _inputs = load_map[? "inputs"];
for(var i = 0; i < ds_list_size(inputs); i++) {
if(i == 5) continue;
if(i == 2 || i == 5) continue;
inputs[| i].applyDeserialize(_inputs[| i], load_scale);
var raw_val = _inputs[| i][? "raw value"];
}
if(LOADING_VERSION < 1060) {
var _dtype = inputs[| 0].getValue();
switch(_dtype) {
case VALUE_DISPLAY.range : inputs[| 0].setValue( 1); break;
case VALUE_DISPLAY.rotation : inputs[| 0].setValue( 2); break;
case VALUE_DISPLAY.rotation_range : inputs[| 0].setValue( 3); break;
case VALUE_DISPLAY.slider : inputs[| 0].setValue( 4); break;
case VALUE_DISPLAY.slider_range : inputs[| 0].setValue( 5); break;
case VALUE_DISPLAY.padding : inputs[| 0].setValue( 6); break;
case VALUE_DISPLAY.vector : inputs[| 0].setValue( 7); break;
case VALUE_DISPLAY.vector_range : inputs[| 0].setValue( 8); break;
case VALUE_DISPLAY.area : inputs[| 0].setValue( 9); break;
case VALUE_DISPLAY.enum_button : inputs[| 0].setValue(10); break;
case VALUE_DISPLAY.enum_scroll : inputs[| 0].setValue(11); break;
case VALUE_DISPLAY.gradient : inputs[| 0].setValue( 1); break;
case VALUE_DISPLAY.palette : inputs[| 0].setValue( 2); break;
default : inputs[| 0].setValue( 0); break;
}
}
onValueUpdate(0);
}

View file

@ -24,7 +24,7 @@ function Node_Iterator_Input(_x, _y, _group = -1) : Node_Group_Input(_x, _y, _gr
if(_node_output == noone || group.iterated == 0)
return outputs[| 0].getValueDefault();
return [ _node_output.node.cache_value, inputs[| 2].getValue() ];
return [ _node_output.node.cache_value, inParent ];
}
outputs[| 1] = nodeValue(1, "Loop entrance", self, JUNCTION_CONNECT.output, VALUE_TYPE.node, 0);

View file

@ -52,8 +52,8 @@ function Node_Cellular(_x, _y, _group = -1) : Node_Processor(_x, _y, _group) con
var _pat = _data[6];
var _mid = _data[7];
_data[8].setVisible(_pat == 1);
_data[9].setVisible(_pat == 1);
inputs[| 8].setVisible(_pat == 1);
inputs[| 9].setVisible(_pat == 1);
var _rad = _data[8];
var _sht = _data[9];

View file

@ -12,7 +12,8 @@ function Node_Palette(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
inputs[| 1] = nodeValue(1, "Trim range", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 1 ])
.setDisplay(VALUE_DISPLAY.slider_range, [0, 1, 0.01]);
outputs[| 0] = nodeValue(0, "Palette", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, []);
outputs[| 0] = nodeValue(0, "Palette", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, [])
.setDisplay(VALUE_DISPLAY.palette);
input_display_list = [0,
["Trim", true], 1

View file

@ -1,6 +1,5 @@
function Node_Particle(_x, _y, _group = -1) : Node_VFX_Spawner_Base(_x, _y, _group) constructor {
name = "Particle";
auto_update = false;
use_cache = true;
inputs[| input_len + 0] = nodeValue(input_len + 0, "Output dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, def_surf_size2)

View file

@ -210,7 +210,7 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor {
addNodeObject(color, "RGB Color", s_node_color_from_rgb, "Node_Color_RGB", [1, Node_Color_RGB]);
addNodeObject(color, "HSV Color", s_node_color_from_hsv, "Node_Color_HSV", [1, Node_Color_HSV]);
addNodeObject(color, "Palette", s_node_palette, "Node_Palette", [1, Node_Palette]);
addNodeObject(color, "Gradient", s_node_gradient_out, "Node_Gradient_Out", [1, Node_Gradient_Out]);
addNodeObject(color, "Gradient data", s_node_gradient_out, "Node_Gradient_Out", [1, Node_Gradient_Out]);
addNodeObject(color, "Sampler", s_node_sampler, "Node_Sampler", [1, Node_Sampler]);
addNodeObject(color, "Color data", s_node_color_data, "Node_Color_Data", [1, Node_Color_Data]);
@ -239,6 +239,7 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor {
var _x = ds_map_try_get(_data, "x", 0);
var _y = ds_map_try_get(_data, "y", 0);
var _type = ds_map_try_get(_data, "type", 0);
var _node = nodeBuild(_type, _x, _y);
if(_node) {

View file

@ -1,6 +1,5 @@
function Node_Seperate_Shape(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
name = "Separate shape";
auto_update = false;
shader = sh_seperate_shape_ite;
uniform_it_dim = shader_get_uniform(shader, "dimension");
@ -32,7 +31,7 @@ function Node_Seperate_Shape(_x, _y, _group = -1) : Node(_x, _y, _group) constru
_prev_type = -1;
static update = function() {
static inspectorUpdate = function() {
var _inSurf = inputs[| 0].getValue();
var _out_type = inputs[| 1].getValue();
var t = current_time;

View file

@ -11,8 +11,6 @@ enum SPRITE_ANIM_GROUP {
function Node_Render_Sprite_Sheet(_x, _y, _group = -1) : Node(_x, _y, _group) constructor {
name = "Sheet";
auto_update = false;
anim_drawn = array_create(ANIMATOR.frames_total + 1, false);
inputs[| 0] = nodeValue(0, "Sprites", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, PIXEL_SURFACE);
@ -33,16 +31,23 @@ function Node_Render_Sprite_Sheet(_x, _y, _group = -1) : Node(_x, _y, _group) co
outputs[| 0] = nodeValue(0, "Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, PIXEL_SURFACE);
static step = function() {
var inpt = inputs[| 0].getValue();
var oupt = outputs[| 0].getValue();
var grup = inputs[| 1].getValue();
var skip = inputs[| 2].getValue();
var pack = inputs[| 3].getValue();
var alig = inputs[| 5].getValue();
inputs[| 2].setVisible(grup == SPRITE_ANIM_GROUP.animation);
inputs[| 4].setVisible(pack == SPRITE_STACK.grid);
}
static update = function() {
var inpt = inputs[| 0].getValue();
var grup = inputs[| 1].getValue();
var skip = inputs[| 2].getValue();
var pack = inputs[| 3].getValue();
var grid = inputs[| 4].getValue();
var alig = inputs[| 5].getValue();
var oupt = outputs[| 0].getValue();
if(grup != SPRITE_ANIM_GROUP.animation) return;
if(safe_mod(ANIMATOR.current_frame, skip) != 0) return;
@ -125,7 +130,7 @@ function Node_Render_Sprite_Sheet(_x, _y, _group = -1) : Node(_x, _y, _group) co
if(drawn) anim_drawn[ANIMATOR.current_frame] = true;
}
static update = function() {
static inspectorUpdate = function() {
for(var i = 0; i < array_length(anim_drawn); i++) anim_drawn[i] = false;
var inpt = inputs[| 0].getValue();
@ -137,7 +142,7 @@ function Node_Render_Sprite_Sheet(_x, _y, _group = -1) : Node(_x, _y, _group) co
if(!LOADING && !APPENDING) {
ANIMATOR.setFrame(-1);
ANIMATOR.is_playing = true;
ANIMATOR.stopOnEnd = true;
ANIMATOR.rendering = true;
}
var skip = inputs[| 2].getValue();
@ -303,10 +308,8 @@ function Node_Render_Sprite_Sheet(_x, _y, _group = -1) : Node(_x, _y, _group) co
}
surface_reset_target();
outputs[| 0].setValue(_surf);
} else {
} else
outputs[| 0].setValue(inpt);
}
}
}
doUpdate();
}

View file

@ -86,11 +86,12 @@ function value_color(i) {
function value_bit(i) {
switch(i) {
case VALUE_TYPE.integer : return 1 << 0 | 1 << 1;
case VALUE_TYPE.float : return 1 << 1 | 1 << 2;
case VALUE_TYPE.color : return 1 << 3;
case VALUE_TYPE.surface : return 1 << 4;
case VALUE_TYPE.float : return 1 << 2 | 1 << 1;
case VALUE_TYPE.boolean : return 1 << 3 | 1 << 1;
case VALUE_TYPE.color : return 1 << 4;
case VALUE_TYPE.surface : return 1 << 5;
case VALUE_TYPE.path : return 1 << 10;
case VALUE_TYPE.text : return 1 << 0 | 1 << 1 | 1 << 10 | 1 << 11;
case VALUE_TYPE.text : return 1 << 10 | 1 << 11;
case VALUE_TYPE.node : return 1 << 12;
case VALUE_TYPE.object : return 1 << 20;
@ -100,7 +101,16 @@ function value_bit(i) {
}
function value_type_directional(f, t) {
if(f.type == VALUE_TYPE.surface && (t.type == VALUE_TYPE.integer || t.type == VALUE_TYPE.float)) return true;
if(f.type == VALUE_TYPE.surface && t.type == VALUE_TYPE.integer) return true;
if(f.type == VALUE_TYPE.surface && t.type == VALUE_TYPE.float) return true;
if(f.type == VALUE_TYPE.integer && t.type == VALUE_TYPE.color) return true;
if(f.type == VALUE_TYPE.float && t.type == VALUE_TYPE.color) return true;
if(f.type == VALUE_TYPE.integer && t.type == VALUE_TYPE.text) return true;
if(f.type == VALUE_TYPE.float && t.type == VALUE_TYPE.text) return true;
if(f.type == VALUE_TYPE.boolean && t.type == VALUE_TYPE.text) return true;
return false;
}
@ -170,6 +180,7 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
animator = new valueAnimator(_value, self);
on_end = KEYFRAME_END.hold;
extra_data = ds_list_create();
dyna_depo = ds_list_create();
visible = _connect == JUNCTION_CONNECT.output || _type == VALUE_TYPE.surface || _type == VALUE_TYPE.path;
show_in_inspector = true;
@ -465,17 +476,33 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
return self;
}
static valueProcess = function(value, type) {
static valueProcess = function(value, type, display) {
switch(type) {
case VALUE_TYPE.text : return string(value);
default : return value;
case VALUE_TYPE.text :
return string(value);
case VALUE_TYPE.color :
if(display_type == VALUE_DISPLAY.gradient && display == VALUE_DISPLAY._default) {
ds_list_clear(dyna_depo);
ds_list_add(dyna_depo, new valueKey(0, value));
return dyna_depo;
} else if(display_type == VALUE_DISPLAY.gradient && display == VALUE_DISPLAY.palette) {
ds_list_clear(dyna_depo);
var amo = array_length(value);
for( var i = 0; i < amo; i++ ) {
ds_list_add(dyna_depo, new valueKey(i / amo, value[i]));
}
return dyna_depo;
}
}
return value;
}
static getValue = function(_time = ANIMATOR.current_frame) {
var _val = getValueRecursive(_time);
var val = _val[0];
var typ = _val[1];
var nod = _val[1];
var typ = nod.type;
var dis = nod.display_type;
var _base = animator.getValue(_time);
@ -483,9 +510,40 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
if(is_array(val)) {
if(array_length(val) > 0 && is_surface(val[0]))
return [ surface_get_width(val[0]), surface_get_height(val[0]) ];
} else if (is_surface(val)) {
} else if (is_surface(val))
return [ surface_get_width(val), surface_get_height(val) ];
}
} else if(typ == VALUE_TYPE.integer && type == VALUE_TYPE.color) {
if(is_array(val)) {
var v = [];
for( var i = 0; i < array_length(val); i++ )
array_append(v, make_color_hsv(0, 0, val[i]))
return v;
} else
return make_color_hsv(0, 0, val);
} else if(typ == VALUE_TYPE.float && type == VALUE_TYPE.color) {
if(is_array(val)) {
var v = [];
for( var i = 0; i < array_length(val); i++ )
array_append(v, make_color_hsv(0, 0, val[i] * 255))
return v;
} else
return make_color_hsv(0, 0, val * 255);
} else if(typ == VALUE_TYPE.boolean && type == VALUE_TYPE.text) {
if(is_array(val)) {
var v = [];
for( var i = 0; i < array_length(val); i++ )
array_append(v, val[i]? "true" : "false")
return v;
} else
return val? "true" : "false";
} else if(typ == VALUE_TYPE.float && type == VALUE_TYPE.text) {
if(is_array(val)) {
var v = [];
for( var i = 0; i < array_length(val); i++ )
array_append(v, string(val[i]))
return v;
} else
return string(val);
}
if(is_array(_base)) {
@ -497,20 +555,20 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
}
}
if(is_array(val)) {
if(nod.isArray(val)) {
for( var i = 0; i < array_length(val); i++ )
val[i] = valueProcess(val[i], typ);
val[i] = valueProcess(val[i], typ, dis);
} else
val = valueProcess(val, typ);
val = valueProcess(val, typ, dis);
return val;
}
static getValueRecursive = function(_time = ANIMATOR.current_frame) {
var val = [ -1, VALUE_TYPE.any ];
var val = [ -1, VALUE_TYPE.any, VALUE_DISPLAY._default ];
if(value_from == noone)
val = [animator.getValue(_time), type];
val = [animator.getValue(_time), self ];
else if(value_from != self)
val = value_from.getValueRecursive(_time);
@ -518,12 +576,12 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
}
static getExtraData = function() {
var data = extra_data;
if(value_from != noone && value_from != self)
data = value_from.getExtraData();
return data;
if(value_from != noone && value_from != self) {
if(display_type == VALUE_DISPLAY.gradient && value_from.display_type != VALUE_DISPLAY.gradient)
return extra_data;
return value_from.getExtraData();
}
return extra_data;
}
static __anim = function() {
@ -543,15 +601,15 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
return val;
}
static isArray = function() {
var val = getValue();
static isArray = function(val = getValue()) {
if(!is_array(val))
return false;
if(is_array(val)) {
if(typeArray(display_type) && array_length(val) > 0)
return is_array(val[0]);
else
if(!typeArray(display_type))
return true;
}
if(array_length(val) > 0)
return is_array(val[0]);
return false;
}
@ -574,7 +632,7 @@ function NodeValue(_index, _name, _node, _connect, _type, _value, _tag = VALUE_T
updated = _o != _n;
if(updated) {
if(node.auto_update && connect_type == JUNCTION_CONNECT.input)
if(connect_type == JUNCTION_CONNECT.input)
node.triggerRender();
if(node.use_cache) node.clearCache();

View file

@ -291,6 +291,7 @@ function Panel_Collection() : PanelContent() constructor {
var dia = dialogCall(o_dialog_file_name, mouse_mx + 8, mouse_my + 8);
dia.onModify = function (txt) {
directory_create(txt);
refreshContext();
};
dia.path = context.path + "\\";
}

View file

@ -219,13 +219,17 @@ function Panel_Graph() : PanelContent() constructor {
function dragGraph() {
if(graph_dragging) {
if(!MOUSE_WRAPPING) {
var dx = mx - graph_drag_mx;
var dy = my - graph_drag_my;
graph_drag_mx = mx;
graph_drag_my = my;
graph_x += dx / graph_s;
graph_y += dy / graph_s;
}
graph_drag_mx = mx;
graph_drag_my = my;
setMouseWrap();
if(mouse_release(drag_key))
graph_dragging = false;
@ -735,7 +739,7 @@ function Panel_Graph() : PanelContent() constructor {
cx = cx + 160;
cy = round(cy / ds_list_size(nodes_select_list) / 32) * 32;
var _compose = new Node_Composite(cx, cy);
var _compose = nodeBuild("Node_Composite", cx, cy);
for( var i = 0; i < ds_list_size(nodes_select_list); i++ ) {
var _node = nodes_select_list[| i];

View file

@ -466,13 +466,14 @@ function Panel_Inspector() : PanelContent() constructor {
if(buttonInstant(THEME.button_hide, bx, by, ui(32), ui(32), [mx, my], pFOCUS, pHOVER, "Presets", THEME.preset, 1) == 2)
dialogCall(o_dialog_preset, x + bx, y + by + ui(36), { "node": inspecting });
if(!inspecting.auto_update) {
var bx = w - ui(44);
var by = ui(12);
if(inspecting.inspectorUpdate != noone) {
if(buttonInstant(THEME.button_hide, bx, by, ui(32), ui(32), [mx, my], pFOCUS, pHOVER, "Execute node", THEME.sequence_control, 1, COLORS._main_value_positive) == 2)
inspecting.doUpdate();
}
inspecting.inspectorUpdate();
} else
draw_sprite_ui(THEME.sequence_control, 1, bx + ui(16), by + ui(16),,,, COLORS._main_icon_dark);
if(inspecting.use_cache) {
var bx = w - ui(44);

View file

@ -173,13 +173,17 @@ function Panel_Preview() : PanelContent() constructor {
function dragCanvas() {
if(canvas_dragging) {
if(!MOUSE_WRAPPING) {
var dx = mx - canvas_drag_mx;
var dy = my - canvas_drag_my;
canvas_drag_mx = mx;
canvas_drag_my = my;
canvas_x += dx;
canvas_y += dy;
}
canvas_drag_mx = mx;
canvas_drag_my = my;
setMouseWrap();
if(mouse_release(mb_middle))
canvas_dragging = false;

View file

@ -16,7 +16,7 @@ function rangeBox(_type, _onModify) constructor {
}
static draw = function(_x, _y, _w, _h, _data, _m) {
if(extras && instanceof(extras) == "buttonClass") {
if(extras != -1 && is_struct(extras) && instanceof(extras) == "buttonClass") {
extras.hover = hover;
extras.active = active;

View file

@ -32,7 +32,7 @@ function __nodeInLoop(_node) {
function Render(partial = false) {
var rendering = noone;
var error = 0;
printIf(global.RENDER_LOG, "=== RENDER START ===");
printIf(global.RENDER_LOG, "=== RENDER START [frame " + string(ANIMATOR.current_frame) + "] ===");
if(!partial || ALWAYS_FULL) {
var _key = ds_map_find_first(NODE_MAP);
@ -75,7 +75,6 @@ function Render(partial = false) {
var txt = rendering.rendered? " [Skip]" : " [Update]";
if(!rendering.rendered) {
if(LOADING || APPENDING || rendering.auto_update)
rendering.doUpdate();
rendering.setRenderStatus(true);
}

View file

@ -106,7 +106,7 @@ function scrollPane(_w, _h, ondraw) constructor {
draw_sprite_stretched_ext(THEME.ui_scrollbar, 0, bar_x, bar_y, bar_w, bar_h, bar_col, 1);
if(active && point_in_rectangle(mx, my, scr_x - 2, scr_y - 2, scr_x + scr_w + 2, scr_y + scr_h + 2) || is_scrolling) {
draw_sprite_stretched_ext(THEME.ui_scrollbar, 0, bar_x, bar_y, bar_w, bar_h, bar_hcol, 1);
if(mouse_click(mb_left, active)) {
if(mouse_press(mb_left, active)) {
is_scrolling = true;
scroll_ms = is_vert? my : mx;
}

View file

@ -17,7 +17,7 @@ function draw_surface_part_ext_safe(surface, _l, _t, _w, _h, _x, _y, _xs = 1, _y
function surface_size_to(surface, width, height) {
if(!surface_exists(surface)) return false;
if(width == 1 && height == 1) return false;
if(width <= 1 && height <= 1) return false;
width = surface_valid_size(width);
height = surface_valid_size(height);

View file

@ -279,7 +279,7 @@ function textBox(_input, _onModify) constructor {
if(sliding > 0) {
var dx = _m[0] - slide_mx;
var dy = slide_my - _m[1];
var dy = -(_m[1] - slide_my);
if(sliding == 1 && (abs(dx) > 16 || abs(dy) > 16)) {
sliding = 2;
@ -288,6 +288,9 @@ function textBox(_input, _onModify) constructor {
}
if(sliding == 2) {
var _ip = _input_text;
if(!MOUSE_WRAPPING) {
var spd = (abs(dx) > abs(dy)? dx : dy) * slide_speed;
if(keyboard_check(vk_alt))
@ -295,21 +298,22 @@ function textBox(_input, _onModify) constructor {
if(key_mod_press(CTRL))
spd *= 10;
var _ip = _input_text;
_input_text = _input_text + spd;
switch(input) {
case TEXTBOX_INPUT.number : _input_text = round(_input_text); break;
}
if(_input_text != _ip) {
apply();
UNDO_HOLDING = true;
}
if(MOUSE_WRAPPING || _input_text != _ip) {
slide_mx = _m[0];
slide_my = _m[1];
}
apply();
UNDO_HOLDING = true;
setMouseWrap();
if(mouse_release(mb_left)) {
UNDO_HOLDING = false;
TEXTBOX_ACTIVE = noone;

View file

@ -0,0 +1,327 @@
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec2 dimension;
//enables 2:1 slopes. otherwise only uses 45 degree slopes
#define SLOPE
//cleans up small detail slope transitions (if SLOPE is enabled)
//if only using for rotation, CLEANUP has negligable effect and should be disabled for speed
#define CLEANUP
//the color with the highest priority.
// other colors will be tested based on distance to this
// color to determine which colors take priority for overlaps.
/* uniform */ vec3 highestColor = vec3(1., 1., 1.);
//how close two colors should be to be considered "similar".
// can group shapes of visually similar colors, but creates
// some artifacting and should be kept as low as possible.
/* uniform */ float similarThreshold = 0.0;
/* uniform */ float lineWidth = 1.0;
const float scale = 4.0;
const mat3 yuv_matrix = mat3(vec3(0.299, 0.587, 0.114), vec3(-0.169, -0.331, 0.5), vec3(0.5, -0.419, -0.081));
const mat3 yuv_matrix_t = mat3(vec3(0.299, -0.169, 0.5), vec3(0.587, -0.331, -0.419), vec3(0.114, 0.5, -0.081));
vec3 yuv(vec3 col){
return yuv_matrix_t * col;
}
bool similar(vec4 col1, vec4 col2){
return (col1.a == 0. && col2.a == 0.) || distance(col1, col2) <= similarThreshold;
}
//multiple versions because godot doesn't support function overloading
//note: inner check should ideally check between all permutations
// but this is good enough, and faster
bool similar3(vec4 col1, vec4 col2, vec4 col3){
return similar(col1, col2) && similar(col2, col3);
}
bool similar4(vec4 col1, vec4 col2, vec4 col3, vec4 col4){
return similar(col1, col2) && similar(col2, col3) && similar(col3, col4);
}
bool similar5(vec4 col1, vec4 col2, vec4 col3, vec4 col4, vec4 col5){
return similar(col1, col2) && similar(col2, col3) && similar(col3, col4) && similar(col4, col5);
}
bool higher(vec4 thisCol, vec4 otherCol){
if(similar(thisCol, otherCol)) return false;
if(thisCol.a == otherCol.a){
// return yuv(thisCol.rgb).x > yuv(otherCol.rgb).x;
// return distance(yuv(thisCol.rgb), yuv(highestColor)) < distance(yuv(otherCol.rgb), yuv(highestColor));
return distance(thisCol.rgb, highestColor) < distance(otherCol.rgb, highestColor);
} else {
return thisCol.a > otherCol.a;
}
}
vec4 higherCol(vec4 thisCol, vec4 otherCol){
return higher(thisCol, otherCol) ? thisCol : otherCol;
}
//color distance
float cd(vec4 col1, vec4 col2){
return distance(col1.rgba, col2.rgba);
}
float distToLine(vec2 testPt, vec2 pt1, vec2 pt2, vec2 dir){
vec2 lineDir = pt2 - pt1;
vec2 perpDir = vec2(lineDir.y, -lineDir.x);
vec2 dirToPt1 = pt1 - testPt;
return (dot(perpDir, dir) > 0.0 ? 1.0 : -1.0) * (dot(normalize(perpDir), dirToPt1));
}
//based on down-forward direction
vec4 sliceDist(vec2 point, vec2 mainDir, vec2 pointDir, vec4 u, vec4 uf, vec4 uff, vec4 b, vec4 c, vec4 f, vec4 ff, vec4 db, vec4 d, vec4 df, vec4 dff, vec4 ddb, vec4 dd, vec4 ddf){
#ifdef SLOPE
float minWidth = 0.44;
float maxWidth = 1.142;
#else
float minWidth = 0.0;
float maxWidth = 1.4;
#endif
float _lineWidth = max(minWidth, min(maxWidth, lineWidth));
point = mainDir * (point - 0.5) + 0.5; //flip point
//edge detection
float distAgainst = 4.0 * cd(f,d) + cd(uf,c) + cd(c,db) + cd(ff,df) + cd(df,dd);
float distTowards = 4.0 * cd(c,df) + cd(u,f) + cd(f,dff) + cd(b,d) + cd(d,ddf);
bool shouldSlice =
(distAgainst < distTowards)
|| (distAgainst < distTowards + 0.001) && !higher(c, f); //equivalent edges edge case
if(similar4(f, d, b, u) && similar3(uf, df, db/*, ub*/) && !similar(c, f)){ //checkerboard edge case
shouldSlice = false;
}
if(!shouldSlice) return vec4(-1.0);
//only applicable for very large lineWidth (>1.3)
// if(similar3(c, f, df)){ //don't make slice for same color
// return vec4(-1.0);
// }
float dist = 1.0;
bool flip = false;
vec2 center = vec2(0.5, 0.5);
#ifdef SLOPE
if(similar3(f, d, db) && !similar3(f, d, b) && !similar(uf, db)){ //lower shallow 2:1 slant
if(similar(c, df) && higher(c, f)){ //single pixel wide diagonal, dont flip
} else {
//priority edge cases
if(higher(c, f)){
flip = true;
}
if(similar(u, f) && !similar(c, df) && !higher(c, u)){
flip = true;
}
}
if(flip){
dist = _lineWidth-distToLine(point, center + vec2(1.5, -1.0) * pointDir, center + vec2(-0.5, 0.0) * pointDir, -pointDir); //midpoints of neighbor two-pixel groupings
} else {
dist = distToLine(point, center + vec2(1.5, 0.0) * pointDir, center + vec2(-0.5, 1.0) * pointDir, pointDir); //midpoints of neighbor two-pixel groupings
}
//cleanup slant transitions
#ifdef CLEANUP
if(!flip && similar(c, uf) && !(similar3(c, uf, uff) && !similar3(c, uf, ff) && !similar(d, uff))){ //shallow
float dist2 = distToLine(point, center + vec2(2.0, -1.0) * pointDir, center + vec2(-0.0, 1.0) * pointDir, pointDir);
dist = min(dist, dist2);
}
#endif
dist -= (_lineWidth / 2.0);
return dist <= 0.0 ? ((cd(c,f) <= cd(c,d)) ? f : d) : vec4(-1.0);
} else if(similar3(uf, f, d) && !similar3(u, f, d) && !similar(uf, db)){ //forward steep 2:1 slant
if(similar(c, df) && higher(c, d)){ //single pixel wide diagonal, dont flip
} else {
//priority edge cases
if(higher(c, d)){
flip = true;
}
if(similar(b, d) && !similar(c, df) && !higher(c, d)){
flip = true;
}
}
if(flip){
dist = _lineWidth-distToLine(point, center + vec2(0.0, -0.5) * pointDir, center + vec2(-1.0, 1.5) * pointDir, -pointDir); //midpoints of neighbor two-pixel groupings
} else {
dist = distToLine(point, center + vec2(1.0, -0.5) * pointDir, center + vec2(0.0, 1.5) * pointDir, pointDir); //midpoints of neighbor two-pixel groupings
}
//cleanup slant transitions
#ifdef CLEANUP
if(!flip && similar(c, db) && !(similar3(c, db, ddb) && !similar3(c, db, dd) && !similar(f, ddb))){ //steep
float dist2 = distToLine(point, center + vec2(1.0, 0.0) * pointDir, center + vec2(-1.0, 2.0) * pointDir, pointDir);
dist = min(dist, dist2);
}
#endif
dist -= (_lineWidth/2.0);
return dist <= 0.0 ? ((cd(c, f) <= cd(c, d)) ? f : d) : vec4(-1.0);
} else
#endif
if(similar(f, d)) { //45 diagonal
if(similar(c, df) && higher(c, f)) { //single pixel diagonal along neighbors, dont flip
if(!similar(c, dd) && !similar(c, ff)) { //line against triple color stripe edge case
flip = true;
}
} else {
//priority edge cases
if(higher(c, f)) {
flip = true;
}
if(!similar(c, b) && similar4(b, f, d, u)) {
flip = true;
}
}
//single pixel 2:1 slope, dont flip
if((( (similar(f, db) && similar3(u, f, df)) || (similar(uf, d) && similar3(b, d, df)) ) && !similar(c, df))){
flip = true;
}
if(flip){
dist = _lineWidth-distToLine(point, center + vec2(1.0, -1.0) * pointDir, center + vec2(-1.0, 1.0) * pointDir, -pointDir); //midpoints of own diagonal pixels
} else {
dist = distToLine(point, center + vec2(1.0, 0.0) * pointDir, center + vec2(0.0, 1.0) * pointDir, pointDir); //midpoints of corner neighbor pixels
}
//cleanup slant transitions
#ifdef SLOPE
#ifdef CLEANUP
if(!flip && similar3(c, uf, uff) && !similar3(c, uf, ff) && !similar(d, uff)){ //shallow
float dist2 = distToLine(point, center + vec2(1.5, 0.0) * pointDir, center + vec2(-0.5, 1.0) * pointDir, pointDir);
dist = max(dist, dist2);
}
if(!flip && similar3(ddb, db, c) && !similar3(dd, db, c) && !similar(ddb, f)){ //steep
float dist2 = distToLine(point, center + vec2(1.0, -0.5) * pointDir, center + vec2(0.0, 1.5) * pointDir, pointDir);
dist = max(dist, dist2);
}
#endif
#endif
dist -= (_lineWidth/2.0);
return dist <= 0.0 ? ((cd(c,f) <= cd(c,d)) ? f : d) : vec4(-1.0);
}
#ifdef SLOPE
else if(similar3(ff, df, d) && !similar3(ff, df, c) && !similar(uff, d)){ //far corner of shallow slant
if(similar(f, dff) && higher(f, ff)){ //single pixel wide diagonal, dont flip
} else {
//priority edge cases
if(higher(f, ff)){
flip = true;
}
if(similar(uf, ff) && !similar(f, dff) && !higher(f, uf)){
flip = true;
}
}
if(flip){
dist = _lineWidth-distToLine(point, center + vec2(1.5 + 1.0, -1.0) * pointDir, center + vec2(-0.5+1.0, 0.0) * pointDir, -pointDir); //midpoints of neighbor two-pixel groupings
} else {
dist = distToLine(point, center + vec2(1.5 + 1.0, 0.0) * pointDir, center + vec2(-0.5 + 1.0, 1.0) * pointDir, pointDir); //midpoints of neighbor two-pixel groupings
}
dist -= (_lineWidth/2.0);
return dist <= 0.0 ? ((cd(f,ff) <= cd(f,df)) ? ff : df) : vec4(-1.0);
} else if(similar3(f, df, dd) && !similar3(c, df, dd) && !similar(f, ddb)){ //far corner of steep slant
if(similar(d, ddf) && higher(d, dd)){ //single pixel wide diagonal, dont flip
} else {
//priority edge cases
if(higher(d, dd)){
flip = true;
}
if(similar(db, dd) && !similar(d, ddf) && !higher(d, dd)){
flip = true;
}
// if(!higher(d, dd)){
// return vec4(1.0);
// flip = true;
// }
}
if(flip){
dist = _lineWidth-distToLine(point, center + vec2(0.0, -0.5 + 1.0) * pointDir, center + vec2(-1.0, 1.5 + 1.0) * pointDir, -pointDir); //midpoints of neighbor two-pixel groupings
} else {
dist = distToLine(point, center + vec2(1.0, -0.5 + 1.0) * pointDir, center + vec2(0.0, 1.5 + 1.0) * pointDir, pointDir); //midpoints of neighbor two-pixel groupings
}
dist -= (_lineWidth/2.0);
return dist <= 0.0 ? ((cd(d, df) <= cd(d, dd)) ? df : dd) : vec4(-1.0);
}
#endif
return vec4(-1.0);
}
float round(float val) { return fract(val) >= 0.5? ceil(val) : floor(val); }
vec2 round(vec2 vec) { return vec2(round(vec.x), round(vec.y)); }
void main() {
vec2 size = dimension + 0.0001; //fix for some sort of rounding error
vec2 px = v_vTexcoord / dimension * size;
vec2 local = fract(px);
px = ceil(px);
vec2 pointDir = round(local) * 2.0 - 1.0;
//neighbor pixels
//Up, Down, Forward, and Back
//relative to quadrant of current location within pixel
vec4 uub = texture2D( gm_BaseTexture, (px + vec2(-1.0, -2.0) * pointDir) / size);
vec4 uu = texture2D( gm_BaseTexture, (px + vec2( 0.0, -2.0) * pointDir) / size);
vec4 uuf = texture2D( gm_BaseTexture, (px + vec2( 1.0, -2.0) * pointDir) / size);
vec4 ubb = texture2D( gm_BaseTexture, (px + vec2(-2.0, -2.0) * pointDir) / size);
vec4 ub = texture2D( gm_BaseTexture, (px + vec2(-1.0, -1.0) * pointDir) / size);
vec4 u = texture2D( gm_BaseTexture, (px + vec2( 0.0, -1.0) * pointDir) / size);
vec4 uf = texture2D( gm_BaseTexture, (px + vec2( 1.0, -1.0) * pointDir) / size);
vec4 uff = texture2D( gm_BaseTexture, (px + vec2( 2.0, -1.0) * pointDir) / size);
vec4 bb = texture2D( gm_BaseTexture, (px + vec2(-2.0, 0.0) * pointDir) / size);
vec4 b = texture2D( gm_BaseTexture, (px + vec2(-1.0, 0.0) * pointDir) / size);
vec4 c = texture2D( gm_BaseTexture, (px + vec2( 0.0, 0.0) * pointDir) / size);
vec4 f = texture2D( gm_BaseTexture, (px + vec2( 1.0, 0.0) * pointDir) / size);
vec4 ff = texture2D( gm_BaseTexture, (px + vec2( 2.0, 0.0) * pointDir) / size);
vec4 dbb = texture2D( gm_BaseTexture, (px + vec2(-2.0, 1.0) * pointDir) / size);
vec4 db = texture2D( gm_BaseTexture, (px + vec2(-1.0, 1.0) * pointDir) / size);
vec4 d = texture2D( gm_BaseTexture, (px + vec2( 0.0, 1.0) * pointDir) / size);
vec4 df = texture2D( gm_BaseTexture, (px + vec2( 1.0, 1.0) * pointDir) / size);
vec4 dff = texture2D( gm_BaseTexture, (px + vec2( 2.0, 1.0) * pointDir) / size);
vec4 ddb = texture2D( gm_BaseTexture, (px + vec2(-1.0, 2.0) * pointDir) / size);
vec4 dd = texture2D( gm_BaseTexture, (px + vec2( 0.0, 2.0) * pointDir) / size);
vec4 ddf = texture2D( gm_BaseTexture, (px + vec2( 1.0, 2.0) * pointDir) / size);
vec4 col = c;
//c_orner, b_ack, and u_p slices
// (slices from neighbor pixels will only ever reach these 3 quadrants
vec4 c_col = sliceDist(local, vec2( 1.0, 1.0), pointDir, u, uf, uff, b, c, f, ff, db, d, df, dff, ddb, dd, ddf);
vec4 b_col = sliceDist(local, vec2(-1.0, 1.0), pointDir, u, ub, ubb, f, c, b, bb, df, d, db, dbb, ddf, dd, ddb);
vec4 u_col = sliceDist(local, vec2( 1.0,-1.0), pointDir, d, df, dff, b, c, f, ff, ub, u, uf, uff, uub, uu, uuf);
if(c_col.r >= 0.0){
col = c_col;
}
if(b_col.r >= 0.0){
col = b_col;
}
if(u_col.r >= 0.0){
col = u_col;
}
gl_FragColor = col;
}

View file

@ -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;
}

View file

@ -0,0 +1,10 @@
{
"resourceType": "GMShader",
"resourceVersion": "1.0",
"name": "sh_clean_shape",
"type": 1,
"parent": {
"name": "filter",
"path": "folders/shader/filter.yy",
},
}