mirror of
https://github.com/Ttanasart-pt/Pixel-Composer.git
synced 2025-02-03 16:55:14 +01:00
- [Gif, Image animation] Add properties parity (animation speed, loop modes) and custom frame order mode.
This commit is contained in:
parent
69d7cd73de
commit
f7c119a77b
6 changed files with 12929 additions and 12803 deletions
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -105,10 +105,10 @@
|
|||
|
||||
globalvar VERSION, SAVE_VERSION, VERSION_STRING, BUILD_NUMBER;
|
||||
|
||||
VERSION = 11531;
|
||||
VERSION = 11540;
|
||||
SAVE_VERSION = 11530;
|
||||
VERSION_STRING = "1.15.3.1";
|
||||
BUILD_NUMBER = 11531;
|
||||
VERSION_STRING = "1.15.4";
|
||||
BUILD_NUMBER = 11540;
|
||||
|
||||
globalvar APPEND_MAP;
|
||||
APPEND_MAP = ds_map_create();
|
||||
|
|
|
@ -105,10 +105,15 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
.setDisplay(VALUE_DISPLAY.slider, [0, 100, 1])
|
||||
.rejectArray();
|
||||
|
||||
inputs[| 11] = nodeValue("Sequence begin", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
|
||||
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, [0, PROJECT.animator.frames_total, 1])
|
||||
.setDisplay(VALUE_DISPLAY.slider_range, [0, PROJECT.animator.frames_total, 1]);
|
||||
|
||||
png_format = [ "INDEX4", "INDEX8", "Default (PNG32)" ];
|
||||
png_format_r = [ "PNG4", "PNG8" ];
|
||||
inputs[| 13] = nodeValue("Subformat", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 4)
|
||||
.setDisplay(VALUE_DISPLAY.enum_scroll, png_format, { update_hover: false });
|
||||
|
||||
outputs[| 0] = nodeValue("Loop exit", self, JUNCTION_CONNECT.output, VALUE_TYPE.any, 0);
|
||||
|
||||
|
@ -196,7 +201,8 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
input_display_list = [
|
||||
["Export", false], 0, 1, 2, export_template,
|
||||
["Format ", false], 3, 9,
|
||||
["Settings", false], 12, 8, 5, 6, 7, 10, 11,
|
||||
["Animation", false], 12, 8, 5, 11,
|
||||
["Quality", false], 6, 7, 10, 13,
|
||||
];
|
||||
|
||||
directory = DIRECTORY + "temp/" + string(irandom_range(100000, 999999));
|
||||
|
@ -448,22 +454,34 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
|
||||
var extd = inputs[| 9].getValue();
|
||||
var qual = inputs[| 10].getValue();
|
||||
var indx = inputs[| 13].getValue();
|
||||
var ext = array_safe_get(format_image, extd, ".png");
|
||||
|
||||
var _pathOut = _path;
|
||||
var _pathTemp = directory + "/" + string(irandom_range(10000, 99999)) + ".png";
|
||||
var _pathTemp = $"{directory}/{irandom_range(10000, 99999)}.png";
|
||||
|
||||
switch(ext) {
|
||||
case ".png":
|
||||
surface_save_safe(_surf, _path);
|
||||
if(indx == 0) {
|
||||
surface_save_safe(_surf, _pathTemp);
|
||||
|
||||
var shell_cmd = $"convert \"{_pathTemp}\" \"{_pathOut}\"";
|
||||
shell_execute(magick, shell_cmd, self);
|
||||
} else if(indx == 2) {
|
||||
surface_save_safe(_surf, _pathOut);
|
||||
} else {
|
||||
surface_save_safe(_surf, _pathTemp);
|
||||
|
||||
var shell_cmd = $"convert {_pathTemp} {png_format_r[indx]}:\"{_pathOut}\"";
|
||||
shell_execute(magick, shell_cmd, self);
|
||||
}
|
||||
break;
|
||||
|
||||
case ".jpg":
|
||||
surface_save_safe(_surf, _pathTemp);
|
||||
|
||||
_pathOut = "\"" + string_replace_all(_path, ".png", "") + ".jpg\"";
|
||||
_pathTemp = "\"" + _pathTemp + "\"";
|
||||
var shell_cmd = _pathTemp + " -quality " + string(qual) + " " + _pathOut;
|
||||
_pathOut = $"\"{string_replace_all(_path, ".png", "")}.jpg\"";
|
||||
var shell_cmd = $"\"{_pathTemp}\" -quality {qual} {_pathOut}";
|
||||
|
||||
shell_execute(magick, shell_cmd, self);
|
||||
break;
|
||||
|
@ -471,9 +489,8 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
case ".webp":
|
||||
surface_save_safe(_surf, _pathTemp);
|
||||
|
||||
_pathOut = "\"" + string_replace_all(_path, ".png", "") + ".webp\"";
|
||||
_pathTemp = "\"" + _pathTemp + "\"";
|
||||
var shell_cmd = _pathTemp + " -quality " + string(qual) + " -define webp:lossless=true " + _pathOut;
|
||||
_pathOut = $"\"{string_replace_all(_path, ".png", "")}.webp\"";
|
||||
var shell_cmd = $"\"{_pathTemp}\" -quality {qual} -define webp:lossless=true {_pathOut}";
|
||||
|
||||
shell_execute(magick, shell_cmd, self);
|
||||
break;
|
||||
|
@ -590,6 +607,8 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
|
||||
static step = function() { #region
|
||||
var surf = inputs[| 0].getValue();
|
||||
var pngf = inputs[| 13].getValue();
|
||||
|
||||
if(is_array(surf)) {
|
||||
inputs[| 3].display_data = format_array;
|
||||
inputs[| 3].editWidget.data_list = format_array;
|
||||
|
@ -600,7 +619,7 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
|
||||
outputs[| 1].setValue(surf);
|
||||
|
||||
var anim = inputs[| 3].getValue();
|
||||
var anim = inputs[| 3].getValue(); // single, sequence, animation
|
||||
var extn = inputs[| 9].getValue();
|
||||
|
||||
inputs[| 5].setVisible(anim == 2);
|
||||
|
@ -608,8 +627,9 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor
|
|||
inputs[| 7].setVisible(anim == 2);
|
||||
inputs[| 8].setVisible(anim == 2);
|
||||
inputs[| 11].setVisible(anim == 1);
|
||||
inputs[| 12].setVisible(anim >= 1);
|
||||
inputs[| 12].setVisible(anim > 0);
|
||||
inputs[| 12].editWidget.maxx = PROJECT.animator.frames_total;
|
||||
inputs[| 13].setVisible(anim < 2);
|
||||
|
||||
if(anim == NODE_EXPORT_FORMAT.gif) {
|
||||
inputs[| 9].display_data = format_animation;
|
||||
|
|
|
@ -49,10 +49,10 @@ function Node_Image_Animated(_x, _y, _group = noone) : Node(_x, _y, _group) cons
|
|||
inputs[| 2] = nodeValue("Stretch frame", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Stretch animation speed to match project length.")
|
||||
.rejectArray();
|
||||
|
||||
inputs[| 3] = nodeValue("Frame duration", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
|
||||
inputs[| 3] = nodeValue("Animation speed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
|
||||
.rejectArray();
|
||||
|
||||
inputs[| 4] = nodeValue("Animation end", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
|
||||
inputs[| 4] = nodeValue("Loop modes", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
|
||||
.setDisplay(VALUE_DISPLAY.enum_scroll, ["Loop", "Ping pong", "Hold last frame", "Hide"])
|
||||
.rejectArray();
|
||||
|
||||
|
@ -62,18 +62,22 @@ function Node_Image_Animated(_x, _y, _group = noone) : Node(_x, _y, _group) cons
|
|||
PROJECT.animator.frames_total = array_length(spr);
|
||||
}, "Match length"] );
|
||||
|
||||
inputs[| 6] = nodeValue("Custom frame order", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
|
||||
|
||||
inputs[| 7] = nodeValue("Frame", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0);
|
||||
|
||||
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
|
||||
|
||||
input_display_list = [
|
||||
["Image", false], 0, 1,
|
||||
["Animation", false], 5, 2, 3, 4,
|
||||
["Animation", false], 5, 4, 6, 7, 2, 3,
|
||||
];
|
||||
|
||||
attribute_surface_depth();
|
||||
|
||||
path_loaded = [];
|
||||
|
||||
on_drop_file = function(path) {
|
||||
on_drop_file = function(path) { #region
|
||||
if(directory_exists(path)) {
|
||||
with(dialogCall(o_dialog_drag_folder, WIN_W / 2, WIN_H / 2)) {
|
||||
dir_paths = path;
|
||||
|
@ -91,9 +95,9 @@ function Node_Image_Animated(_x, _y, _group = noone) : Node(_x, _y, _group) cons
|
|||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} #endregion
|
||||
|
||||
function updatePaths(paths) {
|
||||
function updatePaths(paths) { #region
|
||||
if(!is_array(paths) && ds_exists(paths, ds_type_list))
|
||||
paths = ds_list_to_array(paths);
|
||||
|
||||
|
@ -123,56 +127,71 @@ function Node_Image_Animated(_x, _y, _group = noone) : Node(_x, _y, _group) cons
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} #endregion
|
||||
|
||||
insp1UpdateTooltip = __txt("Refresh");
|
||||
insp1UpdateIcon = [ THEME.refresh, 1, COLORS._main_value_positive ];
|
||||
|
||||
static onInspector1Update = function() {
|
||||
static onInspector1Update = function() { #region
|
||||
var path = inputs[| 0].getValue();
|
||||
if(path == "") return;
|
||||
updatePaths(path);
|
||||
update();
|
||||
}
|
||||
} #endregion
|
||||
|
||||
static update = function(frame = PROJECT.animator.current_frame) {
|
||||
static step = function() { #region
|
||||
var str = inputs[| 2].getValue();
|
||||
var _cus = inputs[| 6].getValue();
|
||||
|
||||
inputs[| 7].setVisible( _cus);
|
||||
inputs[| 2].setVisible(!_cus);
|
||||
inputs[| 3].setVisible(!_cus && !str);
|
||||
inputs[| 4].setVisible(!_cus && !str);
|
||||
} #endregion
|
||||
|
||||
static update = function(frame = PROJECT.animator.current_frame) { #region
|
||||
var path = inputs[| 0].getValue();
|
||||
if(path == "") return;
|
||||
if(is_array(path) && !array_equals(path, path_loaded))
|
||||
updatePaths(path);
|
||||
if(array_length(spr) == 0) return;
|
||||
|
||||
var pad = inputs[| 1].getValue();
|
||||
var str = inputs[| 2].getValue();
|
||||
inputs[| 3].setVisible(!str);
|
||||
inputs[| 4].setVisible(!str);
|
||||
var _pad = inputs[| 1].getValue();
|
||||
|
||||
var spd = str? (PROJECT.animator.frames_total + 1) / array_length(spr) : inputs[| 3].getValue();
|
||||
var _cus = inputs[| 6].getValue();
|
||||
var _str = inputs[| 2].getValue();
|
||||
var _end = inputs[| 4].getValue();
|
||||
if(spd == 0) spd = 1;
|
||||
var _spd = _str? (PROJECT.animator.frames_total + 1) / array_length(spr) : 1 / inputs[| 3].getValue();
|
||||
if(_spd == 0) _spd = 1;
|
||||
var _frame = _cus? inputs[| 7].getValue() : floor(PROJECT.animator.current_frame / _spd);
|
||||
|
||||
var _len = array_length(spr);
|
||||
var _drw = true;
|
||||
|
||||
var ww = sprite_get_width(spr[0]);
|
||||
var hh = sprite_get_height(spr[0]);
|
||||
ww += pad[0] + pad[2];
|
||||
hh += pad[1] + pad[3];
|
||||
ww += _pad[0] + _pad[2];
|
||||
hh += _pad[1] + _pad[3];
|
||||
|
||||
var surfs = outputs[| 0].getValue();
|
||||
surfs = surface_verify(surfs, ww, hh, attrDepth());
|
||||
outputs[| 0].setValue(surfs);
|
||||
|
||||
var _frame = floor(PROJECT.animator.current_frame / spd);
|
||||
|
||||
switch(_end) {
|
||||
case ANIMATION_END.loop :
|
||||
_frame = safe_mod(_frame, array_length(spr));
|
||||
_frame = safe_mod(_frame, _len);
|
||||
break;
|
||||
case ANIMATION_END.ping :
|
||||
_frame = safe_mod(_frame, array_length(spr) * 2 - 2);
|
||||
if(_frame >= array_length(spr))
|
||||
_frame = array_length(spr) * 2 - 2 - _frame;
|
||||
_frame = safe_mod(_frame, _len * 2 - 2);
|
||||
if(_frame >= _len)
|
||||
_frame = _len * 2 - 2 - _frame;
|
||||
break;
|
||||
case ANIMATION_END.hold :
|
||||
_frame = min(_frame, array_length(spr) - 1);
|
||||
_frame = min(_frame, _len - 1);
|
||||
break;
|
||||
case ANIMATION_END.hide :
|
||||
if(_frame < 0 || _frame >= _len)
|
||||
_drw = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -181,18 +200,11 @@ function Node_Image_Animated(_x, _y, _group = noone) : Node(_x, _y, _group) cons
|
|||
|
||||
var curr_w = sprite_get_width(spr[_frame]);
|
||||
var curr_h = sprite_get_height(spr[_frame]);
|
||||
var curr_x = pad[2] + (ww - curr_w) / 2;
|
||||
var curr_y = pad[1] + (hh - curr_h) / 2;
|
||||
var curr_x = _pad[2] + (ww - curr_w) / 2;
|
||||
var curr_y = _pad[1] + (hh - curr_h) / 2;
|
||||
|
||||
surface_set_target(surfs);
|
||||
DRAW_CLEAR
|
||||
BLEND_OVERRIDE;
|
||||
if(_end == ANIMATION_END.hide) {
|
||||
if(_frame < array_length(spr))
|
||||
draw_sprite(spr[_frame], 0, curr_x, curr_y);
|
||||
} else
|
||||
draw_sprite(spr[_frame], 0, curr_x, curr_y);
|
||||
BLEND_NORMAL;
|
||||
surface_reset_target();
|
||||
}
|
||||
surface_set_shader(surfs);
|
||||
if(_drw) draw_sprite(spr[_frame], 0, curr_x, curr_y);
|
||||
surface_reset_shader();
|
||||
} #endregion
|
||||
}
|
|
@ -10,7 +10,6 @@ function Node_create_Image_gif(_x, _y, _group = noone) {
|
|||
node.inputs[| 0].setValue(path);
|
||||
node.doUpdate();
|
||||
|
||||
//ds_list_add(PANEL_GRAPH.nodes_list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -21,7 +20,6 @@ function Node_create_Image_gif_path(_x, _y, path) {
|
|||
node.inputs[| 0].setValue(path);
|
||||
node.doUpdate();
|
||||
|
||||
//ds_list_add(PANEL_GRAPH.nodes_list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -43,17 +41,34 @@ function Node_Image_gif(_x, _y, _group = noone) : Node(_x, _y, _group) construct
|
|||
|
||||
inputs[| 2] = nodeValue("Output as array", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
|
||||
|
||||
inputs[| 3] = nodeValue("Loop modes", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
|
||||
.setDisplay(VALUE_DISPLAY.enum_scroll, ["Loop", "Ping pong", "Hold last frame", "Hide"])
|
||||
.rejectArray();
|
||||
|
||||
inputs[| 4] = nodeValue("Start frame", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0);
|
||||
|
||||
inputs[| 5] = nodeValue("Custom frame order", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
|
||||
|
||||
inputs[| 6] = nodeValue("Frame", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0);
|
||||
|
||||
inputs[| 7] = nodeValue("Animation speed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1);
|
||||
|
||||
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
|
||||
outputs[| 1] = nodeValue("Path", self, JUNCTION_CONNECT.output, VALUE_TYPE.path, "")
|
||||
.setVisible(true, true);
|
||||
|
||||
input_display_list = [
|
||||
["Image", false], 0,
|
||||
["Output", false], 2,
|
||||
["Animation", false], 1, 3, 5, 4, 6, 7,
|
||||
];
|
||||
|
||||
attribute_surface_depth();
|
||||
|
||||
spr = noone;
|
||||
path_current = "";
|
||||
loading = 0;
|
||||
spr_builder = noone;
|
||||
|
||||
surfaces = [];
|
||||
|
||||
on_drop_file = function(path) {
|
||||
|
@ -70,14 +85,14 @@ function Node_Image_gif(_x, _y, _group = noone) : Node(_x, _y, _group) construct
|
|||
insp1UpdateTooltip = __txt("Refresh");
|
||||
insp1UpdateIcon = [ THEME.refresh, 1, COLORS._main_value_positive ];
|
||||
|
||||
static onInspector1Update = function() {
|
||||
static onInspector1Update = function() { #region
|
||||
var path = inputs[| 0].getValue();
|
||||
if(path == "") return;
|
||||
updatePaths(path);
|
||||
update();
|
||||
}
|
||||
} #endregion
|
||||
|
||||
function updatePaths(path) {
|
||||
function updatePaths(path) { #region
|
||||
path = try_get_path(path);
|
||||
if(path == -1) return false;
|
||||
|
||||
|
@ -101,9 +116,18 @@ function Node_Image_gif(_x, _y, _group = noone) : Node(_x, _y, _group) construct
|
|||
path_current = path;
|
||||
|
||||
return true;
|
||||
}
|
||||
} #endregion
|
||||
|
||||
static step = function() { #region
|
||||
var _arr = inputs[| 2].getValue();
|
||||
var _lop = inputs[| 3].getValue();
|
||||
var _cus = inputs[| 5].getValue();
|
||||
|
||||
inputs[| 3].setVisible(!_arr);
|
||||
inputs[| 4].setVisible(!_cus);
|
||||
inputs[| 6].setVisible( _cus);
|
||||
inputs[| 7].setVisible(!_cus);
|
||||
|
||||
static step = function() {
|
||||
if(loading == 2 && spr_builder != noone && spr_builder.building()) {
|
||||
surfaces = [];
|
||||
spr = spr_builder._spr;
|
||||
|
@ -112,9 +136,9 @@ function Node_Image_gif(_x, _y, _group = noone) : Node(_x, _y, _group) construct
|
|||
|
||||
gc_collect();
|
||||
}
|
||||
}
|
||||
} #endregion
|
||||
|
||||
static update = function(frame = PROJECT.animator.current_frame) {
|
||||
static update = function(frame = PROJECT.animator.current_frame) { #region
|
||||
var path = inputs[| 0].getValue();
|
||||
if(path == "") return;
|
||||
if(path_current != path) updatePaths(path);
|
||||
|
@ -148,13 +172,40 @@ function Node_Image_gif(_x, _y, _group = noone) : Node(_x, _y, _group) construct
|
|||
return;
|
||||
}
|
||||
|
||||
var _loop = inputs[| 3].getValue();
|
||||
var _strt = inputs[| 4].getValue();
|
||||
var _cust = inputs[| 5].getValue();
|
||||
var _spd = inputs[| 7].getValue();
|
||||
var _frm = _cust? inputs[| 6].getValue() : PROJECT.animator.current_frame * _spd - _strt;
|
||||
|
||||
var _len = sprite_get_number(spr);
|
||||
var _drw = true;
|
||||
|
||||
switch(_loop) {
|
||||
case ANIMATION_END.loop :
|
||||
_frm = safe_mod(_frm, _len);
|
||||
break;
|
||||
case ANIMATION_END.ping :
|
||||
_frm = safe_mod(_frm, _len * 2 - 2);
|
||||
if(_frm >= _len)
|
||||
_frm = _len * 2 - 2 - _frm;
|
||||
break;
|
||||
case ANIMATION_END.hold :
|
||||
_frm = clamp(_frm, -_len, _len - 1);
|
||||
break;
|
||||
case ANIMATION_END.hide :
|
||||
if(_frm < 0 || _frm >= _len)
|
||||
_drw = false;
|
||||
break;
|
||||
}
|
||||
|
||||
_outsurf = surface_verify(_outsurf, ww, hh, attrDepth());
|
||||
outputs[| 0].setValue(_outsurf);
|
||||
|
||||
surface_set_shader(_outsurf);
|
||||
draw_sprite(spr, PROJECT.animator.current_frame, 0, 0);
|
||||
if(_drw) draw_sprite(spr, _frm, 0, 0);
|
||||
surface_reset_shader();
|
||||
}
|
||||
} #endregion
|
||||
|
||||
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
|
||||
if(loading) draw_sprite_ui(THEME.loading, 0, xx + w * _s / 2, yy + h * _s / 2, _s, _s, current_time / 2, COLORS._main_icon, 1);
|
||||
|
|
Loading…
Reference in a new issue