From fa00d1e2b2314ded1e9893c770c392499c513641 Mon Sep 17 00:00:00 2001 From: Tanasart <22589759+Ttanasart-pt@users.noreply.github.com> Date: Tue, 8 Aug 2023 11:42:01 +0200 Subject: [PATCH] gmedit migration --- #backups/scripts/globals/globals.gml.backup0 | 246 +++ #backups/scripts/globals/globals.gml.backup1 | 246 +++ .../scripts/node_data/node_data.gml.backup0 | 1543 +++++++++++++++++ .../scripts/node_data/node_data.gml.backup1 | 1543 +++++++++++++++++ .../scripts/pxl_server/pxl_server.gml.backup0 | 200 +++ .../scripts/pxl_server/pxl_server.gml.backup1 | 200 +++ .../string_eval/string_eval.gml.backup0 | 841 +++++++++ .../string_eval/string_eval.gml.backup1 | 841 +++++++++ .../sh_blend_normal.fsh.backup0 | 41 + PixelComposer.resource_order | 35 +- scripts/globals/globals.gml | 21 +- scripts/node_data/node_data.gml | 5 +- scripts/pxl_server/pxl_server.gml | 17 +- scripts/string_eval/string_eval.gml | 32 +- 14 files changed, 5756 insertions(+), 55 deletions(-) create mode 100644 #backups/scripts/globals/globals.gml.backup0 create mode 100644 #backups/scripts/globals/globals.gml.backup1 create mode 100644 #backups/scripts/node_data/node_data.gml.backup0 create mode 100644 #backups/scripts/node_data/node_data.gml.backup1 create mode 100644 #backups/scripts/pxl_server/pxl_server.gml.backup0 create mode 100644 #backups/scripts/pxl_server/pxl_server.gml.backup1 create mode 100644 #backups/scripts/string_eval/string_eval.gml.backup0 create mode 100644 #backups/scripts/string_eval/string_eval.gml.backup1 create mode 100644 #backups/shaders/sh_blend_normal/sh_blend_normal.fsh.backup0 diff --git a/#backups/scripts/globals/globals.gml.backup0 b/#backups/scripts/globals/globals.gml.backup0 new file mode 100644 index 000000000..f86f7c868 --- /dev/null +++ b/#backups/scripts/globals/globals.gml.backup0 @@ -0,0 +1,246 @@ +// 2023-08-07 09:56:48 +#region save + globalvar LOADING, APPENDING, CLONING, SAFE_MODE; + globalvar CONNECTION_CONFLICT, ALWAYS_FULL; + + LOADING = false; + CLONING = false; + APPENDING = false; + SAFE_MODE = false; + + CONNECTION_CONFLICT = ds_queue_create(); + + randomize(); + ALWAYS_FULL = false; +#endregion + +#region project + function Project() constructor { + active = true; /// @is {bool} + + path = ""; /// @is {string} + version = SAVE_VERSION; /// @is {number} + seed = irandom_range(100000, 999999); /// @is {number} + + modified = false; /// @is {bool} + readonly = false; /// @is {bool} + + nodes = ds_list_create(); + nodeMap = ds_map_create(); + nodeNameMap = ds_map_create(); + + animator = new AnimationManager(); + + globalNode = new Node_Global(); + + previewGrid = { + show : false, + snap : false, + width : 16, + height : 16, + opacity : 0.5, + color : COLORS.panel_preview_grid, + } + + graphGrid = { + show : true, + snap : true, + size : 32, + opacity : 0.05, + color : c_white, + } + + addons = {}; + + onion_skin = { + enabled: false, + range: [ -1, 1 ], + step: 1, + color: [ c_red, c_blue ], + alpha: 0.5, + on_top: true, + }; + + attributes = { + surface_dimension: [ 32, 32 ], + palette: [ c_black, c_white ] + } + + attributeEditor = [ + [ "Default Surface", "surface_dimension", new vectorBox(2, function(ind, val) { attributes.surface_dimension[ind] = val; }) ], + [ "Palette", "palette", new buttonPalette(function(pal) { attributes.palette = pal; }) ], + ] + + static cleanup = function() { + if(!ds_map_empty(nodeMap)) + array_map(ds_map_keys_to_array(nodeMap), function(_key, _ind) { nodeMap[? _key].active = false; }); + + ds_list_destroy(nodes); + ds_map_destroy(nodeMap); + ds_map_destroy(nodeNameMap); + } + } + + globalvar PROJECTS; /// @is {Project[]} + globalvar PROJECT; /// @is {Project} + + gml_pragma("global", "__init()"); + function __init() { + PROJECT = new Project(); + PROJECTS = [ PROJECT ]; + } +#endregion + +#region main + globalvar OS, DEBUG, THEME, COLOR_KEYS; + OS = os_type; + //OS = os_macosx; + + DEBUG = false; + THEME = new Theme(); + COLOR_KEYS = []; + + globalvar VERSION, SAVE_VERSION, VERSION_STRING, BUILD_NUMBER; + + VERSION = 11484; + SAVE_VERSION = 11482; + VERSION_STRING = "1.15rc4"; + BUILD_NUMBER = 11484; + + globalvar APPEND_MAP; + APPEND_MAP = ds_map_create(); + + globalvar HOTKEYS, HOTKEY_CONTEXT; + HOTKEYS = ds_map_create(); + HOTKEY_CONTEXT = ds_list_create(); + HOTKEY_CONTEXT[| 0] = ""; + + globalvar CURSOR, TOOLTIP, DRAGGING, DIALOG_DEPTH_HOVER; + globalvar UPDATE, RENDER_QUEUE; +#endregion + +#region inputs + globalvar FOCUS, FOCUS_STR, HOVER, HOVERING_ELEMENT, _HOVERING_ELEMENT; + globalvar DOUBLE_CLICK, DOUBLE_CLICK_POS; + globalvar DIALOG_CLICK; + + DOUBLE_CLICK_POS = [ 0, 0 ]; + DOUBLE_CLICK = false; + FOCUS = noone; + FOCUS_STR = ""; + HOVER = noone; + HOVERING_ELEMENT = noone; + _HOVERING_ELEMENT = noone; + DIALOG_CLICK = true; + + globalvar ADD_NODE_PAGE; + ADD_NODE_PAGE = 0; +#endregion + +#region macro + #macro WIN_W window_get_width() + #macro WIN_H window_get_height() + + #macro WIN_SW window_get_width() + #macro WIN_SH window_get_height() + + #macro UI_SCALE PREF_MAP[? "display_scaling"] + + #macro mouse_mx device_mouse_x_to_gui(0) + #macro mouse_my device_mouse_y_to_gui(0) + #macro mouse_raw_x (device_mouse_raw_x(0) + window_get_x()) + #macro mouse_raw_y (device_mouse_raw_y(0) + window_get_y()) + #macro mouse_ui [device_mouse_x_to_gui(0), device_mouse_y_to_gui(0)] + + #macro sFOCUS FOCUS == self.id + #macro sHOVER HOVER == self.id + + #macro DELTA_TIME delta_time / 1_000_000 + + #macro CONF_TESTING false + globalvar TESTING, TEST_ERROR; + TESTING = CONF_TESTING; + TEST_ERROR = false; + + #macro DEMO false + #macro ItchDemo:DEMO true + #macro SteamDemo:DEMO true + #macro MacAlpha:DEMO true + + #macro ALPHA false + #macro MacAlpha:ALPHA true + + #region color + #macro c_ui_blue_dkblack $251919 + #macro c_ui_blue_mdblack $2c1e1e + #macro c_ui_blue_black $362727 + #macro c_ui_blue_dkgrey $4e3b3b + #macro c_ui_blue_grey $816d6d + #macro c_ui_blue_ltgrey $8f7e7e + #macro c_ui_blue_white $e8d6d6 + #macro c_ui_cyan $e9ff88 + + #macro c_ui_yellow $78e4ff + #macro c_ui_orange $6691ff + #macro c_ui_orange_light $92c2ff + + #macro c_ui_red $4b00eb + #macro c_ui_pink $b700eb + #macro c_ui_purple $d40092 + + #macro c_ui_lime_dark $38995e + #macro c_ui_lime $5dde8f + #macro c_ui_lime_light $b2ffd0 + + #macro c_ui_white $ffffff + #endregion + + #macro printlog if(log) show_debug_message + + #macro RETURN_ON_REST if(!PROJECT.animator.is_playing || !PROJECT.animator.frame_progress) return; + + #macro PANEL_PAD THEME_VALUE.panel_padding + + function print(str) { + //show_debug_message(string(str)); + noti_status(string(str)); + } + + function printIf(cond, log) { + if(!cond) return; + show_debug_message(log); + } +#endregion + +#region presets + function INIT_FOLDERS() { + if(!directory_exists(DIRECTORY + "Palettes")) + directory_create(DIRECTORY + "Palettes"); + if(!directory_exists(DIRECTORY + "Gradients")) + directory_create(DIRECTORY + "Gradients"); + } +#endregion + +#region default + globalvar DEF_SURFACE, USE_DEF; + DEF_SURFACE = noone; + USE_DEF = -10; + + function DEF_SURFACE_RESET() { + if(is_surface(DEF_SURFACE)) return; + + DEF_SURFACE = surface_create_valid(32, 32); + surface_set_target(DEF_SURFACE); + draw_clear(c_white); + surface_reset_target(); + } + DEF_SURFACE_RESET(); +#endregion + +#region PATCH + #macro PATCH_STATIC static _doUpdate = function() { doUpdate() }; +#endregion + +#region debug + global.FLAG = {}; +#endregion \ No newline at end of file diff --git a/#backups/scripts/globals/globals.gml.backup1 b/#backups/scripts/globals/globals.gml.backup1 new file mode 100644 index 000000000..00dc65d8c --- /dev/null +++ b/#backups/scripts/globals/globals.gml.backup1 @@ -0,0 +1,246 @@ +// 2023-08-07 09:55:37 +#region save + globalvar LOADING, APPENDING, CLONING, SAFE_MODE; + globalvar CONNECTION_CONFLICT, ALWAYS_FULL; + + LOADING = false; + CLONING = false; + APPENDING = false; + SAFE_MODE = false; + + CONNECTION_CONFLICT = ds_queue_create(); + + randomize(); + ALWAYS_FULL = false; +#endregion + +#region project + function Project() constructor { + active = true; /// @is {bool} + + path = ""; /// @is {string} + version = SAVE_VERSION; /// @is {number} + seed = irandom_range(100000, 999999); /// @is {number} + + modified = false; /// @is {bool} + readonly = false; /// @is {bool} + + nodes = ds_list_create(); + nodeMap = ds_map_create(); + nodeNameMap = ds_map_create(); + + animator = new AnimationManager(); + + globalNode = new Node_Global(); + + previewGrid = { + show : false, + snap : false, + width : 16, + height : 16, + opacity : 0.5, + color : COLORS.panel_preview_grid, + } + + graphGrid = { + show : true, + snap : true, + size : 32, + opacity : 0.05, + color : c_white, + } + + addons = {}; + + onion_skin = { + enabled: false, + range: [ -1, 1 ], + step: 1, + color: [ c_red, c_blue ], + alpha: 0.5, + on_top: true, + }; + + attributes = { + surface_dimension: [ 32, 32 ], + palette: [ c_black, c_white ] + } + + attributeEditor = [ + [ "Default Surface", "surface_dimension", new vectorBox(2, function(ind, val) { attributes.surface_dimension[ind] = val; }) ], + [ "Palette", "palette", new buttonPalette(function(pal) { attributes.palette = pal; }) ], + ] + + static cleanup = function() { + if(!ds_map_empty(nodeMap)) + array_map(ds_map_keys_to_array(nodeMap), function(_key, _ind) { nodeMap[? _key].active = false; }); + + ds_list_destroy(nodes); + ds_map_destroy(nodeMap); + ds_map_destroy(nodeNameMap); + } + } + + globalvar PROJECTS; /// @is {Project[]} + globalvar PROJECT; /// @is {Project} + + gml_pragma("global", "__init()"); + function __init() { + PROJECT = new Project(); + PROJECTS = [ PROJECT ]; + } +#endregion + +#region main + globalvar OS, DEBUG, THEME, COLOR_KEYS; + OS = os_type; + //OS = os_macosx; + + DEBUG = false; + THEME = new Theme(); + COLOR_KEYS = []; + + globalvar VERSION, SAVE_VERSION, VERSION_STRING, BUILD_NUMBER; + + VERSION = 11484; + SAVE_VERSION = 11482; + VERSION_STRING = "1.15rc4"; + BUILD_NUMBER = 11484; + + globalvar APPEND_MAP; + APPEND_MAP = ds_map_create(); + + globalvar HOTKEYS, HOTKEY_CONTEXT; + HOTKEYS = ds_map_create(); + HOTKEY_CONTEXT = ds_list_create(); + HOTKEY_CONTEXT[| 0] = ""; + + globalvar CURSOR, TOOLTIP, DRAGGING, DIALOG_DEPTH_HOVER; + globalvar UPDATE, RENDER_QUEUE; +#endregion + +#region inputs + globalvar FOCUS, FOCUS_STR, HOVER, HOVERING_ELEMENT, _HOVERING_ELEMENT; + globalvar DOUBLE_CLICK, DOUBLE_CLICK_POS; + globalvar DIALOG_CLICK; + + DOUBLE_CLICK_POS = [ 0, 0 ]; + DOUBLE_CLICK = false; + FOCUS = noone; + FOCUS_STR = ""; + HOVER = noone; + HOVERING_ELEMENT = noone; + _HOVERING_ELEMENT = noone; + DIALOG_CLICK = true; + + globalvar ADD_NODE_PAGE; + ADD_NODE_PAGE = 0; +#endregion + +#region macro + #macro WIN_W window_get_width() + #macro WIN_H window_get_height() + + #macro WIN_SW window_get_width() + #macro WIN_SH window_get_height() + + #macro UI_SCALE PREF_MAP[? "display_scaling"] + + #macro mouse_mx device_mouse_x_to_gui(0) + #macro mouse_my device_mouse_y_to_gui(0) + #macro mouse_raw_x (device_mouse_raw_x(0) + window_get_x()) + #macro mouse_raw_y (device_mouse_raw_y(0) + window_get_y()) + #macro mouse_ui [device_mouse_x_to_gui(0), device_mouse_y_to_gui(0)] + + #macro sFOCUS FOCUS == self.id + #macro sHOVER HOVER == self.id + + #macro DELTA_TIME delta_time / 1_000_000 + + #macro CONF_TESTING false + globalvar TESTING, TEST_ERROR; + TESTING = CONF_TESTING; + TEST_ERROR = false; + + #macro DEMO false + #macro ItchDemo:DEMO true + #macro SteamDemo:DEMO true + #macro MacAlpha:DEMO true + + #macro ALPHA false + #macro MacAlpha:ALPHA true + + #region color + #macro c_ui_blue_dkblack $251919 + #macro c_ui_blue_mdblack $2c1e1e + #macro c_ui_blue_black $362727 + #macro c_ui_blue_dkgrey $4e3b3b + #macro c_ui_blue_grey $816d6d + #macro c_ui_blue_ltgrey $8f7e7e + #macro c_ui_blue_white $e8d6d6 + #macro c_ui_cyan $e9ff88 + + #macro c_ui_yellow $78e4ff + #macro c_ui_orange $6691ff + #macro c_ui_orange_light $92c2ff + + #macro c_ui_red $4b00eb + #macro c_ui_pink $b700eb + #macro c_ui_purple $d40092 + + #macro c_ui_lime_dark $38995e + #macro c_ui_lime $5dde8f + #macro c_ui_lime_light $b2ffd0 + + #macro c_ui_white $ffffff + #endregion + + #macro printlog if(log) show_debug_message + + #macro RETURN_ON_REST if(!PROJECT.animator.is_playing || !PROJECT.animator.frame_progress) return; + + #macro PANEL_PAD THEME_VALUE.panel_padding + + function print(str) { + //show_debug_message(string(str)); + noti_status(string(str)); + } + + function printIf(cond, log) { + if(!cond) return; + show_debug_message(log); + } +#endregion + +#region presets + function INIT_FOLDERS() { + if(!directory_exists(DIRECTORY + "Palettes")) + directory_create(DIRECTORY + "Palettes"); + if(!directory_exists(DIRECTORY + "Gradients")) + directory_create(DIRECTORY + "Gradients"); + } +#endregion + +#region default + globalvar DEF_SURFACE, USE_DEF; + DEF_SURFACE = noone; + USE_DEF = -10; + + function DEF_SURFACE_RESET() { + if(is_surface(DEF_SURFACE)) return; + + DEF_SURFACE = surface_create_valid(32, 32); + surface_set_target(DEF_SURFACE); + draw_clear(c_white); + surface_reset_target(); + } + DEF_SURFACE_RESET(); +#endregion + +#region PATCH + #macro PATCH_STATIC static _doUpdate = function() { doUpdate() }; +#endregion + +#region debug + global.FLAG = {}; +#endregion \ No newline at end of file diff --git a/#backups/scripts/node_data/node_data.gml.backup0 b/#backups/scripts/node_data/node_data.gml.backup0 new file mode 100644 index 000000000..20ddc0372 --- /dev/null +++ b/#backups/scripts/node_data/node_data.gml.backup0 @@ -0,0 +1,1543 @@ +// 2023-08-08 10:31:45 +global.loop_nodes = [ "Node_Iterate", "Node_Iterate_Each" ]; + +function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) : __Node_Base(_x, _y) constructor { + active = true; + renderActive = true; + + node_id = UUID_generate(); + + group = _group; + destroy_when_upgroup = false; + ds_list_add(PANEL_GRAPH.getNodeList(_group), self); + + active_index = -1; + active_range = [ 0, PROJECT.animator.frames_total - 1 ]; + + color = c_white; + icon = noone; + bg_spr = THEME.node_bg; + bg_sel_spr = THEME.node_active; + anim_priority = ds_map_size(PROJECT.nodeMap); + + static resetInternalName = function() { + var str = string_replace_all(name, " ", "_"); + str = string_replace_all(str, "/", ""); + str = string_replace_all(str, "-", ""); + + internalName = str + string(irandom_range(10000, 99999)); + PROJECT.nodeNameMap[? internalName] = self; + } + + if(!LOADING && !APPENDING) { + recordAction(ACTION_TYPE.node_added, self); + PROJECT.nodeMap[? node_id] = self; + PROJECT.modified = true; + + //print($"Adding node {node_id} to {PROJECT.path} [{ds_map_size(PROJECT.nodeMap)}]"); + + run_in(1, function() { + if(display_name != "") return; + resetInternalName(); + display_name = name; //__txt_node_name(instanceof(self), name); + }); + } + + name = ""; + display_name = ""; + internalName = ""; + + tooltip = ""; + x = _x; + y = _y; + + w = 128; + h = 128; + min_h = 0; + draw_padding = 8; + auto_height = true; + + draw_name = true; + draggable = true; + + inputs = ds_list_create(); + outputs = ds_list_create(); + inputMap = ds_map_create(); + outputMap = ds_map_create(); + + input_display_list = -1; + output_display_list = -1; + inspector_display_list = -1; + is_dynamic_output = false; + + attributes = {}; + attributeEditors = []; + + inspectInput1 = nodeValue("Toggle execution", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + inspectInput2 = nodeValue("Toggle execution", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + + updateAction = nodeValue("Update", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + + show_input_name = false; + show_output_name = false; + + inspecting = false; + previewing = 0; + + preview_surface = noone; + preview_amount = 0; + previewable = true; + preview_speed = 0; + preview_index = 0; + preview_channel = 0; + preview_alpha = 1; + preview_x = 0; + preview_y = 0; + + preview_surface_prev = noone; + preview_trans = 1; + preview_drop_x = 0; + preview_drop_y = 0; + + preview_mx = 0; + preview_my = 0; + + rendered = false; + update_on_frame = false; + render_time = 0; + auto_render_time = true; + updated = false; + + use_cache = false; + clearCacheOnChange = true; + cached_output = []; + cache_result = []; + temp_surface = []; + + tools = -1; + + on_dragdrop_file = -1; + + anim_show = true; + dopesheet_color = COLORS.panel_animation_dope_blend_default; + dopesheet_y = 0; + + value_validation = array_create(3); + + error_noti_update = noone; + error_update_enabled = false; + manual_updated = false; + manual_deletable = true; + + isTool = false; + tool_settings = []; + tool_attribute = {}; + + is_dynamic_input = false; + input_display_len = 0; + input_fix_len = 0; + data_length = 1; + + static createNewInput = noone; + + static initTooltip = function() { + var type_self:string = instanceof(self); + if(!struct_has(global.NODE_GUIDE, type_self)) return; + + var _n = global.NODE_GUIDE[$ type_self]; + var _ins = _n.inputs; + var _ots = _n.outputs; + + var amo = min(ds_list_size(inputs), array_length(_ins)); + for( var i = 0; i < amo; i++ ) { + inputs[| i].name = _ins[i].name; + inputs[| i].tooltip = _ins[i].tooltip; + } + + var amo = min(ds_list_size(outputs), array_length(_ots)); + for( var i = 0; i < amo; i++ ) { + outputs[| i].name = _ots[i].name; + outputs[| i].tooltip = _ots[i].tooltip; + } + } + run_in(1, initTooltip); + + static resetDefault = function() { + var folder = instanceof(self); + if(!ds_map_exists(global.PRESETS_MAP, folder)) return; + + var pres = global.PRESETS_MAP[? folder]; + for( var i = 0, n = array_length(pres); i < n; i++ ) { + var preset = pres[i]; + if(preset.name != "_default") continue; + + deserialize(preset.content, true, true); + applyDeserialize(true); + } + + doUpdate(); + } + if(!APPENDING && !LOADING) + run_in(1, method(self, resetDefault)); + + static getInputJunctionIndex = function(index) { + if(input_display_list == -1) + return index; + + var jun_list_arr = input_display_list[index]; + if(is_array(jun_list_arr)) return noone; + if(is_struct(jun_list_arr)) return noone; + return jun_list_arr; + } + + static getOutputJunctionIndex = function(index) { + if(output_display_list == -1) + return index; + return output_display_list[index]; + } + + static setHeight = function() { + var _hi = ui(32); + var _ho = ui(32); + + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(inputs[| i].isVisible()) _hi += 24; + } + + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(outputs[| i].isVisible()) _ho += 24; + } + + h = max(min_h, (preview_surface && previewable)? 128 : 0, _hi, _ho); + } + + onSetDisplayName = noone; + static setDisplayName = function(_name) { + display_name = _name; + internalName = string_replace_all(display_name, " ", "_"); + refreshNodeMap(); + + if(onSetDisplayName != noone) + onSetDisplayName(); + } + + static setIsDynamicInput = function(_data_length = 1) { + is_dynamic_input = true; + input_display_len = input_display_list == -1? 0 : array_length(input_display_list); + input_fix_len = ds_list_size(inputs); + data_length = _data_length; + } + + static getOutput = function(junc = noone) { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(!outputs[| i].visible) continue; + if(junc != noone && !junc.isConnectable(outputs[| i], true)) continue; + + return outputs[| i]; + } + return noone; + } + + static getInput = function(junc = noone) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(!inputs[| i].visible) continue; + if(inputs[| i].value_from != noone) continue; + if(junc != noone && !inputs[| i].isConnectable(junc, true)) continue; + + return inputs[| i]; + } + return noone; + } + + static getFullName = function() { + return display_name == ""? name : "[" + name + "] " + display_name; + } + + static addInput = function(junctionFrom) { + var targ = getInput(junctionFrom); + if(targ == noone) return; + + targ.setFrom(junctionFrom); + } + + static isAnimated = function() { + for(var i = 0; i < ds_list_size(inputs); i++) { + if(inputs[| i].isAnimated()) + return true; + } + return false; + } + + static isInLoop = function() { + return array_exists(global.loop_nodes, instanceof(group)); + } + + static move = function(_x, _y) { + if(x == _x && y == _y) return; + + x = _x; + y = _y; + if(!LOADING) PROJECT.modified = true; + } + + insp1UpdateTooltip = __txtx("panel_inspector_execute", "Execute node"); + insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + static inspector1Update = function() { + if(error_update_enabled && error_noti_update != noone) + noti_remove(error_noti_update); + error_noti_update = noone; + + onInspector1Update(); + } + static onInspector1Update = noone; + static hasInspector1Update = function() { return onInspector1Update != noone; } + + insp2UpdateTooltip = __txtx("panel_inspector_execute", "Execute node"); + insp2UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + static inspector2Update = function() { onInspector2Update(); } + static onInspector2Update = noone; + static hasInspector2Update = function() { return onInspector2Update != noone; } + + static stepBegin = function() { + if(use_cache) cacheArrayCheck(); + var willUpdate = false; + + if(PROJECT.animator.frame_progress) { + if(update_on_frame) willUpdate = true; + if(isAnimated()) willUpdate = true; + + if(willUpdate) { + setRenderStatus(false); + UPDATE |= RENDER_TYPE.partial; + } + } + + if(auto_height) + setHeight(); + + doStepBegin(); + + if(hasInspector1Update()) inspectInput1.name = insp1UpdateTooltip; + if(hasInspector2Update()) inspectInput2.name = insp2UpdateTooltip; + } + static doStepBegin = function() {} + + static triggerCheck = function() { + _triggerCheck(); + } + + static _triggerCheck = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(inputs[| i].type != VALUE_TYPE.trigger) continue; + if(!is_instanceof(inputs[| i].editWidget, buttonClass)) continue; + + var trig = inputs[| i].getValue(); + if(trig) { + inputs[| i].editWidget.onClick(); + inputs[| i].setValue(false); + } + } + + if(hasInspector1Update()) { + var trig = inspectInput1.getValue(); + if(trig) { + inspectInput1.editWidget.onClick(); + inspectInput1.setValue(false); + } + } + + if(hasInspector2Update()) { + var trig = inspectInput2.getValue(); + if(trig) { + inspectInput2.editWidget.onClick(); + inspectInput2.setValue(false); + } + } + } + + static step = function() {} + static focusStep = function() {} + static inspectorStep = function() {} + + static doUpdate = function() { + if(SAFE_MODE) return; + if(NODE_EXTRACT) return; + + var sBase = surface_get_target(); + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $">>>>>>>>>> DoUpdate called from {internalName} <<<<<<<<<<"); + + try { + var t = get_timer(); + + if(!is_instanceof(self, Node_Collection)) + setRenderStatus(true); + + update(); ///UPDATE + + if(!is_instanceof(self, Node_Collection)) + render_time = get_timer() - t; + } catch(exception) { + var sCurr = surface_get_target(); + while(surface_get_target() != sBase) + surface_reset_target(); + + log_warning("RENDER", exception_print(exception), self); + } + + if(!use_cache && PROJECT.onion_skin) { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(outputs[| i].type != VALUE_TYPE.surface) continue; + cacheCurrentFrame(outputs[| i].getValue()); + break; + } + } + + if(hasInspector1Update()) { + var trigger = inspectInput1.getValue(); + if(trigger) onInspector1Update(); + } + + if(hasInspector2Update()) { + var trigger = inspectInput2.getValue(); + if(trigger) onInspector2Update(); + } + LOG_BLOCK_END(); + } + + static valueUpdate = function(index) { + if(error_update_enabled && error_noti_update == noone) + error_noti_update = noti_error(getFullName() + " node require manual execution.",, self); + + onValueUpdate(index); + } + + static onValueUpdate = function(index = 0) {} + static onValueFromUpdate = function(index) {} + + static triggerRender = function() { + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $"Trigger render for {internalName}"); + + setRenderStatus(false); + UPDATE |= RENDER_TYPE.partial; + + if(is_instanceof(group, Node_Collection) && group.reset_all_child) { + group.resetRender(); + } else { + resetRender(); + + var nodes = getNextNodesRaw(); + for(var i = 0; i < array_length(nodes); i++) + nodes[i].triggerRender(); + } + + LOG_BLOCK_END(); + } + + static resetRender = function() { setRenderStatus(false); } + static isRenderActive = function() { return renderActive || (PREF_MAP[? "render_all_export"] && PROJECT.animator.rendering); } + + static isRenderable = function(log = false) { //Check if every input is ready (updated) + if(!active) return false; + if(!isRenderActive()) return false; + + //if(group && struct_has(group, "iterationStatus") && group.iterationStatus() == ITERATION_STATUS.complete) return false; + + for(var j = 0; j < ds_list_size(inputs); j++) { + var _in = inputs[| j]; + if( _in.type == VALUE_TYPE.node) continue; + + var val_from = _in.value_from; + if( val_from == noone) continue; + if(!val_from.node.active) continue; + if(!val_from.node.isRenderActive()) continue; + if!(val_from.node.rendered || val_from.node.update_on_frame) { + LOG_LINE_IF(global.FLAG.render, $"Node {internalName} is not renderable because input {val_from.node.internalName} is not rendered ({val_from.node.rendered})"); + return false; + } + } + + return true; + } + + static getNextNodesRaw = function() { return getNextNodes(); } + + static getNextNodes = function() { + var nodes = []; + var nodeNames = []; + + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $"→→→→→ Call get next node from: {internalName}"); + LOG_BLOCK_START(); + + for(var i = 0; i < ds_list_size(outputs); i++) { + var _ot = outputs[| i]; + if(!_ot.forward) continue; + + var _tos = _ot.getJunctionTo(); + + for( var j = 0; j < array_length(_tos); j++ ) { + var _to = _tos[j]; + + array_push(nodes, _to.node); + array_push(nodeNames, _to.node.internalName); + + //LOG_IF(global.FLAG.render, $"→→ Check output: {_ot.name} connect to node {_to.node.internalName}"); + } + } + + LOG_IF(global.FLAG.render, $"→→ Push {nodeNames} to stack."); + + LOG_BLOCK_END(); + LOG_BLOCK_END(); + return nodes; + } + + static isTerminal = function() { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + var _to = outputs[| i].getJunctionTo(); + if(array_length(_to)) return false; + } + + return true; + } + + static onInspect = function() {} + + static setRenderStatus = function(result) { + LOG_LINE_IF(global.FLAG.render, $"Set render status for {internalName} : {result}"); + + rendered = result; + } + + static pointIn = function(_x, _y, _mx, _my, _s) { + var xx = x * _s + _x; + var yy = y * _s + _y; + + return point_in_rectangle(_mx, _my, xx, yy, xx + w * _s, yy + h * _s); + } + + draw_graph_culled = false; + static cullCheck = function(_x, _y, _s, minx, miny, maxx, maxy) { + var x0 = x * _s + _x; + var y0 = y * _s + _y; + var x1 = (x + w) * _s + _x; + var y1 = (y + h) * _s + _y; + + draw_graph_culled = !rectangle_in_rectangle(minx, miny, maxx, maxy, x0, y0, x1, y1); + } + + static preDraw = function(_x, _y, _s) { + var xx = x * _s + _x; + var yy = y * _s + _y; + var jun; + + var inspCount = hasInspector1Update() + hasInspector2Update(); + var ind = 1; + if(hasInspector1Update()) { + inspectInput1.x = xx + w * _s * ind / (inspCount + 1); + inspectInput1.y = yy; + ind++; + } + + if(hasInspector2Update()) { + inspectInput2.x = xx + w * _s * ind / (inspCount + 1); + inspectInput2.y = yy; + ind++; + } + + var inamo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var _in = yy + ui(32) * _s; + + for(var i = 0; i < inamo; i++) { + var idx = getInputJunctionIndex(i); + if(idx == noone) continue; + + jun = ds_list_get(inputs, idx, noone); + if(jun == noone || is_undefined(jun)) continue; + jun.x = xx; + jun.y = _in; + _in += 24 * _s * jun.isVisible(); + } + + var outamo = output_display_list == -1? ds_list_size(outputs) : array_length(output_display_list); + + xx = xx + w * _s; + _in = yy + ui(32) * _s; + for(var i = 0; i < outamo; i++) { + var idx = getOutputJunctionIndex(i); + jun = outputs[| idx]; + + jun.x = xx; + jun.y = _in; + _in += 24 * _s * jun.isVisible(); + } + } + + static drawNodeBase = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + var aa = 0.25 + 0.5 * renderActive; + draw_sprite_stretched_ext(bg_spr, 0, xx, yy, w * _s, h * _s, color, aa); + } + + static drawGetBbox = function(xx, yy, _s) { + var x0 = xx + draw_padding * _s; + var x1 = xx + (w - draw_padding) * _s; + var y0 = yy + 20 * draw_name + draw_padding * _s; + var y1 = yy + (h - draw_padding) * _s; + + return BBOX().fromPoints(x0, y0, x1, y1); + } + + static drawNodeName = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + + draw_name = false; + var _name = display_name == ""? name : display_name; + if(_name == "") return; + if(_s < 0.75) return; + draw_name = true; + + var aa = 0.25 + 0.5 * renderActive; + draw_sprite_stretched_ext(THEME.node_bg_name, 0, xx, yy, w * _s, ui(20), color, aa); + + var cc = COLORS._main_text; + if(PREF_MAP[? "node_show_render_status"] && !rendered) + cc = isRenderable()? COLORS._main_value_positive : COLORS._main_value_negative; + + draw_set_text(f_p1, fa_left, fa_center, cc); + + if(hasInspector1Update()) icon = THEME.refresh_s; + var ts = clamp(power(_s, 0.5), 0.5, 1); + + var aa = 0.5 + 0.5 * renderActive; + draw_set_alpha(aa); + + if(icon && _s > 0.75) { + draw_sprite_ui_uniform(icon, 0, xx + ui(12), yy + ui(10),,, aa); + draw_text_cut(xx + ui(24), yy + ui(10), _name, w * _s - ui(24), ts); + } else + draw_text_cut(xx + ui(8), yy + ui(10), _name, w * _s - ui(8), ts); + + draw_set_alpha(1); + } + + static drawJunctions = function(_x, _y, _mx, _my, _s) { + if(!active) return; + var hover = noone; + var amo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var jun; + + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + jun = ds_list_get(inputs, ind, noone); + if(jun == noone || is_undefined(jun)) continue; + + if(jun.drawJunction(_s, _mx, _my)) + hover = jun; + } + + for(var i = 0; i < ds_list_size(outputs); i++) { + jun = outputs[| i]; + + if(jun.drawJunction(_s, _mx, _my)) + hover = jun; + } + + if(hasInspector1Update() && inspectInput1.drawJunction(_s, _mx, _my)) + hover = inspectInput1; + + if(hasInspector2Update() && inspectInput2.drawJunction(_s, _mx, _my)) + hover = inspectInput2; + + return hover; + } + + static drawJunctionNames = function(_x, _y, _mx, _my, _s) { + if(draw_graph_culled) return; + if(!active) return; + var amo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var jun; + + var xx = x * _s + _x; + var yy = y * _s + _y; + + show_input_name = PANEL_GRAPH.pHOVER && point_in_rectangle(_mx, _my, xx - 8 * _s, yy + 20 * _s, xx + 8 * _s, yy + h * _s); + show_output_name = PANEL_GRAPH.pHOVER && point_in_rectangle(_mx, _my, xx + (w - 8) * _s, yy + 20 * _s, xx + (w + 8) * _s, yy + h * _s); + + if(show_input_name) { + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + if(!inputs[| ind]) continue; + + inputs[| ind].drawNameBG(_s); + } + + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + if(!inputs[| ind]) continue; + + inputs[| ind].drawName(_s, _mx, _my); + } + } + + if(show_output_name) { + for(var i = 0; i < ds_list_size(outputs); i++) + outputs[| i].drawNameBG(_s); + + for(var i = 0; i < ds_list_size(outputs); i++) + outputs[| i].drawName(_s, _mx, _my); + } + + if(hasInspector1Update() && PANEL_GRAPH.pHOVER && point_in_circle(_mx, _my, inspectInput1.x, inspectInput1.y, 10)) { + inspectInput1.drawNameBG(_s); + inspectInput1.drawName(_s, _mx, _my); + } + + if(hasInspector2Update() && PANEL_GRAPH.pHOVER && point_in_circle(_mx, _my, inspectInput2.x, inspectInput2.y, 10)) { + inspectInput2.drawNameBG(_s); + inspectInput2.drawName(_s, _mx, _my); + } + } + + static drawConnections = function(_x, _y, _s, mx, my, _active, aa = 1, minx = undefined, miny = undefined, maxx = undefined, maxy = undefined) { + if(!active) return; + + var hovering = noone; + var drawLineIndex = 1; + + for(var i = 0; i < ds_list_size(outputs); i++) { + var jun = outputs[| i]; + var connected = false; + + for( var j = 0; j < ds_list_size(jun.value_to); j++ ) { + if(jun.value_to[| j].value_from == jun) + connected = true; + } + + if(connected) { + jun.drawLineIndex = drawLineIndex; + drawLineIndex += 0.5; + } + } + + var st = 0; + if(hasInspector1Update()) st = -1; + if(hasInspector2Update()) st = -2; + + var _inputs = []; + var drawLineIndex = 1; + for(var i = st; i < ds_list_size(inputs); i++) { + var jun; + if(i == -1) jun = inspectInput1; + else if(i == -2) jun = inspectInput2; + else jun = inputs[| i]; + + if(jun.value_from == noone) continue; + if(!jun.value_from.node.active) continue; + if(!jun.isVisible()) continue; + + if(i >= 0) + array_push(_inputs, jun); + } + + var len = array_length(_inputs); + for( var i = 0; i < len; i++ ) + _inputs[i].drawLineIndex = 1 + (i > len / 2? (len - 1 - i) : i) * 0.5; + + for(var i = st; i < ds_list_size(inputs); i++) { + var jun; + if(i == -1) jun = inspectInput1; + else if(i == -2) jun = inspectInput2; + else jun = inputs[| i]; + + var hov = jun.drawConnections(_x, _y, _s, mx, my, _active, aa, minx, miny, maxx, maxy); + if(hov) hovering = hov; + } + + return hovering; + } + + static drawPreview = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + + var _node = outputs[| preview_channel]; + if(_node.type != VALUE_TYPE.surface) return; + + var surf = _node.getValue(); + preview_amount = 0; + if(is_array(surf)) { + if(array_length(surf) == 0) return; + preview_amount = array_length(surf); + + if(preview_speed != 0) { + preview_index += preview_speed; + if(preview_index <= 0) + preview_index = array_length(surf) - 1; + } + + if(floor(preview_index) > array_length(surf) - 1) preview_index = 0; + surf = surf[preview_index]; + } + + preview_surface = is_surface(surf)? surf : noone; + if(preview_surface == noone) return; + + var pw = surface_get_width(preview_surface); + var ph = surface_get_height(preview_surface); + var ps = min((w * _s - 8) / pw, (h * _s - 8) / ph); + var px = xx + w * _s / 2 - pw * ps / 2; + var py = yy + h * _s / 2 - ph * ps / 2; + var aa = 0.5 + 0.5 * renderActive; + + if(preview_trans == 1) { + draw_surface_ext_safe(preview_surface, px, py, ps, ps, 0, c_white, aa); + return; + } + + if(preview_trans < 1 && is_surface(preview_surface_prev)) { + preview_trans = lerp_float(preview_trans, 1, 8); + var _pw = surface_get_width(preview_surface_prev); + var _ph = surface_get_height(preview_surface_prev); + var _ps = min((w * _s - 8) / _pw, (h * _s - 8) / _ph); + var _px = xx + w * _s / 2 - _pw * _ps / 2; + var _py = yy + h * _s / 2 - _ph * _ps / 2; + + draw_surface_ext_safe(preview_surface_prev, _px, _py, _ps, _ps, 0, c_white, aa); + + shader_set(sh_trans_node_prev_drop); + shader_set_f("dimension", _pw, _ph); + shader_set_f("position", (preview_drop_x - px) / (_pw * _ps), (preview_drop_y - py) / (_ph * _ps)); + shader_set_f("prog", preview_trans); + draw_surface_ext_safe(preview_surface, px, py, ps, ps, 0, c_white, aa); + shader_reset(); + } else if(is_surface(preview_surface_prev)) + surface_free(preview_surface_prev); + } + + static previewDropAnimation = function() { + preview_surface_prev = surface_clone(preview_surface); + preview_trans = 0; + preview_drop_x = preview_mx; + preview_drop_y = preview_my; + } + + static getNodeDimension = function(showFormat = true) { + if(!is_surface(preview_surface)) { + if(ds_list_size(outputs)) + return "[" + array_shape(outputs[| 0].getValue()) + "]"; + return ""; + } + + var pw = surface_get_width(preview_surface); + var ph = surface_get_height(preview_surface); + var format = surface_get_format(preview_surface); + + var txt = "[" + string(pw) + " x " + string(ph) + " "; + if(preview_amount) txt = string(preview_amount) + " x " + txt; + + switch(format) { + case surface_rgba4unorm : txt += showFormat? "4RGBA" : "4R"; break; + case surface_rgba8unorm : txt += showFormat? "8RGBA" : "8R"; break; + case surface_rgba16float : txt += showFormat? "16RGBA" : "16R"; break; + case surface_rgba32float : txt += showFormat? "32RGBA" : "32R"; break; + case surface_r8unorm : txt += showFormat? "8BW" : "8B"; break; + case surface_r16float : txt += showFormat? "16BW" : "16B"; break; + case surface_r32float : txt += showFormat? "32BW" : "32B"; break; + } + + txt += "]"; + + return txt; + } + + static drawDimension = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + if(_s * w < 64) return; + + draw_set_text(f_p2, fa_center, fa_top, COLORS.panel_graph_node_dimension); + var tx = xx + w * _s / 2; + var ty = yy + (h + 4) * _s - 2; + + if(PANEL_GRAPH.show_dimension) { + var txt = string(getNodeDimension(_s > 0.65)); + draw_text(round(tx), round(ty), txt); + ty += string_height(txt) - 2; + } + + draw_set_font(f_p3); + + if(PANEL_GRAPH.show_compute) { + var rt, unit; + if(render_time < 1000) { + rt = round(render_time / 10) * 10; + unit = "us"; + draw_set_color(COLORS.speed[2]); + } else if(render_time < 1000000) { + rt = string_format(render_time / 1000, -1, 2); + unit = "ms"; + draw_set_color(COLORS.speed[1]); + } else { + rt = string_format(render_time / 1000000, -1, 2); + unit = "s"; + draw_set_color(COLORS.speed[0]); + } + draw_text(round(tx), round(ty), string(rt) + " " + unit); + } + } + + static drawNode = function(_x, _y, _mx, _my, _s) { + if(draw_graph_culled) return; + if(!active) return; + + var xx = x * _s + _x; + var yy = y * _s + _y; + + preview_mx = _mx; + preview_my = _my; + + if(value_validation[VALIDATION.error] || error_noti_update != noone) + draw_sprite_stretched_ext(THEME.node_glow, 0, xx - 9, yy - 9, w * _s + 18, h * _s + 18, COLORS._main_value_negative, 1); + + drawNodeBase(xx, yy, _s); + if(previewable && ds_list_size(outputs) > 0) { + if(preview_channel >= ds_list_size(outputs)) + preview_channel = 0; + drawPreview(xx, yy, _s); + } + drawDimension(xx, yy, _s); + + onDrawNode(xx, yy, _mx, _my, _s, PANEL_GRAPH.node_hovering == self, PANEL_GRAPH.node_focus == self); + drawNodeName(xx, yy, _s); + + if(active_draw_index > -1) { + draw_sprite_stretched_ext(bg_sel_spr, 0, xx, yy, round(w * _s), round(h * _s), active_draw_index > 1? COLORS.node_border_file_drop : COLORS._main_accent, 1); + active_draw_index = -1; + } + + if(draw_droppable) + draw_sprite_stretched_ext(THEME.ui_panel_active, 0, xx, yy, w * _s, h * _s, COLORS._main_value_positive, 1); + draw_droppable = false; + + return drawJunctions(xx, yy, _mx, _my, _s); + } + + static onDrawNodeBehind = function(_x, _y, _mx, _my, _s) {} + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) {} + + static onDrawHover = function(_x, _y, _mx, _my, _s) {} + + badgePreview = 0; + badgeInspect = 0; + static drawBadge = function(_x, _y, _s) { + if(!active) return; + var xx = x * _s + _x + w * _s; + var yy = y * _s + _y; + + badgePreview = lerp_float(badgePreview, !!previewing, 2); + badgeInspect = lerp_float(badgeInspect, inspecting, 2); + + if(badgePreview > 0) { + draw_sprite_ext(THEME.node_state, 0, xx, yy, badgePreview, badgePreview, 0, c_white, 1); + xx -= 28 * badgePreview; + } + + if(badgeInspect > 0) { + draw_sprite_ext(THEME.node_state, 1, xx, yy, badgeInspect, badgeInspect, 0, c_white, 1); + xx -= 28 * badgeInspect; + } + + if(isTool) { + draw_sprite_ext(THEME.node_state, 2, xx, yy, 1, 1, 0, c_white, 1); + xx -= 28 * 2; + } + + inspecting = false; + previewing = 0; + } + + active_draw_index = -1; + static drawActive = function(_x, _y, _s, ind = 0) { + active_draw_index = ind; + } + + static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) {} + + static drawAnimationTimeline = function(_w, _h, _s) {} + + static enable = function() { active = true; } + static disable = function() { active = false; } + + static destroy = function(_merge = false) { + if(!active) return; + disable(); + + if(PANEL_GRAPH.node_hover == self) PANEL_GRAPH.node_hover = noone; + if(PANEL_GRAPH.node_focus == self) PANEL_GRAPH.node_focus = noone; + if(PANEL_INSPECTOR.inspecting == self) PANEL_INSPECTOR.inspecting = noone; + + PANEL_PREVIEW.removeNodePreview(self); + PANEL_ANIMATION.updatePropertyList(); + + for(var i = 0; i < ds_list_size(outputs); i++) { + var jun = outputs[| i]; + + for(var j = 0; j < ds_list_size(jun.value_to); j++) { + var _vt = jun.value_to[| j]; + if(_vt.value_from == noone) break; + if(_vt.value_from.node != self) break; + + _vt.removeFrom(false); + + if(!_merge) continue; + + for( var k = 0; k < ds_list_size(inputs); k++ ) { + if(inputs[| k].value_from == noone) continue; + if(_vt.setFrom(inputs[| k].value_from)) break; + } + } + + ds_list_clear(jun.value_to); + } + + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].destroy(); + + for( var i = 0; i < ds_list_size(outputs); i++ ) + outputs[| i].destroy(); + + onDestroy(); + } + + static restore = function() { + if(active) return; + enable(); + ds_list_add(group == noone? PROJECT.nodes : group.getNodeList(), self); + } + + static onValidate = function() { + value_validation[VALIDATION.pass] = 0; + value_validation[VALIDATION.warning] = 0; + value_validation[VALIDATION.error] = 0; + + for( var i = 0; i < ds_list_size(inputs); i++ ) { + var jun = inputs[| i]; + if(jun.value_validation) + value_validation[jun.value_validation]++; + } + } + + static onDestroy = function() {} + + static clearInputCache = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].cache_value[0] = false; + } + + static cacheArrayCheck = function() { + if(array_length(cached_output) != PROJECT.animator.frames_total) + array_resize(cached_output, PROJECT.animator.frames_total); + if(array_length(cache_result) != PROJECT.animator.frames_total) + array_resize(cache_result, PROJECT.animator.frames_total); + } + + static cacheCurrentFrame = function(_frame) { + cacheArrayCheck(); + if(PROJECT.animator.current_frame < 0) return; + if(PROJECT.animator.current_frame >= array_length(cached_output)) return; + + surface_array_free(cached_output[PROJECT.animator.current_frame]); + cached_output[PROJECT.animator.current_frame] = surface_array_clone(_frame); + + array_safe_set(cache_result, PROJECT.animator.current_frame, true); + + return cached_output[PROJECT.animator.current_frame]; + } + + static cacheExist = function(frame = PROJECT.animator.current_frame) { + if(frame < 0) return false; + + if(frame >= array_length(cached_output)) return false; + if(frame >= array_length(cache_result)) return false; + if(!array_safe_get(cache_result, frame, false)) return false; + + var s = array_safe_get(cached_output, frame); + return is_array(s) || surface_exists(s); + } + + static getCacheFrame = function(frame = PROJECT.animator.current_frame) { + if(frame < 0) return false; + + if(!cacheExist(frame)) return noone; + var surf = array_safe_get(cached_output, frame); + return surf; + } + + static recoverCache = function(frame = PROJECT.animator.current_frame) { + if(!cacheExist(frame)) return false; + + var _s = cached_output[PROJECT.animator.current_frame]; + outputs[| 0].setValue(_s); + + return true; + } + static clearCache = function() { + clearInputCache(); + + if(!clearCacheOnChange) return; + if(!use_cache) return; + if(!isRenderActive()) return; + + if(array_length(cached_output) != PROJECT.animator.frames_total) + array_resize(cached_output, PROJECT.animator.frames_total); + for(var i = 0; i < array_length(cached_output); i++) { + var _s = cached_output[i]; + if(is_surface(_s)) + surface_free(_s); + cached_output[i] = 0; + cache_result[i] = false; + } + } + + static clearCacheForward = function() { + _clearCacheForward(); + } + + static _clearCacheForward = function() { + if(!isRenderActive()) return; + + clearCache(); + var arr = getNextNodesRaw(); + for( var i = 0, n = array_length(arr); i < n; i++ ) + arr[i]._clearCacheForward(); + + //for( var i = 0; i < ds_list_size(outputs); i++ ) + //for( var j = 0; j < ds_list_size(outputs[| i].value_to); j++ ) + // outputs[| i].value_to[| j].node._clearCacheForward(); + } + + static clearInputCache = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].resetCache(); + } + + static checkConnectGroup = function(_type = "group") { + var _y = y; + var nodes = []; + + for(var i = 0; i < ds_list_size(inputs); i++) { + var _in = inputs[| i]; + 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 "feedback" : input_node = new Node_Feedback_Input(x - w - 64, _y, group); break; + } + + if(input_node == noone) continue; + + array_push(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++) { + var _to = _ou.value_to[| j]; + if(_to.value_from != _ou) continue; + if(!_to.node.active) continue; + if(_to.node.group == group) continue; + var output_node = noone; + + 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; + + array_push(nodes, output_node); + _to.setFrom(output_node.outParent); + output_node.inputs[| 0].setFrom(_ou); + } + } + + return nodes; + } + + static isNotUsingTool = function() { + return PANEL_PREVIEW.tool_current == noone; + } + + static isUsingTool = function(index, subtool = noone) { + if(tools == -1) + return false; + + var _tool = PANEL_PREVIEW.tool_current; + if(_tool == noone) + return false; + + if(is_real(index) && _tool != tools[index]) + return false; + + if(is_string(index) && _tool.getName(_tool.selecting) != index) + return false; + + if(subtool == noone) + return true; + + return _tool.selecting == subtool; + } + + static clone = function(target = PANEL_GRAPH.getCurrentContext()) { + CLONING = true; + var _type = instanceof(self); + var _node = nodeBuild(_type, x, y, target); + CLONING = false; + + PROJECT.version = SAVE_VERSION; + + if(!_node) return; + + CLONING = true; + var _nid = _node.node_id; + _node.deserialize(serialize()); + _node.postDeserialize(); + _node.applyDeserialize(); + _node.node_id = _nid; + + PROJECT.nodeMap[? node_id] = self; + PROJECT.nodeMap[? _nid] = _node; + PANEL_ANIMATION.updatePropertyList(); + CLONING = false; + + onClone(_node, target); + + return _node; + } + + static onClone = function(_NewNode, target = PANEL_GRAPH.getCurrentContext()) {} + + draw_droppable = false; + static droppable = function(dragObj) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(dragObj.type == inputs[| i].drop_key) + return true; + } + return false; + } + + static onDrop = function(dragObj) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(dragObj.type == inputs[| i].drop_key) { + inputs[| i].setValue(dragObj.data); + previewDropAnimation(); + return; + } + } + } + + static getPreviewValue = function() { + if(preview_channel > ds_list_size(outputs)) return noone; + return outputs[| preview_channel]; + } + + static getPreviewBoundingBox = function() { + var _node = getPreviewValue(); + if(_node == undefined) return noone; + if(_node.type != VALUE_TYPE.surface) return noone; + + var _surf = _node.getValue(); + if(is_array(_surf)) + _surf = array_safe_get(_surf, preview_index, noone); + if(!is_surface(_surf)) return noone; + + return BBOX().fromWH(preview_x, preview_y, surface_get_width(_surf), surface_get_height(_surf)); + } + + static getTool = function() { + return self; + } + + static setTool = function(tool) { + if(!tool) { + isTool = false; + return; + } + + for( var i = 0; i < ds_list_size(group.nodes); i++ ) + group.nodes[| i].isTool = false; + + isTool = true; + } + + static serialize = function(scale = false, preset = false) { + var _map = {}; + //print(" > Serializing: " + name); + + if(!preset) { + _map.id = node_id; + _map.render = renderActive; + _map.name = display_name; + _map.iname = internalName; + _map.x = x; + _map.y = y; + _map.type = instanceof(self); + _map.group = group == noone? group : group.node_id; + _map.preview = previewable; + _map.tool = isTool; + } + + _map.attri = attributeSerialize(); + + if(is_dynamic_input) { + _map.input_fix_len = input_fix_len; + _map.data_length = data_length; + } + + var _inputs = []; + for(var i = 0; i < ds_list_size(inputs); i++) + array_push(_inputs, inputs[| i].serialize(scale, preset)); + _map.inputs = _inputs; + + var _outputs = []; + for(var i = 0; i < ds_list_size(outputs); i++) + array_push(_outputs, outputs[| i].serialize(scale, preset)); + _map.outputs = _outputs; + + var _trigger = []; + array_push(_trigger, inspectInput1.serialize(scale, preset)); + array_push(_trigger, inspectInput2.serialize(scale, preset)); + _map.inspectInputs = _trigger; + + doSerialize(_map); + processSerialize(_map); + return _map; + } + + static attributeSerialize = function() { return attributes; } + static doSerialize = function(_map) {} + static processSerialize = function(_map) {} + + load_scale = false; + load_map = -1; + static deserialize = function(_map, scale = false, preset = false) { + load_map = _map; + load_scale = scale; + + if(!preset) { + if(APPENDING) APPEND_MAP[? load_map.id] = node_id; + else node_id = load_map.id; + + PROJECT.nodeMap[? node_id] = self; + //print($"D Adding node {node_id} to {PROJECT.path} [{ds_map_size(PROJECT.nodeMap)}]"); + + if(struct_has(load_map, "name")) + setDisplayName(load_map.name); + + internalName = struct_try_get(load_map, "iname", internalName); + if(internalName == "") + resetInternalName(); + + _group = struct_try_get(load_map, "group", noone); + if(_group == -1) _group = noone; + + x = struct_try_get(load_map, "x"); + y = struct_try_get(load_map, "y"); + renderActive = struct_try_get(load_map, "render", true); + previewable = struct_try_get(load_map, "preview", previewable); + isTool = struct_try_get(load_map, "tool"); + } + + if(struct_has(load_map, "attri")) + attributeDeserialize(load_map.attri); + + if(is_dynamic_input) { + inputBalance(); + inputGenerate(); + } + + processDeserialize(); + + if(preset) { + postDeserialize(); + applyDeserialize(); + + triggerRender(); + } + } + + static inputBalance = function() { //Cross version compatibility for dynamic input nodes + if(!struct_has(load_map, "data_length")) + return; + + var _input_fix_len = load_map.input_fix_len; + var _data_length = load_map.data_length; + + var _dynamic_inputs = (array_length(load_map.inputs) - _input_fix_len) / _data_length; + if(frac(_dynamic_inputs) != 0) { + noti_warning("LOAD: Uneven dynamic input."); + _dynamic_inputs = ceil(_dynamic_inputs); + } + + if(_input_fix_len == input_fix_len && _data_length == data_length) + return; + + var _pad_dyna = data_length - _data_length; + + for( var i = _dynamic_inputs - 1; i >= 0; i-- ) { + var _ind = _input_fix_len + i * _data_length; + repeat(_pad_dyna) + array_insert(load_map.inputs, _ind, noone); + } + + var _pad_fix = input_fix_len - _input_fix_len; + repeat(_pad_fix) + array_insert(load_map.inputs, _input_fix_len, noone); + } + + static inputGenerate = function() { //Generate input for dynamic input nodes + if(createNewInput == noone) + return; + + var _dynamic_inputs = (array_length(load_map.inputs) - input_fix_len) / data_length; + print($"Node {name} create {_dynamic_inputs} inputs for data length {data_length}"); + repeat(_dynamic_inputs) + createNewInput(); + } + + static attributeDeserialize = function(attr) { + struct_override(attributes, attr); + } + + static postDeserialize = function() {} + static processDeserialize = function() {} + + static applyDeserialize = function(preset = false) { + var _inputs = load_map.inputs; + var amo = min(ds_list_size(inputs), array_length(_inputs)); + + for(var i = 0; i < amo; i++) { + if(inputs[| i] == noone || _inputs[i] == noone) continue; + inputs[| i].applyDeserialize(_inputs[i], load_scale, preset); + } + + if(struct_has(load_map, "outputs")) { + var _outputs = load_map.outputs; + var amo = min(ds_list_size(outputs), array_length(_outputs)); + + for(var i = 0; i < amo; i++) { + if(outputs[| i] == noone) continue; + outputs[| i].applyDeserialize(_outputs[i], load_scale, preset); + } + } + + if(struct_has(load_map, "inspectInputs")) { + var insInp = load_map.inspectInputs; + inspectInput1.applyDeserialize(insInp[0], load_scale, preset); + inspectInput2.applyDeserialize(insInp[1], load_scale, preset); + } + + doApplyDeserialize(); + } + + static doApplyDeserialize = function() {} + + static loadGroup = function(context = PANEL_GRAPH.getCurrentContext()) { + if(_group == noone) { + var c = context; + if(c != noone) c.add(self); + } else { + if(APPENDING) _group = GetAppendID(_group); + + if(ds_map_exists(PROJECT.nodeMap, _group)) { + if(struct_has(PROJECT.nodeMap[? _group], "add")) + PROJECT.nodeMap[? _group].add(self); + else { + var txt = $"Group load failed. Node ID {_group} is not a group."; + throw(txt); + } + } else { + var txt = $"Group load failed. Can't find node ID {_group}"; + throw(txt); + } + } + } + + static connect = function(log = false) { + var connected = true; + for(var i = 0; i < ds_list_size(inputs); i++) + connected &= inputs[| i].connect(log); + + if(struct_has(load_map, "inspectInputs")) { + inspectInput1.connect(log); + inspectInput2.connect(log); + } + + if(!connected) ds_queue_enqueue(CONNECTION_CONFLICT, self); + + return connected; + } + + static preConnect = function() {} + static postConnect = function() {} + + static resetAnimation = function() {} + + static cleanUp = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].cleanUp(); + for( var i = 0; i < ds_list_size(outputs); i++ ) + outputs[| i].cleanUp(); + + ds_list_destroy(inputs); + ds_list_destroy(outputs); + + ds_map_destroy(inputMap); + ds_map_destroy(outputMap); + + for( var i = 0, n = array_length(temp_surface); i < n; i++ ) + surface_free(temp_surface[i]); + + onCleanUp(); + } + + static onCleanUp = function() {} + + // helper function + static attrDepth = function() { + if(struct_has(attributes, "color_depth")) { + var form = attributes.color_depth; + if(inputs[| 0].type == VALUE_TYPE.surface) + form--; + if(form >= 0) + return array_safe_get(global.SURFACE_FORMAT, form, surface_rgba8unorm); + } + + var _s = inputs[| 0].getValue(); + while(is_array(_s) && array_length(_s)) _s = _s[0]; + if(!is_surface(_s)) + return surface_rgba8unorm; + return surface_get_format(_s); + } +} \ No newline at end of file diff --git a/#backups/scripts/node_data/node_data.gml.backup1 b/#backups/scripts/node_data/node_data.gml.backup1 new file mode 100644 index 000000000..e7c204e63 --- /dev/null +++ b/#backups/scripts/node_data/node_data.gml.backup1 @@ -0,0 +1,1543 @@ +// 2023-08-08 10:28:44 +global.loop_nodes = [ "Node_Iterate", "Node_Iterate_Each" ]; + +function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) : __Node_Base(_x, _y) constructor { + active = true; + renderActive = true; + + node_id = UUID_generate(); + + group = _group; + destroy_when_upgroup = false; + ds_list_add(PANEL_GRAPH.getNodeList(_group), self); + + active_index = -1; + active_range = [ 0, PROJECT.animator.frames_total - 1 ]; + + color = c_white; + icon = noone; + bg_spr = THEME.node_bg; + bg_sel_spr = THEME.node_active; + anim_priority = ds_map_size(PROJECT.nodeMap); + + static resetInternalName = function() { + var str = string_replace_all(name, " ", "_"); + str = string_replace_all(str, "/", ""); + str = string_replace_all(str, "-", ""); + + internalName = str + string(irandom_range(10000, 99999)); + PROJECT.nodeNameMap[? internalName] = self; + } + + if(!LOADING && !APPENDING) { + recordAction(ACTION_TYPE.node_added, self); + PROJECT.nodeMap[? node_id] = self; + PROJECT.modified = true; + + //print($"Adding node {node_id} to {PROJECT.path} [{ds_map_size(PROJECT.nodeMap)}]"); + + run_in(1, function() { + if(display_name != "") return; + resetInternalName(); + display_name = name; //__txt_node_name(instanceof(self), name); + }); + } + + name = ""; + display_name = ""; + internalName = ""; + + tooltip = ""; + x = _x; + y = _y; + + w = 128; + h = 128; + min_h = 0; + draw_padding = 8; + auto_height = true; + + draw_name = true; + draggable = true; + + inputs = ds_list_create(); + outputs = ds_list_create(); + inputMap = ds_map_create(); + outputMap = ds_map_create(); + + input_display_list = -1; + output_display_list = -1; + inspector_display_list = -1; + is_dynamic_output = false; + + attributes = {}; + attributeEditors = []; + + inspectInput1 = nodeValue("Toggle execution", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + inspectInput2 = nodeValue("Toggle execution", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + + updateAction = nodeValue("Update", self, JUNCTION_CONNECT.input, VALUE_TYPE.action, false).setVisible(true, true); + + show_input_name = false; + show_output_name = false; + + inspecting = false; + previewing = 0; + + preview_surface = noone; + preview_amount = 0; + previewable = true; + preview_speed = 0; + preview_index = 0; + preview_channel = 0; + preview_alpha = 1; + preview_x = 0; + preview_y = 0; + + preview_surface_prev = noone; + preview_trans = 1; + preview_drop_x = 0; + preview_drop_y = 0; + + preview_mx = 0; + preview_my = 0; + + rendered = false; + update_on_frame = false; + render_time = 0; + auto_render_time = true; + updated = false; + + use_cache = false; + clearCacheOnChange = true; + cached_output = []; + cache_result = []; + temp_surface = []; + + tools = -1; + + on_dragdrop_file = -1; + + anim_show = true; + dopesheet_color = COLORS.panel_animation_dope_blend_default; + dopesheet_y = 0; + + value_validation = array_create(3); + + error_noti_update = noone; + error_update_enabled = false; + manual_updated = false; + manual_deletable = true; + + isTool = false; + tool_settings = []; + tool_attribute = {}; + + is_dynamic_input = false; + input_display_len = 0; + input_fix_len = 0; + data_length = 1; + + static createNewInput = noone; + + static initTooltip = function() { + var type_self:string = instanceof(self); + if(!struct_has(global.NODE_GUIDE, type_self)) return; + + var _n = global.NODE_GUIDE[$ type_self]; + var _ins = _n.inputs; + var _ots = _n.outputs; + + var amo = min(ds_list_size(inputs), array_length(_ins)); + for( var i = 0; i < amo; i++ ) { + inputs[| i].name = _ins[i].name; + inputs[| i].tooltip = _ins[i].tooltip; + } + + var amo = min(ds_list_size(outputs), array_length(_ots)); + for( var i = 0; i < amo; i++ ) { + outputs[| i].name = _ots[i].name; + outputs[| i].tooltip = _ots[i].tooltip; + } + } + run_in(1, initTooltip); + + static resetDefault = function() { + var folder = instanceof(self); + if(!ds_map_exists(global.PRESETS_MAP, folder)) return; + + var pres = global.PRESETS_MAP[? folder]; + for( var i = 0, n = array_length(pres); i < n; i++ ) { + var preset = pres[i]; + if(preset.name != "_default") continue; + + deserialize(preset.content, true, true); + applyDeserialize(true); + } + + doUpdate(); + } + if(!APPENDING && !LOADING) + run_in(1, method(self, resetDefault)); + + static getInputJunctionIndex = function(index) { + if(input_display_list == -1) + return index; + + var jun_list_arr = input_display_list[index]; + if(is_array(jun_list_arr)) return noone; + if(is_struct(jun_list_arr)) return noone; + return jun_list_arr; + } + + static getOutputJunctionIndex = function(index) { + if(output_display_list == -1) + return index; + return output_display_list[index]; + } + + static setHeight = function() { + var _hi = ui(32); + var _ho = ui(32); + + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(inputs[| i].isVisible()) _hi += 24; + } + + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(outputs[| i].isVisible()) _ho += 24; + } + + h = max(min_h, (preview_surface && previewable)? 128 : 0, _hi, _ho); + } + + onSetDisplayName = noone; + static setDisplayName = function(_name) { + display_name = _name; + internalName = string_replace_all(display_name, " ", "_"); + refreshNodeMap(); + + if(onSetDisplayName != noone) + onSetDisplayName(); + } + + static setIsDynamicInput = function(_data_length = 1) { + is_dynamic_input = true; + input_display_len = input_display_list == -1? 0 : array_length(input_display_list); + input_fix_len = ds_list_size(inputs); + data_length = _data_length; + } + + static getOutput = function(junc = noone) { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(!outputs[| i].visible) continue; + if(junc != noone && !junc.isConnectable(outputs[| i], true)) continue; + + return outputs[| i]; + } + return noone; + } + + static getInput = function(junc = noone) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(!inputs[| i].visible) continue; + if(inputs[| i].value_from != noone) continue; + if(junc != noone && !inputs[| i].isConnectable(junc, true)) continue; + + return inputs[| i]; + } + return noone; + } + + static getFullName = function() { + return display_name == ""? name : "[" + name + "] " + display_name; + } + + static addInput = function(junctionFrom) { + var targ = getInput(junctionFrom); + if(targ == noone) return; + + targ.setFrom(junctionFrom); + } + + static isAnimated = function() { + for(var i = 0; i < ds_list_size(inputs); i++) { + if(inputs[| i].isAnimated()) + return true; + } + return false; + } + + static isInLoop = function() { + return array_exists(global.loop_nodes, instanceof(group)); + } + + static move = function(_x, _y) { + if(x == _x && y == _y) return; + + x = _x; + y = _y; + if(!LOADING) PROJECT.modified = true; + } + + insp1UpdateTooltip = __txtx("panel_inspector_execute", "Execute node"); + insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + static inspector1Update = function() { + if(error_update_enabled && error_noti_update != noone) + noti_remove(error_noti_update); + error_noti_update = noone; + + onInspector1Update(); + } + static onInspector1Update = noone; + static hasInspector1Update = function() { return onInspector1Update != noone; } + + insp2UpdateTooltip = __txtx("panel_inspector_execute", "Execute node"); + insp2UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + static inspector2Update = function() { onInspector2Update(); } + static onInspector2Update = noone; + static hasInspector2Update = function() { return onInspector2Update != noone; } + + static stepBegin = function() { + if(use_cache) cacheArrayCheck(); + var willUpdate = false; + + if(PROJECT.animator.frame_progress) { + if(update_on_frame) willUpdate = true; + if(isAnimated()) willUpdate = true; + + if(willUpdate) { + setRenderStatus(false); + UPDATE |= RENDER_TYPE.partial; + } + } + + if(auto_height) + setHeight(); + + doStepBegin(); + + if(hasInspector1Update()) inspectInput1.name = insp1UpdateTooltip; + if(hasInspector2Update()) inspectInput2.name = insp2UpdateTooltip; + } + static doStepBegin = function() {} + + static triggerCheck = function() { + _triggerCheck(); + } + + static _triggerCheck = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(inputs[| i].type != VALUE_TYPE.trigger) continue; + if(!is_instanceof(inputs[| i].editWidget, buttonClass)) continue; + + var trig = inputs[| i].getValue(); + if(trig) { + inputs[| i].editWidget.onClick(); + inputs[| i].setValue(false); + } + } + + if(hasInspector1Update()) { + var trig = inspectInput1.getValue(); + if(trig) { + inspectInput1.editWidget.onClick(); + inspectInput1.setValue(false); + } + } + + if(hasInspector2Update()) { + var trig = inspectInput2.getValue(); + if(trig) { + inspectInput2.editWidget.onClick(); + inspectInput2.setValue(false); + } + } + } + + static step = function() {} + static focusStep = function() {} + static inspectorStep = function() {} + + static doUpdate = function() { + if(SAFE_MODE) return; + if(NODE_EXTRACT) return; + + var sBase = surface_get_target(); + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $">>>>>>>>>> DoUpdate called from {internalName} <<<<<<<<<<"); + + try { + var t = get_timer(); + + if(!is_instanceof(self, Node_Collection)) + setRenderStatus(true); + + update(); ///UPDATE + + if(!is_instanceof(self, Node_Collection)) + render_time = get_timer() - t; + } catch(exception) { + var sCurr = surface_get_target(); + while(surface_get_target() != sBase) + surface_reset_target(); + + log_warning("RENDER", exception_print(exception), self); + } + + if(!use_cache && PROJECT.onion_skin) { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + if(outputs[| i].type != VALUE_TYPE.surface) continue; + cacheCurrentFrame(outputs[| i].getValue()); + break; + } + } + + if(hasInspector1Update()) { + var trigger = inspectInput1.getValue(); + if(trigger) onInspector1Update(); + } + + if(hasInspector2Update()) { + var trigger = inspectInput2.getValue(); + if(trigger) onInspector2Update(); + } + LOG_BLOCK_END(); + } + + static valueUpdate = function(index) { + if(error_update_enabled && error_noti_update == noone) + error_noti_update = noti_error(getFullName() + " node require manual execution.",, self); + + onValueUpdate(index); + } + + static onValueUpdate = function(index = 0) {} + static onValueFromUpdate = function(index) {} + + static triggerRender = function() { + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $"Trigger render for {internalName}"); + + setRenderStatus(false); + UPDATE |= RENDER_TYPE.partial; + + if(is_instanceof(group, Node_Collection) && group.reset_all_child) { + group.resetRender(); + } else { + resetRender(); + + var nodes = getNextNodesRaw(); + for(var i = 0; i < array_length(nodes); i++) + nodes[i].triggerRender(); + } + + LOG_BLOCK_END(); + } + + static resetRender = function() { setRenderStatus(false); } + static isRenderActive = function() { return renderActive || (PREF_MAP[? "render_all_export"] && PROJECT.animator.rendering); } + + static isRenderable = function(log = false) { //Check if every input is ready (updated) + if(!active) return false; + if(!isRenderActive()) return false; + + //if(group && struct_has(group, "iterationStatus") && group.iterationStatus() == ITERATION_STATUS.complete) return false; + + for(var j = 0; j < ds_list_size(inputs); j++) { + var _in = inputs[| j]; + if( _in.type == VALUE_TYPE.node) continue; + + var val_from = _in.value_from; + if( val_from == noone) continue; + if(!val_from.node.active) continue; + if(!val_from.node.isRenderActive()) continue; + if!(val_from.node.rendered || val_from.node.update_on_frame) { + LOG_LINE_IF(global.FLAG.render, $"Node {internalName} is not renderable because input {val_from.node.internalName} is not rendered ({val_from.node.rendered})"); + return false; + } + } + + return true; + } + + static getNextNodesRaw = function() { return getNextNodes(); } + + static getNextNodes = function() { + var nodes = []; + var nodeNames = []; + + LOG_BLOCK_START(); + LOG_IF(global.FLAG.render, $"→→→→→ Call get next node from: {internalName}"); + LOG_BLOCK_START(); + + for(var i = 0; i < ds_list_size(outputs); i++) { + var _ot = outputs[| i]; + if(!_ot.forward) continue; + + var _tos = _ot.getJunctionTo(); + + for( var j = 0; j < array_length(_tos); j++ ) { + var _to = _tos[j]; + + array_push(nodes, _to.node); + array_push(nodeNames, _to.node.internalName); + + //LOG_IF(global.FLAG.render, $"→→ Check output: {_ot.name} connect to node {_to.node.internalName}"); + } + } + + LOG_IF(global.FLAG.render, $"→→ Push {nodeNames} to stack."); + + LOG_BLOCK_END(); + LOG_BLOCK_END(); + return nodes; + } + + static isTerminal = function() { + for( var i = 0; i < ds_list_size(outputs); i++ ) { + var _to = outputs[| i].getJunctionTo(); + if(array_length(_to)) return false; + } + + return true; + } + + static onInspect = function() {} + + static setRenderStatus = function(result) { + LOG_LINE_IF(global.FLAG.render, $"Set render status for {internalName} : {result}"); + + rendered = result; + } + + static pointIn = function(_x, _y, _mx, _my, _s) { + var xx = x * _s + _x; + var yy = y * _s + _y; + + return point_in_rectangle(_mx, _my, xx, yy, xx + w * _s, yy + h * _s); + } + + draw_graph_culled = false; + static cullCheck = function(_x, _y, _s, minx, miny, maxx, maxy) { + var x0 = x * _s + _x; + var y0 = y * _s + _y; + var x1 = (x + w) * _s + _x; + var y1 = (y + h) * _s + _y; + + draw_graph_culled = !rectangle_in_rectangle(minx, miny, maxx, maxy, x0, y0, x1, y1); + } + + static preDraw = function(_x, _y, _s) { + var xx = x * _s + _x; + var yy = y * _s + _y; + var jun; + + var inspCount = hasInspector1Update() + hasInspector2Update(); + var ind = 1; + if(hasInspector1Update()) { + inspectInput1.x = xx + w * _s * ind / (inspCount + 1); + inspectInput1.y = yy; + ind++; + } + + if(hasInspector2Update()) { + inspectInput2.x = xx + w * _s * ind / (inspCount + 1); + inspectInput2.y = yy; + ind++; + } + + var inamo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var _in = yy + ui(32) * _s; + + for(var i = 0; i < inamo; i++) { + var idx = getInputJunctionIndex(i); + if(idx == noone) continue; + + jun = ds_list_get(inputs, idx, noone); + if(jun == noone || is_undefined(jun)) continue; + jun.x = xx; + jun.y = _in; + _in += 24 * _s * jun.isVisible(); + } + + var outamo = output_display_list == -1? ds_list_size(outputs) : array_length(output_display_list); + + xx = xx + w * _s; + _in = yy + ui(32) * _s; + for(var i = 0; i < outamo; i++) { + var idx = getOutputJunctionIndex(i); + jun = outputs[| idx]; + + jun.x = xx; + jun.y = _in; + _in += 24 * _s * jun.isVisible(); + } + } + + static drawNodeBase = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + var aa = 0.25 + 0.5 * renderActive; + draw_sprite_stretched_ext(bg_spr, 0, xx, yy, w * _s, h * _s, color, aa); + } + + static drawGetBbox = function(xx, yy, _s) { + var x0 = xx + draw_padding * _s; + var x1 = xx + (w - draw_padding) * _s; + var y0 = yy + 20 * draw_name + draw_padding * _s; + var y1 = yy + (h - draw_padding) * _s; + + return BBOX().fromPoints(x0, y0, x1, y1); + } + + static drawNodeName = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + + draw_name = false; + var _name = display_name == ""? name : display_name; + if(_name == "") return; + if(_s < 0.75) return; + draw_name = true; + + var aa = 0.25 + 0.5 * renderActive; + draw_sprite_stretched_ext(THEME.node_bg_name, 0, xx, yy, w * _s, ui(20), color, aa); + + var cc = COLORS._main_text; + if(PREF_MAP[? "node_show_render_status"] && !rendered) + cc = isRenderable()? COLORS._main_value_positive : COLORS._main_value_negative; + + draw_set_text(f_p1, fa_left, fa_center, cc); + + if(hasInspector1Update()) icon = THEME.refresh_s; + var ts = clamp(power(_s, 0.5), 0.5, 1); + + var aa = 0.5 + 0.5 * renderActive; + draw_set_alpha(aa); + + if(icon && _s > 0.75) { + draw_sprite_ui_uniform(icon, 0, xx + ui(12), yy + ui(10),,, aa); + draw_text_cut(xx + ui(24), yy + ui(10), _name, w * _s - ui(24), ts); + } else + draw_text_cut(xx + ui(8), yy + ui(10), _name, w * _s - ui(8), ts); + + draw_set_alpha(1); + } + + static drawJunctions = function(_x, _y, _mx, _my, _s) { + if(!active) return; + var hover = noone; + var amo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var jun; + + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + jun = ds_list_get(inputs, ind, noone); + if(jun == noone || is_undefined(jun)) continue; + + if(jun.drawJunction(_s, _mx, _my)) + hover = jun; + } + + for(var i = 0; i < ds_list_size(outputs); i++) { + jun = outputs[| i]; + + if(jun.drawJunction(_s, _mx, _my)) + hover = jun; + } + + if(hasInspector1Update() && inspectInput1.drawJunction(_s, _mx, _my)) + hover = inspectInput1; + + if(hasInspector2Update() && inspectInput2.drawJunction(_s, _mx, _my)) + hover = inspectInput2; + + return hover; + } + + static drawJunctionNames = function(_x, _y, _mx, _my, _s) { + if(draw_graph_culled) return; + if(!active) return; + var amo = input_display_list == -1? ds_list_size(inputs) : array_length(input_display_list); + var jun; + + var xx = x * _s + _x; + var yy = y * _s + _y; + + show_input_name = PANEL_GRAPH.pHOVER && point_in_rectangle(_mx, _my, xx - 8 * _s, yy + 20 * _s, xx + 8 * _s, yy + h * _s); + show_output_name = PANEL_GRAPH.pHOVER && point_in_rectangle(_mx, _my, xx + (w - 8) * _s, yy + 20 * _s, xx + (w + 8) * _s, yy + h * _s); + + if(show_input_name) { + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + if(!inputs[| ind]) continue; + + inputs[| ind].drawNameBG(_s); + } + + for(var i = 0; i < amo; i++) { + var ind = getInputJunctionIndex(i); + if(ind == noone) continue; + if(!inputs[| ind]) continue; + + inputs[| ind].drawName(_s, _mx, _my); + } + } + + if(show_output_name) { + for(var i = 0; i < ds_list_size(outputs); i++) + outputs[| i].drawNameBG(_s); + + for(var i = 0; i < ds_list_size(outputs); i++) + outputs[| i].drawName(_s, _mx, _my); + } + + if(hasInspector1Update() && PANEL_GRAPH.pHOVER && point_in_circle(_mx, _my, inspectInput1.x, inspectInput1.y, 10)) { + inspectInput1.drawNameBG(_s); + inspectInput1.drawName(_s, _mx, _my); + } + + if(hasInspector2Update() && PANEL_GRAPH.pHOVER && point_in_circle(_mx, _my, inspectInput2.x, inspectInput2.y, 10)) { + inspectInput2.drawNameBG(_s); + inspectInput2.drawName(_s, _mx, _my); + } + } + + static drawConnections = function(_x, _y, _s, mx, my, _active, aa = 1, minx = undefined, miny = undefined, maxx = undefined, maxy = undefined) { + if(!active) return; + + var hovering = noone; + var drawLineIndex = 1; + + for(var i = 0; i < ds_list_size(outputs); i++) { + var jun = outputs[| i]; + var connected = false; + + for( var j = 0; j < ds_list_size(jun.value_to); j++ ) { + if(jun.value_to[| j].value_from == jun) + connected = true; + } + + if(connected) { + jun.drawLineIndex = drawLineIndex; + drawLineIndex += 0.5; + } + } + + var st = 0; + if(hasInspector1Update()) st = -1; + if(hasInspector2Update()) st = -2; + + var _inputs = []; + var drawLineIndex = 1; + for(var i = st; i < ds_list_size(inputs); i++) { + var jun; + if(i == -1) jun = inspectInput1; + else if(i == -2) jun = inspectInput2; + else jun = inputs[| i]; + + if(jun.value_from == noone) continue; + if(!jun.value_from.node.active) continue; + if(!jun.isVisible()) continue; + + if(i >= 0) + array_push(_inputs, jun); + } + + var len = array_length(_inputs); + for( var i = 0; i < len; i++ ) + _inputs[i].drawLineIndex = 1 + (i > len / 2? (len - 1 - i) : i) * 0.5; + + for(var i = st; i < ds_list_size(inputs); i++) { + var jun; + if(i == -1) jun = inspectInput1; + else if(i == -2) jun = inspectInput2; + else jun = inputs[| i]; + + var hov = jun.drawConnections(_x, _y, _s, mx, my, _active, aa, minx, miny, maxx, maxy); + if(hov) hovering = hov; + } + + return hovering; + } + + static drawPreview = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + + var _node = outputs[| preview_channel]; + if(_node.type != VALUE_TYPE.surface) return; + + var surf = _node.getValue(); + preview_amount = 0; + if(is_array(surf)) { + if(array_length(surf) == 0) return; + preview_amount = array_length(surf); + + if(preview_speed != 0) { + preview_index += preview_speed; + if(preview_index <= 0) + preview_index = array_length(surf) - 1; + } + + if(floor(preview_index) > array_length(surf) - 1) preview_index = 0; + surf = surf[preview_index]; + } + + preview_surface = is_surface(surf)? surf : noone; + if(preview_surface == noone) return; + + var pw = surface_get_width(preview_surface); + var ph = surface_get_height(preview_surface); + var ps = min((w * _s - 8) / pw, (h * _s - 8) / ph); + var px = xx + w * _s / 2 - pw * ps / 2; + var py = yy + h * _s / 2 - ph * ps / 2; + var aa = 0.5 + 0.5 * renderActive; + + if(preview_trans == 1) { + draw_surface_ext_safe(preview_surface, px, py, ps, ps, 0, c_white, aa); + return; + } + + if(preview_trans < 1 && is_surface(preview_surface_prev)) { + preview_trans = lerp_float(preview_trans, 1, 8); + var _pw = surface_get_width(preview_surface_prev); + var _ph = surface_get_height(preview_surface_prev); + var _ps = min((w * _s - 8) / _pw, (h * _s - 8) / _ph); + var _px = xx + w * _s / 2 - _pw * _ps / 2; + var _py = yy + h * _s / 2 - _ph * _ps / 2; + + draw_surface_ext_safe(preview_surface_prev, _px, _py, _ps, _ps, 0, c_white, aa); + + shader_set(sh_trans_node_prev_drop); + shader_set_f("dimension", _pw, _ph); + shader_set_f("position", (preview_drop_x - px) / (_pw * _ps), (preview_drop_y - py) / (_ph * _ps)); + shader_set_f("prog", preview_trans); + draw_surface_ext_safe(preview_surface, px, py, ps, ps, 0, c_white, aa); + shader_reset(); + } else if(is_surface(preview_surface_prev)) + surface_free(preview_surface_prev); + } + + static previewDropAnimation = function() { + preview_surface_prev = surface_clone(preview_surface); + preview_trans = 0; + preview_drop_x = preview_mx; + preview_drop_y = preview_my; + } + + static getNodeDimension = function(showFormat = true) { + if(!is_surface(preview_surface)) { + if(ds_list_size(outputs)) + return "[" + array_shape(outputs[| 0].getValue()) + "]"; + return ""; + } + + var pw = surface_get_width(preview_surface); + var ph = surface_get_height(preview_surface); + var format = surface_get_format(preview_surface); + + var txt = "[" + string(pw) + " x " + string(ph) + " "; + if(preview_amount) txt = string(preview_amount) + " x " + txt; + + switch(format) { + case surface_rgba4unorm : txt += showFormat? "4RGBA" : "4R"; break; + case surface_rgba8unorm : txt += showFormat? "8RGBA" : "8R"; break; + case surface_rgba16float : txt += showFormat? "16RGBA" : "16R"; break; + case surface_rgba32float : txt += showFormat? "32RGBA" : "32R"; break; + case surface_r8unorm : txt += showFormat? "8BW" : "8B"; break; + case surface_r16float : txt += showFormat? "16BW" : "16B"; break; + case surface_r32float : txt += showFormat? "32BW" : "32B"; break; + } + + txt += "]"; + + return txt; + } + + static drawDimension = function(xx, yy, _s) { + if(draw_graph_culled) return; + if(!active) return; + if(_s * w < 64) return; + + draw_set_text(f_p2, fa_center, fa_top, COLORS.panel_graph_node_dimension); + var tx = xx + w * _s / 2; + var ty = yy + (h + 4) * _s - 2; + + if(PANEL_GRAPH.show_dimension) { + var txt = string(getNodeDimension(_s > 0.65)); + draw_text(round(tx), round(ty), txt); + ty += string_height(txt) - 2; + } + + draw_set_font(f_p3); + + if(PANEL_GRAPH.show_compute) { + var rt, unit; + if(render_time < 1000) { + rt = round(render_time / 10) * 10; + unit = "us"; + draw_set_color(COLORS.speed[2]); + } else if(render_time < 1000000) { + rt = string_format(render_time / 1000, -1, 2); + unit = "ms"; + draw_set_color(COLORS.speed[1]); + } else { + rt = string_format(render_time / 1000000, -1, 2); + unit = "s"; + draw_set_color(COLORS.speed[0]); + } + draw_text(round(tx), round(ty), string(rt) + " " + unit); + } + } + + static drawNode = function(_x, _y, _mx, _my, _s) { + if(draw_graph_culled) return; + if(!active) return; + + var xx = x * _s + _x; + var yy = y * _s + _y; + + preview_mx = _mx; + preview_my = _my; + + if(value_validation[VALIDATION.error] || error_noti_update != noone) + draw_sprite_stretched_ext(THEME.node_glow, 0, xx - 9, yy - 9, w * _s + 18, h * _s + 18, COLORS._main_value_negative, 1); + + drawNodeBase(xx, yy, _s); + if(previewable && ds_list_size(outputs) > 0) { + if(preview_channel >= ds_list_size(outputs)) + preview_channel = 0; + drawPreview(xx, yy, _s); + } + drawDimension(xx, yy, _s); + + onDrawNode(xx, yy, _mx, _my, _s, PANEL_GRAPH.node_hovering == self, PANEL_GRAPH.node_focus == self); + drawNodeName(xx, yy, _s); + + if(active_draw_index > -1) { + draw_sprite_stretched_ext(bg_sel_spr, 0, xx, yy, round(w * _s), round(h * _s), active_draw_index > 1? COLORS.node_border_file_drop : COLORS._main_accent, 1); + active_draw_index = -1; + } + + if(draw_droppable) + draw_sprite_stretched_ext(THEME.ui_panel_active, 0, xx, yy, w * _s, h * _s, COLORS._main_value_positive, 1); + draw_droppable = false; + + return drawJunctions(xx, yy, _mx, _my, _s); + } + + static onDrawNodeBehind = function(_x, _y, _mx, _my, _s) {} + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) {} + + static onDrawHover = function(_x, _y, _mx, _my, _s) {} + + badgePreview = 0; + badgeInspect = 0; + static drawBadge = function(_x, _y, _s) { + if(!active) return; + var xx = x * _s + _x + w * _s; + var yy = y * _s + _y; + + badgePreview = lerp_float(badgePreview, !!previewing, 2); + badgeInspect = lerp_float(badgeInspect, inspecting, 2); + + if(badgePreview > 0) { + draw_sprite_ext(THEME.node_state, 0, xx, yy, badgePreview, badgePreview, 0, c_white, 1); + xx -= 28 * badgePreview; + } + + if(badgeInspect > 0) { + draw_sprite_ext(THEME.node_state, 1, xx, yy, badgeInspect, badgeInspect, 0, c_white, 1); + xx -= 28 * badgeInspect; + } + + if(isTool) { + draw_sprite_ext(THEME.node_state, 2, xx, yy, 1, 1, 0, c_white, 1); + xx -= 28 * 2; + } + + inspecting = false; + previewing = 0; + } + + active_draw_index = -1; + static drawActive = function(_x, _y, _s, ind = 0) { + active_draw_index = ind; + } + + static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) {} + + static drawAnimationTimeline = function(_w, _h, _s) {} + + static enable = function() { active = true; } + static disable = function() { active = false; } + + static destroy = function(_merge = false) { + if(!active) return; + disable(); + + if(PANEL_GRAPH.node_hover == self) PANEL_GRAPH.node_hover = noone; + if(PANEL_GRAPH.node_focus == self) PANEL_GRAPH.node_focus = noone; + if(PANEL_INSPECTOR.inspecting == self) PANEL_INSPECTOR.inspecting = noone; + + PANEL_PREVIEW.removeNodePreview(self); + PANEL_ANIMATION.updatePropertyList(); + + for(var i = 0; i < ds_list_size(outputs); i++) { + var jun = outputs[| i]; + + for(var j = 0; j < ds_list_size(jun.value_to); j++) { + var _vt = jun.value_to[| j]; + if(_vt.value_from == noone) break; + if(_vt.value_from.node != self) break; + + _vt.removeFrom(false); + + if(!_merge) continue; + + for( var k = 0; k < ds_list_size(inputs); k++ ) { + if(inputs[| k].value_from == noone) continue; + if(_vt.setFrom(inputs[| k].value_from)) break; + } + } + + ds_list_clear(jun.value_to); + } + + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].destroy(); + + for( var i = 0; i < ds_list_size(outputs); i++ ) + outputs[| i].destroy(); + + onDestroy(); + } + + static restore = function() { + if(active) return; + enable(); + ds_list_add(group == noone? PROJECT.nodes : group.getNodeList(), self); + } + + static onValidate = function() { + value_validation[VALIDATION.pass] = 0; + value_validation[VALIDATION.warning] = 0; + value_validation[VALIDATION.error] = 0; + + for( var i = 0; i < ds_list_size(inputs); i++ ) { + var jun = inputs[| i]; + if(jun.value_validation) + value_validation[jun.value_validation]++; + } + } + + static onDestroy = function() {} + + static clearInputCache = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].cache_value[0] = false; + } + + static cacheArrayCheck = function() { + if(array_length(cached_output) != PROJECT.animator.frames_total) + array_resize(cached_output, PROJECT.animator.frames_total); + if(array_length(cache_result) != PROJECT.animator.frames_total) + array_resize(cache_result, PROJECT.animator.frames_total); + } + + static cacheCurrentFrame = function(_frame) { + cacheArrayCheck(); + if(PROJECT.animator.current_frame < 0) return; + if(PROJECT.animator.current_frame >= array_length(cached_output)) return; + + surface_array_free(cached_output[PROJECT.animator.current_frame]); + cached_output[PROJECT.animator.current_frame] = surface_array_clone(_frame); + + array_safe_set(cache_result, PROJECT.animator.current_frame, true); + + return cached_output[PROJECT.animator.current_frame]; + } + + static cacheExist = function(frame = PROJECT.animator.current_frame) { + if(frame < 0) return false; + + if(frame >= array_length(cached_output)) return false; + if(frame >= array_length(cache_result)) return false; + if(!array_safe_get(cache_result, frame, false)) return false; + + var s = array_safe_get(cached_output, frame); + return is_array(s) || surface_exists(s); + } + + static getCacheFrame = function(frame = PROJECT.animator.current_frame) { + if(frame < 0) return false; + + if(!cacheExist(frame)) return noone; + var surf = array_safe_get(cached_output, frame); + return surf; + } + + static recoverCache = function(frame = PROJECT.animator.current_frame) { + if(!cacheExist(frame)) return false; + + var _s = cached_output[PROJECT.animator.current_frame]; + outputs[| 0].setValue(_s); + + return true; + } + static clearCache = function() { + clearInputCache(); + + if(!clearCacheOnChange) return; + if(!use_cache) return; + if(!isRenderActive()) return; + + if(array_length(cached_output) != PROJECT.animator.frames_total) + array_resize(cached_output, PROJECT.animator.frames_total); + for(var i = 0; i < array_length(cached_output); i++) { + var _s = cached_output[i]; + if(is_surface(_s)) + surface_free(_s); + cached_output[i] = 0; + cache_result[i] = false; + } + } + + static clearCacheForward = function() { + _clearCacheForward(); + } + + static _clearCacheForward = function() { + if(!isRenderActive()) return; + + clearCache(); + var arr = getNextNodesRaw(); + for( var i = 0, n = array_length(arr); i < n; i++ ) + arr[i]._clearCacheForward(); + + //for( var i = 0; i < ds_list_size(outputs); i++ ) + //for( var j = 0; j < ds_list_size(outputs[| i].value_to); j++ ) + // outputs[| i].value_to[| j].node._clearCacheForward(); + } + + static clearInputCache = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].resetCache(); + } + + static checkConnectGroup = function(_type = "group") { + var _y = y; + var nodes = []; + + for(var i = 0; i < ds_list_size(inputs); i++) { + var _in = inputs[| i]; + 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 "feedback" : input_node = new Node_Feedback_Input(x - w - 64, _y, group); break; + } + + if(input_node == noone) continue; + + array_push(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++) { + var _to = _ou.value_to[| j]; + if(_to.value_from != _ou) continue; + if(!_to.node.active) continue; + if(_to.node.group == group) continue; + var output_node = noone; + + 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; + + array_push(nodes, output_node); + _to.setFrom(output_node.outParent); + output_node.inputs[| 0].setFrom(_ou); + } + } + + return nodes; + } + + static isNotUsingTool = function() { + return PANEL_PREVIEW.tool_current == noone; + } + + static isUsingTool = function(index, subtool = noone) { + if(tools == -1) + return false; + + var _tool = PANEL_PREVIEW.tool_current; + if(_tool == noone) + return false; + + if(is_real(index) && _tool != tools[index]) + return false; + + if(is_string(index) && _tool.getName(_tool.selecting) != index) + return false; + + if(subtool == noone) + return true; + + return _tool.selecting == subtool; + } + + static clone = function(target = PANEL_GRAPH.getCurrentContext()) { + CLONING = true; + var _type = instanceof(self); + var _node = nodeBuild(_type, x, y, target); + CLONING = false; + + PROJECT.version = SAVE_VERSION; + + if(!_node) return; + + CLONING = true; + var _nid = _node.node_id; + _node.deserialize(serialize()); + _node.postDeserialize(); + _node.applyDeserialize(); + _node.node_id = _nid; + + PROJECT.nodeMap[? node_id] = self; + PROJECT.nodeMap[? _nid] = _node; + PANEL_ANIMATION.updatePropertyList(); + CLONING = false; + + onClone(_node, target); + + return _node; + } + + static onClone = function(_NewNode, target = PANEL_GRAPH.getCurrentContext()) {} + + draw_droppable = false; + static droppable = function(dragObj) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(dragObj.type == inputs[| i].drop_key) + return true; + } + return false; + } + + static onDrop = function(dragObj) { + for( var i = 0; i < ds_list_size(inputs); i++ ) { + if(dragObj.type == inputs[| i].drop_key) { + inputs[| i].setValue(dragObj.data); + previewDropAnimation(); + return; + } + } + } + + static getPreviewValue = function() { + if(preview_channel > ds_list_size(outputs)) return noone; + return outputs[| preview_channel]; + } + + static getPreviewBoundingBox = function() { + var _node = getPreviewValue(); + if(_node == undefined) return noone; + if(_node.type != VALUE_TYPE.surface) return noone; + + var _surf = _node.getValue(); + if(is_array(_surf)) + _surf = array_safe_get(_surf, preview_index, noone); + if(!is_surface(_surf)) return noone; + + return BBOX().fromWH(preview_x, preview_y, surface_get_width(_surf), surface_get_height(_surf)); + } + + static getTool = function() { + return self; + } + + static setTool = function(tool) { + if(!tool) { + isTool = false; + return; + } + + for( var i = 0; i < ds_list_size(group.nodes); i++ ) + group.nodes[| i].isTool = false; + + isTool = true; + } + + static serialize = function(scale = false, preset = false) { + var _map = {}; + //print(" > Serializing: " + name); + + if(!preset) { + _map.id = node_id; + _map.render = renderActive; + _map.name = display_name; + _map.iname = internalName; + _map.x = x; + _map.y = y; + _map.type = instanceof(self); + _map.group = group == noone? group : group.node_id; + _map.preview = previewable; + _map.tool = isTool; + } + + _map.attri = attributeSerialize(); + + if(is_dynamic_input) { + _map.input_fix_len = input_fix_len; + _map.data_length = data_length; + } + + var _inputs = []; + for(var i = 0; i < ds_list_size(inputs); i++) + array_push(_inputs, inputs[| i].serialize(scale, preset)); + _map.inputs = _inputs; + + var _outputs = []; + for(var i = 0; i < ds_list_size(outputs); i++) + array_push(_outputs, outputs[| i].serialize(scale, preset)); + _map.outputs = _outputs; + + var _trigger = []; + array_push(_trigger, inspectInput1.serialize(scale, preset)); + array_push(_trigger, inspectInput2.serialize(scale, preset)); + _map.inspectInputs = _trigger; + + doSerialize(_map); + processSerialize(_map); + return _map; + } + + static attributeSerialize = function() { return attributes; } + static doSerialize = function(_map) {} + static processSerialize = function(_map) {} + + load_scale = false; + load_map = -1; + static deserialize = function(_map, scale = false, preset = false) { + load_map = _map; + load_scale = scale; + + if(!preset) { + if(APPENDING) APPEND_MAP[? load_map.id] = node_id; + else node_id = load_map.id; + + PROJECT.nodeMap[? node_id] = self; + //print($"D Adding node {node_id} to {PROJECT.path} [{ds_map_size(PROJECT.nodeMap)}]"); + + if(struct_has(load_map, "name")) + setDisplayName(load_map.name); + + internalName = struct_try_get(load_map, "iname", internalName); + if(internalName == "") + resetInternalName(); + + _group = struct_try_get(load_map, "group", noone); + if(_group == -1) _group = noone; + + x = struct_try_get(load_map, "x"); + y = struct_try_get(load_map, "y"); + renderActive = struct_try_get(load_map, "render", true); + previewable = struct_try_get(load_map, "preview", previewable); + isTool = struct_try_get(load_map, "tool"); + } + + if(struct_has(load_map, "attri")) + attributeDeserialize(load_map.attri); + + if(is_dynamic_input) { + inputBalance(); + inputGenerate(); + } + + processDeserialize(); + + if(preset) { + postDeserialize(); + applyDeserialize(); + + triggerRender(); + } + } + + static inputBalance = function() { //Cross version compatibility for dynamic input nodes + if(!struct_has(load_map, "data_length")) + return; + + var _input_fix_len = load_map.input_fix_len; + var _data_length = load_map.data_length; + + var _dynamic_inputs = (array_length(load_map.inputs) - _input_fix_len) / _data_length; + if(frac(_dynamic_inputs) != 0) { + noti_warning("LOAD: Uneven dynamic input."); + _dynamic_inputs = ceil(_dynamic_inputs); + } + + if(_input_fix_len == input_fix_len && _data_length == data_length) + return; + + var _pad_dyna = data_length - _data_length; + + for( var i = _dynamic_inputs - 1; i >= 0; i-- ) { + var _ind = _input_fix_len + i * _data_length; + repeat(_pad_dyna) + array_insert(load_map.inputs, _ind, noone); + } + + var _pad_fix = input_fix_len - _input_fix_len; + repeat(_pad_fix) + array_insert(load_map.inputs, _input_fix_len, noone); + } + + static inputGenerate = function() { //Generate input for dynamic input nodes + if(createNewInput == noone) + return; + + var _dynamic_inputs = (array_length(load_map.inputs) - input_fix_len) / data_length; + print($"Node {name} create {_dynamic_inputs} inputs for data length {data_length}"); + repeat(_dynamic_inputs) + createNewInput(); + } + + static attributeDeserialize = function(attr) { + struct_override(attributes, attr); + } + + static postDeserialize = function() {} + static processDeserialize = function() {} + + static applyDeserialize = function(preset = false) { + var _inputs = load_map.inputs; + var amo = min(ds_list_size(inputs), array_length(_inputs)); + + for(var i = 0; i < amo; i++) { + if(inputs[| i] == noone || _inputs[i] == noone) continue; + inputs[| i].applyDeserialize(_inputs[i], load_scale, preset); + } + + if(struct_has(load_map, "outputs")) { + var _outputs = load_map.outputs; + var amo = min(ds_list_size(outputs), array_length(_outputs)); + + for(var i = 0; i < amo; i++) { + if(outputs[| i] == noone) continue; + outputs[| i].applyDeserialize(_outputs[i], load_scale, preset); + } + } + + if(struct_has(load_map, "inspectInputs")) { + var insInp = load_map.inspectInputs; + inspectInput1.applyDeserialize(insInp[0], load_scale, preset); + inspectInput2.applyDeserialize(insInp[1], load_scale, preset); + } + + doApplyDeserialize(); + } + + static doApplyDeserialize = function() {} + + static loadGroup = function(context = PANEL_GRAPH.getCurrentContext()) { + if(_group == noone) { + var c = context; + if(c != noone) c.add(self); + } else { + if(APPENDING) _group = GetAppendID(_group); + + if(ds_map_exists(PROJECT.nodeMap, _group)) { + if(struct_has(PROJECT.nodeMap[? _group], "add")) + PROJECT.nodeMap[? _group].add(self); + else { + var txt = $"Group load failed. Node ID {_group} is not a group."; + throw(txt); + } + } else { + var txt = $"Group load failed. Can't find node ID {_group}"; + throw(txt); + } + } + } + + static connect = function(log = false) { + var connected = true; + for(var i = 0; i < ds_list_size(inputs); i++) + connected &= inputs[| i].connect(log); + + if(struct_has(load_map, "inspectInputs")) { + inspectInput1.connect(log); + inspectInput2.connect(log); + } + + if(!connected) ds_queue_enqueue(CONNECTION_CONFLICT, self); + + return connected; + } + + static preConnect = function() {} + static postConnect = function() {} + + static resetAnimation = function() {} + + static cleanUp = function() { + for( var i = 0; i < ds_list_size(inputs); i++ ) + inputs[| i].cleanUp(); + for( var i = 0; i < ds_list_size(outputs); i++ ) + outputs[| i].cleanUp(); + + ds_list_destroy(inputs); + ds_list_destroy(outputs); + + ds_map_destroy(inputMap); + ds_map_destroy(outputMap); + + for( var i = 0, n = array_length(temp_surface); i < n; i++ ) + surface_free(temp_surface[i]); + + onCleanUp(); + } + + static onCleanUp = function() {} + + // helper function + static attrDepth = function() { + if(struct_has(attributes, "color_depth")) { + var form = attributes.color_depth; + if(inputs[| 0].type == VALUE_TYPE.surface) + form--; + if(form >= 0) + return array_safe_get(global.SURFACE_FORMAT, form, surface_rgba8unorm); + } + + var _s = inputs[| 0].getValue(); + while(is_array(_s) && array_length(_s)) _s = _s[0]; + if(!is_surface(_s)) + return surface_rgba8unorm; + return surface_get_format(_s); + } +} \ No newline at end of file diff --git a/#backups/scripts/pxl_server/pxl_server.gml.backup0 b/#backups/scripts/pxl_server/pxl_server.gml.backup0 new file mode 100644 index 000000000..ac9e908a2 --- /dev/null +++ b/#backups/scripts/pxl_server/pxl_server.gml.backup0 @@ -0,0 +1,200 @@ +// 2023-08-07 09:44:13 +global.NODE_SUB_CATAG = [ "input", "output" ]; + +function pxl_document_parser(prompt) { + var params = []; + + var lines = string_split(prompt, "\n"); + + for( var i = 0, n = array_length(lines); i < n; i++ ) { + var line = lines[i]; + line = functionStringClean(line); + + var eq = string_split(line, "="); + + if(array_length(eq) > 1) { + for( var j = 0; j < array_length(eq) - 1; j++ ) + array_push_unique(params, string_trim(eq[j])); + } + } + + return params; +} + +function pxl_autocomplete_server(prompt, params = []) { + var res = []; + var pr_list = ds_priority_create(); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + for( var i = 0, n = array_length(params); i < n; i++ ) { + var gl = params[i]; + + var match = string_partial_match(string_lower(gl), string_lower(prompt)); + if(match == -9999) continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 2], gl, "local", gl], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var _arr = variable_struct_get_names(PROJECT_VARIABLES); + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var gl = _arr[i]; + + var match = string_partial_match(string_lower(gl), string_lower(prompt)); + if(match == -9999) continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 0], gl, "global", gl], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = PROJECT.globalNode.value; + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(prompt)); + if(match == -9999) { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? prompt]; + ds_priority_add(pr_list, [[THEME.ac_constant, 0], k, "global", k], match); + k = ds_map_find_next(F, k); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var sp = string_splice(prompt, "."); + + if(array_length(sp) > 1) { + if(struct_has(PROJECT_VARIABLES, sp[0])) { + var _glo_var = PROJECT_VARIABLES[$ sp[0]]; + var _arr = variable_struct_get_names(_glo_var); + + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var _key = _arr[i]; + var match = string_partial_match(string_lower(_key), string_lower(sp[1])); + if(match == -9999 && sp[1] != "") + continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 0], _key, sp[0], $"{sp[0]}.{_key}"], match); + } + } else if(ds_map_exists(PROJECT.nodeNameMap, sp[0])) { + if(array_length(sp) == 2) { + for( var i = 0, n = array_length(global.NODE_SUB_CATAG); i < n; i++ ) { + var gl = global.NODE_SUB_CATAG[i]; + + var match = string_partial_match(string_lower(gl), string_lower(sp[1])); + if(match == -9999 && sp[1] != "") continue; + + ds_priority_add(pr_list, [[THEME.ac_node, i], gl, sp[0], $"{sp[0]}.{gl}"], match); + } + } else if(array_length(sp) == 3) { + var node = PROJECT.nodeNameMap[? sp[0]]; + var F = noone; + var tag = ""; + switch(string_lower(sp[1])) { + case "inputs" : + case "input" : + F = node.inputMap; + tag = "input"; + break; + case "outputs" : + case "output" : + F = node.outputMap; + tag = "output"; + break; + default : return 0; + } + + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(sp[2])); + if(match == -9999 && sp[2] != "") { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? k]; + ds_priority_add(pr_list, [fn.junction_drawing, k, sp[0] + "." + tag, $"{sp[0]}.{sp[1]}.{k}"], match); + k = ds_map_find_next(F, k); + } + } + } + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = PROJECT.nodeNameMap; + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(prompt)); + if(match == -9999) { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? prompt]; + ds_priority_add(pr_list, [[THEME.ac_constant, 1], k, "node", k], match); + k = ds_map_find_next(F, k); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = global.FUNCTIONS; + var _keys = ds_map_keys_to_array(F); + + for( var i = 0, n = array_length(_keys); i < n; i++ ) { + var _key = _keys[i]; + var match = string_partial_match(string_lower(_key), string_lower(prompt)); + if(match == -9999) + continue; + + ds_priority_add(pr_list, [[THEME.ac_function, 0], _key, "function", _key], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ds_priority_destroy(pr_list); + + return res; +} + +function pxl_function_guide_server(prompt) { + if(!ds_map_exists(global.FUNCTIONS, prompt)) return ""; + + var fn = global.FUNCTIONS[? prompt]; + var guide = prompt + "("; + for( var i = 0, n = array_length(fn[0]); i < n; i++ ) + guide += (i? ", " : "") + string(fn[0][i]); + guide += ")"; + + return guide; +} \ No newline at end of file diff --git a/#backups/scripts/pxl_server/pxl_server.gml.backup1 b/#backups/scripts/pxl_server/pxl_server.gml.backup1 new file mode 100644 index 000000000..2df7c1312 --- /dev/null +++ b/#backups/scripts/pxl_server/pxl_server.gml.backup1 @@ -0,0 +1,200 @@ +// 2023-08-07 09:44:07 +global.NODE_SUB_CATAG = [ "input", "output" ]; + +function pxl_document_parser(prompt) { + var params = []; + + var lines = string_split(prompt, "\n"); + + for( var i = 0, n = array_length(lines); i < n; i++ ) { + var line = lines[i]; + line = functionStringClean(line); + + var eq = string_split(line, "="); + + if(array_length(eq) > 1) { + for( var j = 0; j < array_length(eq) - 1; j++ ) + array_push_unique(params, string_trim(eq[j])); + } + } + + return params; +} + +function pxl_autocomplete_server(prompt, params = []) { + var res = []; + var pr_list = ds_priority_create(); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + for( var i = 0, n = array_length(params); i < n; i++ ) { + var gl = params[i]; + + var match = string_partial_match(string_lower(gl), string_lower(prompt)); + if(match == -9999) continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 2], gl, "local", gl], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var _arr = variable_struct_get_names(PROJECT_VARIABLES); + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var gl = _arr[i]; + + var match = string_partial_match(string_lower(gl), string_lower(prompt)); + if(match == -9999) continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 0], gl, "global", gl], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = PROJECT.globalNode.value; + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(prompt)); + if(match == -9999) { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? prompt]; + ds_priority_add(pr_list, [[THEME.ac_constant, 0], k, "global", k], match); + k = ds_map_find_next(F, k); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var sp = string_splice(prompt, "."); + + if(array_length(sp) > 1) { + if(struct_has(PROJECT_VARIABLES, sp[0])) { + var _glo_var = PROJECT_VARIABLES[$ sp[0]]; + var _arr = variable_struct_get_names(_glo_var); + + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var _key = _arr[i]; + var match = string_partial_match(string_lower(_key), string_lower(sp[1])); + if(match == -9999 && sp[1] != "") + continue; + + ds_priority_add(pr_list, [[THEME.ac_constant, 0], _key, sp[0], $"{sp[0]}.{_key}"], match); + } + } else if(ds_map_exists(PROJECT.nodeNameMap, sp[0])) { + if(array_length(sp) == 2) { + for( var i = 0, n = array_length(global.NODE_SUB_CATAG); i < n; i++ ) { + var gl = global.NODE_SUB_CATAG[i]; + + var match = string_partial_match(string_lower(gl), string_lower(sp[1])); + if(match == -9999 && sp[1] != "") continue; + + ds_priority_add(pr_list, [[THEME.ac_node, i], gl, sp[0], $"{sp[0]}.{gl}"], match); + } + } else if(array_length(sp) == 3) { + var node = PROJECT.nodeNameMap[? sp[0]]; + var F = noone; + var tag = ""; + switch(string_lower(sp[1])) { + case "inputs" : + case "input" : + F = node.inputMap; + tag = "input"; + break; + case "outputs" : + case "output" : + F = node.outputMap; + tag = "output"; + break; + default : return 0; + } + + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(sp[2])); + if(match == -9999 && sp[2] != "") { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? k]; + ds_priority_add(pr_list, [fn.junction_drawing, k, sp[0] + "." + tag, $"{sp[0]}.{sp[1]}.{k}"], match); + k = ds_map_find_next(F, k); + } + } + } + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = PROJECT.nodeNameMap; + var k = ds_map_find_first(F); + var a = ds_map_size(F); + repeat(a) { + var match = string_partial_match(string_lower(k), string_lower(prompt)); + if(match == -9999) { + k = ds_map_find_next(F, k); + continue; + } + + var fn = F[? prompt]; + ds_priority_add(pr_list, [[THEME.ac_constant, 1], k, "node", k], match); + k = ds_map_find_next(F, k); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ////////////////////////////////// + ds_priority_clear(pr_list); + + var F = global.FUNCTIONS; + var _keys = ds_map_keys_to_array(F); + + for( var i = 0, n = array_length(_keys); i < n; i++ ) { + var _key = _keys[i]; + var match = string_partial_match(string_lower(_key), string_lower(prompt)); + if(match == -9999) + continue; + + ds_priority_add(pr_list, [[THEME.ac_function, 0], _key, "function", _key], match); + } + + repeat(ds_priority_size(pr_list)) + array_push(res, ds_priority_delete_max(pr_list)); + + ds_priority_destroy(pr_list); + + return res; +} + +function pxl_function_guide_server(prompt) { + if(!ds_map_exists(global.FUNCTIONS, prompt)) return ""; + + var fn = global.FUNCTIONS[$ prompt]; + var guide = prompt + "("; + for( var i = 0, n = array_length(fn[0]); i < n; i++ ) + guide += (i? ", " : "") + string(fn[0][i]); + guide += ")"; + + return guide; +} \ No newline at end of file diff --git a/#backups/scripts/string_eval/string_eval.gml.backup0 b/#backups/scripts/string_eval/string_eval.gml.backup0 new file mode 100644 index 000000000..0fce3dcec --- /dev/null +++ b/#backups/scripts/string_eval/string_eval.gml.backup0 @@ -0,0 +1,841 @@ +// 2023-08-07 09:46:17 +#region data + global.LOG_EXPRESSION = false; + + global.EVALUATE_HEAD = noone; + + global.EQUATION_PRES = ds_map_create(); + global.EQUATION_PRES[? "+"] = 1; + global.EQUATION_PRES[? "-"] = 1; + global.EQUATION_PRES[? "∸"] = 9; //unary negative + global.EQUATION_PRES[? "*"] = 2; + global.EQUATION_PRES[? "/"] = 2; + global.EQUATION_PRES[? "%"] = 2; + global.EQUATION_PRES[? "$"] = 3; + + global.EQUATION_PRES[? "&"] = 5; + global.EQUATION_PRES[? "|"] = 4; + global.EQUATION_PRES[? "^"] = 3; + global.EQUATION_PRES[? "<"] = 3; + global.EQUATION_PRES[? "»"] = 6; + global.EQUATION_PRES[? "«"] = 6; + global.EQUATION_PRES[? "~"] = 9; + + global.EQUATION_PRES[? "="] = -99; + global.EQUATION_PRES[? "⊕"] = -99; //+= + global.EQUATION_PRES[? "⊖"] = -99; //-= + global.EQUATION_PRES[? "⊗"] = -99; //*= + global.EQUATION_PRES[? "⊘"] = -99; ///= + + global.EQUATION_PRES[? "⩵"] = -1; //== + global.EQUATION_PRES[? "≠"] = -1; //!= + global.EQUATION_PRES[? "<"] = 0; + global.EQUATION_PRES[? ">"] = 0; + global.EQUATION_PRES[? "≤"] = 0; + global.EQUATION_PRES[? "≥"] = 0; + + global.EQUATION_PRES[? "@"] = 5; //array accerssor symbol + + global.FUNCTIONS = ds_map_create(); + global.FUNCTIONS[? "sin"] = [ ["radian"], function(val) { return sin(val[0]); } ]; + global.FUNCTIONS[? "cos"] = [ ["radian"], function(val) { return cos(val[0]); } ]; + global.FUNCTIONS[? "tan"] = [ ["radian"], function(val) { return tan(val[0]); } ]; + + global.FUNCTIONS[? "abs"] = [ ["number"], function(val) { return abs(val[0]); } ]; + global.FUNCTIONS[? "round"] = [ ["number"], function(val) { return round(val[0]); } ]; + global.FUNCTIONS[? "ceil"] = [ ["number"], function(val) { return ceil(val[0]); } ]; + global.FUNCTIONS[? "floor"] = [ ["number"], function(val) { return floor(val[0]); } ]; + + global.FUNCTIONS[? "lerp"] = [ ["number_0", "number_1", "amount"], function(val) { return lerp(array_safe_get(val, 0), array_safe_get(val, 1), array_safe_get(val, 2)); } ]; + + global.FUNCTIONS[? "wiggle"] = [ ["time", "frequency", "octave = 1", "seed = 0"], function(val) { + return wiggle(0, 1, PROJECT.animator.frameTotal / array_safe_get(val, 1), + array_safe_get(val, 0), + array_safe_get(val, 3, 0), + array_safe_get(val, 2, 1)); + } ]; + global.FUNCTIONS[? "random"] = [ ["min = 0", "max = 1"], function(val) { + return random_range(array_safe_get(val, 0, 0), + array_safe_get(val, 1, 1)); + } ]; + global.FUNCTIONS[? "irandom"] = [ ["min = 0", "max = 1"], function(val) { + return irandom_range(array_safe_get(val, 0, 0), + array_safe_get(val, 1, 1)); + } ]; + + global.FUNCTIONS[? "range"] = [ ["length", "start = 0", "step = 1"], function(val) { + var arr = array_create(array_safe_get(val, 0, 0)); + for( var i = 0, n = array_length(arr); i < n; i++ ) + arr[i] = array_safe_get(val, 1, 0) + i * array_safe_get(val, 2, 1); + return arr; + } ]; + + globalvar PROJECT_VARIABLES; + PROJECT_VARIABLES = {}; + + PROJECT_VARIABLES.Project = {}; + PROJECT_VARIABLES.Project.frame = () => PROJECT.animator.current_frame; + PROJECT_VARIABLES.Project.progress = () => PROJECT.animator.current_frame / (PROJECT.animator.frames_total - 1); + PROJECT_VARIABLES.Project.frameTotal = () => PROJECT.animator.frames_total; + PROJECT_VARIABLES.Project.fps = () => PROJECT.animator.framerate; + PROJECT_VARIABLES.Project.time = () => PROJECT.animator.current_frame / PROJECT.animator.framerate; + PROJECT_VARIABLES.Project.name = () => filename_name_only(PROJECT.path); + + PROJECT_VARIABLES.Program = {}; + PROJECT_VARIABLES.Program.time = () => current_time / 1000; + + PROJECT_VARIABLES.Device = {}; + PROJECT_VARIABLES.Device.timeSecond = () => current_second; + PROJECT_VARIABLES.Device.timeMinute = () => current_minute; + PROJECT_VARIABLES.Device.timeHour = () => current_hour; + PROJECT_VARIABLES.Device.timeDay = () => current_day; + PROJECT_VARIABLES.Device.timeDayInWeek = () => current_weekday; + PROJECT_VARIABLES.Device.timeMonth = () => current_month; + PROJECT_VARIABLES.Device.timeYear = () => current_year; +#endregion + +function functionStringClean(fx) { + var ch = "", ind = 0, len = string_length(fx); + var _fx = "", str = false; + while(ind++ <= len) { + ch = string_char_at(fx, ind); + + if(ch == " ") { + if(str) + _fx += ch; + } else + _fx += ch; + + if(ch == "\"") + str = !str; + } + + fx = _fx; + + + fx = string_replace_all(fx, "\n", ""); + fx = string_replace_all(fx, "**", "$"); + fx = string_replace_all(fx, "<<", "«"); + fx = string_replace_all(fx, ">>", "»"); + + fx = string_replace_all(fx, "==", "⩵"); + fx = string_replace_all(fx, "!=", "≠"); + fx = string_replace_all(fx, "<>", "≠"); + fx = string_replace_all(fx, ">=", "≥"); + fx = string_replace_all(fx, "<=", "≤"); + + fx = string_replace_all(fx, "++", "⊕1"); + fx = string_replace_all(fx, "--", "⊖1"); + + fx = string_replace_all(fx, "+=", "⊕"); + fx = string_replace_all(fx, "-=", "⊖"); + fx = string_replace_all(fx, "*=", "⊗"); + fx = string_replace_all(fx, "/=", "⊘"); + + fx = string_trim(fx); + + return fx; +} + +#region evaluator + enum EXPRESS_TREE_ANIM { + none, + base_value, + animated + } + + function __funcList() constructor { + funcTrees = []; + + static addFunction = function(fn) { + array_push(funcTrees, fn); + } + + static validate = function() { + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + if(!funcTrees[i].validate()) + return false; + + return true; + } + + static isAnimated = function() { + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + if(!funcTrees[i].isAnimated()) + return false; + + return true; + } + + static eval = function(params = {}) { + //var _params = variable_clone(params); + var val = 0; + + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + val = funcTrees[i].eval(params); + + return val; + } + } + + function __funcIf() constructor { + condition = noone; + if_true = new __funcList(); + if_false = new __funcList(); + + static validate = function() { + if(condition != noone && !condition.validate()) return false; + if(if_true != noone && !if_true.validate()) return false; + if(if_false != noone && !if_false.validate()) return false; + return true; + } + + static isAnimated = function() { + if(condition != noone && !condition.isAnimated()) return false; + if(if_true != noone && !if_true.isAnimated()) return false; + if(if_false != noone && !if_false.isAnimated()) return false; + return true; + } + + static eval = function(params = {}) { + if(condition == noone) return 0; + + var res = condition.eval(params); + printIf(global.LOG_EXPRESSION, $"<<<<<< IF {res} >>>>>>"); + + if(res) return if_true == noone? 0 : if_true.eval(params); + else return if_false == noone? 0 : if_false.eval(params); + } + } + + function __funcFor() constructor { + itr_array = false; + + cond_init = noone; + cond_indx = noone; + cond_iter = noone; + cond_term = noone; + + cond_arr = noone; + + cond_step = 1; + action = new __funcList(); + + static validate = function() { + if(itr_array) { + if(cond_arr == noone || !cond_arr.validate()) return false; + } else { + if(cond_init == noone || !cond_init.validate()) return false; + if(cond_term == noone || !cond_term.validate()) return false; + } + + if(action != noone && !action.validate()) return false; + + return true; + } + + static isAnimated = function() { + if(itr_array) { + if(cond_arr == noone || !cond_arr.isAnimated()) return false; + } else { + if(cond_init == noone || !cond_init.isAnimated()) return false; + if(cond_term == noone || !cond_term.isAnimated()) return false; + } + + if(action != noone && !action.isAnimated()) return false; + + return true; + } + + static eval = function(params = {}) { + if(itr_array) { + var _arr = cond_arr.eval(params); + printIf(global.LOG_EXPRESSION, $"<<<<<< FOR EACH {_arr} >>>>>>"); + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var val = _arr[i]; + if(cond_indx != noone) + params[$ cond_indx] = i; + params[$ cond_iter] = val; + + printIf(global.LOG_EXPRESSION, $"<< ITER {i}: {cond_iter} = {val} >>"); + action.eval(params); + } + } else { + printIf(global.LOG_EXPRESSION, "<< FOR >>"); + cond_init.eval(params); + + while(cond_term.eval(params)) { + action.eval(params); + cond_iter.eval(params); + } + } + } + } + + function __funcTree(symbol, l = noone, r = noone) constructor { + self.symbol = symbol; + self.l = l; + self.r = r; + dependency = []; + + static _string = function(str) { + return string_char_at(str, 1) == "\"" && string_char_at(str, string_length(str)) == "\""; + } + + static _string_trim = function(str) { + return string_trim(str, [ "\"" ]); + } + + static getVal = function(val, params = {}, getRaw = false) { + if(is_struct(val)) return val.eval(params, getRaw); + if(is_real(val)) return val; + if(getRaw) return val; + + if(is_string(val)) val = string_trim(val); + + //printIf(global.LOG_EXPRESSION, $" [ get struct {params}[{val}] ]"); + + if(struct_has(params, val)) + return struct_try_get(params, val); + + val = string_trim(val); + + if(_string(val)) + return _string_trim(val); + + return nodeGetData(val); + } + + static _validate = function(val) { + if(is_real(val)) return true; + if(is_string(val)) return true; + if(is_struct(val)) return val.validate(); + + if(val == "value") return true; + if(PROJECT.globalNode.inputExist(val)) return true; + + var strs = string_splice(val, "."); + if(array_length(strs) < 2) return false; + + if(struct_has(PROJECT_VARIABLES, strs[0])) + return struct_has(PROJECT_VARIABLES[$ strs[0]], strs[1]); + + if(!ds_map_exists(PROJECT.nodeNameMap, strs[0])) + return false; + + array_push_unique(dependency, strs[0]); + return true; + } + + static validate = function() { + dependency = []; + + if(ds_map_exists(global.FUNCTIONS, symbol)) { + if(!is_array(l)) return false; + for( var i = 0, n = array_length(l); i < n; i++ ) + if(!_validate(l[i])) return false; + return true; + } + + switch(symbol) { + case "@": return _validate(l); + case "【": return true; + case "": return true; + } + + return _validate(l) && _validate(r); + } + + static _isAnimated = function(val) { + if(is_real(val)) return EXPRESS_TREE_ANIM.none; + if(is_struct(val)) return val._isAnimated(); + + if(val == "value") return EXPRESS_TREE_ANIM.base_value; + if(PROJECT.globalNode.inputExist(val)) { + var _inp = PROJECT.globalNode.getInput(val); + if(_inp.is_anim) return EXPRESS_TREE_ANIM.animated; + } + + return EXPRESS_TREE_ANIM.none; + } + + static isAnimated = function() { + var anim = EXPRESS_TREE_ANIM.none; + anim = max(anim, _isAnimated(l)); + if(symbol != "@") + anim = max(anim, _isAnimated(r)); + + return anim; + } + + static eval = function(params = {}, isLeft = false) { + if(ds_map_exists(global.FUNCTIONS, symbol)) { + if(!is_array(l)) return 0; + + var _fn = global.FUNCTIONS[? symbol]; + var _ev = _fn[1]; + var _l = array_create(array_length(l)); + + for( var i = 0, n = array_length(l); i < n; i++ ) + _l[i] = getVal(l[i], params); + + var res = _ev(_l); + printIf(global.LOG_EXPRESSION, $"Function {symbol}{_l} = {res}"); + printIf(global.LOG_EXPRESSION, "===================="); + + return res; + } + + var getRaw = false; + switch(symbol) { + case "=": + case "【": + getRaw = true; + } + + var v1 = getVal(l, params, getRaw || isLeft); + var v2 = getVal(r, params); + + var res = 0; + + if(symbol == "") { + res = v1; + } else if(symbol == "【") { //array builder + res = array_create(array_length(v1)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = getVal(v1[i], params); + } else if(symbol == "@") { + if(isLeft) res = [ v1, v2 ]; + else res = is_real(v2)? array_safe_get(v1, v2) : 0; + } else if(symbol == "=") { + if(is_array(v1)) { + var val = params[$ v1[0]]; + val = array_safe_set(val, v1[1], v2); + params[$ v1[0]] = val; + res = val; + } else { + params[$ v1] = v2; + res = v2; + } + } else if(is_array(v1) && !is_array(v2)) { + res = array_create(array_length(v1)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(array_safe_get(v1, i), v2); + } else if(!is_array(v1) && is_array(v2)) { + res = array_create(array_length(v2)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(v1, array_safe_get(v2, i)); + } else if(is_array(v1) && is_array(v2)) { + res = array_create(max(array_length(v1), array_length(v2))); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(array_safe_get(v1, i), array_safe_get(v2, i)); + } else + res = eval_real(v1, v2); + + var _v1_var = getVal(l, params, true); + switch(symbol) { + case "⊕": + case "⊖": + case "⊗": + case "⊘": + if(is_array(_v1_var)) { + var val = params[$ _v1_var[0]]; + val = array_safe_set(val, _v1_var[1], res); + params[$ _v1_var[0]] = val; + } else + params[$ _v1_var] = res; + + printIf(global.LOG_EXPRESSION, $"|{_v1_var}| = {v1}|{symbol}|{v2}| = {res}"); + printIf(global.LOG_EXPRESSION, $"symbol : {symbol}"); + printIf(global.LOG_EXPRESSION, $"l : | {typeof(l)} |{l}|"); + printIf(global.LOG_EXPRESSION, $"r : | {typeof(r)} |{r}|"); + printIf(global.LOG_EXPRESSION, "===================="); + break; + default: + printIf(global.LOG_EXPRESSION, $"|{v1}|{symbol}|{v2}| = {res}"); + printIf(global.LOG_EXPRESSION, $"symbol : {symbol}"); + printIf(global.LOG_EXPRESSION, $"l : | {typeof(l)} |{l}|"); + printIf(global.LOG_EXPRESSION, $"r : | {typeof(r)} |{r}|"); + printIf(global.LOG_EXPRESSION, "===================="); + break; + } + + return res; + } + + static eval_real = function(v1, v2, _symbol = symbol) { + switch(_symbol) { + case "+": + case "⊕": + if(is_string(v1) || is_string(v2)) return string(v1) + string(v2); + if(is_real(v1) && is_real(v2)) return v1 + v2; + return 0; + case "-": + case "⊖": return (is_real(v1) && is_real(v2))? v1 - v2 : 0; + case "∸": return is_real(v1)? -v1 : 0; + case "*": + case "⊗": return (is_real(v1) && is_real(v2))? v1 * v2 : 0; + case "$": return (is_real(v1) && is_real(v2))? power(v1, v2) : 0; + case "/": + case "⊘": return (is_real(v1) && is_real(v2) && v2 != 0)? v1 / v2 : 0; + case "%": return (is_real(v1) && is_real(v2) && v2 != 0)? v1 % v2 : 0; + + case "&": return (is_real(v1) && is_real(v2))? v1 & v2 : 0; + case "|": return (is_real(v1) && is_real(v2))? v1 | v2 : 0; + case "^": return (is_real(v1) && is_real(v2))? v1 ^ v2 : 0; + case "«": return (is_real(v1) && is_real(v2))? v1 << v2 : 0; + case "»": return (is_real(v1) && is_real(v2))? v1 >> v2 : 0; + case "~": return is_real(v1)? ~v1 : 0; + + case "⩵": return (is_real(v1) && is_real(v2))? v1 == v2 : 0; + case "≠": return (is_real(v1) && is_real(v2))? v1 != v2 : 0; + case "≤": return (is_real(v1) && is_real(v2))? v1 <= v2 : 0; + case "≥": return (is_real(v1) && is_real(v2))? v1 >= v2 : 0; + case ">": return (is_real(v1) && is_real(v2))? v1 > v2 : 0; + case "<": return (is_real(v1) && is_real(v2))? v1 < v2 : 0; + + case "sin" : return is_real(v1)? sin(v1) : 0; + case "cos" : return is_real(v1)? cos(v1) : 0; + case "tan" : return is_real(v1)? tan(v1) : 0; + case "abs" : return is_real(v1)? abs(v1) : 0; + case "round" : return is_real(v1)? round(v1) : 0; + case "ceil" : return is_real(v1)? ceil(v1) : 0; + case "floor" : return is_real(v1)? floor(v1) : 0; + } + + return v1; + } + } + + function functionStrip(fx) { + var el_st = 1; + var el_ed = 1; + + for( var i = 1; i <= string_length(fx); i++ ) { + var cch = string_char_at(fx, i); + if(cch == "(") { + el_st = i + 1; + break; + } + } + + for( var i = string_length(fx); i >= 1; i-- ) { + var cch = string_char_at(fx, i); + if(cch == ")") { + el_ed = i; + break; + } + } + + return string_copy(fx, el_st, el_ed - el_st) + } + + function evaluateFunctionList(fx) { + fx = string_replace_all(fx, "{", "\n{\n"); + fx = string_replace_all(fx, "}", "\n}\n"); + + var fxs = string_split(fx, "\n", true); + + var flist = new __funcList(); + + var call_st = ds_stack_create(); + var blok_st = ds_stack_create(); + ds_stack_push(call_st, flist); + + for( var i = 0, n = array_length(fxs); i < n; i++ ) { + var _fx = functionStringClean(fxs[i]); + //print($"Eval line {i}: {_fx} [stack size = {ds_stack_size(call_st)}]"); + + if(_fx == "" || _fx == "{") continue; + if(_fx == "}") { + ds_stack_pop(call_st); + continue; + } + + var _fx_sp = string_split(_fx, "("); + var _cmd = string_trim(_fx_sp[0]); + var _cond = functionStrip(_fx); + + switch(_cmd) { + case "if": + var con_if = new __funcIf(); + con_if.condition = evaluateFunctionTree(_cond); + ds_stack_top(call_st).addFunction(con_if); + ds_stack_push(call_st, con_if.if_true); + ds_stack_push(blok_st, con_if); + continue; + case "elseif": + var con_if = ds_stack_pop(blok_st); + var con_elif = new __funcIf(); + con_elif.condition = evaluateFunctionTree(_cond); + + con_if.if_false.addFunction(con_elif); + ds_stack_push(call_st, con_elif.if_true); + ds_stack_push(blok_st, con_elif); + continue; + case "else": + var con_if = ds_stack_pop(blok_st); + + ds_stack_push(call_st, con_if.if_false); + continue; + case "for": + var con_for = new __funcFor(); + var cond = string_splice(_cond, ":"); + if(array_length(cond) == 2) { + con_for.itr_array = true; + con_for.cond_arr = evaluateFunctionTree(cond[1]); + + cond[0] = string_trim(cond[0]); + var _itr = string_split(cond[0], ","); + if(array_length(_itr) == 1) + con_for.cond_iter = cond[0]; + else if(array_length(_itr) == 2) { + con_for.cond_indx = string_trim(_itr[0]); + con_for.cond_iter = string_trim(_itr[1]); + } + } else if(array_length(cond) == 3) { + con_for.itr_array = false; + con_for.cond_init = evaluateFunctionTree(cond[0]); + con_for.cond_iter = evaluateFunctionTree(cond[1]); + con_for.cond_term = evaluateFunctionTree(cond[2]); + } + ds_stack_top(call_st).addFunction(con_for); + ds_stack_push(call_st, con_for.action); + continue; + } + + if(ds_stack_empty(call_st)) { + print("Block stack empty, how?"); + } else { + var _top = ds_stack_top(call_st); + _top.addFunction(evaluateFunctionTree(_fx)); + } + } + + ds_stack_destroy(call_st); + ds_stack_destroy(blok_st); + + return flist; + } + + function evaluateFunctionTree(fx) { + static __BRACKETS = [ "(", ")", "[", "]" ]; + + var pres = global.EQUATION_PRES; + var vl = ds_stack_create(); + var op = ds_stack_create(); + var last_push = ""; + + var len = string_length(fx); + var l = 1; + var ch = ""; + var cch = ""; + var _ch = ""; + var in_str = false; + + printIf(global.LOG_EXPRESSION, $"===== Evaluating function: {fx} ====="); + + while(l <= len) { + ch = string_char_at(fx, l); + + //print($"Analyzing {ch}"); + + if(ds_map_exists(pres, ch)) { //symbol is operator + last_push = "op"; + + if(ds_stack_empty(op)) ds_stack_push(op, ch); + else { + var _top = ds_stack_top(op); + if(_top == "(" || ds_map_exists(global.FUNCTIONS, _top) || pres[? ch] > pres[? _top]) { + ds_stack_push(op, ch); + } else { + if(ch == "-" && ds_map_exists(pres, _ch)) ch = "∸"; //unary negative + + while(pres[? ch] <= pres[? ds_stack_top(op)] && !ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + ds_stack_push(op, ch); + } + } + + l++; + } else if (ch == "(") { + if(last_push == "fn") ds_stack_push(op, [ "〚", ds_stack_size(vl) ]); + else ds_stack_push(op, ch); + last_push = "op"; + l++; + } else if (ch == ")") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "(") break; + if(is_array(_top) && _top[0] == "〚") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + + ds_stack_push(vl, new __funcTree(ds_stack_pop(op), arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == "[") { + if(last_push == "vl") { + ds_stack_push(op, "@"); + ds_stack_push(op, ch); + } else + ds_stack_push(op, [ "{", ds_stack_size(vl) ]); + + last_push = "op"; + l++; + } else if (ch == "]") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "[") break; + if(is_array(_top) && _top[0] == "{") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + ds_stack_push(vl, new __funcTree("【", arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == ",") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_top(op); + if(_top == "[" || _top == "(" || (is_array(_top) && _top[0] == "{")) break; + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else { + var vsl = ""; + + while(l <= len) { + cch = string_char_at(fx, l); + if(ds_map_exists(pres, cch) || array_exists(__BRACKETS, cch)) break; + if(cch == ",") { + l++; + break; + } + + vsl += cch; + l++; + } + + if(vsl == "") continue; + + if(ds_map_exists(global.FUNCTIONS, vsl)) { //function + ds_stack_push(op, vsl); + last_push = "fn"; + } else { + vsl = string_trim(vsl); + + switch(vsl) { + case "e" : ds_stack_push(vl, 2.71828); break; + case "pi": ds_stack_push(vl, pi); break; + default : ds_stack_push(vl, isNumber(vsl)? toNumber(vsl) : vsl); break; + } + + last_push = "vl"; + } + } + + //print($"op: {ds_stack_size(op)}; vl: {ds_stack_size(vl)}"); + + _ch = ch; + } + + while(!ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + + var tree = ds_stack_empty(vl)? noone : ds_stack_pop(vl); + + ds_stack_destroy(op); + ds_stack_destroy(vl); + + if(!is_struct(tree)) + tree = new __funcTree("", tree); + + printIf(global.LOG_EXPRESSION, tree); + printIf(global.LOG_EXPRESSION, ""); + + return tree; + } + + function buildFuncTree(operator, vl) { + if(ds_stack_empty(vl)) return noone; + + if(ds_map_exists(global.FUNCTIONS, operator)) { + if(ds_stack_empty(vl)) + return noone; + + var _v1 = ds_stack_pop(vl); + return new __funcTree(operator, _v1); + } + + switch(operator) { + case "-": //deal with preceeding negative number -5 + if(ds_stack_size(vl) >= 2) { + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree("-", _v2, _v1); + } else + return new __funcTree("-", ds_stack_pop(vl), 0); + + case "@": + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + + case "+": //binary operators + case "*": + case "$": + case "/": + case "%": + + case "|": + case "&": + case "^": + case "»": + case "«": + + case "=": + case "⩵": + case "≠": + case "≤": + case "≥": + case "<": + case ">": + + case "⊕": + case "⊖": + case "⊗": + case "⊘": + + if(ds_stack_size(vl) >= 2) { + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + } + + default: return new __funcTree(operator, ds_stack_pop(vl)); + } + + return noone; + } + + function evaluateFunction(fx, params = {}) { + if(isNumber(fx)) return toNumber(fx); + return evaluateFunctionList(fx).eval(params); + } +#endregion \ No newline at end of file diff --git a/#backups/scripts/string_eval/string_eval.gml.backup1 b/#backups/scripts/string_eval/string_eval.gml.backup1 new file mode 100644 index 000000000..512a40da9 --- /dev/null +++ b/#backups/scripts/string_eval/string_eval.gml.backup1 @@ -0,0 +1,841 @@ +// 2023-08-07 09:46:13 +#region data + global.LOG_EXPRESSION = false; + + global.EVALUATE_HEAD = noone; + + global.EQUATION_PRES = ds_map_create(); + global.EQUATION_PRES[? "+"] = 1; + global.EQUATION_PRES[? "-"] = 1; + global.EQUATION_PRES[? "∸"] = 9; //unary negative + global.EQUATION_PRES[? "*"] = 2; + global.EQUATION_PRES[? "/"] = 2; + global.EQUATION_PRES[? "%"] = 2; + global.EQUATION_PRES[? "$"] = 3; + + global.EQUATION_PRES[? "&"] = 5; + global.EQUATION_PRES[? "|"] = 4; + global.EQUATION_PRES[? "^"] = 3; + global.EQUATION_PRES[? "<"] = 3; + global.EQUATION_PRES[? "»"] = 6; + global.EQUATION_PRES[? "«"] = 6; + global.EQUATION_PRES[? "~"] = 9; + + global.EQUATION_PRES[? "="] = -99; + global.EQUATION_PRES[? "⊕"] = -99; //+= + global.EQUATION_PRES[? "⊖"] = -99; //-= + global.EQUATION_PRES[? "⊗"] = -99; //*= + global.EQUATION_PRES[? "⊘"] = -99; ///= + + global.EQUATION_PRES[? "⩵"] = -1; //== + global.EQUATION_PRES[? "≠"] = -1; //!= + global.EQUATION_PRES[? "<"] = 0; + global.EQUATION_PRES[? ">"] = 0; + global.EQUATION_PRES[? "≤"] = 0; + global.EQUATION_PRES[? "≥"] = 0; + + global.EQUATION_PRES[? "@"] = 5; //array accerssor symbol + + global.FUNCTIONS = ds_map_create(); + global.FUNCTIONS[? "sin"] = [ ["radian"], function(val) { return sin(val[0]); } ]; + global.FUNCTIONS[? "cos"] = [ ["radian"], function(val) { return cos(val[0]); } ]; + global.FUNCTIONS[? "tan"] = [ ["radian"], function(val) { return tan(val[0]); } ]; + + global.FUNCTIONS[? "abs"] = [ ["number"], function(val) { return abs(val[0]); } ]; + global.FUNCTIONS[? "round"] = [ ["number"], function(val) { return round(val[0]); } ]; + global.FUNCTIONS[? "ceil"] = [ ["number"], function(val) { return ceil(val[0]); } ]; + global.FUNCTIONS[? "floor"] = [ ["number"], function(val) { return floor(val[0]); } ]; + + global.FUNCTIONS[? "lerp"] = [ ["number_0", "number_1", "amount"], function(val) { return lerp(array_safe_get(val, 0), array_safe_get(val, 1), array_safe_get(val, 2)); } ]; + + global.FUNCTIONS[? "wiggle"] = [ ["time", "frequency", "octave = 1", "seed = 0"], function(val) { + return wiggle(0, 1, PROJECT.animator.frameTotal, array_safe_get(val, 1), + array_safe_get(val, 0), + array_safe_get(val, 3, 0), + array_safe_get(val, 2, 1)); + } ]; + global.FUNCTIONS[? "random"] = [ ["min = 0", "max = 1"], function(val) { + return random_range(array_safe_get(val, 0, 0), + array_safe_get(val, 1, 1)); + } ]; + global.FUNCTIONS[? "irandom"] = [ ["min = 0", "max = 1"], function(val) { + return irandom_range(array_safe_get(val, 0, 0), + array_safe_get(val, 1, 1)); + } ]; + + global.FUNCTIONS[? "range"] = [ ["length", "start = 0", "step = 1"], function(val) { + var arr = array_create(array_safe_get(val, 0, 0)); + for( var i = 0, n = array_length(arr); i < n; i++ ) + arr[i] = array_safe_get(val, 1, 0) + i * array_safe_get(val, 2, 1); + return arr; + } ]; + + globalvar PROJECT_VARIABLES; + PROJECT_VARIABLES = {}; + + PROJECT_VARIABLES.Project = {}; + PROJECT_VARIABLES.Project.frame = () => PROJECT.animator.current_frame; + PROJECT_VARIABLES.Project.progress = () => PROJECT.animator.current_frame / (PROJECT.animator.frames_total - 1); + PROJECT_VARIABLES.Project.frameTotal = () => PROJECT.animator.frames_total; + PROJECT_VARIABLES.Project.fps = () => PROJECT.animator.framerate; + PROJECT_VARIABLES.Project.time = () => PROJECT.animator.current_frame / PROJECT.animator.framerate; + PROJECT_VARIABLES.Project.name = () => filename_name_only(PROJECT.path); + + PROJECT_VARIABLES.Program = {}; + PROJECT_VARIABLES.Program.time = () => current_time / 1000; + + PROJECT_VARIABLES.Device = {}; + PROJECT_VARIABLES.Device.timeSecond = () => current_second; + PROJECT_VARIABLES.Device.timeMinute = () => current_minute; + PROJECT_VARIABLES.Device.timeHour = () => current_hour; + PROJECT_VARIABLES.Device.timeDay = () => current_day; + PROJECT_VARIABLES.Device.timeDayInWeek = () => current_weekday; + PROJECT_VARIABLES.Device.timeMonth = () => current_month; + PROJECT_VARIABLES.Device.timeYear = () => current_year; +#endregion + +function functionStringClean(fx) { + var ch = "", ind = 0, len = string_length(fx); + var _fx = "", str = false; + while(ind++ <= len) { + ch = string_char_at(fx, ind); + + if(ch == " ") { + if(str) + _fx += ch; + } else + _fx += ch; + + if(ch == "\"") + str = !str; + } + + fx = _fx; + + + fx = string_replace_all(fx, "\n", ""); + fx = string_replace_all(fx, "**", "$"); + fx = string_replace_all(fx, "<<", "«"); + fx = string_replace_all(fx, ">>", "»"); + + fx = string_replace_all(fx, "==", "⩵"); + fx = string_replace_all(fx, "!=", "≠"); + fx = string_replace_all(fx, "<>", "≠"); + fx = string_replace_all(fx, ">=", "≥"); + fx = string_replace_all(fx, "<=", "≤"); + + fx = string_replace_all(fx, "++", "⊕1"); + fx = string_replace_all(fx, "--", "⊖1"); + + fx = string_replace_all(fx, "+=", "⊕"); + fx = string_replace_all(fx, "-=", "⊖"); + fx = string_replace_all(fx, "*=", "⊗"); + fx = string_replace_all(fx, "/=", "⊘"); + + fx = string_trim(fx); + + return fx; +} + +#region evaluator + enum EXPRESS_TREE_ANIM { + none, + base_value, + animated + } + + function __funcList() constructor { + funcTrees = []; + + static addFunction = function(fn) { + array_push(funcTrees, fn); + } + + static validate = function() { + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + if(!funcTrees[i].validate()) + return false; + + return true; + } + + static isAnimated = function() { + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + if(!funcTrees[i].isAnimated()) + return false; + + return true; + } + + static eval = function(params = {}) { + //var _params = variable_clone(params); + var val = 0; + + for( var i = 0, n = array_length(funcTrees); i < n; i++ ) + val = funcTrees[i].eval(params); + + return val; + } + } + + function __funcIf() constructor { + condition = noone; + if_true = new __funcList(); + if_false = new __funcList(); + + static validate = function() { + if(condition != noone && !condition.validate()) return false; + if(if_true != noone && !if_true.validate()) return false; + if(if_false != noone && !if_false.validate()) return false; + return true; + } + + static isAnimated = function() { + if(condition != noone && !condition.isAnimated()) return false; + if(if_true != noone && !if_true.isAnimated()) return false; + if(if_false != noone && !if_false.isAnimated()) return false; + return true; + } + + static eval = function(params = {}) { + if(condition == noone) return 0; + + var res = condition.eval(params); + printIf(global.LOG_EXPRESSION, $"<<<<<< IF {res} >>>>>>"); + + if(res) return if_true == noone? 0 : if_true.eval(params); + else return if_false == noone? 0 : if_false.eval(params); + } + } + + function __funcFor() constructor { + itr_array = false; + + cond_init = noone; + cond_indx = noone; + cond_iter = noone; + cond_term = noone; + + cond_arr = noone; + + cond_step = 1; + action = new __funcList(); + + static validate = function() { + if(itr_array) { + if(cond_arr == noone || !cond_arr.validate()) return false; + } else { + if(cond_init == noone || !cond_init.validate()) return false; + if(cond_term == noone || !cond_term.validate()) return false; + } + + if(action != noone && !action.validate()) return false; + + return true; + } + + static isAnimated = function() { + if(itr_array) { + if(cond_arr == noone || !cond_arr.isAnimated()) return false; + } else { + if(cond_init == noone || !cond_init.isAnimated()) return false; + if(cond_term == noone || !cond_term.isAnimated()) return false; + } + + if(action != noone && !action.isAnimated()) return false; + + return true; + } + + static eval = function(params = {}) { + if(itr_array) { + var _arr = cond_arr.eval(params); + printIf(global.LOG_EXPRESSION, $"<<<<<< FOR EACH {_arr} >>>>>>"); + for( var i = 0, n = array_length(_arr); i < n; i++ ) { + var val = _arr[i]; + if(cond_indx != noone) + params[$ cond_indx] = i; + params[$ cond_iter] = val; + + printIf(global.LOG_EXPRESSION, $"<< ITER {i}: {cond_iter} = {val} >>"); + action.eval(params); + } + } else { + printIf(global.LOG_EXPRESSION, "<< FOR >>"); + cond_init.eval(params); + + while(cond_term.eval(params)) { + action.eval(params); + cond_iter.eval(params); + } + } + } + } + + function __funcTree(symbol, l = noone, r = noone) constructor { + self.symbol = symbol; + self.l = l; + self.r = r; + dependency = []; + + static _string = function(str) { + return string_char_at(str, 1) == "\"" && string_char_at(str, string_length(str)) == "\""; + } + + static _string_trim = function(str) { + return string_trim(str, [ "\"" ]); + } + + static getVal = function(val, params = {}, getRaw = false) { + if(is_struct(val)) return val.eval(params, getRaw); + if(is_real(val)) return val; + if(getRaw) return val; + + if(is_string(val)) val = string_trim(val); + + //printIf(global.LOG_EXPRESSION, $" [ get struct {params}[{val}] ]"); + + if(struct_has(params, val)) + return struct_try_get(params, val); + + val = string_trim(val); + + if(_string(val)) + return _string_trim(val); + + return nodeGetData(val); + } + + static _validate = function(val) { + if(is_real(val)) return true; + if(is_string(val)) return true; + if(is_struct(val)) return val.validate(); + + if(val == "value") return true; + if(PROJECT.globalNode.inputExist(val)) return true; + + var strs = string_splice(val, "."); + if(array_length(strs) < 2) return false; + + if(struct_has(PROJECT_VARIABLES, strs[0])) + return struct_has(PROJECT_VARIABLES[$ strs[0]], strs[1]); + + if(!ds_map_exists(PROJECT.nodeNameMap, strs[0])) + return false; + + array_push_unique(dependency, strs[0]); + return true; + } + + static validate = function() { + dependency = []; + + if(ds_map_exists(global.FUNCTIONS, symbol)) { + if(!is_array(l)) return false; + for( var i = 0, n = array_length(l); i < n; i++ ) + if(!_validate(l[i])) return false; + return true; + } + + switch(symbol) { + case "@": return _validate(l); + case "【": return true; + case "": return true; + } + + return _validate(l) && _validate(r); + } + + static _isAnimated = function(val) { + if(is_real(val)) return EXPRESS_TREE_ANIM.none; + if(is_struct(val)) return val._isAnimated(); + + if(val == "value") return EXPRESS_TREE_ANIM.base_value; + if(PROJECT.globalNode.inputExist(val)) { + var _inp = PROJECT.globalNode.getInput(val); + if(_inp.is_anim) return EXPRESS_TREE_ANIM.animated; + } + + return EXPRESS_TREE_ANIM.none; + } + + static isAnimated = function() { + var anim = EXPRESS_TREE_ANIM.none; + anim = max(anim, _isAnimated(l)); + if(symbol != "@") + anim = max(anim, _isAnimated(r)); + + return anim; + } + + static eval = function(params = {}, isLeft = false) { + if(ds_map_exists(global.FUNCTIONS, symbol)) { + if(!is_array(l)) return 0; + + var _fn = global.FUNCTIONS[? symbol]; + var _ev = _fn[1]; + var _l = array_create(array_length(l)); + + for( var i = 0, n = array_length(l); i < n; i++ ) + _l[i] = getVal(l[i], params); + + var res = _ev(_l); + printIf(global.LOG_EXPRESSION, $"Function {symbol}{_l} = {res}"); + printIf(global.LOG_EXPRESSION, "===================="); + + return res; + } + + var getRaw = false; + switch(symbol) { + case "=": + case "【": + getRaw = true; + } + + var v1 = getVal(l, params, getRaw || isLeft); + var v2 = getVal(r, params); + + var res = 0; + + if(symbol == "") { + res = v1; + } else if(symbol == "【") { //array builder + res = array_create(array_length(v1)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = getVal(v1[i], params); + } else if(symbol == "@") { + if(isLeft) res = [ v1, v2 ]; + else res = is_real(v2)? array_safe_get(v1, v2) : 0; + } else if(symbol == "=") { + if(is_array(v1)) { + var val = params[$ v1[0]]; + val = array_safe_set(val, v1[1], v2); + params[$ v1[0]] = val; + res = val; + } else { + params[$ v1] = v2; + res = v2; + } + } else if(is_array(v1) && !is_array(v2)) { + res = array_create(array_length(v1)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(array_safe_get(v1, i), v2); + } else if(!is_array(v1) && is_array(v2)) { + res = array_create(array_length(v2)); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(v1, array_safe_get(v2, i)); + } else if(is_array(v1) && is_array(v2)) { + res = array_create(max(array_length(v1), array_length(v2))); + for( var i = 0, n = array_length(res); i < n; i++ ) + res[i] = eval_real(array_safe_get(v1, i), array_safe_get(v2, i)); + } else + res = eval_real(v1, v2); + + var _v1_var = getVal(l, params, true); + switch(symbol) { + case "⊕": + case "⊖": + case "⊗": + case "⊘": + if(is_array(_v1_var)) { + var val = params[$ _v1_var[0]]; + val = array_safe_set(val, _v1_var[1], res); + params[$ _v1_var[0]] = val; + } else + params[$ _v1_var] = res; + + printIf(global.LOG_EXPRESSION, $"|{_v1_var}| = {v1}|{symbol}|{v2}| = {res}"); + printIf(global.LOG_EXPRESSION, $"symbol : {symbol}"); + printIf(global.LOG_EXPRESSION, $"l : | {typeof(l)} |{l}|"); + printIf(global.LOG_EXPRESSION, $"r : | {typeof(r)} |{r}|"); + printIf(global.LOG_EXPRESSION, "===================="); + break; + default: + printIf(global.LOG_EXPRESSION, $"|{v1}|{symbol}|{v2}| = {res}"); + printIf(global.LOG_EXPRESSION, $"symbol : {symbol}"); + printIf(global.LOG_EXPRESSION, $"l : | {typeof(l)} |{l}|"); + printIf(global.LOG_EXPRESSION, $"r : | {typeof(r)} |{r}|"); + printIf(global.LOG_EXPRESSION, "===================="); + break; + } + + return res; + } + + static eval_real = function(v1, v2, _symbol = symbol) { + switch(_symbol) { + case "+": + case "⊕": + if(is_string(v1) || is_string(v2)) return string(v1) + string(v2); + if(is_real(v1) && is_real(v2)) return v1 + v2; + return 0; + case "-": + case "⊖": return (is_real(v1) && is_real(v2))? v1 - v2 : 0; + case "∸": return is_real(v1)? -v1 : 0; + case "*": + case "⊗": return (is_real(v1) && is_real(v2))? v1 * v2 : 0; + case "$": return (is_real(v1) && is_real(v2))? power(v1, v2) : 0; + case "/": + case "⊘": return (is_real(v1) && is_real(v2) && v2 != 0)? v1 / v2 : 0; + case "%": return (is_real(v1) && is_real(v2) && v2 != 0)? v1 % v2 : 0; + + case "&": return (is_real(v1) && is_real(v2))? v1 & v2 : 0; + case "|": return (is_real(v1) && is_real(v2))? v1 | v2 : 0; + case "^": return (is_real(v1) && is_real(v2))? v1 ^ v2 : 0; + case "«": return (is_real(v1) && is_real(v2))? v1 << v2 : 0; + case "»": return (is_real(v1) && is_real(v2))? v1 >> v2 : 0; + case "~": return is_real(v1)? ~v1 : 0; + + case "⩵": return (is_real(v1) && is_real(v2))? v1 == v2 : 0; + case "≠": return (is_real(v1) && is_real(v2))? v1 != v2 : 0; + case "≤": return (is_real(v1) && is_real(v2))? v1 <= v2 : 0; + case "≥": return (is_real(v1) && is_real(v2))? v1 >= v2 : 0; + case ">": return (is_real(v1) && is_real(v2))? v1 > v2 : 0; + case "<": return (is_real(v1) && is_real(v2))? v1 < v2 : 0; + + case "sin" : return is_real(v1)? sin(v1) : 0; + case "cos" : return is_real(v1)? cos(v1) : 0; + case "tan" : return is_real(v1)? tan(v1) : 0; + case "abs" : return is_real(v1)? abs(v1) : 0; + case "round" : return is_real(v1)? round(v1) : 0; + case "ceil" : return is_real(v1)? ceil(v1) : 0; + case "floor" : return is_real(v1)? floor(v1) : 0; + } + + return v1; + } + } + + function functionStrip(fx) { + var el_st = 1; + var el_ed = 1; + + for( var i = 1; i <= string_length(fx); i++ ) { + var cch = string_char_at(fx, i); + if(cch == "(") { + el_st = i + 1; + break; + } + } + + for( var i = string_length(fx); i >= 1; i-- ) { + var cch = string_char_at(fx, i); + if(cch == ")") { + el_ed = i; + break; + } + } + + return string_copy(fx, el_st, el_ed - el_st) + } + + function evaluateFunctionList(fx) { + fx = string_replace_all(fx, "{", "\n{\n"); + fx = string_replace_all(fx, "}", "\n}\n"); + + var fxs = string_split(fx, "\n", true); + + var flist = new __funcList(); + + var call_st = ds_stack_create(); + var blok_st = ds_stack_create(); + ds_stack_push(call_st, flist); + + for( var i = 0, n = array_length(fxs); i < n; i++ ) { + var _fx = functionStringClean(fxs[i]); + //print($"Eval line {i}: {_fx} [stack size = {ds_stack_size(call_st)}]"); + + if(_fx == "" || _fx == "{") continue; + if(_fx == "}") { + ds_stack_pop(call_st); + continue; + } + + var _fx_sp = string_split(_fx, "("); + var _cmd = string_trim(_fx_sp[0]); + var _cond = functionStrip(_fx); + + switch(_cmd) { + case "if": + var con_if = new __funcIf(); + con_if.condition = evaluateFunctionTree(_cond); + ds_stack_top(call_st).addFunction(con_if); + ds_stack_push(call_st, con_if.if_true); + ds_stack_push(blok_st, con_if); + continue; + case "elseif": + var con_if = ds_stack_pop(blok_st); + var con_elif = new __funcIf(); + con_elif.condition = evaluateFunctionTree(_cond); + + con_if.if_false.addFunction(con_elif); + ds_stack_push(call_st, con_elif.if_true); + ds_stack_push(blok_st, con_elif); + continue; + case "else": + var con_if = ds_stack_pop(blok_st); + + ds_stack_push(call_st, con_if.if_false); + continue; + case "for": + var con_for = new __funcFor(); + var cond = string_splice(_cond, ":"); + if(array_length(cond) == 2) { + con_for.itr_array = true; + con_for.cond_arr = evaluateFunctionTree(cond[1]); + + cond[0] = string_trim(cond[0]); + var _itr = string_split(cond[0], ","); + if(array_length(_itr) == 1) + con_for.cond_iter = cond[0]; + else if(array_length(_itr) == 2) { + con_for.cond_indx = string_trim(_itr[0]); + con_for.cond_iter = string_trim(_itr[1]); + } + } else if(array_length(cond) == 3) { + con_for.itr_array = false; + con_for.cond_init = evaluateFunctionTree(cond[0]); + con_for.cond_iter = evaluateFunctionTree(cond[1]); + con_for.cond_term = evaluateFunctionTree(cond[2]); + } + ds_stack_top(call_st).addFunction(con_for); + ds_stack_push(call_st, con_for.action); + continue; + } + + if(ds_stack_empty(call_st)) { + print("Block stack empty, how?"); + } else { + var _top = ds_stack_top(call_st); + _top.addFunction(evaluateFunctionTree(_fx)); + } + } + + ds_stack_destroy(call_st); + ds_stack_destroy(blok_st); + + return flist; + } + + function evaluateFunctionTree(fx) { + static __BRACKETS = [ "(", ")", "[", "]" ]; + + var pres = global.EQUATION_PRES; + var vl = ds_stack_create(); + var op = ds_stack_create(); + var last_push = ""; + + var len = string_length(fx); + var l = 1; + var ch = ""; + var cch = ""; + var _ch = ""; + var in_str = false; + + printIf(global.LOG_EXPRESSION, $"===== Evaluating function: {fx} ====="); + + while(l <= len) { + ch = string_char_at(fx, l); + + //print($"Analyzing {ch}"); + + if(ds_map_exists(pres, ch)) { //symbol is operator + last_push = "op"; + + if(ds_stack_empty(op)) ds_stack_push(op, ch); + else { + var _top = ds_stack_top(op); + if(_top == "(" || ds_map_exists(global.FUNCTIONS, _top) || pres[? ch] > pres[? _top]) { + ds_stack_push(op, ch); + } else { + if(ch == "-" && ds_map_exists(pres, _ch)) ch = "∸"; //unary negative + + while(pres[? ch] <= pres[? ds_stack_top(op)] && !ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + ds_stack_push(op, ch); + } + } + + l++; + } else if (ch == "(") { + if(last_push == "fn") ds_stack_push(op, [ "〚", ds_stack_size(vl) ]); + else ds_stack_push(op, ch); + last_push = "op"; + l++; + } else if (ch == ")") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "(") break; + if(is_array(_top) && _top[0] == "〚") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + + ds_stack_push(vl, new __funcTree(ds_stack_pop(op), arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == "[") { + if(last_push == "vl") { + ds_stack_push(op, "@"); + ds_stack_push(op, ch); + } else + ds_stack_push(op, [ "{", ds_stack_size(vl) ]); + + last_push = "op"; + l++; + } else if (ch == "]") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_pop(op); + if(_top == "[") break; + if(is_array(_top) && _top[0] == "{") { + var arr = []; + while(ds_stack_size(vl) > _top[1]) + array_insert(arr, 0, ds_stack_pop(vl)); + ds_stack_push(vl, new __funcTree("【", arr)); + break; + } + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else if (ch == ",") { + while(!ds_stack_empty(op)) { + var _top = ds_stack_top(op); + if(_top == "[" || _top == "(" || (is_array(_top) && _top[0] == "{")) break; + + ds_stack_push(vl, buildFuncTree(_top, vl)); + } + + last_push = "vl"; + l++; + } else { + var vsl = ""; + + while(l <= len) { + cch = string_char_at(fx, l); + if(ds_map_exists(pres, cch) || array_exists(__BRACKETS, cch)) break; + if(cch == ",") { + l++; + break; + } + + vsl += cch; + l++; + } + + if(vsl == "") continue; + + if(ds_map_exists(global.FUNCTIONS, vsl)) { //function + ds_stack_push(op, vsl); + last_push = "fn"; + } else { + vsl = string_trim(vsl); + + switch(vsl) { + case "e" : ds_stack_push(vl, 2.71828); break; + case "pi": ds_stack_push(vl, pi); break; + default : ds_stack_push(vl, isNumber(vsl)? toNumber(vsl) : vsl); break; + } + + last_push = "vl"; + } + } + + //print($"op: {ds_stack_size(op)}; vl: {ds_stack_size(vl)}"); + + _ch = ch; + } + + while(!ds_stack_empty(op)) + ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl)); + + var tree = ds_stack_empty(vl)? noone : ds_stack_pop(vl); + + ds_stack_destroy(op); + ds_stack_destroy(vl); + + if(!is_struct(tree)) + tree = new __funcTree("", tree); + + printIf(global.LOG_EXPRESSION, tree); + printIf(global.LOG_EXPRESSION, ""); + + return tree; + } + + function buildFuncTree(operator, vl) { + if(ds_stack_empty(vl)) return noone; + + if(ds_map_exists(global.FUNCTIONS, operator)) { + if(ds_stack_empty(vl)) + return noone; + + var _v1 = ds_stack_pop(vl); + return new __funcTree(operator, _v1); + } + + switch(operator) { + case "-": //deal with preceeding negative number -5 + if(ds_stack_size(vl) >= 2) { + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree("-", _v2, _v1); + } else + return new __funcTree("-", ds_stack_pop(vl), 0); + + case "@": + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + + case "+": //binary operators + case "*": + case "$": + case "/": + case "%": + + case "|": + case "&": + case "^": + case "»": + case "«": + + case "=": + case "⩵": + case "≠": + case "≤": + case "≥": + case "<": + case ">": + + case "⊕": + case "⊖": + case "⊗": + case "⊘": + + if(ds_stack_size(vl) >= 2) { + var _v1 = ds_stack_pop(vl); + var _v2 = ds_stack_pop(vl); + return new __funcTree(operator, _v2, _v1); + } + + default: return new __funcTree(operator, ds_stack_pop(vl)); + } + + return noone; + } + + function evaluateFunction(fx, params = {}) { + if(isNumber(fx)) return toNumber(fx); + return evaluateFunctionList(fx).eval(params); + } +#endregion \ No newline at end of file diff --git a/#backups/shaders/sh_blend_normal/sh_blend_normal.fsh.backup0 b/#backups/shaders/sh_blend_normal/sh_blend_normal.fsh.backup0 new file mode 100644 index 000000000..3cf007f9d --- /dev/null +++ b/#backups/shaders/sh_blend_normal/sh_blend_normal.fsh.backup0 @@ -0,0 +1,41 @@ +// 2023-08-07 09:34:22 +// +// Simple passthrough fragment shader +// +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +uniform vec2 dimension; +uniform int tile_type; + +uniform int useMask; +uniform int preserveAlpha; +uniform sampler2D mask; +uniform sampler2D fore; +uniform float opacity; + +float sampleMask() { + if(useMask == 0) return 1.; + vec4 m = texture2D( mask, v_vTexcoord ); + return (m.r + m.g + m.b) / 3. * m.a; +} + +void main() { + vec4 _col1 = texture2D( gm_BaseTexture, v_vTexcoord ); + + vec2 fore_tex = v_vTexcoord; + if(tile_type == 0) { + fore_tex = v_vTexcoord; + } else if(tile_type == 1) { + fore_tex = fract(v_vTexcoord * dimension); + } + + vec4 _col0 = texture2D( fore, fore_tex ); + _col0.a *= opacity * sampleMask(); + + float al = _col0.a + _col1.a * (1. - _col0.a); + vec4 res = ((_col0 * _col0.a) + (_col1 * _col1.a * (1. - _col0.a))) / al; + res.a = al; + + gl_FragColor = res; +} diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index d65c34fdb..77062faf6 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -1,15 +1,15 @@ { "FolderOrderSettings": [ - {"name":"_crash_handler","order":13,"path":"folders/_crash_handler.yy",}, + {"name":"_crash_handler","order":19,"path":"folders/_crash_handler.yy",}, {"name":"sprites","order":3,"path":"folders/_crash_handler/sprites.yy",}, - {"name":"_extensions","order":9,"path":"folders/_extensions.yy",}, + {"name":"_extensions","order":16,"path":"folders/_extensions.yy",}, {"name":"BBMOD","order":8,"path":"folders/_extensions/BBMOD.yy",}, {"name":"Math","order":1,"path":"folders/_extensions/BBMOD/Math.yy",}, {"name":"MAC","order":6,"path":"folders/_extensions/MAC.yy",}, - {"name":"addons","order":11,"path":"folders/addons.yy",}, + {"name":"addons","order":10,"path":"folders/addons.yy",}, {"name":"custom","order":4,"path":"folders/addons/custom.yy",}, {"name":"key displayer","order":2,"path":"folders/addons/key displayer.yy",}, - {"name":"animation_curve","order":10,"path":"folders/animation_curve.yy",}, + {"name":"animation_curve","order":9,"path":"folders/animation_curve.yy",}, {"name":"dialog","order":4,"path":"folders/dialog.yy",}, {"name":"animation","order":6,"path":"folders/dialog/animation.yy",}, {"name":"color selector","order":4,"path":"folders/dialog/color selector.yy",}, @@ -49,6 +49,7 @@ {"name":"object","order":4,"path":"folders/functions/fluid sim/Internal/Compatibility/object.yy",}, {"name":"texture","order":5,"path":"folders/functions/fluid sim/Internal/Compatibility/texture.yy",}, {"name":"view","order":6,"path":"folders/functions/fluid sim/Internal/Compatibility/view.yy",}, + {"name":null,"path":"folders/shader/_crash_handler.yy","order":16,}, {"name":"geometry","order":31,"path":"folders/functions/geometry.yy",}, {"name":"importers","order":6,"path":"folders/functions/importers.yy",}, {"name":"inputs","order":7,"path":"folders/functions/inputs.yy",}, @@ -69,14 +70,13 @@ {"name":"startup scripts","order":2,"path":"folders/main/startup scripts.yy",}, {"name":"nodes","order":3,"path":"folders/nodes.yy",}, {"name":"data","order":1,"path":"folders/nodes/data.yy",}, - {"name":"__base__","order":11,"path":"folders/nodes/data/__base__.yy",}, - {"name":"3D","order":7,"path":"folders/nodes/data/3D.yy",}, + {"name":"3D","order":8,"path":"folders/nodes/data/3D.yy",}, {"name":"primitive","order":19,"path":"folders/nodes/data/3D/primitive.yy",}, - {"name":"animation","order":5,"path":"folders/nodes/data/animation.yy",}, + {"name":"animation","order":6,"path":"folders/nodes/data/animation.yy",}, {"name":"audio","order":19,"path":"folders/nodes/data/audio.yy",}, {"name":"compose","order":14,"path":"folders/nodes/data/compose.yy",}, {"name":"armature","order":5,"path":"folders/nodes/data/compose/armature.yy",}, - {"name":"filter","order":1,"path":"folders/nodes/data/filter.yy",}, + {"name":"filter","order":2,"path":"folders/nodes/data/filter.yy",}, {"name":"colors","order":4,"path":"folders/nodes/data/filter/colors.yy",}, {"name":"combine","order":1,"path":"folders/nodes/data/filter/combine.yy",}, {"name":"conversion","order":5,"path":"folders/nodes/data/filter/conversion.yy",}, @@ -84,27 +84,27 @@ {"name":"fixes","order":6,"path":"folders/nodes/data/filter/fixes.yy",}, {"name":"warps","order":2,"path":"folders/nodes/data/filter/warps.yy",}, {"name":"fluidSim","order":17,"path":"folders/nodes/data/fluidSim.yy",}, - {"name":"generator","order":4,"path":"folders/nodes/data/generator.yy",}, + {"name":"generator","order":5,"path":"folders/nodes/data/generator.yy",}, {"name":"noise","order":14,"path":"folders/nodes/data/generator/noise.yy",}, {"name":"pattern","order":15,"path":"folders/nodes/data/generator/pattern.yy",}, - {"name":"group","order":6,"path":"folders/nodes/data/group.yy",}, + {"name":"group","order":7,"path":"folders/nodes/data/group.yy",}, {"name":"network","order":16,"path":"folders/nodes/data/IO/network.yy",}, - {"name":"iterate","order":9,"path":"folders/nodes/data/iterate.yy",}, + {"name":"iterate","order":10,"path":"folders/nodes/data/iterate.yy",}, {"name":"feedback","order":7,"path":"folders/nodes/data/iterate/feedback.yy",}, {"name":"for each","order":1,"path":"folders/nodes/data/iterate/for each.yy",}, {"name":"for filter","order":3,"path":"folders/nodes/data/iterate/for filter.yy",}, {"name":"for sort","order":5,"path":"folders/nodes/data/iterate/for sort.yy",}, {"name":"lua","order":16,"path":"folders/nodes/data/lua.yy",}, - {"name":"node","order":10,"path":"folders/nodes/data/node.yy",}, + {"name":"node","order":11,"path":"folders/nodes/data/node.yy",}, {"name":"pixel builder","order":20,"path":"folders/nodes/data/pixel builder.yy",}, {"name":"box","order":2,"path":"folders/nodes/data/pixel builder/box.yy",}, {"name":"draw","order":3,"path":"folders/nodes/data/pixel builder/draw.yy",}, {"name":"effect","order":4,"path":"folders/nodes/data/pixel builder/effect.yy",}, - {"name":"render","order":2,"path":"folders/nodes/data/render.yy",}, + {"name":"render","order":3,"path":"folders/nodes/data/render.yy",}, {"name":"rigidSim","order":15,"path":"folders/nodes/data/rigidSim.yy",}, {"name":"strandSim","order":18,"path":"folders/nodes/data/strandSim.yy",}, - {"name":"transform","order":8,"path":"folders/nodes/data/transform.yy",}, - {"name":"value","order":3,"path":"folders/nodes/data/value.yy",}, + {"name":"transform","order":9,"path":"folders/nodes/data/transform.yy",}, + {"name":"value","order":4,"path":"folders/nodes/data/value.yy",}, {"name":"atlas","order":9,"path":"folders/nodes/data/value/atlas.yy",}, {"name":"buffer","order":11,"path":"folders/nodes/data/value/buffer.yy",}, {"name":"mesh","order":7,"path":"folders/nodes/data/value/mesh.yy",}, @@ -152,6 +152,7 @@ {"name":"blur","order":38,"path":"folders/shader/blur.yy",}, {"name":"channels","order":42,"path":"folders/shader/channels.yy",}, {"name":"color picker","order":56,"path":"folders/shader/color picker.yy",}, + {"name":null,"path":"folders/nodes/data/IO.yy","order":1,}, {"name":"color selector","order":51,"path":"folders/shader/color selector.yy",}, {"name":"draw","order":39,"path":"folders/shader/draw.yy",}, {"name":"filter","order":30,"path":"folders/shader/filter.yy",}, @@ -174,10 +175,10 @@ {"name":"surface replace","order":53,"path":"folders/shader/surface replace.yy",}, {"name":"transition","order":52,"path":"folders/shader/transition.yy",}, {"name":"warp","order":41,"path":"folders/shader/warp.yy",}, - {"name":"sprites","order":12,"path":"folders/sprites.yy",}, + {"name":"sprites","order":11,"path":"folders/sprites.yy",}, {"name":"gameframe","order":2,"path":"folders/sprites/gameframe.yy",}, {"name":"misc","order":3,"path":"folders/sprites/misc.yy",}, - {"name":"VCT","order":14,"path":"folders/VCT.yy",}, + {"name":"VCT","order":12,"path":"folders/VCT.yy",}, {"name":"biterator","order":2,"path":"folders/VCT/biterator.yy",}, {"name":"widget","order":3,"path":"folders/VCT/widget.yy",}, {"name":"widgets","order":5,"path":"folders/widgets.yy",}, diff --git a/scripts/globals/globals.gml b/scripts/globals/globals.gml index 174de0294..67d512617 100644 --- a/scripts/globals/globals.gml +++ b/scripts/globals/globals.gml @@ -15,14 +15,14 @@ #region project function Project() constructor { - active = true; + active = true; /// @is {bool} - path = ""; - version = SAVE_VERSION; - seed = irandom_range(100000, 999999); + path = ""; /// @is {string} + version = SAVE_VERSION; /// @is {number} + seed = irandom_range(100000, 999999); /// @is {number} - modified = false; - readonly = false; + modified = false; /// @is {bool} + readonly = false; /// @is {bool} nodes = ds_list_create(); nodeMap = ds_map_create(); @@ -80,7 +80,8 @@ } } - globalvar PROJECTS, PROJECT; + globalvar PROJECTS; /// @is {Project[]} + globalvar PROJECT; /// @is {Project} gml_pragma("global", "__init()"); function __init() { @@ -100,10 +101,10 @@ globalvar VERSION, SAVE_VERSION, VERSION_STRING, BUILD_NUMBER; - VERSION = 11483; + VERSION = 11484; SAVE_VERSION = 11482; - VERSION_STRING = "1.15rc3"; - BUILD_NUMBER = 11483; + VERSION_STRING = "1.15rc4"; + BUILD_NUMBER = 11484; globalvar APPEND_MAP; APPEND_MAP = ds_map_create(); diff --git a/scripts/node_data/node_data.gml b/scripts/node_data/node_data.gml index e9bc99320..52895f6b1 100644 --- a/scripts/node_data/node_data.gml +++ b/scripts/node_data/node_data.gml @@ -140,9 +140,10 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) : __Node_Base(_x static createNewInput = noone; static initTooltip = function() { - if(!struct_has(global.NODE_GUIDE, instanceof(self))) return; + var type_self/*:string*/ = instanceof(self); + if(!struct_has(global.NODE_GUIDE, type_self)) return; - var _n = global.NODE_GUIDE[$ instanceof(self)]; + var _n = global.NODE_GUIDE[$ type_self]; var _ins = _n.inputs; var _ots = _n.outputs; diff --git a/scripts/pxl_server/pxl_server.gml b/scripts/pxl_server/pxl_server.gml index 9c319b8a6..0d9450132 100644 --- a/scripts/pxl_server/pxl_server.gml +++ b/scripts/pxl_server/pxl_server.gml @@ -167,18 +167,15 @@ function pxl_autocomplete_server(prompt, params = []) { ds_priority_clear(pr_list); var F = global.FUNCTIONS; - var k = ds_map_find_first(F); - var a = ds_map_size(F); - repeat(a) { - var match = string_partial_match(string_lower(k), string_lower(prompt)); - if(match == -9999) { - k = ds_map_find_next(F, k); + var _keys = ds_map_keys_to_array(F); + + for( var i = 0, n = array_length(_keys); i < n; i++ ) { + var _key = _keys[i]; + var match = string_partial_match(string_lower(_key), string_lower(prompt)); + if(match == -9999) continue; - } - var fn = F[? prompt]; - ds_priority_add(pr_list, [[THEME.ac_function, 0], k, "function", k], match); - k = ds_map_find_next(F, k); + ds_priority_add(pr_list, [[THEME.ac_function, 0], _key, "function", _key], match); } repeat(ds_priority_size(pr_list)) diff --git a/scripts/string_eval/string_eval.gml b/scripts/string_eval/string_eval.gml index d9a47954a..575d3845d 100644 --- a/scripts/string_eval/string_eval.gml +++ b/scripts/string_eval/string_eval.gml @@ -48,7 +48,7 @@ global.FUNCTIONS[? "lerp"] = [ ["number_0", "number_1", "amount"], function(val) { return lerp(array_safe_get(val, 0), array_safe_get(val, 1), array_safe_get(val, 2)); } ]; global.FUNCTIONS[? "wiggle"] = [ ["time", "frequency", "octave = 1", "seed = 0"], function(val) { - return wiggle(0, 1, array_safe_get(val, 1), + return wiggle(0, 1, PROJECT.animator.frameTotal / array_safe_get(val, 1), array_safe_get(val, 0), array_safe_get(val, 3, 0), array_safe_get(val, 2, 1)); @@ -68,29 +68,29 @@ arr[i] = array_safe_get(val, 1, 0) + i * array_safe_get(val, 2, 1); return arr; } ]; - + globalvar PROJECT_VARIABLES; PROJECT_VARIABLES = {}; PROJECT_VARIABLES.Project = {}; - PROJECT_VARIABLES.Project.frame = function() { return PROJECT.animator.current_frame; }; - PROJECT_VARIABLES.Project.progress = function() { return PROJECT.animator.current_frame / (PROJECT.animator.frames_total - 1); }; - PROJECT_VARIABLES.Project.frameTotal = function() { return PROJECT.animator.frames_total; }; - PROJECT_VARIABLES.Project.fps = function() { return PROJECT.animator.framerate; }; - PROJECT_VARIABLES.Project.time = function() { return PROJECT.animator.current_frame / PROJECT.animator.framerate; }; - PROJECT_VARIABLES.Project.name = function() { return filename_name_only(PROJECT.path); }; + PROJECT_VARIABLES.Project.frame = function() /*=>*/ {return PROJECT.animator.current_frame}; + PROJECT_VARIABLES.Project.progress = function() /*=>*/ {return PROJECT.animator.current_frame / (PROJECT.animator.frames_total - 1)}; + PROJECT_VARIABLES.Project.frameTotal = function() /*=>*/ {return PROJECT.animator.frames_total}; + PROJECT_VARIABLES.Project.fps = function() /*=>*/ {return PROJECT.animator.framerate}; + PROJECT_VARIABLES.Project.time = function() /*=>*/ {return PROJECT.animator.current_frame / PROJECT.animator.framerate}; + PROJECT_VARIABLES.Project.name = function() /*=>*/ {return filename_name_only(PROJECT.path)}; PROJECT_VARIABLES.Program = {}; - PROJECT_VARIABLES.Program.time = function() { return current_time / 1000; }; + PROJECT_VARIABLES.Program.time = function() /*=>*/ {return current_time / 1000}; PROJECT_VARIABLES.Device = {}; - PROJECT_VARIABLES.Device.timeSecond = function() { return current_second; }; - PROJECT_VARIABLES.Device.timeMinute = function() { return current_minute; }; - PROJECT_VARIABLES.Device.timeHour = function() { return current_hour; }; - PROJECT_VARIABLES.Device.timeDay = function() { return current_day; }; - PROJECT_VARIABLES.Device.timeDayInWeek = function() { return current_weekday; }; - PROJECT_VARIABLES.Device.timeMonth = function() { return current_month; }; - PROJECT_VARIABLES.Device.timeYear = function() { return current_year; }; + PROJECT_VARIABLES.Device.timeSecond = function() /*=>*/ {return current_second}; + PROJECT_VARIABLES.Device.timeMinute = function() /*=>*/ {return current_minute}; + PROJECT_VARIABLES.Device.timeHour = function() /*=>*/ {return current_hour}; + PROJECT_VARIABLES.Device.timeDay = function() /*=>*/ {return current_day}; + PROJECT_VARIABLES.Device.timeDayInWeek = function() /*=>*/ {return current_weekday}; + PROJECT_VARIABLES.Device.timeMonth = function() /*=>*/ {return current_month}; + PROJECT_VARIABLES.Device.timeYear = function() /*=>*/ {return current_year}; #endregion function functionStringClean(fx) {