Line texture, crashes fix.

This commit is contained in:
Tanasart 2023-04-21 19:08:10 +02:00
parent 965453bcc6
commit 6edb5d40a4
30 changed files with 505 additions and 247 deletions

View File

@ -400,6 +400,7 @@
{"name":"s_node_blur","order":9,"path":"sprites/s_node_blur/s_node_blur.yy",},
{"name":"textArea","order":20,"path":"scripts/textArea/textArea.yy",},
{"name":"s_node_gradient_4points","order":2,"path":"sprites/s_node_gradient_4points/s_node_gradient_4points.yy",},
{"name":"regEdit","order":9,"path":"extensions/regEdit/regEdit.yy",},
{"name":"s_node_gradient_out","order":9,"path":"sprites/s_node_gradient_out/s_node_gradient_out.yy",},
{"name":"s_node_vec3","order":8,"path":"sprites/s_node_vec3/s_node_vec3.yy",},
{"name":"s_node_strandSim_create","order":2,"path":"sprites/s_node_strandSim_create/s_node_strandSim_create.yy",},
@ -733,6 +734,7 @@
{"name":"s_node_vfx_spawn","order":2,"path":"sprites/s_node_vfx_spawn/s_node_vfx_spawn.yy",},
{"name":"texture_set_repeat","order":1,"path":"scripts/texture_set_repeat/texture_set_repeat.yy",},
{"name":"fd_rectangle_update_velocity","order":22,"path":"scripts/fd_rectangle_update_velocity/fd_rectangle_update_velocity.yy",},
{"name":"sh_draw_mapping","order":4,"path":"shaders/sh_draw_mapping/sh_draw_mapping.yy",},
{"name":"__bbox","order":5,"path":"scripts/__bbox/__bbox.yy",},
{"name":"node_shadow","order":14,"path":"scripts/node_shadow/node_shadow.yy",},
{"name":"s_node_color_data","order":3,"path":"sprites/s_node_color_data/s_node_color_data.yy",},

View File

@ -1125,6 +1125,7 @@
{"id":{"name":"s_node_blur","path":"sprites/s_node_blur/s_node_blur.yy",},},
{"id":{"name":"textArea","path":"scripts/textArea/textArea.yy",},},
{"id":{"name":"s_node_gradient_4points","path":"sprites/s_node_gradient_4points/s_node_gradient_4points.yy",},},
{"id":{"name":"regEdit","path":"extensions/regEdit/regEdit.yy",},},
{"id":{"name":"s_node_gradient_out","path":"sprites/s_node_gradient_out/s_node_gradient_out.yy",},},
{"id":{"name":"s_node_vec3","path":"sprites/s_node_vec3/s_node_vec3.yy",},},
{"id":{"name":"s_node_strandSim_create","path":"sprites/s_node_strandSim_create/s_node_strandSim_create.yy",},},
@ -1499,6 +1500,7 @@
{"id":{"name":"s_node_vfx_spawn","path":"sprites/s_node_vfx_spawn/s_node_vfx_spawn.yy",},},
{"id":{"name":"texture_set_repeat","path":"scripts/texture_set_repeat/texture_set_repeat.yy",},},
{"id":{"name":"fd_rectangle_update_velocity","path":"scripts/fd_rectangle_update_velocity/fd_rectangle_update_velocity.yy",},},
{"id":{"name":"sh_draw_mapping","path":"shaders/sh_draw_mapping/sh_draw_mapping.yy",},},
{"id":{"name":"__bbox","path":"scripts/__bbox/__bbox.yy",},},
{"id":{"name":"node_shadow","path":"scripts/node_shadow/node_shadow.yy",},},
{"id":{"name":"s_node_color_data","path":"sprites/s_node_color_data/s_node_color_data.yy",},},

Binary file not shown.

View File

@ -16,6 +16,9 @@ event_inherited();
meta_expand = false;
updating = noone;
node = noone;
data_path = "";
ugc = 0;
ugc_loading = false;
//name = get_text("new_collection_placeholder", "New collection");

View File

@ -57,7 +57,7 @@
meta.author_steam_id = STEAM_USER_ID;
if(updating == noone) {
PANEL_COLLECTION.saveCollection(meta.name, true, meta);
saveCollection(node, data_path, meta.name, true, meta);
} else {
var path = updating.path;
var map = json_load(path);
@ -77,7 +77,7 @@
steam_ugc_create_collection(updating);
ugc_loading = true;
} else if(ugc == 2) {
PANEL_COLLECTION.saveCollection(updating.path, false, updating.meta);
saveCollection(node, data_path, updating.path, false, updating.meta);
steam_ugc_update_collection(updating);
ugc_loading = true;
} else

View File

@ -2,8 +2,8 @@
event_inherited();
#region data
dialog_w = ui(640);
dialog_h = ui(480);
dialog_w = ui( 900);
dialog_h = ui( 640);
page_width = 160;
destroy_on_click_out = true;
@ -31,6 +31,21 @@ event_inherited();
pref_global = ds_list_create();
ds_list_add(pref_global, [
get_text("panel_directory", "Directory path (restart required)"),
function() { return PRESIST_PREF.path; },
new textBox(TEXTBOX_INPUT.text, function(txt) {
PRESIST_PREF.path = txt;
json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF);
},
button(function() {
PRESIST_PREF.path = get_directory(PRESIST_PREF.path);
json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF);
}, THEME.button_path_icon)
).setFont(f_p2)
.setEmpty()
]);
ds_list_add(pref_global, [
get_text("pref_show_welcome_screen", "Show welcome screen"),
"show_splash",
@ -403,6 +418,11 @@ event_inherited();
}
var name = _pref[0];
var txt = _pref[1];
if(is_method(txt))
txt = txt();
else
txt = PREF_MAP[? txt];
if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0)
continue;
@ -416,23 +436,24 @@ event_inherited();
switch(instanceof(_pref[2])) {
case "textBox" :
_pref[2].draw(x1 - ui(4), yy + th / 2, ui(88), th, PREF_MAP[? _pref[1]], _m,, fa_right, fa_center);
var widget_w = _pref[2].input == TEXTBOX_INPUT.text? ui(400) : ui(88);
_pref[2].draw(x1 - ui(4), yy + th / 2, widget_w, th, txt, _m,, fa_right, fa_center);
break;
case "vectorBox" :
_pref[2].draw(x1 - ui(4 + 200), yy, ui(200), th, PREF_MAP[? _pref[1]], _m);
_pref[2].draw(x1 - ui(4 + 200), yy, ui(200), th, txt, _m);
break;
case "checkBox" :
_pref[2].draw(x1 - ui(48), yy + th / 2, PREF_MAP[? _pref[1]], _m,, fa_center, fa_center);
_pref[2].draw(x1 - ui(48), yy + th / 2, txt, _m,, fa_center, fa_center);
break;
case "slider" :
_pref[2].draw(x1 - ui(4), yy + th / 2, ui(200), th, PREF_MAP[? _pref[1]], _m, ui(88), fa_right, fa_center);
_pref[2].draw(x1 - ui(4), yy + th / 2, ui(200), th, txt, _m, ui(88), fa_right, fa_center);
break;
case "scrollBox" :
var _w = ui(200);
var _h = th;
_pref[2].align = fa_left;
_pref[2].draw(x1 - ui(4) - _w, yy + th / 2 - _h / 2, _w, _h, PREF_MAP[? _pref[1]], _m, _r[0], _r[1]);
_pref[2].draw(x1 - ui(4) - _w, yy + th / 2 - _h / 2, _w, _h, txt, _m, _r[0], _r[1]);
break;
}
@ -506,22 +527,24 @@ event_inherited();
draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text);
draw_text(ui(16), _y + hh, name);
var dk = key.key == -1? "None" : key_get_name(key.key, key.modi);
var dk = key_get_name(key.key, key.modi);
var kw = string_width(dk);
if(hk_editing == key) {
var _mod_prs = 0;
if(key_mod_press(CTRL)) _mod_prs |= MOD_KEY.ctrl;
if(key_mod_press(SHIFT)) _mod_prs |= MOD_KEY.shift;
if(key_mod_press(ALT)) _mod_prs |= MOD_KEY.alt;
if(keyboard_check(vk_control)) _mod_prs |= MOD_KEY.ctrl;
if(keyboard_check(vk_shift)) _mod_prs |= MOD_KEY.shift;
if(keyboard_check(vk_alt)) _mod_prs |= MOD_KEY.alt;
if(keyboard_check_pressed(vk_escape)) {
key.key = -1;
key.key = 0;
key.modi = 0;
PREF_SAVE();
} else if(keyboard_check_pressed(vk_anykey)) {
key.modi = _mod_prs;
key.key = 0;
var press = false;
for(var a = 0; a < array_length(vk_list); a++) {
@ -545,10 +568,11 @@ event_inherited();
}
}
if(press) key.modi = _mod_prs;
PREF_SAVE();
}
dk = key_get_name(key.key, key.modi);
kw = string_width(dk);
draw_sprite_stretched(THEME.button_hide, 2, key_x1 - ui(40) - kw, _y + hh - ui(6), kw + ui(32), th + ui(12));
} else {
var bx = key_x1 - ui(40) - kw;
@ -559,7 +583,7 @@ event_inherited();
}
}
var cc = key.key == -1? COLORS._main_text_sub : COLORS._main_text;
var cc = (key.key == 0 && key.modi == MOD_KEY.none)? COLORS._main_text_sub : COLORS._main_text;
if(hk_editing == key) cc = COLORS._main_text_accent;
draw_set_text(f_p0, fa_right, fa_top, cc);

View File

@ -2,19 +2,45 @@
//print("===== Game Start Begin =====");
#region directory
globalvar DIRECTORY;
globalvar DIRECTORY, APP_DIRECTORY, PRESIST_PREF;
DIRECTORY = "";
PRESIST_PREF = {};
if(OS == os_windows)
DIRECTORY = environment_get_variable("userprofile") + "/AppData/Local/PixelComposer/";
else if(OS == os_macosx) {
if(OS == os_windows) {
APP_DIRECTORY = environment_get_variable("userprofile") + "\\AppData\\Local\\PixelComposer\\";
} else if(OS == os_macosx) {
var home_dir = environment_get_variable("HOME");
if(string(home_dir) == "0")
log_message("DIRECTORY", "Directory not found.");
else
DIRECTORY = string(home_dir) + "/PixelComposer/";
APP_DIRECTORY = string(home_dir) + "/PixelComposer/";
}
show_debug_message("Current working directory: " + string(DIRECTORY));
show_debug_message("App directory: " + string(APP_DIRECTORY));
if(!directory_exists(APP_DIRECTORY)) directory_create(APP_DIRECTORY);
var perstPath = APP_DIRECTORY + "persistPreference.json";
if(file_exists(perstPath)) {
PRESIST_PREF = json_load_struct(perstPath);
DIRECTORY = struct_has(PRESIST_PREF, "path")? PRESIST_PREF.path : "";
}
show_debug_message("Env directory: " + string(DIRECTORY));
var dir_valid = DIRECTORY != "" && directory_exists(DIRECTORY);
var tmp = file_text_open_write(DIRECTORY + "val_check.txt");
if(tmp == -1) {
dir_valid = false;
print("WARNING: Inaccessible directory [" + DIRECTORY + "] this may be caused by non existing folder, or Pixel Composer has no permission to open the folder.");
} else {
file_text_close(tmp);
file_delete(DIRECTORY + "val_check.txt");
}
if(!dir_valid) DIRECTORY = APP_DIRECTORY;
PRESIST_PREF.path = DIRECTORY;
json_save_struct(perstPath, PRESIST_PREF);
if(!directory_exists(DIRECTORY))
directory_create(DIRECTORY);
@ -22,7 +48,9 @@
directory_create(DIRECTORY + "temp");
METADATA = __getdefaultMetaData();
#endregion
#region Set up
PREF_LOAD();
log_clear();

View File

@ -37,27 +37,30 @@ if(OS == os_windows && gameframe_is_minimized()) exit;
if(SHIFT == KEYBOARD_STATUS.pressing) HOTKEY_MOD |= MOD_KEY.shift;
if(ALT == KEYBOARD_STATUS.pressing) HOTKEY_MOD |= MOD_KEY.alt;
if(ds_map_exists(HOTKEYS, "")) {
var l = HOTKEYS[? ""];
for(var i = 0; i < ds_list_size(l); i++) {
var hotkey = l[| i];
var name = hotkey.name;
if(!instance_exists(o_dialog_preference)) {
if(ds_map_exists(HOTKEYS, "")) {
var l = HOTKEYS[? ""];
for(var i = 0; i < ds_list_size(l); i++) {
var hotkey = l[| i];
if(hotkey.key == 0 && hotkey.modi == MOD_KEY.none) continue;
if(hotkey.key != -1 && key_press(hotkey.key, hotkey.modi)) {
hotkey.action();
break;
if(key_press(hotkey.key, hotkey.modi)) {
hotkey.action();
break;
}
}
}
}
if(ds_map_exists(HOTKEYS, FOCUS_STR)) {
var list = HOTKEYS[? FOCUS_STR];
for(var i = 0; i < ds_list_size(list); i++) {
var hotkey = list[| i];
if(ds_map_exists(HOTKEYS, FOCUS_STR)) {
var list = HOTKEYS[? FOCUS_STR];
for(var i = 0; i < ds_list_size(list); i++) {
var hotkey = list[| i];
if(hotkey.key == 0 && hotkey.modi == MOD_KEY.none) continue;
if(hotkey.key != -1 && key_press(hotkey.key, hotkey.modi)) {
hotkey.action();
break;
if(key_press(hotkey.key, hotkey.modi)) {
hotkey.action();
break;
}
}
}
}

View File

@ -46,7 +46,7 @@ function buttonClass(_onClick, _icon = noone) : widget() constructor {
var click = false;
if(hover && point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h)) {
draw_sprite_stretched_ext(spr, 1, _x, _y, _w, _h, b, 1);
if(mouse_press(mb_left, active)) {
if(mouse_release(mb_left, active)) {
trigger();
click = true;
}

View File

@ -56,4 +56,18 @@ function searchCollection(_list, _search_str, _clear_list = true) {
}
ds_stack_destroy(st);
}
function saveCollection(_node, _path, _name, save_surface = true, metadata = noone) {
if(_node == noone) return;
var _pre_name = (_path == ""? "" : _path + "/") + _name;
var ext = filename_ext(_pre_name);
_path = ext == ".pxcc"? _pre_name : _pre_name + ".pxcc";
SAVE_COLLECTION(_node, _path, save_surface, metadata, _node.group);
PANEL_COLLECTION.updated_path = _path;
PANEL_COLLECTION.updated_prog = 1;
PANEL_COLLECTION.refreshContext();
}

View File

@ -28,6 +28,16 @@
function key_mod_press(key) {
return key == KEYBOARD_STATUS.pressing;
}
function key_mod_press_index(keyindex) {
switch(keyindex) {
case MOD_KEY.alt : return ALT == KEYBOARD_STATUS.pressing;
case MOD_KEY.shift : return SHIFT == KEYBOARD_STATUS.pressing;
case MOD_KEY.ctrl : return CTRL == KEYBOARD_STATUS.pressing;
}
return false;
}
#endregion
#region widget

View File

@ -45,7 +45,7 @@ function log_crash(str) {
function log_newline() {
var path = DIRECTORY + "log.txt";
var f = file_text_open_append(path);
var f = file_text_open_write(path);
file_text_writeln(f);
file_text_close(f);
}

View File

@ -1,6 +1,7 @@
#region key map
global.KEY_STRING_MAP = ds_map_create();
global.KEY_STRING_MAP[? 0] = ""
global.KEY_STRING_MAP[? 48] = "0"
global.KEY_STRING_MAP[? 49] = "1"
global.KEY_STRING_MAP[? 50] = "2"
@ -83,11 +84,14 @@
#region get name
function key_get_name(_key, _mod) {
if(_key == 0 && _mod == MOD_KEY.none)
return "None";
var dk = "";
if(_mod & MOD_KEY.ctrl) dk += "Ctrl+";
if(_mod & MOD_KEY.shift) dk += "Shift+";
if(_mod & MOD_KEY.alt) dk += "Alt+";
switch(_key) {
case vk_space : dk += "Space"; break;
case vk_left : dk += "Left"; break;
@ -95,14 +99,14 @@
case vk_up : dk += "Up"; break;
case vk_down : dk += "Down"; break;
case vk_backspace : dk += "Backspace"; break;
case vk_tab : dk += "Tab"; break;
case vk_home : dk += "Home"; break;
case vk_end : dk += "End"; break;
case vk_delete : dk += "Delete"; break;
case vk_insert : dk += "Insert"; break;
case vk_pageup : dk += "Page Up"; break;
case vk_tab : dk += "Tab"; break;
case vk_home : dk += "Home"; break;
case vk_end : dk += "End"; break;
case vk_delete : dk += "Delete"; break;
case vk_insert : dk += "Insert"; break;
case vk_pageup : dk += "Page Up"; break;
case vk_pagedown : dk += "Page Down"; break;
case vk_pause : dk += "Pause"; break;
case vk_pause : dk += "Pause"; break;
case vk_printscreen : dk += "Printscreen"; break;
case vk_f1 : dk += "F1"; break;
case vk_f2 : dk += "F2"; break;
@ -116,7 +120,8 @@
case vk_f10 : dk += "F10"; break;
case vk_f11 : dk += "F11"; break;
case vk_f12 : dk += "F12"; break;
default :
case -1 : break;
default :
if(ds_map_exists(global.KEY_STRING_MAP, _key))
dk += global.KEY_STRING_MAP[? _key];
else
@ -124,6 +129,9 @@
break;
}
if(string_char_at(dk, string_length(dk)) == "+")
dk = string_copy(dk, 1, string_length(dk) - 1);
return dk;
}
#endregion
@ -137,7 +145,7 @@ enum MOD_KEY {
function key_press(_key, _mod) {
if(WIDGET_CURRENT) return false;
if(_key < 0 || _key == "") return false;
if(_mod == MOD_KEY.none && _key == 0) return false;
if(keyboard_check_pressed(_key) && HOTKEY_MOD == _mod)
return true;

View File

@ -216,8 +216,8 @@ function MetaDataManager() constructor {
function __getdefaultMetaData() {
var meta = new MetaDataManager();
var path = DIRECTORY + "meta.json";
if(!file_exists(path)) return meta;
var over = json_load(path);
return meta.deserialize(over);

View File

@ -74,6 +74,10 @@ function drawWidget(xx, yy, ww, _m, jun, global_var = true, _hover, _focus, _scr
cc = expValid? COLORS._main_value_positive : COLORS._main_value_negative;
}
if(global_var) {
if(string_pos(" ", jun.name)) cc = COLORS._main_value_negative;
}
draw_set_text(f_p0, fa_left, fa_center, cc);
draw_text_add(xx + ui(40), lb_y - ui(2), jun.name);
var lb_w = string_width(jun.name) + ui(32);

View File

@ -352,6 +352,8 @@ function Node(_x, _y, _group = PANEL_GRAPH.getCurrentContext()) : __Node_Base(_x
if(!active) return false;
if(!renderActive) 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;

View File

@ -16,6 +16,9 @@ function variable_editor(nodeVal) constructor {
tb_name = new textArea(TEXTBOX_INPUT.text, function(str) {
value_name = str;
value.name = str;
if(string_pos(" ", value.name))
noti_warning("Global variable name can't have space.");
UPDATE |= RENDER_TYPE.full;
});
@ -223,8 +226,13 @@ function Node_Global(_x = 0, _y = 0) : __Node_Base(_x, _y) constructor {
static step = function() {
for( var i = 0; i < ds_list_size(inputs); i++ ) {
var val = inputs[| i].getValue();
value[? inputs[| i].name] = inputs[| i];
var _inp = inputs[| i];
var val = _inp.getValue();
value[? _inp.name] = _inp;
var val = true;
if(string_pos(" ", _inp.name)) val = false;
_inp.editor.tb_name.boxColor = val? c_white : COLORS._main_value_negative;
}
}

View File

@ -73,15 +73,20 @@ function Node_Iterator_Each_Output(_x, _y, _group = noone) : Node(_x, _y, _group
}
static update = function(frame = ANIMATOR.current_frame) {
if(inputs[| 0].value_from == noone)
if(!variable_struct_exists(group, "iterated"))
return;
if(!variable_struct_exists(group, "iterated"))
if(inputs[| 0].value_from == noone) {
group.iterationUpdate();
return;
}
var ind = group.iterated;
var _val = group.outputs[| 0].getValue();
if(!is_array(_val)) return;
if(!is_array(_val)) {
group.iterationUpdate();
return;
}
_val[@ ind] = cloneValue(array_safe_get(_val, ind), inputs[| 0].getValue());

View File

@ -59,16 +59,22 @@ function Node_Iterator_Filter_Output(_x, _y, _group = noone) : Node(_x, _y, _gro
}
static update = function(frame = ANIMATOR.current_frame) {
if(inputs[| 0].value_from == noone)
if(!variable_struct_exists(group, "iterated"))
return;
if(!variable_struct_exists(group, "iterated"))
if(inputs[| 0].value_from == noone) {
group.iterationUpdate();
return;
}
var val = inputs[| 0].getValue();
var res = inputs[| 1].getValue();
var _val = group.outputs[| 0].getValue();
if(!is_array(_val)) return;
if(!is_array(_val)) {
group.iterationUpdate();
return;
}
if(res) {
var is_surf = inputs[| 0].value_from.type == VALUE_TYPE.surface;

View File

@ -40,7 +40,7 @@ function Node_Iterator_Output(_x, _y, _group = noone) : Node_Group_Output(_x, _y
if(!_to.node.renderActive) continue;
if(_to.node.active && _to.value_from != noone && _to.value_from.node == group) {
if(_to.node.isRenderable())
if(_to.node.isRenderable())
array_push(nodes, _to.node);
}
}
@ -91,7 +91,13 @@ function Node_Iterator_Output(_x, _y, _group = noone) : Node_Group_Output(_x, _y
}
static update = function(frame = ANIMATOR.current_frame) {
if(inputs[| 0].value_from == noone) return;
if(!variable_struct_exists(group, "iterated"))
return;
if(inputs[| 0].value_from == noone) {
group.iterationUpdate();
return;
}
var _val = inputs[| 0].getValue();
cache_value = cloneValue(cache_value, _val);

View File

@ -54,12 +54,22 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
inputs[| 20] = nodeValue("Segment length", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4);
inputs[| 21] = nodeValue("Texture position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ])
.setDisplay(VALUE_DISPLAY.vector);
inputs[| 22] = nodeValue("Texture rotation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0)
.setDisplay(VALUE_DISPLAY.rotation);
inputs[| 23] = nodeValue("Texture scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1 ])
.setDisplay(VALUE_DISPLAY.vector);
input_display_list = [
["Output", true], 0, 1,
["Line data", false], 6, 7, 19, 2, 20,
["Line settings", false], 17, 3, 11, 12, 8, 9, 13, 14,
["Wiggle", false], 4, 5,
["Render", false], 10, 15, 16, 18,
["Render", false], 10, 15, 16,
["Texture", false], 18, 21, 22, 23,
];
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
@ -67,6 +77,7 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
lines = [];
attribute_surface_depth();
attribute_interpolation();
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) {
draw_set_color(COLORS._main_accent);
@ -130,11 +141,15 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
var _colP = _data[15];
var _colW = _data[16];
var _1px = _data[17];
var _tex = _data[18];
var _fixL = _data[19];
var _segL = _data[20];
var _tex = _data[18];
var _texPos = _data[21];
var _texRot = _data[22];
var _texSca = _data[23];
inputs[| 14].setVisible(_cap);
var _rangeMin = min(_ratio[0], _ratio[1]);
@ -159,148 +174,160 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
var _sedIndex = 0;
_outSurf = surface_verify(_outSurf, _dim[0], _dim[1], attrDepth());
var _ox, _nx, _nx1, _oy, _ny, _ny1;
var _ow, _nw, _oa, _na, _oc, _nc;
lines = [];
if(_use_path) {
var lineLen = 1;
if(struct_has(_pat, "getLineCount"))
lineLen = _pat.getLineCount();
if(_rtMax > 0)
for( var i = 0; i < lineLen; i++ ) {
var _useDistance = _fixL && struct_has(_pat, "getLength");
var _pathLength = _useDistance? _pat.getLength(i) : 1;
if(_pathLength == 0) continue;
var _segLength = struct_has(_pat, "getAccuLength")? _pat.getAccuLength(i) : [];
var _segIndex = 0;
var _pathStr = _rtStr;
var _pathEnd = _rtMax;
var _stepLen = min(_pathEnd, 1 / _seg); //Distance to move per step
if(_stepLen <= 0.00001) continue;
var _total = _pathEnd; //Length remaining
var _total_prev = _total; //Use to prevent infinite loop
var _freeze = 0; //Use to prevent infinite loop
var _prog_curr = frac(_shift); //Pointer to the current position
var _prog_next = 0;
var _prog = _prog_curr + 1; //Record previous position to delete from _total
var _prog_total = 0; //Record how far the pointer have moved so far
var points = [];
var p;
if(_useDistance) {
_pathStr *= _pathLength;
_pathEnd *= _pathLength;
_stepLen = min(_segL, _pathEnd); //TODO: Change this to node input
_total *= _pathLength;
_total_prev = _total;
_prog_curr *= _pathLength;
}
while(_total >= 0) {
if(_useDistance) {
var segmentLength = array_safe_get(_segLength, _segIndex, 99999);
_prog_next = _prog_curr % _pathLength; //Wrap overflow path
_prog_next = min(_prog_curr + _stepLen, _pathLength, segmentLength);
if(_prog_next == segmentLength)
_segIndex = (_segIndex + 1) % array_length(_segLength);
} else {
if(_prog_curr >= 1) //Wrap overflow path
_prog_next = frac(_prog_curr);
else
_prog_next = min(_prog_curr + _stepLen, 1); //Move forward _stepLen or _total (if less) stop at 1
}
if(_useDistance)
p = _pat.getPointDistance(_prog_curr, i);
else if(!_useDistance)
p = _pat.getPointRatio(_prog_curr, i);
_nx = p.x;
_ny = p.y;
if(_total < _pathEnd) { //Do not wiggle the last point.
var _d = point_direction(_ox, _oy, _nx, _ny);
_nx += lengthdir_x(random1D(_sed + _sedIndex, -_wig, _wig), _d + 90); _sedIndex++;
_ny += lengthdir_y(random1D(_sed + _sedIndex, -_wig, _wig), _d + 90); _sedIndex++;
}
if(_prog_total >= _pathStr) { //Do not add point before range start. Do this instead of starting at _rtStr to prevent wiggle.
array_push(points, [ _nx, _ny, _prog_total / _pathEnd, _prog_curr / _pathLength ]);
}
if(_prog_next > _prog_curr) {
_prog_total += _prog_next - _prog_curr;
_total -= _prog_next - _prog_curr;
}
_stepLen = min(_stepLen, _total);
_prog_curr = _prog_next;
_ox = _nx;
_oy = _ny;
if(_total_prev == _total && ++_freeze > 16) break;
_total_prev = _total;
}
array_push(lines, points);
}
} else {
var x0, y0, x1, y1;
var _0 = point_rectangle_overlap(_dim[0], _dim[1], (_ang + 180) % 360);
var _1 = point_rectangle_overlap(_dim[0], _dim[1], _ang);
x0 = _0[0]; y0 = _0[1];
x1 = _1[0]; y1 = _1[1];
var _l = point_distance(x0, y0, x1, y1);
var _d = point_direction(x0, y0, x1, y1);
var _od = _d, _nd = _d;
var ww = _rtMax / _seg;
var _total = _rtMax;
var _prog_curr = frac(_shift) - ww;
var _prog = _prog_curr + 1;
var _prog_total = 0;
var points = [];
while(_total > 0) {
if(_prog_curr >= 1) _prog_curr = 0;
else _prog_curr = min(_prog_curr + min(_total, ww), 1);
_prog_total += min(_total, ww);
_nx = x0 + lengthdir_x(_l * _prog_curr, _d);
_ny = y0 + lengthdir_y(_l * _prog_curr, _d);
var wgLen = random1D(_sed + _sedIndex, -_wig, _wig); _sedIndex++;
_nx += lengthdir_x(wgLen, _d + 90);
_ny += lengthdir_y(wgLen, _d + 90);
if(_prog_total > _rtStr) //prevent drawing point before range start.
array_push(points, [_nx, _ny, _prog_total / _rtMax, _prog_curr]);
if(_prog_curr > _prog)
_total -= (_prog_curr - _prog);
_prog = _prog_curr;
_ox = _nx;
_oy = _ny;
}
lines = [ points ];
}
surface_set_target(_outSurf);
if(_bg) draw_clear_alpha(0, 1);
else DRAW_CLEAR
var _ox, _nx, _nx1, _oy, _ny, _ny1;
var _ow, _nw, _oa, _na, _oc, _nc;
lines = [];
if(_use_path) {
var lineLen = 1;
if(struct_has(_pat, "getLineCount"))
lineLen = _pat.getLineCount();
if(_useTex) {
var tex = surface_get_texture(_tex);
if(_rtMax > 0)
for( var i = 0; i < lineLen; i++ ) {
var _useDistance = _fixL && struct_has(_pat, "getLength");
var _pathLength = _useDistance? _pat.getLength(i) : 1;
if(_pathLength == 0) continue;
var _segLength = struct_has(_pat, "getAccuLength")? _pat.getAccuLength(i) : [];
var _segIndex = 0;
var _pathStr = _rtStr;
var _pathEnd = _rtMax;
var _stepLen = min(_pathEnd, 1 / _seg); //Distance to move per step
if(_stepLen <= 0.00001) continue;
var _total = _pathEnd; //Length remaining
var _total_prev = _total; //Use to prevent infinite loop
var _freeze = 0; //Use to prevent infinite loop
var _prog_curr = frac(_shift); //Pointer to the current position
var _prog_next = 0;
var _prog = _prog_curr + 1; //Record previous position to delete from _total
var _prog_total = 0; //Record how far the pointer have moved so far
var points = [];
var p;
if(_useDistance) {
_pathStr *= _pathLength;
_pathEnd *= _pathLength;
_stepLen = min(_segL, _pathEnd); //TODO: Change this to node input
_total *= _pathLength;
_total_prev = _total;
_prog_curr *= _pathLength;
}
while(_total >= 0) {
if(_useDistance) {
var segmentLength = array_safe_get(_segLength, _segIndex, 99999);
_prog_next = _prog_curr % _pathLength; //Wrap overflow path
_prog_next = min(_prog_curr + _stepLen, _pathLength, segmentLength);
if(_prog_next == segmentLength)
_segIndex = (_segIndex + 1) % array_length(_segLength);
} else {
if(_prog_curr >= 1) //Wrap overflow path
_prog_next = frac(_prog_curr);
else
_prog_next = min(_prog_curr + _stepLen, 1); //Move forward _stepLen or _total (if less) stop at 1
}
if(_useDistance)
p = _pat.getPointDistance(_prog_curr, i);
else if(!_useDistance)
p = _pat.getPointRatio(_prog_curr, i);
_nx = p.x;
_ny = p.y;
if(_total < _pathEnd) { //Do not wiggle the last point.
var _d = point_direction(_ox, _oy, _nx, _ny);
_nx += lengthdir_x(random1D(_sed + _sedIndex, -_wig, _wig), _d + 90); _sedIndex++;
_ny += lengthdir_y(random1D(_sed + _sedIndex, -_wig, _wig), _d + 90); _sedIndex++;
}
if(_prog_total >= _pathStr) { //Do not add point before range start. Do this instead of starting at _rtStr to prevent wiggle.
array_push(points, [ _nx, _ny, _prog_total / _pathEnd, _prog_curr / _pathLength ]);
}
if(_prog_next > _prog_curr) {
_prog_total += _prog_next - _prog_curr;
_total -= _prog_next - _prog_curr;
}
_stepLen = min(_stepLen, _total);
_prog_curr = _prog_next;
_ox = _nx;
_oy = _ny;
if(_total_prev == _total && ++_freeze > 16) break;
_total_prev = _total;
}
array_push(lines, points);
}
} else {
var x0, y0, x1, y1;
var _0 = point_rectangle_overlap(_dim[0], _dim[1], (_ang + 180) % 360);
var _1 = point_rectangle_overlap(_dim[0], _dim[1], _ang);
x0 = _0[0]; y0 = _0[1];
x1 = _1[0]; y1 = _1[1];
var _l = point_distance(x0, y0, x1, y1);
var _d = point_direction(x0, y0, x1, y1);
var _od = _d, _nd = _d;
shader_set(sh_draw_mapping);
shader_set_f("position", _texPos);
shader_set_f("rotation", degtorad(_texRot));
shader_set_f("scale", _texSca);
var ww = _rtMax / _seg;
var _total = _rtMax;
var _prog_curr = frac(_shift) - ww;
var _prog = _prog_curr + 1;
var _prog_total = 0;
var points = [];
while(_total > 0) {
if(_prog_curr >= 1) _prog_curr = 0;
else _prog_curr = min(_prog_curr + min(_total, ww), 1);
_prog_total += min(_total, ww);
_nx = x0 + lengthdir_x(_l * _prog_curr, _d);
_ny = y0 + lengthdir_y(_l * _prog_curr, _d);
var wgLen = random1D(_sed + _sedIndex, -_wig, _wig); _sedIndex++;
_nx += lengthdir_x(wgLen, _d + 90);
_ny += lengthdir_y(wgLen, _d + 90);
if(_prog_total > _rtStr) //prevent drawing point before range start.
array_push(points, [_nx, _ny, _prog_total / _rtMax, _prog_curr]);
if(_prog_curr > _prog)
_total -= (_prog_curr - _prog);
_prog = _prog_curr;
_ox = _nx;
_oy = _ny;
}
lines = [ points ];
shader_set_interpolation(_tex);
draw_primitive_begin_texture(pr_trianglestrip, tex);
}
for( var i = 0; i < array_length(lines); i++ ) {
@ -309,11 +336,6 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
var pxs = [];
if(_useTex) {
var tex = surface_get_texture(_tex);
draw_primitive_begin_texture(pr_trianglestrip, tex);
}
for( var j = 0; j < array_length(points); j++ ) {
var p0 = points[j];
var _nx = p0[0];
@ -409,8 +431,10 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons
}
}
if(_useTex)
if(_useTex) {
draw_primitive_end();
shader_reset();
}
}
surface_reset_target();

View File

@ -1487,7 +1487,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru
var animTo = ext.inputs[| j].animator;
var animLs = animTo.values;
ext.setAnim(is_anim);
ext.inputs[| j].setAnim(is_anim);
ds_list_clear(animLs);
}
@ -1506,7 +1506,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru
var animTo = ext.inputs[| 0].animator;
var animLs = animTo.values;
ext.setAnim(is_anim);
ext.inputs[| 0].setAnim(is_anim);
ds_list_clear(animLs);
for( var i = 0; i < ds_list_size(animFrom); i++ )

View File

@ -39,14 +39,16 @@ function Panel_Collection() : PanelContent() constructor {
if(meta == noone || !meta.steam) {
contentMenu = [
menuItem(get_text("panel_collection_replace", "Replace with selected"), function() {
saveCollection(_menu_node.path, false, _menu_node.meta);
saveCollection(PANEL_INSPECTOR.inspecting, _menu_node.data_path, _menu_node.path, false, _menu_node.meta);
}),
menuItem(get_text("panel_collection_edit_meta", "Edit metadata") + "...", function() {
var dia = dialogCall(o_dialog_file_name_collection, mouse_mx + ui(8), mouse_my + ui(-320));
var meta = _menu_node.getMetadata();
if(meta != noone && meta != undefined)
dia.meta = meta;
dia.node = PANEL_INSPECTOR.inspecting;
dia.data_path = data_path;
dia.updating = _menu_node;
dia.doExpand();
}),
@ -69,6 +71,8 @@ function Panel_Collection() : PanelContent() constructor {
if(meta != noone && meta != undefined)
dia.meta = meta;
dia.node = PANEL_INSPECTOR.inspecting;
dia.data_path = data_path;
dia.ugc = 1;
dia.updating = _menu_node;
dia.doExpand();
@ -81,6 +85,8 @@ function Panel_Collection() : PanelContent() constructor {
if(meta != noone && meta != undefined)
dia.meta = meta;
dia.node = PANEL_INSPECTOR.inspecting;
dia.data_path = data_path;
dia.ugc = 2;
dia.updating = _menu_node;
dia.doExpand();
@ -317,24 +323,6 @@ function Panel_Collection() : PanelContent() constructor {
steamUCGload();
}
function saveCollection(_name, save_surface = true, metadata = noone) {
if(PANEL_INSPECTOR.inspecting == noone) return;
var _pre_name = (data_path == ""? "" : data_path + "/") + _name;
var ext = filename_ext(_pre_name);
var _path = ext == ".pxcc"? _pre_name : _pre_name + ".pxcc";
if(ds_list_empty(PANEL_GRAPH.nodes_select_list))
SAVE_COLLECTION(PANEL_INSPECTOR.inspecting, _path, save_surface, metadata, PANEL_INSPECTOR.inspecting.group);
else
SAVE_COLLECTIONS(PANEL_GRAPH.nodes_select_list, _path, save_surface, metadata);
updated_path = _path;
updated_prog = 1;
refreshContext();
}
function drawContent(panel) {
draw_clear_alpha(COLORS.panel_bg_clear, 0);
@ -414,8 +402,11 @@ function Panel_Collection() : PanelContent() constructor {
if(PANEL_INSPECTOR.inspecting != noone) {
data_path = context.path;
var dia = dialogCall(o_dialog_file_name_collection, mouse_mx + ui(8), mouse_my + ui(8));
if(PANEL_INSPECTOR.inspecting)
if(PANEL_INSPECTOR.inspecting) {
dia.meta.name = PANEL_INSPECTOR.inspecting.display_name;
dia.node = PANEL_INSPECTOR.inspecting;
dia.data_path = data_path;
}
}
}
} else {

View File

@ -11,6 +11,7 @@ function Panel_Graph() : PanelContent() constructor {
grid_color = c_white;
grid_opacity = 0.05;
graph_dragging_key = false;
graph_draggable= true;
graph_dragging = false;
graph_drag_mx = 0;
@ -236,6 +237,8 @@ function Panel_Graph() : PanelContent() constructor {
addHotkey("Graph", "Copy", "C", MOD_KEY.ctrl, function() { PANEL_GRAPH.doCopy(); });
addHotkey("Graph", "Paste", "V", MOD_KEY.ctrl, function() { PANEL_GRAPH.doPaste(); });
addHotkey("Graph", "Pan", "", MOD_KEY.alt, function() { PANEL_GRAPH.graph_dragging_key = true; });
function onFocusBegin() {
PANEL_GRAPH = self;
PANEL_ANIMATION.updatePropertyList();
@ -303,7 +306,7 @@ function Panel_Graph() : PanelContent() constructor {
if(mouse_press(mb_middle)) {
_doDragging = true;
drag_key = mb_middle;
} else if(mouse_press(mb_left) && key_mod_press(ALT)) {
} else if(mouse_press(mb_left) && graph_dragging_key) {
_doDragging = true;
drag_key = mb_left;
}
@ -636,7 +639,7 @@ function Panel_Graph() : PanelContent() constructor {
var hoverable = !bool(node_dragging) && pHOVER;
for(var i = 0; i < ds_list_size(nodes_list); i++) {
var _hov = nodes_list[| i].drawConnections(gr_x, gr_y, graph_s, mx, my, hoverable, aa);
if(_hov != noone) hov = _hov;
if(_hov != noone && is_struct(hov)) hov = _hov;
}
//print("Draw connection: " + string(current_time - t)); t = current_time;
surface_reset_target();
@ -646,7 +649,7 @@ function Panel_Graph() : PanelContent() constructor {
draw_surface(connection_surface, 0, 0);
shader_reset();
junction_hovering = node_hovering == noone? hov : noone;
junction_hovering = (node_hovering == noone && is_struct(node_hovering))? hov : noone;
value_focus = noone;
#region draw node
@ -856,7 +859,7 @@ function Panel_Graph() : PanelContent() constructor {
nodes_junction_d = noone;
}
if(mouse_on_graph && mouse_press(mb_left, pFOCUS) && !key_mod_press(ALT)) {
if(mouse_on_graph && mouse_press(mb_left, pFOCUS) && !graph_dragging_key) {
if(junction_hovering && junction_hovering.draw_line_shift_hover) {
nodes_select_mx = mx;
nodes_select_my = my;
@ -1758,6 +1761,8 @@ function Panel_Graph() : PanelContent() constructor {
checkDropItem();
}
}
graph_dragging_key = false;
}
static checkDropItem = function() {

View File

@ -21,6 +21,7 @@ function Panel_Preview() : PanelContent() constructor {
do_fullView = false;
canvas_hover = true;
canvas_dragging_key = false;
canvas_dragging = false;
canvas_drag_key = 0;
canvas_drag_mx = 0;
@ -147,6 +148,8 @@ function Panel_Preview() : PanelContent() constructor {
addHotkey("Preview", "Preview window", "P", MOD_KEY.ctrl, function() { PANEL_PREVIEW.previewWindow(PANEL_PREVIEW.getNodePreview()); });
addHotkey("Preview", "Toggle grid", "G", MOD_KEY.ctrl, function() { PANEL_PREVIEW.grid_show = !PANEL_PREVIEW.grid_show; });
addHotkey("Preview", "Pan", "", MOD_KEY.alt, function() { PANEL_PREVIEW.canvas_dragging_key = true; });
function setNodePreview(node) {
if(resetViewOnDoubleClick)
do_fullView = true;
@ -221,7 +224,7 @@ function Panel_Preview() : PanelContent() constructor {
if(mouse_press(mb_middle)) {
hold = true;
canvas_drag_key = mb_middle;
} else if(mouse_press(mb_left) && key_mod_press(ALT)) {
} else if(mouse_press(mb_left) && canvas_dragging_key) {
hold = true;
canvas_drag_key = mb_left;
}
@ -251,6 +254,7 @@ function Panel_Preview() : PanelContent() constructor {
}
}
canvas_dragging_key = false;
canvas_hover = point_in_rectangle(mx, my, 0, toolbar_height, w, h - toolbar_height);
}

View File

@ -33,6 +33,8 @@
PREF_MAP[? "default_surface_side"] = 32;
PREF_MAP[? "panel_layout_file"] = "Vertical";
PREF_MAP[? "panel_graph_dragging"] = MOD_KEY.alt;
PREF_MAP[? "panel_preview_dragging"] = MOD_KEY.alt;
PREF_MAP[? "inspector_line_break_width"] = 500;

View File

@ -4,7 +4,7 @@ enum TEXTBOX_INPUT {
}
function textBox(_input, _onModify, _extras = noone) : textInput(_input, _onModify, _extras) constructor {
align = fa_right;
align = _input == TEXTBOX_INPUT.number? fa_right : fa_left;
hide = false;
font = noone;
color = COLORS._main_text;
@ -41,6 +41,16 @@ function textBox(_input, _onModify, _extras = noone) : textInput(_input, _onModi
text_surface = surface_create(1, 1);
static setFont = function(font) {
self.font = font;
return self;
}
static setEmpty = function() {
no_empty = false;
return self;
}
static activate = function() {
WIDGET_CURRENT = self;
WIDGET_CURRENT_SCROLL = parent;
@ -304,6 +314,18 @@ function textBox(_input, _onModify, _extras = noone) : textInput(_input, _onModi
w = _w;
h = _h;
switch(halign) {
case fa_left: _x = _x; break;
case fa_center: _x = _x - _w / 2; break;
case fa_right: _x = _x - _w; break;
}
switch(valign) {
case fa_top: _y = _y; break;
case fa_center: _y = _y - _h / 2; break;
case fa_bottom: _y = _y - _h; break;
}
if(extras && instanceof(extras) == "buttonClass") {
extras.setActiveFocus(hover, active);
extras.draw(_x + _w - ui(32), _y + _h / 2 - ui(32 / 2), ui(32), ui(32), _m, THEME.button_hide);
@ -360,18 +382,6 @@ function textBox(_input, _onModify, _extras = noone) : textInput(_input, _onModi
}
}
switch(halign) {
case fa_left: _x = _x; break;
case fa_center: _x = _x - _w / 2; break;
case fa_right: _x = _x - _w; break;
}
switch(valign) {
case fa_top: _y = _y; break;
case fa_center: _y = _y - _h / 2; break;
case fa_bottom: _y = _y - _h; break;
}
var tb_surf_x = _x + ui(8);
var tb_surf_y = _y;

View File

@ -0,0 +1,68 @@
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec2 position;
uniform float rotation;
uniform vec2 scale;
/////////////// SAMPLING ///////////////
const float PI = 3.14159265358979323846;
uniform int interpolation;
uniform vec2 sampleDimension;
const int RSIN_RADIUS = 1;
float sinc ( float x ) { return x == 0.? 1. : sin(x * PI) / (x * PI); }
vec4 texture2D_rsin( sampler2D texture, vec2 uv ) {
vec2 tx = 1.0 / sampleDimension;
vec2 p = uv * sampleDimension - vec2(0.5);
vec4 sum = vec4(0.0);
float weights = 0.;
for (int x = -RSIN_RADIUS; x <= RSIN_RADIUS; x++)
for (int y = -RSIN_RADIUS; y <= RSIN_RADIUS; y++) {
float a = length(vec2(float(x), float(y))) / float(RSIN_RADIUS);
if(a > 1.) continue;
float w = sinc(a * PI * tx.x) * sinc(a * PI * tx.y);
vec2 offset = vec2(float(x), float(y)) * tx;
vec4 sample = texture2D(texture, (p + offset + vec2(0.5)) / sampleDimension);
sum += w * sample;
weights += w;
}
return sum / weights;
}
vec4 texture2D_bicubic( sampler2D texture, vec2 uv ) {
uv = uv * sampleDimension + 0.5;
vec2 iuv = floor( uv );
vec2 fuv = fract( uv );
uv = iuv + fuv * fuv * (3.0 - 2.0 * fuv);
uv = (uv - 0.5) / sampleDimension;
return texture2D( texture, uv );
}
vec4 texture2Dintp( sampler2D texture, vec2 uv ) {
if(interpolation == 2) return texture2D_bicubic( texture, uv );
else if(interpolation == 3) return texture2D_rsin( texture, uv );
return texture2D( texture, uv );
}
/////////////// SAMPLING ///////////////
void main() {
vec2 cpos = v_vTexcoord - vec2(0.5);
vec2 pos;
pos.x = cpos.x * cos(rotation) - cpos.y * sin(rotation);
pos.y = cpos.x * sin(rotation) + cpos.y * cos(rotation);
pos = pos * scale + vec2(0.5) - position;
pos = fract(pos);
gl_FragColor = v_vColour * texture2Dintp( gm_BaseTexture, pos );
}

View File

@ -0,0 +1,19 @@
//
// Simple passthrough vertex shader
//
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main()
{
vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
}

View File

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