diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index e335144b9..48051bc66 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -1,9 +1,9 @@ { "FolderOrderSettings": [ {"name":"_Extensions","order":9,"path":"folders/_Extensions.yy",}, - {"name":"BBMOD","order":9,"path":"folders/_Extensions/BBMOD.yy",}, + {"name":"BBMOD","order":8,"path":"folders/_Extensions/BBMOD.yy",}, {"name":"Math","order":1,"path":"folders/_Extensions/BBMOD/Math.yy",}, - {"name":"MAC","order":7,"path":"folders/_Extensions/MAC.yy",}, + {"name":"MAC","order":6,"path":"folders/_Extensions/MAC.yy",}, {"name":"addons","order":11,"path":"folders/addons.yy",}, {"name":"custom","order":4,"path":"folders/addons/custom.yy",}, {"name":"key displayer","order":2,"path":"folders/addons/key displayer.yy",}, @@ -102,7 +102,7 @@ {"name":"filter","order":141,"path":"folders/nodes/icons/filter.yy",}, {"name":"fluidSim","order":147,"path":"folders/nodes/icons/fluidSim.yy",}, {"name":"generator","order":142,"path":"folders/nodes/icons/generator.yy",}, - {"name":"input","order":143,"path":"folders/nodes/icons/input.yy",}, + {"name":"IO","order":143,"path":"folders/nodes/icons/IO.yy",}, {"name":"node","order":139,"path":"folders/nodes/icons/node.yy",}, {"name":"render","order":140,"path":"folders/nodes/icons/render.yy",}, {"name":"rigidSim","order":146,"path":"folders/nodes/icons/rigidSim.yy",}, @@ -233,7 +233,7 @@ {"name":"fd_rectangle_set_velocity_time_step","order":17,"path":"scripts/fd_rectangle_set_velocity_time_step/fd_rectangle_set_velocity_time_step.yy",}, {"name":"fd_rectangle_set_collision_mask_sprite","order":1,"path":"scripts/fd_rectangle_set_collision_mask_sprite/fd_rectangle_set_collision_mask_sprite.yy",}, {"name":"sh_flip","order":7,"path":"shaders/sh_flip/sh_flip.yy",}, - {"name":"libdlgmodule","order":3,"path":"extensions/libdlgmodule/libdlgmodule.yy",}, + {"name":"libdlgmodule","order":2,"path":"extensions/libdlgmodule/libdlgmodule.yy",}, {"name":"s_node_alpha_grey","order":4,"path":"sprites/s_node_alpha_grey/s_node_alpha_grey.yy",}, {"name":"fd_rectangle_set_pressure_iteration_type","order":10,"path":"scripts/fd_rectangle_set_pressure_iteration_type/fd_rectangle_set_pressure_iteration_type.yy",}, {"name":"s_node_sort_array","order":29,"path":"sprites/s_node_sort_array/s_node_sort_array.yy",}, @@ -319,6 +319,7 @@ {"name":"__node","order":9,"path":"scripts/__node/__node.yy",}, {"name":"fd_rectangle_add_velocity","order":5,"path":"scripts/fd_rectangle_add_velocity/fd_rectangle_add_velocity.yy",}, {"name":"sh_level_selector","order":23,"path":"shaders/sh_level_selector/sh_level_selector.yy",}, + {"name":"byte_writer","order":8,"path":"scripts/byte_writer/byte_writer.yy",}, {"name":"checkboxGroup","order":28,"path":"scripts/checkboxGroup/checkboxGroup.yy",}, {"name":"node_FXAA","order":8,"path":"scripts/node_FXAA/node_FXAA.yy",}, {"name":"s_node_pixel_find","order":13,"path":"sprites/s_node_pixel_find/s_node_pixel_find.yy",}, @@ -435,7 +436,7 @@ {"name":"draw_text_delimiter","order":14,"path":"scripts/draw_text_delimiter/draw_text_delimiter.yy",}, {"name":"s_node_path_anchor","order":13,"path":"sprites/s_node_path_anchor/s_node_path_anchor.yy",}, {"name":"node_array_get","order":10,"path":"scripts/node_array_get/node_array_get.yy",}, - {"name":"Apollo","order":6,"path":"extensions/Apollo/Apollo.yy",}, + {"name":"Apollo","order":5,"path":"extensions/Apollo/Apollo.yy",}, {"name":"sh_grid","order":14,"path":"shaders/sh_grid/sh_grid.yy",}, {"name":"sh_twirl","order":3,"path":"shaders/sh_twirl/sh_twirl.yy",}, {"name":"s_node_shape","order":14,"path":"sprites/s_node_shape/s_node_shape.yy",}, @@ -512,7 +513,7 @@ {"name":"_node_fluid_nodes","order":7,"path":"scripts/_node_fluid_nodes/_node_fluid_nodes.yy",}, {"name":"sh_noise","order":16,"path":"shaders/sh_noise/sh_noise.yy",}, {"name":"sh_skew","order":6,"path":"shaders/sh_skew/sh_skew.yy",}, - {"name":"libxprocess","order":5,"path":"extensions/libxprocess/libxprocess.yy",}, + {"name":"libxprocess","order":4,"path":"extensions/libxprocess/libxprocess.yy",}, {"name":"fd_rectangle_get_pressure_height","order":16,"path":"scripts/fd_rectangle_get_pressure_height/fd_rectangle_get_pressure_height.yy",}, {"name":"node_VFX_effect_destroy","order":12,"path":"scripts/node_VFX_effect_destroy/node_VFX_effect_destroy.yy",}, {"name":"node_cache","order":9,"path":"scripts/node_cache/node_cache.yy",}, @@ -642,7 +643,7 @@ {"name":"_draw_defines","order":21,"path":"scripts/_draw_defines/_draw_defines.yy",}, {"name":"sh_color_replace","order":8,"path":"shaders/sh_color_replace/sh_color_replace.yy",}, {"name":"__surface","order":8,"path":"scripts/__surface/__surface.yy",}, - {"name":"clipboard","order":10,"path":"extensions/clipboard/clipboard.yy",}, + {"name":"clipboard","order":9,"path":"extensions/clipboard/clipboard.yy",}, {"name":"rotator","order":11,"path":"scripts/rotator/rotator.yy",}, {"name":"s_node_edge_detect","order":22,"path":"sprites/s_node_edge_detect/s_node_edge_detect.yy",}, {"name":"node_fluid_add_collider","order":6,"path":"scripts/node_fluid_add_collider/node_fluid_add_collider.yy",}, @@ -687,6 +688,7 @@ {"name":"sh_invert","order":25,"path":"shaders/sh_invert/sh_invert.yy",}, {"name":"preview_overlay_puppet","order":4,"path":"scripts/preview_overlay_puppet/preview_overlay_puppet.yy",}, {"name":"s_icon_64","order":2,"path":"sprites/s_icon_64/s_icon_64.yy",}, + {"name":"panel_graph_export_image","order":4,"path":"scripts/panel_graph_export_image/panel_graph_export_image.yy",}, {"name":"s_node_gradient_replace","order":18,"path":"sprites/s_node_gradient_replace/s_node_gradient_replace.yy",}, {"name":"node_perlin_smear","order":6,"path":"scripts/node_perlin_smear/node_perlin_smear.yy",}, {"name":"node_alpha_cutoff","order":10,"path":"scripts/node_alpha_cutoff/node_alpha_cutoff.yy",}, @@ -768,6 +770,7 @@ {"name":"fd_rectangle_set_repeat","order":12,"path":"scripts/fd_rectangle_set_repeat/fd_rectangle_set_repeat.yy",}, {"name":"sh_fd_calculate_velocity_divergence_glsl","order":10,"path":"shaders/sh_fd_calculate_velocity_divergence_glsl/sh_fd_calculate_velocity_divergence_glsl.yy",}, {"name":"node_simple_shape","order":4,"path":"scripts/node_simple_shape/node_simple_shape.yy",}, + {"name":"node_wav_file_write","order":3,"path":"scripts/node_wav_file_write/node_wav_file_write.yy",}, {"name":"node_random","order":5,"path":"scripts/node_random/node_random.yy",}, {"name":"node_atlas","order":2,"path":"scripts/node_atlas/node_atlas.yy",}, {"name":"sh_blend_sat","order":18,"path":"shaders/sh_blend_sat/sh_blend_sat.yy",}, @@ -824,7 +827,7 @@ {"name":"o_dialog_animation","order":1,"path":"objects/o_dialog_animation/o_dialog_animation.yy",}, {"name":"s_gizmo","order":4,"path":"sprites/s_gizmo/s_gizmo.yy",}, {"name":"s_node_3d_plane","order":6,"path":"sprites/s_node_3d_plane/s_node_3d_plane.yy",}, - {"name":"Regex","order":8,"path":"extensions/Regex/Regex.yy",}, + {"name":"Regex","order":7,"path":"extensions/Regex/Regex.yy",}, {"name":"s_node_path_shift","order":4,"path":"sprites/s_node_path_shift/s_node_path_shift.yy",}, {"name":"s_node_grid_tri","order":6,"path":"sprites/s_node_grid_tri/s_node_grid_tri.yy",}, {"name":"s_node_local_analyze","order":52,"path":"sprites/s_node_local_analyze/s_node_local_analyze.yy",}, @@ -986,7 +989,7 @@ {"name":"BBMOD_Matrix","order":2,"path":"scripts/BBMOD_Matrix/BBMOD_Matrix.yy",}, {"name":"pack_shelf","order":1,"path":"scripts/pack_shelf/pack_shelf.yy",}, {"name":"s_node_path_trim","order":6,"path":"sprites/s_node_path_trim/s_node_path_trim.yy",}, - {"name":"libfilesystem","order":4,"path":"extensions/libfilesystem/libfilesystem.yy",}, + {"name":"libfilesystem","order":3,"path":"extensions/libfilesystem/libfilesystem.yy",}, {"name":"node_channels_hsv","order":1,"path":"scripts/node_channels_hsv/node_channels_hsv.yy",}, {"name":"sh_stripe","order":10,"path":"shaders/sh_stripe/sh_stripe.yy",}, {"name":"node_path_trim","order":6,"path":"scripts/node_path_trim/node_path_trim.yy",}, @@ -1108,6 +1111,7 @@ {"name":"fd_rectangle_replace_velocity","order":16,"path":"scripts/fd_rectangle_replace_velocity/fd_rectangle_replace_velocity.yy",}, {"name":"node_VFX_effector","order":6,"path":"scripts/node_VFX_effector/node_VFX_effector.yy",}, {"name":"node_path_shift","order":5,"path":"scripts/node_path_shift/node_path_shift.yy",}, + {"name":"s_node_wav_file_write","order":20,"path":"sprites/s_node_wav_file_write/s_node_wav_file_write.yy",}, {"name":"s_node_3d_cylinder","order":1,"path":"sprites/s_node_3d_cylinder/s_node_3d_cylinder.yy",}, {"name":"node_strand_break","order":9,"path":"scripts/node_strand_break/node_strand_break.yy",}, {"name":"s_node_vec_split","order":6,"path":"sprites/s_node_vec_split/s_node_vec_split.yy",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index b86a2e1d1..3d0535bc6 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -134,7 +134,7 @@ {"resourceType":"GMFolder","resourceVersion":"1.0","name":"filter","folderPath":"folders/nodes/icons/filter.yy",}, {"resourceType":"GMFolder","resourceVersion":"1.0","name":"fluidSim","folderPath":"folders/nodes/icons/fluidSim.yy",}, {"resourceType":"GMFolder","resourceVersion":"1.0","name":"generator","folderPath":"folders/nodes/icons/generator.yy",}, - {"resourceType":"GMFolder","resourceVersion":"1.0","name":"input","folderPath":"folders/nodes/icons/input.yy",}, + {"resourceType":"GMFolder","resourceVersion":"1.0","name":"IO","folderPath":"folders/nodes/icons/IO.yy",}, {"resourceType":"GMFolder","resourceVersion":"1.0","name":"node","folderPath":"folders/nodes/icons/node.yy",}, {"resourceType":"GMFolder","resourceVersion":"1.0","name":"render","folderPath":"folders/nodes/icons/render.yy",}, {"resourceType":"GMFolder","resourceVersion":"1.0","name":"rigidSim","folderPath":"folders/nodes/icons/rigidSim.yy",}, @@ -812,6 +812,11 @@ {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"tile_0044.png","CopyToMask":-1,"filePath":"datafiles/Getting started",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"tile_0067.png","CopyToMask":-1,"filePath":"datafiles/Getting started",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"tile_0126.png","CopyToMask":-1,"filePath":"datafiles/Getting started",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"LICENSE","CopyToMask":-1,"filePath":"datafiles/gifski",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"README.md","CopyToMask":-1,"filePath":"datafiles/gifski",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"gifski.dll","CopyToMask":-1,"filePath":"datafiles/gifski/win/developer",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"gifski.h","CopyToMask":-1,"filePath":"datafiles/gifski/win/developer",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"gifski.exe","CopyToMask":-1,"filePath":"datafiles/gifski/win",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"convert.exe","CopyToMask":-1,"filePath":"datafiles/ImageMagick",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"LICENSE.txt","CopyToMask":-1,"filePath":"datafiles/ImageMagick",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"magick.exe","CopyToMask":-1,"filePath":"datafiles/ImageMagick",}, @@ -848,6 +853,7 @@ {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Tree sway.pxc","CopyToMask":-1,"filePath":"datafiles/Sample Projects",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Steamworks_Extension_Documentation.html","CopyToMask":0,"filePath":"datafiles",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"ucrtbased.dll","ConfigValues":{},"CopyToMask":-1,"filePath":"datafiles",}, + {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Uninstall gifski.lnk","CopyToMask":-1,"filePath":"datafiles",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"webpmux.exe","CopyToMask":-1,"filePath":"datafiles/webp",}, {"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"Welcome files.zip","CopyToMask":-1,"filePath":"datafiles",}, ], @@ -1049,6 +1055,7 @@ {"id":{"name":"sh_level_selector","path":"shaders/sh_level_selector/sh_level_selector.yy",},}, {"id":{"name":"string_eval","path":"scripts/string_eval/string_eval.yy",},}, {"id":{"name":"s_node_struct","path":"sprites/s_node_struct/s_node_struct.yy",},}, + {"id":{"name":"byte_writer","path":"scripts/byte_writer/byte_writer.yy",},}, {"id":{"name":"checkboxGroup","path":"scripts/checkboxGroup/checkboxGroup.yy",},}, {"id":{"name":"node_FXAA","path":"scripts/node_FXAA/node_FXAA.yy",},}, {"id":{"name":"s_node_pixel_find","path":"sprites/s_node_pixel_find/s_node_pixel_find.yy",},}, @@ -1468,6 +1475,7 @@ {"id":{"name":"preview_overlay_puppet","path":"scripts/preview_overlay_puppet/preview_overlay_puppet.yy",},}, {"id":{"name":"__mesh","path":"scripts/__mesh/__mesh.yy",},}, {"id":{"name":"s_icon_64","path":"sprites/s_icon_64/s_icon_64.yy",},}, + {"id":{"name":"panel_graph_export_image","path":"scripts/panel_graph_export_image/panel_graph_export_image.yy",},}, {"id":{"name":"save_function","path":"scripts/save_function/save_function.yy",},}, {"id":{"name":"s_node_gradient_replace","path":"sprites/s_node_gradient_replace/s_node_gradient_replace.yy",},}, {"id":{"name":"node_perlin_smear","path":"scripts/node_perlin_smear/node_perlin_smear.yy",},}, @@ -1555,6 +1563,7 @@ {"id":{"name":"fd_rectangle_set_repeat","path":"scripts/fd_rectangle_set_repeat/fd_rectangle_set_repeat.yy",},}, {"id":{"name":"sh_fd_calculate_velocity_divergence_glsl","path":"shaders/sh_fd_calculate_velocity_divergence_glsl/sh_fd_calculate_velocity_divergence_glsl.yy",},}, {"id":{"name":"node_simple_shape","path":"scripts/node_simple_shape/node_simple_shape.yy",},}, + {"id":{"name":"node_wav_file_write","path":"scripts/node_wav_file_write/node_wav_file_write.yy",},}, {"id":{"name":"fd_rectangle_get_acceleration_a","path":"scripts/fd_rectangle_get_acceleration_a/fd_rectangle_get_acceleration_a.yy",},}, {"id":{"name":"node_random","path":"scripts/node_random/node_random.yy",},}, {"id":{"name":"sh_channel_A","path":"shaders/sh_channel_A/sh_channel_A.yy",},}, @@ -1947,6 +1956,7 @@ {"id":{"name":"node_VFX_effector","path":"scripts/node_VFX_effector/node_VFX_effector.yy",},}, {"id":{"name":"sh_blur_gaussian","path":"shaders/sh_blur_gaussian/sh_blur_gaussian.yy",},}, {"id":{"name":"node_path_shift","path":"scripts/node_path_shift/node_path_shift.yy",},}, + {"id":{"name":"s_node_wav_file_write","path":"sprites/s_node_wav_file_write/s_node_wav_file_write.yy",},}, {"id":{"name":"s_node_3d_cylinder","path":"sprites/s_node_3d_cylinder/s_node_3d_cylinder.yy",},}, {"id":{"name":"node_strand_break","path":"scripts/node_strand_break/node_strand_break.yy",},}, {"id":{"name":"s_node_vec_split","path":"sprites/s_node_vec_split/s_node_vec_split.yy",},}, diff --git a/datafiles/Uninstall gifski.lnk b/datafiles/Uninstall gifski.lnk new file mode 100644 index 000000000..37087cc5c Binary files /dev/null and b/datafiles/Uninstall gifski.lnk differ diff --git a/datafiles/data/themes/default.zip b/datafiles/data/themes/default.zip index 694fc5fb1..b6e617be7 100644 Binary files a/datafiles/data/themes/default.zip and b/datafiles/data/themes/default.zip differ diff --git a/datafiles/gifski/LICENSE b/datafiles/gifski/LICENSE new file mode 100644 index 000000000..24eda8a7b --- /dev/null +++ b/datafiles/gifski/LICENSE @@ -0,0 +1,619 @@ + +Let [me](https://kornel.ski/contact) know if you'd like to use it in a product incompatible with this license. I can offer alternative licensing options. + +---- + +### GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +© 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains +free software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing +under this license. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public +License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your +version supports such interaction) an opportunity to receive the +Corresponding Source of your version by providing access to the +Corresponding Source from a network server at no charge, through some +standard or customary means of facilitating copying of software. This +Corresponding Source shall include the Corresponding Source for any +work covered by version 3 of the GNU General Public License that is +incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Affero General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever +published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. diff --git a/datafiles/gifski/README.md b/datafiles/gifski/README.md new file mode 100644 index 000000000..888668361 --- /dev/null +++ b/datafiles/gifski/README.md @@ -0,0 +1,100 @@ +# [gif.ski](https://gif.ski) + +Highest-quality GIF encoder based on [pngquant](https://pngquant.org). + +**[gifski](https://gif.ski)** converts video frames to GIF animations using pngquant's fancy features for efficient cross-frame palettes and temporal dithering. It produces animated GIFs that use thousands of colors per frame. + +![(CC) Blender Foundation | gooseberry.blender.org](https://gif.ski/demo.gif) + +It's a CLI tool, but it can also be compiled [as a C library](https://docs.rs/gifski) for seamless use in other apps. + +## Download and install + +See [releases](https://github.com/ImageOptim/gifski/releases) page for executables. + +If you have [Homebrew](https://brew.sh/), you can also get it with `brew install gifski`. + +If you have [Rust from rustup](https://www.rust-lang.org/install.html) (1.63+), you can also build it from source with [`cargo install gifski`](https://lib.rs/crates/gifski). + +## Usage + +gifski is a command-line tool. There is no GUI for Windows or Linux (there is one for [macOS](https://sindresorhus.com/gifski)). + +The recommended way is to first export video as PNG frames. If you have `ffmpeg` installed, you can run in terminal: + +```sh +ffmpeg -i video.webm frame%04d.png +``` + +and then make the GIF from the frames: + +```sh +gifski -o anim.gif frame*.png +``` + +You can also resize frames (with `-W ` option). If the input was ever encoded using a lossy video codec it's recommended to at least halve size of the frames to hide compression artefacts and counter chroma subsampling that was done by the video codec. + +Adding `--quality=90` may reduce file sizes a bit, but expect to lose a lot of quality for little gain. GIF just isn't that good at compressing, no matter how much you compromise. + +See `gifski -h` for more options. + +## Building + +1. [Install Rust via rustup](https://www.rust-lang.org/en-US/install.html) or run `rustup update`. This project only supports up-to-date versions of Rust. You may get compile errors, warnings about "unstable edition", etc. if you don't run `rustup update` regularly. +2. Clone the repository: `git clone https://github.com/ImageOptim/gifski` +3. In the cloned directory, run: `cargo build --release` + +### Using from C + +[See `gifski.h`](https://github.com/ImageOptim/gifski/blob/main/gifski.h) for [the C API](https://docs.rs/gifski/latest/gifski/c_api/#functions). To build the library, run: + +```sh +rustup update +cargo build --release +``` + +and link with `target/release/libgifski.a`. Please observe the [LICENSE](LICENSE). + +## License + +AGPL 3 or later. I can offer alternative licensing options, including [commercial licenses](https://supso.org/projects/pngquant). Let [me](https://kornel.ski/contact) know if you'd like to use it in a product incompatible with this license. + +## With built-in video support + +The tool optionally supports decoding video directly, but unfortunately it relies on ffmpeg 4.x, which may be *very hard* to get working, so it's not enabled by default. + +You must have `ffmpeg` and `libclang` installed, both with their C headers installed in default system include paths. Details depend on the platform and version, but you usually need to install packages such as `libavformat-dev`, `libavfilter-dev`, `libavdevice-dev`, `libclang-dev`, `clang`. Please note that installation of these dependencies may be quite difficult. Especially on macOS and Windows it takes *expert knowledge* to just get them installed without wasting several hours on endless stupid installation and compilation errors, which I can't help with. If you're cross-compiling, try uncommenting `[patch.crates-io]` section at the end of `Cargo.toml`, which includes some experimental fixes for ffmpeg. + +Once you have dependencies installed, compile with `cargo build --release --features=video` or `cargo build --release --features=video-static`. + +When compiled with video support [ffmpeg licenses](https://www.ffmpeg.org/legal.html) apply. You may need to have a patent license to use H.264/H.265 video (I recommend using VP9/WebM instead). + +```sh +gifski -o out.gif video.mp4 +``` + +## Cross-compilation for iOS + +The easy option is to use the included `gifski.xcodeproj` file to build the library automatically for all Apple platforms. Add it as a [subproject](https://lib.rs/crates/cargo-xcode) to your Xcode project, and link with `gifski-staticlib` Xcode target. See [the GUI app](https://github.com/sindresorhus/Gifski) for an example how to integrate the library. + +### Cross-compilation for iOS manually + +Make sure you have Rust installed via [rustup](https://rustup.rs/). Run once: + +```sh +rustup target add aarch64-apple-ios +``` + +and then to build the library: + +```sh +rustup update +cargo build --lib --release --target=aarch64-apple-ios +``` + +The build will print "dropping unsupported crate type `cdylib`" warning. This is normal and expected when building for iOS (the cdylib option exists for other platforms). + +This will create a static library in `./target/aarch64-apple-ios/release/libgifski.a`. You can add this library to your Xcode project. See [gifski.app](https://github.com/sindresorhus/Gifski) for an example how to use libgifski from Swift. + + + diff --git a/datafiles/gifski/win/developer/gifski.dll b/datafiles/gifski/win/developer/gifski.dll new file mode 100644 index 000000000..449a27322 Binary files /dev/null and b/datafiles/gifski/win/developer/gifski.dll differ diff --git a/datafiles/gifski/win/developer/gifski.h b/datafiles/gifski/win/developer/gifski.h new file mode 100644 index 000000000..86a7ba75f --- /dev/null +++ b/datafiles/gifski/win/developer/gifski.h @@ -0,0 +1,321 @@ +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +struct gifski; +typedef struct gifski gifski; + +/** +How to use from C + +```c +gifski *g = gifski_new(&(GifskiSettings){ + .quality = 90, +}); +gifski_set_file_output(g, "file.gif"); + +for(int i=0; i < frames; i++) { + int res = gifski_add_frame_rgba(g, i, width, height, buffer, 5); + if (res != GIFSKI_OK) break; +} +int res = gifski_finish(g); +if (res != GIFSKI_OK) return; +``` + +It's safe and efficient to call `gifski_add_frame_*` in a loop as fast as you can get frames, +because it blocks and waits until previous frames are written. + +To cancel processing, make progress callback return 0 and call `gifski_finish()`. The write callback +may still be called between the cancellation and `gifski_finish()` returning. + +To build as a library: + +```bash +cargo build --release --lib +``` + +it will create `target/release/libgifski.a` (static library) +and `target/release/libgifski.so`/`dylib` or `gifski.dll` (dynamic library) + +Static is recommended. + +To build for iOS: + +```bash +rustup target add aarch64-apple-ios +cargo build --release --lib --target aarch64-apple-ios +``` + +it will build `target/aarch64-apple-ios/release/libgifski.a` (ignore the warning about cdylib). + +*/ + +/** + * Settings for creating a new encoder instance. See `gifski_new` + */ +typedef struct GifskiSettings { + /** + * Resize to max this width if non-0. + */ + uint32_t width; + /** + * Resize to max this height if width is non-0. Note that aspect ratio is not preserved. + */ + uint32_t height; + /** + * 1-100, but useful range is 50-100. Recommended to set to 90. + */ + uint8_t quality; + /** + * Lower quality, but faster encode. + */ + bool fast; + /** + * If negative, looping is disabled. The number of times the sequence is repeated. 0 to loop forever. + */ + int16_t repeat; +} GifskiSettings; + +enum GifskiError { + GIFSKI_OK = 0, + /** one of input arguments was NULL */ + GIFSKI_NULL_ARG, + /** a one-time function was called twice, or functions were called in wrong order */ + GIFSKI_INVALID_STATE, + /** internal error related to palette quantization */ + GIFSKI_QUANT, + /** internal error related to gif composing */ + GIFSKI_GIF, + /** internal error - unexpectedly aborted */ + GIFSKI_THREAD_LOST, + /** I/O error: file or directory not found */ + GIFSKI_NOT_FOUND, + /** I/O error: permission denied */ + GIFSKI_PERMISSION_DENIED, + /** I/O error: file already exists */ + GIFSKI_ALREADY_EXISTS, + /** invalid arguments passed to function */ + GIFSKI_INVALID_INPUT, + /** misc I/O error */ + GIFSKI_TIMED_OUT, + /** misc I/O error */ + GIFSKI_WRITE_ZERO, + /** misc I/O error */ + GIFSKI_INTERRUPTED, + /** misc I/O error */ + GIFSKI_UNEXPECTED_EOF, + /** progress callback returned 0, writing aborted */ + GIFSKI_ABORTED, + /** should not happen, file a bug */ + GIFSKI_OTHER, +}; + +/* workaround for a wrong definition in an older version of this header. Please use GIFSKI_ABORTED directly */ +#ifndef ABORTED +#define ABORTED GIFSKI_ABORTED +#endif + +typedef enum GifskiError GifskiError; + +/** + * Call to start the process + * + * See `gifski_add_frame_png_file` and `gifski_end_adding_frames` + * + * Returns a handle for the other functions, or `NULL` on error (if the settings are invalid). + */ +gifski *gifski_new(const GifskiSettings *settings); + + +/** Quality 1-100 of temporal denoising. Lower values reduce motion. Defaults to `settings.quality`. + * + * Only valid immediately after calling `gifski_new`, before any frames are added. */ +GifskiError gifski_set_motion_quality(gifski *handle, uint8_t quality); + +/** Quality 1-100 of gifsicle compression. Lower values add noise. Defaults to `settings.quality`. + * Has no effect if the `gifsicle` feature hasn't been enabled. + * Only valid immediately after calling `gifski_new`, before any frames are added. */ +GifskiError gifski_set_lossy_quality(gifski *handle, uint8_t quality); + +/** If `true`, encoding will be significantly slower, but may look a bit better. + * + * Only valid immediately after calling `gifski_new`, before any frames are added. */ +GifskiError gifski_set_extra_effort(gifski *handle, bool extra); + +/** + * Adds a frame to the animation. This function is asynchronous. + * + * File path must be valid UTF-8. + * + * `frame_number` orders frames (consecutive numbers starting from 0). + * You can add frames in any order, and they will be sorted by their `frame_number`. + * + * Presentation timestamp (PTS) is time in seconds, since start of the file, when this frame is to be displayed. + * For a 20fps video it could be `frame_number/20.0`. + * Frames with duplicate or out-of-order PTS will be skipped. + * + * The first frame should have PTS=0. If the first frame has PTS > 0, it'll be used as a delay after the last frame. + * + * Returns 0 (`GIFSKI_OK`) on success, and non-0 `GIFSKI_*` constant on error. + */ +GifskiError gifski_add_frame_png_file(gifski *handle, + uint32_t frame_number, + const char *file_path, + double presentation_timestamp); + +/** + * Adds a frame to the animation. This function is asynchronous. + * + * `pixels` is an array width×height×4 bytes large. + * The array is copied, so you can free/reuse it immediately after this function returns. + * + * `frame_number` orders frames (consecutive numbers starting from 0). + * You can add frames in any order, and they will be sorted by their `frame_number`. + * + * Presentation timestamp (PTS) is time in seconds, since start of the file, when this frame is to be displayed. + * For a 20fps video it could be `frame_number/20.0`. First frame must have PTS=0. + * Frames with duplicate or out-of-order PTS will be skipped. + * + * The first frame should have PTS=0. If the first frame has PTS > 0, it'll be used as a delay after the last frame. + * + * Colors are in sRGB, uncorrelated RGBA, with alpha byte last. + * + * Returns 0 (`GIFSKI_OK`) on success, and non-0 `GIFSKI_*` constant on error. + */ +GifskiError gifski_add_frame_rgba(gifski *handle, + uint32_t frame_number, + uint32_t width, + uint32_t height, + const unsigned char *pixels, + double presentation_timestamp); + +/** Same as `gifski_add_frame_rgba`, but with bytes per row arg */ +GifskiError gifski_add_frame_rgba_stride(gifski *handle, + uint32_t frame_number, + uint32_t width, + uint32_t height, + uint32_t bytes_per_row, + const unsigned char *pixels, + double presentation_timestamp); + +/** Same as `gifski_add_frame_rgba_stride`, except it expects components in ARGB order. + +Bytes per row must be multiple of 4, and greater or equal width×4. +If the bytes per row value is invalid (e.g. an odd number), frames may look sheared/skewed. + +Colors are in sRGB, uncorrelated ARGB, with alpha byte first. + +`gifski_add_frame_rgba` is preferred over this function. +*/ +GifskiError gifski_add_frame_argb(gifski *handle, + uint32_t frame_number, + uint32_t width, + uint32_t bytes_per_row, + uint32_t height, + const unsigned char *pixels, + double presentation_timestamp); + +/** Same as `gifski_add_frame_rgba_stride`, except it expects RGB components (3 bytes per pixel) + +Bytes per row must be multiple of 3, and greater or equal width×3. +If the bytes per row value is invalid (not multiple of 3), frames may look sheared/skewed. + +Colors are in sRGB, red byte first. + +`gifski_add_frame_rgba` is preferred over this function. +*/ +GifskiError gifski_add_frame_rgb(gifski *handle, + uint32_t frame_number, + uint32_t width, + uint32_t bytes_per_row, + uint32_t height, + const unsigned char *pixels, + double presentation_timestamp); + +/** + * Get a callback for frame processed, and abort processing if desired. + * + * The callback is called once per input frame, + * even if the encoder decides to skip some frames. + * + * It gets arbitrary pointer (`user_data`) as an argument. `user_data` can be `NULL`. + * + * The callback must return `1` to continue processing, or `0` to abort. + * + * The callback must be thread-safe (it will be called from another thread). + * It must remain valid at all times, until `gifski_finish` completes. + * + * This function must be called before `gifski_set_file_output()` to take effect. + */ +void gifski_set_progress_callback(gifski *handle, int (*progress_callback)(void *user_data), void *user_data); + +/** + * Get a callback when an error occurs. + * This is intended mostly for logging and debugging, not for user interface. + * + * The callback function has the following arguments: + * * A `\0`-terminated C string in UTF-8 encoding. The string is only valid for the duration of the call. Make a copy if you need to keep it. + * * An arbitrary pointer (`user_data`). `user_data` can be `NULL`. + * + * The callback must be thread-safe (it will be called from another thread). + * It must remain valid at all times, until `gifski_finish` completes. + * + * If the callback is not set, errors will be printed to stderr. + * + * This function must be called before `gifski_set_file_output()` to take effect. + */ +GifskiError gifski_set_error_message_callback(gifski *handle, void (*error_message_callback)(const char*, void*), void *user_data); + +/** + * Start writing to the file at `destination_path` (overwrites if needed). + * The file path must be ASCII or valid UTF-8. + * + * This function has to be called before any frames are added. + * This call will not block. + * + * Returns 0 (`GIFSKI_OK`) on success, and non-0 `GIFSKI_*` constant on error. + */ +GifskiError gifski_set_file_output(gifski *handle, const char *destination_path); + +/** + * Start writing via callback (any buffer, file, whatever you want). This has to be called before any frames are added. + * This call will not block. + * + * The callback function receives 3 arguments: + * - size of the buffer to write, in bytes. IT MAY BE ZERO (when it's zero, either do nothing, or flush internal buffers if necessary). + * - pointer to the buffer. + * - context pointer to arbitrary user data, same as passed in to this function. + * + * The callback should return 0 (`GIFSKI_OK`) on success, and non-zero on error. + * + * The callback function must be thread-safe. It must remain valid at all times, until `gifski_finish` completes. + * + * Returns 0 (`GIFSKI_OK`) on success, and non-0 `GIFSKI_*` constant on error. + */ +GifskiError gifski_set_write_callback(gifski *handle, + int (*write_callback)(size_t buffer_length, const uint8_t *buffer, void *user_data), + void *user_data); + +/** + * The last step: + * - stops accepting any more frames (gifski_add_frame_* calls are blocked) + * - blocks and waits until all already-added frames have finished writing + * + * Returns final status of write operations. Remember to check the return value! + * + * Must always be called, otherwise it will leak memory. + * After this call, the handle is freed and can't be used any more. + * + * Returns 0 (`GIFSKI_OK`) on success, and non-0 `GIFSKI_*` constant on error. + */ +GifskiError gifski_finish(gifski *g); + +#ifdef __cplusplus +} +#endif diff --git a/datafiles/gifski/win/gifski.exe b/datafiles/gifski/win/gifski.exe new file mode 100644 index 000000000..e538b708d Binary files /dev/null and b/datafiles/gifski/win/gifski.exe differ diff --git a/objects/o_dialog_about/Create_0.gml b/objects/o_dialog_about/Create_0.gml index 8aef650b5..475b5fbf9 100644 --- a/objects/o_dialog_about/Create_0.gml +++ b/objects/o_dialog_about/Create_0.gml @@ -37,7 +37,7 @@ event_inherited(); draw_text(cx, yy, "Special Thanks"); for( var i = 0; i < array_length(credits); i++ ) { - yy += line_height(, 8); + yy += line_get_height(, 8); draw_set_font(f_p2); draw_set_color(COLORS._main_text_sub); draw_text(cx, yy, credits[i][0]); diff --git a/objects/o_dialog_about/Draw_64.gml b/objects/o_dialog_about/Draw_64.gml index 3d34168c8..63c20e406 100644 --- a/objects/o_dialog_about/Draw_64.gml +++ b/objects/o_dialog_about/Draw_64.gml @@ -15,7 +15,7 @@ if !ready exit; draw_set_text(f_h3, fa_center, fa_top, COLORS._main_text_accent); draw_text(cx, ly, "Pixel Composer"); - ly += line_height(); + ly += line_get_height(); draw_set_text(f_p0, fa_center, fa_top, COLORS._main_text_sub); draw_text(cx, ly, "2021, MakhamDev"); diff --git a/objects/o_dialog_arrayBox/Alarm_0.gml b/objects/o_dialog_arrayBox/Alarm_0.gml index 0b4dc17a7..4ca552455 100644 --- a/objects/o_dialog_arrayBox/Alarm_0.gml +++ b/objects/o_dialog_arrayBox/Alarm_0.gml @@ -1,6 +1,6 @@ /// @description init #region pos - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var hh = array_length(arrayBox.data) * hght; dialog_h = min(max_h, hh); diff --git a/objects/o_dialog_arrayBox/Create_0.gml b/objects/o_dialog_arrayBox/Create_0.gml index aac9d2b67..d0632f19f 100644 --- a/objects/o_dialog_arrayBox/Create_0.gml +++ b/objects/o_dialog_arrayBox/Create_0.gml @@ -14,7 +14,7 @@ event_inherited(); sc_content = new scrollPane(0, 0, function(_y, _m) { draw_clear_alpha(COLORS.panel_bg_clear, 0); - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var _h = array_length(arrayBox.data) * hght; var _dw = sc_content.surface_w; var array = arrayBox.arraySet; diff --git a/objects/o_dialog_crashed/Draw_64.gml b/objects/o_dialog_crashed/Draw_64.gml index 91caf0b7a..6088bb914 100644 --- a/objects/o_dialog_crashed/Draw_64.gml +++ b/objects/o_dialog_crashed/Draw_64.gml @@ -15,7 +15,7 @@ draw_set_alpha(1); var py = dialog_y + ui(16); draw_set_text(f_h5, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(24), py, get_text("crashed_title", "Restore project")); - py += line_height(, 4); + py += line_get_height(, 4); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); draw_text(dialog_x + ui(24), py, get_text("crashed_content", "Restore previous project before crash?")); diff --git a/objects/o_dialog_exit/Draw_64.gml b/objects/o_dialog_exit/Draw_64.gml index 0b87454a5..c86eb393e 100644 --- a/objects/o_dialog_exit/Draw_64.gml +++ b/objects/o_dialog_exit/Draw_64.gml @@ -16,7 +16,7 @@ draw_set_alpha(1); var py = dialog_y + ui(16); draw_set_text(f_h5, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(24), py, "Project modified"); - py += line_height(, 4); + py += line_get_height(, 4); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); draw_text(dialog_x + ui(24), py, "Save progress before exit?"); diff --git a/objects/o_dialog_file_name_collection/Draw_64.gml b/objects/o_dialog_file_name_collection/Draw_64.gml index 41389b6d1..d1ccc8168 100644 --- a/objects/o_dialog_file_name_collection/Draw_64.gml +++ b/objects/o_dialog_file_name_collection/Draw_64.gml @@ -99,8 +99,8 @@ draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(16), yy, get_text("description", "Description")); - yy += line_height() + ui(4); - dialog_h += line_height() + ui(4); + yy += line_get_height() + ui(4); + dialog_h += line_get_height() + ui(4); t_desc.setActiveFocus(sFOCUS, sHOVER); t_desc.register(); @@ -110,8 +110,8 @@ draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(16), yy, get_text("author", "Author")); - yy += line_height() + ui(4); - dialog_h += line_height() + ui(4); + yy += line_get_height() + ui(4); + dialog_h += line_get_height() + ui(4); t_auth.setActiveFocus(sFOCUS, sHOVER); t_auth.register(); @@ -121,8 +121,8 @@ draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(16), yy, get_text("contact_info", "Contact info")); - yy += line_height() + ui(4); - dialog_h += line_height() + ui(4); + yy += line_get_height() + ui(4); + dialog_h += line_get_height() + ui(4); t_cont.setActiveFocus(sFOCUS, sHOVER); t_cont.register(); @@ -132,8 +132,8 @@ draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(16), yy, get_text("alias", "Alias")); - yy += line_height() + ui(4); - dialog_h += line_height() + ui(4); + yy += line_get_height() + ui(4); + dialog_h += line_get_height() + ui(4); t_alias.setActiveFocus(sFOCUS, sHOVER); t_alias.register(); @@ -143,8 +143,8 @@ draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(16), yy, get_text("tags", "Tags")); - yy += line_height() + ui(4); - dialog_h += line_height() + ui(4); + yy += line_get_height() + ui(4); + dialog_h += line_get_height() + ui(4); t_tags.setActiveFocus(sFOCUS, sHOVER); t_tags.register(); diff --git a/objects/o_dialog_fontscrollbox/Alarm_0.gml b/objects/o_dialog_fontscrollbox/Alarm_0.gml index 1dbe25baa..716ab4b7b 100644 --- a/objects/o_dialog_fontscrollbox/Alarm_0.gml +++ b/objects/o_dialog_fontscrollbox/Alarm_0.gml @@ -1,6 +1,6 @@ /// @description init #region pos - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var hh = array_length(FONT_INTERNAL) * hght; dialog_h = min(max_h, hh); diff --git a/objects/o_dialog_fontscrollbox/Create_0.gml b/objects/o_dialog_fontscrollbox/Create_0.gml index 9785d5a6c..394b66aec 100644 --- a/objects/o_dialog_fontscrollbox/Create_0.gml +++ b/objects/o_dialog_fontscrollbox/Create_0.gml @@ -14,7 +14,7 @@ event_inherited(); sc_content = new scrollPane(0, 0, function(_y, _m) { draw_clear_alpha(COLORS.panel_bg_clear, 0); - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var data = FONT_INTERNAL; var _h = array_length(data) * hght; var _dw = sc_content.surface_w; diff --git a/objects/o_dialog_history/Create_0.gml b/objects/o_dialog_history/Create_0.gml index e0555049b..ecd4f5fae 100644 --- a/objects/o_dialog_history/Create_0.gml +++ b/objects/o_dialog_history/Create_0.gml @@ -52,7 +52,7 @@ event_inherited(); draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); - var lh = line_height() + ui(8); + var lh = line_get_height() + ui(8); var _h = 0, hh; var yy = _y + ui(8); diff --git a/objects/o_dialog_l_system/Create_0.gml b/objects/o_dialog_l_system/Create_0.gml index cd14a00e1..e7388af59 100644 --- a/objects/o_dialog_l_system/Create_0.gml +++ b/objects/o_dialog_l_system/Create_0.gml @@ -76,7 +76,7 @@ event_inherited(); } if(is_array(_f)) { - var hh = (line_height(f_p0b) + pad) * array_length(_f) + ui(16); + var hh = (line_get_height(f_p0b) + pad) * array_length(_f) + ui(16); BLEND_OVERRIDE draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, ui(8), yy, sp_note.surface_w - ui(16), hh, COLORS.dialog_lua_ref_bg, 1); @@ -87,7 +87,7 @@ event_inherited(); for( var j = 0; j < array_length(_f); j++ ) { var _t = _f[j][0]; var _c = _f[j][1]; - hh = line_height(f_p0b); + hh = line_get_height(f_p0b); draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_accent); draw_text(ui(32), yy, _t); diff --git a/objects/o_dialog_load/Draw_64.gml b/objects/o_dialog_load/Draw_64.gml index 248ec86cd..5db52485d 100644 --- a/objects/o_dialog_load/Draw_64.gml +++ b/objects/o_dialog_load/Draw_64.gml @@ -16,7 +16,7 @@ draw_set_alpha(1); var py = dialog_y + ui(16); draw_set_text(f_h5, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(24), py, "Project modified"); - py += line_height(, 4); + py += line_get_height(, 4); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); draw_text(dialog_x + ui(24), py, "Do you want to save progress?"); diff --git a/objects/o_dialog_lua_reference/Create_0.gml b/objects/o_dialog_lua_reference/Create_0.gml index ef695666c..002d6be49 100644 --- a/objects/o_dialog_lua_reference/Create_0.gml +++ b/objects/o_dialog_lua_reference/Create_0.gml @@ -28,7 +28,7 @@ event_inherited(); if(is_string(_f)) { draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text_accent); yy += ui(8); - var hh = line_height() + pad + ui(8); + var hh = line_get_height() + pad + ui(8); draw_text_over(ui(24), yy, _f); @@ -42,12 +42,12 @@ event_inherited(); var _func = array_length(_f) > 2? _f[2] : _f[0]; var _desp = array_safe_get(_f, 3, ""); var _args = array_safe_get(_f, 4, []); - var hh = line_height(); + var hh = line_get_height(); if(is_open[i]) { draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); hh += pad + string_height(_desp) + ui(8); if(array_length(_args)) - hh += (line_height() + ui(4)) * (array_length(_args) + 1) + ui(20); + hh += (line_get_height() + ui(4)) * (array_length(_args) + 1) + ui(20); } hh += pad * 2; @@ -63,12 +63,12 @@ event_inherited(); sp_note.surface_w, hh, COLORS.dialog_lua_ref_bg, 1); BLEND_NORMAL; - draw_sprite_ui(THEME.arrow, is_open[i]? 3 : 0, ui(16), yy + pad + line_height() / 2,,,, COLORS._main_icon); + draw_sprite_ui(THEME.arrow, is_open[i]? 3 : 0, ui(16), yy + pad + line_get_height() / 2,,,, COLORS._main_icon); draw_set_text(f_code, fa_left, fa_top, COLORS._main_text); draw_code(ui(28), yy + pad, _func); if(is_open[i]) { - var ty = yy + pad + line_height() + ui(4); + var ty = yy + pad + line_get_height() + ui(4); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text_sub); draw_text(ui(32), ty, _desp); @@ -76,9 +76,9 @@ event_inherited(); var ax0 = ui(64 + 16); var ax1 = ui(200); var ax2 = ui(320); - ty += line_height() + ui(12); + ty += line_get_height() + ui(12); - var ah = (line_height() + ui(4)) * (array_length(_args) + 1) + ui(8); + var ah = (line_get_height() + ui(4)) * (array_length(_args) + 1) + ui(8); draw_sprite_stretched_ext(THEME.ui_panel_bg, 0, ui(64), ty, sp_note.surface_w - ui(96), ah, COLORS.dialog_lua_ref_bg_args, 1); @@ -88,13 +88,13 @@ event_inherited(); draw_text(ax2, ty, "Description"); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); - ty += line_height() + ui(4); + ty += line_get_height() + ui(4); for( var j = 0; j < array_length(_args); j++ ) { draw_text(ax0, ty, _args[j][0]); draw_text(ax1, ty, _args[j][1]); draw_text(ax2, ty, _args[j][2]); - ty += line_height() + ui(4); + ty += line_get_height() + ui(4); } } } diff --git a/objects/o_dialog_migration/Draw_64.gml b/objects/o_dialog_migration/Draw_64.gml index 4fec3b92a..1fa4b07ac 100644 --- a/objects/o_dialog_migration/Draw_64.gml +++ b/objects/o_dialog_migration/Draw_64.gml @@ -15,7 +15,7 @@ draw_set_alpha(1); var py = dialog_y + ui(16); draw_set_text(f_h5, fa_left, fa_top, COLORS._main_text_title); draw_text(dialog_x + ui(24), py, get_text("dialog_migration_title", "Program directory changed in 1.13")); - py += line_height(, 4); + py += line_get_height(, 4); draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); draw_text_ext(dialog_x + ui(24), py, get_text("dialog_migration_content", diff --git a/objects/o_dialog_output_visibility/Create_0.gml b/objects/o_dialog_output_visibility/Create_0.gml index 76c7f4930..afcdd29fb 100644 --- a/objects/o_dialog_output_visibility/Create_0.gml +++ b/objects/o_dialog_output_visibility/Create_0.gml @@ -17,7 +17,7 @@ event_inherited(); draw_clear_alpha(COLORS._main_text, 0); if(node == noone) return 0; - var hh = line_height() + ui(8); + var hh = line_get_height() + ui(8); var _h = ds_list_size(node.outputs) * hh; for( var i = 0; i < ds_list_size(node.outputs); i++ ) { diff --git a/objects/o_dialog_preference/Draw_64.gml b/objects/o_dialog_preference/Draw_64.gml index 55f89fc9e..9551a80f2 100644 --- a/objects/o_dialog_preference/Draw_64.gml +++ b/objects/o_dialog_preference/Draw_64.gml @@ -19,7 +19,7 @@ if !ready exit; #region page var yy = dialog_y + ui(title_height); var yl = yy - ui(8); - var hg = line_height(f_p0, 16); + var hg = line_get_height(f_p0, 16); for(var i = 0; i < array_length(page); i++) { draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text); diff --git a/objects/o_dialog_preset/Create_0.gml b/objects/o_dialog_preset/Create_0.gml index dda2057c0..24850259d 100644 --- a/objects/o_dialog_preset/Create_0.gml +++ b/objects/o_dialog_preset/Create_0.gml @@ -21,7 +21,7 @@ event_inherited(); var pres = global.PRESETS_MAP[? folder]; var amo = array_length(pres); - var hh = line_height() + ui(8); + var hh = line_get_height() + ui(8); var _h = amo * (hh + ui(4)) + ui(32); for( var i = 0; i < amo; i++ ) { diff --git a/objects/o_dialog_scrollbox/Create_0.gml b/objects/o_dialog_scrollbox/Create_0.gml index 482c63548..8598a1dce 100644 --- a/objects/o_dialog_scrollbox/Create_0.gml +++ b/objects/o_dialog_scrollbox/Create_0.gml @@ -54,7 +54,7 @@ event_inherited(); } function setSize() { - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var hh = ui(16 + 24); for( var i = 0; i < array_length(data); i++ ) @@ -68,7 +68,7 @@ event_inherited(); sc_content = new scrollPane(0, 0, function(_y, _m) { draw_clear_alpha(COLORS.panel_bg_clear, 0); - var hght = line_height(f_p0, 8); + var hght = line_get_height(f_p0, 8); var _dw = sc_content.surface_w; var _h = 0; var _ly = _y; diff --git a/objects/o_dialog_splash/Create_0.gml b/objects/o_dialog_splash/Create_0.gml index bf2c04881..4d171bf43 100644 --- a/objects/o_dialog_splash/Create_0.gml +++ b/objects/o_dialog_splash/Create_0.gml @@ -45,7 +45,7 @@ event_inherited(); var ww = ui(264); var hh = 0; var pad = ui(8); - var hgt = ui(16) + line_height(f_p0b) + line_height(f_p1); + var hgt = ui(16) + line_get_height(f_p0b) + line_get_height(f_p1); _y += pad; var col = expand? 2 : 1; @@ -92,11 +92,11 @@ event_inherited(); } } - var ly = recent_thumbnail? _y + hg - (line_height(f_p0b) + line_height(f_p1)) - ui(8) : _y + ui(8); + var ly = recent_thumbnail? _y + hg - (line_get_height(f_p0b) + line_get_height(f_p1)) - ui(8) : _y + ui(8); draw_set_text(f_p0b, fa_left, fa_top, COLORS._main_text); draw_text(fx + ui(12), ly, filename_name(_rec)); - ly += line_height(); + ly += line_get_height(); draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text_sub); draw_text_cut(fx + ui(12), ly, _rec, ww - ui(24)); } @@ -179,7 +179,7 @@ event_inherited(); draw_set_color(_project.tag == "Getting started"? COLORS._main_text_accent : COLORS._main_text_sub); draw_text(tx, ty - ui(2), _project.tag); - ty += line_height(); + ty += line_get_height(); } draw_set_text(f_p1, fa_center, fa_top, COLORS._main_text); diff --git a/objects/o_dialog_splash/Draw_64.gml b/objects/o_dialog_splash/Draw_64.gml index 4609f70a8..a38d16698 100644 --- a/objects/o_dialog_splash/Draw_64.gml +++ b/objects/o_dialog_splash/Draw_64.gml @@ -17,7 +17,7 @@ if !ready exit; var txt = "v. " + VERSION_STRING; draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text_sub); var ww = string_width(txt) + ui(16); - var hh = line_height(, 16); + var hh = line_get_height(, 16); if(buttonInstant(THEME.button_hide, bx, by - hh / 2, ww, hh, mouse_ui, sFOCUS, sHOVER) == 2) { dialogCall(o_dialog_release_note, WIN_W / 2, WIN_H / 2); } diff --git a/objects/o_main/Draw_75.gml b/objects/o_main/Draw_75.gml index 6cae73c77..98068d2bf 100644 --- a/objects/o_main/Draw_75.gml +++ b/objects/o_main/Draw_75.gml @@ -28,6 +28,9 @@ if(OS == os_windows && gameframe_is_minimized()) exit; 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("[" + get_text("tooltip_3d_object", "3D Object") + "]"); break; @@ -70,6 +73,9 @@ if(OS == os_windows && gameframe_is_minimized()) exit; txt += " (groups: " + string(array_length(content)) + ")"; draw_tooltip_text("[" + txt + "]"); break; + case VALUE_TYPE.atlas : + draw_tooltip_atlas(content); + break; } } else draw_tooltip_text(TOOLTIP); diff --git a/scripts/_node_VFX_spawner/_node_VFX_spawner.gml b/scripts/_node_VFX_spawner/_node_VFX_spawner.gml index 0862f938e..e8cbf3b93 100644 --- a/scripts/_node_VFX_spawner/_node_VFX_spawner.gml +++ b/scripts/_node_VFX_spawner/_node_VFX_spawner.gml @@ -34,8 +34,7 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co inputs[| 11] = nodeValue("Scale over time", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11 ); - inputs[| 12] = nodeValue("Color over lifetime", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 12] = nodeValue("Color over lifetime", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 13] = nodeValue("Alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1 ]) .setDisplay(VALUE_DISPLAY.range); @@ -78,8 +77,7 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co inputs[| 27] = nodeValue("Spawn", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true); - inputs[| 28] = nodeValue("Random blend", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 28] = nodeValue("Random blend", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 29] = nodeValue("Directed from center", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false, "Make particle move away from the spawn center."); diff --git a/scripts/buttonGradient/buttonGradient.gml b/scripts/buttonGradient/buttonGradient.gml index 19cc36f81..587e6412e 100644 --- a/scripts/buttonGradient/buttonGradient.gml +++ b/scripts/buttonGradient/buttonGradient.gml @@ -24,6 +24,8 @@ function buttonGradient(_onApply, dialog = noone) : widget() constructor { y = _y; w = _w; h = _h; + if(!is_instanceof(_gradient, gradientObject)) return; + current_gradient = _gradient; var click = false; diff --git a/scripts/byte_writer/byte_writer.gml b/scripts/byte_writer/byte_writer.gml new file mode 100644 index 000000000..014f58d3c --- /dev/null +++ b/scripts/byte_writer/byte_writer.gml @@ -0,0 +1,27 @@ +function buffer_write_int8_little(buffer, value) { + buffer_write(buffer, buffer_u8, clamp(value, -128, 127)); +} + +function buffer_write_int16_little(buffer, value) { + value = ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8); + buffer_write(buffer, buffer_s16, value); +} + +function buffer_write_int32_little(buffer, value) { + value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); + buffer_write(buffer, buffer_s32, value); +} + +function buffer_write_uint8_little(buffer, value) { + buffer_write(buffer, buffer_u8, clamp(value, 0, 255)); +} + +function buffer_write_uint16_little(buffer, value) { + value = ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8); + buffer_write(buffer, buffer_u16, value); +} + +function buffer_write_uint32_little(buffer, value) { + value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); + buffer_write(buffer, buffer_u32, value); +} diff --git a/scripts/byte_writer/byte_writer.yy b/scripts/byte_writer/byte_writer.yy new file mode 100644 index 000000000..bc1cd8578 --- /dev/null +++ b/scripts/byte_writer/byte_writer.yy @@ -0,0 +1,11 @@ +{ + "resourceType": "GMScript", + "resourceVersion": "1.0", + "name": "byte_writer", + "isCompatibility": false, + "isDnD": false, + "parent": { + "name": "importers", + "path": "folders/functions/importers.yy", + }, +} \ No newline at end of file diff --git a/scripts/draw_UI_scale/draw_UI_scale.gml b/scripts/draw_UI_scale/draw_UI_scale.gml index 5515cf733..790c5deb9 100644 --- a/scripts/draw_UI_scale/draw_UI_scale.gml +++ b/scripts/draw_UI_scale/draw_UI_scale.gml @@ -1,4 +1,4 @@ -function line_height(font = noone, offset = 0) { +function line_get_height(font = noone, offset = 0) { var ff = draw_get_font(); if(font != noone) @@ -9,7 +9,7 @@ function line_height(font = noone, offset = 0) { return hh; } -function line_width(txt, font = noone, offset = 0) { +function line_get_width(txt, font = noone, offset = 0) { var ff = draw_get_font(); if(font != noone) @@ -21,7 +21,7 @@ function line_width(txt, font = noone, offset = 0) { } #region global - #macro TEXTBOX_HEIGHT line_height(f_p0, 12) + #macro TEXTBOX_HEIGHT line_get_height(f_p0, 12) function ui(val) { gml_pragma("forceinline"); diff --git a/scripts/draw_tooltip/draw_tooltip.gml b/scripts/draw_tooltip/draw_tooltip.gml index 31300738f..884726c71 100644 --- a/scripts/draw_tooltip/draw_tooltip.gml +++ b/scripts/draw_tooltip/draw_tooltip.gml @@ -18,11 +18,6 @@ function draw_tooltip_color(clr) { return; } - if(is_struct(clr)) { - draw_tooltip_gradient(clr); - return; - } - var ww = ui(32); var hh = ui(32); @@ -120,4 +115,49 @@ function draw_tooltip_surface(surf) { draw_sprite_stretched(THEME.textbox, 0, mx, my, ww + ui(16), hh + ui(16)); draw_surface_ext_safe(surf, mx + ui(8), my + ui(8), ss, ss); +} + +function draw_tooltip_atlas(atlas) { + if(!is_array(atlas)) atlas = [ atlas ]; + + var amo = array_length(atlas); + var ww = ui(160); + var hh = amo * ui(48 + 8) - ui(8); + + var mx = min(mouse_mx + ui(16), WIN_W - (ww + ui(16))); + var my = min(mouse_my + ui(16), WIN_H - (hh + ui(16))); + + draw_sprite_stretched(THEME.textbox, 3, mx, my, ww + ui(16), hh + ui(16)); + draw_sprite_stretched(THEME.textbox, 0, mx, my, ww + ui(16), hh + ui(16)); + + var sx = mx + ui(8); + var sy = my + ui(8); + + for( var i = 0; i < amo; i++ ) { + var _y = sy + i * ui(48 + 8); + + var atl = atlas[i]; + var surf = atl.surface.get(); + + if(!is_surface(surf)) continue; + + var sw = surface_get_width(surf); + var sh = surface_get_height(surf); + + var ss = min(ui(48) / sw, ui(48) / sh); + draw_surface_ext_safe(surf, sx, _y, ss, ss); + + draw_set_color(COLORS._main_icon); + draw_rectangle(sx, _y, sx + ui(48), _y + ui(48), 1); + + draw_set_text(f_p3, fa_left, fa_top, COLORS._main_text_sub); + draw_text_add(sx + ui( 56), _y + ui( 0), "Position"); + draw_text_add(sx + ui( 56), _y + ui(16), "Rotation"); + draw_text_add(sx + ui( 56), _y + ui(32), "Scale"); + + draw_set_text(f_p3, fa_right, fa_top, COLORS._main_text); + draw_text_add(sx + ui(160), _y + ui( 0), atl.position); + draw_text_add(sx + ui(160), _y + ui(16), atl.rotation); + draw_text_add(sx + ui(160), _y + ui(32), atl.scale); + } } \ No newline at end of file diff --git a/scripts/globals/globals.gml b/scripts/globals/globals.gml index 9d5bd7612..b05ab318c 100644 --- a/scripts/globals/globals.gml +++ b/scripts/globals/globals.gml @@ -32,10 +32,10 @@ globalvar VERSION, SAVEFILE_VERSION, VERSION_STRING, BUILD_NUMBER; - VERSION = 1144; + VERSION = 1145; SAVEFILE_VERSION = 1440; - VERSION_STRING = "1.14.4.1"; - BUILD_NUMBER = 114400; + VERSION_STRING = "1.14.5"; + BUILD_NUMBER = 114500; globalvar NODES, NODE_MAP, APPEND_MAP, NODE_NAME_MAP; globalvar HOTKEYS, HOTKEY_CONTEXT, NODE_INSTANCES; diff --git a/scripts/globalvar_drawer/globalvar_drawer.gml b/scripts/globalvar_drawer/globalvar_drawer.gml index c6b06322b..4beaf52ad 100644 --- a/scripts/globalvar_drawer/globalvar_drawer.gml +++ b/scripts/globalvar_drawer/globalvar_drawer.gml @@ -4,7 +4,7 @@ function globalvar_viewer_init() { function globalvar_viewer_draw(xx, yy, ww, _m, focus, hover, _scrollPane, rx, ry) { var hh = 0; - var lb_h = line_height(f_p0) + ui(8); + var lb_h = line_get_height(f_p0) + ui(8); var padd = ui(8); if(var_editing) { diff --git a/scripts/meta_data/meta_data.gml b/scripts/meta_data/meta_data.gml index 29ce294a3..57393cef0 100644 --- a/scripts/meta_data/meta_data.gml +++ b/scripts/meta_data/meta_data.gml @@ -23,11 +23,11 @@ function MetaDataManager() constructor { steam = false; static displays = [ - [ get_text("description", "Description"), function(meta) { return meta.description; } , line_height() * 5], - [ get_text("author", "Author"), function(meta) { return meta.author; } , line_height() ], - [ get_text("contact_info", "Contact info"), function(meta) { return meta.contact; } , line_height() ], - [ get_text("alias", "Alias"), function(meta) { return meta.alias; } , line_height() ], - [ get_text("tags", "Tags"), function(meta) { return meta.tags; } , line_height() ], + [ get_text("description", "Description"), function(meta) { return meta.description; } , line_get_height() * 5], + [ get_text("author", "Author"), function(meta) { return meta.author; } , line_get_height() ], + [ get_text("contact_info", "Contact info"), function(meta) { return meta.contact; } , line_get_height() ], + [ get_text("alias", "Alias"), function(meta) { return meta.alias; } , line_get_height() ], + [ get_text("tags", "Tags"), function(meta) { return meta.tags; } , line_get_height() ], ]; static serialize = function() { @@ -130,7 +130,7 @@ function MetaDataManager() constructor { draw_set_font(f_p0); _h += ui(8); var tx = 0; - var hh = line_height(f_p0, ui(4)); + var hh = line_get_height(f_p0, ui(4)); var th = hh; for( var i = 0; i < array_length(tags); i++ ) { var ww = string_width(tags[i]) + ui(16); @@ -191,7 +191,7 @@ function MetaDataManager() constructor { draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text); ty += ui(8); var tx = 0; - var hh = line_height(f_p0, ui(4)); + var hh = line_get_height(f_p0, ui(4)); for( var i = 0; i < array_length(tags); i++ ) { var ww = string_width(tags[i]) + ui(16); diff --git a/scripts/nodeValue_drawer/nodeValue_drawer.gml b/scripts/nodeValue_drawer/nodeValue_drawer.gml index e69605831..220a2230a 100644 --- a/scripts/nodeValue_drawer/nodeValue_drawer.gml +++ b/scripts/nodeValue_drawer/nodeValue_drawer.gml @@ -11,7 +11,7 @@ function drawWidget(xx, yy, ww, _m, jun, global_var = true, _hover = false, _foc var con_w = ww - ui(4); var xc = xx + ww / 2; - var lb_h = line_height(f_p0) + ui(8); + var lb_h = line_get_height(f_p0) + ui(8); var lb_y = yy + lb_h / 2; var butx = xx; @@ -265,6 +265,9 @@ function drawWidget(xx, yy, ww, _m, jun, global_var = true, _hover = false, _foc case VALUE_TYPE.color : jun.editWidget.draw(editBoxX, editBoxY, editBoxW, editBoxH, jun.showValue(), _m); break; + case VALUE_TYPE.gradient : + jun.editWidget.draw(editBoxX, editBoxY, editBoxW, editBoxH, jun.showValue(), _m); + break; case VALUE_TYPE.path : switch(jun.display_type) { case VALUE_DISPLAY.path_load : diff --git a/scripts/node_ase_file_read/node_ase_file_read.gml b/scripts/node_ase_file_read/node_ase_file_read.gml index 4e14f5525..501292244 100644 --- a/scripts/node_ase_file_read/node_ase_file_read.gml +++ b/scripts/node_ase_file_read/node_ase_file_read.gml @@ -89,7 +89,7 @@ function Node_ASE_File_Read(_x, _y, _group = noone) : Node(_x, _y, _group) const var current_tag = inputs[| 2].getValue(); var amo = array_length(tags); var abx = ui(24); - var lb_h = line_height(f_p0); + var lb_h = line_get_height(f_p0); var lb_y = _y + lb_h / 2 + ui(6); var by = _y; diff --git a/scripts/node_colorize/node_colorize.gml b/scripts/node_colorize/node_colorize.gml index 0edef932e..872af8077 100644 --- a/scripts/node_colorize/node_colorize.gml +++ b/scripts/node_colorize/node_colorize.gml @@ -11,8 +11,7 @@ function Node_Colorize(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) inputs[| 0] = nodeValue("Surface in", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0); - inputs[| 1] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject([ c_black, c_white ]) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 1] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject([ c_black, c_white ]) ); inputs[| 2] = nodeValue("Gradient shift", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) .setDisplay(VALUE_DISPLAY.slider, [ -1, 1, .01 ]); diff --git a/scripts/node_composite/node_composite.gml b/scripts/node_composite/node_composite.gml index d06041bf4..47f4dafce 100644 --- a/scripts/node_composite/node_composite.gml +++ b/scripts/node_composite/node_composite.gml @@ -244,7 +244,8 @@ function Node_Composite(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); - outputs[| 1] = nodeValue("Atlas data", self, JUNCTION_CONNECT.output, VALUE_TYPE.atlas, []); + outputs[| 1] = nodeValue("Atlas data", self, JUNCTION_CONNECT.output, VALUE_TYPE.atlas, []) + .rejectArrayProcess(); temp_surface = [ surface_create(1, 1), surface_create(1, 1) ]; @@ -717,6 +718,7 @@ function Node_Composite(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) static process_data = function(_outSurf, _data, _output_index, _array_index) { if(_output_index == 1) return atlas_data; + if(_output_index == 0 && _array_index == 0) atlas_data = []; if(array_length(_data) < 4) return _outSurf; var _pad = _data[0]; @@ -766,7 +768,6 @@ function Node_Composite(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) var res_index = 0, bg = 0; var imageAmo = (ds_list_size(inputs) - input_fix_len) / data_length; var _vis = attributes[? "layer_visible"]; - atlas_data = []; surface_set_shader(_outSurf, sh_sample, true, BLEND.alphamulp); diff --git a/scripts/node_display_text/node_display_text.gml b/scripts/node_display_text/node_display_text.gml index dfafae6f9..20f9c8db2 100644 --- a/scripts/node_display_text/node_display_text.gml +++ b/scripts/node_display_text/node_display_text.gml @@ -237,7 +237,7 @@ function Node_Display_Text(_x, _y, _group = noone) : Node(_x, _y, _group) constr draw_set_text(font, fa_left, fa_top, color); for( var i = 0; i < array_length(_lines); i++ ) { var _line = _lines[i]; - var _h = line_height(font); + var _h = line_get_height(font); var _w = draw_text_style(tx, ty, _line, _s); ww = max(ww, _w); diff --git a/scripts/node_export/node_export.gml b/scripts/node_export/node_export.gml index e7418a06b..7ca766b83 100644 --- a/scripts/node_export/node_export.gml +++ b/scripts/node_export/node_export.gml @@ -103,6 +103,8 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor magick = working_directory + "ImageMagick/magick.exe"; webp = working_directory + "webp/webpmux.exe"; + gifski = working_directory + "gifski\\win\\gifski.exe"; + static onValueUpdate = function(_index) { var form = inputs[| 3].getValue(); @@ -200,31 +202,33 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor } static renderGif = function(temp_path, target_path) { - var loop = inputs[| 5].getValue(); - var opti = inputs[| 6].getValue(); - var fuzz = inputs[| 7].getValue(); - var rate = inputs[| 8].getValue(); + var loop = inputs[| 5].getValue(); + var opti = inputs[| 6].getValue(); + var fuzz = inputs[| 7].getValue(); + var rate = inputs[| 8].getValue(); + var qual = inputs[| 10].getValue(); if(rate == 0) rate = 1; - var framerate = 100 / rate; - var loop_str = loop? 0 : 1; + 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 " + string(framerate) + - " -alpha set" + - " -dispose previous" + - " -loop " + string(loop_str); - - if(opti) { - shell_cmd += " -fuzz " + string(fuzz * 100) + "%" + - " -layers OptimizeFrame" + - " -layers OptimizeTransparency"; + if(use_gifski) { + var shell_cmd = $"-o {target_path} -r {rate} --repeat {loop_str} -Q {qual} "; + shell_cmd += temp_path; + + //print($"{gifski} {shell_cmd}"); + execute_shell(gifski, shell_cmd); + } else { + var shell_cmd = $"-delay {string(framerate)} -alpha set -dispose previous -loop {string(loop_str)}"; + if(opti) shell_cmd += $" -fuzz {string(fuzz * 100)}% -layers OptimizeFrame -layers OptimizeTransparency"; + shell_cmd += " " + temp_path + " " + target_path; + + //print($"{converter} {shell_cmd}"); + execute_shell(converter, shell_cmd); } - shell_cmd += " " + temp_path + - " " + target_path; - - execute_shell(converter, shell_cmd); - var noti = log_message("EXPORT", "Export gif as " + target_path, THEME.noti_icon_tick, COLORS._main_value_positive, false); noti.path = filename_dir(target_path); noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer); @@ -476,7 +480,7 @@ function Node_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor if(anim == NODE_EXPORT_FORMAT.gif) { inputs[| 9].display_data = format_animation; inputs[| 9].editWidget.data_list = format_animation; - inputs[| 10].setVisible(extn == 1); + inputs[| 10].setVisible(true); } else { inputs[| 9].display_data = format_image; inputs[| 9].editWidget.data_list = format_image; diff --git a/scripts/node_global/node_global.gml b/scripts/node_global/node_global.gml index 8819db71f..d2ac72367 100644 --- a/scripts/node_global/node_global.gml +++ b/scripts/node_global/node_global.gml @@ -1,8 +1,8 @@ function variable_editor(nodeVal) constructor { value = nodeVal; - val_type = [ VALUE_TYPE.integer, VALUE_TYPE.float, VALUE_TYPE.boolean, VALUE_TYPE.color, VALUE_TYPE.path, VALUE_TYPE.curve, VALUE_TYPE.text ]; - val_type_name = [ "Integer", "Float", "Boolean", "Color", "Path", "Curve", "Text" ]; + val_type = [ VALUE_TYPE.integer, VALUE_TYPE.float, VALUE_TYPE.boolean, VALUE_TYPE.color, VALUE_TYPE.gradient, VALUE_TYPE.path, VALUE_TYPE.curve, VALUE_TYPE.text ]; + val_type_name = [ "Integer", "Float", "Boolean", "Color", "Gradient", "Path", "Curve", "Text" ]; display_list = [ /*Integer*/ [ "Default", "Range", "Rotation", "Rotation range", "Slider", "Slider range", "Padding", "Vector2", "Vector3", "Vector4", "Vector range", "Vector2 range", "Area" ], /*Float*/ [ "Default", "Range", "Rotation", "Rotation range", "Slider", "Slider range", "Padding", "Vector2", "Vector3", "Vector4", "Vector range", "Vector2 range", "Area" ], @@ -93,9 +93,6 @@ function variable_editor(nodeVal) constructor { break; case VALUE_TYPE.color : switch(sc_disp.data_list[disp_index]) { - case "Gradient" : - value.setValue(new gradientObject(c_black)); - break; case "Palette" : value.setValue([0]); break; @@ -104,6 +101,9 @@ function variable_editor(nodeVal) constructor { break; } break; + case VALUE_TYPE.gradient : + value.setValue(new gradientObject(c_black)); + break; case VALUE_TYPE.boolean : value.setValue(false); break; @@ -135,7 +135,6 @@ function variable_editor(nodeVal) constructor { case "Vector range" : value.setDisplay(VALUE_DISPLAY.vector_range); break; case "Vector2 range" : value.setDisplay(VALUE_DISPLAY.vector_range); break; case "Area" : value.setDisplay(VALUE_DISPLAY.area); break; - case "Gradient" : value.setDisplay(VALUE_DISPLAY.gradient); break; case "Palette" : value.setDisplay(VALUE_DISPLAY.palette); break; case "Import" : value.setDisplay(VALUE_DISPLAY.path_load, ["", ""]); break; diff --git a/scripts/node_gradient/node_gradient.gml b/scripts/node_gradient/node_gradient.gml index 6b564d5b8..6f5053fab 100644 --- a/scripts/node_gradient/node_gradient.gml +++ b/scripts/node_gradient/node_gradient.gml @@ -18,8 +18,7 @@ function Node_Gradient(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, def_surf_size2 ) .setDisplay(VALUE_DISPLAY.vector); - inputs[| 1] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 1] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 2] = nodeValue("Type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) .setDisplay(VALUE_DISPLAY.enum_scroll, [ "Linear", "Circular", "Radial" ]); diff --git a/scripts/node_gradient_extract/node_gradient_extract.gml b/scripts/node_gradient_extract/node_gradient_extract.gml index bb13df56c..129dc29e8 100644 --- a/scripts/node_gradient_extract/node_gradient_extract.gml +++ b/scripts/node_gradient_extract/node_gradient_extract.gml @@ -4,8 +4,7 @@ function Node_Gradient_Extract(_x, _y, _group = noone) : Node_Processor(_x, _y, w = 96; - inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient) + inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) .setVisible(true, true); outputs[| 0] = nodeValue("Colors", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, [] ) diff --git a/scripts/node_gradient_output/node_gradient_output.gml b/scripts/node_gradient_output/node_gradient_output.gml index fdc16e435..c810a5e37 100644 --- a/scripts/node_gradient_output/node_gradient_output.gml +++ b/scripts/node_gradient_output/node_gradient_output.gml @@ -4,15 +4,13 @@ function Node_Gradient_Out(_x, _y, _group = noone) : Node_Processor(_x, _y, _gro w = 96; - inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 1] = nodeValue("Sample", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0, "Position to sample a color from the gradient.") .setDisplay(VALUE_DISPLAY.slider, [0, 1, 0.01]) .rejectArray(); - outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.gradient, new gradientObject(c_white) ); outputs[| 1] = nodeValue("Color", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, c_white); diff --git a/scripts/node_gradient_palette/node_gradient_palette.gml b/scripts/node_gradient_palette/node_gradient_palette.gml index 9b2129aba..fedbe5d62 100644 --- a/scripts/node_gradient_palette/node_gradient_palette.gml +++ b/scripts/node_gradient_palette/node_gradient_palette.gml @@ -1,5 +1,5 @@ function Node_Gradient_Palette(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { - name = "Gradient Palette"; + name = "Palette to Gradient"; previewable = false; w = 96; @@ -17,8 +17,7 @@ function Node_Gradient_Palette(_x, _y, _group = noone) : Node_Processor(_x, _y, inputs[| 3] = nodeValue("Blending", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) .setDisplay(VALUE_DISPLAY.enum_button, [ "RGB", "HSV", "Hard" ]); - outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.gradient, new gradientObject(c_white) ) _pal = -1; diff --git a/scripts/node_gradient_replace/node_gradient_replace.gml b/scripts/node_gradient_replace/node_gradient_replace.gml index 29e43b9bd..139212d62 100644 --- a/scripts/node_gradient_replace/node_gradient_replace.gml +++ b/scripts/node_gradient_replace/node_gradient_replace.gml @@ -4,8 +4,7 @@ function Node_Gradient_Replace_Color(_x, _y, _group = noone) : Node_Processor(_x w = 96; - inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient) + inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) .setVisible(true, true); inputs[| 1] = nodeValue("Color from", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, [ c_black ]) @@ -17,8 +16,7 @@ function Node_Gradient_Replace_Color(_x, _y, _group = noone) : Node_Processor(_x inputs[| 3] = nodeValue("Threshold", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) .setDisplay(VALUE_DISPLAY.slider, [0, 1, 0.01]); - outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.gradient, new gradientObject(c_white) ); static process_data = function(_outSurf, _data, _output_index, _array_index) { var gra = _data[0]; diff --git a/scripts/node_gradient_shift/node_gradient_shift.gml b/scripts/node_gradient_shift/node_gradient_shift.gml index 7bbf96ec2..a341d3dfe 100644 --- a/scripts/node_gradient_shift/node_gradient_shift.gml +++ b/scripts/node_gradient_shift/node_gradient_shift.gml @@ -4,8 +4,7 @@ function Node_Gradient_Shift(_x, _y, _group = noone) : Node_Processor(_x, _y, _g w = 96; - inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient) + inputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ) .setDisplay(true, true); inputs[| 1] = nodeValue("Shift", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) @@ -16,8 +15,7 @@ function Node_Gradient_Shift(_x, _y, _group = noone) : Node_Processor(_x, _y, _g inputs[| 3] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) .setDisplay(VALUE_DISPLAY.slider, [0, 2, 0.01]); - outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + outputs[| 0] = nodeValue("Gradient", self, JUNCTION_CONNECT.output, VALUE_TYPE.gradient, new gradientObject(c_white) ); _pal = -1; diff --git a/scripts/node_grid/node_grid.gml b/scripts/node_grid/node_grid.gml index 7aa3c788a..2a431b6a3 100644 --- a/scripts/node_grid/node_grid.gml +++ b/scripts/node_grid/node_grid.gml @@ -34,8 +34,7 @@ function Node_Grid(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons inputs[| 4] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) .setDisplay(VALUE_DISPLAY.rotation); - inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 6] = nodeValue("Gap color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_black); diff --git a/scripts/node_grid_hex/node_grid_hex.gml b/scripts/node_grid_hex/node_grid_hex.gml index a29bebeec..f4aa1ce18 100644 --- a/scripts/node_grid_hex/node_grid_hex.gml +++ b/scripts/node_grid_hex/node_grid_hex.gml @@ -32,8 +32,7 @@ function Node_Grid_Hex(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) inputs[| 4] = nodeValue("Gap", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.1) .setDisplay(VALUE_DISPLAY.slider, [0, 0.5, 0.01]); - inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 6] = nodeValue("Gap color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_black); diff --git a/scripts/node_grid_tri/node_grid_tri.gml b/scripts/node_grid_tri/node_grid_tri.gml index 7c1c75b6d..c0daaf2db 100644 --- a/scripts/node_grid_tri/node_grid_tri.gml +++ b/scripts/node_grid_tri/node_grid_tri.gml @@ -32,8 +32,7 @@ function Node_Grid_Tri(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) inputs[| 4] = nodeValue("Angle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) .setDisplay(VALUE_DISPLAY.rotation); - inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 5] = nodeValue("Tile color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 6] = nodeValue("Gap color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, c_black); diff --git a/scripts/node_group_input/node_group_input.gml b/scripts/node_group_input/node_group_input.gml index 604d47fff..b735807f1 100644 --- a/scripts/node_group_input/node_group_input.gml +++ b/scripts/node_group_input/node_group_input.gml @@ -107,7 +107,7 @@ function Node_Group_Input(_x, _y, _group = noone) : Node(_x, _y, _group) constru _dtype = display_list[_val_type][_dtype]; - inParent.type = _val_type; + inParent.type = _val_type; outputs[| 0].type = _val_type; var _val = inParent.getValue(); @@ -177,8 +177,11 @@ function Node_Group_Input(_x, _y, _group = noone) : Node(_x, _y, _group) constru break; case "Gradient": + inParent.type = VALUE_TYPE.gradient; + outputs[| 0].type = inParent.type; + inParent.animator = new valueAnimator(new gradientObject(c_white), inParent); - inParent.setDisplay(VALUE_DISPLAY.gradient); + inParent.setDisplay(VALUE_DISPLAY._default); break; default: inParent.setDisplay(VALUE_DISPLAY._default); break; } diff --git a/scripts/node_keyframe/node_keyframe.gml b/scripts/node_keyframe/node_keyframe.gml index 35b1f2942..8d2c9e934 100644 --- a/scripts/node_keyframe/node_keyframe.gml +++ b/scripts/node_keyframe/node_keyframe.gml @@ -142,7 +142,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor { if(ds_list_size(values) == 1) return processType(values[| 0].value); - if(prop.display_type == VALUE_DISPLAY.gradient) + if(prop.type == VALUE_TYPE.gradient) return values[| 0].value; if(prop.type == VALUE_TYPE.path) @@ -389,7 +389,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor { static deserialize = function(_list, scale = false) { ds_list_clear(values); - if(prop.type == VALUE_TYPE.color && prop.display_type == VALUE_DISPLAY.gradient && LOADING_VERSION < 1340 && !CLONING) { //backward compat: Gradient + if(prop.type == VALUE_TYPE.gradient && LOADING_VERSION < 1340 && !CLONING) { //backward compat: Gradient var _val = []; var value = _list[| 0][| 1]; @@ -430,7 +430,7 @@ function valueAnimator(_val, _prop, _sep_axis = false) constructor { else if(prop.type == VALUE_TYPE.path && prop.display_type == VALUE_DISPLAY.path_array) { for(var j = 0; j < ds_list_size(value); j++) _val[j] = value[| j]; - } else if(prop.type == VALUE_TYPE.color && prop.display_type == VALUE_DISPLAY.gradient) { + } else if(prop.type == VALUE_TYPE.gradient) { var grad = new gradientObject(); _val = grad.deserialize(value); } else if(!sep_axis && typeArray(prop.display_type)) { diff --git a/scripts/node_line/node_line.gml b/scripts/node_line/node_line.gml index f1263a616..230350d54 100644 --- a/scripts/node_line/node_line.gml +++ b/scripts/node_line/node_line.gml @@ -30,8 +30,7 @@ function Node_Line(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) cons inputs[| 9] = nodeValue("Shift", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) .setDisplay(VALUE_DISPLAY._default, 1 / 64); - inputs[| 10] = nodeValue("Color over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 10] = nodeValue("Color over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 11] = nodeValue("Width over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11); diff --git a/scripts/node_pixel_cloud/node_pixel_cloud.gml b/scripts/node_pixel_cloud/node_pixel_cloud.gml index 0435e732a..7149ea196 100644 --- a/scripts/node_pixel_cloud/node_pixel_cloud.gml +++ b/scripts/node_pixel_cloud/node_pixel_cloud.gml @@ -27,8 +27,7 @@ function Node_Pixel_Cloud(_x, _y, _group = noone) : Node_Processor(_x, _y, _grou inputs[| 3] = nodeValue("Strength map", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0); - inputs[| 4] = nodeValue("Color over lifetime", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 4] = nodeValue("Color over lifetime", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 5] = nodeValue("Distance", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1); diff --git a/scripts/node_plot_linear/node_plot_linear.gml b/scripts/node_plot_linear/node_plot_linear.gml index 6c1b2435c..fd0840bf2 100644 --- a/scripts/node_plot_linear/node_plot_linear.gml +++ b/scripts/node_plot_linear/node_plot_linear.gml @@ -34,8 +34,7 @@ function Node_Plot_Linear(_x, _y, _group = noone) : Node_Processor(_x, _y, _grou inputs[| 12] = nodeValue("Value Offset", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0); - inputs[| 13] = nodeValue("Color Over Sample", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white)) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 13] = nodeValue("Color Over Sample", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white)); inputs[| 14] = nodeValue("Trim mode", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) .setDisplay(VALUE_DISPLAY.enum_scroll, [ "Range", "Window" ]); diff --git a/scripts/node_processor/node_processor.gml b/scripts/node_processor/node_processor.gml index b80131eed..a28eee719 100644 --- a/scripts/node_processor/node_processor.gml +++ b/scripts/node_processor/node_processor.gml @@ -206,9 +206,13 @@ function Node_Processor(_x, _y, _group = noone) : Node(_x, _y, _group) construct process_length[i][1] = amoMax; } + var val; for(var i = 0; i < ds_list_size(outputs); i++) { - var val = preProcess(i); - if(val == undefined) continue; + if(outputs[| i].process_array) { + val = preProcess(i); + if(val == undefined) continue; + } else + val = process_data(noone, noone, i); outputs[| i].setValue(val); } } diff --git a/scripts/node_registry/node_registry.gml b/scripts/node_registry/node_registry.gml index 1dc407c33..f6916a882 100644 --- a/scripts/node_registry/node_registry.gml +++ b/scripts/node_registry/node_registry.gml @@ -230,6 +230,7 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor { addNodeObject(input, "ASE File In", s_node_ase_file, "Node_ASE_File_Read", [0, Node_create_ASE_File_Read],, "Load Aseprite file with support for layers, tags.").setVersion(1100); addNodeObject(input, "ASE Layer", s_node_ase_layer, "Node_ASE_layer", [1, Node_ASE_layer]).setVersion(1100); addNodeObject(input, "WAV File In", s_node_wav_file_read, "Node_WAV_File_Read", [0, Node_create_WAV_File_Read],, "Load wav audio file.").setVersion(1144); + addNodeObject(input, "WAV File Out", s_node_wav_file_write, "Node_WAV_File_Write", [1, Node_WAV_File_Write],, "Save wav audio file.").setVersion(1145); var transform = ds_list_create(); addNodeCatagory("Transform", transform); @@ -528,7 +529,7 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor { ds_list_add(color, "Gradient"); addNodeObject(color, "Gradient", s_node_gradient_out, "Node_Gradient_Out", [1, Node_Gradient_Out]); - addNodeObject(color, "Gradient Palette", s_node_gradient_palette, "Node_Gradient_Palette", [1, Node_Gradient_Palette],, "Create gradient from palette.").setVersion(1135); + addNodeObject(color, "Palette to Gradient", s_node_gradient_palette, "Node_Gradient_Palette", [1, Node_Gradient_Palette],, "Create gradient from palette.").setVersion(1135); addNodeObject(color, "Gradient Shift", s_node_gradient_shift, "Node_Gradient_Shift", [1, Node_Gradient_Shift],, "Move gradients keys."); addNodeObject(color, "Gradient Replace", s_node_gradient_replace, "Node_Gradient_Replace_Color", [1, Node_Gradient_Replace_Color]).setVersion(1135); addNodeObject(color, "Gradient Data", s_node_gradient_data, "Node_Gradient_Extract", [1, Node_Gradient_Extract],, "Get palatte and array of key positions from gradient.").setVersion(1135); @@ -541,11 +542,12 @@ function NodeObject(_name, _spr, _node, _create, tags = []) constructor { addNodeObject(animation, "Evaluate Curve", s_node_curve_eval, "Node_Anim_Curve", [1, Node_Anim_Curve],, "Evaluate value from an animation curve."); ds_list_add(animation, "Audio"); - addNodeObject(animation, "WAV File In", s_node_wav_file_read, "Node_WAV_File_Read", [0, Node_create_WAV_File_Read],, "Load wav audio file.").setVersion(1144); - addNodeObject(animation, "FFT", s_node_FFT, "Node_FFT", [1, Node_FFT], ["frequency analysis"], "Perform fourier transform on number array.").setVersion(1144); - addNodeObject(animation, "Bar / Graph", s_node_bar_graph, "Node_Plot_Linear", [1, Node_Plot_Linear], ["graph", "waveform", "bar chart", "plot"], "Plot graph or bar chart from array of number.").setVersion(1144); - addNodeObject(animation, "Audio Window",s_node_audio_trim, "Node_Audio_Window", [1, Node_Audio_Window],, "Take a slice of an audio array based on the current frame.").setVersion(1144); - + addNodeObject(animation, "WAV File In", s_node_wav_file_read, "Node_WAV_File_Read", [0, Node_create_WAV_File_Read],, "Load wav audio file.").setVersion(1144); + addNodeObject(animation, "WAV File Out", s_node_wav_file_write, "Node_WAV_File_Write", [1, Node_WAV_File_Write],, "Save wav audio file.").setVersion(1145); + addNodeObject(animation, "FFT", s_node_FFT, "Node_FFT", [1, Node_FFT], ["frequency analysis"], "Perform fourier transform on number array.").setVersion(1144); + addNodeObject(animation, "Bar / Graph", s_node_bar_graph, "Node_Plot_Linear", [1, Node_Plot_Linear], ["graph", "waveform", "bar chart", "plot"], "Plot graph or bar chart from array of number.").setVersion(1144); + addNodeObject(animation, "Audio Window", s_node_audio_trim, "Node_Audio_Window", [1, Node_Audio_Window],, "Take a slice of an audio array based on the current frame.").setVersion(1144); + var node = ds_list_create(); addNodeCatagory("Node", node); ds_list_add(node, "Logic"); diff --git a/scripts/node_repeat/node_repeat.gml b/scripts/node_repeat/node_repeat.gml index eb43192a0..5df9c753c 100644 --- a/scripts/node_repeat/node_repeat.gml +++ b/scripts/node_repeat/node_repeat.gml @@ -39,8 +39,7 @@ function Node_Repeat(_x, _y, _group = noone) : Node(_x, _y, _group) constructor inputs[| 13] = nodeValue("Path shift", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0); - inputs[| 14] = nodeValue("Color over copy", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 14] = nodeValue("Color over copy", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 15] = nodeValue("Alpha over copy", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11 ); diff --git a/scripts/node_scatter/node_scatter.gml b/scripts/node_scatter/node_scatter.gml index 572d5b2f8..012a4ee03 100644 --- a/scripts/node_scatter/node_scatter.gml +++ b/scripts/node_scatter/node_scatter.gml @@ -30,8 +30,7 @@ function Node_Scatter(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c inputs[| 10] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom(9999999)); - inputs[| 11] = nodeValue("Random blend", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 11] = nodeValue("Random blend", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 12] = nodeValue("Alpha", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 1, 1 ]) .setDisplay(VALUE_DISPLAY.slider_range, [0, 1, 0.01]); @@ -59,7 +58,8 @@ function Node_Scatter(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); - outputs[| 1] = nodeValue("Atlas data", self, JUNCTION_CONNECT.output, VALUE_TYPE.atlas, []); + outputs[| 1] = nodeValue("Atlas data", self, JUNCTION_CONNECT.output, VALUE_TYPE.atlas, []) + .rejectArrayProcess(); input_display_list = [ ["Output", false], 0, 1, 15, 10, @@ -103,7 +103,7 @@ function Node_Scatter(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) c static process_data = function(_outSurf, _data, _output_index, _array_index) { if(_output_index == 1) return scatter_data; - scatter_data = []; + if(_output_index == 0 && _array_index == 0) scatter_data = []; var _inSurf = _data[0]; if(_inSurf == 0) diff --git a/scripts/node_strand_render/node_strand_render.gml b/scripts/node_strand_render/node_strand_render.gml index 11d89f352..6565710d1 100644 --- a/scripts/node_strand_render/node_strand_render.gml +++ b/scripts/node_strand_render/node_strand_render.gml @@ -15,11 +15,9 @@ function Node_Strand_Render(_x, _y, _group = noone) : Node(_x, _y, _group) const inputs[| 3] = nodeValue("Thickness over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_11); - inputs[| 4] = nodeValue("Random color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white)) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 4] = nodeValue("Random color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white)); - inputs[| 5] = nodeValue("Color over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white)) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 5] = nodeValue("Color over length", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white)); inputs[| 6] = nodeValue("Seed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, irandom_range(10000, 99999)); diff --git a/scripts/node_strand_render_texture/node_strand_render_texture.gml b/scripts/node_strand_render_texture/node_strand_render_texture.gml index 63c4dc34b..93277039a 100644 --- a/scripts/node_strand_render_texture/node_strand_render_texture.gml +++ b/scripts/node_strand_render_texture/node_strand_render_texture.gml @@ -13,8 +13,7 @@ function Node_Strand_Render_Texture(_x, _y, _group = noone) : Node(_x, _y, _grou inputs[| 2] = nodeValue("Thickness", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 8, 8 ]) .setDisplay(VALUE_DISPLAY.vector_range); - inputs[| 3] = nodeValue("Random color", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white)) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 3] = nodeValue("Random color", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white)); inputs[| 4] = nodeValue("Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, 0); diff --git a/scripts/node_stripe/node_stripe.gml b/scripts/node_stripe/node_stripe.gml index 7751a6b55..61726947b 100644 --- a/scripts/node_stripe/node_stripe.gml +++ b/scripts/node_stripe/node_stripe.gml @@ -38,8 +38,7 @@ function Node_Stripe(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co inputs[| 6] = nodeValue("Random color", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); - inputs[| 7] = nodeValue("Colors", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, new gradientObject(c_white) ) - .setDisplay(VALUE_DISPLAY.gradient); + inputs[| 7] = nodeValue("Colors", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white) ); inputs[| 8] = nodeValue("Color 1", 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 531b4821c..afdb64192 100644 --- a/scripts/node_value/node_value.gml +++ b/scripts/node_value/node_value.gml @@ -30,6 +30,7 @@ enum VALUE_TYPE { atlas = 20, d3vertex = 21, + gradient = 22, action = 99, } @@ -47,7 +48,6 @@ enum VALUE_DISPLAY { slider_range, //Color - gradient, palette, //Int array @@ -107,6 +107,7 @@ function value_color(i) { $5dde8f, //trigger $976bff, //atlas #c1007c, //d3vertex + $5dde8f, //gradient ]; if(i == 99) return $5dde8f; @@ -119,6 +120,7 @@ function value_bit(i) { case VALUE_TYPE.float : return 1 << 2 | 1 << 1; case VALUE_TYPE.boolean : return 1 << 3 | 1 << 1; case VALUE_TYPE.color : return 1 << 4; + case VALUE_TYPE.gradient : return 1 << 25; case VALUE_TYPE.surface : return 1 << 5; case VALUE_TYPE.path : return 1 << 10; case VALUE_TYPE.text : return 1 << 10; @@ -146,17 +148,18 @@ function value_bit(i) { } function value_type_directional(f, t) { - if(f == VALUE_TYPE.surface && t == VALUE_TYPE.integer) return true; - if(f == VALUE_TYPE.surface && t == VALUE_TYPE.float) return true; + if(f == VALUE_TYPE.surface && t == VALUE_TYPE.integer) return true; + if(f == VALUE_TYPE.surface && t == VALUE_TYPE.float) return true; if(f == VALUE_TYPE.integer && t == VALUE_TYPE.text) return true; if(f == VALUE_TYPE.float && t == VALUE_TYPE.text) return true; if(f == VALUE_TYPE.boolean && t == VALUE_TYPE.text) return true; - if(f == VALUE_TYPE.integer && t == VALUE_TYPE.color) return true; - if(f == VALUE_TYPE.float && t == VALUE_TYPE.color) return true; - if(f == VALUE_TYPE.color && t == VALUE_TYPE.integer) return true; - if(f == VALUE_TYPE.color && t == VALUE_TYPE.float ) return true; + if(f == VALUE_TYPE.integer && t == VALUE_TYPE.color) return true; + if(f == VALUE_TYPE.float && t == VALUE_TYPE.color) return true; + if(f == VALUE_TYPE.color && t == VALUE_TYPE.integer) return true; + if(f == VALUE_TYPE.color && t == VALUE_TYPE.float ) return true; + if(f == VALUE_TYPE.color && t == VALUE_TYPE.gradient) return true; if(f == VALUE_TYPE.strands && t == VALUE_TYPE.pathnode ) return true; @@ -195,7 +198,6 @@ function typeArrayDynamic(_type) { switch(_type) { case VALUE_DISPLAY.curve : case VALUE_DISPLAY.palette : - case VALUE_DISPLAY.gradient : return true; } return false; @@ -426,6 +428,8 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru express_edit.boxColor = COLORS._main_value_positive; express_edit.align = fa_left; + process_array = true; + static setDefault = function(vals) { if(LOADING || APPENDING) return self; @@ -480,8 +484,13 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru return self; } + static rejectArrayProcess = function() { + process_array = false; + return self; + } + static isAnimable = function() { - if(display_type == VALUE_DISPLAY.gradient) return false; + if(type == VALUE_TYPE.gradient) return false; if(display_type == VALUE_DISPLAY.text_array) return false; return true; } @@ -494,10 +503,10 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru case VALUE_TYPE.color : switch(display_type) { case VALUE_DISPLAY.palette : drop_key = "Palette"; break; - case VALUE_DISPLAY.gradient : drop_key = "Gradient"; break; default : drop_key = "Color"; } break; + case VALUE_TYPE.gradient : drop_key = "Gradient"; break; case VALUE_TYPE.path : drop_key = "Asset"; break; case VALUE_TYPE.text : drop_key = "Text"; break; case VALUE_TYPE.pathnode : drop_key = "Path"; break; @@ -740,14 +749,6 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru graph_h = ui(16); extract_node = "Node_Color"; break; - case VALUE_DISPLAY.gradient : - editWidget = new buttonGradient(function(gradient) { - MODIFIED = true; - return setValueDirect(gradient); - } ); - - extract_node = "Node_Gradient_Out"; - break; case VALUE_DISPLAY.palette : editWidget = new buttonPalette(function(color) { MODIFIED = true; @@ -758,6 +759,14 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru break; } break; + case VALUE_TYPE.gradient : + editWidget = new buttonGradient(function(gradient) { + MODIFIED = true; + return setValueDirect(gradient); + } ); + + extract_node = "Node_Gradient_Out"; + break; case VALUE_TYPE.path : switch(display_type) { case VALUE_DISPLAY.path_array : @@ -907,8 +916,8 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru var typeFrom = nodeFrom.type; var display = nodeFrom.display_type; - if(display_type == VALUE_DISPLAY.gradient && typeFrom == VALUE_TYPE.color) { - if(display == VALUE_DISPLAY.gradient || (is_struct(value) && instanceof(value) == "gradientObject")) + if(type == VALUE_TYPE.gradient && typeFrom == VALUE_TYPE.color) { + if(is_struct(value) && instanceof(value) == "gradientObject") return value; if(is_array(value)) { var amo = array_length(value); @@ -1197,7 +1206,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru updated = animator.setValue(val, connect_type == JUNCTION_CONNECT.input && record, time); } - if(display_type == VALUE_DISPLAY.gradient) updated = true; + if(type == VALUE_TYPE.gradient) updated = true; if(display_type == VALUE_DISPLAY.palette) updated = true; if(updated) { @@ -1478,7 +1487,7 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru if(type == VALUE_TYPE.action) { var tx = x; draw_set_text(f_p1, fa_center, fa_center, _draw_cc); - draw_text(tx, y - (line_height() + 16) / 2, name); + draw_text(tx, y - (line_get_height() + 16) / 2, name); } else if(connect_type == JUNCTION_CONNECT.input) { var tx = x - 12 * _s; draw_set_halign(fa_right); diff --git a/scripts/node_wav_file_write/node_wav_file_write.gml b/scripts/node_wav_file_write/node_wav_file_write.gml new file mode 100644 index 000000000..873885b5f --- /dev/null +++ b/scripts/node_wav_file_write/node_wav_file_write.gml @@ -0,0 +1,119 @@ +function Node_WAV_File_Write(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { + name = "WAV File Out"; + color = COLORS.node_blend_input; + previewable = false; + + h = 72; + min_h = h; + + inputs[| 0] = nodeValue("Path", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "") + .setDisplay(VALUE_DISPLAY.path_save, ["*.wav", ""]) + .rejectArray() + .setVisible(true); + + inputs[| 1] = nodeValue("Audio Data", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [[]]) + .setArrayDepth(1) + .setVisible(true, true); + + inputs[| 2] = nodeValue("Sample", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 44100); + + inputs[| 3] = nodeValue("Bit Depth", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) + .setDisplay(VALUE_DISPLAY.enum_scroll, [ "8 bit positive", "16 bit integer" ]); + + inputs[| 4] = nodeValue("Remap Data", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + + inputs[| 5] = nodeValue("Data Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 1 ]) + .setDisplay(VALUE_DISPLAY.vector); + + input_display_list = [ + [ "Data", false], 1, 0, 4, 5, + [ "Format", false], 2, 3, + ] + + insp1UpdateTooltip = "Export"; + insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ]; + + static onInspector1Update = function() { + export(); + } + + static step = function() { + var remap = inputs[| 4].getValue(); + + inputs[| 5].setVisible(remap); + } + + static export = function() { + var path = inputs[| 0].getValue(); + var data = inputs[| 1].getValue(); + var samp = inputs[| 2].getValue(); + var bitd = inputs[| 3].getValue() + 1; + + var remp = inputs[| 4].getValue(); + var rern = inputs[| 5].getValue(); + + if(!is_array(data)) return; + + var _chn = array_length(data); + var _siz = 0; + + for( var i = 0; i < _chn; i++ ) { + if(!is_array(data[i])) { + noti_warning("Audio Export: Malformed data. Expects 2D array [channel x number array]."); + return; + } + var len = array_length(data[i]); + + if(_siz && _siz != len) { + noti_warning("Audio Export: Uneven sample per channel."); + return; + } + + _siz = len; + } + + if(filename_ext(path) != ".wav") path += ".wav"; + + var buff = buffer_create(1, buffer_grow, 1); + var _pkg = _chn * _siz * bitd + 12 + 24 + 8; + + buffer_write(buff, buffer_text, "RIFF"); + buffer_write(buff, buffer_u32, _pkg); //package size + buffer_write(buff, buffer_text, "WAVE"); + + buffer_write(buff, buffer_text, "fmt "); + buffer_write(buff, buffer_u32, 16); //chunk size + buffer_write(buff, buffer_u16, 1); //format + buffer_write(buff, buffer_u16, _chn); //channels + buffer_write(buff, buffer_u32, samp); //sampling rate + buffer_write(buff, buffer_u32, samp * bitd); //data rate + buffer_write(buff, buffer_u16, bitd); //bitrate (byte) + buffer_write(buff, buffer_u16, bitd * 8); //bit per sample + + buffer_write(buff, buffer_text, "data"); //bit per sample + buffer_write(buff, buffer_u32, _siz); //data length + + var typ = bitd == 1? buffer_u8 : buffer_s16; + var rerng = rern[1] - rern[0]; + + for( var i = 0; i < _siz; i++ ) + for( var j = 0; j < _chn; j++ ) { + var _dat = data[j][i]; + if(remp) { + if(bitd == 1) _dat = (_dat - rern[0]) / rerng * 255; + else if(bitd == 2) _dat = (_dat - rern[0]) / rerng * 65535 - 32768; + _dat = round(_dat); + } + + buffer_write(buff, typ, _dat); + } + + buffer_save(buff, path); + buffer_delete(buff); + } + + static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { + var bbox = drawGetBbox(xx, yy, _s); + draw_sprite_fit(s_node_wav_file_write, 0, bbox.xc, bbox.yc, bbox.w, bbox.h); + } +} \ No newline at end of file diff --git a/scripts/node_wav_file_write/node_wav_file_write.yy b/scripts/node_wav_file_write/node_wav_file_write.yy new file mode 100644 index 000000000..e97e57afd --- /dev/null +++ b/scripts/node_wav_file_write/node_wav_file_write.yy @@ -0,0 +1,11 @@ +{ + "resourceType": "GMScript", + "resourceVersion": "1.0", + "name": "node_wav_file_write", + "isCompatibility": false, + "isDnD": false, + "parent": { + "name": "audio", + "path": "folders/nodes/data/audio.yy", + }, +} \ No newline at end of file diff --git a/scripts/panel_collection/panel_collection.gml b/scripts/panel_collection/panel_collection.gml index 4ca9ff218..833c5b4bd 100644 --- a/scripts/panel_collection/panel_collection.gml +++ b/scripts/panel_collection/panel_collection.gml @@ -168,6 +168,7 @@ function Panel_Collection() : PanelContent() constructor { var _node = index < node_list? nodes[| index] : steamNode[index - node_list]; var _nx = grid_space + (grid_width + grid_space) * j; var _boxx = _nx + (grid_width - grid_size) / 2; + _boxx = round(_boxx); var gr_x1 = _boxx + grid_size; var gr_y1 = yy + grid_size; @@ -373,7 +374,7 @@ function Panel_Collection() : PanelContent() constructor { var _x = ui(16); var _y = ui(24); - var bh = line_height(f_p0b, 8); + var bh = line_get_height(f_p0b, 8); var rootx = 0; for( var i = 0; i < array_length(roots); i++ ) { diff --git a/scripts/panel_graph_export_image/panel_graph_export_image.gml b/scripts/panel_graph_export_image/panel_graph_export_image.gml new file mode 100644 index 000000000..ea08bd78d --- /dev/null +++ b/scripts/panel_graph_export_image/panel_graph_export_image.gml @@ -0,0 +1,3 @@ +function Script659(){ + +} \ No newline at end of file diff --git a/scripts/panel_graph_export_image/panel_graph_export_image.yy b/scripts/panel_graph_export_image/panel_graph_export_image.yy new file mode 100644 index 000000000..477ac405c --- /dev/null +++ b/scripts/panel_graph_export_image/panel_graph_export_image.yy @@ -0,0 +1,11 @@ +{ + "resourceType": "GMScript", + "resourceVersion": "1.0", + "name": "panel_graph_export_image", + "isCompatibility": false, + "isDnD": false, + "parent": { + "name": "graph", + "path": "folders/panels/graph.yy", + }, +} \ No newline at end of file diff --git a/scripts/panel_history/panel_history.gml b/scripts/panel_history/panel_history.gml index 37e1e1f2e..8d21ea95d 100644 --- a/scripts/panel_history/panel_history.gml +++ b/scripts/panel_history/panel_history.gml @@ -51,7 +51,7 @@ function Panel_History() : PanelContent() constructor { draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text); - var lh = line_height() + ui(8); + var lh = line_get_height() + ui(8); var _h = 0, hh; var yy = _y + ui(8); diff --git a/scripts/panel_inspector/panel_inspector.gml b/scripts/panel_inspector/panel_inspector.gml index 31dc93b89..50bae7fc2 100644 --- a/scripts/panel_inspector/panel_inspector.gml +++ b/scripts/panel_inspector/panel_inspector.gml @@ -156,8 +156,8 @@ function Panel_Inspector() : PanelContent() constructor { draw_set_text(f_p0, fa_left, fa_top, COLORS._main_text); draw_text_add(ui(16), yy, display[0]); - yy += line_height() + ui(6); - hh += line_height() + ui(6); + yy += line_get_height() + ui(6); + hh += line_get_height() + ui(6); meta_tb[j].setActiveFocus(pFOCUS, _hover); if(pFOCUS) meta_tb[j].register(contentPane); @@ -416,8 +416,8 @@ function Panel_Inspector() : PanelContent() constructor { if(pos == 0) continue; } - var lb_h = line_height(f_p0) + ui(8); - var lb_w = line_width(jun.name, f_p0) + ui(16); + var lb_h = line_get_height(f_p0) + ui(8); + var lb_w = line_get_width(jun.name, f_p0) + ui(16); var padd = ui(8); var _selY = yy - ui(0); diff --git a/scripts/panel_menu/panel_menu.gml b/scripts/panel_menu/panel_menu.gml index 303774055..22afbfff1 100644 --- a/scripts/panel_menu/panel_menu.gml +++ b/scripts/panel_menu/panel_menu.gml @@ -348,7 +348,7 @@ function Panel_Menu() : PanelContent() constructor { for(var i = 0; i < array_length(menus); i++) { draw_set_text(f_p1, fa_center, fa_center, COLORS._main_text); var ww = string_width(menus[i][0]) + ui(16); - var hh = line_height() + ui(8); + var hh = line_get_height() + ui(8); if(hori) { xc = xx + ww / 2; diff --git a/scripts/panel_notification/panel_notification.gml b/scripts/panel_notification/panel_notification.gml index 77be1de54..e382f8efb 100644 --- a/scripts/panel_notification/panel_notification.gml +++ b/scripts/panel_notification/panel_notification.gml @@ -79,7 +79,7 @@ function Panel_Notification() : PanelContent() constructor { menuItem(get_text("noti_delete_message", "Delete notification"), function() { ds_list_remove(STATUSES, o_dialog_menubox.noti); }), - ],, o_dialog_menubox.noti); + ],, noti); dia.noti = noti; } } diff --git a/scripts/textArea/textArea.gml b/scripts/textArea/textArea.gml index e221a9bea..aebbc5454 100644 --- a/scripts/textArea/textArea.gml +++ b/scripts/textArea/textArea.gml @@ -86,10 +86,11 @@ function textArea(_input, _onModify, _extras = noone) : textInput(_input, _onMod var currW = 0; var currL = ""; var cut = true; + var len = array_length(words); - for( var j = 0; j < array_length(words); j++ ) { + for( var j = 0; j < len; j++ ) { var word = words[j]; - if(j) word = " " + word; + if(j < len - 1) word = word + " "; if(string_width(word) > line_width) { //the entire word is longer than a line for( var k = 1; k <= string_length(word); k++ ) { @@ -302,7 +303,7 @@ function textArea(_input, _onModify, _extras = noone) : textInput(_input, _onMod else if(format == TEXT_AREA_FORMAT.delimiter) draw_text_delimiter(ch_x, ch_y, _str); - ch_y += line_height(); + ch_y += line_get_height(); } draw_set_alpha(1); @@ -318,7 +319,7 @@ function textArea(_input, _onModify, _extras = noone) : textInput(_input, _onMod for( var i = 0; i < array_length(_input_text_line); i++ ) { _str = string_trim_end(_input_text_line[i]); _l = string_length(_str); - _ch_h = line_height(); + _ch_h = line_get_height(); ch_cxo = sx; ch_x = sx; @@ -387,7 +388,7 @@ function textArea(_input, _onModify, _extras = noone) : textInput(_input, _onMod } draw_set_font(font); - var c_h = line_height(); + var c_h = line_get_height(); var line_count = max(min_lines, array_length(_input_text_line)); hh = max(_h, ui(14) + c_h * line_count); @@ -565,7 +566,7 @@ function textArea(_input, _onModify, _extras = noone) : textInput(_input, _onMod cursor_line = i; } char_run += _l; - ch_y += line_height(); + ch_y += line_get_height(); } cursor_pos_x = cursor_pos_x == 0? cursor_pos_x_to : lerp_float(cursor_pos_x, cursor_pos_x_to, 4); diff --git a/scripts/textArrayBox/textArrayBox.gml b/scripts/textArrayBox/textArrayBox.gml index b0b5053ee..57f8474d2 100644 --- a/scripts/textArrayBox/textArrayBox.gml +++ b/scripts/textArrayBox/textArrayBox.gml @@ -17,7 +17,7 @@ function textArrayBox(arraySet, data, onModify = noone) : widget() constructor { var tx = _x + ui(4); var ty = _y + ui(4); - var hh = line_height(f_p0, ui(4)); + var hh = line_get_height(f_p0, ui(4)); var th = hh + ui(8); draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text); @@ -52,7 +52,7 @@ function textArrayBox(arraySet, data, onModify = noone) : widget() constructor { var tx = _x + ui(4); var ty = _y + ui(4); - var hh = line_height(f_p0, ui(4)); + var hh = line_get_height(f_p0, ui(4)); draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text); for( var i = 0; i < array_length(arraySet); i++ ) { diff --git a/scripts/wav_file_read/wav_file_read.gml b/scripts/wav_file_read/wav_file_read.gml index dfa1739ef..31de86368 100644 --- a/scripts/wav_file_read/wav_file_read.gml +++ b/scripts/wav_file_read/wav_file_read.gml @@ -39,10 +39,16 @@ function file_read_wav(path) { printIf(global.FLAG.wav_import, "-- FORMAT --") var b = file_read_ASCII(wav_file_reader, 4); printIf(global.FLAG.wav_import, b); var l = file_read_bytes(wav_file_reader, 4); printIf(global.FLAG.wav_import, $"Length: {l}"); + + if(l != 16) { + noti_waning("File format not supported, the audio file need to be 8, 16 bit PCM wav with no extension."); + return; + } + var l = file_read_bytes(wav_file_reader, 2); printIf(global.FLAG.wav_import, $"0x01: {l}"); var ch = file_read_bytes(wav_file_reader, 2); printIf(global.FLAG.wav_import, $"Channels: {ch}"); var sm = file_read_bytes(wav_file_reader, 4); printIf(global.FLAG.wav_import, $"Sample: {sm}"); - var l = file_read_bytes(wav_file_reader, 4); printIf(global.FLAG.wav_import, $"BPS: {l}"); + var l = file_read_bytes(wav_file_reader, 4); printIf(global.FLAG.wav_import, $"BPS: {l}"); var br = file_read_bytes(wav_file_reader, 2); printIf(global.FLAG.wav_import, $"Bitrate: {br}"); var l = file_read_bytes(wav_file_reader, 2); printIf(global.FLAG.wav_import, $"Bit/Sam: {l}"); diff --git a/sprites/s_node_ase_file/s_node_ase_file.yy b/sprites/s_node_ase_file/s_node_ase_file.yy index f2003868b..551b1838b 100644 --- a/sprites/s_node_ase_file/s_node_ase_file.yy +++ b/sprites/s_node_ase_file/s_node_ase_file.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_ase_layer/s_node_ase_layer.yy b/sprites/s_node_ase_layer/s_node_ase_layer.yy index 411e536f3..daba920c5 100644 --- a/sprites/s_node_ase_layer/s_node_ase_layer.yy +++ b/sprites/s_node_ase_layer/s_node_ase_layer.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_canvas/s_node_canvas.yy b/sprites/s_node_canvas/s_node_canvas.yy index b3ed23688..4ceb38b4e 100644 --- a/sprites/s_node_canvas/s_node_canvas.yy +++ b/sprites/s_node_canvas/s_node_canvas.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_csv_file_read/s_node_csv_file_read.yy b/sprites/s_node_csv_file_read/s_node_csv_file_read.yy index 0f46a7782..637135f9f 100644 --- a/sprites/s_node_csv_file_read/s_node_csv_file_read.yy +++ b/sprites/s_node_csv_file_read/s_node_csv_file_read.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_csv_file_write/s_node_csv_file_write.yy b/sprites/s_node_csv_file_write/s_node_csv_file_write.yy index acb99e25f..1abf947c9 100644 --- a/sprites/s_node_csv_file_write/s_node_csv_file_write.yy +++ b/sprites/s_node_csv_file_write/s_node_csv_file_write.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image/s_node_image.yy b/sprites/s_node_image/s_node_image.yy index f1a370a90..7ae13d079 100644 --- a/sprites/s_node_image/s_node_image.yy +++ b/sprites/s_node_image/s_node_image.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_animation/s_node_image_animation.yy b/sprites/s_node_image_animation/s_node_image_animation.yy index 9d2836ec3..f71381cb0 100644 --- a/sprites/s_node_image_animation/s_node_image_animation.yy +++ b/sprites/s_node_image_animation/s_node_image_animation.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_copy/s_node_image_copy.yy b/sprites/s_node_image_copy/s_node_image_copy.yy index 12aa4ef57..912db281e 100644 --- a/sprites/s_node_image_copy/s_node_image_copy.yy +++ b/sprites/s_node_image_copy/s_node_image_copy.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_gif/s_node_image_gif.yy b/sprites/s_node_image_gif/s_node_image_gif.yy index 66657e6c8..41a834b9d 100644 --- a/sprites/s_node_image_gif/s_node_image_gif.yy +++ b/sprites/s_node_image_gif/s_node_image_gif.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_sequence/s_node_image_sequence.yy b/sprites/s_node_image_sequence/s_node_image_sequence.yy index f41350eb4..4c718903d 100644 --- a/sprites/s_node_image_sequence/s_node_image_sequence.yy +++ b/sprites/s_node_image_sequence/s_node_image_sequence.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_sequence_to_anim/s_node_image_sequence_to_anim.yy b/sprites/s_node_image_sequence_to_anim/s_node_image_sequence_to_anim.yy index c339e1078..9013ccbc3 100644 --- a/sprites/s_node_image_sequence_to_anim/s_node_image_sequence_to_anim.yy +++ b/sprites/s_node_image_sequence_to_anim/s_node_image_sequence_to_anim.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_image_sheet/s_node_image_sheet.yy b/sprites/s_node_image_sheet/s_node_image_sheet.yy index 203c6f2fe..9b0cdd394 100644 --- a/sprites/s_node_image_sheet/s_node_image_sheet.yy +++ b/sprites/s_node_image_sheet/s_node_image_sheet.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_json_file_read/s_node_json_file_read.yy b/sprites/s_node_json_file_read/s_node_json_file_read.yy index 567f6c592..62311b025 100644 --- a/sprites/s_node_json_file_read/s_node_json_file_read.yy +++ b/sprites/s_node_json_file_read/s_node_json_file_read.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_json_file_write/s_node_json_file_write.yy b/sprites/s_node_json_file_write/s_node_json_file_write.yy index b0bbab7ee..345dbc240 100644 --- a/sprites/s_node_json_file_write/s_node_json_file_write.yy +++ b/sprites/s_node_json_file_write/s_node_json_file_write.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_text_file_read/s_node_text_file_read.yy b/sprites/s_node_text_file_read/s_node_text_file_read.yy index 375966e4b..058d14c88 100644 --- a/sprites/s_node_text_file_read/s_node_text_file_read.yy +++ b/sprites/s_node_text_file_read/s_node_text_file_read.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_text_file_write/s_node_text_file_write.yy b/sprites/s_node_text_file_write/s_node_text_file_write.yy index 99421b26c..73559ab1c 100644 --- a/sprites/s_node_text_file_write/s_node_text_file_write.yy +++ b/sprites/s_node_text_file_write/s_node_text_file_write.yy @@ -25,8 +25,8 @@ "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { diff --git a/sprites/s_node_wav_file_read/2c9b305d-d36e-476b-a921-16c2f79031b8.png b/sprites/s_node_wav_file_read/2c9b305d-d36e-476b-a921-16c2f79031b8.png new file mode 100644 index 000000000..cd69bb658 Binary files /dev/null and b/sprites/s_node_wav_file_read/2c9b305d-d36e-476b-a921-16c2f79031b8.png differ diff --git a/sprites/s_node_wav_file_read/ed7117f7-7897-476a-acf0-d7b1d10f562f.png b/sprites/s_node_wav_file_read/ed7117f7-7897-476a-acf0-d7b1d10f562f.png deleted file mode 100644 index 04d6ec641..000000000 Binary files a/sprites/s_node_wav_file_read/ed7117f7-7897-476a-acf0-d7b1d10f562f.png and /dev/null differ diff --git a/sprites/s_node_wav_file_read/layers/2c9b305d-d36e-476b-a921-16c2f79031b8/fa7c8971-1920-4811-911b-85dc4a0031ba.png b/sprites/s_node_wav_file_read/layers/2c9b305d-d36e-476b-a921-16c2f79031b8/fa7c8971-1920-4811-911b-85dc4a0031ba.png new file mode 100644 index 000000000..cd69bb658 Binary files /dev/null and b/sprites/s_node_wav_file_read/layers/2c9b305d-d36e-476b-a921-16c2f79031b8/fa7c8971-1920-4811-911b-85dc4a0031ba.png differ diff --git a/sprites/s_node_wav_file_read/layers/ed7117f7-7897-476a-acf0-d7b1d10f562f/d0ffea8e-e51f-4415-b383-c42802705804.png b/sprites/s_node_wav_file_read/layers/ed7117f7-7897-476a-acf0-d7b1d10f562f/d0ffea8e-e51f-4415-b383-c42802705804.png deleted file mode 100644 index 04d6ec641..000000000 Binary files a/sprites/s_node_wav_file_read/layers/ed7117f7-7897-476a-acf0-d7b1d10f562f/d0ffea8e-e51f-4415-b383-c42802705804.png and /dev/null differ diff --git a/sprites/s_node_wav_file_read/s_node_wav_file_read.yy b/sprites/s_node_wav_file_read/s_node_wav_file_read.yy index 071adabb9..22886eba0 100644 --- a/sprites/s_node_wav_file_read/s_node_wav_file_read.yy +++ b/sprites/s_node_wav_file_read/s_node_wav_file_read.yy @@ -2,10 +2,10 @@ "resourceType": "GMSprite", "resourceVersion": "1.0", "name": "s_node_wav_file_read", - "bbox_bottom": 62, + "bbox_bottom": 57, "bbox_left": 0, "bbox_right": 62, - "bbox_top": 0, + "bbox_top": 6, "bboxMode": 0, "collisionKind": 1, "collisionTolerance": 0, @@ -13,20 +13,20 @@ "edgeFiltering": false, "For3D": false, "frames": [ - {"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"ed7117f7-7897-476a-acf0-d7b1d10f562f",}, + {"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"2c9b305d-d36e-476b-a921-16c2f79031b8",}, ], "gridX": 0, "gridY": 0, "height": 64, "HTile": false, "layers": [ - {"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"d0ffea8e-e51f-4415-b383-c42802705804","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,}, + {"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"fa7c8971-1920-4811-911b-85dc4a0031ba","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,}, ], "nineSlice": null, "origin": 4, "parent": { - "name": "input", - "path": "folders/nodes/icons/input.yy", + "name": "IO", + "path": "folders/nodes/icons/IO.yy", }, "preMultiplyAlpha": false, "sequence": { @@ -54,7 +54,7 @@ "timeUnits": 1, "tracks": [ {"resourceType":"GMSpriteFramesTrack","resourceVersion":"1.0","name":"frames","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"resourceType":"KeyframeStore","resourceVersion":"1.0","Keyframes":[ - {"resourceType":"Keyframe","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"ed7117f7-7897-476a-acf0-d7b1d10f562f","path":"sprites/s_node_wav_file_read/s_node_wav_file_read.yy",},},},"Disabled":false,"id":"97d549db-4e6f-4505-b6dd-aacd000eaa4c","IsCreationKey":false,"Key":0.0,"Length":1.0,"Stretch":false,}, + {"resourceType":"Keyframe","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"2c9b305d-d36e-476b-a921-16c2f79031b8","path":"sprites/s_node_wav_file_read/s_node_wav_file_read.yy",},},},"Disabled":false,"id":"f1114075-0273-45bf-9df3-d4c534342938","IsCreationKey":false,"Key":0.0,"Length":1.0,"Stretch":false,}, ],},"modifiers":[],"spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, ], "visibleRange": null, diff --git a/sprites/s_node_wav_file_write/f600e086-97a1-4550-abca-174b3b243d48.png b/sprites/s_node_wav_file_write/f600e086-97a1-4550-abca-174b3b243d48.png new file mode 100644 index 000000000..1708c88ef Binary files /dev/null and b/sprites/s_node_wav_file_write/f600e086-97a1-4550-abca-174b3b243d48.png differ diff --git a/sprites/s_node_wav_file_write/layers/f600e086-97a1-4550-abca-174b3b243d48/9875a4ef-d711-48b8-b516-a9d19283bd1a.png b/sprites/s_node_wav_file_write/layers/f600e086-97a1-4550-abca-174b3b243d48/9875a4ef-d711-48b8-b516-a9d19283bd1a.png new file mode 100644 index 000000000..1708c88ef Binary files /dev/null and b/sprites/s_node_wav_file_write/layers/f600e086-97a1-4550-abca-174b3b243d48/9875a4ef-d711-48b8-b516-a9d19283bd1a.png differ diff --git a/sprites/s_node_wav_file_write/s_node_wav_file_write.yy b/sprites/s_node_wav_file_write/s_node_wav_file_write.yy new file mode 100644 index 000000000..643c12b0a --- /dev/null +++ b/sprites/s_node_wav_file_write/s_node_wav_file_write.yy @@ -0,0 +1,74 @@ +{ + "resourceType": "GMSprite", + "resourceVersion": "1.0", + "name": "s_node_wav_file_write", + "bbox_bottom": 63, + "bbox_left": 0, + "bbox_right": 63, + "bbox_top": 0, + "bboxMode": 0, + "collisionKind": 1, + "collisionTolerance": 0, + "DynamicTexturePage": false, + "edgeFiltering": false, + "For3D": false, + "frames": [ + {"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"f600e086-97a1-4550-abca-174b3b243d48",}, + ], + "gridX": 0, + "gridY": 0, + "height": 64, + "HTile": false, + "layers": [ + {"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"9875a4ef-d711-48b8-b516-a9d19283bd1a","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,}, + ], + "nineSlice": null, + "origin": 4, + "parent": { + "name": "IO", + "path": "folders/nodes/icons/IO.yy", + }, + "preMultiplyAlpha": false, + "sequence": { + "resourceType": "GMSequence", + "resourceVersion": "1.4", + "name": "s_node_wav_file_write", + "autoRecord": true, + "backdropHeight": 768, + "backdropImageOpacity": 0.5, + "backdropImagePath": "", + "backdropWidth": 1366, + "backdropXOffset": 0.0, + "backdropYOffset": 0.0, + "events": {"resourceType":"KeyframeStore","resourceVersion":"1.0","Keyframes":[],}, + "eventStubScript": null, + "eventToFunction": {}, + "length": 1.0, + "lockOrigin": false, + "moments": {"resourceType":"KeyframeStore","resourceVersion":"1.0","Keyframes":[],}, + "playback": 1, + "playbackSpeed": 30.0, + "playbackSpeedType": 0, + "showBackdrop": true, + "showBackdropImage": false, + "timeUnits": 1, + "tracks": [ + {"resourceType":"GMSpriteFramesTrack","resourceVersion":"1.0","name":"frames","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"resourceType":"KeyframeStore","resourceVersion":"1.0","Keyframes":[ + {"resourceType":"Keyframe","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"f600e086-97a1-4550-abca-174b3b243d48","path":"sprites/s_node_wav_file_write/s_node_wav_file_write.yy",},},},"Disabled":false,"id":"0a3f90fa-129f-4c03-a0d8-cac031cdfc05","IsCreationKey":false,"Key":0.0,"Length":1.0,"Stretch":false,}, + ],},"modifiers":[],"spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, + ], + "visibleRange": null, + "volume": 1.0, + "xorigin": 32, + "yorigin": 32, + }, + "swatchColours": null, + "swfPrecision": 2.525, + "textureGroupId": { + "name": "Default", + "path": "texturegroups/Default", + }, + "type": 0, + "VTile": false, + "width": 64, +} \ No newline at end of file