2024-08-29 06:14:32 +02:00
function Node_create_Export(_x, _y, _group = noone) {
2022-01-13 05:24:03 +01:00
var path = "";
2024-05-03 13:40:46 +02:00
if(NODE_NEW_MANUAL) {
2024-05-16 15:28:45 +02:00
path = get_save_filename_pxc(@"Portable Network Graphics (.png)|*.png|
2023-05-16 21:28:16 +02:00
Joint Photographic Experts Group (.jpg)|*.jpg|
Graphics Interchange Format (.gif)|*.gif|
2023-11-01 08:10:25 +01:00
Animated WebP (.webp)|*.webp|
MPEG-4 (.mp4)|*.mp4",
2023-05-16 21:28:16 +02:00
"export");
2023-02-28 09:43:01 +01:00
key_release();
2022-01-13 05:24:03 +01:00
}
2024-07-31 05:45:59 +02:00
var node = new Node_Export(_x, _y, _group).skipDefault();
2024-08-08 06:57:51 +02:00
node.inputs[1].setValue(path);
2024-05-03 13:40:46 +02:00
if(NODE_NEW_MANUAL) node.extensionCheck();
2022-01-13 05:24:03 +01:00
return node;
}
2024-12-11 03:07:22 +01:00
2023-06-17 14:30:49 +02:00
function exportAll() {
2023-11-04 13:22:52 +01:00
if(IS_RENDERING) return;
2023-11-03 14:43:28 +01:00
2024-06-08 13:31:27 +02:00
for (var i = 0, n = array_length(PROJECT.allNodes); i < n; i++) {
var node = PROJECT.allNodes[i];
2023-06-17 14:30:49 +02:00
if(!node.active) continue;
2024-02-11 14:53:33 +01:00
if(!is_instanceof(node, Node_Export)) continue;
2024-02-12 13:59:43 +01:00
2023-06-17 14:30:49 +02:00
node.doInspectorAction();
}
2024-08-29 06:14:32 +02:00
}
2023-06-17 14:30:49 +02:00
2023-01-17 08:11:55 +01:00
enum NODE_EXPORT_FORMAT {
single,
sequence,
2023-11-01 08:10:25 +01:00
animation,
2023-01-17 08:11:55 +01:00
}
2023-10-01 14:57:57 +02:00
function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
2023-05-22 20:31:55 +02:00
name = "Export";
2024-07-15 05:54:28 +02:00
preview_channel = 0;
2023-01-17 08:11:55 +01:00
2022-01-13 05:24:03 +01:00
playing = false;
played = 0;
2023-10-02 08:57:44 +02:00
_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" };
2023-05-16 21:28:16 +02:00
2024-08-18 06:16:20 +02:00
newInput(0, nodeValue_Surface("Surface", self));
2023-01-01 02:06:02 +01:00
2024-08-18 09:13:41 +02:00
newInput(1, nodeValue_Path("Paths", self, ""))
2023-05-16 21:28:16 +02:00
.setDisplay(VALUE_DISPLAY.path_save, _format_still)
2023-03-07 14:29:47 +01:00
.setVisible(true);
2022-01-13 05:24:03 +01:00
2024-08-18 09:13:41 +02:00
newInput(2, nodeValue_Text("Template", self, "%d%n"))
2023-02-14 05:32:32 +01:00
.rejectArray();
2024-08-29 06:14:32 +02:00
inputs[2].editWidget.format = TEXT_AREA_FORMAT.path_template;
inputs[2].editWidget.auto_update = true;
2022-01-13 05:24:03 +01:00
2023-02-28 09:43:01 +01:00
format_single = ["Single image", "Image sequence", "Animation"];
2024-05-02 09:48:48 +02:00
format_array = ["Multiple images", "Image sequences", "Animations"];
2023-01-01 02:06:02 +01:00
2024-08-18 09:13:41 +02:00
newInput(3, nodeValue_Enum_Scroll("Type", self, 0, { data: format_single, update_hover: false }))
2023-02-14 05:32:32 +01:00
.rejectArray();
2022-01-13 05:24:03 +01:00
2024-08-18 06:16:20 +02:00
newInput(4, nodeValue_Int("Template guides", self, 0));
2022-01-13 05:24:03 +01:00
2024-08-18 09:13:41 +02:00
newInput(5, nodeValue_Bool("Loop", self, true))
2023-02-14 05:32:32 +01:00
.setVisible(false)
.rejectArray();
2023-01-01 02:06:02 +01:00
2024-08-18 09:13:41 +02:00
newInput(6, nodeValue_Bool("Frame optimization", self, false))
2023-02-14 05:32:32 +01:00
.setVisible(false)
.rejectArray();
2023-01-01 02:06:02 +01:00
2024-08-18 09:13:41 +02:00
newInput(7, nodeValue_Float("Color merge", self, 0.02))
2023-10-02 08:57:44 +02:00
.setDisplay(VALUE_DISPLAY.slider)
2023-02-14 05:32:32 +01:00
.setVisible(false)
.rejectArray();
2023-01-01 02:06:02 +01:00
2024-08-18 09:13:41 +02:00
newInput(8, nodeValue_Int("Framerate", self, 30))
2023-02-14 05:32:32 +01:00
.rejectArray();
2022-01-13 05:24:03 +01:00
2023-02-14 05:32:32 +01:00
format_image = [ ".png", ".jpg", ".webp" ];
2023-12-15 12:56:36 +01:00
format_animation = [ ".gif", ".apng", ".webp", ".mp4" ];
2023-02-14 05:32:32 +01:00
2024-08-18 09:13:41 +02:00
newInput(9, nodeValue_Enum_Scroll("Format", self, 0, { data: format_image, update_hover: false }))
2023-02-14 05:32:32 +01:00
.rejectArray();
2024-08-18 09:13:41 +02:00
newInput(10, nodeValue_Float("Quality", self, 23))
2024-03-24 04:58:08 +01:00
.setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 100, 0.1 ] })
2023-02-14 05:32:32 +01:00
.rejectArray();
2023-02-14 11:40:24 +01:00
2024-08-18 06:16:20 +02:00
newInput(11, nodeValue_Int("Sequence begin", self, 0));
2023-03-02 07:59:14 +01:00
2024-08-18 06:16:20 +02:00
newInput(12, nodeValue_Slider_Range("Frame range", self, [0, -1], { range: [0, TOTAL_FRAMES, 0.1] }));
2023-10-01 14:57:57 +02:00
png_format = [ "INDEX4", "INDEX8", "Default (PNG32)" ];
2024-08-18 06:16:20 +02:00
newInput(13, nodeValue_Enum_Scroll("Subformat", self, 2, { data: png_format, update_hover: false }));
2023-07-11 14:18:23 +02:00
2024-08-18 06:16:20 +02:00
newInput(14, nodeValue_Int("Frame step", self, 1));
2023-10-31 13:33:36 +01:00
2024-08-18 09:13:41 +02:00
newInput(15, nodeValue_Bool("Custom Range", self, false))
2024-01-19 09:33:37 +01:00
.rejectArray();
2024-05-11 14:36:19 +02:00
2024-08-18 09:13:41 +02:00
newInput(16, nodeValue_Bool("Export on Save", self, false))
2024-05-11 14:36:19 +02:00
2024-09-04 03:57:11 +02:00
newOutput(0, nodeValue_Output("Preview", self, VALUE_TYPE.surface, noone));
2023-02-28 09:43:01 +01:00
2023-08-13 13:10:20 +02:00
template_guide = [
2024-08-30 03:59:20 +02:00
["%d", "Directory"],
["%1d", "Goes up 1 level"],
["%n", "File name"],
["%f", "Frame"],
["%i", "Array index"],
["%{i+1}", "Array index + 1"],
2023-08-13 13:10:20 +02:00
];
2024-08-29 06:14:32 +02:00
export_template = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) {
2024-09-13 09:43:09 +02:00
2023-08-13 13:10:20 +02:00
var _tx = _x + ui(10);
var _ty = _y;
var _tw = _w - ui(8);
2023-10-02 08:57:44 +02:00
var rawpath = getInputData(1);
2024-03-31 05:36:11 +02:00
if(is_array(rawpath)) rawpath = array_safe_get_fast(rawpath, 0, "");
2023-08-13 13:10:20 +02:00
2023-10-02 08:57:44 +02:00
var _ext = getInputData(9);
2023-08-13 13:10:20 +02:00
var path = pathString(rawpath);
var pathA = pathString(rawpath,, true);
2024-08-08 06:57:51 +02:00
path = string_replace(path, ".png", array_safe_get_fast(inputs[ 9].display_data.data, _ext, ""));
2023-08-13 13:10:20 +02:00
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;
2024-09-13 09:43:09 +02:00
case "ext" : draw_set_color(COLORS._main_text_sub); break;
2023-08-13 13:10:20 +02:00
}
_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);
2024-09-13 09:43:09 +02:00
var hh = _th + ui(16 + 20 * array_length(template_guide));
2023-08-13 13:10:20 +02:00
var _cy = _y + _th + ui(8);
2024-09-13 09:43:09 +02:00
2023-08-13 13:10:20 +02:00
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;
2024-08-29 06:14:32 +02:00
});
2023-08-13 13:10:20 +02:00
2022-01-13 05:24:03 +01:00
input_display_list = [
2024-05-11 14:36:19 +02:00
["Export", false], 0, 1, 2, export_template, 16,
2024-01-19 09:33:37 +01:00
["Format", false], 3, 9, 6, 7, 10, 13,
["Custom Range", true, 15], 12,
["Animation", false], 8, 5, 11, 14,
2022-01-13 05:24:03 +01:00
];
2023-11-04 13:22:52 +01:00
render_process_id = 0;
2023-11-03 14:43:28 +01:00
render_type = "";
render_target = "";
2024-05-11 14:36:19 +02:00
exportLog = true;
2023-11-03 14:43:28 +01:00
2023-11-01 08:10:25 +01:00
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";
2023-12-15 12:56:36 +01:00
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.");
2024-08-29 06:14:32 +02:00
2023-12-15 12:56:36 +01:00
} 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";
}
2023-05-28 20:00:51 +02:00
2024-08-29 06:14:32 +02:00
static onValueUpdate = function(_index) {
2023-10-02 08:57:44 +02:00
var form = getInputData(3);
2022-01-13 05:24:03 +01:00
2023-05-16 21:28:16 +02:00
if(_index == 3) {
2024-08-08 06:57:51 +02:00
if(NOT_LOAD) inputs[9].setValue(0);
2023-05-16 21:28:16 +02:00
switch(form) {
case 0 :
case 1 :
2024-08-08 06:57:51 +02:00
inputs[1].display_data = _format_still;
2023-05-16 21:28:16 +02:00
break;
case 2 :
2024-08-08 06:57:51 +02:00
inputs[1].display_data = _format_anim;
2023-05-16 21:28:16 +02:00
break;
}
}
2023-02-14 05:32:32 +01:00
2023-11-01 08:10:25 +01:00
if(NOT_LOAD && _index == 3 && form == 1)
2024-08-08 06:57:51 +02:00
inputs[2].setValue("%d%n%3f%i");
2023-05-16 21:28:16 +02:00
2023-11-01 08:10:25 +01:00
if(NOT_LOAD && _index == 1) {
2023-10-02 08:57:44 +02:00
var _path = getInputData(1);
2023-05-16 21:28:16 +02:00
var _ext = filename_ext(_path);
switch(_ext) {
2024-08-08 06:57:51 +02:00
case ".png" : inputs[9].setValue(0); break;
case ".jpg" : inputs[9].setValue(1); break;
2023-05-16 21:28:16 +02:00
2024-08-08 06:57:51 +02:00
case ".gif" : inputs[9].setValue(0); break;
case ".webp" : inputs[9].setValue(1); break;
2023-05-16 21:28:16 +02:00
}
}
2024-08-29 06:14:32 +02:00
}
2023-05-16 21:28:16 +02:00
2024-08-29 06:14:32 +02:00
static extensionCheck = function() {
2023-10-02 08:57:44 +02:00
var _path = getInputData(1);
2023-05-16 21:28:16 +02:00
var _ext = filename_ext(_path);
switch(_ext) {
case ".png" :
2024-08-08 06:57:51 +02:00
inputs[3].setValue(0);
inputs[9].setValue(0);
2023-05-16 21:28:16 +02:00
break;
case ".jpg" :
2024-08-08 06:57:51 +02:00
inputs[3].setValue(0);
inputs[9].setValue(1);
2023-05-16 21:28:16 +02:00
break;
case ".gif" :
2024-08-08 06:57:51 +02:00
inputs[3].setValue(2);
inputs[9].setValue(0);
2023-05-16 21:28:16 +02:00
break;
case ".webp" :
2024-08-08 06:57:51 +02:00
inputs[3].setValue(2);
inputs[9].setValue(1);
2023-05-16 21:28:16 +02:00
break;
}
2024-08-29 06:14:32 +02:00
}
2023-02-14 05:32:32 +01:00
2024-08-29 06:14:32 +02:00
static renderWebp = function(temp_path, target_path) {
2024-05-01 14:28:15 +02:00
var _path = file_find_first(temp_path + "*.png", 0);
2023-02-14 05:32:32 +01:00
var frames = [];
while(_path != "") {
2024-11-02 05:10:04 +01:00
var _frame = string_quote(temp_path + string_replace_all(_path, ".png", "") + ".webp");
2023-11-03 14:43:28 +01:00
var _pathTemp = string_quote(temp_path + _path);
2024-10-21 04:36:08 +02:00
var shell_cmd = $"{_pathTemp} -define webp:lossless=true {_frame}";
2023-02-14 05:32:32 +01:00
array_push(frames, _frame);
2024-10-21 04:36:08 +02:00
shell_execute(magick, shell_cmd, self, false);
2023-11-03 14:43:28 +01:00
2023-02-14 05:32:32 +01:00
_path = file_find_next();
}
2023-10-02 08:57:44 +02:00
var rate = getInputData(8);
2023-05-16 21:28:16 +02:00
if(rate == 0) rate = 1;
2023-02-14 05:32:32 +01:00
var framerate = round(1 / rate * 1000);
var cmd = "";
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(frames); i < n; i++ )
2024-05-01 14:28:15 +02:00
cmd += $"-frame {frames[i]} +{framerate}+0+0+1 ";
2023-02-14 05:32:32 +01:00
cmd += "-bgcolor 0,0,0,0 ";
2023-11-03 14:43:28 +01:00
cmd += "-o " + string_quote(target_path);
2022-01-13 05:24:03 +01:00
2023-11-03 14:43:28 +01:00
render_process_id = shell_execute_async(webp, cmd, self);
render_type = "webp";
render_target = target_path;
2024-08-29 06:14:32 +02:00
}
2022-01-13 05:24:03 +01:00
2024-08-29 06:14:32 +02:00
static renderGif = function(temp_path, target_path) {
2023-10-02 08:57:44 +02:00
var loop = getInputData( 5);
var opti = getInputData( 6);
var fuzz = getInputData( 7);
2024-05-07 06:53:51 +02:00
var rate = max(1, getInputData( 8));
2023-10-02 08:57:44 +02:00
var qual = getInputData(10);
2022-05-17 14:39:12 +02:00
2024-05-01 14:28:15 +02:00
temp_path = string_replace_all(temp_path, "/", "\\");
2023-05-28 20:00:51 +02:00
target_path = string_replace_all(target_path, "/", "\\");
2024-05-01 14:28:15 +02:00
2023-05-28 20:00:51 +02:00
var framerate = 100 / rate;
var loop_str = loop? 0 : 1;
var use_gifski = false;
2022-01-13 05:24:03 +01:00
2024-02-03 13:11:50 +01:00
var shell_cmd = $"-delay {framerate} -alpha set -dispose 2 -loop {loop_str}";
2023-12-15 12:56:36 +01:00
if(opti) shell_cmd += $" -fuzz {fuzz * 100}% -layers OptimizeFrame -layers OptimizeTransparency";
shell_cmd += $" {string_quote(temp_path)} {string_quote(target_path)}";
2023-05-28 20:00:51 +02:00
2023-12-15 12:56:36 +01:00
render_process_id = shell_execute_async(converter, shell_cmd, self);
2023-11-03 14:43:28 +01:00
render_type = "gif";
render_target = target_path;
2024-08-29 06:14:32 +02:00
}
2023-11-01 08:10:25 +01:00
2024-08-29 06:14:32 +02:00
static renderMp4 = function(temp_path, target_path) {
2023-11-01 08:10:25 +01:00
var rate = getInputData( 8);
2023-12-15 12:56:36 +01:00
var qual = getInputData(10); qual = clamp(qual, 0, 51);
2023-11-01 08:10:25 +01:00
if(rate == 0) rate = 1;
2023-12-08 03:50:09 +01:00
if(file_exists_empty(target_path)) file_delete(target_path);
2023-11-01 08:10:25 +01:00
temp_path = string_replace_all(temp_path, "/", "\\");
2024-05-05 13:29:06 +02:00
temp_path = string_trim(temp_path, ["*.png"]) + "%05d.png";
2023-11-01 08:10:25 +01:00
target_path = string_replace_all(target_path, "/", "\\");
2024-05-05 13:29:06 +02:00
var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}\" -c:v libx264 -r {rate} -pix_fmt yuv420p -crf {qual} {string_quote(target_path)}";
2023-11-01 08:10:25 +01:00
2023-11-03 14:43:28 +01:00
render_process_id = shell_execute_async(ffmpeg, shell_cmd, self);
render_type = "mp4";
render_target = target_path;
2024-08-29 06:14:32 +02:00
}
2023-12-15 12:56:36 +01:00
2024-08-29 06:14:32 +02:00
static renderApng = function(temp_path, target_path) {
2023-12-15 12:56:36 +01:00
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, "/", "\\");
2024-05-05 13:29:06 +02:00
temp_path = string_trim(temp_path, ["*.png"]) + "%05d.png";
2023-12-15 12:56:36 +01:00
target_path = string_replace_all(target_path, "/", "\\");
2024-05-05 13:29:06 +02:00
var shell_cmd = $"-hide_banner -loglevel quiet -framerate {rate} -i \"{temp_path}\" -plays 0 {string_quote(target_path)}";
2023-12-15 12:56:36 +01:00
render_process_id = shell_execute_async(ffmpeg, shell_cmd, self);
render_type = "apng";
render_target = target_path;
2024-08-29 06:14:32 +02:00
}
2022-01-13 05:24:03 +01:00
2024-08-29 06:14:32 +02:00
static pathString = function(path, index = 0, _array = false) {
2023-10-02 08:57:44 +02:00
var suff = getInputData( 2);
var form = getInputData( 3);
var strt = getInputData(11);
2022-01-13 05:24:03 +01:00
2023-08-13 13:10:20 +02:00
path = string_replace_all(path, "\\", "/");
var s = _array? [] : "";
var i = 1;
2022-01-13 05:24:03 +01:00
var len = string_length(suff);
2024-08-29 06:14:32 +02:00
var ch, cmd, cmx, par, eli, val, _txt;
2023-08-13 13:10:20 +02:00
2022-01-13 05:24:03 +01:00
while(i <= len) {
ch = string_char_at(suff, i);
if(ch == "%") {
i++;
2024-08-29 06:14:32 +02:00
par = "";
cmd = "";
cmx = "";
_txt = "";
eli = 0;
val = 0;
2022-01-13 05:24:03 +01:00
do {
2024-08-29 06:14:32 +02:00
var _rawc = string_char_at(suff, i++);
if(_rawc == "{") eli++;
else if(_rawc == "}") {
eli--;
if(eli == 0) {
cmx = string_trim(cmx, ["{", "}"]);
cmd = string_letters(cmx);
2022-01-13 05:24:03 +01:00
break;
2024-08-29 06:14:32 +02:00
}
}
if(eli) {
cmx += _rawc;
} else {
if(string_letters(_rawc) == "")
par += _rawc;
else {
cmd = _rawc;
2022-01-13 05:24:03 +01:00
break;
2024-08-29 06:14:32 +02:00
}
}
} until(i > len);
par = toNumber(par);
switch(cmd) {
case "f" :
case "i" :
switch(cmd) {
case "f": val = CURRENT_FRAME + 1 + strt; break;
case "i": val = index; break;
}
if(cmx != "") {
cmx = string_replace_all(cmx, "f", string(CURRENT_FRAME + 1 + strt));
cmx = string_replace_all(cmx, "i", string(index));
2023-08-13 13:10:20 +02:00
2024-08-29 06:14:32 +02:00
val = evaluateFunction(cmx);
}
val = string(val);
if(par) {
var str_val = max(par - string_length(val), 0);
repeat(str_val) _txt += "0";
}
_txt += val;
if(_array) array_push(s, [ cmd, _txt ]);
else s += _txt;
break;
case "d" :
var dir = filename_dir(path) + "/";
if(par) {
var dir_s = "";
var sep = string_splice(dir, "/");
2023-08-13 13:10:20 +02:00
2024-08-29 06:14:32 +02:00
for(var j = 0; j < array_length(sep) - par; j++)
dir_s += sep[j] + "/";
_txt += dir_s;
} else
_txt += dir;
if(_array) array_push(s, [ "d", _txt ]);
else s += _txt;
break;
case "n" :
_txt = filename_name_only(path);
2022-01-13 05:24:03 +01:00
2024-08-29 06:14:32 +02:00
if(_array) array_push(s, [ "n", _txt ]);
else s += _txt;
break;
}
2022-01-13 05:24:03 +01:00
} else {
2023-08-13 13:10:20 +02:00
if(_array) array_push(s, ch);
else s += ch;
2022-01-13 05:24:03 +01:00
i++;
}
}
2023-10-02 08:57:44 +02:00
var _e = getInputData(9);
2024-08-08 06:57:51 +02:00
var _ext = array_safe_get_fast(inputs[9].display_data.data, _e, ".png");
2023-09-26 14:35:25 +02:00
if(_array) array_push(s, ["ext", _ext]);
else s += _ext;
2022-01-13 05:24:03 +01:00
return s;
2024-08-29 06:14:32 +02:00
}
2022-01-13 05:24:03 +01:00
2024-08-29 06:14:32 +02:00
static save_surface = function(_surf, _path) {
2023-10-02 08:57:44 +02:00
var form = getInputData(3);
2024-06-20 13:22:21 +02:00
// print($">>>>>>>>>>>>>>>>>>>> save surface {_surf} - {_path} <<<<<<<<<<<<<<<<<<<<");
2023-02-14 05:32:32 +01:00
2023-11-01 08:10:25 +01:00
if(form == NODE_EXPORT_FORMAT.animation) {
2023-03-19 09:17:39 +01:00
surface_save_safe(_surf, _path);
2023-02-14 05:32:32 +01:00
return _path;
}
2023-10-02 08:57:44 +02:00
var extd = getInputData( 9);
var qual = getInputData(10);
var indx = getInputData(13);
2024-03-31 05:36:11 +02:00
var ext = array_safe_get_fast(format_image, extd, ".png");
2023-02-14 05:32:32 +01:00
2023-04-10 20:02:59 +02:00
var _pathOut = _path;
2023-10-01 14:57:57 +02:00
var _pathTemp = $"{directory}/{irandom_range(10000, 99999)}.png";
2023-02-14 05:32:32 +01:00
switch(ext) {
case ".png":
2023-10-10 10:40:36 +02:00
switch(indx) {
case 0 :
surface_save_safe(_surf, _pathTemp);
2023-10-01 14:57:57 +02:00
2023-11-03 14:43:28 +01:00
var shell_cmd = $"convert {string_quote(_pathTemp)} {string_quote(_pathOut)}";
shell_execute_async(magick, shell_cmd, self);
2023-10-10 10:40:36 +02:00
break;
case 1 :
surface_save_safe(_surf, _pathTemp);
2023-10-01 14:57:57 +02:00
2023-11-03 14:43:28 +01:00
var shell_cmd = $"convert {string_quote(_pathTemp)} PNG8:{string_quote(_pathOut)}";
shell_execute_async(magick, shell_cmd, self);
2023-10-10 10:40:36 +02:00
break;
case 2 :
surface_save_safe(_surf, _pathOut);
break;
2023-10-01 14:57:57 +02:00
}
2023-02-14 05:32:32 +01:00
break;
2023-04-10 20:02:59 +02:00
2023-02-14 05:32:32 +01:00
case ".jpg":
2023-03-19 09:17:39 +01:00
surface_save_safe(_surf, _pathTemp);
2023-10-01 14:57:57 +02:00
_pathOut = $"\"{string_replace_all(_path, ".png", "")}.jpg\"";
2023-11-03 14:43:28 +01:00
var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} {string_quote(_pathOut)}";
2023-02-14 05:32:32 +01:00
2023-11-03 14:43:28 +01:00
shell_execute_async(magick, shell_cmd, self);
2023-02-14 05:32:32 +01:00
break;
2023-04-10 20:02:59 +02:00
2023-10-01 14:57:57 +02:00
case ".webp":
2023-03-19 09:17:39 +01:00
surface_save_safe(_surf, _pathTemp);
2023-02-14 05:32:32 +01:00
2023-10-01 14:57:57 +02:00
_pathOut = $"\"{string_replace_all(_path, ".png", "")}.webp\"";
2023-11-03 14:43:28 +01:00
var shell_cmd = $"{string_quote(_pathTemp)} -quality {qual} -define webp:lossless=true {string_quote(_pathOut)}";
2023-02-14 05:32:32 +01:00
2023-11-03 14:43:28 +01:00
shell_execute_async(magick, shell_cmd, self);
2023-02-14 05:32:32 +01:00
break;
}
return _pathOut;
2024-08-29 06:14:32 +02:00
}
2023-02-14 05:32:32 +01:00
2024-08-29 06:14:32 +02:00
static export = function(log = true) {
2024-06-20 13:22:21 +02:00
// print($">>>>>>>>>>>>>>>>>>>> export {CURRENT_FRAME} <<<<<<<<<<<<<<<<<<<<");
2024-02-12 13:59:43 +01:00
2024-11-02 05:10:04 +01:00
randomize();
2024-05-11 14:36:19 +02:00
exportLog = log;
2023-10-02 08:57:44 +02:00
var surf = getInputData( 0);
var path = getInputData( 1);
var suff = getInputData( 2);
var form = getInputData( 3);
var rang = getInputData(12);
2023-10-31 13:33:36 +01:00
var stps = getInputData(14);
2024-01-19 09:33:37 +01:00
var user = getInputData(15);
2022-01-13 05:24:03 +01:00
2024-01-19 09:33:37 +01:00
if(form >= 1 && user) {
2023-10-31 13:33:36 +01:00
var rng_s = rang[0];
2024-01-19 09:33:37 +01:00
var rng_e = rang[1];
2023-10-31 13:33:36 +01:00
var rng_st = stps >= 1? (CURRENT_FRAME - rng_s) % stps : 0;
2023-07-11 14:18:23 +02:00
2024-01-19 09:33:37 +01:00
if(CURRENT_FRAME < rng_s - 1) return;
if(CURRENT_FRAME > rng_e - 1) return;
2023-10-31 13:33:36 +01:00
if(rng_st != 0) return;
2023-07-11 14:18:23 +02:00
}
2022-01-13 05:24:03 +01:00
if(is_array(surf)) {
2023-01-17 08:11:55 +01:00
var p = "";
2022-01-13 05:24:03 +01:00
for(var i = 0; i < array_length(surf); i++) {
var _surf = surf[i];
2022-09-21 06:09:40 +02:00
if(!is_surface(_surf)) continue;
2023-11-01 08:10:25 +01:00
if(form == NODE_EXPORT_FORMAT.animation) {
2023-10-31 13:33:36 +01:00
p = $"{directory}/{i}/{string_lead_zero(CURRENT_FRAME, 5)}.png";
2023-02-14 05:32:32 +01:00
} else {
2022-09-21 06:09:40 +02:00
if(is_array(path) && array_length(path) == array_length(surf))
2024-03-31 05:36:11 +02:00
p = pathString(array_safe_get_fast(path, i), i);
2022-09-21 06:09:40 +02:00
else
2023-08-13 13:10:20 +02:00
p = pathString(path, i);
2024-02-15 14:23:26 +01:00
CLI_EXPORT_AMOUNT++;
2022-01-13 05:24:03 +01:00
}
2022-09-21 06:09:40 +02:00
2023-02-14 05:32:32 +01:00
p = save_surface(_surf, p);
2022-01-13 05:24:03 +01:00
}
2023-01-17 08:11:55 +01:00
2024-05-11 14:36:19 +02:00
if(exportLog && form != NODE_EXPORT_FORMAT.animation && !IS_CMD) {
2024-06-26 06:38:57 +02:00
var _txt = $"Export {array_length(surf)} images complete.";
logNode(_txt);
var noti = log_message("EXPORT", _txt, THEME.noti_icon_tick, COLORS._main_value_positive, false);
2023-01-17 08:11:55 +01:00
noti.path = filename_dir(p);
noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer);
2022-01-13 05:24:03 +01:00
2023-01-17 08:11:55 +01:00
PANEL_MENU.setNotiIcon(THEME.noti_icon_tick);
}
2024-06-20 13:22:21 +02:00
2023-01-17 08:11:55 +01:00
} else if(is_surface(surf)) {
var p = path;
if(is_array(path)) p = path[0];
2022-01-13 05:24:03 +01:00
2024-02-15 14:23:26 +01:00
if(form == NODE_EXPORT_FORMAT.animation) {
2023-10-31 13:33:36 +01:00
p = $"{directory}/{string_lead_zero(CURRENT_FRAME, 5)}.png";
2024-02-15 14:23:26 +01:00
} else {
2023-08-13 13:10:20 +02:00
p = pathString(p);
2024-02-15 14:23:26 +01:00
CLI_EXPORT_AMOUNT++;
}
2023-01-17 08:11:55 +01:00
2023-02-14 05:32:32 +01:00
p = save_surface(surf, p);
2024-02-15 14:23:26 +01:00
2024-05-11 14:36:19 +02:00
if(exportLog && form != NODE_EXPORT_FORMAT.animation && !IS_CMD) {
2024-06-26 06:38:57 +02:00
var _txt = $"Export image as {p}";
logNode(_txt);
var noti = log_message("EXPORT", _txt, THEME.noti_icon_tick, COLORS._main_value_positive, false);
2023-01-17 08:11:55 +01:00
noti.path = filename_dir(p);
noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer);
2022-12-22 03:09:55 +01:00
2023-01-17 08:11:55 +01:00
PANEL_MENU.setNotiIcon(THEME.noti_icon_tick);
}
2022-01-13 05:24:03 +01:00
}
2024-06-20 13:22:21 +02:00
// print($">>>>>>>>>>>>>>>>>>>> export {CURRENT_FRAME} complete <<<<<<<<<<<<<<<<<<<<");
2024-08-29 06:14:32 +02:00
}
2022-01-13 05:24:03 +01:00
2024-08-29 06:14:32 +02:00
static renderCompleted = function() {
2023-10-31 13:33:36 +01:00
var surf = getInputData( 0);
var path = getInputData( 1);
var suff = getInputData( 2);
var extd = getInputData( 9);
var temp_path, target_path;
2023-11-04 13:22:52 +01:00
update_on_frame = false;
2023-10-31 13:33:36 +01:00
if(is_array(surf)) {
for(var i = 0; i < array_length(surf); i++) {
temp_path = $"{directory}/{i}/*.png";
2024-03-31 05:36:11 +02:00
if(is_array(path)) target_path = pathString(array_safe_get_fast(path, i), i);
2023-10-31 13:33:36 +01:00
else target_path = pathString(path, i);
2023-12-15 12:56:36 +01:00
switch(format_animation[extd]) {
case ".gif" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".gif");
2023-11-03 14:43:28 +01:00
renderGif(temp_path, target_path);
2023-11-01 08:10:25 +01:00
break;
2023-12-15 12:56:36 +01:00
case ".webp" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".webp");
renderWebp(temp_path, target_path);
break;
2023-12-15 12:56:36 +01:00
case ".mp4" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".mp4");
renderMp4(temp_path, target_path);
break;
2023-12-15 12:56:36 +01:00
case ".apng" :
target_path = string_replace(target_path, ".png", ".apng");
renderApng(temp_path, target_path);
break;
2023-10-31 13:33:36 +01:00
}
}
} else {
target_path = pathString(path);
2023-12-15 12:56:36 +01:00
switch(format_animation[extd]) {
case ".gif" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".gif");
2023-11-03 14:43:28 +01:00
renderGif(directory + "/*.png", target_path);
2023-11-01 08:10:25 +01:00
break;
2023-12-15 12:56:36 +01:00
case ".webp" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".webp");
renderWebp(directory + "/", target_path);
break;
2023-12-15 12:56:36 +01:00
case ".mp4" :
2023-11-01 08:10:25 +01:00
target_path = string_replace(target_path, ".png", ".mp4");
renderMp4(directory + "/", target_path);
break;
2023-12-15 12:56:36 +01:00
case ".apng" :
target_path = string_replace(target_path, ".png", ".apng");
renderApng(directory + "/", target_path);
break;
2023-10-31 13:33:36 +01:00
}
}
updatedOutTrigger.setValue(true);
2024-02-15 14:23:26 +01:00
CLI_EXPORT_AMOUNT++;
2024-08-29 06:14:32 +02:00
}
2023-10-31 13:33:36 +01:00
2024-11-26 05:52:57 +01:00
setTrigger(1, "Export", [ THEME.sequence_control, 1, COLORS._main_value_positive ], function(_fromValue = false) /*=>*/ {
2023-11-04 13:22:52 +01:00
if(IS_RENDERING) return;
2023-11-03 14:43:28 +01:00
2024-06-20 13:22:21 +02:00
if(_fromValue) {
export();
return;
}
2023-10-02 10:45:30 +02:00
if(isInLoop()) RENDER_ALL
2023-02-14 13:44:46 +01:00
else doInspectorAction();
2024-11-26 05:52:57 +01:00
});
2023-02-14 05:32:32 +01:00
2024-11-26 05:52:57 +01:00
setTrigger(2, "Export All", [ THEME.play_all, 0, COLORS._main_value_positive ], function() /*=>*/ {
2023-11-04 13:22:52 +01:00
if(IS_RENDERING) return;
2023-11-03 14:43:28 +01:00
exportAll();
2024-11-26 05:52:57 +01:00
});
2023-02-14 05:32:32 +01:00
2024-08-29 06:14:32 +02:00
static doInspectorAction = function() {
2024-02-15 14:23:26 +01:00
if(!IS_CMD && (LOADING || APPENDING)) return;
2024-11-04 06:08:06 +01:00
directory = $"{TEMPDIR}{irandom_range(100000, 999999)}";
2022-01-26 13:02:30 +01:00
2023-10-02 08:57:44 +02:00
var path = getInputData(1);
2022-01-13 05:24:03 +01:00
if(path == "") return;
2023-10-02 08:57:44 +02:00
var form = getInputData(3);
2022-01-13 05:24:03 +01:00
2023-01-17 08:11:55 +01:00
if(form == NODE_EXPORT_FORMAT.single) {
2023-06-17 14:30:49 +02:00
Render();
2022-01-13 05:24:03 +01:00
export();
2023-10-06 11:51:11 +02:00
updatedOutTrigger.setValue(true);
2023-01-17 08:11:55 +01:00
return;
}
2023-11-04 13:22:52 +01:00
update_on_frame = true;
playing = true;
played = 0;
2024-01-19 09:33:37 +01:00
PROJECT.animator.render();
2023-01-17 08:11:55 +01:00
2024-02-12 13:59:43 +01:00
if(IS_CMD) array_push(PROGRAM_ARGUMENTS._exporting, node_id);
2023-02-14 05:32:32 +01:00
if(directory_exists(directory))
directory_destroy(directory);
directory_create(directory);
2024-08-29 06:14:32 +02:00
}
2022-12-23 04:45:52 +01:00
2024-08-29 06:14:32 +02:00
static step = function() {
2023-11-04 13:22:52 +01:00
insp1UpdateActive = !IS_RENDERING;
insp2UpdateActive = !IS_RENDERING;
2024-05-11 14:36:19 +02:00
2023-10-02 08:57:44 +02:00
var surf = getInputData( 0);
var pngf = getInputData(13);
2024-05-15 12:42:54 +02:00
var expo = getInputData(16);
2023-10-01 14:57:57 +02:00
2023-02-14 05:32:32 +01:00
if(is_array(surf)) {
2024-08-08 06:57:51 +02:00
inputs[3].display_data.data = format_array;
inputs[3].editWidget.data_list = format_array;
2023-02-14 05:32:32 +01:00
} else {
2024-08-08 06:57:51 +02:00
inputs[3].display_data.data = format_single;
inputs[3].editWidget.data_list = format_single;
2023-02-14 05:32:32 +01:00
}
2022-12-23 04:45:52 +01:00
2024-08-08 06:57:51 +02:00
outputs[0].setValue(surf);
2023-02-28 09:43:01 +01:00
2023-10-02 08:57:44 +02:00
var anim = getInputData(3); // single, sequence, animation
var extn = getInputData(9);
2024-01-19 09:33:37 +01:00
var user = getInputData(15);
2023-02-14 05:32:32 +01:00
2024-05-15 12:42:54 +02:00
if(expo && anim == NODE_EXPORT_FORMAT.single && IS_SAVING)
doInspectorAction();
2024-08-08 06:57:51 +02:00
inputs[11].setVisible(anim == 1);
inputs[16].setVisible(anim == 0);
2024-01-19 09:33:37 +01:00
2024-08-08 06:57:51 +02:00
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);
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[14].setVisible(anim > 0);
2023-02-14 05:32:32 +01:00
2023-11-01 08:10:25 +01:00
if(anim == NODE_EXPORT_FORMAT.animation) {
2024-03-31 05:36:11 +02:00
var _fmt = array_safe_get_fast(format_animation, extn);
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[ 5].setVisible(_fmt == ".gif");
inputs[ 6].setVisible(_fmt == ".gif");
inputs[ 7].setVisible(_fmt == ".gif");
inputs[ 8].setVisible(true);
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[ 9].display_data.data = format_animation;
inputs[ 9].editWidget.data_list = format_animation;
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[13].setVisible(false);
2023-12-15 12:56:36 +01:00
if(_fmt == ".mp4") {
2024-08-08 06:57:51 +02:00
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.";
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[10].setVisible(true);
inputs[10].editWidget.minn = 0;
inputs[10].editWidget.maxx = 51;
2023-12-15 12:56:36 +01:00
} else
2024-08-08 06:57:51 +02:00
inputs[10].setVisible(false);
2023-02-14 05:32:32 +01:00
} else {
2024-03-31 05:36:11 +02:00
var _fmt = array_safe_get_fast(format_image, extn);
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[ 5].setVisible(false);
inputs[ 6].setVisible(false);
inputs[ 7].setVisible(false);
inputs[ 8].setVisible(false);
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[ 9].display_data.data = format_image;
inputs[ 9].editWidget.data_list = format_image;
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[13].setVisible(_fmt == ".png");
2023-12-15 12:56:36 +01:00
if(_fmt == ".jpg" || _fmt == ".webp") {
2024-08-08 06:57:51 +02:00
inputs[10].setName("Quality");
inputs[10].tooltip = "Quality of the output.";
2023-12-15 12:56:36 +01:00
2024-08-08 06:57:51 +02:00
inputs[10].setVisible(true);
inputs[10].editWidget.minn = 0;
inputs[10].editWidget.maxx = 100;
2023-12-15 12:56:36 +01:00
} else
2024-08-08 06:57:51 +02:00
inputs[10].setVisible(false);
2023-02-14 05:32:32 +01:00
}
2023-02-14 11:40:24 +01:00
2023-11-04 13:22:52 +01:00
if(render_process_id != 0) {
2023-11-03 14:43:28 +01:00
var res = ProcIdExists(render_process_id);
2023-11-21 11:54:45 +01:00
2023-12-15 12:56:36 +01:00
if(res == 0 || OS == os_macosx) {
2024-02-12 10:25:23 +01:00
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);
}
2023-11-04 13:22:52 +01:00
render_process_id = 0;
2024-02-12 13:59:43 +01:00
if(IS_CMD) array_remove(PROGRAM_ARGUMENTS._exporting, node_id);
2023-11-03 14:43:28 +01:00
}
}
2024-08-29 06:14:32 +02:00
}
2023-02-14 05:32:32 +01:00
2024-08-29 06:14:32 +02:00
static update = function(frame = CURRENT_FRAME) {
2023-10-02 08:57:44 +02:00
var anim = getInputData(3);
2024-05-11 14:36:19 +02:00
2023-02-14 11:40:24 +01:00
if(anim == NODE_EXPORT_FORMAT.single) {
2024-05-15 12:42:54 +02:00
if(isInLoop()) export(false);
2023-02-14 11:40:24 +01:00
return;
}
2022-12-23 04:45:52 +01:00
2023-07-06 19:49:16 +02:00
if(!PROJECT.animator.is_playing) {
2022-12-23 04:45:52 +01:00
playing = false;
return;
}
2023-11-04 13:22:52 +01:00
if(!playing) return;
2023-03-12 02:28:21 +01:00
2022-12-23 04:45:52 +01:00
export();
2023-02-19 02:13:19 +01:00
2024-01-19 09:33:37 +01:00
if(IS_LAST_FRAME && anim == NODE_EXPORT_FORMAT.animation)
renderCompleted();
2024-08-29 06:14:32 +02:00
}
2023-05-16 21:28:16 +02:00
2024-08-29 06:14:32 +02:00
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
2023-11-03 14:43:28 +01:00
graph_preview_alpha = 1;
2023-11-04 13:22:52 +01:00
if(render_process_id != 0) {
2023-11-03 14:43:28 +01:00
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);
}
2024-08-29 06:14:32 +02:00
}
2023-11-03 14:43:28 +01:00
2024-11-12 05:39:37 +01:00
static postApplyDeserialize = function() { onValueUpdate(3); }
2022-01-13 05:24:03 +01:00
}