From c751d80542db5acfa8876aeb3aa689f1e6cda25c Mon Sep 17 00:00:00 2001 From: Tanasart Date: Wed, 1 May 2024 19:28:15 +0700 Subject: [PATCH] - [3D Mesh] Fix rotation manipulation error with in euler angles unit. --- .../o_dialog_preference.yy.backup0 | 1221 +++++++++++++++++ .../o_dialog_preference.yy.backup1 | 1221 +++++++++++++++++ #backups/objects/o_main/o_main.yy.backup0 | 206 +-- #backups/objects/o_main/o_main.yy.backup1 | 206 +-- .../BBMOD_Quaternion.gml.backup0 | 670 +++++++++ .../BBMOD_Quaternion.gml.backup1 | 670 +++++++++ .../scripts/__node_3d/__node_3d.gml.backup0 | 86 ++ .../scripts/__node_3d/__node_3d.gml.backup1 | 86 ++ .../__node_3d_object.gml.backup0 | 633 +++++++++ .../__node_3d_object.gml.backup1 | 633 +++++++++ .../color_selector/color_selector.gml.backup0 | 2 +- .../color_selector/color_selector.gml.backup1 | 2 +- .../scripts/d3d_bbox/d3d_bbox.gml.backup0 | 23 + .../scripts/d3d_bbox/d3d_bbox.gml.backup1 | 23 + .../scripts/d3d_object/d3d_object.gml.backup0 | 253 ++++ .../scripts/d3d_object/d3d_object.gml.backup1 | 253 ++++ #backups/scripts/globals/globals.gml.backup0 | 2 +- #backups/scripts/globals/globals.gml.backup1 | 2 +- .../node_3d_mesh_obj.gml.backup0 | 243 ++++ .../node_3d_mesh_obj.gml.backup1 | 243 ++++ .../node_export/node_export.gml.backup0 | 857 ++++++++++++ .../node_export/node_export.gml.backup1 | 857 ++++++++++++ .../node_random_tile.gml.backup0 | 129 ++ .../node_random_tile.gml.backup1 | 129 ++ .../scripts/node_value/node_value.gml.backup0 | 49 +- .../scripts/node_value/node_value.gml.backup1 | 49 +- .../scripts/obj_reader/obj_reader.gml.backup0 | 295 ++++ .../scripts/obj_reader/obj_reader.gml.backup1 | 295 ++++ .../panel_graph/panel_graph.gml.backup0 | 4 +- .../panel_graph/panel_graph.gml.backup1 | 4 +- .../panel_preview/panel_preview.gml.backup0 | 26 +- .../panel_preview/panel_preview.gml.backup1 | 26 +- .../preferences/preferences.gml.backup0 | 3 +- .../preferences/preferences.gml.backup1 | 3 +- .../quarternionBox/quarternionBox.gml.backup0 | 151 ++ .../quarternionBox/quarternionBox.gml.backup1 | 152 ++ .../shell_functions.gml.backup0 | 51 + .../string_functions.gml.backup0 | 13 +- .../string_functions.gml.backup1 | 13 +- #backups/scripts/textBox/textBox.gml.backup0 | 12 +- #backups/scripts/textBox/textBox.gml.backup1 | 12 +- objects/o_dialog_preference/Create_0.gml | 11 + objects/o_main/Draw_75.gml | 204 +-- scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml | 12 +- scripts/__node_3d/__node_3d.gml | 11 +- scripts/__node_3d_object/__node_3d_object.gml | 10 +- scripts/d3d_bbox/d3d_bbox.gml | 2 +- scripts/d3d_object/d3d_object.gml | 20 +- scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml | 41 +- scripts/node_export/node_export.gml | 8 +- scripts/node_grid/node_grid.gml | 2 +- scripts/node_grid_hex/node_grid_hex.gml | 2 +- scripts/node_grid_tri/node_grid_tri.gml | 2 +- .../node_herringbone_tile.gml | 2 +- .../node_pytagorean_tile.gml | 2 +- scripts/node_random_tile/node_random_tile.gml | 2 +- scripts/node_shadow_cast/node_shadow_cast.gml | 2 +- scripts/node_shape/node_shape.gml | 2 +- scripts/node_value/node_value.gml | 47 +- scripts/obj_reader/obj_reader.gml | 45 +- scripts/panel_graph/panel_graph.gml | 2 +- scripts/panel_preview/panel_preview.gml | 24 +- scripts/preferences/preferences.gml | 1 + scripts/quarternionBox/quarternionBox.gml | 36 +- scripts/shell_functions/shell_functions.gml | 4 +- scripts/string_functions/string_functions.gml | 11 +- scripts/textBox/textBox.gml | 10 +- 67 files changed, 9791 insertions(+), 532 deletions(-) create mode 100644 #backups/objects/o_dialog_preference/o_dialog_preference.yy.backup0 create mode 100644 #backups/objects/o_dialog_preference/o_dialog_preference.yy.backup1 create mode 100644 #backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup0 create mode 100644 #backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup1 create mode 100644 #backups/scripts/__node_3d/__node_3d.gml.backup0 create mode 100644 #backups/scripts/__node_3d/__node_3d.gml.backup1 create mode 100644 #backups/scripts/__node_3d_object/__node_3d_object.gml.backup0 create mode 100644 #backups/scripts/__node_3d_object/__node_3d_object.gml.backup1 create mode 100644 #backups/scripts/d3d_bbox/d3d_bbox.gml.backup0 create mode 100644 #backups/scripts/d3d_bbox/d3d_bbox.gml.backup1 create mode 100644 #backups/scripts/d3d_object/d3d_object.gml.backup0 create mode 100644 #backups/scripts/d3d_object/d3d_object.gml.backup1 create mode 100644 #backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup0 create mode 100644 #backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup1 create mode 100644 #backups/scripts/node_export/node_export.gml.backup0 create mode 100644 #backups/scripts/node_export/node_export.gml.backup1 create mode 100644 #backups/scripts/node_random_tile/node_random_tile.gml.backup0 create mode 100644 #backups/scripts/node_random_tile/node_random_tile.gml.backup1 create mode 100644 #backups/scripts/obj_reader/obj_reader.gml.backup0 create mode 100644 #backups/scripts/obj_reader/obj_reader.gml.backup1 create mode 100644 #backups/scripts/quarternionBox/quarternionBox.gml.backup0 create mode 100644 #backups/scripts/quarternionBox/quarternionBox.gml.backup1 create mode 100644 #backups/scripts/shell_functions/shell_functions.gml.backup0 diff --git a/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup0 b/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup0 new file mode 100644 index 000000000..5c45d257d --- /dev/null +++ b/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup0 @@ -0,0 +1,1221 @@ +// 2024-05-01 15:59:00 +#event properties (no comments/etc. here are saved) +parent_index = _p_dialog; +uses_physics = false; + +#event create init +event_inherited(); + +#region data + dialog_w = ui(900); + dialog_h = ui(640); + page_width = ui(160); + + destroy_on_click_out = true; + destroy_on_escape = false; + + should_restart = false; +#endregion + +#region resize + dialog_resizable = true; + dialog_w_min = ui(640); + dialog_h_min = ui(480); + + onResize = function() { + sp_page.resize(page_width - ui(4), dialog_h - ui(title_height + padding)); + + sp_pref.resize( dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding)); + sp_hotkey.resize(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding)); + sp_colors.resize(dialog_w - ui(padding + padding) - page_width, dialog_h - (title_height + ui(padding + 40))); + } +#endregion + +#region pages + page_current = 0; + page[0] = __txtx("pref_pages_general", "General"); + page[1] = __txtx("pref_pages_interface", "Interface"); + page[2] = __txt("Nodes"); + page[3] = __txt("Theme"); + page[4] = __txt("Hotkeys"); + + section_current = ""; + sections = array_create(array_length(page)); + + sp_page = new scrollPane(page_width - ui(4), dialog_h - ui(title_height + padding), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 1); + var ww = sp_page.surface_w; + var hh = 0; + + var yl = _y; + var hg = line_get_height(f_p0, 16); + var hs = line_get_height(f_p1, 8); + + for(var i = 0; i < array_length(page); i++) { + if(i == page_current) draw_set_text(f_p0b, fa_left, fa_center, COLORS._main_text_accent); + else draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text_inner); + + if(sHOVER && point_in_rectangle(_m[0], _m[1], 0, yl, ww, yl + hg)) { + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yl, ww, hg, CDEF.main_white, 1); + + if(i != page_current && mouse_click(mb_left, sFOCUS)) { + page_current = i; + sp_pref.setScroll(0); + } + } + + draw_text_add(ui(8), yl + hg / 2, page[i]); + yl += hg; + hh += hg; + + if(i == page_current && sections[i] != 0) { + for( var j = 0, m = array_length(sections[i]); j < m; j++ ) { + var sect = sections[i][j]; + + draw_set_text(f_p1, fa_left, fa_center, section_current == sect[0]? COLORS._main_text : COLORS._main_text_sub); + + if(sHOVER && point_in_rectangle(_m[0], _m[1], 0, yl, ww, yl + hs - 1)) { + if(mouse_press(mb_left, sFOCUS)) + sect[1].scroll_y_to = -sect[2]; + + draw_set_color(COLORS._main_text); + } + + var _xx = ui(8 + 16); + var sect_title = sect[0]; + var sp = string_split(sect_title, " "); + if(sp[0] == "-") { + _xx += ui(16); + sect_title = string_replace(sect_title, "- ", ""); + } + + draw_text_add(_xx, yl + hs / 2, __txt(sect_title)); + + yl += hs; + hh += hs; + } + } + } + + return hh; + }); + + sp_page.always_scroll = true; + sp_page.show_scroll = false; +#endregion + +#region general + pref_global = ds_list_create(); + + ds_list_add(pref_global, __txt("Paths")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item( + __txtx("pref_directory", "Main directory path" + "*"), + new textBox(TEXTBOX_INPUT.text, function(txt) { + PRESIST_PREF.path = txt; + json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF); + }) + .setSideButton(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(), + function() { return PRESIST_PREF.path; }, + function(val) { PRESIST_PREF.path = val; json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF); }, + APP_DIRECTORY, + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_temp", "Temp directory path" + "*"), + "temp_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.temp_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.temp_path = get_directory(PREFERENCES.temp_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, __txt("Inputs")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_double_click_delay", "Double click delay"), + "double_click_delay", + slider(0, 1, 0.01, function(val) { + PREFERENCES.double_click_delay = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_mouse_wheel_speed", "Scroll speed"), + "mouse_wheel_speed", + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.mouse_wheel_speed = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_keyboard_hold_start", "Keyboard hold start"), + "keyboard_repeat_start", + slider(0, 1, 0.01, function(val) { + PREFERENCES.keyboard_repeat_start = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_keyboard_repeat_delay", "Keyboard repeat delay"), + "keyboard_repeat_speed", + slider(0, 1, 0.01, function(val) { + PREFERENCES.keyboard_repeat_speed = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_expand_hovering_panel", "Expand hovering panel"), + "expand_hover", + new checkBox(function() { + PREFERENCES.expand_hover = !PREFERENCES.expand_hover; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Save/Load")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_save_file_minify", "Minify save file"), + "save_file_minify", + new checkBox(function() { + PREFERENCES.save_file_minify = !PREFERENCES.save_file_minify; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Crash")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_legacy_exception", "Use legacy exception handler"), + "use_legacy_exception", + new checkBox(function() { + PREFERENCES.use_legacy_exception = !PREFERENCES.use_legacy_exception; + PREF_APPLY(); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_crash_dialog", "Show dialog after crash"), + "show_crash_dialog", + new checkBox(function() { + PREFERENCES.show_crash_dialog = !PREFERENCES.show_crash_dialog; + PREF_APPLY(); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Misc")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_clear_temp", "Clear temp file on close"), + "clear_temp_on_close", + new checkBox(function() { + PREFERENCES.clear_temp_on_close = !PREFERENCES.clear_temp_on_close; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_enable_test_mode", "Enable developer mode" + "*"), + "test_mode", + new checkBox(function() { + PREFERENCES.test_mode = !PREFERENCES.test_mode; + should_restart = true; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Libraries")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_ImageMagick", "ImageMagick path" + "*"), + "ImageMagick_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.ImageMagick_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.ImageMagick_path = get_directory(PREFERENCES.ImageMagick_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_webp", "Webp path" + "*"), + "webp_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.webp_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.webp_path = get_directory(PREFERENCES.webp_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_gifski", "Gifski path" + "*"), + "gifski_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.gifski_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.gifski_path = get_directory(PREFERENCES.gifski_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_FFmpeg", "FFmpeg path" + "*"), + "ffmpeg_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.gifski_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.ffmpeg_path = get_directory(PREFERENCES.ffmpeg_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + +#endregion + +#region interface + pref_appr = ds_list_create(); + + ds_list_add(pref_appr, __txt("Interface")); /////////////////////////////////////////////////////////////// Interface + + PREFERENCES._display_scaling = PREFERENCES.display_scaling; + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item( + __txtx("pref_gui_scaling", "GUI scaling*"), + slider(0.5, 2, 0.01, function(val) { + PREFERENCES._display_scaling = val; + should_restart = true; + + }, function() { + PREFERENCES._display_scaling = max(PREFERENCES._display_scaling, 0.5); + resetScale(PREFERENCES._display_scaling, true); + should_restart = true; + }), + + function() { return PREFERENCES._display_scaling; }, + function(val) { + + PREFERENCES._display_scaling = val; + resetScale(PREFERENCES._display_scaling, true); + should_restart = true; + }, + 1, + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_ui_frame_rate", "UI frame rate"), + "ui_framerate", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.ui_framerate = max(15, round(real(str))); + game_set_speed(PREFERENCES.ui_framerate, gamespeed_fps); + PREF_SAVE(); + }) + )); + + locals = []; + var f = file_find_first(DIRECTORY + "Locale/*", fa_directory); + while(f != "") { + if(directory_exists(DIRECTORY + "Locale/" + f)) { + if(f != "_extend") array_push(locals, f); + } + f = file_find_next(); + } + file_find_close(); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_interface_language", "Interface Language" + "*"), + "local", + new scrollBox(locals, function(str) { + if(str < 0) return; + PREFERENCES.local = locals[str]; + PREF_SAVE(); + }, false) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_ui_font", "Overwrite UI font") + "*", + "font_overwrite", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.font_overwrite = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.font_overwrite = get_open_filename("Font files (.ttf, .otf)|*.ttf;*.otf", ""); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty() + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_windows_control", "Use Windows style window control."), + "panel_menu_right_control", + new checkBox(function() { + PREFERENCES.panel_menu_right_control = !PREFERENCES.panel_menu_right_control; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Splash")); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_auto_save_time", "Autosave delay (-1 to disable)"), + "auto_save_time", + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.auto_save_time = val; + PREF_SAVE(); + }) + )); + + if(IS_PATREON) + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_supporter_icon", "Show supporter icon"), + "show_supporter_icon", + new checkBox(function() { + PREFERENCES.show_supporter_icon = !PREFERENCES.show_supporter_icon; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Graph")); //////////////////////////////////////////////////////////////////////// Graph + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_add_node_remember", "Remember add node position"), + "add_node_remember", + new checkBox(function() { PREFERENCES.add_node_remember = !PREFERENCES.add_node_remember; }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_type", "Connection type"), + "curve_connection_line", + new buttonGroup([ THEME.icon_curve_connection, THEME.icon_curve_connection, THEME.icon_curve_connection, THEME.icon_curve_connection ], + function(val) { + PREFERENCES.curve_connection_line = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_thickness", "Connection thickness"), + "connection_line_width", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_width = real(str); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_curve_smoothness", "Connection curve smoothness"), + "connection_line_sample", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_sample = real(str); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_aa", "Connection anti aliasing"), + "connection_line_aa", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_aa = max(1, real(str)); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_anim", "Connection line animation"), + "connection_line_transition", + new checkBox(function() { + PREFERENCES.connection_line_transition = !PREFERENCES.connection_line_transition; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_graph_group_in_tab", "Open group in new tab"), + "graph_open_group_in_tab", + new checkBox(function() { + PREFERENCES.graph_open_group_in_tab = !PREFERENCES.graph_open_group_in_tab; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_graph_zoom_smoothing", "Graph zoom smoothing"), + "graph_zoom_smoooth", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.graph_zoom_smoooth = max(1, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("panel_graph_group_require_shift", "Hold Shift to enter group"), + "panel_graph_group_require_shift", + new checkBox(function() { + PREFERENCES.panel_graph_group_require_shift = !PREFERENCES.panel_graph_group_require_shift; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Preview")); ////////////////////////////////////////////////////////////////////// Preview + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_preview_show_real_fps", "Show real fps"), + "panel_preview_show_real_fps", + new checkBox(function(str) { + PREFERENCES.panel_preview_show_real_fps = !PREFERENCES.panel_preview_show_real_fps; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Inspector")); //////////////////////////////////////////////////////////////////// Inspector + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_inspector_focus_on_double_click", "Focus on double click"), + "inspector_focus_on_double_click", + new checkBox(function(str) { + PREFERENCES.inspector_focus_on_double_click = !PREFERENCES.inspector_focus_on_double_click; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Collection")); /////////////////////////////////////////////////////////////////// Collection + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_collection_preview_speed", "Collection preview speed"), + "collection_preview_speed", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.collection_preview_speed = max(1, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Notification")); ///////////////////////////////////////////////////////////////// Notification + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_warning_notification_time", "Warning notification time"), + "notification_time", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.notification_time = max(0, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Text Area")); //////////////////////////////////////////////////////////////////// Text area + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_autocomplete_delay", "Code Autocomplete delay"), + "widget_autocomplete_delay", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.widget_autocomplete_delay = round(real(str)); + PREF_SAVE(); + }) + )); + + if(IS_PATREON) { + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_textbox_shake", "Textbox shake"), + "textbox_shake", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.textbox_shake = real(str); + PREF_SAVE(); + }) + ).patreon()); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_textbox_particles", "Textbox particles"), + "textbox_particle", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.textbox_particle = round(real(str)); + PREF_SAVE(); + }) + ).patreon()); + + } + +#endregion + +#region node + pref_node = ds_list_create(); + + ds_list_add(pref_node, __txt("Node")); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_param_show", "Show paramater on new node"), + "node_param_show", + + new checkBox(function() { + PREFERENCES.node_param_show = !PREFERENCES.node_param_show; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_param_width", "Default param width"), + "node_param_width", + + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.node_param_width = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_3d_preview", "Preview surface size"), + "node_3d_preview_size", + + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.node_3d_preview_size = clamp(val, 16, 1024); + PREF_SAVE(); + }) + )); + +#endregion + +#region theme + themes = []; + var f = file_find_first(DIRECTORY + "Themes/*", fa_directory); + while(f != "") { + var _path = $"{DIRECTORY}Themes/{f}"; + if(directory_exists(_path)) { + var _metaPath = _path + "/meta.json"; + if(!file_exists_empty(_metaPath)) { + var _item = new scrollItem(f, THEME.circle, 0, COLORS._main_accent); + _item.tooltip = "Theme made for earlier version."; + array_push(themes, _item); + } else { + var _meta = json_load_struct(_metaPath); + var _item = new scrollItem(_meta.name, _meta.version >= VERSION? noone : THEME.circle, 0, COLORS._main_accent); + _item.data = f; + + if(_meta.version < VERSION) + _item.tooltip = "Theme made for earlier version."; + array_push(themes, _item); + } + } + + f = file_find_next(); + } + file_find_close(); + + sb_theme = new scrollBox(themes, function(index) { + var thm = themes[index].data; + if(PREFERENCES.theme == thm) return; + + PREFERENCES.theme = thm; + PREF_SAVE(); + + loadGraphic(thm); + loadColor(thm); + loadFonts(); + }, false); + sb_theme.align = fa_left; + + sp_colors = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - (title_height + ui(padding) + ui(40)), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var hh = 0; + var th = ui(28); + var x1 = sp_colors.surface_w; + var yy = _y + ui(8); + var padd = ui(6); + var ind = 0; + + var cw = ui(100); + var ch = th - ui(4); + var cx = x1 - cw - ui(8); + var category = ""; + + var sect = []; + var psect = ""; + + for( var i = 0, n = array_length(COLOR_KEYS); i < n; i++ ) { + var key = COLOR_KEYS[i]; + var val = variable_struct_get(COLORS, key); + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(key)) == 0) + continue; + + if(is_array(val)) continue; + var spl = string_splice(key, "_"); + var cat = spl[0] == ""? spl[1] : spl[0]; + if(cat != category) { + category = cat; + var _sect = string_title(category); + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy - ui(4), _sect); + + array_push(sect, [ _sect, sp_colors, hh + ui(12) ]); + if(yy >= 0 && section_current == "") + section_current = psect; + psect = _sect; + + yy += string_height(category) + ui(8); + hh += string_height(category) + ui(8); + ind = 0; + } + + if(ind % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy - padd, + sp_colors.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + var keyStr = string_replace_all(key, "_", " "); + keyStr = string_replace(keyStr, cat + " ", ""); + keyStr = string_title(keyStr); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text_add(ui(24), yy + th / 2, keyStr); + + var b = buttonInstant(THEME.button_def, cx, yy + ui(2), cw, ch, _m, sFOCUS, sHOVER && sp_colors.hover); + draw_sprite_stretched_ext(THEME.color_picker_sample, 0, cx + ui(2), yy + ui(2 + 2), cw - ui(4), ch - ui(4), val, 1); + + if(b == 2) { + var dialog = dialogCall(o_dialog_color_selector, WIN_W / 2, WIN_H / 2); + dialog.setDefault(val); + self.key = key; + dialog.onApply = function(color) { + variable_struct_set(COLORS, key, color); + overrideColor(); + }; + dialog.selector.onApply = dialog.onApply; + + addChildren(dialog); + } + + yy += th + padd + ui(8); + hh += th + padd + ui(8); + ind++; + } + + sections[page_current] = sect; + + return hh; + }); + + function overrideColor() { + var path = $"{DIRECTORY}Themes/{PREFERENCES.theme}/override.json"; + json_save_struct(path, COLORS, true); + } +#endregion + +#region hotkey + pref_hot = ds_list_create(); + ds_list_add(pref_hot, [ + __txtx("pref_use_alt", "Use ALT for"), + "alt_picker", + new buttonGroup([ "Pan", "Color Picker" ], function(val) { + PREFERENCES.alt_picker = val; + PREF_SAVE(); + }) + ]); + + ds_list_add(pref_hot, [ + __txtx("pref_pan_key", "Panning key"), + function() { return PREFERENCES.pan_mouse_key - 3; }, + new scrollBox([ "Middle Mouse", "Mouse 4", "Mouse 5" ], function(val) { + PREFERENCES.pan_mouse_key = val + 3; + PREF_SAVE(); + }) + ]); + + vk_list = [ + vk_left, vk_right, vk_up, vk_down, vk_space, vk_backspace, vk_tab, vk_home, vk_end, vk_delete, vk_insert, + vk_pageup, vk_pagedown, vk_pause, vk_printscreen, + vk_f1, vk_f2, vk_f3, vk_f4, vk_f5, vk_f6, vk_f7, vk_f8, vk_f9, vk_f10, vk_f11, vk_f12, + ]; + hk_editing = noone; + + sp_hotkey = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding), function(_y, _m) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var padd = ui(8); + var hh = ui(8); + var currGroup = noone; + var x1 = sp_hotkey.surface_w; + var key_x1 = x1 - ui(32); + var modified = false; + + draw_set_text(f_p0, fa_left, fa_top); + + var yy = _y + ui(8); + var ind = 0; + var sect = []; + var psect = ""; + + for( var i = 0, n = ds_list_size(pref_hot); i < n; i++ ) { + var _pref = pref_hot[| i]; + var th = line_get_height(); + + var name = _pref[0]; + var val = _pref[1]; + val = is_method(val)? val() : PREFERENCES[$ val]; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(ind % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, + sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, _pref[0]); + + _pref[2].setFocusHover(sFOCUS, sHOVER && sp_hotkey.hover); + + var widget_w = ui(240); + var widget_h = th + (padd - ui(4)) * 2; + + var widget_x = x1 - ui(4) - widget_w; + var widget_y = yy + hh - ui(4); + + var params = new widgetParam(widget_x, widget_y, widget_w, widget_h, val, {}, _m, sp_hotkey.x, sp_hotkey.y); + var th = _pref[2].drawParam(params) ?? 0; + + hh += th + padd + ui(8); + ind++; + } + + for(var j = 0; j < ds_list_size(HOTKEY_CONTEXT); j++) { + var ll = HOTKEYS[? HOTKEY_CONTEXT[| j]]; + + for(var i = 0; i < ds_list_size(ll); i++) { + var key = ll[| i]; + var group = key.context; + var name = __txt(key.name); + var pkey = key.key; + var modi = key.modi; + + var dkey = key.dKey; + var dmod = key.dModi; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(group != currGroup) { + if(group != "") hh += ui(12); + + var _grp = group == ""? __txt("Global") : group; + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, _grp); + + array_push(sect, [ _grp, sp_hotkey, hh + ui(12) ]); + if(yy + hh >= 0 && section_current == "") + section_current = psect; + psect = _grp; + + hh += string_height("l") + ui(16); + currGroup = group; + } + + if(i % 2 == 0) { + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, + sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + } + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, name); + + var dk = key_get_name(key.key, key.modi); + var kw = string_width(dk); + + if(hk_editing == key) { + var _mod_prs = 0; + + 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 = 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++) { + if(!keyboard_check_pressed(vk_list[a])) continue; + key.key = vk_list[a]; + press = true; + break; + } + + if(!press) { + var k = ds_map_find_first(global.KEY_STRING_MAP); + var amo = ds_map_size(global.KEY_STRING_MAP); + repeat(amo) { + if(!keyboard_check_pressed(k)) { + k = ds_map_find_next(global.KEY_STRING_MAP, k); + continue; + } + key.key = k; + press = true; + break; + } + } + + 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, yy + hh - ui(6), kw + ui(32), th + ui(12)); + } else { + var bx = key_x1 - ui(40) - kw; + var by = yy + hh - ui(6); + if(buttonInstant(THEME.button_hide, bx, by, kw + ui(32), th + ui(12), _m, sFOCUS, sHOVER && sp_hotkey.hover) == 2) { + hk_editing = key; + keyboard_lastchar = pkey; + } + } + + 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); + draw_text_add(key_x1 - ui(24), yy + hh, dk); + + if(key.key != dkey || key.modi != dmod) { + modified = true; + var bx = x1 - ui(32); + var by = yy + hh; + if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset"), THEME.refresh_16) == 2) { + key.key = dkey; + key.modi = dmod; + + PREF_SAVE(); + } + } + + hh += th + padd * 2; + } + } + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, "Nodes (Single key only)"); + array_push(sect, [ "Nodes", sp_hotkey, hh + ui(12) ]); + hh += string_height("l") + ui(16); + + var keys = struct_get_names(HOTKEYS_CUSTOM); + for( var i = 0, n = array_length(keys); i < n; i++ ) { + var _key = keys[i]; + var hotkeys = struct_get_names(HOTKEYS_CUSTOM[$ _key]); + + var _key_t = string_title(string_replace(_key, "Node_", "")); + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, _key_t); + array_push(sect, [ "- " + _key_t, sp_hotkey, hh + ui(12) ]); + if(yy + hh >= 0 && section_current == "") + section_current = psect; + psect = "- " + _key_t; + hh += string_height("l") + ui(16); + + for( var j = 0, m = array_length(hotkeys); j < m; j++ ) { + var _hotkey = hotkeys[j]; + var hotkey = HOTKEYS_CUSTOM[$ _key][$ _hotkey]; + + var name = __txt(_hotkey); + var pkey = hotkey.key; + if(pkey == "") pkey = "None"; + + if(j % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, name); + + var kw = string_width(pkey); + var bx = key_x1 - ui(40) - kw; + var key = hotkey; + + if(hk_editing == key) { + if(keyboard_check_pressed(vk_escape)) { + key.key = ""; + PREF_SAVE(); + } else if(keyboard_check_pressed(vk_anykey)) { + key.key = string_upper(keyboard_lastchar); + PREF_SAVE(); + } + + draw_sprite_stretched(THEME.button_hide, 2, key_x1 - ui(40) - kw, yy + hh - ui(6), kw + ui(32), th + ui(12)); + } else { + var bx = key_x1 - ui(40) - kw; + var by = yy + hh - ui(6); + if(buttonInstant(THEME.button_hide, bx, by, kw + ui(32), th + ui(12), _m, sFOCUS, sHOVER && sp_hotkey.hover) == 2) { + hk_editing = key; + keyboard_lastchar = pkey; + } + } + + var cc = (hotkey.key == "")? 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); + draw_text_add(key_x1 - ui(24), yy + hh, pkey); + + if(key.key != key.dkey) { + modified = true; + var bx = x1 - ui(32); + var by = yy + hh; + if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset"), THEME.refresh_16) == 2) { + key.key = key.dkey; + + PREF_SAVE(); + } + } + + hh += th + padd * 2; + } + } + + //if(modified) { + // var bx = x1 - ui(32); + // var by = yy + ui(2); + // if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset all"), THEME.refresh_16) == 2) { + // for(var j = 0; j < ds_list_size(HOTKEY_CONTEXT); j++) { + // var ll = HOTKEYS[? HOTKEY_CONTEXT[| j]]; + // for(var i = 0; i < ds_list_size(ll); i++) { + // var key = ll[| i]; + // key.key = key.dKey; + // key.modi = key.dModi; + + // PREF_SAVE(); + // } + // } + // } + //} + + sections[page_current] = sect; + + return hh; + }) +#endregion + +#region scrollpane + current_list = pref_global; + + sp_pref = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var hh = 0; + var th = TEXTBOX_HEIGHT; + var x1 = sp_pref.surface_w; + var yy = _y + ui(8); + var padd = ui(6); + var ind = 0; + + for(var i = 0; i < ds_list_size(current_list); i++) { + var _pref = current_list[| i]; + if(is_string(_pref)) continue; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(_pref.name)) == 0) + continue; + + _pref.editWidget.register(sp_pref); + } + + var sect = []; + var psect = ""; + + for(var i = 0; i < ds_list_size(current_list); i++) { + var _pref = current_list[| i]; + var th = TEXTBOX_HEIGHT; + + if(is_string(_pref)) { + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy, _pref); + + array_push(sect, [ _pref, sp_pref, hh + ui(12) ]); + if(yy >= 0 && section_current == "") + section_current = psect; + psect = _pref; + + yy += string_height(_pref) + ui(8); + hh += string_height(_pref) + ui(8); + ind = 0; + continue; + } + + var name = _pref.name; + var data = _pref.data(); + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(ind % 2 == 0) draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy - padd, sp_pref.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text_add(ui(24), yy + th / 2, name); + + if(_pref.is_patreon) { + var spr_x = ui(20); + var spr_y = yy + ui(4); + + BLEND_SUBTRACT + gpu_set_colorwriteenable(0, 0, 0, 1); + draw_sprite_ext(s_patreon_supporter, 0, spr_x, spr_y, -1, 1, 0, c_white, 1); + gpu_set_colorwriteenable(1, 1, 1, 1); + BLEND_NORMAL + + draw_sprite_ext(s_patreon_supporter, 1, spr_x, spr_y, -1, 1, 0, COLORS._main_accent, 1); + } + + _pref.editWidget.setFocusHover(sFOCUS, sHOVER && sp_pref.hover); + + var widget_w = ui(260); + var widget_h = th; + + if(is_instanceof(_pref.editWidget, textBox)) + widget_w = _pref.editWidget.input == TEXTBOX_INPUT.text? ui(400) : widget_w; + + var widget_x = x1 - ui(4) - widget_w; + var widget_y = yy; + + if(_pref.getDefault != noone) + widget_w -= ui(32 + 8); + + var params = new widgetParam(widget_x, widget_y, widget_w, widget_h, data, {}, _m, _r[0], _r[1]); + params.s = ui(30); + + if(instanceof(_pref.editWidget) == "checkBox") params.halign = fa_center; + var th = _pref.editWidget.drawParam(params) ?? 0; + + if(_pref.getDefault != noone) { + var _defVal = is_method(_pref.getDefault)? _pref.getDefault() : _pref.getDefault; + var _bs = ui(32); + var _bx = x1 - ui(4) - _bs; + var _by = yy + th / 2 - _bs / 2; + + if(isEqual(data, _defVal)) + draw_sprite_ext(THEME.refresh_16, 0, _bx + _bs / 2, _by + _bs / 2, 1, 1, 0, COLORS._main_icon_dark); + else { + if(buttonInstant(THEME.button_hide, _bx, _by, _bs, _bs, _m, sFOCUS, sHOVER && sp_pref.hover, __txt("Reset"), THEME.refresh_16) == 2) + _pref.onEdit(_defVal); + } + } + + yy += th + padd + ui(8); + hh += th + padd + ui(8); + ind++; + } + + sections[page_current] = sect; + + return hh; + }); +#endregion + +#region search + tb_search = new textBox(TEXTBOX_INPUT.text, function(str) { + search_text = str; + }); + tb_search.align = fa_left; + + search_text = ""; +#endregion + + +#event destroy +event_inherited(); +ds_list_destroy(pref_global); + +#event draw_gui init +if !ready exit; + +#region base UI + DIALOG_DRAW_BG + if(sFOCUS) + DIALOG_DRAW_FOCUS + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text(dialog_x + ui(56), dialog_y + ui(20), __txt("Preferences")); + + var bx = dialog_x + ui(24); + var by = dialog_y + ui(18); + if(buttonInstant(THEME.button_hide, bx, by, ui(28), ui(28), mouse_ui, sFOCUS, sHOVER, destroy_on_click_out? __txt("Pin") : __txt("Unpin"), + THEME.pin, !destroy_on_click_out, destroy_on_click_out? COLORS._main_icon : COLORS._main_icon_light) == 2) + destroy_on_click_out = !destroy_on_click_out; + + if(should_restart) { + var _txt = "Restart recommended"; + var _rx = dialog_x + ui(168); + var _ry = dialog_y + ui(20); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_accent); + + var _rw = string_width(_txt); + var _rh = string_height(_txt); + + draw_sprite_stretched_ext(THEME.group_label, 0, _rx - ui(8), _ry - ui(4), _rw + ui(16), _rh + ui(8), COLORS._main_accent, 1); + draw_text(_rx, _ry, _txt); + } +#endregion + +#region page + sp_page.setFocusHover(sFOCUS, sHOVER); + sp_page.draw(dialog_x + ui(padding), dialog_y + ui(title_height)); +#endregion + +#region draw + section_current = ""; + var px = dialog_x + ui(padding) + page_width; + var py = dialog_y + ui(title_height); + var pw = dialog_w - ui(padding + padding) - page_width; + var ph = dialog_h - ui(title_height + padding); + + draw_sprite_stretched(THEME.ui_panel_bg, 1, px - ui(8), py - ui(8), pw + ui(16), ph + ui(16)); + + tb_search.auto_update = true; + tb_search.no_empty = false; + tb_search.font = f_p1; + tb_search.active = sFOCUS; + tb_search.hover = sHOVER; + tb_search.draw(dialog_x + dialog_w - ui(padding - 8), dialog_y + ui(title_height) / 2, ui(200), ui(28), search_text, mouse_ui, fa_right, fa_center); + draw_sprite_ui_uniform(THEME.search, 0, dialog_x + dialog_w - ui(padding + 208), dialog_y + ui(title_height) / 2, 1, COLORS._main_text_sub); + + if(page_current == 0) { + current_list = pref_global; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 1) { + current_list = pref_appr; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 2) { + current_list = pref_node; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 3) { + var _w = ui(200); + var _h = TEXTBOX_HEIGHT; + + var _x = dialog_x + dialog_w - ui(8); + var bx = _x - ui(48); + var _txt = __txtx("pref_reset_color", "Reset colors"); + var b = buttonInstant(THEME.button_hide, bx, py, ui(32), ui(32), mouse_ui, sFOCUS, sHOVER, _txt, THEME.refresh_icon); + if(b == 2) { + var path = $"{DIRECTORY}Themes/{PREFERENCES.theme}/override.json"; + if(file_exists_empty(path)) file_delete(path); + loadColor(PREFERENCES.theme); + } + + var x1 = dialog_x + ui(padding) + page_width; + var x2 = _x - ui(32); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text(x1 + ui(8), py + _h / 2, __txt("Theme")); + sb_theme.setFocusHover(sFOCUS, sHOVER); + sb_theme.draw(x2 - ui(24) - _w, py, _w, _h, PREFERENCES.theme); + + sp_colors.setFocusHover(sFOCUS, sHOVER); + sp_colors.draw(px, py + ui(40)); + + } else if(page_current == 4) { + if(mouse_press(mb_left, sFOCUS)) + hk_editing = noone; + + sp_hotkey.setFocusHover(sFOCUS, sHOVER); + sp_hotkey.draw(px, py); + } +#endregion \ No newline at end of file diff --git a/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup1 b/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup1 new file mode 100644 index 000000000..fe6436363 --- /dev/null +++ b/#backups/objects/o_dialog_preference/o_dialog_preference.yy.backup1 @@ -0,0 +1,1221 @@ +// 2024-05-01 15:58:59 +#event properties (no comments/etc. here are saved) +parent_index = _p_dialog; +uses_physics = false; + +#event create init +event_inherited(); + +#region data + dialog_w = ui(900); + dialog_h = ui(640); + page_width = ui(160); + + destroy_on_click_out = true; + destroy_on_escape = false; + + should_restart = false; +#endregion + +#region resize + dialog_resizable = true; + dialog_w_min = ui(640); + dialog_h_min = ui(480); + + onResize = function() { + sp_page.resize(page_width - ui(4), dialog_h - ui(title_height + padding)); + + sp_pref.resize( dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding)); + sp_hotkey.resize(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding)); + sp_colors.resize(dialog_w - ui(padding + padding) - page_width, dialog_h - (title_height + ui(padding + 40))); + } +#endregion + +#region pages + page_current = 0; + page[0] = __txtx("pref_pages_general", "General"); + page[1] = __txtx("pref_pages_interface", "Interface"); + page[2] = __txt("Nodes"); + page[3] = __txt("Theme"); + page[4] = __txt("Hotkeys"); + + section_current = ""; + sections = array_create(array_length(page)); + + sp_page = new scrollPane(page_width - ui(4), dialog_h - ui(title_height + padding), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 1); + var ww = sp_page.surface_w; + var hh = 0; + + var yl = _y; + var hg = line_get_height(f_p0, 16); + var hs = line_get_height(f_p1, 8); + + for(var i = 0; i < array_length(page); i++) { + if(i == page_current) draw_set_text(f_p0b, fa_left, fa_center, COLORS._main_text_accent); + else draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text_inner); + + if(sHOVER && point_in_rectangle(_m[0], _m[1], 0, yl, ww, yl + hg)) { + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yl, ww, hg, CDEF.main_white, 1); + + if(i != page_current && mouse_click(mb_left, sFOCUS)) { + page_current = i; + sp_pref.setScroll(0); + } + } + + draw_text_add(ui(8), yl + hg / 2, page[i]); + yl += hg; + hh += hg; + + if(i == page_current && sections[i] != 0) { + for( var j = 0, m = array_length(sections[i]); j < m; j++ ) { + var sect = sections[i][j]; + + draw_set_text(f_p1, fa_left, fa_center, section_current == sect[0]? COLORS._main_text : COLORS._main_text_sub); + + if(sHOVER && point_in_rectangle(_m[0], _m[1], 0, yl, ww, yl + hs - 1)) { + if(mouse_press(mb_left, sFOCUS)) + sect[1].scroll_y_to = -sect[2]; + + draw_set_color(COLORS._main_text); + } + + var _xx = ui(8 + 16); + var sect_title = sect[0]; + var sp = string_split(sect_title, " "); + if(sp[0] == "-") { + _xx += ui(16); + sect_title = string_replace(sect_title, "- ", ""); + } + + draw_text_add(_xx, yl + hs / 2, __txt(sect_title)); + + yl += hs; + hh += hs; + } + } + } + + return hh; + }); + + sp_page.always_scroll = true; + sp_page.show_scroll = false; +#endregion + +#region general + pref_global = ds_list_create(); + + ds_list_add(pref_global, __txt("Paths")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item( + __txtx("pref_directory", "Main directory path" + "*"), + new textBox(TEXTBOX_INPUT.text, function(txt) { + PRESIST_PREF.path = txt; + json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF); + }) + .setSideButton(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(), + function() { return PRESIST_PREF.path; }, + function(val) { PRESIST_PREF.path = val; json_save_struct(APP_DIRECTORY + "persistPreference.json", PRESIST_PREF); }, + APP_DIRECTORY, + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_temp", "Temp directory path" + "*"), + "temp_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.temp_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.temp_path = get_directory(PREFERENCES.temp_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, __txt("Inputs")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_double_click_delay", "Double click delay"), + "double_click_delay", + slider(0, 1, 0.01, function(val) { + PREFERENCES.double_click_delay = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_mouse_wheel_speed", "Scroll speed"), + "mouse_wheel_speed", + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.mouse_wheel_speed = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_keyboard_hold_start", "Keyboard hold start"), + "keyboard_repeat_start", + slider(0, 1, 0.01, function(val) { + PREFERENCES.keyboard_repeat_start = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_keyboard_repeat_delay", "Keyboard repeat delay"), + "keyboard_repeat_speed", + slider(0, 1, 0.01, function(val) { + PREFERENCES.keyboard_repeat_speed = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_expand_hovering_panel", "Expand hovering panel"), + "expand_hover", + new checkBox(function() { + PREFERENCES.expand_hover = !PREFERENCES.expand_hover; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Save/Load")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_save_file_minify", "Minify save file"), + "save_file_minify", + new checkBox(function() { + PREFERENCES.save_file_minify = !PREFERENCES.save_file_minify; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Crash")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_legacy_exception", "Use legacy exception handler"), + "use_legacy_exception", + new checkBox(function() { + PREFERENCES.use_legacy_exception = !PREFERENCES.use_legacy_exception; + PREF_APPLY(); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_crash_dialog", "Show dialog after crash"), + "show_crash_dialog", + new checkBox(function() { + PREFERENCES.show_crash_dialog = !PREFERENCES.show_crash_dialog; + PREF_APPLY(); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Misc")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_clear_temp", "Clear temp file on close"), + "clear_temp_on_close", + new checkBox(function() { + PREFERENCES.clear_temp_on_close = !PREFERENCES.clear_temp_on_close; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_enable_test_mode", "Enable developer mode" + "*"), + "test_mode", + new checkBox(function() { + PREFERENCES.test_mode = !PREFERENCES.test_mode; + should_restart = true; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_global, __txt("Libraries")); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_ImageMagick", "ImageMagick path" + "*"), + "ImageMagick_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.ImageMagick_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.ImageMagick_path = get_directory(PREFERENCES.ImageMagick_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_webp", "Webp path" + "*"), + "webp_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.webp_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.webp_path = get_directory(PREFERENCES.webp_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_gifski", "Gifski path" + "*"), + "gifski_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.gifski_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.gifski_path = get_directory(PREFERENCES.gifski_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + + ds_list_add(pref_global, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_directory_FFmpeg", "FFmpeg path" + "*"), + "ffmpeg_path", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.gifski_path = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.ffmpeg_path = get_directory(PREFERENCES.ffmpeg_path); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty(), + )); + +#endregion + +#region interface + pref_appr = ds_list_create(); + + ds_list_add(pref_appr, __txt("Interface")); /////////////////////////////////////////////////////////////// Interface + + PREFERENCES._display_scaling = PREFERENCES.display_scaling; + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item( + __txtx("pref_gui_scaling", "GUI scaling*"), + slider(0.5, 2, 0.01, function(val) { + PREFERENCES._display_scaling = val; + should_restart = true; + + }, function() { + PREFERENCES._display_scaling = max(PREFERENCES._display_scaling, 0.5); + resetScale(PREFERENCES._display_scaling, true); + should_restart = true; + }), + + function() { return PREFERENCES._display_scaling; }, + function(val) { + + PREFERENCES._display_scaling = val; + resetScale(PREFERENCES._display_scaling, true); + should_restart = true; + }, + 1, + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_ui_frame_rate", "UI frame rate"), + "ui_framerate", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.ui_framerate = max(15, round(real(str))); + game_set_speed(PREFERENCES.ui_framerate, gamespeed_fps); + PREF_SAVE(); + }) + )); + + locals = []; + var f = file_find_first(DIRECTORY + "Locale/*", fa_directory); + while(f != "") { + if(directory_exists(DIRECTORY + "Locale/" + f)) { + if(f != "_extend") array_push(locals, f); + } + f = file_find_next(); + } + file_find_close(); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_interface_language", "Interface Language" + "*"), + "local", + new scrollBox(locals, function(str) { + if(str < 0) return; + PREFERENCES.local = locals[str]; + PREF_SAVE(); + }, false) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_ui_font", "Overwrite UI font") + "*", + "font_overwrite", + new textBox(TEXTBOX_INPUT.text, function(txt) { PREFERENCES.font_overwrite = txt; PREF_SAVE(); }) + .setSideButton(button(function() { PREFERENCES.font_overwrite = get_open_filename("Font files (.ttf, .otf)|*.ttf;*.otf", ""); PREF_SAVE(); }, THEME.button_path_icon)) + .setFont(f_p2) + .setEmpty() + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_windows_control", "Use Windows style window control."), + "panel_menu_right_control", + new checkBox(function() { + PREFERENCES.panel_menu_right_control = !PREFERENCES.panel_menu_right_control; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Splash")); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_auto_save_time", "Autosave delay (-1 to disable)"), + "auto_save_time", + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.auto_save_time = val; + PREF_SAVE(); + }) + )); + + if(IS_PATREON) + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_supporter_icon", "Show supporter icon"), + "show_supporter_icon", + new checkBox(function() { + PREFERENCES.show_supporter_icon = !PREFERENCES.show_supporter_icon; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Graph")); //////////////////////////////////////////////////////////////////////// Graph + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_add_node_remember", "Remember add node position"), + "add_node_remember", + new checkBox(function() { PREFERENCES.add_node_remember = !PREFERENCES.add_node_remember; }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_type", "Connection type"), + "curve_connection_line", + new buttonGroup([ THEME.icon_curve_connection, THEME.icon_curve_connection, THEME.icon_curve_connection, THEME.icon_curve_connection ], + function(val) { + PREFERENCES.curve_connection_line = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_thickness", "Connection thickness"), + "connection_line_width", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_width = real(str); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_curve_smoothness", "Connection curve smoothness"), + "connection_line_sample", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_sample = real(str); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_aa", "Connection anti aliasing"), + "connection_line_aa", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.connection_line_aa = max(1, real(str)); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_connection_anim", "Connection line animation"), + "connection_line_transition", + new checkBox(function() { + PREFERENCES.connection_line_transition = !PREFERENCES.connection_line_transition; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_graph_group_in_tab", "Open group in new tab"), + "graph_open_group_in_tab", + new checkBox(function() { + PREFERENCES.graph_open_group_in_tab = !PREFERENCES.graph_open_group_in_tab; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_graph_zoom_smoothing", "Graph zoom smoothing"), + "graph_zoom_smoooth", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.graph_zoom_smoooth = max(1, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("panel_graph_group_require_shift", "Hold Shift to enter group"), + "panel_graph_group_require_shift", + new checkBox(function() { + PREFERENCES.panel_graph_group_require_shift = !PREFERENCES.panel_graph_group_require_shift; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Preview")); ////////////////////////////////////////////////////////////////////// Preview + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_preview_show_real_fps", "Show real fps"), + "panel_preview_show_real_fps", + new checkBox(function(str) { + PREFERENCES.panel_preview_show_real_fps = !PREFERENCES.panel_preview_show_real_fps; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Inspector")); //////////////////////////////////////////////////////////////////// Inspector + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_inspector_focus_on_double_click", "Focus on double click"), + "inspector_focus_on_double_click", + new checkBox(function(str) { + PREFERENCES.inspector_focus_on_double_click = !PREFERENCES.inspector_focus_on_double_click; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Collection")); /////////////////////////////////////////////////////////////////// Collection + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_collection_preview_speed", "Collection preview speed"), + "collection_preview_speed", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.collection_preview_speed = max(1, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Notification")); ///////////////////////////////////////////////////////////////// Notification + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_warning_notification_time", "Warning notification time"), + "notification_time", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.notification_time = max(0, round(real(str))); + PREF_SAVE(); + }) + )); + + ds_list_add(pref_appr, __txt("Text Area")); //////////////////////////////////////////////////////////////////// Text area + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_autocomplete_delay", "Code Autocomplete delay"), + "widget_autocomplete_delay", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.widget_autocomplete_delay = round(real(str)); + PREF_SAVE(); + }) + )); + + if(IS_PATREON) { + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_textbox_shake", "Textbox shake"), + "textbox_shake", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.textbox_shake = real(str); + PREF_SAVE(); + }) + ).patreon()); + + ds_list_add(pref_appr, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_widget_textbox_particles", "Textbox particles"), + "textbox_particle", + new textBox(TEXTBOX_INPUT.number, function(str) { + PREFERENCES.textbox_particle = round(real(str)); + PREF_SAVE(); + }) + ).patreon()); + + } + +#endregion + +#region node + pref_node = ds_list_create(); + + ds_list_add(pref_node, __txt("Node")); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_param_show", "Show paramater on new node"), + "node_param_show", + + new checkBox(function() { + PREFERENCES.node_param_show = !PREFERENCES.node_param_show; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_param_width", "Default param width"), + "node_param_width", + + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.node_param_width = val; + PREF_SAVE(); + }) + )); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_3d_preview", "Preview surface size"), + "node_3d_preview_size", + + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.node_3d_preview_size = clamp(val, 16, 1024); + PREF_SAVE(); + }) + )); + +#endregion + +#region theme + themes = []; + var f = file_find_first(DIRECTORY + "Themes/*", fa_directory); + while(f != "") { + var _path = $"{DIRECTORY}Themes/{f}"; + if(directory_exists(_path)) { + var _metaPath = _path + "/meta.json"; + if(!file_exists_empty(_metaPath)) { + var _item = new scrollItem(f, THEME.circle, 0, COLORS._main_accent); + _item.tooltip = "Theme made for earlier version."; + array_push(themes, _item); + } else { + var _meta = json_load_struct(_metaPath); + var _item = new scrollItem(_meta.name, _meta.version >= VERSION? noone : THEME.circle, 0, COLORS._main_accent); + _item.data = f; + + if(_meta.version < VERSION) + _item.tooltip = "Theme made for earlier version."; + array_push(themes, _item); + } + } + + f = file_find_next(); + } + file_find_close(); + + sb_theme = new scrollBox(themes, function(index) { + var thm = themes[index].data; + if(PREFERENCES.theme == thm) return; + + PREFERENCES.theme = thm; + PREF_SAVE(); + + loadGraphic(thm); + loadColor(thm); + loadFonts(); + }, false); + sb_theme.align = fa_left; + + sp_colors = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - (title_height + ui(padding) + ui(40)), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var hh = 0; + var th = ui(28); + var x1 = sp_colors.surface_w; + var yy = _y + ui(8); + var padd = ui(6); + var ind = 0; + + var cw = ui(100); + var ch = th - ui(4); + var cx = x1 - cw - ui(8); + var category = ""; + + var sect = []; + var psect = ""; + + for( var i = 0, n = array_length(COLOR_KEYS); i < n; i++ ) { + var key = COLOR_KEYS[i]; + var val = variable_struct_get(COLORS, key); + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(key)) == 0) + continue; + + if(is_array(val)) continue; + var spl = string_splice(key, "_"); + var cat = spl[0] == ""? spl[1] : spl[0]; + if(cat != category) { + category = cat; + var _sect = string_title(category); + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy - ui(4), _sect); + + array_push(sect, [ _sect, sp_colors, hh + ui(12) ]); + if(yy >= 0 && section_current == "") + section_current = psect; + psect = _sect; + + yy += string_height(category) + ui(8); + hh += string_height(category) + ui(8); + ind = 0; + } + + if(ind % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy - padd, + sp_colors.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + var keyStr = string_replace_all(key, "_", " "); + keyStr = string_replace(keyStr, cat + " ", ""); + keyStr = string_title(keyStr); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text_add(ui(24), yy + th / 2, keyStr); + + var b = buttonInstant(THEME.button_def, cx, yy + ui(2), cw, ch, _m, sFOCUS, sHOVER && sp_colors.hover); + draw_sprite_stretched_ext(THEME.color_picker_sample, 0, cx + ui(2), yy + ui(2 + 2), cw - ui(4), ch - ui(4), val, 1); + + if(b == 2) { + var dialog = dialogCall(o_dialog_color_selector, WIN_W / 2, WIN_H / 2); + dialog.setDefault(val); + self.key = key; + dialog.onApply = function(color) { + variable_struct_set(COLORS, key, color); + overrideColor(); + }; + dialog.selector.onApply = dialog.onApply; + + addChildren(dialog); + } + + yy += th + padd + ui(8); + hh += th + padd + ui(8); + ind++; + } + + sections[page_current] = sect; + + return hh; + }); + + function overrideColor() { + var path = $"{DIRECTORY}Themes/{PREFERENCES.theme}/override.json"; + json_save_struct(path, COLORS, true); + } +#endregion + +#region hotkey + pref_hot = ds_list_create(); + ds_list_add(pref_hot, [ + __txtx("pref_use_alt", "Use ALT for"), + "alt_picker", + new buttonGroup([ "Pan", "Color Picker" ], function(val) { + PREFERENCES.alt_picker = val; + PREF_SAVE(); + }) + ]); + + ds_list_add(pref_hot, [ + __txtx("pref_pan_key", "Panning key"), + function() { return PREFERENCES.pan_mouse_key - 3; }, + new scrollBox([ "Middle Mouse", "Mouse 4", "Mouse 5" ], function(val) { + PREFERENCES.pan_mouse_key = val + 3; + PREF_SAVE(); + }) + ]); + + vk_list = [ + vk_left, vk_right, vk_up, vk_down, vk_space, vk_backspace, vk_tab, vk_home, vk_end, vk_delete, vk_insert, + vk_pageup, vk_pagedown, vk_pause, vk_printscreen, + vk_f1, vk_f2, vk_f3, vk_f4, vk_f5, vk_f6, vk_f7, vk_f8, vk_f9, vk_f10, vk_f11, vk_f12, + ]; + hk_editing = noone; + + sp_hotkey = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding), function(_y, _m) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var padd = ui(8); + var hh = ui(8); + var currGroup = noone; + var x1 = sp_hotkey.surface_w; + var key_x1 = x1 - ui(32); + var modified = false; + + draw_set_text(f_p0, fa_left, fa_top); + + var yy = _y + ui(8); + var ind = 0; + var sect = []; + var psect = ""; + + for( var i = 0, n = ds_list_size(pref_hot); i < n; i++ ) { + var _pref = pref_hot[| i]; + var th = line_get_height(); + + var name = _pref[0]; + var val = _pref[1]; + val = is_method(val)? val() : PREFERENCES[$ val]; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(ind % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, + sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, _pref[0]); + + _pref[2].setFocusHover(sFOCUS, sHOVER && sp_hotkey.hover); + + var widget_w = ui(240); + var widget_h = th + (padd - ui(4)) * 2; + + var widget_x = x1 - ui(4) - widget_w; + var widget_y = yy + hh - ui(4); + + var params = new widgetParam(widget_x, widget_y, widget_w, widget_h, val, {}, _m, sp_hotkey.x, sp_hotkey.y); + var th = _pref[2].drawParam(params) ?? 0; + + hh += th + padd + ui(8); + ind++; + } + + for(var j = 0; j < ds_list_size(HOTKEY_CONTEXT); j++) { + var ll = HOTKEYS[? HOTKEY_CONTEXT[| j]]; + + for(var i = 0; i < ds_list_size(ll); i++) { + var key = ll[| i]; + var group = key.context; + var name = __txt(key.name); + var pkey = key.key; + var modi = key.modi; + + var dkey = key.dKey; + var dmod = key.dModi; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(group != currGroup) { + if(group != "") hh += ui(12); + + var _grp = group == ""? __txt("Global") : group; + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, _grp); + + array_push(sect, [ _grp, sp_hotkey, hh + ui(12) ]); + if(yy + hh >= 0 && section_current == "") + section_current = psect; + psect = _grp; + + hh += string_height("l") + ui(16); + currGroup = group; + } + + if(i % 2 == 0) { + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, + sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + } + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, name); + + var dk = key_get_name(key.key, key.modi); + var kw = string_width(dk); + + if(hk_editing == key) { + var _mod_prs = 0; + + 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 = 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++) { + if(!keyboard_check_pressed(vk_list[a])) continue; + key.key = vk_list[a]; + press = true; + break; + } + + if(!press) { + var k = ds_map_find_first(global.KEY_STRING_MAP); + var amo = ds_map_size(global.KEY_STRING_MAP); + repeat(amo) { + if(!keyboard_check_pressed(k)) { + k = ds_map_find_next(global.KEY_STRING_MAP, k); + continue; + } + key.key = k; + press = true; + break; + } + } + + 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, yy + hh - ui(6), kw + ui(32), th + ui(12)); + } else { + var bx = key_x1 - ui(40) - kw; + var by = yy + hh - ui(6); + if(buttonInstant(THEME.button_hide, bx, by, kw + ui(32), th + ui(12), _m, sFOCUS, sHOVER && sp_hotkey.hover) == 2) { + hk_editing = key; + keyboard_lastchar = pkey; + } + } + + 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); + draw_text_add(key_x1 - ui(24), yy + hh, dk); + + if(key.key != dkey || key.modi != dmod) { + modified = true; + var bx = x1 - ui(32); + var by = yy + hh; + if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset"), THEME.refresh_16) == 2) { + key.key = dkey; + key.modi = dmod; + + PREF_SAVE(); + } + } + + hh += th + padd * 2; + } + } + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, "Nodes (Single key only)"); + array_push(sect, [ "Nodes", sp_hotkey, hh + ui(12) ]); + hh += string_height("l") + ui(16); + + var keys = struct_get_names(HOTKEYS_CUSTOM); + for( var i = 0, n = array_length(keys); i < n; i++ ) { + var _key = keys[i]; + var hotkeys = struct_get_names(HOTKEYS_CUSTOM[$ _key]); + + var _key_t = string_title(string_replace(_key, "Node_", "")); + + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy + hh, _key_t); + array_push(sect, [ "- " + _key_t, sp_hotkey, hh + ui(12) ]); + if(yy + hh >= 0 && section_current == "") + section_current = psect; + psect = "- " + _key_t; + hh += string_height("l") + ui(16); + + for( var j = 0, m = array_length(hotkeys); j < m; j++ ) { + var _hotkey = hotkeys[j]; + var hotkey = HOTKEYS_CUSTOM[$ _key][$ _hotkey]; + + var name = __txt(_hotkey); + var pkey = hotkey.key; + if(pkey == "") pkey = "None"; + + if(j % 2 == 0) + draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy + hh - padd, sp_hotkey.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text_add(ui(24), yy + hh, name); + + var kw = string_width(pkey); + var bx = key_x1 - ui(40) - kw; + var key = hotkey; + + if(hk_editing == key) { + if(keyboard_check_pressed(vk_escape)) { + key.key = ""; + PREF_SAVE(); + } else if(keyboard_check_pressed(vk_anykey)) { + key.key = string_upper(keyboard_lastchar); + PREF_SAVE(); + } + + draw_sprite_stretched(THEME.button_hide, 2, key_x1 - ui(40) - kw, yy + hh - ui(6), kw + ui(32), th + ui(12)); + } else { + var bx = key_x1 - ui(40) - kw; + var by = yy + hh - ui(6); + if(buttonInstant(THEME.button_hide, bx, by, kw + ui(32), th + ui(12), _m, sFOCUS, sHOVER && sp_hotkey.hover) == 2) { + hk_editing = key; + keyboard_lastchar = pkey; + } + } + + var cc = (hotkey.key == "")? 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); + draw_text_add(key_x1 - ui(24), yy + hh, pkey); + + if(key.key != key.dkey) { + modified = true; + var bx = x1 - ui(32); + var by = yy + hh; + if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset"), THEME.refresh_16) == 2) { + key.key = key.dkey; + + PREF_SAVE(); + } + } + + hh += th + padd * 2; + } + } + + //if(modified) { + // var bx = x1 - ui(32); + // var by = yy + ui(2); + // if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, sFOCUS, sHOVER && sp_hotkey.hover, __txt("Reset all"), THEME.refresh_16) == 2) { + // for(var j = 0; j < ds_list_size(HOTKEY_CONTEXT); j++) { + // var ll = HOTKEYS[? HOTKEY_CONTEXT[| j]]; + // for(var i = 0; i < ds_list_size(ll); i++) { + // var key = ll[| i]; + // key.key = key.dKey; + // key.modi = key.dModi; + + // PREF_SAVE(); + // } + // } + // } + //} + + sections[page_current] = sect; + + return hh; + }) +#endregion + +#region scrollpane + current_list = pref_global; + + sp_pref = new scrollPane(dialog_w - ui(padding + padding) - page_width, dialog_h - ui(title_height + padding), function(_y, _m, _r) { + draw_clear_alpha(COLORS.panel_bg_clear, 0); + var hh = 0; + var th = TEXTBOX_HEIGHT; + var x1 = sp_pref.surface_w; + var yy = _y + ui(8); + var padd = ui(6); + var ind = 0; + + for(var i = 0; i < ds_list_size(current_list); i++) { + var _pref = current_list[| i]; + if(is_string(_pref)) continue; + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(_pref.name)) == 0) + continue; + + _pref.editWidget.register(sp_pref); + } + + var sect = []; + var psect = ""; + + for(var i = 0; i < ds_list_size(current_list); i++) { + var _pref = current_list[| i]; + var th = TEXTBOX_HEIGHT; + + if(is_string(_pref)) { + draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(ui(8), yy, _pref); + + array_push(sect, [ _pref, sp_pref, hh + ui(12) ]); + if(yy >= 0 && section_current == "") + section_current = psect; + psect = _pref; + + yy += string_height(_pref) + ui(8); + hh += string_height(_pref) + ui(8); + ind = 0; + continue; + } + + var name = _pref.name; + var data = _pref.data(); + + if(search_text != "" && string_pos(string_lower(search_text), string_lower(name)) == 0) + continue; + + if(ind % 2 == 0) draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, 0, yy - padd, sp_pref.surface_w, th + padd * 2, COLORS.dialog_preference_prop_bg, 1); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text_add(ui(24), yy + th / 2, name); + + if(_pref.is_patreon) { + var spr_x = ui(20); + var spr_y = yy + ui(4); + + BLEND_SUBTRACT + gpu_set_colorwriteenable(0, 0, 0, 1); + draw_sprite_ext(s_patreon_supporter, 0, spr_x, spr_y, -1, 1, 0, c_white, 1); + gpu_set_colorwriteenable(1, 1, 1, 1); + BLEND_NORMAL + + draw_sprite_ext(s_patreon_supporter, 1, spr_x, spr_y, -1, 1, 0, COLORS._main_accent, 1); + } + + _pref.editWidget.setFocusHover(sFOCUS, sHOVER && sp_pref.hover); + + var widget_w = ui(260); + var widget_h = th; + + if(is_instanceof(_pref.editWidget, textBox)) + widget_w = _pref.editWidget.input == TEXTBOX_INPUT.text? ui(400) : widget_w; + + var widget_x = x1 - ui(4) - widget_w; + var widget_y = yy; + + if(_pref.getDefault != noone) + widget_w -= ui(32 + 8); + + var params = new widgetParam(widget_x, widget_y, widget_w, widget_h, data, {}, _m, _r[0], _r[1]); + params.s = ui(30); + + if(instanceof(_pref.editWidget) == "checkBox") params.halign = fa_center; + var th = _pref.editWidget.drawParam(params) ?? 0; + + if(_pref.getDefault != noone) { + var _defVal = is_method(_pref.getDefault)? _pref.getDefault() : _pref.getDefault; + var _bs = ui(32); + var _bx = x1 - ui(4) - _bs; + var _by = yy + th / 2 - _bs / 2; + + if(isEqual(data, _defVal)) + draw_sprite_ext(THEME.refresh_16, 0, _bx + _bs / 2, _by + _bs / 2, 1, 1, 0, COLORS._main_icon_dark); + else { + if(buttonInstant(THEME.button_hide, _bx, _by, _bs, _bs, _m, sFOCUS, sHOVER && sp_pref.hover, __txt("Reset"), THEME.refresh_16) == 2) + _pref.onEdit(_defVal); + } + } + + yy += th + padd + ui(8); + hh += th + padd + ui(8); + ind++; + } + + sections[page_current] = sect; + + return hh; + }); +#endregion + +#region search + tb_search = new textBox(TEXTBOX_INPUT.text, function(str) { + search_text = str; + }); + tb_search.align = fa_left; + + search_text = ""; +#endregion + + +#event destroy +event_inherited(); +ds_list_destroy(pref_global); + +#event draw_gui init +if !ready exit; + +#region base UI + DIALOG_DRAW_BG + if(sFOCUS) + DIALOG_DRAW_FOCUS + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); + draw_text(dialog_x + ui(56), dialog_y + ui(20), __txt("Preferences")); + + var bx = dialog_x + ui(24); + var by = dialog_y + ui(18); + if(buttonInstant(THEME.button_hide, bx, by, ui(28), ui(28), mouse_ui, sFOCUS, sHOVER, destroy_on_click_out? __txt("Pin") : __txt("Unpin"), + THEME.pin, !destroy_on_click_out, destroy_on_click_out? COLORS._main_icon : COLORS._main_icon_light) == 2) + destroy_on_click_out = !destroy_on_click_out; + + if(should_restart) { + var _txt = "Restart recommended"; + var _rx = dialog_x + ui(168); + var _ry = dialog_y + ui(20); + + draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_accent); + + var _rw = string_width(_txt); + var _rh = string_height(_txt); + + draw_sprite_stretched_ext(THEME.group_label, 0, _rx - ui(8), _ry - ui(4), _rw + ui(16), _rh + ui(8), COLORS._main_accent, 1); + draw_text(_rx, _ry, _txt); + } +#endregion + +#region page + sp_page.setFocusHover(sFOCUS, sHOVER); + sp_page.draw(dialog_x + ui(padding), dialog_y + ui(title_height)); +#endregion + +#region draw + section_current = ""; + var px = dialog_x + ui(padding) + page_width; + var py = dialog_y + ui(title_height); + var pw = dialog_w - ui(padding + padding) - page_width; + var ph = dialog_h - ui(title_height + padding); + + draw_sprite_stretched(THEME.ui_panel_bg, 1, px - ui(8), py - ui(8), pw + ui(16), ph + ui(16)); + + tb_search.auto_update = true; + tb_search.no_empty = false; + tb_search.font = f_p1; + tb_search.active = sFOCUS; + tb_search.hover = sHOVER; + tb_search.draw(dialog_x + dialog_w - ui(padding - 8), dialog_y + ui(title_height) / 2, ui(200), ui(28), search_text, mouse_ui, fa_right, fa_center); + draw_sprite_ui_uniform(THEME.search, 0, dialog_x + dialog_w - ui(padding + 208), dialog_y + ui(title_height) / 2, 1, COLORS._main_text_sub); + + if(page_current == 0) { + current_list = pref_global; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 1) { + current_list = pref_appr; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 2) { + current_list = pref_node; + sp_pref.setFocusHover(sFOCUS, sHOVER); + sp_pref.draw(px, py); + + } else if(page_current == 3) { + var _w = ui(200); + var _h = TEXTBOX_HEIGHT; + + var _x = dialog_x + dialog_w - ui(8); + var bx = _x - ui(48); + var _txt = __txtx("pref_reset_color", "Reset colors"); + var b = buttonInstant(THEME.button_hide, bx, py, ui(32), ui(32), mouse_ui, sFOCUS, sHOVER, _txt, THEME.refresh_icon); + if(b == 2) { + var path = $"{DIRECTORY}Themes/{PREFERENCES.theme}/override.json"; + if(file_exists_empty(path)) file_delete(path); + loadColor(PREFERENCES.theme); + } + + var x1 = dialog_x + ui(padding) + page_width; + var x2 = _x - ui(32); + + draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); + draw_text(x1 + ui(8), py + _h / 2, __txt("Theme")); + sb_theme.setFocusHover(sFOCUS, sHOVER); + sb_theme.draw(x2 - ui(24) - _w, py, _w, _h, PREFERENCES.theme); + + sp_colors.setFocusHover(sFOCUS, sHOVER); + sp_colors.draw(px, py + ui(40)); + + } else if(page_current == 4) { + if(mouse_press(mb_left, sFOCUS)) + hk_editing = noone; + + sp_hotkey.setFocusHover(sFOCUS, sHOVER); + sp_hotkey.draw(px, py); + } +#endregion \ No newline at end of file diff --git a/#backups/objects/o_main/o_main.yy.backup0 b/#backups/objects/o_main/o_main.yy.backup0 index fe80f4a93..253e7e437 100644 --- a/#backups/objects/o_main/o_main.yy.backup0 +++ b/#backups/objects/o_main/o_main.yy.backup0 @@ -1,4 +1,4 @@ -// 2024-04-29 18:32:52 +// 2024-05-01 08:45:28 #event properties (no comments/etc. here are saved) parent_index = -1; persistent = true; @@ -1378,110 +1378,112 @@ if(APP_SURF_OVERRIDE) { #region if(winMan_isMinimized()) exit; #region tooltip - if(is_struct(TOOLTIP)) { - if(struct_has(TOOLTIP, "drawTooltip")) - TOOLTIP.drawTooltip(); - - } else if(is_array(TOOLTIP)) { - var content = TOOLTIP[0]; - var type = TOOLTIP[1]; - - if(is_method(content)) content = content(); - - switch(type) { - case VALUE_TYPE.float : - case VALUE_TYPE.integer : - case VALUE_TYPE.text : - case VALUE_TYPE.struct : - case VALUE_TYPE.path : - draw_tooltip_text(string_real(content)); - break; + if(!_MOUSE_BLOCK) { + if(is_struct(TOOLTIP)) { + if(struct_has(TOOLTIP, "drawTooltip")) + TOOLTIP.drawTooltip(); - case VALUE_TYPE.boolean : - draw_tooltip_text(printBool(content)); - break; + } else if(is_array(TOOLTIP)) { + var content = TOOLTIP[0]; + var type = TOOLTIP[1]; - case VALUE_TYPE.curve : - draw_tooltip_text("[" + __txt("Curve Object") + "]"); - break; + if(is_method(content)) content = content(); - case VALUE_TYPE.color : - draw_tooltip_color(content); - break; - - case VALUE_TYPE.gradient : - draw_tooltip_gradient(content); - break; - - case VALUE_TYPE.d3object : - draw_tooltip_text("[" + __txt("3D Object") + "]"); - break; - - case VALUE_TYPE.object : - draw_tooltip_text("[" + __txt("Object") + "]"); - break; - - case VALUE_TYPE.surface : - draw_tooltip_surface(content); - break; - - case VALUE_TYPE.rigid : - draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); - break; - - case VALUE_TYPE.particle : - var txt = "[" + - __txt("Particle Object") + - " (size: " + string(array_length(content)) + ") " + - "]"; - draw_tooltip_text(txt); - break; - - case VALUE_TYPE.pathnode : - draw_tooltip_text("[" + __txt("Path Object") + "]"); - break; - - case VALUE_TYPE.sdomain : - draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); - break; - - case VALUE_TYPE.strands : - var txt = __txt("Strands Object"); - if(is_struct(content)) - txt += " (strands: " + string(array_length(content.hairs)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.mesh : - var txt = __txt("Mesh Object"); - if(is_struct(content)) - txt += " (triangles: " + string(array_length(content.triangles)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.d3vertex : - var txt = __txt("3D Vertex"); - txt += " (groups: " + string(array_length(content)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.buffer : - draw_tooltip_buffer(content); - break; - - case "sprite" : - draw_tooltip_sprite(content); - break; - - default : - var tt = ""; - if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; - else tt = string(content); - - draw_tooltip_text(tt); - } - } else if(TOOLTIP != "") - draw_tooltip_text(TOOLTIP); + switch(type) { + case VALUE_TYPE.float : + case VALUE_TYPE.integer : + case VALUE_TYPE.text : + case VALUE_TYPE.struct : + case VALUE_TYPE.path : + draw_tooltip_text(string_real(content)); + break; + + case VALUE_TYPE.boolean : + draw_tooltip_text(printBool(content)); + break; + + case VALUE_TYPE.curve : + draw_tooltip_text("[" + __txt("Curve Object") + "]"); + break; + + case VALUE_TYPE.color : + draw_tooltip_color(content); + break; + + case VALUE_TYPE.gradient : + draw_tooltip_gradient(content); + break; + + case VALUE_TYPE.d3object : + draw_tooltip_text("[" + __txt("3D Object") + "]"); + break; + + case VALUE_TYPE.object : + draw_tooltip_text("[" + __txt("Object") + "]"); + break; + + case VALUE_TYPE.surface : + draw_tooltip_surface(content); + break; + + case VALUE_TYPE.rigid : + draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); + break; + + case VALUE_TYPE.particle : + var txt = "[" + + __txt("Particle Object") + + " (size: " + string(array_length(content)) + ") " + + "]"; + draw_tooltip_text(txt); + break; + + case VALUE_TYPE.pathnode : + draw_tooltip_text("[" + __txt("Path Object") + "]"); + break; + + case VALUE_TYPE.sdomain : + draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); + break; + + case VALUE_TYPE.strands : + var txt = __txt("Strands Object"); + if(is_struct(content)) + txt += " (strands: " + string(array_length(content.hairs)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.mesh : + var txt = __txt("Mesh Object"); + if(is_struct(content)) + txt += " (triangles: " + string(array_length(content.triangles)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.d3vertex : + var txt = __txt("3D Vertex"); + txt += " (groups: " + string(array_length(content)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.buffer : + draw_tooltip_buffer(content); + break; + + case "sprite" : + draw_tooltip_sprite(content); + break; + + default : + var tt = ""; + if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; + else tt = string(content); + + draw_tooltip_text(tt); + } + } else if(TOOLTIP != "") + draw_tooltip_text(TOOLTIP); + } TOOLTIP = ""; #endregion diff --git a/#backups/objects/o_main/o_main.yy.backup1 b/#backups/objects/o_main/o_main.yy.backup1 index 770c3b17a..7e9c070f3 100644 --- a/#backups/objects/o_main/o_main.yy.backup1 +++ b/#backups/objects/o_main/o_main.yy.backup1 @@ -1,4 +1,4 @@ -// 2024-04-21 15:26:33 +// 2024-05-01 08:44:52 #event properties (no comments/etc. here are saved) parent_index = -1; persistent = true; @@ -1378,110 +1378,112 @@ if(APP_SURF_OVERRIDE) { #region if(winMan_isMinimized()) exit; #region tooltip - if(is_struct(TOOLTIP)) { - if(struct_has(TOOLTIP, "drawTooltip")) - TOOLTIP.drawTooltip(); - - } else if(is_array(TOOLTIP)) { - var content = TOOLTIP[0]; - var type = TOOLTIP[1]; - - if(is_method(content)) content = content(); - - switch(type) { - case VALUE_TYPE.float : - case VALUE_TYPE.integer : - case VALUE_TYPE.text : - case VALUE_TYPE.struct : - case VALUE_TYPE.path : - draw_tooltip_text(string_real(content)); - break; + if(!_MOUSE_BLOCK) { + if(is_struct(TOOLTIP)) { + if(struct_has(TOOLTIP, "drawTooltip")) + TOOLTIP.drawTooltip(); - case VALUE_TYPE.boolean : - draw_tooltip_text(printBool(content)); - break; + } else if(is_array(TOOLTIP)) { + var content = TOOLTIP[0]; + var type = TOOLTIP[1]; - case VALUE_TYPE.curve : - draw_tooltip_text("[" + __txt("Curve Object") + "]"); - break; + if(is_method(content)) content = content(); - case VALUE_TYPE.color : - draw_tooltip_color(content); - break; - - case VALUE_TYPE.gradient : - draw_tooltip_gradient(content); - break; - - case VALUE_TYPE.d3object : - draw_tooltip_text("[" + __txt("3D Object") + "]"); - break; - - case VALUE_TYPE.object : - draw_tooltip_text("[" + __txt("Object") + "]"); - break; - - case VALUE_TYPE.surface : - draw_tooltip_surface(content); - break; - - case VALUE_TYPE.rigid : - draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); - break; - - case VALUE_TYPE.particle : - var txt = "[" + - __txt("Particle Object") + - " (size: " + string(array_length(content)) + ") " + - "]"; - draw_tooltip_text(txt); - break; - - case VALUE_TYPE.pathnode : - draw_tooltip_text("[" + __txt("Path Object") + "]"); - break; - - case VALUE_TYPE.sdomain : - draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); - break; - - case VALUE_TYPE.strands : - var txt = __txt("Strands Object"); - if(is_struct(content)) - txt += " (strands: " + string(array_length(content.hairs)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.mesh : - var txt = __txt("Mesh Object"); - if(is_struct(content)) - txt += " (triangles: " + string(array_length(content.triangles)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.d3vertex : - var txt = __txt("3D Vertex"); - txt += " (groups: " + string(array_length(content)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.buffer : - draw_tooltip_buffer(content); - break; - - case "sprite" : - draw_tooltip_sprite(content); - break; - - default : - var tt = ""; - if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; - else tt = string(content); - - draw_tooltip_text(tt); - } - } else if(TOOLTIP != "") - draw_tooltip_text(TOOLTIP); + switch(type) { + case VALUE_TYPE.float : + case VALUE_TYPE.integer : + case VALUE_TYPE.text : + case VALUE_TYPE.struct : + case VALUE_TYPE.path : + draw_tooltip_text(string_real(content)); + break; + + case VALUE_TYPE.boolean : + draw_tooltip_text(printBool(content)); + break; + + case VALUE_TYPE.curve : + draw_tooltip_text("[" + __txt("Curve Object") + "]"); + break; + + case VALUE_TYPE.color : + draw_tooltip_color(content); + break; + + case VALUE_TYPE.gradient : + draw_tooltip_gradient(content); + break; + + case VALUE_TYPE.d3object : + draw_tooltip_text("[" + __txt("3D Object") + "]"); + break; + + case VALUE_TYPE.object : + draw_tooltip_text("[" + __txt("Object") + "]"); + break; + + case VALUE_TYPE.surface : + draw_tooltip_surface(content); + break; + + case VALUE_TYPE.rigid : + draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); + break; + + case VALUE_TYPE.particle : + var txt = "[" + + __txt("Particle Object") + + " (size: " + string(array_length(content)) + ") " + + "]"; + draw_tooltip_text(txt); + break; + + case VALUE_TYPE.pathnode : + draw_tooltip_text("[" + __txt("Path Object") + "]"); + break; + + case VALUE_TYPE.sdomain : + draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); + break; + + case VALUE_TYPE.strands : + var txt = __txt("Strands Object"); + if(is_struct(content)) + txt += " (strands: " + string(array_length(content.hairs)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.mesh : + var txt = __txt("Mesh Object"); + if(is_struct(content)) + txt += " (triangles: " + string(array_length(content.triangles)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.d3vertex : + var txt = __txt("3D Vertex"); + txt += " (groups: " + string(array_length(content)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.buffer : + draw_tooltip_buffer(content); + break; + + case "sprite" : + draw_tooltip_sprite(content); + break; + + default : + var tt = ""; + if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; + else tt = string(content); + + draw_tooltip_text(tt); + } + } else if(TOOLTIP != "") + draw_tooltip_text(TOOLTIP); + } TOOLTIP = ""; #endregion diff --git a/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup0 b/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup0 new file mode 100644 index 000000000..e6762e772 --- /dev/null +++ b/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup0 @@ -0,0 +1,670 @@ +// 2024-05-01 17:17:25 +// feather ignore all + +/// @func BBMOD_Quaternion([_x, _y, _z, _w]) +/// +/// @desc A quaternion. +/// +/// @param {Real} [_x] The first component of the quaternion. Defaults to 0. +/// @param {Real} [_y] The second component of the quaternion. Defaults to 0. +/// @param {Real} [_z] The third component of the quaternion. Defaults to 0. +/// @param {Real} [_w] The fourth component of the quaternion. Defaults to 1. +/// +/// @note If you leave the arguments to their default values, then an identity +/// quaternion is created. +function BBMOD_Quaternion(_x=0.0, _y=0.0, _z=0.0, _w=1.0) constructor +{ + /// @var {Real} The first component of the quaternion. + X = _x; + + /// @var {Real} The second component of the quaternion. + Y = _y; + + /// @var {Real} The third component of the quaternion. + Z = _z; + + /// @var {Real} The fourth component of the quaternion. + W = _w; + + static set = function(x, y, z, w) { + INLINE + X = x; + Y = y; + Z = z; + W = w; + return self; + } + + /// @func Add(_q) + /// + /// @desc Adds quaternions and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Add = function (_q) { + INLINE + return new BBMOD_Quaternion( + X + _q.X, + Y + _q.Y, + Z + _q.Z, + W + _q.W + ); + }; + + /// @func Clone() + /// + /// @desc Creates a clone of the quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Clone = function () { + INLINE + return new BBMOD_Quaternion(X, Y, Z, W); + }; + + /// @func Conjugate() + /// + /// @desc Conjugates the quaternion and returns the result as a quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Conjugate = function () { + INLINE + return new BBMOD_Quaternion(-X, -Y, -Z, W); + }; + + /// @func Copy(_dest) + /// + /// @desc Copies components of the quaternion into other quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _dest The destination quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static Copy = function (_dest) { + INLINE + _dest.X = X; + _dest.Y = Y; + _dest.Z = Z; + _dest.W = W; + return self; + }; + + /// @func Dot(_q) + /// + /// @desc Computes a dot product of two dual quaternions. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Real} The dot product of the quaternions. + static Dot = function (_q) { + INLINE + return ( + X * _q.X + + Y * _q.Y + + Z * _q.Z + + W * _q.W + ); + }; + + /// @func Exp() + /// + /// @desc Computes an exponential map of the quaternion and returns + /// the result as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Exp = function () { + INLINE + var _length = Length(); + if (_length >= math_get_epsilon()) + { + var _sinc = Sinc(_length); + return new BBMOD_Quaternion( + X * _sinc, + Y * _sinc, + Z * _sinc, + exp(W) * cos(_length) + ); + } + return new BBMOD_Quaternion(0.0, 0.0, 0.0, exp(W)); + }; + + /// @func FromArray(_array[, _index]) + /// + /// @desc Loads quaternion components `(x, y, z, w)` from an array. + /// + /// @param {Array} _array The array to read the quaternion components + /// from. + /// @param {Real} [_index] The index to start reading the quaternion + /// components from. Defaults to 0. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromArray = function (_array, _index=0) { + INLINE + X = _array[_index]; + Y = _array[_index + 1]; + Z = _array[_index + 2]; + W = _array[_index + 3]; + return self; + }; + + /// @func FromAxisAngle(_axis, _angle) + /// + /// @desc Initializes the quaternion using an axis and an angle. + /// + /// @param {Struct.BBMOD_Vec3} _axis The axis of rotaiton. + /// + /// @param {Real} _angle The rotation angle. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromAxisAngle = function (_axis, _angle) { + INLINE + _angle = -_angle; + var _sinHalfAngle = dsin(_angle * 0.5); + X = is_nan(_axis.X)? 0 : _axis.X * _sinHalfAngle; + Y = is_nan(_axis.Y)? 0 : _axis.Y * _sinHalfAngle; + Z = is_nan(_axis.Z)? 0 : _axis.Z * _sinHalfAngle; + W = dcos(_angle * 0.5); + return self; + }; + + /// @func FromBuffer(_buffer, _type) + /// + /// @desc Loads quaternion components `(x, y, z, w)` from a buffer. + /// + /// @param {Id.Buffer} _buffer The buffer to read the quaternion components + /// from. + /// + /// @param {Constant.BufferDataType} [_type] The type of each component. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromBuffer = function (_buffer, _type) { + INLINE + X = buffer_read(_buffer, _type); + Y = buffer_read(_buffer, _type); + Z = buffer_read(_buffer, _type); + W = buffer_read(_buffer, _type); + return self; + }; + + /// @func FromEuler(_x, _y, _z) + /// + /// @desc Initializes the quaternion using euler angles. + /// + /// @param {Real} _x The rotation around the X axis (in degrees). + /// @param {Real} _y The rotation around the Y axis (in degrees). + /// @param {Real} _z The rotation around the Z axis (in degrees). + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + /// + /// @note The order of rotations is YXZ, same as in the `matrix_build` + /// function. + static FromEuler = function (_x, _y, _z) { + INLINE + + _x = -_x * 0.5; + _y = -_y * 0.5; + _z = -_z * 0.5; + + var _q1Sin, _q1Cos, _temp; + var _qX, _qY, _qZ, _qW; + + _q1Sin = dsin(_z); + _q1Cos = dcos(_z); + + _temp = dsin(_x); + + _qX = _q1Cos * _temp; + _qY = _q1Sin * _temp; + + _temp = dcos(_x); + + _qZ = _q1Sin * _temp; + _qW = _q1Cos * _temp; + + _q1Sin = dsin(_y); + _q1Cos = dcos(_y); + + X = _qX * _q1Cos - _qZ * _q1Sin; + Y = _qW * _q1Sin + _qY * _q1Cos; + Z = _qZ * _q1Cos + _qX * _q1Sin; + W = _qW * _q1Cos - _qY * _q1Sin; + + return self; + }; + + /// @func FromLookRotation(_forward, _up) + /// + /// @desc Initializes the quaternion using a forward and an up vector. These + /// vectors must not be parallel! If they are, the quaternion will be set to an + /// identity. + /// + /// @param {Struct.BBMOD_Vec3} _forward The vector facing forward. + /// @param {Struct.BBMOD_Vec3} _up The vector facing up. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromLookRotation = function (_forward, _up) { + INLINE + + _forward = new BBMOD_Vec3(_forward); + _up = new BBMOD_Vec3(_up); + + if (!_forward.Orthonormalize(_up)) { + X = 0.0; + Y = 0.0; + Z = 0.0; + W = 1.0; + return self; + } + + var _right = _up.Cross(_forward); + var _w = sqrt(abs(1.0 + _right.X + _up.Y + _forward.Z)) * 0.5; + var _w4Recip = _w == 0? 0 : 1.0 / (4.0 * _w); + + X = (_up.Z - _forward.Y) * _w4Recip; + Y = (_forward.X - _right.Z) * _w4Recip; + Z = (_right.Y - _up.X) * _w4Recip; + W = _w; + return self; + }; + + static FromMatrix = function(rotMatrix) { + INLINE + + W = sqrt(1 + rotMatrix[0] + rotMatrix[5] + rotMatrix[10]) / 2; + X = (rotMatrix[9] - rotMatrix[6]) / (4 * W); + Y = (rotMatrix[2] - rotMatrix[8]) / (4 * W); + Z = (rotMatrix[4] - rotMatrix[1]) / (4 * W); + return self; + } + + /// @func GetAngle() + /// + /// @desc Retrieves the rotation angle of the quaternion. + /// + /// @return {Real} The rotation angle. + static GetAngle = function () { + INLINE + return radtodeg(arccos(W) * 2.0); + }; + + /// @func GetAxis() + /// + /// @desc Retrieves the axis of rotation of the quaternion. + /// + /// @return {Struct.BBMOD_Vec3} The axis of rotation. + static GetAxis = function () { + INLINE + var _sinThetaInv = 1.0 / sin(arccos(W)); + return new BBMOD_Vec3( + X * _sinThetaInv, + Y * _sinThetaInv, + Z * _sinThetaInv + ); + }; + + /// @func Inverse() + /// + /// @desc Computes an inverse of the quaternion and returns the result + /// as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Inverse = function () { + INLINE + return Length() == 0? new BBMOD_Quaternion() : Conjugate().Scale(1.0 / Length()); + }; + + /// @func Length() + /// + /// @desc Computes the length of the quaternion. + /// + /// @return {Real} The length of the quaternion. + static Length = function () { + INLINE + return sqrt( + X * X + + Y * Y + + Z * Z + + W * W + ); + }; + + /// @func LengthSqr() + /// + /// @desc Computes a squared length of the quaternion. + /// + /// @return {Real} The squared length of the quaternion. + static LengthSqr = function () { + INLINE + return ( + X * X + + Y * Y + + Z * Z + + W * W + ); + }; + + /// @func Lerp(_q, _s) + /// + /// @desc Computes a linear interpolation of two quaternions + /// and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// @param {Real} _s The interpolation factor. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Lerp = function (_q, _s) { + INLINE + return new BBMOD_Quaternion( + lerp(X, _q.X, _s), + lerp(Y, _q.Y, _s), + lerp(Z, _q.Z, _s), + lerp(W, _q.W, _s) + ); + }; + + /// @func Log() + /// + /// @desc Computes the logarithm map of the quaternion and returns the + /// result as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Log = function () { + INLINE + var _length = Length(); + var _w = logn(2.71828, _length); + var _a = arccos(W / _length); + if (_a >= math_get_epsilon()) + { + var _mag = 1.0 / _length / Sinc(_a); + return new BBMOD_Quaternion( + X * _mag, + Y * _mag, + Z * _mag, + _w + ); + } + return new BBMOD_Quaternion(0.0, 0.0, 0.0, _w); + }; + + /// @func Mul(_q) + /// + /// @desc Multiplies two quaternions and returns the result as a new + /// quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Mul = function (_q) { + INLINE + return new BBMOD_Quaternion( + W * _q.X + X * _q.W + Y * _q.Z - Z * _q.Y, + W * _q.Y + Y * _q.W + Z * _q.X - X * _q.Z, + W * _q.Z + Z * _q.W + X * _q.Y - Y * _q.X, + W * _q.W - X * _q.X - Y * _q.Y - Z * _q.Z + ); + }; + + /// @func Normalize() + /// + /// @desc Normalizes the quaternion and returns the result as a new + /// quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Normalize = function () { + INLINE + var _lengthSqr = LengthSqr(); + + if(_lengthSqr == 0) + return new BBMOD_Quaternion(); + + if (_lengthSqr >= math_get_epsilon()) + return Scale(1.0 / sqrt(_lengthSqr)); + return Clone(); + }; + + /// @func Rotate(_v) + /// + /// @desc Rotates a vector using the quaternion and returns the result + /// as a new vector. + /// + /// @param {Struct.BBMOD_Vec3} _v The vector to rotate. + /// + /// @return {Struct.BBMOD_Vec3} The created vector. + static Rotate = function (_v) { + INLINE + + var _tovec = is_instanceof(_v, __vec3); + if(_tovec) _v = new BBMOD_Vec3(_v.x, _v.y, _v.z); + + var _q = Normalize(); + var _V = new BBMOD_Quaternion(_v.X, _v.Y, _v.Z, 0.0); + var _rot = _q.Mul(_V).Mul(_q.Conjugate()); + + var res; + if(_tovec) res = new __vec3(_rot.X, _rot.Y, _rot.Z); + else res = new BBMOD_Vec3(_rot.X, _rot.Y, _rot.Z); + + return res; + }; + + /// @func Scale(_s) + /// + /// @desc Scales each component of the quaternion by a real value and + /// returns the result as a new quaternion. + /// + /// @param {Real} _s The value to scale the quaternion by. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Scale = function (_s) { + INLINE + return new BBMOD_Quaternion( + X * _s, + Y * _s, + Z * _s, + W * _s + ); + }; + + static Sinc = function (_x) { + INLINE + return (_x >= math_get_epsilon()) ? (sin(_x) / _x) : 1.0; + }; + + /// @func Slerp(_q, _s) + /// + /// @desc Computes a spherical linear interpolation of two quaternions + /// and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// @param {Real} _s The interpolation factor. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Slerp = function (_q, _s) { + INLINE + + var _q10 = X; + var _q11 = Y; + var _q12 = Z; + var _q13 = W; + + var _q20 = _q.X; + var _q21 = _q.Y; + var _q22 = _q.Z; + var _q23 = _q.W; + + var _norm; + + _norm = 1.0 / sqrt(_q10 * _q10 + + _q11 * _q11 + + _q12 * _q12 + + _q13 * _q13); + + _q10 *= _norm; + _q11 *= _norm; + _q12 *= _norm; + _q13 *= _norm; + + _norm = sqrt(_q20 * _q20 + + _q21 * _q21 + + _q22 * _q22 + + _q23 * _q23); + + _q20 *= _norm; + _q21 *= _norm; + _q22 *= _norm; + _q23 *= _norm; + + var _dot = _q10 * _q20 + + _q11 * _q21 + + _q12 * _q22 + + _q13 * _q23; + + if (_dot < 0.0) + { + _dot = -_dot; + _q20 *= -1.0; + _q21 *= -1.0; + _q22 *= -1.0; + _q23 *= -1.0; + } + + if (_dot > 0.9995) + { + return new BBMOD_Quaternion( + lerp(_q10, _q20, _s), + lerp(_q11, _q21, _s), + lerp(_q12, _q22, _s), + lerp(_q13, _q23, _s) + ); + } + + var _theta0 = arccos(_dot); + var _theta = _theta0 * _s; + var _sinTheta = sin(_theta); + var _sinTheta0 = sin(_theta0); + var _s2 = _sinTheta / _sinTheta0; + var _s1 = cos(_theta) - (_dot * _s2); + + return new BBMOD_Quaternion( + (_q10 * _s1) + (_q20 * _s2), + (_q11 * _s1) + (_q21 * _s2), + (_q12 * _s1) + (_q22 * _s2), + (_q13 * _s1) + (_q23 * _s2) + ); + }; + + /// @func ToArray([_array[, _index]]) + /// + /// @desc Writes components `(x, y, z, w)` of the quaternion into an array. + /// + /// @param {Array} [_array] The destination array. If not defined, a + /// new one is created. + /// @param {Real} [_index] The index to start writing to. Defaults to 0. + /// + /// @return {Array} Returns the destination array. + static ToArray = function (_array=undefined, _index=0) { + INLINE + _array ??= array_create(4, 0.0); + _array[@ _index] = X; + _array[@ _index + 1] = Y; + _array[@ _index + 2] = Z; + _array[@ _index + 3] = W; + return _array; + }; + + /// @func ToBuffer(_buffer, _type) + /// + /// @desc Writes the quaternion into a buffer. + /// + /// @param {Id.Buffer} _buffer The buffer to write the quaternion to. + /// @param {Constant.BufferDataType} _type The type of each component. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static ToBuffer = function (_buffer, _type) { + INLINE + buffer_write(_buffer, _type, X); + buffer_write(_buffer, _type, Y); + buffer_write(_buffer, _type, Z); + buffer_write(_buffer, _type, W); + return self; + }; + + static ToEuler = function(isArray = false) { + var ysqr = Y * Y; + + // roll (x-axis rotation) + var t0 = +2.0 * (W * X + Y * Z); + var t1 = +1.0 - 2.0 * (X * X + ysqr); + var roll = arctan2(t0, t1); + + // pitch (y-axis rotation) + var t2 = +2.0 * (W * Y - Z * X); + t2 = clamp(t2, -1.0, 1.0); // Prevent numerical instability + var pitch = arcsin(t2); + + // yaw (z-axis rotation) + var t3 = +2.0 * (W * Z + X * Y); + var t4 = +1.0 - 2.0 * (ysqr + Z * Z); + var yaw = arctan2(t3, t4); + + // Convert radians to degrees + var _dx = roll * 180.0 / pi; + var _dy = pitch * 180.0 / pi; + var _dz = yaw * 180.0 / pi; + + _dx = round(_dx * 1000) / 1000; + _dy = round(_dy * 1000) / 1000; + _dz = round(_dz * 1000) / 1000; + + return isArray? [ _dx, _dy, _dz ] : new __rot3(_dx, _dy, _dz); + } + + /// @func ToMatrix([_dest[, _index]]) + /// + /// @desc Converts quaternion into a matrix. + /// + /// @param {Array} [_dest] The destination array. If not specified, a + /// new one is created. + /// @param {Real} [_index] The starting index in the destination array. + /// Defaults to 0. + /// + /// @return {Array} Returns the destination array. + static ToMatrix = function (_dest=undefined, _index=0) { + INLINE + + _dest ??= matrix_build_identity(); + + if(is_nan(X)) return _dest; + + var _norm = Normalize(); + + var _temp0, _temp1, _temp2; + var _q0 = _norm.X; + var _q1 = _norm.Y; + var _q2 = _norm.Z; + var _q3 = _norm.W; + + _temp0 = _q0 * _q0; + _temp1 = _q1 * _q1; + _temp2 = _q2 * _q2; + _dest[@ _index] = 1.0 - 2.0 * (_temp1 + _temp2); + _dest[@ _index + 5] = 1.0 - 2.0 * (_temp0 + _temp2); + _dest[@ _index + 10] = 1.0 - 2.0 * (_temp0 + _temp1); + + _temp0 = _q0 * _q1; + _temp1 = _q3 * _q2; + _dest[@ _index + 1] = 2.0 * (_temp0 + _temp1); + _dest[@ _index + 4] = 2.0 * (_temp0 - _temp1); + + _temp0 = _q0 * _q2 + _temp1 = _q3 * _q1; + _dest[@ _index + 2] = 2.0 * (_temp0 - _temp1); + _dest[@ _index + 8] = 2.0 * (_temp0 + _temp1); + + _temp0 = _q1 * _q2; + _temp1 = _q3 * _q0; + _dest[@ _index + 6] = 2.0 * (_temp0 + _temp1); + _dest[@ _index + 9] = 2.0 * (_temp0 - _temp1); + + return _dest; + }; +} diff --git a/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup1 b/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup1 new file mode 100644 index 000000000..cc06f25a1 --- /dev/null +++ b/#backups/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml.backup1 @@ -0,0 +1,670 @@ +// 2024-05-01 17:17:23 +// feather ignore all + +/// @func BBMOD_Quaternion([_x, _y, _z, _w]) +/// +/// @desc A quaternion. +/// +/// @param {Real} [_x] The first component of the quaternion. Defaults to 0. +/// @param {Real} [_y] The second component of the quaternion. Defaults to 0. +/// @param {Real} [_z] The third component of the quaternion. Defaults to 0. +/// @param {Real} [_w] The fourth component of the quaternion. Defaults to 1. +/// +/// @note If you leave the arguments to their default values, then an identity +/// quaternion is created. +function BBMOD_Quaternion(_x=0.0, _y=0.0, _z=0.0, _w=1.0) constructor +{ + /// @var {Real} The first component of the quaternion. + X = _x; + + /// @var {Real} The second component of the quaternion. + Y = _y; + + /// @var {Real} The third component of the quaternion. + Z = _z; + + /// @var {Real} The fourth component of the quaternion. + W = _w; + + static set = function(x, y, z, w) { + INLINE + X = x; + Y = y; + Z = z; + W = w; + return self; + } + + /// @func Add(_q) + /// + /// @desc Adds quaternions and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Add = function (_q) { + INLINE + return new BBMOD_Quaternion( + X + _q.X, + Y + _q.Y, + Z + _q.Z, + W + _q.W + ); + }; + + /// @func Clone() + /// + /// @desc Creates a clone of the quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Clone = function () { + INLINE + return new BBMOD_Quaternion(X, Y, Z, W); + }; + + /// @func Conjugate() + /// + /// @desc Conjugates the quaternion and returns the result as a quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Conjugate = function () { + INLINE + return new BBMOD_Quaternion(-X, -Y, -Z, W); + }; + + /// @func Copy(_dest) + /// + /// @desc Copies components of the quaternion into other quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _dest The destination quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static Copy = function (_dest) { + INLINE + _dest.X = X; + _dest.Y = Y; + _dest.Z = Z; + _dest.W = W; + return self; + }; + + /// @func Dot(_q) + /// + /// @desc Computes a dot product of two dual quaternions. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Real} The dot product of the quaternions. + static Dot = function (_q) { + INLINE + return ( + X * _q.X + + Y * _q.Y + + Z * _q.Z + + W * _q.W + ); + }; + + /// @func Exp() + /// + /// @desc Computes an exponential map of the quaternion and returns + /// the result as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Exp = function () { + INLINE + var _length = Length(); + if (_length >= math_get_epsilon()) + { + var _sinc = Sinc(_length); + return new BBMOD_Quaternion( + X * _sinc, + Y * _sinc, + Z * _sinc, + exp(W) * cos(_length) + ); + } + return new BBMOD_Quaternion(0.0, 0.0, 0.0, exp(W)); + }; + + /// @func FromArray(_array[, _index]) + /// + /// @desc Loads quaternion components `(x, y, z, w)` from an array. + /// + /// @param {Array} _array The array to read the quaternion components + /// from. + /// @param {Real} [_index] The index to start reading the quaternion + /// components from. Defaults to 0. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromArray = function (_array, _index=0) { + INLINE + X = _array[_index]; + Y = _array[_index + 1]; + Z = _array[_index + 2]; + W = _array[_index + 3]; + return self; + }; + + /// @func FromAxisAngle(_axis, _angle) + /// + /// @desc Initializes the quaternion using an axis and an angle. + /// + /// @param {Struct.BBMOD_Vec3} _axis The axis of rotaiton. + /// + /// @param {Real} _angle The rotation angle. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromAxisAngle = function (_axis, _angle) { + INLINE + _angle = -_angle; + var _sinHalfAngle = dsin(_angle * 0.5); + X = is_nan(_axis.X)? 0 : _axis.X * _sinHalfAngle; + Y = is_nan(_axis.Y)? 0 : _axis.Y * _sinHalfAngle; + Z = is_nan(_axis.Z)? 0 : _axis.Z * _sinHalfAngle; + W = dcos(_angle * 0.5); + return self; + }; + + /// @func FromBuffer(_buffer, _type) + /// + /// @desc Loads quaternion components `(x, y, z, w)` from a buffer. + /// + /// @param {Id.Buffer} _buffer The buffer to read the quaternion components + /// from. + /// + /// @param {Constant.BufferDataType} [_type] The type of each component. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromBuffer = function (_buffer, _type) { + INLINE + X = buffer_read(_buffer, _type); + Y = buffer_read(_buffer, _type); + Z = buffer_read(_buffer, _type); + W = buffer_read(_buffer, _type); + return self; + }; + + /// @func FromEuler(_x, _y, _z) + /// + /// @desc Initializes the quaternion using euler angles. + /// + /// @param {Real} _x The rotation around the X axis (in degrees). + /// @param {Real} _y The rotation around the Y axis (in degrees). + /// @param {Real} _z The rotation around the Z axis (in degrees). + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + /// + /// @note The order of rotations is YXZ, same as in the `matrix_build` + /// function. + static FromEuler = function (_x, _y, _z) { + INLINE + + _x = -_x * 0.5; + _y = -_y * 0.5; + _z = -_z * 0.5; + + var _q1Sin, _q1Cos, _temp; + var _qX, _qY, _qZ, _qW; + + _q1Sin = dsin(_z); + _q1Cos = dcos(_z); + + _temp = dsin(_x); + + _qX = _q1Cos * _temp; + _qY = _q1Sin * _temp; + + _temp = dcos(_x); + + _qZ = _q1Sin * _temp; + _qW = _q1Cos * _temp; + + _q1Sin = dsin(_y); + _q1Cos = dcos(_y); + + X = _qX * _q1Cos - _qZ * _q1Sin; + Y = _qW * _q1Sin + _qY * _q1Cos; + Z = _qZ * _q1Cos + _qX * _q1Sin; + W = _qW * _q1Cos - _qY * _q1Sin; + + return self; + }; + + /// @func FromLookRotation(_forward, _up) + /// + /// @desc Initializes the quaternion using a forward and an up vector. These + /// vectors must not be parallel! If they are, the quaternion will be set to an + /// identity. + /// + /// @param {Struct.BBMOD_Vec3} _forward The vector facing forward. + /// @param {Struct.BBMOD_Vec3} _up The vector facing up. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static FromLookRotation = function (_forward, _up) { + INLINE + + _forward = new BBMOD_Vec3(_forward); + _up = new BBMOD_Vec3(_up); + + if (!_forward.Orthonormalize(_up)) { + X = 0.0; + Y = 0.0; + Z = 0.0; + W = 1.0; + return self; + } + + var _right = _up.Cross(_forward); + var _w = sqrt(abs(1.0 + _right.X + _up.Y + _forward.Z)) * 0.5; + var _w4Recip = _w == 0? 0 : 1.0 / (4.0 * _w); + + X = (_up.Z - _forward.Y) * _w4Recip; + Y = (_forward.X - _right.Z) * _w4Recip; + Z = (_right.Y - _up.X) * _w4Recip; + W = _w; + return self; + }; + + static FromMatrix = function(rotMatrix) { + INLINE + + W = sqrt(1 + rotMatrix[0] + rotMatrix[5] + rotMatrix[10]) / 2; + X = (rotMatrix[9] - rotMatrix[6]) / (4 * W); + Y = (rotMatrix[2] - rotMatrix[8]) / (4 * W); + Z = (rotMatrix[4] - rotMatrix[1]) / (4 * W); + return self; + } + + /// @func GetAngle() + /// + /// @desc Retrieves the rotation angle of the quaternion. + /// + /// @return {Real} The rotation angle. + static GetAngle = function () { + INLINE + return radtodeg(arccos(W) * 2.0); + }; + + /// @func GetAxis() + /// + /// @desc Retrieves the axis of rotation of the quaternion. + /// + /// @return {Struct.BBMOD_Vec3} The axis of rotation. + static GetAxis = function () { + INLINE + var _sinThetaInv = 1.0 / sin(arccos(W)); + return new BBMOD_Vec3( + X * _sinThetaInv, + Y * _sinThetaInv, + Z * _sinThetaInv + ); + }; + + /// @func Inverse() + /// + /// @desc Computes an inverse of the quaternion and returns the result + /// as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Inverse = function () { + INLINE + return Length() == 0? new BBMOD_Quaternion() : Conjugate().Scale(1.0 / Length()); + }; + + /// @func Length() + /// + /// @desc Computes the length of the quaternion. + /// + /// @return {Real} The length of the quaternion. + static Length = function () { + INLINE + return sqrt( + X * X + + Y * Y + + Z * Z + + W * W + ); + }; + + /// @func LengthSqr() + /// + /// @desc Computes a squared length of the quaternion. + /// + /// @return {Real} The squared length of the quaternion. + static LengthSqr = function () { + INLINE + return ( + X * X + + Y * Y + + Z * Z + + W * W + ); + }; + + /// @func Lerp(_q, _s) + /// + /// @desc Computes a linear interpolation of two quaternions + /// and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// @param {Real} _s The interpolation factor. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Lerp = function (_q, _s) { + INLINE + return new BBMOD_Quaternion( + lerp(X, _q.X, _s), + lerp(Y, _q.Y, _s), + lerp(Z, _q.Z, _s), + lerp(W, _q.W, _s) + ); + }; + + /// @func Log() + /// + /// @desc Computes the logarithm map of the quaternion and returns the + /// result as a new quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Log = function () { + INLINE + var _length = Length(); + var _w = logn(2.71828, _length); + var _a = arccos(W / _length); + if (_a >= math_get_epsilon()) + { + var _mag = 1.0 / _length / Sinc(_a); + return new BBMOD_Quaternion( + X * _mag, + Y * _mag, + Z * _mag, + _w + ); + } + return new BBMOD_Quaternion(0.0, 0.0, 0.0, _w); + }; + + /// @func Mul(_q) + /// + /// @desc Multiplies two quaternions and returns the result as a new + /// quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Mul = function (_q) { + INLINE + return new BBMOD_Quaternion( + W * _q.X + X * _q.W + Y * _q.Z - Z * _q.Y, + W * _q.Y + Y * _q.W + Z * _q.X - X * _q.Z, + W * _q.Z + Z * _q.W + X * _q.Y - Y * _q.X, + W * _q.W - X * _q.X - Y * _q.Y - Z * _q.Z + ); + }; + + /// @func Normalize() + /// + /// @desc Normalizes the quaternion and returns the result as a new + /// quaternion. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Normalize = function () { + INLINE + var _lengthSqr = LengthSqr(); + + if(_lengthSqr == 0) + return new BBMOD_Quaternion(); + + if (_lengthSqr >= math_get_epsilon()) + return Scale(1.0 / sqrt(_lengthSqr)); + return Clone(); + }; + + /// @func Rotate(_v) + /// + /// @desc Rotates a vector using the quaternion and returns the result + /// as a new vector. + /// + /// @param {Struct.BBMOD_Vec3} _v The vector to rotate. + /// + /// @return {Struct.BBMOD_Vec3} The created vector. + static Rotate = function (_v) { + INLINE + + var _tovec = is_instanceof(_v, __vec3); + if(_tovec) _v = new BBMOD_Vec3(_v.x, _v.y, _v.z); + + var _q = Normalize(); + var _V = new BBMOD_Quaternion(_v.X, _v.Y, _v.Z, 0.0); + var _rot = _q.Mul(_V).Mul(_q.Conjugate()); + + var res; + if(_tovec) res = new __vec3(_rot.X, _rot.Y, _rot.Z); + else res = new BBMOD_Vec3(_rot.X, _rot.Y, _rot.Z); + + return res; + }; + + /// @func Scale(_s) + /// + /// @desc Scales each component of the quaternion by a real value and + /// returns the result as a new quaternion. + /// + /// @param {Real} _s The value to scale the quaternion by. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Scale = function (_s) { + INLINE + return new BBMOD_Quaternion( + X * _s, + Y * _s, + Z * _s, + W * _s + ); + }; + + static Sinc = function (_x) { + INLINE + return (_x >= math_get_epsilon()) ? (sin(_x) / _x) : 1.0; + }; + + /// @func Slerp(_q, _s) + /// + /// @desc Computes a spherical linear interpolation of two quaternions + /// and returns the result as a new quaternion. + /// + /// @param {Struct.BBMOD_Quaternion} _q The other quaternion. + /// @param {Real} _s The interpolation factor. + /// + /// @return {Struct.BBMOD_Quaternion} The created quaternion. + static Slerp = function (_q, _s) { + INLINE + + var _q10 = X; + var _q11 = Y; + var _q12 = Z; + var _q13 = W; + + var _q20 = _q.X; + var _q21 = _q.Y; + var _q22 = _q.Z; + var _q23 = _q.W; + + var _norm; + + _norm = 1.0 / sqrt(_q10 * _q10 + + _q11 * _q11 + + _q12 * _q12 + + _q13 * _q13); + + _q10 *= _norm; + _q11 *= _norm; + _q12 *= _norm; + _q13 *= _norm; + + _norm = sqrt(_q20 * _q20 + + _q21 * _q21 + + _q22 * _q22 + + _q23 * _q23); + + _q20 *= _norm; + _q21 *= _norm; + _q22 *= _norm; + _q23 *= _norm; + + var _dot = _q10 * _q20 + + _q11 * _q21 + + _q12 * _q22 + + _q13 * _q23; + + if (_dot < 0.0) + { + _dot = -_dot; + _q20 *= -1.0; + _q21 *= -1.0; + _q22 *= -1.0; + _q23 *= -1.0; + } + + if (_dot > 0.9995) + { + return new BBMOD_Quaternion( + lerp(_q10, _q20, _s), + lerp(_q11, _q21, _s), + lerp(_q12, _q22, _s), + lerp(_q13, _q23, _s) + ); + } + + var _theta0 = arccos(_dot); + var _theta = _theta0 * _s; + var _sinTheta = sin(_theta); + var _sinTheta0 = sin(_theta0); + var _s2 = _sinTheta / _sinTheta0; + var _s1 = cos(_theta) - (_dot * _s2); + + return new BBMOD_Quaternion( + (_q10 * _s1) + (_q20 * _s2), + (_q11 * _s1) + (_q21 * _s2), + (_q12 * _s1) + (_q22 * _s2), + (_q13 * _s1) + (_q23 * _s2) + ); + }; + + /// @func ToArray([_array[, _index]]) + /// + /// @desc Writes components `(x, y, z, w)` of the quaternion into an array. + /// + /// @param {Array} [_array] The destination array. If not defined, a + /// new one is created. + /// @param {Real} [_index] The index to start writing to. Defaults to 0. + /// + /// @return {Array} Returns the destination array. + static ToArray = function (_array=undefined, _index=0) { + INLINE + _array ??= array_create(4, 0.0); + _array[@ _index] = X; + _array[@ _index + 1] = Y; + _array[@ _index + 2] = Z; + _array[@ _index + 3] = W; + return _array; + }; + + /// @func ToBuffer(_buffer, _type) + /// + /// @desc Writes the quaternion into a buffer. + /// + /// @param {Id.Buffer} _buffer The buffer to write the quaternion to. + /// @param {Constant.BufferDataType} _type The type of each component. + /// + /// @return {Struct.BBMOD_Quaternion} Returns `self`. + static ToBuffer = function (_buffer, _type) { + INLINE + buffer_write(_buffer, _type, X); + buffer_write(_buffer, _type, Y); + buffer_write(_buffer, _type, Z); + buffer_write(_buffer, _type, W); + return self; + }; + + static ToEuler = function(isArray = false) { + var ysqr = Y * Y; + + // roll (x-axis rotation) + var t0 = +2.0 * (W * X + Y * Z); + var t1 = +1.0 - 2.0 * (X * X + ysqr); + var roll = arctan2(t0, t1); + + // pitch (y-axis rotation) + var t2 = +2.0 * (W * Y - Z * X); + t2 = clamp(t2, -1.0, 1.0); // Prevent numerical instability + var pitch = arcsin(t2); + + // yaw (z-axis rotation) + var t3 = +2.0 * (W * Z + X * Y); + var t4 = +1.0 - 2.0 * (ysqr + Z * Z); + var yaw = arctan2(t3, t4); + + // Convert radians to degrees + var _dx = roll * 180.0 / pi; + var _dy = pitch * 180.0 / pi; + var _dz = yaw * 180.0 / pi; + + _dx = round(_dx * 1000) / 1000; + _dy = round(_dy * 1000) / 1000; + _dz = round(_dz * 1000) / 1000; + + return isArray? [ _dx, _dy, _dz ] : new __rot3(_dx, _dy, _dz); + } + + /// @func ToMatrix([_dest[, _index]]) + /// + /// @desc Converts quaternion into a matrix. + /// + /// @param {Array} [_dest] The destination array. If not specified, a + /// new one is created. + /// @param {Real} [_index] The starting index in the destination array. + /// Defaults to 0. + /// + /// @return {Array} Returns the destination array. + static ToMatrix = function (_dest=undefined, _index=0) { + INLINE + + _dest ??= matrix_build_identity(); + + if(is_nan(X)) return _dest; + + var _norm = Normalize(); + + var _temp0, _temp1, _temp2; + var _q0 = _norm.X; + var _q1 = _norm.Y; + var _q2 = _norm.Z; + var _q3 = _norm.W; + + _temp0 = _q0 * _q0; + _temp1 = _q1 * _q1; + _temp2 = _q2 * _q2; + _dest[@ _index] = 1.0 - 2.0 * (_temp1 + _temp2); + _dest[@ _index + 5] = 1.0 - 2.0 * (_temp0 + _temp2); + _dest[@ _index + 10] = 1.0 - 2.0 * (_temp0 + _temp1); + + _temp0 = _q0 * _q1; + _temp1 = _q3 * _q2; + _dest[@ _index + 1] = 2.0 * (_temp0 + _temp1); + _dest[@ _index + 4] = 2.0 * (_temp0 - _temp1); + + _temp0 = _q0 * _q2 + _temp1 = _q3 * _q1; + _dest[@ _index + 2] = 2.0 * (_temp0 - _temp1); + _dest[@ _index + 8] = 2.0 * (_temp0 + _temp1); + + _temp0 = _q1 * _q2; + _temp1 = _q3 * _q0; + _dest[@ _index + 6] = 2.0 * (_temp0 + _temp1); + _dest[@ _index + 9] = 2.0 * (_temp0 - _temp1); + + return _dest; + }; +} diff --git a/#backups/scripts/__node_3d/__node_3d.gml.backup0 b/#backups/scripts/__node_3d/__node_3d.gml.backup0 new file mode 100644 index 000000000..02294d16a --- /dev/null +++ b/#backups/scripts/__node_3d/__node_3d.gml.backup0 @@ -0,0 +1,86 @@ +// 2024-05-01 16:00:45 +function Node_3D(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "3D"; + is_3D = true; + surface_depth_disable(false); + + mesh_prev_surface = surface_create(64, 64); + + static drawOverlay3D = function(active, params, _mx, _my, _snx, _sny, _panel) {} + + static processData = function(_outSurf, _data, _output_index, _array_index) {} + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {} + + static getPreviewObject = function() { #region + if(ds_list_empty(outputs)) return noone; + + switch(outputs[| preview_channel].type) { + case VALUE_TYPE.d3Mesh : + case VALUE_TYPE.d3Light : + case VALUE_TYPE.d3Camera : + case VALUE_TYPE.d3Scene : break; + + default : return noone; + } + + var _obj = outputs[| 0].getValue(); + if(is_array(_obj)) _obj = array_safe_get_fast(_obj, preview_index, noone); + + return _obj; + } #endregion + + static getPreviewObjects = function() { return [ getPreviewObject() ]; } + + static getPreviewObjectOutline = function() { return getPreviewObjects() } + + static refreshPreview = function() { #region + var _prev_obj = getPreviewObjects(); + + mesh_prev_surface = surface_verify(mesh_prev_surface, PREFERENCES.node_3d_preview_size, PREFERENCES.node_3d_preview_size); + surface_set_target(mesh_prev_surface); + DRAW_CLEAR + + gpu_set_zwriteenable(true); + gpu_set_ztestenable(true); + gpu_set_cullmode(cull_noculling); + + D3D_GLOBAL_PREVIEW.camera.applyCamera(); + D3D_GLOBAL_PREVIEW.apply(); + + for( var i = 0, n = array_length(_prev_obj); i < n; i++ ) { + var _prev = _prev_obj[i]; + if(!is_struct(_prev) || !struct_has(_prev, "getBBOX")) continue; + + var _b = _prev.getBBOX(); + var _c = _prev.getCenter(); + if(_b == noone || _c == noone) continue; + + D3D_GLOBAL_PREVIEW.custom_transform.position.set(_c._multiply(-1)); + + var _sca = 2 / _b.getScale(); + //print($"Submitting object {_prev}\n{_b}, {_c}, {_sca}"); + + D3D_GLOBAL_PREVIEW.custom_transform.scale.set(_sca); + D3D_GLOBAL_PREVIEW.submitUI(_prev); + } + surface_reset_target(); + + D3D_GLOBAL_PREVIEW.camera.resetCamera(); + } #endregion + + static postProcess = function() { refreshPreview(); } + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) { #region + if(!is_surface(mesh_prev_surface)) return; + if(!previewable) return; + + var bbox = drawGetBbox(xx, yy, _s); + var aa = 0.5 + 0.5 * renderActive; + if(!isHighlightingInGraph()) aa *= 0.25; + + draw_surface_bbox(mesh_prev_surface, bbox,, aa); + onDrawNodeOver(xx, yy, _mx, _my, _s, _hover, _focus); + } #endregion + + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) { } +} \ No newline at end of file diff --git a/#backups/scripts/__node_3d/__node_3d.gml.backup1 b/#backups/scripts/__node_3d/__node_3d.gml.backup1 new file mode 100644 index 000000000..60ed1286d --- /dev/null +++ b/#backups/scripts/__node_3d/__node_3d.gml.backup1 @@ -0,0 +1,86 @@ +// 2024-05-01 16:00:18 +function Node_3D(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "3D"; + is_3D = true; + surface_depth_disable(false); + + mesh_prev_surface = surface_create(64, 64); + + static drawOverlay3D = function(active, params, _mx, _my, _snx, _sny, _panel) {} + + static processData = function(_outSurf, _data, _output_index, _array_index) {} + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {} + + static getPreviewObject = function() { #region + if(ds_list_empty(outputs)) return noone; + + switch(outputs[| preview_channel].type) { + case VALUE_TYPE.d3Mesh : + case VALUE_TYPE.d3Light : + case VALUE_TYPE.d3Camera : + case VALUE_TYPE.d3Scene : break; + + default : return noone; + } + + var _obj = outputs[| 0].getValue(); + if(is_array(_obj)) _obj = array_safe_get_fast(_obj, preview_index, noone); + + return _obj; + } #endregion + + static getPreviewObjects = function() { return [ getPreviewObject() ]; } + + static getPreviewObjectOutline = function() { return getPreviewObjects() } + + static refreshPreview = function() { #region + var _prev_obj = getPreviewObjects(); + + mesh_prev_surface = surface_verify(mesh_prev_surface, PREFERENCES.node_3d_preview_size, PREFERENCES.node_3d_preview_size); + surface_set_target(mesh_prev_surface); + DRAW_CLEAR + + gpu_set_zwriteenable(true); + gpu_set_ztestenable(true); + gpu_set_cullmode(cull_noculling); + + D3D_GLOBAL_PREVIEW.camera.applyCamera(); + D3D_GLOBAL_PREVIEW.apply(); + + for( var i = 0, n = array_length(_prev_obj); i < n; i++ ) { + var _prev = _prev_obj[i]; + if(!is_struct(_prev) || !struct_has(_prev, "getBBOX")) continue; + + var _b = _prev.getBBOX(); + var _c = _prev.getCenter(); + if(_b == noone || _c == noone) continue; + + D3D_GLOBAL_PREVIEW.custom_transform.position.set(_c._multiply(-1)); + + var _sca = 2 / _b.getScale(); + //print($"Submitting object {_prev}\n{_b}, {_c}, {_sca}"); + + D3D_GLOBAL_PREVIEW.custom_transform.scale.set(_sca); + D3D_GLOBAL_PREVIEW.submitUI(_prev); + } + surface_reset_target(); + + D3D_GLOBAL_PREVIEW.camera.resetCamera(); + } #endregion + + static postProcess = function() { refreshPreview(); } + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) { #region + if(!is_surface(mesh_prev_surface)) return; + if(!previewable) return; + + var bbox = drawGetBbox(xx, yy, _s); + var aa = 0.5 + 0.5 * renderActive; + if(!isHighlightingInGraph()) aa *= 0.25; + + draw_surface_bbox(mesh_prev_surface, bbox,, aa); + onDrawNodeOver(xx, yy, _mx, _my, _s, _hover, _focus); + } #endregion + + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) { } +} \ No newline at end of file diff --git a/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup0 b/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup0 new file mode 100644 index 000000000..a5b61d4c7 --- /dev/null +++ b/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup0 @@ -0,0 +1,633 @@ +// 2024-05-01 16:28:40 +function Node_3D_Object(_x, _y, _group = noone) : Node_3D(_x, _y, _group) constructor { + name = "3D Object"; + cached_object = []; + object_class = noone; + + preview_channel = 0; + + inputs[| 0] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 1] = nodeValue("Rotation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0, 1 ]) + .setDisplay(VALUE_DISPLAY.d3quarternion); + + inputs[| 2] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1, 1 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 3] = nodeValue("Anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + in_d3d = ds_list_size(inputs); + + #macro __d3d_input_list_transform ["Transform", false], 0, 3, 1, 2 + + #region ---- overlay ---- + drag_axis = noone; + drag_sv = 0; + drag_delta = 0; + drag_prev = 0; + drag_dist = 0; + drag_val = 0; + + drag_mx = 0; + drag_my = 0; + drag_px = 0; + drag_py = 0; + drag_cx = 0; + drag_cy = 0; + drag_rot_axis = new BBMOD_Quaternion(); + + drag_original = 0; + + axis_hover = noone; + #endregion + + #region ---- tools ---- + tool_pos = new NodeTool( "Transform", THEME.tools_3d_transform, "Node_3D_Object" ); + tool_rot = new NodeTool( "Rotate", THEME.tools_3d_rotate, "Node_3D_Object" ); + tool_sca = new NodeTool( "Scale", THEME.tools_3d_scale, "Node_3D_Object" ); + tools = [ tool_pos, tool_rot, tool_sca ]; + + tool_axis_edit = new scrollBox([ "local", "global" ], function(val) { tool_attribute.context = val; }); + // tool_axis_edit.font = f_p2; + // tool_axis_edit.arrow_spr = THEME.arrow; + // tool_axis_edit.arrow_ind = 3; + tool_attribute.context = 0; + tool_settings = [ + [ "Axis", tool_axis_edit, "context", tool_attribute ], + ]; + + static getToolSettings = function() { + if(isUsingTool("Transform") || isUsingTool("Rotate")) + return tool_settings; + return []; + } + #endregion + + static drawGizmoPosition = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + #region ---- main ---- + var _pos = inputs[| index].getValue(,,, true); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, 0, size); + ga[2] = new BBMOD_Vec3(0, -size, 0); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, 0, hs - sq), + new BBMOD_Vec3(-hs - sq, 0, hs - sq), + new BBMOD_Vec3(-hs - sq, 0, hs + sq), + new BBMOD_Vec3(-hs + sq, 0, hs + sq), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, hs - sq), + new BBMOD_Vec3( 0, -hs - sq, hs - sq), + new BBMOD_Vec3( 0, -hs - sq, hs + sq), + new BBMOD_Vec3( 0, -hs + sq, hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, -size, 0); + ga[2] = new BBMOD_Vec3(0, 0, -size); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs + sq), + new BBMOD_Vec3( 0, -hs + sq, -hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs + sq), + new BBMOD_Vec3(-hs + sq, 0, -hs + sq), ]; + + for( var i = 0; i < 3; i++ ) { + if(_axis == 0) + ga[i] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i]))); + else if(_axis == 1) + ga[i] = _qview.Rotate(_qinv.Rotate(ga[i])); + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + if(point_distance(cx, cy, cx + ga[i].X, cy + ga[i].Y) < 5) + draw_line_round(cx, cy, cx + ga[i].X, cy + ga[i].Y, th); + else + draw_line_round_arrow(cx, cy, cx + ga[i].X, cy + ga[i].Y, th, 3); + + var _d = distance_to_line(_mx, _my, cx, cy, cx + ga[i].X, cy + ga[i].Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + for( var i = 3; i < 6; i++ ) { + for( var j = 0; j < 4; j++ ) { + if(_axis == 0) + ga[i][j] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i][j]))); + else if(_axis == 1) + ga[i][j] = _qview.Rotate(_qinv.Rotate(ga[i][j])); + } + + th = 1; + + var p0x = cx + ga[i][0].X, p0y = cy + ga[i][0].Y; + var p1x = cx + ga[i][1].X, p1y = cy + ga[i][1].Y; + var p2x = cx + ga[i][2].X, p2y = cy + ga[i][2].Y; + var p3x = cx + ga[i][3].X, p3y = cy + ga[i][3].Y; + + var _pax = (p0x + p1x + p2x + p3x) / 4; + var _pay = (p0y + p1y + p2y + p3y) / 4; + + if((abs(p0x - _pax) + abs(p1x - _pax) + abs(p2x - _pax) + abs(p3x - _pax)) / 4 < 1) + continue; + if((abs(p0y - _pay) + abs(p1y - _pay) + abs(p2y - _pay) + abs(p3y - _pay)) / 4 < 1) + continue; + + draw_set_color(COLORS.axis[(i - 3 - 1 + 3) % 3]); + if(axis_hover == i || drag_axis == i) { + draw_primitive_begin(pr_trianglestrip); + draw_vertex(p0x, p0y); + draw_vertex(p1x, p1y); + draw_vertex(p3x, p3y); + draw_vertex(p2x, p2y); + draw_primitive_end(); + } else if (drag_axis == noone) { + draw_line(p0x, p0y, p1x, p1y); + draw_line(p1x, p1y, p2x, p2y); + draw_line(p2x, p2y, p3x, p3y); + draw_line(p3x, p3y, p0x, p0y); + } else + continue; + + if(point_in_rectangle_points(_mx, _my, p0x, p0y, p1x, p1y, p3x, p3y, p2x, p2y)) + _hover = i; + } + + axis_hover = _hover; + #endregion display + + if(drag_axis != noone) { #region editing + if(!MOUSE_WRAPPING) { + drag_mx += _mx - drag_px; + drag_my += _my - drag_py; + + var mAdj, nor, prj; + + var ray = _camera.viewPointToWorldRay(drag_mx, drag_my); + var val = [ drag_val[0], drag_val[1], drag_val[2] ]; + + if(drag_axis < 3) { + switch(drag_axis) { + case 0 : nor = new __vec3(0, 1, 0); prj = new __vec3(1, 0, 0); break; + case 1 : nor = new __vec3(0, 0, 1); prj = new __vec3(0, 1, 0); break; + case 2 : nor = new __vec3(1, 0, 0); prj = new __vec3(0, 0, 1); break; + } + + if(_axis == 0) { + nor = _qrot.Rotate(nor); + prj = _qrot.Rotate(prj); + } + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + var _dist = _diff.dot(prj); + + for( var i = 0; i < 3; i++ ) + val[i] += prj.getIndex(i) * _dist; + + if(inputs[| index].setValue(value_snap(val, _snx))) + UNDO_HOLDING = true; + } + } else { + switch(drag_axis) { + case 3 : nor = new __vec3(0, 0, 1); break; + case 4 : nor = new __vec3(1, 0, 0); break; + case 5 : nor = new __vec3(0, 1, 0); break; + } + + if(_axis == 0) + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + + for( var i = 0; i < 3; i++ ) + val[i] += _diff.getIndex(i); + + if(inputs[| index].setValue(value_snap(val, _snx))) + UNDO_HOLDING = true; + } + } + + drag_val = [ val[0], val[1], val[2] ]; + drag_prev = mAdj; + } + + setMouseWrap(); + drag_px = _mx; + drag_py = _my; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_mx = _mx; + drag_my = _my; + drag_px = _mx; + drag_py = _my; + drag_cx = cx; + drag_cy = cy; + + drag_val = _pos; + drag_original = new __vec3(_pos); + } #endregion + } #endregion + + static drawGizmoRotation = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + #region ---- main ---- + var _rot = inputs[| index].getValue(); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + var size = 64; + for( var i = 0; i < 3; i++ ) { + var op, np; + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + for( var j = 0; j <= 32; j++ ) { + var ang = j / 32 * 360; + + switch(i) { + case 0 : np = new BBMOD_Vec3(0, lengthdir_x(size, ang), lengthdir_y(size, ang)); break; + case 1 : np = new BBMOD_Vec3(lengthdir_x(size, ang), lengthdir_y(size, ang), 0); break; + case 2 : np = new BBMOD_Vec3(lengthdir_x(size, ang), 0, lengthdir_y(size, ang)); break; + } + + if(_axis == 0) + np = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(np))); + else if(_axis == 1) + np = _qview.Rotate(_qinv.Rotate(np)); + + if(j && (op.Z > 0 && np.Z > 0 || drag_axis == i)) { + draw_line_round(cx + op.X, cy + op.Y, cx + np.X, cy + np.Y, th); + var _d = distance_to_line(_mx, _my, cx + op.X, cy + op.Y, cx + np.X, cy + np.Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + op = np; + } + } + axis_hover = _hover; + #endregion + + if(drag_axis != noone) { #region + var mAng = point_direction(cx, cy, _mx, _my); + + if(drag_rot_axis == undefined) { + drag_rot_axis = BBMOD_VEC3_FORWARD; + + switch(drag_axis) { + case 0 : drag_rot_axis = new BBMOD_Vec3(-1, 0, 0); break; + case 1 : drag_rot_axis = new BBMOD_Vec3( 0, 0, -1); break; + case 2 : drag_rot_axis = new BBMOD_Vec3( 0, -1, 0); break; + } + + if(_axis == 0) drag_rot_axis = _qrot.Rotate(drag_rot_axis).Normalize(); + } + + var _nv = _qview.Rotate(_qinv.Rotate(drag_rot_axis)); + draw_line_round(cx, cy, cx + _nv.X * 100, cy + _nv.Y * 100, 2); + + if(drag_prev != undefined) { + var _rd = (mAng - drag_prev) * (_nv.Z > 0? 1 : -1); + drag_dist += _rd; + var _dist = value_snap(drag_dist, _sny); + + var _currR = new BBMOD_Quaternion().FromAxisAngle(drag_rot_axis, _dist); + var _val = _currR.Mul(drag_val); + var _Nrot = _val.ToArray(); + + if(inputs[| index].setValue(_Nrot)) + UNDO_HOLDING = true; + } + + draw_set_color(COLORS._main_accent); + draw_line_dashed(cx, cy, _mx, _my, 1, 4); + + drag_prev = mAng; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_val = _qrot.Clone(); + drag_dist = 0; + + drag_rot_axis = undefined; + } #endregion + } #endregion + + static drawGizmoScale = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + tool_attribute.context = 0; + #region ---- main ---- + var _sca = inputs[| index].getValue(,,, true); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, -size, 0); + ga[2] = new BBMOD_Vec3(0, 0, -size); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs + sq), + new BBMOD_Vec3( 0, -hs + sq, -hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs + sq), + new BBMOD_Vec3(-hs + sq, 0, -hs + sq), ]; + + for( var i = 0; i < 3; i++ ) { + ga[i] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i]))); + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + if(point_distance(cx, cy, cx + ga[i].X, cy + ga[i].Y) < 5) + draw_line_round(cx, cy, cx + ga[i].X, cy + ga[i].Y, th); + else + draw_line_round_arrow_block(cx, cy, cx + ga[i].X, cy + ga[i].Y, th, 3); + + var _d = distance_to_line(_mx, _my, cx, cy, cx + ga[i].X, cy + ga[i].Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + for( var i = 3; i < 6; i++ ) { + for( var j = 0; j < 4; j++ ) { + if(_axis == 0) + ga[i][j] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i][j]))); + else + ga[i][j] = _qview.Rotate(_qinv.Rotate(ga[i][j])); + } + + th = 1; + + var p0x = cx + ga[i][0].X, p0y = cy + ga[i][0].Y; + var p1x = cx + ga[i][1].X, p1y = cy + ga[i][1].Y; + var p2x = cx + ga[i][2].X, p2y = cy + ga[i][2].Y; + var p3x = cx + ga[i][3].X, p3y = cy + ga[i][3].Y; + + var _pax = (p0x + p1x + p2x + p3x) / 4; + var _pay = (p0y + p1y + p2y + p3y) / 4; + + if((abs(p0x - _pax) + abs(p1x - _pax) + abs(p2x - _pax) + abs(p3x - _pax)) / 4 < 1) + continue; + if((abs(p0y - _pay) + abs(p1y - _pay) + abs(p2y - _pay) + abs(p3y - _pay)) / 4 < 1) + continue; + + draw_set_color(COLORS.axis[(i - 3 - 1 + 3) % 3]); + if(axis_hover == i || drag_axis == i) { + draw_primitive_begin(pr_trianglestrip); + draw_vertex(p0x, p0y); + draw_vertex(p1x, p1y); + draw_vertex(p3x, p3y); + draw_vertex(p2x, p2y); + draw_primitive_end(); + } else if (drag_axis == noone) { + draw_line(p0x, p0y, p1x, p1y); + draw_line(p1x, p1y, p2x, p2y); + draw_line(p2x, p2y, p3x, p3y); + draw_line(p3x, p3y, p0x, p0y); + } else + continue; + + if(point_in_rectangle_points(_mx, _my, p0x, p0y, p1x, p1y, p3x, p3y, p2x, p2y)) + _hover = i; + } + + axis_hover = _hover; + #endregion + + if(drag_axis != noone) { #region editing + if(!MOUSE_WRAPPING) { + drag_mx += _mx - drag_px; + drag_my += _my - drag_py; + + var mAdj, nor, prj; + var ray = _camera.viewPointToWorldRay(drag_mx, drag_my); + + if(drag_axis < 3) { + switch(drag_axis) { + case 0 : nor = new __vec3(0, 1, 0); prj = new __vec3(1, 0, 0); break; + case 1 : nor = new __vec3(0, 0, 1); prj = new __vec3(0, 1, 0); break; + case 2 : nor = new __vec3(1, 0, 0); prj = new __vec3(0, 0, 1); break; + } + + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + var _dist = _diff.dot(prj); + + drag_val[drag_axis] += prj.getIndex(drag_axis) * _dist; + + if(inputs[| index].setValue(value_snap(drag_val, _snx))) + UNDO_HOLDING = true; + } + } else { + switch(drag_axis) { + case 3 : nor = new __vec3(0, 0, 1); break; + case 4 : nor = new __vec3(1, 0, 0); break; + case 5 : nor = new __vec3(0, 1, 0); break; + } + + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + + for( var i = 0; i < 3; i++ ) + drag_val[i] += _diff.getIndex(i); + + if(inputs[| index].setValue(value_snap(drag_val, _snx))) + UNDO_HOLDING = true; + } + } + + drag_prev = mAdj; + } + + setMouseWrap(); + drag_px = _mx; + drag_py = _my; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_mx = _mx; + drag_my = _my; + drag_px = _mx; + drag_py = _my; + drag_cx = cx; + drag_cy = cy; + + drag_val = [ _sca[0], _sca[1], _sca[2] ]; + drag_original = new __vec3(_sca); + } #endregion + } #endregion + + static drawOverlay3D = function(active, params, _mx, _my, _snx, _sny, _panel) { #region + var object = getPreviewObjects(); + if(array_empty(object)) return; + object = object[0]; + + var _pos = inputs[| 0].getValue(,,, true); + var _vpos = new __vec3( _pos[0], _pos[1], _pos[2] ); + + if(isUsingTool("Transform")) drawGizmoPosition(0, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + else if(isUsingTool("Rotate")) drawGizmoRotation(1, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + else if(isUsingTool("Scale")) drawGizmoScale(2, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + + if(drag_axis != noone && mouse_release(mb_left)) { + drag_axis = noone; + UNDO_HOLDING = false; + } + + if(onDrawOverlay3D != 0) onDrawOverlay3D(active, params, _mx, _my, _snx, _sny, _panel); + } #endregion + + static onDrawOverlay3D = 0; + + static setTransform = function(object, _data) { #region + if(object == noone) return; + var _pos = _data[0]; + var _rot = _data[1]; + var _sca = _data[2]; + var _anc = _data[3]; + + object.transform.position.set( _pos[0], _pos[1], _pos[2]); + object.transform.anchor.set( _anc[0], _anc[1], _anc[2]); + object.transform.rotation.set( _rot[0], _rot[1], _rot[2], _rot[3]); + object.transform.scale.set( _sca[0], _sca[1], _sca[2]); + + return object; + } #endregion + + static getObject = function(index, class = object_class) { #region + var _obj = array_safe_get_fast(cached_object, index, noone); + if(_obj == noone) { + _obj = new class(); + } else if(!is_instanceof(_obj, class)) { + _obj.destroy(); + _obj = new class(); + } + + cached_object[index] = _obj; + return _obj; + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup1 b/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup1 new file mode 100644 index 000000000..11fd654c9 --- /dev/null +++ b/#backups/scripts/__node_3d_object/__node_3d_object.gml.backup1 @@ -0,0 +1,633 @@ +// 2024-05-01 16:28:38 +function Node_3D_Object(_x, _y, _group = noone) : Node_3D(_x, _y, _group) constructor { + name = "3D Object"; + cached_object = []; + object_class = noone; + + preview_channel = 0; + + inputs[| 0] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 1] = nodeValue("Rotation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0, 1 ]) + .setDisplay(VALUE_DISPLAY.d3quarternion); + + inputs[| 2] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1, 1 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 3] = nodeValue("Anchor", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + in_d3d = ds_list_size(inputs); + + #macro __d3d_input_list_transform ["Transform", false], 0, 3, 1, 2 + + #region ---- overlay ---- + drag_axis = noone; + drag_sv = 0; + drag_delta = 0; + drag_prev = 0; + drag_dist = 0; + drag_val = 0; + + drag_mx = 0; + drag_my = 0; + drag_px = 0; + drag_py = 0; + drag_cx = 0; + drag_cy = 0; + drag_rot_axis = new BBMOD_Quaternion(); + + drag_original = 0; + + axis_hover = noone; + #endregion + + #region ---- tools ---- + tool_pos = new NodeTool( "Transform", THEME.tools_3d_transform, "Node_3D_Object" ); + tool_rot = new NodeTool( "Rotate", THEME.tools_3d_rotate, "Node_3D_Object" ); + tool_sca = new NodeTool( "Scale", THEME.tools_3d_scale, "Node_3D_Object" ); + tools = [ tool_pos, tool_rot, tool_sca ]; + + tool_axis_edit = new scrollBox([ "local", "global" ], function(val) { tool_attribute.context = val; }); + // tool_axis_edit.font = f_p2; + // tool_axis_edit.arrow_spr = THEME.arrow; + // tool_axis_edit.arrow_ind = 3; + tool_attribute.context = 0; + tool_settings = [ + [ "Axis", tool_axis_edit, "context", tool_attribute ], + ]; + + static getToolSettings = function() { + if(isUsingTool("Transform") || isUsingTool("Rotate")) + return tool_settings; + return []; + } + #endregion + + static drawGizmoPosition = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + #region ---- main ---- + var _pos = inputs[| index].getValue(,,, true); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, 0, size); + ga[2] = new BBMOD_Vec3(0, -size, 0); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, 0, hs - sq), + new BBMOD_Vec3(-hs - sq, 0, hs - sq), + new BBMOD_Vec3(-hs - sq, 0, hs + sq), + new BBMOD_Vec3(-hs + sq, 0, hs + sq), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, hs - sq), + new BBMOD_Vec3( 0, -hs - sq, hs - sq), + new BBMOD_Vec3( 0, -hs - sq, hs + sq), + new BBMOD_Vec3( 0, -hs + sq, hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, -size, 0); + ga[2] = new BBMOD_Vec3(0, 0, -size); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs + sq), + new BBMOD_Vec3( 0, -hs + sq, -hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs + sq), + new BBMOD_Vec3(-hs + sq, 0, -hs + sq), ]; + + for( var i = 0; i < 3; i++ ) { + if(_axis == 0) + ga[i] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i]))); + else if(_axis == 1) + ga[i] = _qview.Rotate(_qinv.Rotate(ga[i])); + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + if(point_distance(cx, cy, cx + ga[i].X, cy + ga[i].Y) < 5) + draw_line_round(cx, cy, cx + ga[i].X, cy + ga[i].Y, th); + else + draw_line_round_arrow(cx, cy, cx + ga[i].X, cy + ga[i].Y, th, 3); + + var _d = distance_to_line(_mx, _my, cx, cy, cx + ga[i].X, cy + ga[i].Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + for( var i = 3; i < 6; i++ ) { + for( var j = 0; j < 4; j++ ) { + if(_axis == 0) + ga[i][j] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i][j]))); + else if(_axis == 1) + ga[i][j] = _qview.Rotate(_qinv.Rotate(ga[i][j])); + } + + th = 1; + + var p0x = cx + ga[i][0].X, p0y = cy + ga[i][0].Y; + var p1x = cx + ga[i][1].X, p1y = cy + ga[i][1].Y; + var p2x = cx + ga[i][2].X, p2y = cy + ga[i][2].Y; + var p3x = cx + ga[i][3].X, p3y = cy + ga[i][3].Y; + + var _pax = (p0x + p1x + p2x + p3x) / 4; + var _pay = (p0y + p1y + p2y + p3y) / 4; + + if((abs(p0x - _pax) + abs(p1x - _pax) + abs(p2x - _pax) + abs(p3x - _pax)) / 4 < 1) + continue; + if((abs(p0y - _pay) + abs(p1y - _pay) + abs(p2y - _pay) + abs(p3y - _pay)) / 4 < 1) + continue; + + draw_set_color(COLORS.axis[(i - 3 - 1 + 3) % 3]); + if(axis_hover == i || drag_axis == i) { + draw_primitive_begin(pr_trianglestrip); + draw_vertex(p0x, p0y); + draw_vertex(p1x, p1y); + draw_vertex(p3x, p3y); + draw_vertex(p2x, p2y); + draw_primitive_end(); + } else if (drag_axis == noone) { + draw_line(p0x, p0y, p1x, p1y); + draw_line(p1x, p1y, p2x, p2y); + draw_line(p2x, p2y, p3x, p3y); + draw_line(p3x, p3y, p0x, p0y); + } else + continue; + + if(point_in_rectangle_points(_mx, _my, p0x, p0y, p1x, p1y, p3x, p3y, p2x, p2y)) + _hover = i; + } + + axis_hover = _hover; + #endregion display + + if(drag_axis != noone) { #region editing + if(!MOUSE_WRAPPING) { + drag_mx += _mx - drag_px; + drag_my += _my - drag_py; + + var mAdj, nor, prj; + + var ray = _camera.viewPointToWorldRay(drag_mx, drag_my); + var val = [ drag_val[0], drag_val[1], drag_val[2] ]; + + if(drag_axis < 3) { + switch(drag_axis) { + case 0 : nor = new __vec3(0, 1, 0); prj = new __vec3(1, 0, 0); break; + case 1 : nor = new __vec3(0, 0, 1); prj = new __vec3(0, 1, 0); break; + case 2 : nor = new __vec3(1, 0, 0); prj = new __vec3(0, 0, 1); break; + } + + if(_axis == 0) { + nor = _qrot.Rotate(nor); + prj = _qrot.Rotate(prj); + } + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + var _dist = _diff.dot(prj); + + for( var i = 0; i < 3; i++ ) + val[i] += prj.getIndex(i) * _dist; + + if(inputs[| index].setValue(value_snap(val, _snx))) + UNDO_HOLDING = true; + } + } else { + switch(drag_axis) { + case 3 : nor = new __vec3(0, 0, 1); break; + case 4 : nor = new __vec3(1, 0, 0); break; + case 5 : nor = new __vec3(0, 1, 0); break; + } + + if(_axis == 0) + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + + for( var i = 0; i < 3; i++ ) + val[i] += _diff.getIndex(i); + + if(inputs[| index].setValue(value_snap(val, _snx))) + UNDO_HOLDING = true; + } + } + + drag_val = [ val[0], val[1], val[2] ]; + drag_prev = mAdj; + } + + setMouseWrap(); + drag_px = _mx; + drag_py = _my; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_mx = _mx; + drag_my = _my; + drag_px = _mx; + drag_py = _my; + drag_cx = cx; + drag_cy = cy; + + drag_val = _pos; + drag_original = new __vec3(_pos); + } #endregion + } #endregion + + static drawGizmoRotation = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + #region ---- main ---- + var _rot = inputs[| index].getValue(); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + var size = 64; + for( var i = 0; i < 3; i++ ) { + var op, np; + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + for( var j = 0; j <= 32; j++ ) { + var ang = j / 32 * 360; + + switch(i) { + case 0 : np = new BBMOD_Vec3(0, lengthdir_x(size, ang), lengthdir_y(size, ang)); break; + case 1 : np = new BBMOD_Vec3(lengthdir_x(size, ang), lengthdir_y(size, ang), 0); break; + case 2 : np = new BBMOD_Vec3(lengthdir_x(size, ang), 0, lengthdir_y(size, ang)); break; + } + + if(_axis == 0) + np = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(np))); + else if(_axis == 1) + np = _qview.Rotate(_qinv.Rotate(np)); + + if(j && (op.Z > 0 && np.Z > 0 || drag_axis == i)) { + draw_line_round(cx + op.X, cy + op.Y, cx + np.X, cy + np.Y, th); + var _d = distance_to_line(_mx, _my, cx + op.X, cy + op.Y, cx + np.X, cy + np.Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + op = np; + } + } + axis_hover = _hover; + #endregion + + if(drag_axis != noone) { #region + var mAng = point_direction(cx, cy, _mx, _my); + + if(drag_rot_axis == undefined) { + drag_rot_axis = BBMOD_VEC3_FORWARD; + + switch(drag_axis) { + case 0 : drag_rot_axis = new BBMOD_Vec3(-1, 0, 0); break; + case 1 : drag_rot_axis = new BBMOD_Vec3( 0, 0, -1); break; + case 2 : drag_rot_axis = new BBMOD_Vec3( 0, -1, 0); break; + } + + if(_axis == 0) drag_rot_axis = _qrot.Rotate(drag_rot_axis).Normalize(); + } + + var _nv = _qview.Rotate(_qinv.Rotate(drag_rot_axis)); + draw_line_round(cx, cy, cx + _nv.X * 100, cy + _nv.Y * 100, 2); + + if(drag_prev != undefined) { + var _rd = (mAng - drag_prev) * (_nv.Z > 0? 1 : -1); + drag_dist += _rd; + var _dist = value_snap(drag_dist, _sny); + + var _currR = new BBMOD_Quaternion().FromAxisAngle(drag_rot_axis, _dist); + var _val = _currR.Mul(drag_val); + var _Nrot = _val.ToArray(); + + if(inputs[| index].setValue(_Nrot)) + UNDO_HOLDING = true; + } + + draw_set_color(COLORS._main_accent); + draw_line_dashed(cx, cy, _mx, _my, 1, 4); + + drag_prev = mAng; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_val = _qrot.Clone(); + drag_dist = 0; + + drag_rot_axis = undefined; + } #endregion + } #endregion + + static drawGizmoScale = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region + tool_attribute.context = 0; + #region ---- main ---- + var _sca = inputs[| index].getValue(,,, true); + var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; + var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); + + var _camera = params.camera; + var _qview = new BBMOD_Quaternion().FromEuler(_camera.focus_angle_y, -_camera.focus_angle_x, 0); + + var _axis = tool_attribute.context; + + var _hover = noone; + var _hoverDist = 10; + var th; + + var _posView = _camera.worldPointToViewPoint(_vpos); + + var cx = _posView.x; + var cy = _posView.y; + + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + #endregion + + #region display + var ga = []; + var size = 64; + var hs = size / 2; + var sq = 8; + + ga[0] = new BBMOD_Vec3(-size, 0, 0); + ga[1] = new BBMOD_Vec3(0, -size, 0); + ga[2] = new BBMOD_Vec3(0, 0, -size); + + ga[3] = [ new BBMOD_Vec3(-hs + sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs - sq, 0), + new BBMOD_Vec3(-hs - sq, -hs + sq, 0), + new BBMOD_Vec3(-hs + sq, -hs + sq, 0), ]; + ga[4] = [ new BBMOD_Vec3( 0, -hs + sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs - sq), + new BBMOD_Vec3( 0, -hs - sq, -hs + sq), + new BBMOD_Vec3( 0, -hs + sq, -hs + sq), ]; + ga[5] = [ new BBMOD_Vec3(-hs + sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs - sq), + new BBMOD_Vec3(-hs - sq, 0, -hs + sq), + new BBMOD_Vec3(-hs + sq, 0, -hs + sq), ]; + + for( var i = 0; i < 3; i++ ) { + ga[i] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i]))); + + th = 2 + (axis_hover == i || drag_axis == i); + if(drag_axis != noone && drag_axis != i) + continue; + + draw_set_color(COLORS.axis[i]); + if(point_distance(cx, cy, cx + ga[i].X, cy + ga[i].Y) < 5) + draw_line_round(cx, cy, cx + ga[i].X, cy + ga[i].Y, th); + else + draw_line_round_arrow_block(cx, cy, cx + ga[i].X, cy + ga[i].Y, th, 3); + + var _d = distance_to_line(_mx, _my, cx, cy, cx + ga[i].X, cy + ga[i].Y); + if(_d < _hoverDist) { + _hover = i; + _hoverDist = _d; + } + } + + for( var i = 3; i < 6; i++ ) { + for( var j = 0; j < 4; j++ ) { + if(_axis == 0) + ga[i][j] = _qview.Rotate(_qinv.Rotate(_qrot.Rotate(ga[i][j]))); + else + ga[i][j] = _qview.Rotate(_qinv.Rotate(ga[i][j])); + } + + th = 1; + + var p0x = cx + ga[i][0].X, p0y = cy + ga[i][0].Y; + var p1x = cx + ga[i][1].X, p1y = cy + ga[i][1].Y; + var p2x = cx + ga[i][2].X, p2y = cy + ga[i][2].Y; + var p3x = cx + ga[i][3].X, p3y = cy + ga[i][3].Y; + + var _pax = (p0x + p1x + p2x + p3x) / 4; + var _pay = (p0y + p1y + p2y + p3y) / 4; + + if((abs(p0x - _pax) + abs(p1x - _pax) + abs(p2x - _pax) + abs(p3x - _pax)) / 4 < 1) + continue; + if((abs(p0y - _pay) + abs(p1y - _pay) + abs(p2y - _pay) + abs(p3y - _pay)) / 4 < 1) + continue; + + draw_set_color(COLORS.axis[(i - 3 - 1 + 3) % 3]); + if(axis_hover == i || drag_axis == i) { + draw_primitive_begin(pr_trianglestrip); + draw_vertex(p0x, p0y); + draw_vertex(p1x, p1y); + draw_vertex(p3x, p3y); + draw_vertex(p2x, p2y); + draw_primitive_end(); + } else if (drag_axis == noone) { + draw_line(p0x, p0y, p1x, p1y); + draw_line(p1x, p1y, p2x, p2y); + draw_line(p2x, p2y, p3x, p3y); + draw_line(p3x, p3y, p0x, p0y); + } else + continue; + + if(point_in_rectangle_points(_mx, _my, p0x, p0y, p1x, p1y, p3x, p3y, p2x, p2y)) + _hover = i; + } + + axis_hover = _hover; + #endregion + + if(drag_axis != noone) { #region editing + if(!MOUSE_WRAPPING) { + drag_mx += _mx - drag_px; + drag_my += _my - drag_py; + + var mAdj, nor, prj; + var ray = _camera.viewPointToWorldRay(drag_mx, drag_my); + + if(drag_axis < 3) { + switch(drag_axis) { + case 0 : nor = new __vec3(0, 1, 0); prj = new __vec3(1, 0, 0); break; + case 1 : nor = new __vec3(0, 0, 1); prj = new __vec3(0, 1, 0); break; + case 2 : nor = new __vec3(1, 0, 0); prj = new __vec3(0, 0, 1); break; + } + + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + var _dist = _diff.dot(prj); + + drag_val[drag_axis] += prj.getIndex(drag_axis) * _dist; + + if(inputs[| index].setValue(value_snap(drag_val, _snx))) + UNDO_HOLDING = true; + } + } else { + switch(drag_axis) { + case 3 : nor = new __vec3(0, 0, 1); break; + case 4 : nor = new __vec3(1, 0, 0); break; + case 5 : nor = new __vec3(0, 1, 0); break; + } + + nor = _qrot.Rotate(nor); + + var pln = new __plane(drag_original, nor); + mAdj = d3d_intersect_ray_plane(ray, pln); + + if(drag_prev != undefined) { + var _diff = mAdj.subtract(drag_prev); + + for( var i = 0; i < 3; i++ ) + drag_val[i] += _diff.getIndex(i); + + if(inputs[| index].setValue(value_snap(drag_val, _snx))) + UNDO_HOLDING = true; + } + } + + drag_prev = mAdj; + } + + setMouseWrap(); + drag_px = _mx; + drag_py = _my; + } #endregion + + if(_hover != noone && mouse_press(mb_left, active)) { #region + drag_axis = _hover; + drag_prev = undefined; + drag_mx = _mx; + drag_my = _my; + drag_px = _mx; + drag_py = _my; + drag_cx = cx; + drag_cy = cy; + + drag_val = [ _sca[0], _sca[1], _sca[2] ]; + drag_original = new __vec3(_sca); + } #endregion + } #endregion + + static drawOverlay3D = function(active, params, _mx, _my, _snx, _sny, _panel) { #region + var object = getPreviewObjects(); + if(array_empty(object)) return; + object = object[0]; + + var _pos = inputs[| 0].getValue(,,, true); + var _vpos = new __vec3( _pos[0], _pos[1], _pos[2] ); + + if(isUsingTool("Transform")) drawGizmoPosition(0, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + else if(isUsingTool("Rotate")) drawGizmoRotation(1, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + else if(isUsingTool("Scale")) drawGizmoScale(2, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel); + + if(drag_axis != noone && mouse_release(mb_left)) { + drag_axis = noone; + UNDO_HOLDING = false; + } + + if(onDrawOverlay3D != 0) onDrawOverlay3D(active, params, _mx, _my, _snx, _sny, _panel); + } #endregion + + static onDrawOverlay3D = 0; + + static setTransform = function(object, _data) { #region + if(object == noone) return; + var _pos = _data[0]; + var _rot = _data[1]; + var _sca = _data[2]; + var _anc = _data[3]; + + object.transform.position.set( _pos[0], _pos[1], _pos[2]); + object.transform.anchor.set( _anc[0], _anc[1], _anc[2]); + object.transform.rotation.set( _rot[0], _rot[1], _rot[2], _rot[3]); + object.transform.scale.set( _sca[0], _sca[1], _sca[2]); + + return object; + } #endregion + + static getObject = function(index, class = object_class) { #region + var _obj = array_safe_get_fast(cached_object, index, noone); + if(_obj == noone) { + _obj = new class(); + } else if(!is_instanceof(_obj, class)) { + _obj.destroy(); + _obj = new class(); + } + + cached_object[index] = _obj; + return _obj; + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/color_selector/color_selector.gml.backup0 b/#backups/scripts/color_selector/color_selector.gml.backup0 index 524b92041..22d0cd2c2 100644 --- a/#backups/scripts/color_selector/color_selector.gml.backup0 +++ b/#backups/scripts/color_selector/color_selector.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-05-01 08:40:49 +// 2024-05-01 08:42:42 function colorSelector(onApply = noone) constructor { self.onApply = onApply; diff --git a/#backups/scripts/color_selector/color_selector.gml.backup1 b/#backups/scripts/color_selector/color_selector.gml.backup1 index 79c6c16c5..67272cb46 100644 --- a/#backups/scripts/color_selector/color_selector.gml.backup1 +++ b/#backups/scripts/color_selector/color_selector.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-05-01 08:40:09 +// 2024-05-01 08:42:38 function colorSelector(onApply = noone) constructor { self.onApply = onApply; diff --git a/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup0 b/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup0 new file mode 100644 index 000000000..0b8744bd5 --- /dev/null +++ b/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup0 @@ -0,0 +1,23 @@ +// 2024-05-01 15:56:10 +function __bbox3D(first, second) constructor { + self.first = first; + self.second = second; + + static getScale = function() { + INLINE + return sqrt( + sqr(first.x - second.x) + + sqr(first.y - second.y) + + sqr(first.z - second.z) + ); + } + + static getMaximumScale = function() { + INLINE + return max( + abs(first.x - second.x), + abs(first.y - second.y), + abs(first.z - second.z), + ); + } +} diff --git a/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup1 b/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup1 new file mode 100644 index 000000000..7b44b7837 --- /dev/null +++ b/#backups/scripts/d3d_bbox/d3d_bbox.gml.backup1 @@ -0,0 +1,23 @@ +// 2024-05-01 15:56:08 +function __bbox3D(first, second) constructor { + self.first = first; + self.second = second; + + static getScale = function() { + INLINE + return sqrt( + sqr(first.x - second.x) + + sqr(first.y - second.y) + + sqr(first.z - second.z) + ); + } + + static getMaximumScale = function() { + INLINE + return max( + abs(first.x - second.x), + abs(first.y - second.y), + abs(first.z - second.z), + ); + } +} diff --git a/#backups/scripts/d3d_object/d3d_object.gml.backup0 b/#backups/scripts/d3d_object/d3d_object.gml.backup0 new file mode 100644 index 000000000..f7f3570ed --- /dev/null +++ b/#backups/scripts/d3d_object/d3d_object.gml.backup0 @@ -0,0 +1,253 @@ +// 2024-05-01 15:54:59 +#region vertex format + vertex_format_begin(); + vertex_format_add_position_3d(); + vertex_format_add_color(); + global.VF_POS_COL = vertex_format_end(); + + vertex_format_begin(); + vertex_format_add_position_3d(); + vertex_format_add_normal(); + vertex_format_add_texcoord(); + vertex_format_add_color(); + global.VF_POS_NORM_TEX_COL = vertex_format_end(); + global.VF_POS_NORM_TEX_COL_size = 36; +#endregion + +function __3dObject() constructor { + vertex = []; + normal_vertex = []; + object_counts = 1; + VB = []; + + NVB = noone; + normal_draw_size = 0.2; + + VF = global.VF_POS_COL; + render_type = pr_trianglelist; + + custom_shader = noone; + + transform = new __transform(); + size = new __vec3(1); + + materials = []; + material_index = []; + texture_flip = false; + + static checkParameter = function(params = {}, forceUpdate = false) { #region + var _keys = struct_get_names(params); + var check = false; + for( var i = 0, n = array_length(_keys); i < n; i++ ) { + var key = _keys[i]; + if(self[$ key] != params[$ key]) + check = true; + self[$ key] = params[$ key]; + } + + if(forceUpdate || check) onParameterUpdate(); + } #endregion + + static onParameterUpdate = function() {} + + static generateNormal = function(_s = normal_draw_size) { #region + if(render_type != pr_trianglelist) return; + + NVB = array_create(object_counts); + + for( var i = 0; i < object_counts; i++ ) { + NVB[i] = vertex_create_buffer(); + + vertex_begin(NVB[i], global.VF_POS_COL); + for( var j = 0, n = array_length(vertex[i]); j < n; j++ ) { + var _v = vertex[i][j]; + + vertex_position_3d(NVB[i], _v.x, _v.y, _v.z); + vertex_color(NVB[i], c_red, 1); + + vertex_position_3d(NVB[i], _v.x + _v.nx * _s, _v.y + _v.ny * _s, _v.z + _v.nz * _s); + vertex_color(NVB[i], c_red, 1); + } + vertex_end(NVB[i]); + } + } #endregion + + static buildVertex = function(_vertex) { #region + var _buffer = vertex_create_buffer(); + vertex_begin(_buffer, VF); + for( var i = 0, n = array_length(_vertex); i < n; i++ ) { + var v = _vertex[i]; + + switch(VF) { + case global.VF_POS_COL : vertex_add_vc(_buffer, v); break; + case global.VF_POS_NORM_TEX_COL : vertex_add_vntc(_buffer, v); break; + } + } + vertex_end(_buffer); + //vertex_freeze(_buffer); + + return _buffer; + } #endregion + + static build = function(_buffer = VB, _vertex = vertex, counts = object_counts) { #region + if(is_array(_buffer)) { + for( var i = 0, n = array_length(_buffer); i < n; i++ ) + if(_buffer[i] != noone) vertex_delete_buffer(_buffer[i]) + } else if(_buffer != noone) vertex_delete_buffer(_buffer); + + if(array_empty(_vertex)) return noone; + + var _res = array_create(counts); + for( var i = 0; i < counts; i++ ) + _res[i] = buildVertex(_vertex[i]); + + return _res; + } #endregion + + static preSubmitVertex = function(scene = {}) {} + static postSubmitVertex = function(scene = {}) {} + + static getCenter = function() { return new __vec3(transform.position.x, transform.position.y, transform.position.z); } + static getBBOX = function() { return new __bbox3D(size.multiplyVec(transform.scale).multiply(-0.5), size.multiplyVec(transform.scale).multiply(0.5)); } + + static submit = function(scene = {}, shader = noone) { submitVertex(scene, shader); } + static submitUI = function(scene = {}, shader = noone) { submitVertex(scene, shader); } + static submitSel = function(scene = {}, shader = noone) { #region + var _s = variable_clone(scene); + _s.show_normal = false; + submitVertex(_s, sh_d3d_silhouette); + } #endregion + static submitShader = function(scene = {}, shader = noone) {} + static submitShadow = function(scene = {}, object = noone) {} + + static submitVertex = function(scene = {}, shader = noone) { #region + var _shader = sh_d3d_default; + + switch(VF) { + case global.VF_POS_NORM_TEX_COL: _shader = sh_d3d_default; break; + case global.VF_POS_COL: _shader = sh_d3d_wireframe; break; + } + + if(custom_shader != noone) _shader = custom_shader; + if(shader != noone) _shader = shader; + + shader_set(_shader); + + preSubmitVertex(scene); + + transform.submitMatrix(); + + matrix_set(matrix_world, matrix_stack_top()); + + #region ++++ Submit & Material ++++ + gpu_set_tex_repeat(true); + + for( var i = 0, n = array_length(VB); i < n; i++ ) { + var _ind = array_safe_get_fast(material_index, i, i); + var _mat = array_safe_get_fast(materials, _ind, noone); + var _useMat = is_instanceof(_mat, __d3dMaterial); + + shader_set_i("mat_flip", texture_flip); + var _tex = _useMat? _mat.getTexture() : -1; + + if(_shader == sh_d3d_default) { + if(_useMat) { + _mat.submitShader(); + } else { + shader_set_f("mat_diffuse", 1); + shader_set_f("mat_specular", 0); + shader_set_f("mat_shine", 1); + shader_set_i("mat_metalic", 0); + shader_set_f("mat_reflective", 0); + } + + vertex_submit(VB[i], render_type, _tex); + } else if(_shader == sh_d3d_geometry) { + if(_useMat) + _mat.submitGeometry(); + else + shader_set_i("use_normal", 0); + + vertex_submit(VB[i], render_type, _tex); + } else + vertex_submit(VB[i], render_type, _tex); + + // print($"Submit vertex ({scene}) [{VB[i]}: {vertex_get_buffer_size(VB[i])}]"); + } + + gpu_set_tex_repeat(false); + #endregion + + shader_reset(); + + if(scene.show_normal) { #region + if(NVB == noone) generateNormal(); + if(NVB != noone) { + shader_set(sh_d3d_wireframe); + shader_set_color("blend", c_white); + + for( var i = 0, n = array_length(NVB); i < n; i++ ) + vertex_submit(NVB[i], pr_linelist, -1); + shader_reset(); + } + } #endregion + + transform.clearMatrix(); + matrix_set(matrix_world, matrix_build_identity()); + + postSubmitVertex(scene); + + } #endregion + + static clone = function(_vertex = true, cloneBuffer = false) { #region + var _obj = new __3dObject(); + + if(_vertex) { + _obj.vertex = array_create(array_length(vertex)); + for( var i = 0, n = array_length(vertex); i < n; i++ ) { + _obj.vertex[i] = array_create(array_length(vertex[i])); + + for( var j = 0, m = array_length(vertex[i]); j < m; j++ ) + _obj.vertex[i][j] = vertex[i][j].clone(); + } + } + + if(cloneBuffer) { + _obj.VB = array_create(array_length(VB)); + + for( var i = 0, n = array_length(VB); i < n; i++ ) { + var _vnum = vertex_get_number(VB[i]); + var _buff = buffer_create(1, buffer_grow, 1); + buffer_copy_from_vertex_buffer(VB[i], 0, _vnum - 1, _buff, 0); + + _obj.VB[i] = vertex_create_buffer_from_buffer(_buff, VF); + } + } else { + _obj.VB = VB; + } + + _obj.NVB = NVB; + _obj.VF = VF; + _obj.render_type = render_type; + _obj.custom_shader = custom_shader; + _obj.object_counts = object_counts; + _obj.transform = transform.clone(); + _obj.size = size.clone(); + _obj.materials = materials; + _obj.material_index = material_index; + _obj.texture_flip = texture_flip; + + return _obj; + } #endregion + + static destroy = function() { #region + for( var i = 0, n = array_length(VB); i < n; i++ ) + vertex_delete_buffer(VB[i]); + VB = []; + onDestroy(); + } #endregion + + static onDestroy = function() { } + + static toString = function() { return $"[D3D Object]\n\t({array_length(vertex)} vertex groups\n\tPosition: {transform.position}\n\tRotation: {transform.rotation}\n\tScale: {transform.scale})" } +} \ No newline at end of file diff --git a/#backups/scripts/d3d_object/d3d_object.gml.backup1 b/#backups/scripts/d3d_object/d3d_object.gml.backup1 new file mode 100644 index 000000000..431db7da0 --- /dev/null +++ b/#backups/scripts/d3d_object/d3d_object.gml.backup1 @@ -0,0 +1,253 @@ +// 2024-05-01 15:51:30 +#region vertex format + vertex_format_begin(); + vertex_format_add_position_3d(); + vertex_format_add_color(); + global.VF_POS_COL = vertex_format_end(); + + vertex_format_begin(); + vertex_format_add_position_3d(); + vertex_format_add_normal(); + vertex_format_add_texcoord(); + vertex_format_add_color(); + global.VF_POS_NORM_TEX_COL = vertex_format_end(); + global.VF_POS_NORM_TEX_COL_size = 36; +#endregion + +function __3dObject() constructor { + vertex = []; + normal_vertex = []; + object_counts = 1; + VB = []; + + NVB = noone; + normal_draw_size = 0.2; + + VF = global.VF_POS_COL; + render_type = pr_trianglelist; + + custom_shader = noone; + + transform = new __transform(); + size = new __vec3(1); + + materials = []; + material_index = []; + texture_flip = false; + + static checkParameter = function(params = {}, forceUpdate = false) { #region + var _keys = struct_get_names(params); + var check = false; + for( var i = 0, n = array_length(_keys); i < n; i++ ) { + var key = _keys[i]; + if(self[$ key] != params[$ key]) + check = true; + self[$ key] = params[$ key]; + } + + if(forceUpdate || check) onParameterUpdate(); + } #endregion + + static onParameterUpdate = function() {} + + static generateNormal = function(_s = normal_draw_size) { #region + if(render_type != pr_trianglelist) return; + + NVB = array_create(object_counts); + + for( var i = 0; i < object_counts; i++ ) { + NVB[i] = vertex_create_buffer(); + + vertex_begin(NVB[i], global.VF_POS_COL); + for( var j = 0, n = array_length(vertex[i]); j < n; j++ ) { + var _v = vertex[i][j]; + + vertex_position_3d(NVB[i], _v.x, _v.y, _v.z); + vertex_color(NVB[i], c_red, 1); + + vertex_position_3d(NVB[i], _v.x + _v.nx * _s, _v.y + _v.ny * _s, _v.z + _v.nz * _s); + vertex_color(NVB[i], c_red, 1); + } + vertex_end(NVB[i]); + } + } #endregion + + static buildVertex = function(_vertex) { #region + var _buffer = vertex_create_buffer(); + vertex_begin(_buffer, VF); + for( var i = 0, n = array_length(_vertex); i < n; i++ ) { + var v = _vertex[i]; + + switch(VF) { + case global.VF_POS_COL : vertex_add_vc(_buffer, v); break; + case global.VF_POS_NORM_TEX_COL : vertex_add_vntc(_buffer, v); break; + } + } + vertex_end(_buffer); + //vertex_freeze(_buffer); + + return _buffer; + } #endregion + + static build = function(_buffer = VB, _vertex = vertex, counts = object_counts) { #region + if(is_array(_buffer)) { + for( var i = 0, n = array_length(_buffer); i < n; i++ ) + if(_buffer[i] != noone) vertex_delete_buffer(_buffer[i]) + } else if(_buffer != noone) vertex_delete_buffer(_buffer); + + if(array_empty(_vertex)) return noone; + + var _res = array_create(counts); + for( var i = 0; i < counts; i++ ) + _res[i] = buildVertex(_vertex[i]); + + return _res; + } #endregion + + static preSubmitVertex = function(scene = {}) {} + static postSubmitVertex = function(scene = {}) {} + + static getCenter = function() { return new __vec3(transform.position.x, transform.position.y, transform.position.z); } + static getBBOX = function() { return new __bbox3D(size.multiplyVec(transform.scale).multiply(-0.5), size.multiplyVec(transform.scale).multiply(0.5)); } + + static submit = function(scene = {}, shader = noone) { submitVertex(scene, shader); } + static submitUI = function(scene = {}, shader = noone) { submitVertex(scene, shader); } + static submitSel = function(scene = {}, shader = noone) { #region + var _s = variable_clone(scene); + _s.show_normal = false; + submitVertex(_s, sh_d3d_silhouette); + } #endregion + static submitShader = function(scene = {}, shader = noone) {} + static submitShadow = function(scene = {}, object = noone) {} + + static submitVertex = function(scene = {}, shader = noone) { #region + var _shader = sh_d3d_default; + + switch(VF) { + case global.VF_POS_NORM_TEX_COL: _shader = sh_d3d_default; break; + case global.VF_POS_COL: _shader = sh_d3d_wireframe; break; + } + + if(custom_shader != noone) _shader = custom_shader; + if(shader != noone) _shader = shader; + + shader_set(_shader); + + preSubmitVertex(scene); + + transform.submitMatrix(); + + matrix_set(matrix_world, matrix_stack_top()); + + #region ++++ Submit & Material ++++ + gpu_set_tex_repeat(true); + + for( var i = 0, n = array_length(VB); i < n; i++ ) { + var _ind = array_safe_get_fast(material_index, i, i); + var _mat = array_safe_get_fast(materials, _ind, noone); + var _useMat = is_instanceof(_mat, __d3dMaterial); + + shader_set_i("mat_flip", texture_flip); + var _tex = _useMat? _mat.getTexture() : -1; + + if(_shader == sh_d3d_default) { + if(_useMat) { + _mat.submitShader(); + } else { + shader_set_f("mat_diffuse", 1); + shader_set_f("mat_specular", 0); + shader_set_f("mat_shine", 1); + shader_set_i("mat_metalic", 0); + shader_set_f("mat_reflective", 0); + } + + vertex_submit(VB[i], render_type, _tex); + } else if(_shader == sh_d3d_geometry) { + if(_useMat) + _mat.submitGeometry(); + else + shader_set_i("use_normal", 0); + + vertex_submit(VB[i], render_type, _tex); + } else + vertex_submit(VB[i], render_type, _tex); + + // print($"Submit vertex ({scene}) [{VB[i]}: {vertex_get_buffer_size(VB[i])}]"); + } + + gpu_set_tex_repeat(false); + #endregion + + shader_reset(); + + if(scene.show_normal) { #region + if(NVB == noone) generateNormal(); + if(NVB != noone) { + shader_set(sh_d3d_wireframe); + shader_set_color("blend", c_white); + + for( var i = 0, n = array_length(NVB); i < n; i++ ) + vertex_submit(NVB[i], pr_linelist, -1); + shader_reset(); + } + } #endregion + + transform.clearMatrix(); + matrix_set(matrix_world, matrix_build_identity()); + + postSubmitVertex(scene); + + } #endregion + + static clone = function(_vertex = true, cloneBuffer = false) { #region + var _obj = new __3dObject(); + + if(_vertex) { + _obj.vertex = array_create(array_length(vertex)); + for( var i = 0, n = array_length(vertex); i < n; i++ ) { + _obj.vertex[i] = array_create(array_length(vertex[i])); + + for( var j = 0, m = array_length(vertex[i]); j < m; j++ ) + _obj.vertex[i][j] = vertex[i][j].clone(); + } + } + + if(cloneBuffer) { + _obj.VB = array_create(array_length(VB)); + + for( var i = 0, n = array_length(VB); i < n; i++ ) { + var _vnum = vertex_get_number(VB[i]); + var _buff = buffer_create(1, buffer_grow, 1); + buffer_copy_from_vertex_buffer(VB[i], 0, _vnum - 1, _buff, 0); + + _obj.VB[i] = vertex_create_buffer_from_buffer(_buff, VF); + } + } else { + _obj.VB = VB; + } + + _obj.NVB = NVB; + _obj.VF = VF; + _obj.render_type = render_type; + _obj.custom_shader = custom_shader; + _obj.object_counts = object_counts; + _obj.transform = transform.clone(); + _obj.size = size.clone(); + _obj.materials = materials; + _obj.material_index = material_index; + _obj.texture_flip = texture_flip; + + return _obj; + } #endregion + + static destroy = function() { #region + for( var i = 0, n = array_length(VB); i < n; i++ ) + vertex_delete_buffer(VB[i]); + VB = []; + onDestroy(); + } #endregion + + static onDestroy = function() { } + + static toString = function() { return $"[D3D Object]\n\t({array_length(vertex)} vertex groups\n\tPosition: {transform.position}\n\tRotation: {transform.rotation}\n\tScale: {transform.scale})" } +} \ No newline at end of file diff --git a/#backups/scripts/globals/globals.gml.backup0 b/#backups/scripts/globals/globals.gml.backup0 index 42aa957fb..49a428538 100644 --- a/#backups/scripts/globals/globals.gml.backup0 +++ b/#backups/scripts/globals/globals.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-05-01 08:11:39 +// 2024-05-01 08:42:51 #region save globalvar LOADING, CLONING, CLONING_GROUP; globalvar CONNECTION_CONFLICT, LOADING_VERSION; diff --git a/#backups/scripts/globals/globals.gml.backup1 b/#backups/scripts/globals/globals.gml.backup1 index fa4b068af..c146aa123 100644 --- a/#backups/scripts/globals/globals.gml.backup1 +++ b/#backups/scripts/globals/globals.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-05-01 08:11:28 +// 2024-05-01 08:42:50 #region save globalvar LOADING, CLONING, CLONING_GROUP; globalvar CONNECTION_CONFLICT, LOADING_VERSION; diff --git a/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup0 b/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup0 new file mode 100644 index 000000000..ec44a4d23 --- /dev/null +++ b/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup0 @@ -0,0 +1,243 @@ +// 2024-05-01 15:53:22 +function Node_create_3D_Obj(_x, _y, _group = noone) { #region + var path = ""; + if(!LOADING && !APPENDING && !CLONING) { + path = get_open_filename("3d object|*.obj", ""); + key_release(); + if(path == "") return noone; + } + + var node = new Node_3D_Mesh_Obj(_x, _y, _group); + node.setPath(path); + return node; +} #endregion + +function Node_create_3D_Obj_path(_x, _y, path) { #region + if(!file_exists_empty(path)) return noone; + + var node = new Node_3D_Mesh_Obj(_x, _y, PANEL_GRAPH.getCurrentContext()); + node.setPath(path); + return node; +} #endregion + +function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) constructor { + name = "3D Obj"; + + object = noone; + object_class = __3dObject; + + inputs[| in_mesh + 0] = nodeValue("File Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "" ) + .setDisplay(VALUE_DISPLAY.path_load, { filter: "3d object|*.obj" }) + .rejectArray(); + + inputs[| in_mesh + 1] = nodeValue("Flip UV", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true, "Flip UV axis, can be use to fix some texture mapping error.") + .rejectArray(); + + inputs[| in_mesh + 2] = nodeValue("Import Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) + .rejectArray(); + + input_display_list = [ + __d3d_input_list_mesh, + __d3d_input_list_transform, + ["Object", false], in_mesh + 0, in_mesh + 2, + ["Material", false], in_mesh + 1, + ] + + setIsDynamicInput(1); + + obj_reading = false; + obj_raw = noone; + obj_read_progress = 0; + obj_read_prog_sub = 0; + obj_read_prog_tot = 3; + obj_read_time = 0; + + current_path = ""; + materials = []; + materialNames = []; + materialIndex = []; + use_normal = false; + + insp1UpdateTooltip = __txt("Refresh"); + insp1UpdateIcon = [ THEME.refresh_icon, 1, COLORS._main_value_positive ]; + + static onInspector1Update = function() { + current_path = ""; + outputs[| 0].setValue(noone); + } + + function setPath(path) { inputs[| in_mesh + 0].setValue(path); } + + static createNewInput = function(index = -1) { #region + if(index == -1) index = ds_list_size(inputs); + + inputs[| index] = nodeValue("Material", self, JUNCTION_CONNECT.input, VALUE_TYPE.d3Material, new __d3dMaterial()) + .setVisible(true, true); + } #endregion + + static createMaterial = function(m_index) { #region + var index = input_fix_len + m_index; + + input_display_list[input_display_len + m_index] = index; + if(index < ds_list_size(inputs)) return; + + createNewInput(index); + + if(m_index >= array_length(materials)) return; + + var matY = y - (array_length(materials) - 1) / 2 * (128 + 32); + var mat = materials[m_index]; + inputs[| index].name = materialNames[m_index] + " Material"; + + if(file_exists_empty(mat.diff_path)) { + var sol = Node_create_Image_path(x - (w + 128), matY + m_index * (128 + 32), mat.diff_path); + sol.name = mat.name + " texture"; + + inputs[| index].setFrom(sol.outputs[| 0]); + } else { + var sol = nodeBuild("Node_Solid", x - (w + 128), matY + m_index * (128 + 32)); + sol.name = mat.name + " texture"; + sol.inputs[| 1].setValue(mat.diff); + + inputs[| index].setFrom(sol.outputs[| 0]); + } + } #endregion + + static updateObj = function(_path) { #region + if(!file_exists_empty(_path)) return; + current_path = _path; + + var _scale = inputs[| in_mesh + 2].getValue(); + + readObj_init(_scale); + + obj_read_time = get_timer(); + obj_read_file = file_text_open_read(current_path); + use_display_list = false; + } #endregion + + static updateObjProcess = function() { #region + switch(obj_read_progress) { + case 0 : readObj_file(); break; + case 1 : readObj_cent(); break; + case 2 : readObj_buff(); break; + } + } #endregion + + static updateObjComplete = function() { #region + use_display_list = true; + if(obj_raw == noone) return; + + // var txt = $"========== OBJ import ==========\n"; + // txt += $"Vertex counts: {obj_raw.vertex_count}\n"; + // txt += $"Object counts: {obj_raw.object_counts}\n"; + // txt += $"Material counts: {array_length(obj_raw.materials)}\n"; + // txt += $"Model BBOX: {obj_raw.model_size}\n"; + // txt += $"Load completed in {(get_timer() - obj_read_time) / 1000} ms\n"; + // print(txt); + + var span = max(abs(obj_raw.model_size.x), abs(obj_raw.model_size.y), abs(obj_raw.model_size.z)); + if(span > 10) noti_warning($"The model is tool large to display properly ({span}u). Scale the model down to preview."); + + if(object != noone) object.destroy(); + + object = new __3dObject(); + object.VB = obj_raw.vertex_groups; + object.vertex = obj_raw.vertex; + object.size = obj_raw.model_size; + object.object_counts = obj_raw.object_counts; + use_normal = obj_raw.use_normal; + + materialNames = [ "Material" ]; + materialIndex = [ 0 ]; + materials = [ new MTLmaterial("Material") ]; + + if(array_length(materialNames)) { + var _dir = filename_dir(current_path); + var _pathMtl = string_copy(current_path, 1, string_length(current_path) - 4) + ".mtl"; + if(obj_raw.mtl_path != "") _pathMtl = _dir + "/" + obj_raw.mtl_path; + materials = readMtl(_pathMtl); + + if(array_length(materials) == array_length(obj_raw.materials)) { + materialNames = array_create(array_length(materials)); + for( var i = 0, n = array_length(materials); i < n; i++ ) + materialNames[i] = materials[i].name; + + for( var i = 0, n = array_length(materials); i < n; i++ ) { + var _mat = obj_raw.materials[i]; + var _ord = array_find(materialNames, _mat); + materialIndex[i] = _ord; + } + } else + noti_warning("Load mtl error: Material amount defined in .mtl file not match the .obj file.") + } + + array_resize(input_display_list, input_display_len); + + var _overflow = input_fix_len + array_length(materialNames); + while(ds_list_size(inputs) > _overflow) + ds_list_delete(inputs, _overflow); + + for(var i = 0; i < array_length(materialNames); i++) + createMaterial(i); + + outputs[| 0].setValue(object); + + triggerRender(); + } #endregion + + static step = function() { #region + if(obj_reading) { + updateObjProcess(); + + if(obj_read_progress == obj_read_prog_tot) { + updateObjComplete(); + obj_reading = false; + + triggerRender(); + } + return; + } + + var _path = getInputData(in_mesh + 0); + if(_path != current_path) updateObj(_path); + } #endregion + + static processData = function(_output, _data, _output_index, _array_index = 0) { #region + if(obj_reading) return noone; + + var _flip = _data[in_mesh + 1]; + + if(object == noone) return noone; + var materials = []; + for( var i = input_fix_len, n = array_length(_data); i < n; i++ ) + materials[i - input_fix_len] = _data[i]; + + var _object = getObject(_array_index); + _object.VF = global.VF_POS_NORM_TEX_COL; + _object.VB = object.VB; + _object.NVB = object.NVB; + _object.vertex = object.vertex; + _object.size = object.size; + _object.object_counts = object.object_counts; + _object.materials = materials; + _object.material_index = materialIndex; + _object.texture_flip = _flip; + + setTransform(_object, _data); + return _object; + } #endregion + + static getPreviewValues = function() { return array_safe_get_fast(all_inputs, in_mesh + 2, noone); } + + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region + if(!obj_reading) return; + + var cx = xx + w * _s / 2; + var cy = yy + h * _s / 2; + var rr = min(w - 32, h - 32) * _s / 2; + + draw_set_color(COLORS._main_icon); + draw_arc(cx, cy, rr, current_time / 5, current_time / 5 + 90, 4 * _s, 90); + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup1 b/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup1 new file mode 100644 index 000000000..a5013ceb2 --- /dev/null +++ b/#backups/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml.backup1 @@ -0,0 +1,243 @@ +// 2024-05-01 15:53:20 +function Node_create_3D_Obj(_x, _y, _group = noone) { #region + var path = ""; + if(!LOADING && !APPENDING && !CLONING) { + path = get_open_filename("3d object|*.obj", ""); + key_release(); + if(path == "") return noone; + } + + var node = new Node_3D_Mesh_Obj(_x, _y, _group); + node.setPath(path); + return node; +} #endregion + +function Node_create_3D_Obj_path(_x, _y, path) { #region + if(!file_exists_empty(path)) return noone; + + var node = new Node_3D_Mesh_Obj(_x, _y, PANEL_GRAPH.getCurrentContext()); + node.setPath(path); + return node; +} #endregion + +function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) constructor { + name = "3D Obj"; + + object = noone; + object_class = __3dObject; + + inputs[| in_mesh + 0] = nodeValue("File Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "" ) + .setDisplay(VALUE_DISPLAY.path_load, { filter: "3d object|*.obj" }) + .rejectArray(); + + inputs[| in_mesh + 1] = nodeValue("Flip UV", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true, "Flip UV axis, can be use to fix some texture mapping error.") + .rejectArray(); + + inputs[| in_mesh + 2] = nodeValue("Import Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) + .rejectArray(); + + input_display_list = [ + __d3d_input_list_mesh, + __d3d_input_list_transform, + ["Object", false], in_mesh + 0, in_mesh + 2, + ["Material", false], in_mesh + 1, + ] + + setIsDynamicInput(1); + + obj_reading = false; + obj_raw = noone; + obj_read_progress = 0; + obj_read_prog_sub = 0; + obj_read_prog_tot = 3; + obj_read_time = 0; + + current_path = ""; + materials = []; + materialNames = []; + materialIndex = []; + use_normal = false; + + insp1UpdateTooltip = __txt("Refresh"); + insp1UpdateIcon = [ THEME.refresh_icon, 1, COLORS._main_value_positive ]; + + static onInspector1Update = function() { + current_path = ""; + outputs[| 0].setValue(noone); + } + + function setPath(path) { inputs[| in_mesh + 0].setValue(path); } + + static createNewInput = function(index = -1) { #region + if(index == -1) index = ds_list_size(inputs); + + inputs[| index] = nodeValue("Material", self, JUNCTION_CONNECT.input, VALUE_TYPE.d3Material, new __d3dMaterial()) + .setVisible(true, true); + } #endregion + + static createMaterial = function(m_index) { #region + var index = input_fix_len + m_index; + + input_display_list[input_display_len + m_index] = index; + if(index < ds_list_size(inputs)) return; + + createNewInput(index); + + if(m_index >= array_length(materials)) return; + + var matY = y - (array_length(materials) - 1) / 2 * (128 + 32); + var mat = materials[m_index]; + inputs[| index].name = materialNames[m_index] + " Material"; + + if(file_exists_empty(mat.diff_path)) { + var sol = Node_create_Image_path(x - (w + 128), matY + m_index * (128 + 32), mat.diff_path); + sol.name = mat.name + " texture"; + + inputs[| index].setFrom(sol.outputs[| 0]); + } else { + var sol = nodeBuild("Node_Solid", x - (w + 128), matY + m_index * (128 + 32)); + sol.name = mat.name + " texture"; + sol.inputs[| 1].setValue(mat.diff); + + inputs[| index].setFrom(sol.outputs[| 0]); + } + } #endregion + + static updateObj = function(_path) { #region + if(!file_exists_empty(_path)) return; + current_path = _path; + + var _scale = inputs[| in_mesh + 2].getValue(); + + readObj_init(_scale); + + obj_read_time = get_timer(); + obj_read_file = file_text_open_read(current_path); + use_display_list = false; + } #endregion + + static updateObjProcess = function() { #region + switch(obj_read_progress) { + case 0 : readObj_file(); break; + case 1 : readObj_cent(); break; + case 2 : readObj_buff(); break; + } + } #endregion + + static updateObjComplete = function() { #region + use_display_list = true; + if(obj_raw == noone) return; + + // var txt = $"========== OBJ import ==========\n"; + // txt += $"Vertex counts: {obj_raw.vertex_count}\n"; + // txt += $"Object counts: {obj_raw.object_counts}\n"; + // txt += $"Material counts: {array_length(obj_raw.materials)}\n"; + // txt += $"Model BBOX: {obj_raw.model_size}\n"; + // txt += $"Load completed in {(get_timer() - obj_read_time) / 1000} ms\n"; + // print(txt); + + var span = max(abs(obj_raw.model_size.x), abs(obj_raw.model_size.y), abs(obj_raw.model_size.z)); + if(span > 10) noti_warning($"The model is tool large to display properly ({span}u). Scale the model down to preview."); + + if(object != noone) object.destroy(); + + object = new __3dObject(); + object.VB = obj_raw.vertex_groups; + object.vertex = obj_raw.vertex; + object.size = obj_raw.model_size; + object.object_counts = obj_raw.object_counts; + use_normal = obj_raw.use_normal; + + materialNames = [ "Material" ]; + materialIndex = [ 0 ]; + materials = [ new MTLmaterial("Material") ]; + + if(array_length(materialNames)) { + var _dir = filename_dir(current_path); + var _pathMtl = string_copy(current_path, 1, string_length(current_path) - 4) + ".mtl"; + if(obj_raw.mtl_path != "") _pathMtl = _dir + "/" + obj_raw.mtl_path; + materials = readMtl(_pathMtl); + + if(array_length(materials) == array_length(obj_raw.materials)) { + materialNames = array_create(array_length(materials)); + for( var i = 0, n = array_length(materials); i < n; i++ ) + materialNames[i] = materials[i].name; + + for( var i = 0, n = array_length(materials); i < n; i++ ) { + var _mat = obj_raw.materials[i]; + var _ord = array_find(materialNames, _mat); + materialIndex[i] = _ord; + } + } else + noti_warning("Load mtl error: Material amount defined in .mtl file not match the .obj file.") + } + + array_resize(input_display_list, input_display_len); + + var _overflow = input_fix_len + array_length(materialNames); + while(ds_list_size(inputs) > _overflow) + ds_list_delete(inputs, _overflow); + + for(var i = 0; i < array_length(materialNames); i++) + createMaterial(i); + + outputs[| 0].setValue(object); + + triggerRender(); + } #endregion + + static step = function() { #region + if(obj_reading) { + updateObjProcess(); + + if(obj_read_progress == obj_read_prog_tot) { + updateObjComplete(); + obj_reading = false; + + triggerRender(); + } + return; + } + + var _path = getInputData(in_mesh + 0); + if(_path != current_path) updateObj(_path); + } #endregion + + static processData = function(_output, _data, _output_index, _array_index = 0) { #region + if(obj_reading) return noone; + + var _flip = _data[in_mesh + 1]; + + if(object == noone) return noone; + var materials = []; + for( var i = input_fix_len, n = array_length(_data); i < n; i++ ) + materials[i - input_fix_len] = _data[i]; + + var _object = getObject(_array_index); + _object.VF = global.VF_POS_NORM_TEX_COL; + _object.VB = object.VB; + _object.NVB = object.NVB; + _object.vertex = object.vertex; + _object.size = object.size; + _object.object_counts = object.object_counts; + _object.materials = materials; + _object.material_index = materialIndex; + _object.texture_flip = _flip; + + setTransform(_object, _data); + return _object; + } #endregion + + static getPreviewValues = function() { return array_safe_get_fast(all_inputs, in_mesh + 2, noone); } + + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region + if(!obj_reading) return; + + var cx = xx + w * _s / 2; + var cy = yy + h * _s / 2; + var rr = min(w - 32, h - 32) * _s / 2; + + draw_set_color(COLORS._main_icon); + draw_arc(cx, cy, rr, current_time / 5, current_time / 5 + 90, 4 * _s, 90); + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/node_export/node_export.gml.backup0 b/#backups/scripts/node_export/node_export.gml.backup0 new file mode 100644 index 000000000..e60221abe --- /dev/null +++ b/#backups/scripts/node_export/node_export.gml.backup0 @@ -0,0 +1,857 @@ +// 2024-05-01 11:49:40 +function Node_create_Export(_x, _y, _group = noone) { #region + var path = ""; + if(!LOADING && !APPENDING && !CLONING) { + path = get_save_filename(@"Portable Network Graphics (.png)|*.png| +Joint Photographic Experts Group (.jpg)|*.jpg| +Graphics Interchange Format (.gif)|*.gif| +Animated WebP (.webp)|*.webp| +MPEG-4 (.mp4)|*.mp4", + "export"); + + key_release(); + } + + var node = new Node_Export(_x, _y, _group); + node.inputs[| 1].setValue(path); + node.extensionCheck(); + + //ds_list_add(PANEL_GRAPH.nodes_list, node); + return node; +} + +function exportAll() { + if(IS_RENDERING) return; + + var key = ds_map_find_first(PROJECT.nodeMap); + + repeat(ds_map_size(PROJECT.nodeMap)) { + var node = PROJECT.nodeMap[? key]; + key = ds_map_find_next(PROJECT.nodeMap, key); + + if(!node.active) continue; + if(!is_instanceof(node, Node_Export)) continue; + + node.doInspectorAction(); + } +} #endregion + +enum NODE_EXPORT_FORMAT { + single, + sequence, + animation, +} + +function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { + name = "Export"; + preview_channel = 1; + autoUpdatedTrigger = false; + + playing = false; + played = 0; + + _format_still = { filter: "Portable Network Graphics (.png)|*.png|Joint Photographic Experts Group (.jpg)|*.jpg" }; + _format_anim = { filter: "Graphics Interchange Format (.gif)|*.gif|Animated WebP (.webp)|*.webp" }; + + inputs[| 0] = nodeValue("Surface", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone); + + inputs[| 1] = nodeValue("Paths", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "") + .setDisplay(VALUE_DISPLAY.path_save, _format_still) + .setVisible(true); + + inputs[| 2] = nodeValue("Template", self, JUNCTION_CONNECT.input, VALUE_TYPE.text, "%d%n") + .rejectArray(); + inputs[| 2].editWidget.format = TEXT_AREA_FORMAT.path_template; + inputs[| 2].editWidget.auto_update = true; + + format_single = ["Single image", "Image sequence", "Animation"]; + format_array = ["Multiple images", "Image sequences", "Animation"]; + + inputs[| 3] = nodeValue("Type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: format_single, update_hover: false }) + .rejectArray(); + + inputs[| 4] = nodeValue("Template guides", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.label, +@"%d Directory +%1d Goes up 1 level +%n File name +%f Frame +%i Array index" ); + + inputs[| 5] = nodeValue("Loop", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true) + .setVisible(false) + .rejectArray(); + + inputs[| 6] = nodeValue("Frame optimization", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + .setVisible(false) + .rejectArray(); + + inputs[| 7] = nodeValue("Color merge", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.02) + .setDisplay(VALUE_DISPLAY.slider) + .setVisible(false) + .rejectArray(); + + inputs[| 8] = nodeValue("Framerate", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 30) + .rejectArray(); + + format_image = [ ".png", ".jpg", ".webp" ]; + format_animation = [ ".gif", ".apng", ".webp", ".mp4" ]; + + inputs[| 9] = nodeValue("Format", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: format_image, update_hover: false }) + .rejectArray(); + + inputs[| 10] = nodeValue("Quality", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 23) + .setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 100, 0.1 ] }) + .rejectArray(); + + inputs[| 11] = nodeValue("Sequence begin", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0); + + inputs[| 12] = nodeValue("Frame range", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [0, -1]) + .setDisplay(VALUE_DISPLAY.slider_range, { range: [0, TOTAL_FRAMES, 0.1] }); + + png_format = [ "INDEX4", "INDEX8", "Default (PNG32)" ]; + inputs[| 13] = nodeValue("Subformat", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 2) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: png_format, update_hover: false }); + + inputs[| 14] = nodeValue("Frame step", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1); + + inputs[| 15] = nodeValue("Custom Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + .rejectArray(); + + outputs[| 0] = nodeValue("Loop exit", self, JUNCTION_CONNECT.output, VALUE_TYPE.any, 0); + + outputs[| 1] = nodeValue("Preview", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone) + .setVisible(false); + + template_guide = [ + ["%d", "Directory"], + ["%1d", "Goes up 1 level"], + ["%n", "File name"], + ["%f", "Frame"], + ["%i", "Array index"], + ]; + export_template = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) { #region + var _tx = _x + ui(10); + var _ty = _y; + var _tw = _w - ui(8); + + var rawpath = getInputData(1); + if(is_array(rawpath)) rawpath = array_safe_get_fast(rawpath, 0, ""); + + var _ext = getInputData(9); + var path = pathString(rawpath); + var pathA = pathString(rawpath,, true); + path = string_replace(path, ".png", array_safe_get_fast(inputs[| 9].display_data.data, _ext, "")); + + draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text); + var _th = ui(12) + string_height_ext(path, -1, _tw - ui(16), true); + draw_sprite_stretched_ext(THEME.ui_panel_bg, 1, _tx, _ty, _tw, _th, COLORS.node_composite_bg_blend, 1); + + var lw = 0; + var lx = _tx + ui(8); + var ly = _ty + ui(6); + + draw_set_alpha(0.9); + for( var i = 0, n = array_length(pathA); i < n; i++ ) { + var _txt = pathA[i]; + + if(is_array(_txt)) { + switch(_txt[0]) { + case "d" : draw_set_color(COLORS.widget_text_dec_d); break; + case "n" : draw_set_color(COLORS.widget_text_dec_n); break; + case "f" : draw_set_color(COLORS.widget_text_dec_f); break; + case "i" : draw_set_color(COLORS.widget_text_dec_i); break; + case "ext" : draw_set_color(COLORS._main_text_sub); break; + } + + _txt = _txt[1]; + } else + draw_set_color(COLORS._main_text); + + for( var j = 1; j <= string_length(_txt); j++ ) { + var ch = string_char_at(_txt, j); + var ww = string_width(ch); + + if(lw + ww > _tw - ui(16)) { + lw = 0; + lx = _tx + ui(8); + ly += string_height("M"); + } + + draw_text(lx, ly, ch); + + lw += ww; + lx += ww; + } + } + draw_set_alpha(1); + + var hh = _th + ui(116); + var _cy = _y + _th + ui(8); + for( var i = 0, n = array_length(template_guide); i < n; i++ ) { + var _yy = _cy + ui(20) * i; + + draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(_x + ui(16 + 16), _yy, template_guide[i][0]); + + draw_set_text(f_p1, fa_right, fa_top, COLORS._main_text_sub); + draw_text_add(_x + _w - ui(4 + 16), _yy, template_guide[i][1]); + } + + return hh; + }); #endregion + + input_display_list = [ + ["Export", false], 0, 1, 2, export_template, + ["Format", false], 3, 9, 6, 7, 10, 13, + ["Custom Range", true, 15], 12, + ["Animation", false], 8, 5, 11, 14, + ]; + + render_process_id = 0; + render_type = ""; + render_target = ""; + + directory = TEMPDIR + string(irandom_range(100000, 999999)); + converter = filepath_resolve(PREFERENCES.ImageMagick_path) + "convert.exe"; + magick = filepath_resolve(PREFERENCES.ImageMagick_path) + "magick.exe"; + webp = filepath_resolve(PREFERENCES.webp_path) + "webpmux.exe"; + gifski = filepath_resolve(PREFERENCES.gifski_path) + "win/gifski.exe"; + ffmpeg = filepath_resolve(PREFERENCES.ffmpeg_path) + "bin/ffmpeg.exe"; + + if(OS == os_windows) { + if(!file_exists_empty(converter) || !file_exists_empty(magick)) noti_warning($"No ImageMagick detected at {magick}, please make sure the installation is complete and ImageMagick path is set properly in preference."); + if(!file_exists_empty(webp)) noti_warning($"No webp detected at {webp}, please make sure the installation is complete and webp path is set properly in preference."); + if(!file_exists_empty(gifski)) noti_warning($"No gifski detected at {gifski}, please make sure the installation is complete and gifski path is set properly in preference."); + if(!file_exists_empty(ffmpeg)) noti_warning($"No FFmpeg detected at {ffmpeg}, please make sure the installation is complete and FFmpeg path is set properly in preference."); + } else if(OS == os_macosx) { + var check_convert = ExecutedProcessReadFromStandardOutput(shell_execute("convert", "")); + if(string_pos(check_convert, "not found")) noti_warning($"No ImageMagick installed, please install imagemagick with homebrew or use the provided 'mac-libraries-installer.command'."); + + var check_webp = ExecutedProcessReadFromStandardOutput(shell_execute("webp", "")); + if(string_pos(check_webp, "not found")) noti_warning($"No webp installed, please install webp with homwbrew or use the provided 'mac-libraries-installer.command'."); + + var check_ffmpeg = ExecutedProcessReadFromStandardOutput(shell_execute("ffmpeg", "")); + if(string_pos(check_ffmpeg, "not found")) noti_warning($"No FFmpeg installed, please install FFmpeg with homebrew or use the provided 'mac-libraries-installer.command'."); + + var _opt = "/opt/homebrew/bin/"; + converter = _opt + "convert"; + magick = _opt + "magick"; + webp = _opt + "webp"; + ffmpeg = _opt + "ffmpeg"; + } + + static onValueUpdate = function(_index) { #region + var form = getInputData(3); + + if(_index == 3) { + if(NOT_LOAD) inputs[| 9].setValue(0); + + switch(form) { + case 0 : + case 1 : + inputs[| 1].display_data = _format_still; + break; + case 2 : + inputs[| 1].display_data = _format_anim; + break; + } + } + + if(NOT_LOAD && _index == 3 && form == 1) + inputs[| 2].setValue("%d%n%3f%i"); + + if(NOT_LOAD && _index == 1) { + var _path = getInputData(1); + var _ext = filename_ext(_path); + + switch(_ext) { + case ".png" : inputs[| 9].setValue(0); break; + case ".jpg" : inputs[| 9].setValue(1); break; + + case ".gif" : inputs[| 9].setValue(0); break; + case ".webp" : inputs[| 9].setValue(1); break; + } + } + } #endregion + + static extensionCheck = function() { #region + var _path = getInputData(1); + var _ext = filename_ext(_path); + + switch(_ext) { + case ".png" : + inputs[| 3].setValue(0); + inputs[| 9].setValue(0); + break; + case ".jpg" : + inputs[| 3].setValue(0); + inputs[| 9].setValue(1); + break; + + case ".gif" : + inputs[| 3].setValue(2); + inputs[| 9].setValue(0); + break; + case ".webp" : + inputs[| 3].setValue(2); + inputs[| 9].setValue(1); + break; + } + } #endregion + + static renderWebp = function(temp_path, target_path) { #region + var _path = file_find_first(temp_path + "*.png", 0); + var frames = []; + + while(_path != "") { + var _frame = string_quote(temp_path + string_replace_all(_path, ".png", "") + ".webp"); + var _pathTemp = string_quote(temp_path + _path); + var shell_cmd = _pathTemp + " -define webp:lossless=true " + _frame; + + array_push(frames, _frame); + shell_execute_async(magick, shell_cmd, self, false); + + _path = file_find_next(); + } + + var rate = getInputData(8); + if(rate == 0) rate = 1; + + var framerate = round(1 / rate * 1000); + var cmd = ""; + + for( var i = 0, n = array_length(frames); i < n; i++ ) + cmd += $"-frame {frames[i]} +{framerate}+0+0+1 "; + + cmd += "-bgcolor 0,0,0,0 "; + cmd += "-o " + string_quote(target_path); + + render_process_id = shell_execute_async(webp, cmd, self); + render_type = "webp"; + render_target = target_path; + } #endregion + + static renderGif = function(temp_path, target_path) { #region + var loop = getInputData( 5); + var opti = getInputData( 6); + var fuzz = getInputData( 7); + var rate = getInputData( 8); + var qual = getInputData(10); + if(rate == 0) rate = 1; + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var framerate = 100 / rate; + var loop_str = loop? 0 : 1; + var use_gifski = false; + + var shell_cmd = $"-delay {framerate} -alpha set -dispose 2 -loop {loop_str}"; + if(opti) shell_cmd += $" -fuzz {fuzz * 100}% -layers OptimizeFrame -layers OptimizeTransparency"; + shell_cmd += $" {string_quote(temp_path)} {string_quote(target_path)}"; + + render_process_id = shell_execute_async(converter, shell_cmd, self); + render_type = "gif"; + render_target = target_path; + } #endregion + + static renderMp4 = function(temp_path, target_path) { #region + var rate = getInputData( 8); + var qual = getInputData(10); qual = clamp(qual, 0, 51); + if(rate == 0) rate = 1; + + if(file_exists_empty(target_path)) file_delete(target_path); + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}%05d.png\" -c:v libx264 -r {rate} -pix_fmt yuv420p -crf {qual} {string_quote(target_path)}"; + + render_process_id = shell_execute_async(ffmpeg, shell_cmd, self); + render_type = "mp4"; + render_target = target_path; + } #endregion + + static renderApng = function(temp_path, target_path) { #region + var rate = getInputData( 8); + if(rate == 0) rate = 1; + + if(file_exists_empty(target_path)) file_delete(target_path); + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}%05d.png\" -plays 0 {string_quote(target_path)}"; + + render_process_id = shell_execute_async(ffmpeg, shell_cmd, self); + render_type = "apng"; + render_target = target_path; + } #endregion + + static pathString = function(path, index = 0, _array = false) { #region + var suff = getInputData( 2); + var form = getInputData( 3); + var strt = getInputData(11); + + path = string_replace_all(path, "\\", "/"); + + var s = _array? [] : ""; + var i = 1; + var ch, ch_s; + var len = string_length(suff); + + while(i <= len) { + ch = string_char_at(suff, i); + + if(ch == "%") { + i++; + var res = false, str = ""; + + do { + ch_s = string_char_at(suff, i); + switch(ch_s) { + case "f" : + var _txt = ""; + var float_str = string_digits(str); + if(float_str != "") { + var float_val = string_digits(float_str); + var str_val = max(float_val - string_length(string(CURRENT_FRAME + 1 + strt)), 0); + repeat(str_val) + _txt += "0"; + } + + _txt += string(CURRENT_FRAME + 1 + strt); + if(_array) array_push(s, [ "f", _txt ]); + else s += _txt; + res = true; + break; + case "i" : + var _txt = ""; + var float_str = string_digits(str); + if(float_str != "") { + var float_val = string_digits(float_str); + var str_val = max(float_val - string_length(string(index)), 0); + repeat(str_val) + _txt += "0"; + } + + _txt += string(index); + if(_array) array_push(s, [ "i", _txt ]); + else s += _txt; + res = true; + break; + case "d" : + var dir = filename_dir(path) + "/"; + var _txt = ""; + + var float_str = string_digits(str); + if(float_str != "") { + var float_val = toNumber(string_digits(float_str)) + 1; + var dir_s = ""; + var sep = string_splice(dir, "/"); + + for(var j = 0; j < array_length(sep) - float_val; j++) + dir_s += sep[j] + "/"; + _txt += dir_s; + } else + _txt += dir; + + if(_array) array_push(s, [ "d", _txt ]); + else s += _txt; + res = true; + break; + case "n" : + var ext = filename_ext(path); + var _txt = string_replace(filename_name(path), ext, ""); + + if(_array) array_push(s, [ "n", _txt ]); + else s += _txt; + res = true; + break; + default : + str += ch_s; + } + + i++; + } until(i > string_length(suff) || res); + } else { + if(_array) array_push(s, ch); + else s += ch; + i++; + } + } + + var _e = getInputData(9); + var _ext = array_safe_get_fast(inputs[| 9].display_data.data, _e, ".png"); + + if(_array) array_push(s, ["ext", _ext]); + else s += _ext; + + return s; + } #endregion + + static save_surface = function(_surf, _path) { #region + var form = getInputData(3); + //print($">>>>>>>>>>>>>>>>>>>> save surface {_surf} - {_path} <<<<<<<<<<<<<<<<<<<<"); + + if(form == NODE_EXPORT_FORMAT.animation) { + surface_save_safe(_surf, _path); + return _path; + } + + var extd = getInputData( 9); + var qual = getInputData(10); + var indx = getInputData(13); + var ext = array_safe_get_fast(format_image, extd, ".png"); + + var _pathOut = _path; + var _pathTemp = $"{directory}/{irandom_range(10000, 99999)}.png"; + + switch(ext) { + case ".png": + switch(indx) { + case 0 : + surface_save_safe(_surf, _pathTemp); + + var shell_cmd = $"convert {string_quote(_pathTemp)} {string_quote(_pathOut)}"; + shell_execute_async(magick, shell_cmd, self); + break; + case 1 : + surface_save_safe(_surf, _pathTemp); + + var shell_cmd = $"convert {string_quote(_pathTemp)} PNG8:{string_quote(_pathOut)}"; + shell_execute_async(magick, shell_cmd, self); + break; + case 2 : + surface_save_safe(_surf, _pathOut); + break; + } + break; + + case ".jpg": + surface_save_safe(_surf, _pathTemp); + + _pathOut = $"\"{string_replace_all(_path, ".png", "")}.jpg\""; + var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} {string_quote(_pathOut)}"; + + shell_execute_async(magick, shell_cmd, self); + break; + + case ".webp": + surface_save_safe(_surf, _pathTemp); + + _pathOut = $"\"{string_replace_all(_path, ".png", "")}.webp\""; + var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} -define webp:lossless=true {string_quote(_pathOut)}"; + + shell_execute_async(magick, shell_cmd, self); + break; + } + + return _pathOut; + } #endregion + + static export = function() { #region + //print($">>>>>>>>>>>>>>>>>>>> export {CURRENT_FRAME} <<<<<<<<<<<<<<<<<<<<"); + + var surf = getInputData( 0); + var path = getInputData( 1); + var suff = getInputData( 2); + var form = getInputData( 3); + var rang = getInputData(12); + var stps = getInputData(14); + var user = getInputData(15); + + if(form >= 1 && user) { + var rng_s = rang[0]; + var rng_e = rang[1]; + var rng_st = stps >= 1? (CURRENT_FRAME - rng_s) % stps : 0; + + if(CURRENT_FRAME < rng_s - 1) return; + if(CURRENT_FRAME > rng_e - 1) return; + if(rng_st != 0) return; + } + + if(is_array(surf)) { + var p = ""; + for(var i = 0; i < array_length(surf); i++) { + var _surf = surf[i]; + if(!is_surface(_surf)) continue; + + if(form == NODE_EXPORT_FORMAT.animation) { + p = $"{directory}/{i}/{string_lead_zero(CURRENT_FRAME, 5)}.png"; + } else { + if(is_array(path) && array_length(path) == array_length(surf)) + p = pathString(array_safe_get_fast(path, i), i); + else + p = pathString(path, i); + CLI_EXPORT_AMOUNT++; + } + + p = save_surface(_surf, p); + } + + if(form != NODE_EXPORT_FORMAT.animation && !IS_CMD) { + var noti = log_message("EXPORT", $"Export {array_length(surf)} images complete.", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(p); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + } else if(is_surface(surf)) { + var p = path; + if(is_array(path)) p = path[0]; + + if(form == NODE_EXPORT_FORMAT.animation) { + p = $"{directory}/{string_lead_zero(CURRENT_FRAME, 5)}.png"; + } else { + p = pathString(p); + CLI_EXPORT_AMOUNT++; + } + + p = save_surface(surf, p); + + if(form != NODE_EXPORT_FORMAT.animation && !IS_CMD) { + var noti = log_message("EXPORT", $"Export image as {p}", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(p); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + } + } #endregion + + static renderCompleted = function() { #region + var surf = getInputData( 0); + var path = getInputData( 1); + var suff = getInputData( 2); + var extd = getInputData( 9); + var temp_path, target_path; + + update_on_frame = false; + + if(is_array(surf)) { + for(var i = 0; i < array_length(surf); i++) { + temp_path = $"{directory}/{i}/*.png"; + if(is_array(path)) target_path = pathString(array_safe_get_fast(path, i), i); + else target_path = pathString(path, i); + + switch(format_animation[extd]) { + case ".gif" : + target_path = string_replace(target_path, ".png", ".gif"); + renderGif(temp_path, target_path); + break; + case ".webp" : + target_path = string_replace(target_path, ".png", ".webp"); + renderWebp(temp_path, target_path); + break; + case ".mp4" : + target_path = string_replace(target_path, ".png", ".mp4"); + renderMp4(temp_path, target_path); + break; + case ".apng" : + target_path = string_replace(target_path, ".png", ".apng"); + renderApng(temp_path, target_path); + break; + } + } + } else { + target_path = pathString(path); + + switch(format_animation[extd]) { + case ".gif" : + target_path = string_replace(target_path, ".png", ".gif"); + renderGif(directory + "/*.png", target_path); + break; + case ".webp" : + target_path = string_replace(target_path, ".png", ".webp"); + renderWebp(directory + "/", target_path); + break; + case ".mp4" : + target_path = string_replace(target_path, ".png", ".mp4"); + renderMp4(directory + "/", target_path); + break; + case ".apng" : + target_path = string_replace(target_path, ".png", ".apng"); + renderApng(directory + "/", target_path); + break; + } + } + + updatedOutTrigger.setValue(true); + CLI_EXPORT_AMOUNT++; + } #endregion + + insp1UpdateTooltip = "Export"; + insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + insp2UpdateTooltip = "Export All"; + insp2UpdateIcon = [ THEME.play_all, 0, COLORS._main_value_positive ]; + + static onInspector1Update = function() { #region + if(IS_RENDERING) return; + + if(isInLoop()) RENDER_ALL + else doInspectorAction(); + } #endregion + + static onInspector2Update = function() { #region + if(IS_RENDERING) return; + exportAll(); + } #endregion + + static doInspectorAction = function() { #region + if(!IS_CMD && (LOADING || APPENDING)) return; + + var path = getInputData(1); + if(path == "") return; + var form = getInputData(3); + + if(form == NODE_EXPORT_FORMAT.single) { + Render(); + + export(); + updatedOutTrigger.setValue(true); + return; + } + + update_on_frame = true; + playing = true; + played = 0; + + PROJECT.animator.render(); + + if(IS_CMD) array_push(PROGRAM_ARGUMENTS._exporting, node_id); + + if(directory_exists(directory)) + directory_destroy(directory); + directory_create(directory); + } #endregion + + static step = function() { #region + insp1UpdateActive = !IS_RENDERING; + insp2UpdateActive = !IS_RENDERING; + + var surf = getInputData( 0); + var pngf = getInputData(13); + + if(is_array(surf)) { + inputs[| 3].display_data.data = format_array; + inputs[| 3].editWidget.data_list = format_array; + } else { + inputs[| 3].display_data.data = format_single; + inputs[| 3].editWidget.data_list = format_single; + } + + outputs[| 1].setValue(surf); + + var anim = getInputData(3); // single, sequence, animation + var extn = getInputData(9); + var user = getInputData(15); + + inputs[| 11].setVisible(anim == 1); + + inputs[| 12].editWidget.minn = FIRST_FRAME + 1; + inputs[| 12].editWidget.maxx = LAST_FRAME + 1; + if(!user) inputs[| 12].setValueDirect([ FIRST_FRAME + 1, LAST_FRAME + 1], noone, false, 0, false); + + inputs[| 14].setVisible(anim > 0); + + if(anim == NODE_EXPORT_FORMAT.animation) { + var _fmt = array_safe_get_fast(format_animation, extn); + + inputs[| 5].setVisible(_fmt == ".gif"); + inputs[| 6].setVisible(_fmt == ".gif"); + inputs[| 7].setVisible(_fmt == ".gif"); + inputs[| 8].setVisible(true); + + inputs[| 9].display_data.data = format_animation; + inputs[| 9].editWidget.data_list = format_animation; + + inputs[| 13].setVisible(false); + + if(_fmt == ".mp4") { + inputs[| 10].setName("CRF value"); + inputs[| 10].tooltip = "Quality of the output, with 0 being the highest (and largest file size), and 51 being the lowest."; + + inputs[| 10].setVisible(true); + inputs[| 10].editWidget.minn = 0; + inputs[| 10].editWidget.maxx = 51; + } else + inputs[| 10].setVisible(false); + } else { + var _fmt = array_safe_get_fast(format_image, extn); + + inputs[| 5].setVisible(false); + inputs[| 6].setVisible(false); + inputs[| 7].setVisible(false); + inputs[| 8].setVisible(false); + + inputs[| 9].display_data.data = format_image; + inputs[| 9].editWidget.data_list = format_image; + + inputs[| 13].setVisible(_fmt == ".png"); + + if(_fmt == ".jpg" || _fmt == ".webp") { + inputs[| 10].setName("Quality"); + inputs[| 10].tooltip = "Quality of the output."; + + inputs[| 10].setVisible(true); + inputs[| 10].editWidget.minn = 0; + inputs[| 10].editWidget.maxx = 100; + } else + inputs[| 10].setVisible(false); + } + + outputs[| 0].visible = isInLoop(); + + if(render_process_id != 0) { + var res = ProcIdExists(render_process_id); + + if(res == 0 || OS == os_macosx) { + if(!IS_CMD) { + var noti = log_message("EXPORT", $"Export {render_type} as {render_target}", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(render_target); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + + render_process_id = 0; + + if(IS_CMD) array_remove(PROGRAM_ARGUMENTS._exporting, node_id); + } + } + } #endregion + + static update = function(frame = CURRENT_FRAME) { #region + var anim = getInputData(3); + if(anim == NODE_EXPORT_FORMAT.single) { + if(isInLoop()) export(); + return; + } + + if(!PROJECT.animator.is_playing) { + playing = false; + return; + } + + if(!playing) return; + + export(); + + if(IS_LAST_FRAME && anim == NODE_EXPORT_FORMAT.animation) + renderCompleted(); + } #endregion + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region + graph_preview_alpha = 1; + if(render_process_id != 0) { + graph_preview_alpha = 0.5; + draw_sprite_ui(THEME.loading, 0, xx + w * _s / 2, yy + h * _s / 2, _s, _s, current_time / 2, COLORS._main_icon, 1); + } + } #endregion + + static doApplyDeserialize = function() { onValueUpdate(3); } +} \ No newline at end of file diff --git a/#backups/scripts/node_export/node_export.gml.backup1 b/#backups/scripts/node_export/node_export.gml.backup1 new file mode 100644 index 000000000..9a39e660d --- /dev/null +++ b/#backups/scripts/node_export/node_export.gml.backup1 @@ -0,0 +1,857 @@ +// 2024-05-01 11:49:13 +function Node_create_Export(_x, _y, _group = noone) { #region + var path = ""; + if(!LOADING && !APPENDING && !CLONING) { + path = get_save_filename(@"Portable Network Graphics (.png)|*.png| +Joint Photographic Experts Group (.jpg)|*.jpg| +Graphics Interchange Format (.gif)|*.gif| +Animated WebP (.webp)|*.webp| +MPEG-4 (.mp4)|*.mp4", + "export"); + + key_release(); + } + + var node = new Node_Export(_x, _y, _group); + node.inputs[| 1].setValue(path); + node.extensionCheck(); + + //ds_list_add(PANEL_GRAPH.nodes_list, node); + return node; +} + +function exportAll() { + if(IS_RENDERING) return; + + var key = ds_map_find_first(PROJECT.nodeMap); + + repeat(ds_map_size(PROJECT.nodeMap)) { + var node = PROJECT.nodeMap[? key]; + key = ds_map_find_next(PROJECT.nodeMap, key); + + if(!node.active) continue; + if(!is_instanceof(node, Node_Export)) continue; + + node.doInspectorAction(); + } +} #endregion + +enum NODE_EXPORT_FORMAT { + single, + sequence, + animation, +} + +function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { + name = "Export"; + preview_channel = 1; + autoUpdatedTrigger = false; + + playing = false; + played = 0; + + _format_still = { filter: "Portable Network Graphics (.png)|*.png|Joint Photographic Experts Group (.jpg)|*.jpg" }; + _format_anim = { filter: "Graphics Interchange Format (.gif)|*.gif|Animated WebP (.webp)|*.webp" }; + + inputs[| 0] = nodeValue("Surface", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone); + + inputs[| 1] = nodeValue("Paths", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "") + .setDisplay(VALUE_DISPLAY.path_save, _format_still) + .setVisible(true); + + inputs[| 2] = nodeValue("Template", self, JUNCTION_CONNECT.input, VALUE_TYPE.text, "%d%n") + .rejectArray(); + inputs[| 2].editWidget.format = TEXT_AREA_FORMAT.path_template; + inputs[| 2].editWidget.auto_update = true; + + format_single = ["Single image", "Image sequence", "Animation"]; + format_array = ["Multiple images", "Image sequences", "Animation"]; + + inputs[| 3] = nodeValue("Type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: format_single, update_hover: false }) + .rejectArray(); + + inputs[| 4] = nodeValue("Template guides", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.label, +@"%d Directory +%1d Goes up 1 level +%n File name +%f Frame +%i Array index" ); + + inputs[| 5] = nodeValue("Loop", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true) + .setVisible(false) + .rejectArray(); + + inputs[| 6] = nodeValue("Frame optimization", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + .setVisible(false) + .rejectArray(); + + inputs[| 7] = nodeValue("Color merge", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.02) + .setDisplay(VALUE_DISPLAY.slider) + .setVisible(false) + .rejectArray(); + + inputs[| 8] = nodeValue("Framerate", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 30) + .rejectArray(); + + format_image = [ ".png", ".jpg", ".webp" ]; + format_animation = [ ".gif", ".apng", ".webp", ".mp4" ]; + + inputs[| 9] = nodeValue("Format", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: format_image, update_hover: false }) + .rejectArray(); + + inputs[| 10] = nodeValue("Quality", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 23) + .setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 100, 0.1 ] }) + .rejectArray(); + + inputs[| 11] = nodeValue("Sequence begin", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0); + + inputs[| 12] = nodeValue("Frame range", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [0, -1]) + .setDisplay(VALUE_DISPLAY.slider_range, { range: [0, TOTAL_FRAMES, 0.1] }); + + png_format = [ "INDEX4", "INDEX8", "Default (PNG32)" ]; + inputs[| 13] = nodeValue("Subformat", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 2) + .setDisplay(VALUE_DISPLAY.enum_scroll, { data: png_format, update_hover: false }); + + inputs[| 14] = nodeValue("Frame step", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1); + + inputs[| 15] = nodeValue("Custom Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + .rejectArray(); + + outputs[| 0] = nodeValue("Loop exit", self, JUNCTION_CONNECT.output, VALUE_TYPE.any, 0); + + outputs[| 1] = nodeValue("Preview", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone) + .setVisible(false); + + template_guide = [ + ["%d", "Directory"], + ["%1d", "Goes up 1 level"], + ["%n", "File name"], + ["%f", "Frame"], + ["%i", "Array index"], + ]; + export_template = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) { #region + var _tx = _x + ui(10); + var _ty = _y; + var _tw = _w - ui(8); + + var rawpath = getInputData(1); + if(is_array(rawpath)) rawpath = array_safe_get_fast(rawpath, 0, ""); + + var _ext = getInputData(9); + var path = pathString(rawpath); + var pathA = pathString(rawpath,, true); + path = string_replace(path, ".png", array_safe_get_fast(inputs[| 9].display_data.data, _ext, "")); + + draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text); + var _th = ui(12) + string_height_ext(path, -1, _tw - ui(16), true); + draw_sprite_stretched_ext(THEME.ui_panel_bg, 1, _tx, _ty, _tw, _th, COLORS.node_composite_bg_blend, 1); + + var lw = 0; + var lx = _tx + ui(8); + var ly = _ty + ui(6); + + draw_set_alpha(0.9); + for( var i = 0, n = array_length(pathA); i < n; i++ ) { + var _txt = pathA[i]; + + if(is_array(_txt)) { + switch(_txt[0]) { + case "d" : draw_set_color(COLORS.widget_text_dec_d); break; + case "n" : draw_set_color(COLORS.widget_text_dec_n); break; + case "f" : draw_set_color(COLORS.widget_text_dec_f); break; + case "i" : draw_set_color(COLORS.widget_text_dec_i); break; + case "ext" : draw_set_color(COLORS._main_text_sub); break; + } + + _txt = _txt[1]; + } else + draw_set_color(COLORS._main_text); + + for( var j = 1; j <= string_length(_txt); j++ ) { + var ch = string_char_at(_txt, j); + var ww = string_width(ch); + + if(lw + ww > _tw - ui(16)) { + lw = 0; + lx = _tx + ui(8); + ly += string_height("M"); + } + + draw_text(lx, ly, ch); + + lw += ww; + lx += ww; + } + } + draw_set_alpha(1); + + var hh = _th + ui(116); + var _cy = _y + _th + ui(8); + for( var i = 0, n = array_length(template_guide); i < n; i++ ) { + var _yy = _cy + ui(20) * i; + + draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(_x + ui(16 + 16), _yy, template_guide[i][0]); + + draw_set_text(f_p1, fa_right, fa_top, COLORS._main_text_sub); + draw_text_add(_x + _w - ui(4 + 16), _yy, template_guide[i][1]); + } + + return hh; + }); #endregion + + input_display_list = [ + ["Export", false], 0, 1, 2, export_template, + ["Format", false], 3, 9, 6, 7, 10, 13, + ["Custom Range", true, 15], 12, + ["Animation", false], 8, 5, 11, 14, + ]; + + render_process_id = 0; + render_type = ""; + render_target = ""; + + directory = TEMPDIR + string(irandom_range(100000, 999999)); + converter = filepath_resolve(PREFERENCES.ImageMagick_path) + "convert.exe"; + magick = filepath_resolve(PREFERENCES.ImageMagick_path) + "magick.exe"; + webp = filepath_resolve(PREFERENCES.webp_path) + "webpmux.exe"; + gifski = filepath_resolve(PREFERENCES.gifski_path) + "win/gifski.exe"; + ffmpeg = filepath_resolve(PREFERENCES.ffmpeg_path) + "bin/ffmpeg.exe"; + + if(OS == os_windows) { + if(!file_exists_empty(converter) || !file_exists_empty(magick)) noti_warning($"No ImageMagick detected at {magick}, please make sure the installation is complete and ImageMagick path is set properly in preference."); + if(!file_exists_empty(webp)) noti_warning($"No webp detected at {webp}, please make sure the installation is complete and webp path is set properly in preference."); + if(!file_exists_empty(gifski)) noti_warning($"No gifski detected at {gifski}, please make sure the installation is complete and gifski path is set properly in preference."); + if(!file_exists_empty(ffmpeg)) noti_warning($"No FFmpeg detected at {ffmpeg}, please make sure the installation is complete and FFmpeg path is set properly in preference."); + } else if(OS == os_macosx) { + var check_convert = ExecutedProcessReadFromStandardOutput(shell_execute("convert", "")); + if(string_pos(check_convert, "not found")) noti_warning($"No ImageMagick installed, please install imagemagick with homebrew or use the provided 'mac-libraries-installer.command'."); + + var check_webp = ExecutedProcessReadFromStandardOutput(shell_execute("webp", "")); + if(string_pos(check_webp, "not found")) noti_warning($"No webp installed, please install webp with homwbrew or use the provided 'mac-libraries-installer.command'."); + + var check_ffmpeg = ExecutedProcessReadFromStandardOutput(shell_execute("ffmpeg", "")); + if(string_pos(check_ffmpeg, "not found")) noti_warning($"No FFmpeg installed, please install FFmpeg with homebrew or use the provided 'mac-libraries-installer.command'."); + + var _opt = "/opt/homebrew/bin/"; + converter = _opt + "convert"; + magick = _opt + "magick"; + webp = _opt + "webp"; + ffmpeg = _opt + "ffmpeg"; + } + + static onValueUpdate = function(_index) { #region + var form = getInputData(3); + + if(_index == 3) { + if(NOT_LOAD) inputs[| 9].setValue(0); + + switch(form) { + case 0 : + case 1 : + inputs[| 1].display_data = _format_still; + break; + case 2 : + inputs[| 1].display_data = _format_anim; + break; + } + } + + if(NOT_LOAD && _index == 3 && form == 1) + inputs[| 2].setValue("%d%n%3f%i"); + + if(NOT_LOAD && _index == 1) { + var _path = getInputData(1); + var _ext = filename_ext(_path); + + switch(_ext) { + case ".png" : inputs[| 9].setValue(0); break; + case ".jpg" : inputs[| 9].setValue(1); break; + + case ".gif" : inputs[| 9].setValue(0); break; + case ".webp" : inputs[| 9].setValue(1); break; + } + } + } #endregion + + static extensionCheck = function() { #region + var _path = getInputData(1); + var _ext = filename_ext(_path); + + switch(_ext) { + case ".png" : + inputs[| 3].setValue(0); + inputs[| 9].setValue(0); + break; + case ".jpg" : + inputs[| 3].setValue(0); + inputs[| 9].setValue(1); + break; + + case ".gif" : + inputs[| 3].setValue(2); + inputs[| 9].setValue(0); + break; + case ".webp" : + inputs[| 3].setValue(2); + inputs[| 9].setValue(1); + break; + } + } #endregion + + static renderWebp = function(temp_path, target_path) { #region + var _path = file_find_first(temp_path + "*.png", 0); + var frames = []; + + while(_path != "") { + var _frame = string_quote(temp_path + string_replace_all(_path, ".png", "") + ".webp"); + var _pathTemp = string_quote(temp_path + _path); + var shell_cmd = _pathTemp + " -define webp:lossless=true " + _frame; + + array_push(frames, _frame); + shell_execute_async(magick, shell_cmd, self, false); + + _path = file_find_next(); + } + + var rate = getInputData(8); + if(rate == 0) rate = 1; + + var framerate = round(1 / rate * 1000); + var cmd = ""; + + for( var i = 0, n = array_length(frames); i < n; i++ ) + cmd += $"-frame {frames[i]} +{framerate}+0+0+1 "; + + cmd += "-bgcolor 0,0,0,0 "; + cmd += "-o " + string_quote(target_path); + + render_process_id = shell_execute_async(webp, cmd, self); + render_type = "webp"; + render_target = target_path; + } #endregion + + static renderGif = function(temp_path, target_path) { #region + var loop = getInputData( 5); + var opti = getInputData( 6); + var fuzz = getInputData( 7); + var rate = getInputData( 8); + var qual = getInputData(10); + if(rate == 0) rate = 1; + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var framerate = 100 / rate; + var loop_str = loop? 0 : 1; + var use_gifski = false; + + var shell_cmd = $"-delay {framerate} -alpha set -dispose 2 -loop {loop_str}"; + if(opti) shell_cmd += $" -fuzz {fuzz * 100}% -layers OptimizeFrame -layers OptimizeTransparency"; + shell_cmd += $" {string_quote(temp_path)} {string_quote(target_path)}"; + + render_process_id = shell_execute_async(converter, shell_cmd, self); + render_type = "gif"; + render_target = target_path; + } #endregion + + static renderMp4 = function(temp_path, target_path) { #region + var rate = getInputData( 8); + var qual = getInputData(10); qual = clamp(qual, 0, 51); + if(rate == 0) rate = 1; + + if(file_exists_empty(target_path)) file_delete(target_path); + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}%05d.png\" -c:v libx264 -r {rate} -pix_fmt yuv420p -crf {qual} {string_quote(target_path)}"; + + render_process_id = shell_execute_async(ffmpeg, shell_cmd, self); + render_type = "mp4"; + render_target = target_path; + } #endregion + + static renderApng = function(temp_path, target_path) { #region + var rate = getInputData( 8); + if(rate == 0) rate = 1; + + if(file_exists_empty(target_path)) file_delete(target_path); + + temp_path = string_replace_all(temp_path, "/", "\\"); + target_path = string_replace_all(target_path, "/", "\\"); + + var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}%05d.png\" -plays 0 {string_quote(target_path)}"; + + render_process_id = shell_execute_async(ffmpeg, shell_cmd, self); + render_type = "apng"; + render_target = target_path; + } #endregion + + static pathString = function(path, index = 0, _array = false) { #region + var suff = getInputData( 2); + var form = getInputData( 3); + var strt = getInputData(11); + + path = string_replace_all(path, "\\", "/"); + + var s = _array? [] : ""; + var i = 1; + var ch, ch_s; + var len = string_length(suff); + + while(i <= len) { + ch = string_char_at(suff, i); + + if(ch == "%") { + i++; + var res = false, str = ""; + + do { + ch_s = string_char_at(suff, i); + switch(ch_s) { + case "f" : + var _txt = ""; + var float_str = string_digits(str); + if(float_str != "") { + var float_val = string_digits(float_str); + var str_val = max(float_val - string_length(string(CURRENT_FRAME + 1 + strt)), 0); + repeat(str_val) + _txt += "0"; + } + + _txt += string(CURRENT_FRAME + 1 + strt); + if(_array) array_push(s, [ "f", _txt ]); + else s += _txt; + res = true; + break; + case "i" : + var _txt = ""; + var float_str = string_digits(str); + if(float_str != "") { + var float_val = string_digits(float_str); + var str_val = max(float_val - string_length(string(index)), 0); + repeat(str_val) + _txt += "0"; + } + + _txt += string(index); + if(_array) array_push(s, [ "i", _txt ]); + else s += _txt; + res = true; + break; + case "d" : + var dir = filename_dir(path) + "/"; + var _txt = ""; + + var float_str = string_digits(str); + if(float_str != "") { + var float_val = toNumber(string_digits(float_str)) + 1; + var dir_s = ""; + var sep = string_splice(dir, "/"); + + for(var j = 0; j < array_length(sep) - float_val; j++) + dir_s += sep[j] + "/"; + _txt += dir_s; + } else + _txt += dir; + + if(_array) array_push(s, [ "d", _txt ]); + else s += _txt; + res = true; + break; + case "n" : + var ext = filename_ext(path); + var _txt = string_replace(filename_name(path), ext, ""); + + if(_array) array_push(s, [ "n", _txt ]); + else s += _txt; + res = true; + break; + default : + str += ch_s; + } + + i++; + } until(i > string_length(suff) || res); + } else { + if(_array) array_push(s, ch); + else s += ch; + i++; + } + } + + var _e = getInputData(9); + var _ext = array_safe_get_fast(inputs[| 9].display_data.data, _e, ".png"); + + if(_array) array_push(s, ["ext", _ext]); + else s += _ext; + + return s; + } #endregion + + static save_surface = function(_surf, _path) { #region + var form = getInputData(3); + //print($">>>>>>>>>>>>>>>>>>>> save surface {_surf} - {_path} <<<<<<<<<<<<<<<<<<<<"); + + if(form == NODE_EXPORT_FORMAT.animation) { + surface_save_safe(_surf, _path); + return _path; + } + + var extd = getInputData( 9); + var qual = getInputData(10); + var indx = getInputData(13); + var ext = array_safe_get_fast(format_image, extd, ".png"); + + var _pathOut = _path; + var _pathTemp = $"{directory}/{irandom_range(10000, 99999)}.png"; + + switch(ext) { + case ".png": + switch(indx) { + case 0 : + surface_save_safe(_surf, _pathTemp); + + var shell_cmd = $"convert {string_quote(_pathTemp)} {string_quote(_pathOut)}"; + shell_execute_async(magick, shell_cmd, self); + break; + case 1 : + surface_save_safe(_surf, _pathTemp); + + var shell_cmd = $"convert {string_quote(_pathTemp)} PNG8:{string_quote(_pathOut)}"; + shell_execute_async(magick, shell_cmd, self); + break; + case 2 : + surface_save_safe(_surf, _pathOut); + break; + } + break; + + case ".jpg": + surface_save_safe(_surf, _pathTemp); + + _pathOut = $"\"{string_replace_all(_path, ".png", "")}.jpg\""; + var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} {string_quote(_pathOut)}"; + + shell_execute_async(magick, shell_cmd, self); + break; + + case ".webp": + surface_save_safe(_surf, _pathTemp); + + _pathOut = $"\"{string_replace_all(_path, ".png", "")}.webp\""; + var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} -define webp:lossless=true {string_quote(_pathOut)}"; + + shell_execute_async(magick, shell_cmd, self); + break; + } + + return _pathOut; + } #endregion + + static export = function() { #region + //print($">>>>>>>>>>>>>>>>>>>> export {CURRENT_FRAME} <<<<<<<<<<<<<<<<<<<<"); + + var surf = getInputData( 0); + var path = getInputData( 1); + var suff = getInputData( 2); + var form = getInputData( 3); + var rang = getInputData(12); + var stps = getInputData(14); + var user = getInputData(15); + + if(form >= 1 && user) { + var rng_s = rang[0]; + var rng_e = rang[1]; + var rng_st = stps >= 1? (CURRENT_FRAME - rng_s) % stps : 0; + + if(CURRENT_FRAME < rng_s - 1) return; + if(CURRENT_FRAME > rng_e - 1) return; + if(rng_st != 0) return; + } + + if(is_array(surf)) { + var p = ""; + for(var i = 0; i < array_length(surf); i++) { + var _surf = surf[i]; + if(!is_surface(_surf)) continue; + + if(form == NODE_EXPORT_FORMAT.animation) { + p = $"{directory}/{i}/{string_lead_zero(CURRENT_FRAME, 5)}.png"; + } else { + if(is_array(path) && array_length(path) == array_length(surf)) + p = pathString(array_safe_get_fast(path, i), i); + else + p = pathString(path, i); + CLI_EXPORT_AMOUNT++; + } + + p = save_surface(_surf, p); + } + + if(form != NODE_EXPORT_FORMAT.animation && !IS_CMD) { + var noti = log_message("EXPORT", $"Export {array_length(surf)} images complete.", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(p); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + } else if(is_surface(surf)) { + var p = path; + if(is_array(path)) p = path[0]; + + if(form == NODE_EXPORT_FORMAT.animation) { + p = $"{directory}/{string_lead_zero(CURRENT_FRAME, 5)}.png"; + } else { + p = pathString(p); + CLI_EXPORT_AMOUNT++; + } + + p = save_surface(surf, p); + + if(form != NODE_EXPORT_FORMAT.animation && !IS_CMD) { + var noti = log_message("EXPORT", $"Export image as {p}", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(p); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + } + } #endregion + + static renderCompleted = function() { #region + var surf = getInputData( 0); + var path = getInputData( 1); + var suff = getInputData( 2); + var extd = getInputData( 9); + var temp_path, target_path; + + update_on_frame = false; + + if(is_array(surf)) { + for(var i = 0; i < array_length(surf); i++) { + temp_path = $"{directory}/{i}/*.png"; + if(is_array(path)) target_path = pathString(array_safe_get_fast(path, i), i); + else target_path = pathString(path, i); + + switch(format_animation[extd]) { + case ".gif" : + target_path = string_replace(target_path, ".png", ".gif"); + renderGif(temp_path, target_path); + break; + case ".webp" : + target_path = string_replace(target_path, ".png", ".webp"); + renderWebp(temp_path, target_path); + break; + case ".mp4" : + target_path = string_replace(target_path, ".png", ".mp4"); + renderMp4(temp_path, target_path); + break; + case ".apng" : + target_path = string_replace(target_path, ".png", ".apng"); + renderApng(temp_path, target_path); + break; + } + } + } else { + target_path = pathString(path); + + switch(format_animation[extd]) { + case ".gif" : + target_path = string_replace(target_path, ".png", ".gif"); + renderGif(directory + "/*.png", target_path); + break; + case ".webp" : + target_path = string_replace(target_path, ".png", ".webp"); + renderWebp(directory + "/", target_path); + break; + case ".mp4" : + target_path = string_replace(target_path, ".png", ".mp4"); + renderMp4(directory + "/", target_path); + break; + case ".apng" : + target_path = string_replace(target_path, ".png", ".apng"); + renderApng(directory + "/", target_path); + break; + } + } + + updatedOutTrigger.setValue(true); + CLI_EXPORT_AMOUNT++; + } #endregion + + insp1UpdateTooltip = "Export"; + insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + insp2UpdateTooltip = "Export All"; + insp2UpdateIcon = [ THEME.play_all, 0, COLORS._main_value_positive ]; + + static onInspector1Update = function() { #region + if(IS_RENDERING) return; + + if(isInLoop()) RENDER_ALL + else doInspectorAction(); + } #endregion + + static onInspector2Update = function() { #region + if(IS_RENDERING) return; + exportAll(); + } #endregion + + static doInspectorAction = function() { #region + if(!IS_CMD && (LOADING || APPENDING)) return; + + var path = getInputData(1); + if(path == "") return; + var form = getInputData(3); + + if(form == NODE_EXPORT_FORMAT.single) { + Render(); + + export(); + updatedOutTrigger.setValue(true); + return; + } + + update_on_frame = true; + playing = true; + played = 0; + + PROJECT.animator.render(); + + if(IS_CMD) array_push(PROGRAM_ARGUMENTS._exporting, node_id); + + if(directory_exists(directory)) + directory_destroy(directory); + directory_create(directory); + } #endregion + + static step = function() { #region + insp1UpdateActive = !IS_RENDERING; + insp2UpdateActive = !IS_RENDERING; + + var surf = getInputData( 0); + var pngf = getInputData(13); + + if(is_array(surf)) { + inputs[| 3].display_data.data = format_array; + inputs[| 3].editWidget.data_list = format_array; + } else { + inputs[| 3].display_data.data = format_single; + inputs[| 3].editWidget.data_list = format_single; + } + + outputs[| 1].setValue(surf); + + var anim = getInputData(3); // single, sequence, animation + var extn = getInputData(9); + var user = getInputData(15); + + inputs[| 11].setVisible(anim == 1); + + inputs[| 12].editWidget.minn = FIRST_FRAME + 1; + inputs[| 12].editWidget.maxx = LAST_FRAME + 1; + if(!user) inputs[| 12].setValueDirect([ FIRST_FRAME + 1, LAST_FRAME + 1], noone, false, 0, false); + + inputs[| 14].setVisible(anim > 0); + + if(anim == NODE_EXPORT_FORMAT.animation) { + var _fmt = array_safe_get_fast(format_animation, extn); + + inputs[| 5].setVisible(_fmt == ".gif"); + inputs[| 6].setVisible(_fmt == ".gif"); + inputs[| 7].setVisible(_fmt == ".gif"); + inputs[| 8].setVisible(true); + + inputs[| 9].display_data.data = format_animation; + inputs[| 9].editWidget.data_list = format_animation; + + inputs[| 13].setVisible(false); + + if(_fmt == ".mp4") { + inputs[| 10].setName("CRF value"); + inputs[| 10].tooltip = "Quality of the output, with 0 being the highest (and largest file size), and 51 being the lowest."; + + inputs[| 10].setVisible(true); + inputs[| 10].editWidget.minn = 0; + inputs[| 10].editWidget.maxx = 51; + } else + inputs[| 10].setVisible(false); + } else { + var _fmt = array_safe_get_fast(format_image, extn); + + inputs[| 5].setVisible(false); + inputs[| 6].setVisible(false); + inputs[| 7].setVisible(false); + inputs[| 8].setVisible(false); + + inputs[| 9].display_data.data = format_image; + inputs[| 9].editWidget.data_list = format_image; + + inputs[| 13].setVisible(_fmt == ".png"); + + if(_fmt == ".jpg" || _fmt == ".webp") { + inputs[| 10].setName("Quality"); + inputs[| 10].tooltip = "Quality of the output."; + + inputs[| 10].setVisible(true); + inputs[| 10].editWidget.minn = 0; + inputs[| 10].editWidget.maxx = 100; + } else + inputs[| 10].setVisible(false); + } + + outputs[| 0].visible = isInLoop(); + + if(render_process_id != 0) { + var res = ProcIdExists(render_process_id); + + if(res == 0 || OS == os_macosx) { + if(!IS_CMD) { + var noti = log_message("EXPORT", $"Export {render_type} as {render_target}", THEME.noti_icon_tick, COLORS._main_value_positive, false); + noti.path = filename_dir(render_target); + noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); + PANEL_MENU.setNotiIcon(THEME.noti_icon_tick); + } + + render_process_id = 0; + + if(IS_CMD) array_remove(PROGRAM_ARGUMENTS._exporting, node_id); + } + } + } #endregion + + static update = function(frame = CURRENT_FRAME) { #region + var anim = getInputData(3); + if(anim == NODE_EXPORT_FORMAT.single) { + if(isInLoop()) export(); + return; + } + + if(!PROJECT.animator.is_playing) { + playing = false; + return; + } + + if(!playing) return; + + export(); + + if(IS_LAST_FRAME && anim == NODE_EXPORT_FORMAT.animation) + renderCompleted(); + } #endregion + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region + graph_preview_alpha = 1; + if(render_process_id != 0) { + graph_preview_alpha = 0.5; + draw_sprite_ui(THEME.loading, 0, xx + w * _s / 2, yy + h * _s / 2, _s, _s, current_time / 2, COLORS._main_icon, 1); + } + } #endregion + + static doApplyDeserialize = function() { onValueUpdate(3); } +} \ No newline at end of file diff --git a/#backups/scripts/node_random_tile/node_random_tile.gml.backup0 b/#backups/scripts/node_random_tile/node_random_tile.gml.backup0 new file mode 100644 index 000000000..febc48bdd --- /dev/null +++ b/#backups/scripts/node_random_tile/node_random_tile.gml.backup0 @@ -0,0 +1,129 @@ +// 2024-05-01 09:30:41 +function Node_Random_Tile(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "Random Tile"; + + inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF ) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 1] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector) + .setUnitRef(function(index) { return getDimension(index); }); + + inputs[| 2] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 2, 2 ]) + .setDisplay(VALUE_DISPLAY.vector) + .setMappable(11); + + inputs[| 3] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) + .setDisplay(VALUE_DISPLAY.rotation) + .setMappable(12); + + inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) + .setMappable(13); + + inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) + .setMappable(17); + + inputs[| 6] = nodeValue("Gap color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_black); + + inputs[| 7] = nodeValue("Render type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, ["Colored tile", "Height map", "Texture grid"]); + + inputs[| 8] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom_range(10000, 99999)); + + inputs[| 9] = nodeValue("Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone); + + inputs[| 10] = nodeValue("Anti aliasing", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 11] = nodeValueMap("Scale map", self); + + inputs[| 12] = nodeValueMap("Angle map", self); + + inputs[| 13] = nodeValueMap("Gap map", self); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 14] = nodeValue("Truchet", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); + + inputs[| 15] = nodeValue("Truchet seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, seed_random()); + + inputs[| 16] = nodeValue("Truchet threshold", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider) + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 17] = nodeValueMap("Gradient map", self); + + inputs[| 18] = nodeValueGradientRange("Gradient map range", self, inputs[| 5]); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 19] = nodeValue("Texture angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ]) + .setDisplay(VALUE_DISPLAY.rotation_range); + + input_display_list = [ + ["Output", false], 0, + ["Pattern", false], 1, 3, 12, 2, 11, 4, 13, + ["Render", false], 7, 8, 5, 17, 6, 9, 10, + ["Truchet", true, 14], 15, 16, 19, + ]; + + outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); + + attribute_surface_depth(); + + static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + var a = inputs[| 1].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); active &= !a; + var a = inputs[| 18].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny, getSingleValue(0)); active &= !a; + } + + static step = function() { #region + inputs[| 2].mappableStep(); + inputs[| 3].mappableStep(); + inputs[| 4].mappableStep(); + inputs[| 5].mappableStep(); + } #endregion + + static processData = function(_outSurf, _data, _output_index, _array_index) { + var _dim = _data[0]; + var _pos = _data[1]; + var _sam = _data[9]; + var _mode = _data[7]; + + var _col_gap = _data[6]; + + inputs[| 5].setVisible(_mode == 0); + inputs[| 6].setVisible(_mode != 1); + inputs[| 9].setVisible(_mode == 2 || _mode == 3); + + _outSurf = surface_verify(_outSurf, _dim[0], _dim[1], attrDepth()); + + surface_set_shader(_outSurf, sh_random_tile); + shader_set_f("dimension", _dim[0], _dim[1]); + shader_set_f("position", _pos[0] / _dim[0], _pos[1] / _dim[1]); + + shader_set_f_map("scale", _data[ 2], _data[11], inputs[| 2]); + shader_set_f_map("angle", _data[ 3], _data[12], inputs[| 3]); + shader_set_f_map("thick", _data[ 4], _data[13], inputs[| 4]); + + shader_set_f("seed", _data[ 8]); + shader_set_i("mode", _mode); + shader_set_i("aa", _data[10]); + shader_set_color("gapCol", _col_gap); + + shader_set_i("textureTruchet", _data[14]); + shader_set_f("truchetSeed", _data[15]); + shader_set_f("truchetThres", _data[16]); + shader_set_f("truchetAngle", _data[19]); + + shader_set_gradient(_data[5], _data[17], _data[18], inputs[| 5]); + + if(is_surface(_sam)) draw_surface_stretched_safe(_sam, 0, 0, _dim[0], _dim[1]); + else draw_sprite_ext(s_fx_pixel, 0, 0, 0, _dim[0], _dim[1], 0, c_white, 1); + surface_reset_shader(); + + return _outSurf; + } +} \ No newline at end of file diff --git a/#backups/scripts/node_random_tile/node_random_tile.gml.backup1 b/#backups/scripts/node_random_tile/node_random_tile.gml.backup1 new file mode 100644 index 000000000..f87389146 --- /dev/null +++ b/#backups/scripts/node_random_tile/node_random_tile.gml.backup1 @@ -0,0 +1,129 @@ +// 2024-05-01 09:29:37 +function Node_Random_Tile(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "Random Tile"; + + inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF ) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 1] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector) + .setUnitRef(function(index) { return getDimension(index); }); + + inputs[| 2] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 2, 2 ]) + .setDisplay(VALUE_DISPLAY.vector) + .setMappable(11); + + inputs[| 3] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) + .setDisplay(VALUE_DISPLAY.rotation) + .setMappable(12); + + inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) + .setMappable(13); + + inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) + .setMappable(17); + + inputs[| 6] = nodeValue("Gap color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_black); + + inputs[| 7] = nodeValue("Render type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, ["Colored tile", "Height map", "Texture grid"]); + + inputs[| 8] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom_range(10000, 99999)); + + inputs[| 9] = nodeValue("Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone); + + inputs[| 10] = nodeValue("Anti aliasing", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 11] = nodeValueMap("Scale map", self); + + inputs[| 12] = nodeValueMap("Angle map", self); + + inputs[| 13] = nodeValueMap("Gap map", self); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 14] = nodeValue("Truchet", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); + + inputs[| 15] = nodeValue("Truchet seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, seed_random()); + + inputs[| 16] = nodeValue("Truchet threshold", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider) + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 17] = nodeValueMap("Gradient map", self); + + inputs[| 18] = nodeValueGradientRange("Gradient map range", self, inputs[| 5]); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + + inputs[| 19] = nodeValue("Texture angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ]) + .setDisplay(VALUE_DISPLAY.rotation_range); + + input_display_list = [ + ["Output", false], 0, + ["Pattern", false], 1, 3, 12, 2, 11, 4, 13, + ["Render", false], 7, 8, 5, 17, 6, 9, 10, + ["Truchet", true, 14], 15, 16, 19, + ]; + + outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); + + attribute_surface_depth(); + + static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { + var a = inputs[| 1].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); active &= !a; + var a = inputs[| 18].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny, getSingleValue(0)); active &= !a; + } + + static step = function() { #region + inputs[| 2].mappableStep(); + inputs[| 3].mappableStep(); + inputs[| 4].mappableStep(); + inputs[| 5].mappableStep(); + } #endregion + + static processData = function(_outSurf, _data, _output_index, _array_index) { + var _dim = _data[0]; + var _pos = _data[1]; + var _sam = _data[9]; + var _mode = _data[7]; + + var _col_gap = _data[6]; + + inputs[| 5].setVisible(_mode == 0); + inputs[| 6].setVisible(_mode != 1); + inputs[| 9].setVisible(_mode == 2 || _mode == 3); + + _outSurf = surface_verify(_outSurf, _dim[0], _dim[1], attrDepth()); + + surface_set_shader(_outSurf, sh_random_tile); + shader_set_f("dimension", _dim[0], _dim[1]); + shader_set_f("position", _pos[0] / _dim[0], _pos[1] / _dim[1]); + + shader_set_f_map("scale", _data[ 2], _data[11], inputs[| 2]); + shader_set_f_map("angle", _data[ 3], _data[12], inputs[| 3]); + shader_set_f_map("thick", _data[ 4], _data[13], inputs[| 4]); + + shader_set_f("seed", _data[ 8]); + shader_set_i("mode", _mode); + shader_set_i("aa", _data[10]); + shader_set_color("gapCol", _col_gap); + + shader_set_i("textureTruchet", _data[14]); + shader_set_f("truchetSeed", _data[15]); + shader_set_f("truchetThres", _data[16]); + shader_set_f("truchetAngle", _data[19]); + + shader_set_gradient(_data[5], _data[17], _data[18], inputs[| 5]); + + if(is_surface(_sam)) draw_surface_stretched_safe(_sam, 0, 0, _dim[0], _dim[1]); + else draw_sprite_ext(s_fx_pixel, 0, 0, 0, _dim[0], _dim[1], 0, c_white, 1); + surface_reset_shader(); + + return _outSurf; + } +} \ No newline at end of file diff --git a/#backups/scripts/node_value/node_value.gml.backup0 b/#backups/scripts/node_value/node_value.gml.backup0 index aef879ecc..08a401d10 100644 --- a/#backups/scripts/node_value/node_value.gml.backup0 +++ b/#backups/scripts/node_value/node_value.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-28 11:37:34 +// 2024-05-01 19:28:09 #region ---- global names ---- global.junctionEndName = [ "Hold", "Loop", "Ping pong", "Wrap" ]; @@ -1152,7 +1152,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru }); extract_node = "Node_Vector4"; - display_data.angle_display = QUARTERNION_DISPLAY.quarterion; + display_data.angle_display = QUARTERNION_DISPLAY.euler; break; #endregion case VALUE_DISPLAY.path_anchor : #region @@ -1552,19 +1552,6 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru return applyUnit? unit.apply(value, arrIndex) : value; } #endregion - if(display_type == VALUE_DISPLAY.d3quarternion) { #region - if(!applyUnit) return value; - var dispType = display_data.angle_display; - - switch(dispType) { - case QUARTERNION_DISPLAY.quarterion : - return value; - case QUARTERNION_DISPLAY.euler : - var euler = new BBMOD_Quaternion().FromEuler(value[0], value[1], value[2]).ToArray(); - return euler; - } - } #endregion - if(type == VALUE_TYPE.text) { #region switch(display_type) { case VALUE_DISPLAY.text_array : return value; @@ -1911,6 +1898,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru } else val = ds_list_empty(animator.values)? 0 : animator.processType(animator.values[| 0].value); + if(display_type == VALUE_DISPLAY.d3quarternion) { + switch(display_data.angle_display) { + case QUARTERNION_DISPLAY.quarterion : return val; + case QUARTERNION_DISPLAY.euler : return new BBMOD_Quaternion(val[0], val[1], val[2], val[3]).ToEuler(true); + } + } + return val; } #endregion @@ -1993,6 +1987,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru static setValueInspector = function(val = 0, index = noone) { #region INLINE + var res = false; val = unit.invApply(val); @@ -2003,27 +1998,32 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru var _node = PANEL_INSPECTOR.inspectings[i]; if(ind >= ds_list_size(_node.inputs)) continue; - var r = _node.inputs[| ind].setValueDirect(val, index); + var r = _node.inputs[| ind].setValueInspectorDirect(val, index); if(_node == node) res = r; } } else { - res = setValueDirect(val, index); - - //print($"Node {node} : {node.name} {node.internalName}"); - //print($"Inspecting {PANEL_INSPECTOR.inspecting} : {PANEL_INSPECTOR.inspecting.name} {PANEL_INSPECTOR.inspecting.internalName}"); - //print($"{node == PANEL_INSPECTOR.inspecting}"); - //print(""); + res = setValueInspectorDirect(val, index); } return res; } #endregion + static setValueInspectorDirect = function(val = 0, index = noone) { + if(display_type == VALUE_DISPLAY.d3quarternion && display_data.angle_display == QUARTERNION_DISPLAY.euler) { + var _qval = new BBMOD_Quaternion().FromEuler(-val[0], -val[1], -val[2]).ToArray(); + var _eval = new BBMOD_Quaternion(_qval[0], _qval[1], _qval[2], _qval[3]).ToEuler(true); + return setValueDirect(_qval); + } + + return setValueDirect(val, index); + } + static setValueDirect = function(val = 0, index = noone, record = true, time = CURRENT_FRAME, _update = true) { #region is_modified = true; var updated = false; var _val = val; var _inp = connect_type == JUNCTION_CONNECT.input; - + if(sep_axis) { if(index == noone) { for( var i = 0, n = array_length(animators); i < n; i++ ) @@ -2039,8 +2039,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru _val[index] = val; } - updated = animator.setValue(_val, _inp && record, time); - //print($"{updated}: {index} - {_val}"); + updated = animator.setValue(_val, _inp && record, time); } if(type == VALUE_TYPE.gradient) updated = true; diff --git a/#backups/scripts/node_value/node_value.gml.backup1 b/#backups/scripts/node_value/node_value.gml.backup1 index ee06a8b45..5a7b8b26c 100644 --- a/#backups/scripts/node_value/node_value.gml.backup1 +++ b/#backups/scripts/node_value/node_value.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-28 11:29:46 +// 2024-05-01 19:27:29 #region ---- global names ---- global.junctionEndName = [ "Hold", "Loop", "Ping pong", "Wrap" ]; @@ -1152,7 +1152,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru }); extract_node = "Node_Vector4"; - display_data.angle_display = QUARTERNION_DISPLAY.quarterion; + display_data.angle_display = QUARTERNION_DISPLAY.euler; break; #endregion case VALUE_DISPLAY.path_anchor : #region @@ -1552,19 +1552,6 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru return applyUnit? unit.apply(value, arrIndex) : value; } #endregion - if(display_type == VALUE_DISPLAY.d3quarternion) { #region - if(!applyUnit) return value; - var dispType = display_data.angle_display; - - switch(dispType) { - case QUARTERNION_DISPLAY.quarterion : - return value; - case QUARTERNION_DISPLAY.euler : - var euler = new BBMOD_Quaternion().FromEuler(value[0], value[1], value[2]).ToArray(); - return euler; - } - } #endregion - if(type == VALUE_TYPE.text) { #region switch(display_type) { case VALUE_DISPLAY.text_array : return value; @@ -1911,6 +1898,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru } else val = ds_list_empty(animator.values)? 0 : animator.processType(animator.values[| 0].value); + if(display_type == VALUE_DISPLAY.d3quarternion) { + switch(display_data.angle_display) { + case QUARTERNION_DISPLAY.quarterion : return val; + case QUARTERNION_DISPLAY.euler : return new BBMOD_Quaternion(val[0], val[1], val[2], val[3]).ToEuler(true); + } + } + return val; } #endregion @@ -1993,6 +1987,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru static setValueInspector = function(val = 0, index = noone) { #region INLINE + var res = false; val = unit.invApply(val); @@ -2003,27 +1998,32 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru var _node = PANEL_INSPECTOR.inspectings[i]; if(ind >= ds_list_size(_node.inputs)) continue; - var r = _node.inputs[| ind].setValueDirect(val, index); + var r = _node.inputs[| ind].setValueInspectorDirect(val, index); if(_node == node) res = r; } } else { - res = setValueDirect(val, index); - - //print($"Node {node} : {node.name} {node.internalName}"); - //print($"Inspecting {PANEL_INSPECTOR.inspecting} : {PANEL_INSPECTOR.inspecting.name} {PANEL_INSPECTOR.inspecting.internalName}"); - //print($"{node == PANEL_INSPECTOR.inspecting}"); - //print(""); + res = setValueInspectorDirect(val, index); } return res; } #endregion + static setValueInspectorDirect = function(val = 0, index = noone) { + if(display_type == VALUE_DISPLAY.d3quarternion && display_data.angle_display == QUARTERNION_DISPLAY.euler) { + var _qval = new BBMOD_Quaternion().FromEuler(-val[0], -val[1], -val[2]).ToArray(); + var _eval = new BBMOD_Quaternion(_qval[0], _qval[1], _qval[2], _qval[3]).ToEuler(true); + return setValueDirect(_qval); + } + + return setValueDirect(val, index); + } + static setValueDirect = function(val = 0, index = noone, record = true, time = CURRENT_FRAME, _update = true) { #region is_modified = true; var updated = false; var _val = val; var _inp = connect_type == JUNCTION_CONNECT.input; - + if(sep_axis) { if(index == noone) { for( var i = 0, n = array_length(animators); i < n; i++ ) @@ -2039,8 +2039,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru _val[index] = val; } - updated = animator.setValue(_val, _inp && record, time); - //print($"{updated}: {index} - {_val}"); + updated = animator.setValue(_val, _inp && record, time); } if(type == VALUE_TYPE.gradient) updated = true; diff --git a/#backups/scripts/obj_reader/obj_reader.gml.backup0 b/#backups/scripts/obj_reader/obj_reader.gml.backup0 new file mode 100644 index 000000000..d12026b0b --- /dev/null +++ b/#backups/scripts/obj_reader/obj_reader.gml.backup0 @@ -0,0 +1,295 @@ +// 2024-05-01 13:45:32 +function readObj_init(_scale = 1) { + obj_reading = true; + obj_read_progress = 0; + obj_read_prog_sub = 0; + obj_read_prog_tot = 3; + obj_raw = noone; + + obj_reading_scale = _scale; + + _VB = []; + _VBT = []; + _VBN = []; + mats = []; + + matIndex = []; + tris = []; + mtlPath = ""; + use_normal = true; + + v = ds_list_create(); + vt = ds_list_create(); + vn = ds_list_create(); + f = ds_list_create(); + ft = ds_list_create(); + fn = ds_list_create(); + tri = 0; +} + +function readObj_file() { + var _time = current_time; + + while(!file_text_eof(obj_read_file)) { #region reading file + var l = file_text_readln(obj_read_file); + l = string_trim(l); + + var sep = string_split(l, " "); + if(array_length(sep) == 0) continue; + + switch(sep[0]) { + case "v" : + ds_list_add(v, [ + toNumber(sep[1]) * obj_reading_scale, + toNumber(sep[2]) * obj_reading_scale, + toNumber(sep[3]) * obj_reading_scale + ]); + break; + + case "vt" : + var _u = toNumber(sep[1]); + var _v = toNumber(sep[2]); + + ds_list_add(vt, [ _u, _v ]); + break; + + case "vn" : + var _nx = toNumber(sep[1]); + var _ny = toNumber(sep[2]); + var _nz = toNumber(sep[3]); + + ds_list_add(vn, [ _nx, _ny, _nz ]); + break; + + case "f" : + var _len = array_length(sep); + var _f = array_create(_len - 1); + var _ft = array_create(_len - 1); + var _fn = array_create(_len - 1); + + for( var i = 1; i < _len; i++ ) { + var _sp = string_split(sep[i], "/"); + if(array_length(_sp) < 3) continue; + + _f[i - 1] = toNumber(_sp[0]); + _ft[i - 1] = toNumber(_sp[1]); + _fn[i - 1] = toNumber(_sp[2]); + + use_normal = array_length(_sp) >= 4; + } + + tri += _len - 2; + ds_list_add(f, _f ); //get position + ds_list_add(ft, _ft); //get texture map + ds_list_add(fn, _fn); //get normal + break; + + case "usemtl" : + var mname = ""; + for( var i = 1; i < array_length(sep); i++ ) + mname += (i == 1? "" : " ") + sep[i]; + mname = string_trim(mname); + + array_push_unique(mats, mname); + array_push(matIndex, array_find(mats, mname)); + + if(!ds_list_empty(f)) { + array_push(_VB, f); + array_push(_VBT, ft); + array_push(_VBN, fn); + array_push(tris, tri); + f = ds_list_create(); + ft = ds_list_create(); + fn = ds_list_create(); + } + + tri = 0; + break; + + case "mtllib" : + mtlPath = ""; + for( var i = 1; i < array_length(sep); i++ ) + mtlPath += (i == 1? "" : " ") + sep[i]; + mtlPath = string_trim(mtlPath); + break; + + case "o" : + //print("Reading vertex group: " + sep[1]) + break; + } + + if(current_time - _time > 30) return; + } #endregion + + if(!ds_list_empty(f)) { + array_push(_VB, f); + array_push(_VBT, ft); + array_push(_VBN, fn); + array_push(tris, tri); + } + file_text_close(obj_read_file); + + if(use_normal) vn[| 0] = [ 0, 0, 0 ]; + + obj_read_progress = 1; + obj_read_prog_sub = 0; + + //var txt = "OBJ summary"; + //txt += $"\n\tVerticies : {ds_list_size(v)}"; + //txt += $"\n\tTexture Verticies : {ds_list_size(vt)}"; + //txt += $"\n\tNormal Verticies : {ds_list_size(vn)}"; + //txt += $"\n\tVertex groups : {array_length(_VB)}"; + //txt += $"\n\tTriangles : {tris}"; + //print(txt); +} + +function readObj_cent() { + #region centralize vertex + _bmin = v[| 0]; + _bmax = v[| 0]; + cv = [0, 0, 0]; + + vertex = ds_list_size(v); + + for( var i = 0; i < vertex; i++ ) { + var _v = v[| i]; + var _v0 = _v[0]; + var _v1 = _v[1]; + var _v2 = _v[2]; + + cv[0] += _v0; + cv[1] += _v1; + cv[2] += _v2; + + _bmin = [ + min(_bmin[0], _v0), + min(_bmin[1], _v1), + min(_bmin[2], _v2), + ]; + _bmax = [ + max(_bmax[0], _v0), + max(_bmax[1], _v1), + max(_bmax[2], _v2), + ]; + } + + cv[0] /= vertex; + cv[1] /= vertex; + cv[2] /= vertex; + + obj_size = new __vec3( + _bmax[0] - _bmin[0], + _bmax[1] - _bmin[1], + _bmax[2] - _bmin[2], + ); + + //print($"{obj_size}"); + + var sc = 1; + //var span = max(abs(_size.x), abs(_size.y), abs(_size.z)); + //if(span > 10) sc = span / 10; + + for( var i = 0, n = ds_list_size(v); i < n; i++ ) { + v[| i][0] = (v[| i][0] - cv[0]) / sc; + v[| i][1] = (v[| i][1] - cv[1]) / sc; + v[| i][2] = (v[| i][2] - cv[2]) / sc; + } + #endregion + + obj_read_progress = 2; + obj_read_prog_sub = 0; +} + +function readObj_buff() { + #region vertex buffer creation + var _vblen = array_length(_VB); + var VBS = array_create(_vblen); + var V = array_create(_vblen); + + for(var i = 0; i < _vblen; i++) { + var VB = vertex_create_buffer(); + vertex_begin(VB, global.VF_POS_NORM_TEX_COL); + var face = _VB[i]; + var facet = _VBT[i]; + var facen = _VBN[i]; + + var _flen = ds_list_size(face); + var _v = ds_list_create(); + + for(var j = 0; j < _flen; j++) { + var _f = face[| j]; + var _ft = facet[| j]; + var _fn = facen[| j]; + + var _vlen = array_length(_f); + var _pf = array_create(_vlen); + var _pft = array_create(_vlen); + var _pfn = array_create(_vlen); + + for( var k = 0; k < _vlen; k++ ) { + var _vPindex = _f[k] - 1; + _pf[k] = v[| _vPindex]; + + var _vNindex = _fn[k] - 1; + _pfn[k] = vn[| _vNindex]; + + var _vTindex = _ft[k] - 1; + _pft[k] = vt[| _vTindex]; + } + + if(_vlen >= 3) { + vertex_add_pntc(VB, _pf[0], _pfn[0], _pft[0]); + vertex_add_pntc(VB, _pf[2], _pfn[2], _pft[2]); + vertex_add_pntc(VB, _pf[1], _pfn[1], _pft[1]); + + ds_list_add(_v, new __vertex(_pf[0][0], _pf[0][1], _pf[0][2]).setNormal(_pfn[0][0], _pfn[0][1]).setUV(_pft[0][0], _pft[0][1])); + ds_list_add(_v, new __vertex(_pf[2][0], _pf[2][1], _pf[2][2]).setNormal(_pfn[2][0], _pfn[2][1]).setUV(_pft[2][0], _pft[2][1])); + ds_list_add(_v, new __vertex(_pf[1][0], _pf[1][1], _pf[1][2]).setNormal(_pfn[1][0], _pfn[1][1]).setUV(_pft[1][0], _pft[1][1])); + } + + if(_vlen >= 4) { + vertex_add_pntc(VB, _pf[0], _pfn[0], _pft[0]); + vertex_add_pntc(VB, _pf[3], _pfn[3], _pft[3]); + vertex_add_pntc(VB, _pf[2], _pfn[2], _pft[2]); + + ds_list_add(_v, new __vertex(_pf[0][0], _pf[0][1], _pf[0][2]).setNormal(_pfn[0][0], _pfn[0][1]).setUV(_pft[0][0], _pft[0][1])); + ds_list_add(_v, new __vertex(_pf[3][0], _pf[3][1], _pf[3][2]).setNormal(_pfn[3][0], _pfn[3][1]).setUV(_pft[3][0], _pft[3][1])); + ds_list_add(_v, new __vertex(_pf[2][0], _pf[2][1], _pf[2][2]).setNormal(_pfn[2][0], _pfn[2][1]).setUV(_pft[2][0], _pft[2][1])); + } + } + + vertex_end(VB); + vertex_freeze(VB); + + VBS[i] = VB; + V[i] = ds_list_to_array(_v); + ds_list_destroy(_v); + } + #endregion + + #region clean + array_foreach(_VB, function(val, ind) { ds_list_destroy(val); }); + array_foreach(_VBT, function(val, ind) { ds_list_destroy(val); }); + array_foreach(_VBN, function(val, ind) { ds_list_destroy(val); }); + + ds_list_destroy(v); + ds_list_destroy(vn); + ds_list_destroy(vt); + #endregion + + obj_read_progress = 3; + obj_read_prog_sub = 0; + + obj_raw = { + vertex: V, + vertex_count: vertex, + vertex_groups: VBS, + object_counts: _vblen, + + materials: mats, + material_index: matIndex, + use_normal: use_normal, + mtl_path: mtlPath, + model_size: obj_size, + }; +} \ No newline at end of file diff --git a/#backups/scripts/obj_reader/obj_reader.gml.backup1 b/#backups/scripts/obj_reader/obj_reader.gml.backup1 new file mode 100644 index 000000000..c20ca6732 --- /dev/null +++ b/#backups/scripts/obj_reader/obj_reader.gml.backup1 @@ -0,0 +1,295 @@ +// 2024-05-01 13:44:23 +function readObj_init(_scale = 1) { + obj_reading = true; + obj_read_progress = 0; + obj_read_prog_sub = 0; + obj_read_prog_tot = 3; + obj_raw = noone; + + obj_reading_scale = _scale; + + _VB = []; + _VBT = []; + _VBN = []; + mats = []; + + matIndex = []; + tris = []; + mtlPath = ""; + use_normal = true; + + v = ds_list_create(); + vt = ds_list_create(); + vn = ds_list_create(); + f = ds_list_create(); + ft = ds_list_create(); + fn = ds_list_create(); + tri = 0; +} + +function readObj_file() { + var _time = current_time; + + while(!file_text_eof(obj_read_file)) { #region reading file + var l = file_text_readln(obj_read_file); + l = string_trim(l); + + var sep = string_split(l, " "); + if(array_length(sep) == 0) continue; + + switch(sep[0]) { + case "v" : + ds_list_add(v, [ + toNumber(sep[1]) * obj_reading_scale, + toNumber(sep[2]) * obj_reading_scale, + toNumber(sep[3]) * obj_reading_scale + ]); + break; + + case "vt" : + var _u = toNumber(sep[1]); + var _v = toNumber(sep[2]); + + ds_list_add(vt, [ _u, _v ]); + break; + + case "vn" : + var _nx = toNumber(sep[1]); + var _ny = toNumber(sep[2]); + var _nz = toNumber(sep[3]); + + ds_list_add(vn, [ _nx, _ny, _nz ]); + break; + + case "f" : + var _len = array_length(sep); + var _f = array_create(_len - 1); + var _ft = array_create(_len - 1); + var _fn = array_create(_len - 1); + + for( var i = 1; i < _len; i++ ) { + var _sp = string_split(sep[i], "/"); + if(array_length(_sp) < 3) continue; + + _f[i - 1] = toNumber(_sp[0]); + _ft[i - 1] = toNumber(_sp[1]); + _fn[i - 1] = toNumber(_sp[2]); + + use_normal = array_length(_sp) >= 4; + } + + tri += _len - 2; + ds_list_add(f, _f ); //get position + ds_list_add(ft, _ft); //get texture map + ds_list_add(fn, _fn); //get normal + break; + + case "usemtl" : + var mname = ""; + for( var i = 1; i < array_length(sep); i++ ) + mname += (i == 1? "" : " ") + sep[i]; + mname = string_trim(mname); + + array_push_unique(mats, mname); + array_push(matIndex, array_find(mats, mname)); + + if(!ds_list_empty(f)) { + array_push(_VB, f); + array_push(_VBT, ft); + array_push(_VBN, fn); + array_push(tris, tri); + f = ds_list_create(); + ft = ds_list_create(); + fn = ds_list_create(); + } + + tri = 0; + break; + + case "mtllib" : + mtlPath = ""; + for( var i = 1; i < array_length(sep); i++ ) + mtlPath += (i == 1? "" : " ") + sep[i]; + mtlPath = string_trim(mtlPath); + break; + + case "o" : + //print("Reading vertex group: " + sep[1]) + break; + } + + if(current_time - _time > 30) return; + } #endregion + + if(!ds_list_empty(f)) { + array_push(_VB, f); + array_push(_VBT, ft); + array_push(_VBN, fn); + array_push(tris, tri); + } + file_text_close(obj_read_file); + + if(use_normal) vn[| 0] = [ 0, 0, 0 ]; + + obj_read_progress = 1; + obj_read_prog_sub = 0; + + //var txt = "OBJ summary"; + //txt += $"\n\tVerticies : {ds_list_size(v)}"; + //txt += $"\n\tTexture Verticies : {ds_list_size(vt)}"; + //txt += $"\n\tNormal Verticies : {ds_list_size(vn)}"; + //txt += $"\n\tVertex groups : {array_length(_VB)}"; + //txt += $"\n\tTriangles : {tris}"; + //print(txt); +} + +function readObj_cent() { + #region centralize vertex + _bmin = v[| 0]; + _bmax = v[| 0]; + cv = [0, 0, 0]; + + vertex = ds_list_size(v); + + for( var i = 0; i < vertex; i++ ) { + var _v = v[| i]; + var _v0 = _v[0]; + var _v1 = _v[1]; + var _v2 = _v[2]; + + cv[0] += _v0; + cv[1] += _v1; + cv[2] += _v2; + + _bmin = [ + min(_bmin[0], _v0), + min(_bmin[1], _v1), + min(_bmin[2], _v2), + ]; + _bmax = [ + max(_bmax[0], _v0), + max(_bmax[1], _v1), + max(_bmax[2], _v2), + ]; + } + + cv[0] /= vertex; + cv[1] /= vertex; + cv[2] /= vertex; + + obj_size = new __vec3( + _bmax[0] - _bmin[0], + _bmax[1] - _bmin[1], + _bmax[2] - _bmin[2], + ); + + print($"{obj_size}"); + + var sc = 1; + //var span = max(abs(_size.x), abs(_size.y), abs(_size.z)); + //if(span > 10) sc = span / 10; + + for( var i = 0, n = ds_list_size(v); i < n; i++ ) { + v[| i][0] = (v[| i][0] - cv[0]) / sc; + v[| i][1] = (v[| i][1] - cv[1]) / sc; + v[| i][2] = (v[| i][2] - cv[2]) / sc; + } + #endregion + + obj_read_progress = 2; + obj_read_prog_sub = 0; +} + +function readObj_buff() { + #region vertex buffer creation + var _vblen = array_length(_VB); + var VBS = array_create(_vblen); + var V = array_create(_vblen); + + for(var i = 0; i < _vblen; i++) { + var VB = vertex_create_buffer(); + vertex_begin(VB, global.VF_POS_NORM_TEX_COL); + var face = _VB[i]; + var facet = _VBT[i]; + var facen = _VBN[i]; + + var _flen = ds_list_size(face); + var _v = ds_list_create(); + + for(var j = 0; j < _flen; j++) { + var _f = face[| j]; + var _ft = facet[| j]; + var _fn = facen[| j]; + + var _vlen = array_length(_f); + var _pf = array_create(_vlen); + var _pft = array_create(_vlen); + var _pfn = array_create(_vlen); + + for( var k = 0; k < _vlen; k++ ) { + var _vPindex = _f[k] - 1; + _pf[k] = v[| _vPindex]; + + var _vNindex = _fn[k] - 1; + _pfn[k] = vn[| _vNindex]; + + var _vTindex = _ft[k] - 1; + _pft[k] = vt[| _vTindex]; + } + + if(_vlen >= 3) { + vertex_add_pntc(VB, _pf[0], _pfn[0], _pft[0]); + vertex_add_pntc(VB, _pf[2], _pfn[2], _pft[2]); + vertex_add_pntc(VB, _pf[1], _pfn[1], _pft[1]); + + ds_list_add(_v, new __vertex(_pf[0][0], _pf[0][1], _pf[0][2]).setNormal(_pfn[0][0], _pfn[0][1]).setUV(_pft[0][0], _pft[0][1])); + ds_list_add(_v, new __vertex(_pf[2][0], _pf[2][1], _pf[2][2]).setNormal(_pfn[2][0], _pfn[2][1]).setUV(_pft[2][0], _pft[2][1])); + ds_list_add(_v, new __vertex(_pf[1][0], _pf[1][1], _pf[1][2]).setNormal(_pfn[1][0], _pfn[1][1]).setUV(_pft[1][0], _pft[1][1])); + } + + if(_vlen >= 4) { + vertex_add_pntc(VB, _pf[0], _pfn[0], _pft[0]); + vertex_add_pntc(VB, _pf[3], _pfn[3], _pft[3]); + vertex_add_pntc(VB, _pf[2], _pfn[2], _pft[2]); + + ds_list_add(_v, new __vertex(_pf[0][0], _pf[0][1], _pf[0][2]).setNormal(_pfn[0][0], _pfn[0][1]).setUV(_pft[0][0], _pft[0][1])); + ds_list_add(_v, new __vertex(_pf[3][0], _pf[3][1], _pf[3][2]).setNormal(_pfn[3][0], _pfn[3][1]).setUV(_pft[3][0], _pft[3][1])); + ds_list_add(_v, new __vertex(_pf[2][0], _pf[2][1], _pf[2][2]).setNormal(_pfn[2][0], _pfn[2][1]).setUV(_pft[2][0], _pft[2][1])); + } + } + + vertex_end(VB); + vertex_freeze(VB); + + VBS[i] = VB; + V[i] = ds_list_to_array(_v); + ds_list_destroy(_v); + } + #endregion + + #region clean + array_foreach(_VB, function(val, ind) { ds_list_destroy(val); }); + array_foreach(_VBT, function(val, ind) { ds_list_destroy(val); }); + array_foreach(_VBN, function(val, ind) { ds_list_destroy(val); }); + + ds_list_destroy(v); + ds_list_destroy(vn); + ds_list_destroy(vt); + #endregion + + obj_read_progress = 3; + obj_read_prog_sub = 0; + + obj_raw = { + vertex: V, + vertex_count: vertex, + vertex_groups: VBS, + object_counts: _vblen, + + materials: mats, + material_index: matIndex, + use_normal: use_normal, + mtl_path: mtlPath, + model_size: obj_size, + }; +} \ No newline at end of file diff --git a/#backups/scripts/panel_graph/panel_graph.gml.backup0 b/#backups/scripts/panel_graph/panel_graph.gml.backup0 index 552e76cc6..65f2af32a 100644 --- a/#backups/scripts/panel_graph/panel_graph.gml.backup0 +++ b/#backups/scripts/panel_graph/panel_graph.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-30 16:02:42 +// 2024-05-01 09:02:09 #region funtion calls function __fnInit_Graph() { __registerFunction("graph_add_node", panel_graph_add_node); @@ -167,7 +167,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #endregion #region ---- position ---- - scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0 ]; graph_s = 1; graph_s_to = graph_s; diff --git a/#backups/scripts/panel_graph/panel_graph.gml.backup1 b/#backups/scripts/panel_graph/panel_graph.gml.backup1 index 69ab39889..f20ff7b8c 100644 --- a/#backups/scripts/panel_graph/panel_graph.gml.backup1 +++ b/#backups/scripts/panel_graph/panel_graph.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-30 15:49:15 +// 2024-05-01 08:49:36 #region funtion calls function __fnInit_Graph() { __registerFunction("graph_add_node", panel_graph_add_node); @@ -167,7 +167,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #endregion #region ---- position ---- - scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0 ]; graph_s = 1; graph_s_to = graph_s; diff --git a/#backups/scripts/panel_preview/panel_preview.gml.backup0 b/#backups/scripts/panel_preview/panel_preview.gml.backup0 index 3bb9b0ab3..b1a1dce96 100644 --- a/#backups/scripts/panel_preview/panel_preview.gml.backup0 +++ b/#backups/scripts/panel_preview/panel_preview.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-30 13:08:35 +// 2024-05-01 16:14:03 #region funtion calls function __fnInit_Preview() { __registerFunction("preview_focus_content", panel_preview_focus_content); @@ -927,7 +927,7 @@ function Panel_Preview() : PanelContent() constructor { #region defer var _prev_obj = _prev_node.getPreviewObject(); - d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); + if(_prev_obj) d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); #endregion #region grid @@ -1504,6 +1504,7 @@ function Panel_Preview() : PanelContent() constructor { } wdg.setFocusHover(pFOCUS, pHOVER); + var _tool_font = f_p3; switch(instanceof(wdg)) { case "textBox" : @@ -1512,16 +1513,27 @@ function Panel_Preview() : PanelContent() constructor { break; case "buttonGroup": - case "checkBoxGroup" : tolw = tolh * wdg.size; break; + case "checkBoxGroup" : + tolw = tolh * wdg.size; + break; - case "checkBox" : tolw = tolh; break; - case "scrollBox" : tolw = ui(96); break; - case "buttonClass" : tolw = wdg.text == ""? tolh : tolw; break; + case "checkBox" : + tolw = tolh; + break; + + case "scrollBox" : + tolw = ui(96); + _tool_font = f_p2; + break; + + case "buttonClass" : + tolw = wdg.text == ""? tolh : tolw; + break; } var params = new widgetParam(tolx, toly, tolw, tolh, atr[$ key],, [ mx, my ]) params.s = tolh; - params.font = f_p3; + params.font = _tool_font; wdg.drawParam(params); diff --git a/#backups/scripts/panel_preview/panel_preview.gml.backup1 b/#backups/scripts/panel_preview/panel_preview.gml.backup1 index 645898e55..57fd77d2e 100644 --- a/#backups/scripts/panel_preview/panel_preview.gml.backup1 +++ b/#backups/scripts/panel_preview/panel_preview.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-30 13:08:33 +// 2024-05-01 16:14:02 #region funtion calls function __fnInit_Preview() { __registerFunction("preview_focus_content", panel_preview_focus_content); @@ -927,7 +927,7 @@ function Panel_Preview() : PanelContent() constructor { #region defer var _prev_obj = _prev_node.getPreviewObject(); - d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); + if(_prev_obj) d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); #endregion #region grid @@ -1504,6 +1504,7 @@ function Panel_Preview() : PanelContent() constructor { } wdg.setFocusHover(pFOCUS, pHOVER); + var _tool_font = f_p3; switch(instanceof(wdg)) { case "textBox" : @@ -1512,16 +1513,27 @@ function Panel_Preview() : PanelContent() constructor { break; case "buttonGroup": - case "checkBoxGroup" : tolw = tolh * wdg.size; break; + case "checkBoxGroup" : + tolw = tolh * wdg.size; + break; - case "checkBox" : tolw = tolh; break; - case "scrollBox" : tolw = ui(96); break; - case "buttonClass" : tolw = wdg.text == ""? tolh : tolw; break; + case "checkBox" : + tolw = tolh; + break; + + case "scrollBox" : + tolw = ui(96); + _tool_font = f_p2; + break; + + case "buttonClass" : + tolw = wdg.text == ""? tolh : tolw; + break; } var params = new widgetParam(tolx, toly, tolw, tolh, atr[$ key],, [ mx, my ]) params.s = tolh; - params.font = f_p3; + params.font = _tool_font; wdg.drawParam(params); diff --git a/#backups/scripts/preferences/preferences.gml.backup0 b/#backups/scripts/preferences/preferences.gml.backup0 index 3dbc7358b..772727856 100644 --- a/#backups/scripts/preferences/preferences.gml.backup0 +++ b/#backups/scripts/preferences/preferences.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-29 18:32:52 +// 2024-05-01 16:00:48 #region preference globalvar PREFERENCES, PREFERENCES_DEF, HOTKEYS_DATA; PREFERENCES = {}; @@ -114,6 +114,7 @@ PREFERENCES.node_param_show = false; PREFERENCES.node_param_width = 192; + PREFERENCES.node_3d_preview_size = 256; #endregion diff --git a/#backups/scripts/preferences/preferences.gml.backup1 b/#backups/scripts/preferences/preferences.gml.backup1 index ff4a68ecf..3b70a17ad 100644 --- a/#backups/scripts/preferences/preferences.gml.backup1 +++ b/#backups/scripts/preferences/preferences.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-28 08:01:20 +// 2024-05-01 15:57:54 #region preference globalvar PREFERENCES, PREFERENCES_DEF, HOTKEYS_DATA; PREFERENCES = {}; @@ -114,6 +114,7 @@ PREFERENCES.node_param_show = false; PREFERENCES.node_param_width = 192; + PREFERENCES.node_3d_preview_size = 256; #endregion diff --git a/#backups/scripts/quarternionBox/quarternionBox.gml.backup0 b/#backups/scripts/quarternionBox/quarternionBox.gml.backup0 new file mode 100644 index 000000000..95e35097f --- /dev/null +++ b/#backups/scripts/quarternionBox/quarternionBox.gml.backup0 @@ -0,0 +1,151 @@ +// 2024-05-01 17:23:09 +enum QUARTERNION_DISPLAY { + quarterion, + euler, +} + +function quarternionBox(_onModify) : widget() constructor { + onModify = _onModify; + current_value = [ 0, 0, 0, 0 ]; + current_unit = QUARTERNION_DISPLAY.quarterion; + + onModifyIndex = function(index, val) { + var v = toNumber(val); + + if(current_unit == QUARTERNION_DISPLAY.quarterion) { + return onModify(index, v); + + } else { + var v = toNumber(val); + var qv = [ + current_value[0], + current_value[1], + current_value[2], + ]; + + qv[index] = v; + return onModify(noone, qv); + } + } + + size = 4; + axis = [ "x", "y", "z", "w" ]; + tooltip = new tooltipSelector("Angle type", [__txt("Quaternion"), __txt("Euler")]); + + disp_w = noone; + clickable = true; + + onModifySingle[0] = function(val) { return onModifyIndex(0, val); } + onModifySingle[1] = function(val) { return onModifyIndex(1, val); } + onModifySingle[2] = function(val) { return onModifyIndex(2, val); } + onModifySingle[3] = function(val) { return onModifyIndex(3, val); } + + for(var i = 0; i < 4; i++) { + tb[i] = new textBox(TEXTBOX_INPUT.number, onModifySingle[i]); + tb[i].slidable = true; + tb[i].label = axis[i]; + } + + static setSlideSpeed = function(speed) { + for(var i = 0; i < size; i++) + tb[i].setSlidable(speed); + } + + static setInteract = function(interactable) { + self.interactable = interactable; + + for( var i = 0; i < size; i++ ) + tb[i].interactable = interactable; + } + + static register = function(parent = noone) { + for( var i = 0; i < size; i++ ) + tb[i].register(parent); + } + + static isHovering = function() { + for( var i = 0, n = array_length(tb); i < n; i++ ) if(tb[i].isHovering()) return true; + return false; + } + + static apply = function() { + for( var i = 0; i < size; i++ ) { + tb[i].apply(); + current_value[i] = toNumber(tb[i]._input_text); + } + } + + static drawParam = function(params) { + setParam(params); + for(var i = 0; i < 4; i++) tb[i].setParam(params); + + return draw(params.x, params.y, params.w, params.h, params.data, params.display_data, params.m); + } + + static draw = function(_x, _y, _w, _h, _data, _display_data, _m) { + x = _x; + y = _y; + w = _w; + h = _h; + + if(!is_array(_data)) return 0; + if(array_empty(_data)) return 0; + if(is_array(_data[0])) return 0; + + var _bs = min(_h, ui(32)); + var _disp = struct_try_get(_display_data, "angle_display"); + + if((_w - _bs) / 2 > ui(64)) { + var bx = _x + _w - _bs; + var by = _y + _h / 2 - _bs / 2; + tooltip.index = _disp; + + if(buttonInstant(THEME.button_hide, bx, by, _bs, _bs, _m, iactive, ihover, tooltip, THEME.unit_angle, _disp, c_white) == 2) { + clickable = false; + _display_data.angle_display = (_disp + 1) % 2; + } + _w -= _bs + ui(8); + } + + current_unit = _display_data.angle_display; + + if(current_unit == QUARTERNION_DISPLAY.quarterion || (!tb[0].sliding && !tb[1].sliding && !tb[2].sliding)) { + current_value[0] = _data[0]; + current_value[1] = _data[1]; + current_value[2] = _data[2]; + + if(current_unit == QUARTERNION_DISPLAY.quarterion) + current_value[3] = _data[3]; + } + + size = _disp? 3 : 4; + var ww = _w / size; + var bx = _x; + disp_w = disp_w == noone? ww : lerp_float(disp_w, ww, 3); + + var _dispDat = _data; + + draw_sprite_stretched_ext(THEME.textbox, 3, _x, _y, _w, _h, c_white, 1); + draw_sprite_stretched_ext(THEME.textbox, 0, _x, _y, _w, _h, c_white, 0.5 + 0.5 * interactable); + + for(var i = 0; i < size; i++) { + var _a = _dispDat[i]; + + tb[i].hide = true; + tb[i].setFocusHover(clickable && active, hover); + tb[i].draw(bx, _y, disp_w, _h, _a, _m); + + bx += disp_w; + } + + clickable = true; + resetFocus(); + + return _h; + } + + static clone = function() { #region + var cln = new quarternionBox(onModify); + return cln; + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/quarternionBox/quarternionBox.gml.backup1 b/#backups/scripts/quarternionBox/quarternionBox.gml.backup1 new file mode 100644 index 000000000..b39492c4d --- /dev/null +++ b/#backups/scripts/quarternionBox/quarternionBox.gml.backup1 @@ -0,0 +1,152 @@ +// 2024-05-01 17:22:26 +enum QUARTERNION_DISPLAY { + quarterion, + euler, +} + +function quarternionBox(_onModify) : widget() constructor { + onModify = _onModify; + current_value = [ 0, 0, 0, 0 ]; + current_unit = QUARTERNION_DISPLAY.quarterion; + + onModifyIndex = function(index, val) { + var v = toNumber(val); + + if(current_unit == QUARTERNION_DISPLAY.quarterion) { + return onModify(index, v); + + } else { + var v = toNumber(val); + var qv = [ + current_value[0], + current_value[1], + current_value[2], + ]; + + qv[index] = v; + print(qv); + return onModify(noone, qv); + } + } + + size = 4; + axis = [ "x", "y", "z", "w" ]; + tooltip = new tooltipSelector("Angle type", [__txt("Quaternion"), __txt("Euler")]); + + disp_w = noone; + clickable = true; + + onModifySingle[0] = function(val) { return onModifyIndex(0, val); } + onModifySingle[1] = function(val) { return onModifyIndex(1, val); } + onModifySingle[2] = function(val) { return onModifyIndex(2, val); } + onModifySingle[3] = function(val) { return onModifyIndex(3, val); } + + for(var i = 0; i < 4; i++) { + tb[i] = new textBox(TEXTBOX_INPUT.number, onModifySingle[i]); + tb[i].slidable = true; + tb[i].label = axis[i]; + } + + static setSlideSpeed = function(speed) { + for(var i = 0; i < size; i++) + tb[i].setSlidable(speed); + } + + static setInteract = function(interactable) { + self.interactable = interactable; + + for( var i = 0; i < size; i++ ) + tb[i].interactable = interactable; + } + + static register = function(parent = noone) { + for( var i = 0; i < size; i++ ) + tb[i].register(parent); + } + + static isHovering = function() { + for( var i = 0, n = array_length(tb); i < n; i++ ) if(tb[i].isHovering()) return true; + return false; + } + + static apply = function() { + for( var i = 0; i < size; i++ ) { + tb[i].apply(); + current_value[i] = toNumber(tb[i]._input_text); + } + } + + static drawParam = function(params) { + setParam(params); + for(var i = 0; i < 4; i++) tb[i].setParam(params); + + return draw(params.x, params.y, params.w, params.h, params.data, params.display_data, params.m); + } + + static draw = function(_x, _y, _w, _h, _data, _display_data, _m) { + x = _x; + y = _y; + w = _w; + h = _h; + + if(!is_array(_data)) return 0; + if(array_empty(_data)) return 0; + if(is_array(_data[0])) return 0; + + var _bs = min(_h, ui(32)); + var _disp = struct_try_get(_display_data, "angle_display"); + + if((_w - _bs) / 2 > ui(64)) { + var bx = _x + _w - _bs; + var by = _y + _h / 2 - _bs / 2; + tooltip.index = _disp; + + if(buttonInstant(THEME.button_hide, bx, by, _bs, _bs, _m, iactive, ihover, tooltip, THEME.unit_angle, _disp, c_white) == 2) { + clickable = false; + _display_data.angle_display = (_disp + 1) % 2; + } + _w -= _bs + ui(8); + } + + current_unit = _display_data.angle_display; + + if(current_unit == QUARTERNION_DISPLAY.quarterion || (!tb[0].sliding && !tb[1].sliding && !tb[2].sliding)) { + current_value[0] = _data[0]; + current_value[1] = _data[1]; + current_value[2] = _data[2]; + + if(current_unit == QUARTERNION_DISPLAY.quarterion) + current_value[3] = _data[3]; + } + + size = _disp? 3 : 4; + var ww = _w / size; + var bx = _x; + disp_w = disp_w == noone? ww : lerp_float(disp_w, ww, 3); + + var _dispDat = _data; + + draw_sprite_stretched_ext(THEME.textbox, 3, _x, _y, _w, _h, c_white, 1); + draw_sprite_stretched_ext(THEME.textbox, 0, _x, _y, _w, _h, c_white, 0.5 + 0.5 * interactable); + + for(var i = 0; i < size; i++) { + var _a = _dispDat[i]; + + tb[i].hide = true; + tb[i].setFocusHover(clickable && active, hover); + tb[i].draw(bx, _y, disp_w, _h, _a, _m); + + bx += disp_w; + } + + clickable = true; + resetFocus(); + + return _h; + } + + static clone = function() { #region + var cln = new quarternionBox(onModify); + return cln; + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/shell_functions/shell_functions.gml.backup0 b/#backups/scripts/shell_functions/shell_functions.gml.backup0 new file mode 100644 index 000000000..5aad2573c --- /dev/null +++ b/#backups/scripts/shell_functions/shell_functions.gml.backup0 @@ -0,0 +1,51 @@ +// 2024-05-01 11:40:21 +function shellOpenExplorer(path) { #region + if(OS == os_windows) { + var _windir = environment_get_variable("WINDIR") + "/explorer.exe"; + path = string_replace_all(path, "/", "\\"); + shell_execute_async(_windir, path); + } else if(OS == os_macosx) { + path = string_replace_all(path, "\\", "/"); + var res = shell_execute_async("open", path); + } +} #endregion + +function shell_execute(path, command, ref = noone) { #region + INLINE + + if(OS == os_macosx) { + path = string_replace_all(path, "\\", "/"); + command = string_replace_all(command, "\\", "/"); + } + + var txt = $"{path} {command}"; + var res = ProcessExecute(txt); + print($"Execute {path} {command} | {res}"); + + return res; +} #endregion + +function shell_execute_async(path, command, ref = noone, _log = true) { #region + INLINE + + if(IS_CMD) return shell_execute(path, command, ref); + + if(OS == os_macosx) { + path = string_replace_all(path, "\\", "/"); + command = string_replace_all(command, "\\", "/"); + } + + var txt = $"{path} {command}"; + var res = ProcessExecuteAsync(txt); + if(_log) print($"Execute async {path} {command} | {res}"); + + return res; +} #endregion + +function env_user() { #region + INLINE + + if(OS == os_windows) return string(environment_get_variable("userprofile")) + "\\AppData\\Local\\PixelComposer\\"; + if(OS == os_macosx) return string(environment_get_variable("HOME")) + "/PixelComposer/"; + return ""; +} #endregion \ No newline at end of file diff --git a/#backups/scripts/string_functions/string_functions.gml.backup0 b/#backups/scripts/string_functions/string_functions.gml.backup0 index c920cbe93..fecfb71b2 100644 --- a/#backups/scripts/string_functions/string_functions.gml.backup0 +++ b/#backups/scripts/string_functions/string_functions.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-16 08:41:19 +// 2024-05-01 11:31:11 function string_to_array(str) { #region var amo = string_length(str); var arr = array_create(amo); @@ -66,12 +66,5 @@ function filename_name_only(name) { #region return string_replace(name, filename_ext(name), "") } #endregion -function string_to_var(str) { #region - INLINE - return string_replace_all(string_lower(str), " ", "_"); -} #endregion - -function string_quote(str) { #region - INLINE - return $"\"{str}\""; -} #endregion \ No newline at end of file +function string_to_var(str) { INLINE return string_replace_all(string_lower(str), " ", "_"); } +function string_quote(str) { INLINE return $"\"{str}\""; } \ No newline at end of file diff --git a/#backups/scripts/string_functions/string_functions.gml.backup1 b/#backups/scripts/string_functions/string_functions.gml.backup1 index 4cf455ec9..de7c8fe3b 100644 --- a/#backups/scripts/string_functions/string_functions.gml.backup1 +++ b/#backups/scripts/string_functions/string_functions.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-16 08:29:49 +// 2024-05-01 11:29:46 function string_to_array(str) { #region var amo = string_length(str); var arr = array_create(amo); @@ -66,12 +66,5 @@ function filename_name_only(name) { #region return string_replace(name, filename_ext(name), "") } #endregion -function string_to_var(str) { #region - INLINE - return string_replace_all(string_lower(str), " ", "_"); -} #endregion - -function string_quote(str) { #region - INLINE - return $"\"{str}\""; -} #endregion \ No newline at end of file +function string_to_var(str) { INLINE return string_replace_all(string_lower(str), " ", "_"); } +function string_quote(str) { INLINE return $"\"{str}\""; } \ No newline at end of file diff --git a/#backups/scripts/textBox/textBox.gml.backup0 b/#backups/scripts/textBox/textBox.gml.backup0 index d32f23168..54eba36d9 100644 --- a/#backups/scripts/textBox/textBox.gml.backup0 +++ b/#backups/scripts/textBox/textBox.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-18 13:00:44 +// 2024-05-01 11:57:36 enum TEXTBOX_INPUT { text, number @@ -7,9 +7,9 @@ enum TEXTBOX_INPUT { function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { onRelease = noone; - align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; - hide = false; - color = COLORS._main_text; + align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; + hide = false; + color = COLORS._main_text; boxColor = c_white; format = TEXT_AREA_FORMAT._default; precision = 5; @@ -498,8 +498,10 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { draw_set_alpha(1); } } - + + var _dpx = disp_x; disp_x = lerp_float(disp_x, disp_x_to, 5); + if(_dpx != disp_x) _update = true; var hoverRect = point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h); diff --git a/#backups/scripts/textBox/textBox.gml.backup1 b/#backups/scripts/textBox/textBox.gml.backup1 index 9c516b0fe..39c159d9a 100644 --- a/#backups/scripts/textBox/textBox.gml.backup1 +++ b/#backups/scripts/textBox/textBox.gml.backup1 @@ -1,4 +1,4 @@ -// 2024-04-18 13:00:36 +// 2024-05-01 11:57:26 enum TEXTBOX_INPUT { text, number @@ -7,9 +7,9 @@ enum TEXTBOX_INPUT { function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { onRelease = noone; - align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; - hide = false; - color = COLORS._main_text; + align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; + hide = false; + color = COLORS._main_text; boxColor = c_white; format = TEXT_AREA_FORMAT._default; precision = 5; @@ -498,8 +498,10 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { draw_set_alpha(1); } } - + + var _dpx = disp_x; disp_x = lerp_float(disp_x, disp_x_to, 5); + if(_dpx != disp_x) _update = true; var hoverRect = point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h); diff --git a/objects/o_dialog_preference/Create_0.gml b/objects/o_dialog_preference/Create_0.gml index b77783ab6..bfc58c9ea 100644 --- a/objects/o_dialog_preference/Create_0.gml +++ b/objects/o_dialog_preference/Create_0.gml @@ -551,6 +551,17 @@ event_inherited(); PREF_SAVE(); }) )); + + ds_list_add(pref_node, new __Panel_Linear_Setting_Item_Preference( + __txtx("pref_node_3d_preview", "Preview surface size"), + "node_3d_preview_size", + + new textBox(TEXTBOX_INPUT.number, function(val) { + PREFERENCES.node_3d_preview_size = clamp(val, 16, 1024); + PREF_SAVE(); + }) + )); + #endregion #region theme diff --git a/objects/o_main/Draw_75.gml b/objects/o_main/Draw_75.gml index 21b55a96f..b73a7f772 100644 --- a/objects/o_main/Draw_75.gml +++ b/objects/o_main/Draw_75.gml @@ -2,110 +2,112 @@ if(winMan_isMinimized()) exit; #region tooltip - if(is_struct(TOOLTIP)) { - if(struct_has(TOOLTIP, "drawTooltip")) - TOOLTIP.drawTooltip(); - - } else if(is_array(TOOLTIP)) { - var content = TOOLTIP[0]; - var type = TOOLTIP[1]; - - if(is_method(content)) content = content(); - - switch(type) { - case VALUE_TYPE.float : - case VALUE_TYPE.integer : - case VALUE_TYPE.text : - case VALUE_TYPE.struct : - case VALUE_TYPE.path : - draw_tooltip_text(string_real(content)); - break; + if(!_MOUSE_BLOCK) { + if(is_struct(TOOLTIP)) { + if(struct_has(TOOLTIP, "drawTooltip")) + TOOLTIP.drawTooltip(); - case VALUE_TYPE.boolean : - draw_tooltip_text(printBool(content)); - break; + } else if(is_array(TOOLTIP)) { + var content = TOOLTIP[0]; + var type = TOOLTIP[1]; - case VALUE_TYPE.curve : - draw_tooltip_text("[" + __txt("Curve Object") + "]"); - break; + if(is_method(content)) content = content(); - case VALUE_TYPE.color : - draw_tooltip_color(content); - break; - - case VALUE_TYPE.gradient : - draw_tooltip_gradient(content); - break; - - case VALUE_TYPE.d3object : - draw_tooltip_text("[" + __txt("3D Object") + "]"); - break; - - case VALUE_TYPE.object : - draw_tooltip_text("[" + __txt("Object") + "]"); - break; - - case VALUE_TYPE.surface : - draw_tooltip_surface(content); - break; - - case VALUE_TYPE.rigid : - draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); - break; - - case VALUE_TYPE.particle : - var txt = "[" + - __txt("Particle Object") + - " (size: " + string(array_length(content)) + ") " + - "]"; - draw_tooltip_text(txt); - break; - - case VALUE_TYPE.pathnode : - draw_tooltip_text("[" + __txt("Path Object") + "]"); - break; - - case VALUE_TYPE.sdomain : - draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); - break; - - case VALUE_TYPE.strands : - var txt = __txt("Strands Object"); - if(is_struct(content)) - txt += " (strands: " + string(array_length(content.hairs)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.mesh : - var txt = __txt("Mesh Object"); - if(is_struct(content)) - txt += " (triangles: " + string(array_length(content.triangles)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.d3vertex : - var txt = __txt("3D Vertex"); - txt += " (groups: " + string(array_length(content)) + ")"; - draw_tooltip_text("[" + txt + "]"); - break; - - case VALUE_TYPE.buffer : - draw_tooltip_buffer(content); - break; - - case "sprite" : - draw_tooltip_sprite(content); - break; - - default : - var tt = ""; - if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; - else tt = string(content); - - draw_tooltip_text(tt); - } - } else if(TOOLTIP != "") - draw_tooltip_text(TOOLTIP); + switch(type) { + case VALUE_TYPE.float : + case VALUE_TYPE.integer : + case VALUE_TYPE.text : + case VALUE_TYPE.struct : + case VALUE_TYPE.path : + draw_tooltip_text(string_real(content)); + break; + + case VALUE_TYPE.boolean : + draw_tooltip_text(printBool(content)); + break; + + case VALUE_TYPE.curve : + draw_tooltip_text("[" + __txt("Curve Object") + "]"); + break; + + case VALUE_TYPE.color : + draw_tooltip_color(content); + break; + + case VALUE_TYPE.gradient : + draw_tooltip_gradient(content); + break; + + case VALUE_TYPE.d3object : + draw_tooltip_text("[" + __txt("3D Object") + "]"); + break; + + case VALUE_TYPE.object : + draw_tooltip_text("[" + __txt("Object") + "]"); + break; + + case VALUE_TYPE.surface : + draw_tooltip_surface(content); + break; + + case VALUE_TYPE.rigid : + draw_tooltip_text("[" + __txt("Rigidbody Object") + " (id: " + string(content[$ "object"]) + ")]"); + break; + + case VALUE_TYPE.particle : + var txt = "[" + + __txt("Particle Object") + + " (size: " + string(array_length(content)) + ") " + + "]"; + draw_tooltip_text(txt); + break; + + case VALUE_TYPE.pathnode : + draw_tooltip_text("[" + __txt("Path Object") + "]"); + break; + + case VALUE_TYPE.sdomain : + draw_tooltip_text("[" + __txt("Domain") + " (id: " + string(content) + ")]"); + break; + + case VALUE_TYPE.strands : + var txt = __txt("Strands Object"); + if(is_struct(content)) + txt += " (strands: " + string(array_length(content.hairs)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.mesh : + var txt = __txt("Mesh Object"); + if(is_struct(content)) + txt += " (triangles: " + string(array_length(content.triangles)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.d3vertex : + var txt = __txt("3D Vertex"); + txt += " (groups: " + string(array_length(content)) + ")"; + draw_tooltip_text("[" + txt + "]"); + break; + + case VALUE_TYPE.buffer : + draw_tooltip_buffer(content); + break; + + case "sprite" : + draw_tooltip_sprite(content); + break; + + default : + var tt = ""; + if(is_struct(content)) tt = $"[{instanceof(content)}] {content}"; + else tt = string(content); + + draw_tooltip_text(tt); + } + } else if(TOOLTIP != "") + draw_tooltip_text(TOOLTIP); + } TOOLTIP = ""; #endregion diff --git a/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml b/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml index 83c92645b..5282c7ba4 100644 --- a/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml +++ b/scripts/BBMOD_Quaternion/BBMOD_Quaternion.gml @@ -587,7 +587,7 @@ function BBMOD_Quaternion(_x=0.0, _y=0.0, _z=0.0, _w=1.0) constructor return self; }; - static ToEuler = function() { + static ToEuler = function(isArray = false) { var ysqr = Y * Y; // roll (x-axis rotation) @@ -606,11 +606,15 @@ function BBMOD_Quaternion(_x=0.0, _y=0.0, _z=0.0, _w=1.0) constructor var yaw = arctan2(t3, t4); // Convert radians to degrees - var _dx = roll * 180.0 / pi; + var _dx = roll * 180.0 / pi; var _dy = pitch * 180.0 / pi; - var _dz = yaw * 180.0 / pi; + var _dz = yaw * 180.0 / pi; - return new __rot3(_dx, _dy, _dz); + _dx = round(_dx * 1000) / 1000; + _dy = round(_dy * 1000) / 1000; + _dz = round(_dz * 1000) / 1000; + + return isArray? [ _dx, _dy, _dz ] : new __rot3(_dx, _dy, _dz); } /// @func ToMatrix([_dest[, _index]]) diff --git a/scripts/__node_3d/__node_3d.gml b/scripts/__node_3d/__node_3d.gml index 3f64b9608..4da0a0862 100644 --- a/scripts/__node_3d/__node_3d.gml +++ b/scripts/__node_3d/__node_3d.gml @@ -35,7 +35,7 @@ function Node_3D(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constr static refreshPreview = function() { #region var _prev_obj = getPreviewObjects(); - mesh_prev_surface = surface_verify(mesh_prev_surface, 64, 64); + mesh_prev_surface = surface_verify(mesh_prev_surface, PREFERENCES.node_3d_preview_size, PREFERENCES.node_3d_preview_size); surface_set_target(mesh_prev_surface); DRAW_CLEAR @@ -56,12 +56,12 @@ function Node_3D(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constr D3D_GLOBAL_PREVIEW.custom_transform.position.set(_c._multiply(-1)); - var _sca = 1 / _b.getMaximumScale(); - D3D_GLOBAL_PREVIEW.custom_transform.scale.set(_sca); + var _sca = 2 / _b.getScale(); + //print($"Submitting object {_prev}\n{_b}, {_c}, {_sca}"); + D3D_GLOBAL_PREVIEW.custom_transform.scale.set(_sca); D3D_GLOBAL_PREVIEW.submitUI(_prev); } - surface_reset_target(); D3D_GLOBAL_PREVIEW.camera.resetCamera(); @@ -78,5 +78,8 @@ function Node_3D(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constr if(!isHighlightingInGraph()) aa *= 0.25; draw_surface_bbox(mesh_prev_surface, bbox,, aa); + onDrawNodeOver(xx, yy, _mx, _my, _s, _hover, _focus); } #endregion + + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover = false, _focus = false) { } } \ No newline at end of file diff --git a/scripts/__node_3d_object/__node_3d_object.gml b/scripts/__node_3d_object/__node_3d_object.gml index 1ff4f90e0..b1bf60447 100644 --- a/scripts/__node_3d_object/__node_3d_object.gml +++ b/scripts/__node_3d_object/__node_3d_object.gml @@ -49,9 +49,9 @@ function Node_3D_Object(_x, _y, _group = noone) : Node_3D(_x, _y, _group) constr tools = [ tool_pos, tool_rot, tool_sca ]; tool_axis_edit = new scrollBox([ "local", "global" ], function(val) { tool_attribute.context = val; }); - tool_axis_edit.font = f_p2; - tool_axis_edit.arrow_spr = THEME.arrow; - tool_axis_edit.arrow_ind = 3; + // tool_axis_edit.font = f_p2; + // tool_axis_edit.arrow_spr = THEME.arrow; + // tool_axis_edit.arrow_ind = 3; tool_attribute.context = 0; tool_settings = [ [ "Axis", tool_axis_edit, "context", tool_attribute ], @@ -279,7 +279,7 @@ function Node_3D_Object(_x, _y, _group = noone) : Node_3D(_x, _y, _group) constr static drawGizmoRotation = function(index, object, _vpos, active, params, _mx, _my, _snx, _sny, _panel) { #region #region ---- main ---- - var _rot = inputs[| index].getValue(,,, true); + var _rot = inputs[| index].getValue(); var _qrot = object == noone? new BBMOD_Quaternion() : object.transform.rotation; var _qinv = new BBMOD_Quaternion().FromAxisAngle(new BBMOD_Vec3(1, 0, 0), 90); @@ -293,7 +293,7 @@ function Node_3D_Object(_x, _y, _group = noone) : Node_3D(_x, _y, _group) constr var th; var _posView = _camera.worldPointToViewPoint(_vpos); - + var cx = _posView.x; var cy = _posView.y; diff --git a/scripts/d3d_bbox/d3d_bbox.gml b/scripts/d3d_bbox/d3d_bbox.gml index ddc8c7bdb..642d4236e 100644 --- a/scripts/d3d_bbox/d3d_bbox.gml +++ b/scripts/d3d_bbox/d3d_bbox.gml @@ -19,4 +19,4 @@ function __bbox3D(first, second) constructor { abs(first.z - second.z), ); } -} \ No newline at end of file +} diff --git a/scripts/d3d_object/d3d_object.gml b/scripts/d3d_object/d3d_object.gml index 000c2024c..1379107e2 100644 --- a/scripts/d3d_object/d3d_object.gml +++ b/scripts/d3d_object/d3d_object.gml @@ -17,7 +17,7 @@ function __3dObject() constructor { vertex = []; normal_vertex = []; object_counts = 1; - VB = noone; + VB = []; NVB = noone; normal_draw_size = 0.2; @@ -134,11 +134,9 @@ function __3dObject() constructor { preSubmitVertex(scene); - if(VB != noone) { #region - transform.submitMatrix(); - - matrix_set(matrix_world, matrix_stack_top()); - } #endregion + transform.submitMatrix(); + + matrix_set(matrix_world, matrix_stack_top()); #region ++++ Submit & Material ++++ gpu_set_tex_repeat(true); @@ -173,7 +171,7 @@ function __3dObject() constructor { } else vertex_submit(VB[i], render_type, _tex); - //print($"Submit vertex ({scene}) [{VB[i]}]"); + // print($"Submit vertex ({scene}) [{VB[i]}: {vertex_get_buffer_size(VB[i])}]"); } gpu_set_tex_repeat(false); @@ -242,11 +240,9 @@ function __3dObject() constructor { } #endregion static destroy = function() { #region - if(is_array(VB)) { - for( var i = 0, n = array_length(VB); i < n; i++ ) - vertex_delete_buffer(VB[i]); - } else if(VB != noone) - vertex_delete_buffer(VB); + for( var i = 0, n = array_length(VB); i < n; i++ ) + vertex_delete_buffer(VB[i]); + VB = []; onDestroy(); } #endregion diff --git a/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml b/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml index bc042fb58..cdea5f5eb 100644 --- a/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml +++ b/scripts/node_3d_mesh_obj/node_3d_mesh_obj.gml @@ -32,10 +32,13 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) inputs[| in_mesh + 1] = nodeValue("Flip UV", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true, "Flip UV axis, can be use to fix some texture mapping error.") .rejectArray(); + inputs[| in_mesh + 2] = nodeValue("Import Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) + .rejectArray(); + input_display_list = [ __d3d_input_list_mesh, __d3d_input_list_transform, - ["Object", false], in_mesh + 0, + ["Object", false], in_mesh + 0, in_mesh + 2, ["Material", false], in_mesh + 1, ] @@ -57,7 +60,10 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) insp1UpdateTooltip = __txt("Refresh"); insp1UpdateIcon = [ THEME.refresh_icon, 1, COLORS._main_value_positive ]; - static onInspector1Update = function() { current_path = ""; } + static onInspector1Update = function() { + current_path = ""; + outputs[| 0].setValue(noone); + } function setPath(path) { inputs[| in_mesh + 0].setValue(path); } @@ -100,7 +106,9 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) if(!file_exists_empty(_path)) return; current_path = _path; - readObj_init(); + var _scale = inputs[| in_mesh + 2].getValue(); + + readObj_init(_scale); obj_read_time = get_timer(); obj_read_file = file_text_open_read(current_path); @@ -119,23 +127,24 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) use_display_list = true; if(obj_raw == noone) return; - //var txt = $"========== OBJ import ==========\n"; - //txt += $"Vertex counts: {obj_raw.vertex_count}\n"; - //txt += $"Object counts: {obj_raw.object_counts}\n"; - //txt += $"Material counts: {array_length(obj_raw.materials)}\n"; - //txt += $"Model BBOX: {obj_raw.model_size}\n"; - //txt += $"Load completed in {(get_timer() - obj_read_time) / 1000} ms\n"; - //print(txt); + // var txt = $"========== OBJ import ==========\n"; + // txt += $"Vertex counts: {obj_raw.vertex_count}\n"; + // txt += $"Object counts: {obj_raw.object_counts}\n"; + // txt += $"Material counts: {array_length(obj_raw.materials)}\n"; + // txt += $"Model BBOX: {obj_raw.model_size}\n"; + // txt += $"Load completed in {(get_timer() - obj_read_time) / 1000} ms\n"; + // print(txt); var span = max(abs(obj_raw.model_size.x), abs(obj_raw.model_size.y), abs(obj_raw.model_size.z)); if(span > 10) noti_warning($"The model is tool large to display properly ({span}u). Scale the model down to preview."); if(object != noone) object.destroy(); + object = new __3dObject(); - object.VB = obj_raw.vertex_groups; - object.vertex = obj_raw.vertex; - object.object_counts = obj_raw.object_counts; + object.VB = obj_raw.vertex_groups; + object.vertex = obj_raw.vertex; object.size = obj_raw.model_size; + object.object_counts = obj_raw.object_counts; use_normal = obj_raw.use_normal; materialNames = [ "Material" ]; @@ -171,6 +180,8 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) for(var i = 0; i < array_length(materialNames); i++) createMaterial(i); + outputs[| 0].setValue(object); + triggerRender(); } #endregion @@ -206,6 +217,7 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) _object.VB = object.VB; _object.NVB = object.NVB; _object.vertex = object.vertex; + _object.size = object.size; _object.object_counts = object.object_counts; _object.materials = materials; _object.material_index = materialIndex; @@ -217,7 +229,7 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) static getPreviewValues = function() { return array_safe_get_fast(all_inputs, in_mesh + 2, noone); } - static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region + static onDrawNodeOver = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region if(!obj_reading) return; var cx = xx + w * _s / 2; @@ -225,7 +237,6 @@ function Node_3D_Mesh_Obj(_x, _y, _group = noone) : Node_3D_Mesh(_x, _y, _group) var rr = min(w - 32, h - 32) * _s / 2; draw_set_color(COLORS._main_icon); - //draw_arc(cx, cy, rr, 90, 90 - 360 * (obj_read_progress + obj_read_prog_sub) / obj_read_prog_tot, 4 * _s, 180); draw_arc(cx, cy, rr, current_time / 5, current_time / 5 + 90, 4 * _s, 90); } #endregion } \ No newline at end of file diff --git a/scripts/node_export/node_export.gml b/scripts/node_export/node_export.gml index a3195c959..03b65a3dc 100644 --- a/scripts/node_export/node_export.gml +++ b/scripts/node_export/node_export.gml @@ -302,7 +302,7 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor } #endregion static renderWebp = function(temp_path, target_path) { #region - var _path = file_find_first(temp_path + "*.png", 0); + var _path = file_find_first(temp_path + "*.png", 0); var frames = []; while(_path != "") { @@ -311,7 +311,7 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor var shell_cmd = _pathTemp + " -define webp:lossless=true " + _frame; array_push(frames, _frame); - shell_execute_async(magick, shell_cmd, self); + shell_execute_async(magick, shell_cmd, self, false); _path = file_find_next(); } @@ -323,7 +323,7 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor var cmd = ""; for( var i = 0, n = array_length(frames); i < n; i++ ) - cmd += "-frame " + frames[i] + " +" + string(framerate) + "+0+0+1 "; + cmd += $"-frame {frames[i]} +{framerate}+0+0+1 "; cmd += "-bgcolor 0,0,0,0 "; cmd += "-o " + string_quote(target_path); @@ -341,7 +341,9 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor var qual = getInputData(10); if(rate == 0) rate = 1; + temp_path = string_replace_all(temp_path, "/", "\\"); target_path = string_replace_all(target_path, "/", "\\"); + var framerate = 100 / rate; var loop_str = loop? 0 : 1; var use_gifski = false; diff --git a/scripts/node_grid/node_grid.gml b/scripts/node_grid/node_grid.gml index 50111e0c1..3206ce425 100644 --- a/scripts/node_grid/node_grid.gml +++ b/scripts/node_grid/node_grid.gml @@ -13,7 +13,7 @@ function Node_Grid(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons .setMappable(13); inputs[| 3] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(14); inputs[| 4] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) diff --git a/scripts/node_grid_hex/node_grid_hex.gml b/scripts/node_grid_hex/node_grid_hex.gml index d75afdce2..b460efcc5 100644 --- a/scripts/node_grid_hex/node_grid_hex.gml +++ b/scripts/node_grid_hex/node_grid_hex.gml @@ -17,7 +17,7 @@ function Node_Grid_Hex(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) .setMappable(12); inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(13); inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) diff --git a/scripts/node_grid_tri/node_grid_tri.gml b/scripts/node_grid_tri/node_grid_tri.gml index fd003d0ed..33c160f88 100644 --- a/scripts/node_grid_tri/node_grid_tri.gml +++ b/scripts/node_grid_tri/node_grid_tri.gml @@ -13,7 +13,7 @@ function Node_Grid_Tri(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) .setMappable(11); inputs[| 3] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(12); inputs[| 4] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) diff --git a/scripts/node_herringbone_tile/node_herringbone_tile.gml b/scripts/node_herringbone_tile/node_herringbone_tile.gml index d6da1d1f6..68ca91042 100644 --- a/scripts/node_herringbone_tile/node_herringbone_tile.gml +++ b/scripts/node_herringbone_tile/node_herringbone_tile.gml @@ -17,7 +17,7 @@ function Node_Herringbone_Tile(_x, _y, _group = noone) : Node_Processor(_x, _y, .setMappable(12); inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.25) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(13); inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) diff --git a/scripts/node_pytagorean_tile/node_pytagorean_tile.gml b/scripts/node_pytagorean_tile/node_pytagorean_tile.gml index 7b3138fbf..c5ab84539 100644 --- a/scripts/node_pytagorean_tile/node_pytagorean_tile.gml +++ b/scripts/node_pytagorean_tile/node_pytagorean_tile.gml @@ -17,7 +17,7 @@ function Node_Pytagorean_Tile(_x, _y, _group = noone) : Node_Processor(_x, _y, _ .setMappable(12); inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.25) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(13); inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) diff --git a/scripts/node_random_tile/node_random_tile.gml b/scripts/node_random_tile/node_random_tile.gml index d79bbeacc..ff33b6c3d 100644 --- a/scripts/node_random_tile/node_random_tile.gml +++ b/scripts/node_random_tile/node_random_tile.gml @@ -17,7 +17,7 @@ function Node_Random_Tile(_x, _y, _group = noone) : Node_Processor(_x, _y, _grou .setMappable(12); inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }) + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }) .setMappable(13); inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) diff --git a/scripts/node_shadow_cast/node_shadow_cast.gml b/scripts/node_shadow_cast/node_shadow_cast.gml index 7c88b0d36..844875fa4 100644 --- a/scripts/node_shadow_cast/node_shadow_cast.gml +++ b/scripts/node_shadow_cast/node_shadow_cast.gml @@ -59,7 +59,7 @@ function Node_Shadow_Cast(_x, _y, _group = noone) : Node_Processor(_x, _y, _grou .setDisplay(VALUE_DISPLAY.slider, { range: [0, 16, 0.1] }); inputs[| 16] = nodeValue("Ambient occlusion strength", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }); + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }); inputs[| 17] = nodeValue("Active", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true); active_index = 17; diff --git a/scripts/node_shape/node_shape.gml b/scripts/node_shape/node_shape.gml index 7563b35ae..32ed73878 100644 --- a/scripts/node_shape/node_shape.gml +++ b/scripts/node_shape/node_shape.gml @@ -64,7 +64,7 @@ function Node_Shape(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) con .setDisplay(VALUE_DISPLAY.rotation_range); inputs[| 9] = nodeValue("Corner radius", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) - .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.01] }); + .setDisplay(VALUE_DISPLAY.slider, { range: [0, 0.5, 0.001] }); inputs[| 10] = nodeValue("Shape color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_white); diff --git a/scripts/node_value/node_value.gml b/scripts/node_value/node_value.gml index f80ca05c8..d6ba442fc 100644 --- a/scripts/node_value/node_value.gml +++ b/scripts/node_value/node_value.gml @@ -1151,7 +1151,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru }); extract_node = "Node_Vector4"; - display_data.angle_display = QUARTERNION_DISPLAY.quarterion; + display_data.angle_display = QUARTERNION_DISPLAY.euler; break; #endregion case VALUE_DISPLAY.path_anchor : #region @@ -1551,19 +1551,6 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru return applyUnit? unit.apply(value, arrIndex) : value; } #endregion - if(display_type == VALUE_DISPLAY.d3quarternion) { #region - if(!applyUnit) return value; - var dispType = display_data.angle_display; - - switch(dispType) { - case QUARTERNION_DISPLAY.quarterion : - return value; - case QUARTERNION_DISPLAY.euler : - var euler = new BBMOD_Quaternion().FromEuler(value[0], value[1], value[2]).ToArray(); - return euler; - } - } #endregion - if(type == VALUE_TYPE.text) { #region switch(display_type) { case VALUE_DISPLAY.text_array : return value; @@ -1910,6 +1897,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru } else val = ds_list_empty(animator.values)? 0 : animator.processType(animator.values[| 0].value); + if(display_type == VALUE_DISPLAY.d3quarternion) { + switch(display_data.angle_display) { + case QUARTERNION_DISPLAY.quarterion : return val; + case QUARTERNION_DISPLAY.euler : return new BBMOD_Quaternion(val[0], val[1], val[2], val[3]).ToEuler(true); + } + } + return val; } #endregion @@ -1992,6 +1986,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru static setValueInspector = function(val = 0, index = noone) { #region INLINE + var res = false; val = unit.invApply(val); @@ -2002,27 +1997,32 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru var _node = PANEL_INSPECTOR.inspectings[i]; if(ind >= ds_list_size(_node.inputs)) continue; - var r = _node.inputs[| ind].setValueDirect(val, index); + var r = _node.inputs[| ind].setValueInspectorDirect(val, index); if(_node == node) res = r; } } else { - res = setValueDirect(val, index); - - //print($"Node {node} : {node.name} {node.internalName}"); - //print($"Inspecting {PANEL_INSPECTOR.inspecting} : {PANEL_INSPECTOR.inspecting.name} {PANEL_INSPECTOR.inspecting.internalName}"); - //print($"{node == PANEL_INSPECTOR.inspecting}"); - //print(""); + res = setValueInspectorDirect(val, index); } return res; } #endregion + static setValueInspectorDirect = function(val = 0, index = noone) { + if(display_type == VALUE_DISPLAY.d3quarternion && display_data.angle_display == QUARTERNION_DISPLAY.euler) { + var _qval = new BBMOD_Quaternion().FromEuler(-val[0], -val[1], -val[2]).ToArray(); + var _eval = new BBMOD_Quaternion(_qval[0], _qval[1], _qval[2], _qval[3]).ToEuler(true); + return setValueDirect(_qval); + } + + return setValueDirect(val, index); + } + static setValueDirect = function(val = 0, index = noone, record = true, time = CURRENT_FRAME, _update = true) { #region is_modified = true; var updated = false; var _val = val; var _inp = connect_type == JUNCTION_CONNECT.input; - + if(sep_axis) { if(index == noone) { for( var i = 0, n = array_length(animators); i < n; i++ ) @@ -2038,8 +2038,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru _val[index] = val; } - updated = animator.setValue(_val, _inp && record, time); - //print($"{updated}: {index} - {_val}"); + updated = animator.setValue(_val, _inp && record, time); } if(type == VALUE_TYPE.gradient) updated = true; diff --git a/scripts/obj_reader/obj_reader.gml b/scripts/obj_reader/obj_reader.gml index 050c941ff..67b00377c 100644 --- a/scripts/obj_reader/obj_reader.gml +++ b/scripts/obj_reader/obj_reader.gml @@ -1,18 +1,22 @@ -function readObj_init() { +function readObj_init(_scale = 1) { obj_reading = true; obj_read_progress = 0; obj_read_prog_sub = 0; obj_read_prog_tot = 3; obj_raw = noone; + obj_reading_scale = _scale; + _VB = []; _VBT = []; _VBN = []; mats = []; + matIndex = []; tris = []; mtlPath = ""; use_normal = true; + v = ds_list_create(); vt = ds_list_create(); vn = ds_list_create(); @@ -34,7 +38,11 @@ function readObj_file() { switch(sep[0]) { case "v" : - ds_list_add(v, [ toNumber(sep[1]), toNumber(sep[2]), toNumber(sep[3]) ]); + ds_list_add(v, [ + toNumber(sep[1]) * obj_reading_scale, + toNumber(sep[2]) * obj_reading_scale, + toNumber(sep[3]) * obj_reading_scale + ]); break; case "vt" : @@ -43,15 +51,11 @@ function readObj_file() { ds_list_add(vt, [ _u, _v ]); break; + case "vn" : var _nx = toNumber(sep[1]); var _ny = toNumber(sep[2]); var _nz = toNumber(sep[3]); - //var _di = sqrt(_nx * _nx + _ny * _ny + _nz * _nz); - - //_nx /= _di; - //_ny /= _di; - //_nz /= _di; ds_list_add(vn, [ _nx, _ny, _nz ]); break; @@ -143,23 +147,28 @@ function readObj_cent() { _bmin = v[| 0]; _bmax = v[| 0]; cv = [0, 0, 0]; + vertex = ds_list_size(v); for( var i = 0; i < vertex; i++ ) { var _v = v[| i]; - cv[0] += _v[0]; - cv[1] += _v[1]; - cv[2] += _v[2]; + var _v0 = _v[0]; + var _v1 = _v[1]; + var _v2 = _v[2]; + + cv[0] += _v0; + cv[1] += _v1; + cv[2] += _v2; _bmin = [ - min(_bmin[0], _v[0]), - min(_bmin[1], _v[1]), - min(_bmin[2], _v[2]), + min(_bmin[0], _v0), + min(_bmin[1], _v1), + min(_bmin[2], _v2), ]; _bmax = [ - max(_bmax[0], _v[0]), - max(_bmax[1], _v[1]), - max(_bmax[2], _v[2]), + max(_bmax[0], _v0), + max(_bmax[1], _v1), + max(_bmax[2], _v2), ]; } @@ -173,7 +182,9 @@ function readObj_cent() { _bmax[2] - _bmin[2], ); - var sc = 1; + //print($"{obj_size}"); + + var sc = 1; //var span = max(abs(_size.x), abs(_size.y), abs(_size.z)); //if(span > 10) sc = span / 10; diff --git a/scripts/panel_graph/panel_graph.gml b/scripts/panel_graph/panel_graph.gml index 1645d71df..c4756f6d9 100644 --- a/scripts/panel_graph/panel_graph.gml +++ b/scripts/panel_graph/panel_graph.gml @@ -166,7 +166,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #endregion #region ---- position ---- - scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0 ]; graph_s = 1; graph_s_to = graph_s; diff --git a/scripts/panel_preview/panel_preview.gml b/scripts/panel_preview/panel_preview.gml index b7dad535d..6427b3e70 100644 --- a/scripts/panel_preview/panel_preview.gml +++ b/scripts/panel_preview/panel_preview.gml @@ -926,7 +926,7 @@ function Panel_Preview() : PanelContent() constructor { #region defer var _prev_obj = _prev_node.getPreviewObject(); - d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); + if(_prev_obj) d3_deferData = d3_scene_preview.deferPass(_prev_obj, w, h, d3_deferData); #endregion #region grid @@ -1503,6 +1503,7 @@ function Panel_Preview() : PanelContent() constructor { } wdg.setFocusHover(pFOCUS, pHOVER); + var _tool_font = f_p3; switch(instanceof(wdg)) { case "textBox" : @@ -1511,16 +1512,27 @@ function Panel_Preview() : PanelContent() constructor { break; case "buttonGroup": - case "checkBoxGroup" : tolw = tolh * wdg.size; break; + case "checkBoxGroup" : + tolw = tolh * wdg.size; + break; - case "checkBox" : tolw = tolh; break; - case "scrollBox" : tolw = ui(96); break; - case "buttonClass" : tolw = wdg.text == ""? tolh : tolw; break; + case "checkBox" : + tolw = tolh; + break; + + case "scrollBox" : + tolw = ui(96); + _tool_font = f_p2; + break; + + case "buttonClass" : + tolw = wdg.text == ""? tolh : tolw; + break; } var params = new widgetParam(tolx, toly, tolw, tolh, atr[$ key],, [ mx, my ]) params.s = tolh; - params.font = f_p3; + params.font = _tool_font; wdg.drawParam(params); diff --git a/scripts/preferences/preferences.gml b/scripts/preferences/preferences.gml index d722a11bd..792435362 100644 --- a/scripts/preferences/preferences.gml +++ b/scripts/preferences/preferences.gml @@ -113,6 +113,7 @@ PREFERENCES.node_param_show = false; PREFERENCES.node_param_width = 192; + PREFERENCES.node_3d_preview_size = 256; #endregion diff --git a/scripts/quarternionBox/quarternionBox.gml b/scripts/quarternionBox/quarternionBox.gml index b33145862..ca59a1b1f 100644 --- a/scripts/quarternionBox/quarternionBox.gml +++ b/scripts/quarternionBox/quarternionBox.gml @@ -4,15 +4,27 @@ enum QUARTERNION_DISPLAY { } function quarternionBox(_onModify) : widget() constructor { - onModify = _onModify; - current_value = []; + onModify = _onModify; + current_value = [ 0, 0, 0, 0 ]; + current_unit = QUARTERNION_DISPLAY.quarterion; onModifyIndex = function(index, val) { var v = toNumber(val); - if(is_callable(onModify)) + if(current_unit == QUARTERNION_DISPLAY.quarterion) { return onModify(index, v); - return noone; + + } else { + var v = toNumber(val); + var qv = [ + current_value[0], + current_value[1], + current_value[2], + ]; + + qv[index] = v; + return onModify(noone, qv); + } } size = 4; @@ -79,8 +91,6 @@ function quarternionBox(_onModify) : widget() constructor { if(array_empty(_data)) return 0; if(is_array(_data[0])) return 0; - current_value = _data; - var _bs = min(_h, ui(32)); var _disp = struct_try_get(_display_data, "angle_display"); @@ -88,7 +98,7 @@ function quarternionBox(_onModify) : widget() constructor { var bx = _x + _w - _bs; var by = _y + _h / 2 - _bs / 2; tooltip.index = _disp; - + if(buttonInstant(THEME.button_hide, bx, by, _bs, _bs, _m, iactive, ihover, tooltip, THEME.unit_angle, _disp, c_white) == 2) { clickable = false; _display_data.angle_display = (_disp + 1) % 2; @@ -96,6 +106,17 @@ function quarternionBox(_onModify) : widget() constructor { _w -= _bs + ui(8); } + current_unit = _display_data.angle_display; + + if(current_unit == QUARTERNION_DISPLAY.quarterion || (!tb[0].sliding && !tb[1].sliding && !tb[2].sliding)) { + current_value[0] = _data[0]; + current_value[1] = _data[1]; + current_value[2] = _data[2]; + + if(current_unit == QUARTERNION_DISPLAY.quarterion) + current_value[3] = _data[3]; + } + size = _disp? 3 : 4; var ww = _w / size; var bx = _x; @@ -124,7 +145,6 @@ function quarternionBox(_onModify) : widget() constructor { static clone = function() { #region var cln = new quarternionBox(onModify); - return cln; } #endregion } \ No newline at end of file diff --git a/scripts/shell_functions/shell_functions.gml b/scripts/shell_functions/shell_functions.gml index 1626811fc..8d668a743 100644 --- a/scripts/shell_functions/shell_functions.gml +++ b/scripts/shell_functions/shell_functions.gml @@ -24,7 +24,7 @@ function shell_execute(path, command, ref = noone) { #region return res; } #endregion -function shell_execute_async(path, command, ref = noone) { #region +function shell_execute_async(path, command, ref = noone, _log = true) { #region INLINE if(IS_CMD) return shell_execute(path, command, ref); @@ -36,7 +36,7 @@ function shell_execute_async(path, command, ref = noone) { #region var txt = $"{path} {command}"; var res = ProcessExecuteAsync(txt); - print($"Execute async {path} {command} | {res}"); + if(_log) print($"Execute async {path} {command} | {res}"); return res; } #endregion diff --git a/scripts/string_functions/string_functions.gml b/scripts/string_functions/string_functions.gml index ef15a4b33..cda5628f2 100644 --- a/scripts/string_functions/string_functions.gml +++ b/scripts/string_functions/string_functions.gml @@ -65,12 +65,5 @@ function filename_name_only(name) { #region return string_replace(name, filename_ext(name), "") } #endregion -function string_to_var(str) { #region - INLINE - return string_replace_all(string_lower(str), " ", "_"); -} #endregion - -function string_quote(str) { #region - INLINE - return $"\"{str}\""; -} #endregion \ No newline at end of file +function string_to_var(str) { INLINE return string_replace_all(string_lower(str), " ", "_"); } +function string_quote(str) { INLINE return $"\"{str}\""; } \ No newline at end of file diff --git a/scripts/textBox/textBox.gml b/scripts/textBox/textBox.gml index 3fe835abd..83b5628f0 100644 --- a/scripts/textBox/textBox.gml +++ b/scripts/textBox/textBox.gml @@ -6,9 +6,9 @@ enum TEXTBOX_INPUT { function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { onRelease = noone; - align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; - hide = false; - color = COLORS._main_text; + align = _input == TEXTBOX_INPUT.number? fa_center : fa_left; + hide = false; + color = COLORS._main_text; boxColor = c_white; format = TEXT_AREA_FORMAT._default; precision = 5; @@ -497,8 +497,10 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { draw_set_alpha(1); } } - + + var _dpx = disp_x; disp_x = lerp_float(disp_x, disp_x_to, 5); + if(_dpx != disp_x) _update = true; var hoverRect = point_in_rectangle(_m[0], _m[1], _x, _y, _x + _w, _y + _h);