- New HSV Curve.

This commit is contained in:
Tanasart 2024-06-02 18:56:11 +07:00
parent b911c4da50
commit 3b08063160
15 changed files with 367 additions and 1 deletions

View file

@ -716,6 +716,7 @@
{"name":"node_cross_section","order":20,"path":"scripts/node_cross_section/node_cross_section.yy",}, {"name":"node_cross_section","order":20,"path":"scripts/node_cross_section/node_cross_section.yy",},
{"name":"node_csv_file_read","order":8,"path":"scripts/node_csv_file_read/node_csv_file_read.yy",}, {"name":"node_csv_file_read","order":8,"path":"scripts/node_csv_file_read/node_csv_file_read.yy",},
{"name":"node_csv_file_write","order":12,"path":"scripts/node_csv_file_write/node_csv_file_write.yy",}, {"name":"node_csv_file_write","order":12,"path":"scripts/node_csv_file_write/node_csv_file_write.yy",},
{"name":"node_curve_hsv","order":18,"path":"scripts/node_curve_hsv/node_curve_hsv.yy",},
{"name":"node_data","order":1,"path":"scripts/node_data/node_data.yy",}, {"name":"node_data","order":1,"path":"scripts/node_data/node_data.yy",},
{"name":"node_de_stray","order":1,"path":"scripts/node_de_stray/node_de_stray.yy",}, {"name":"node_de_stray","order":1,"path":"scripts/node_de_stray/node_de_stray.yy",},
{"name":"node_delay","order":5,"path":"scripts/node_delay/node_delay.yy",}, {"name":"node_delay","order":5,"path":"scripts/node_delay/node_delay.yy",},
@ -1302,6 +1303,7 @@
{"name":"sh_corner_iterate","order":2,"path":"shaders/sh_corner_iterate/sh_corner_iterate.yy",}, {"name":"sh_corner_iterate","order":2,"path":"shaders/sh_corner_iterate/sh_corner_iterate.yy",},
{"name":"sh_cross_histogram","order":26,"path":"shaders/sh_cross_histogram/sh_cross_histogram.yy",}, {"name":"sh_cross_histogram","order":26,"path":"shaders/sh_cross_histogram/sh_cross_histogram.yy",},
{"name":"sh_cross_section","order":25,"path":"shaders/sh_cross_section/sh_cross_section.yy",}, {"name":"sh_cross_section","order":25,"path":"shaders/sh_cross_section/sh_cross_section.yy",},
{"name":"sh_curve_hsv","order":54,"path":"shaders/sh_curve_hsv/sh_curve_hsv.yy",},
{"name":"sh_curve","order":3,"path":"shaders/sh_curve/sh_curve.yy",}, {"name":"sh_curve","order":3,"path":"shaders/sh_curve/sh_curve.yy",},
{"name":"sh_d3d_background","order":8,"path":"shaders/sh_d3d_background/sh_d3d_background.yy",}, {"name":"sh_d3d_background","order":8,"path":"shaders/sh_d3d_background/sh_d3d_background.yy",},
{"name":"sh_d3d_extrude_extends","order":11,"path":"shaders/sh_d3d_extrude_extends/sh_d3d_extrude_extends.yy",}, {"name":"sh_d3d_extrude_extends","order":11,"path":"shaders/sh_d3d_extrude_extends/sh_d3d_extrude_extends.yy",},
@ -1671,6 +1673,7 @@
{"name":"s_node_csv_file_write","order":30,"path":"sprites/s_node_csv_file_write/s_node_csv_file_write.yy",}, {"name":"s_node_csv_file_write","order":30,"path":"sprites/s_node_csv_file_write/s_node_csv_file_write.yy",},
{"name":"s_node_csv_parse","order":19,"path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",}, {"name":"s_node_csv_parse","order":19,"path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",},
{"name":"s_node_curve_edit","order":14,"path":"sprites/s_node_curve_edit/s_node_curve_edit.yy",}, {"name":"s_node_curve_edit","order":14,"path":"sprites/s_node_curve_edit/s_node_curve_edit.yy",},
{"name":"s_node_curve_hsv","order":63,"path":"sprites/s_node_curve_hsv/s_node_curve_hsv.yy",},
{"name":"s_node_curve","order":20,"path":"sprites/s_node_curve/s_node_curve.yy",}, {"name":"s_node_curve","order":20,"path":"sprites/s_node_curve/s_node_curve.yy",},
{"name":"s_node_decorner","order":15,"path":"sprites/s_node_decorner/s_node_decorner.yy",}, {"name":"s_node_decorner","order":15,"path":"sprites/s_node_decorner/s_node_decorner.yy",},
{"name":"s_node_delay","order":7,"path":"sprites/s_node_delay/s_node_delay.yy",}, {"name":"s_node_delay","order":7,"path":"sprites/s_node_delay/s_node_delay.yy",},

View file

@ -1128,6 +1128,7 @@
{"id":{"name":"node_cross_section","path":"scripts/node_cross_section/node_cross_section.yy",},}, {"id":{"name":"node_cross_section","path":"scripts/node_cross_section/node_cross_section.yy",},},
{"id":{"name":"node_csv_file_read","path":"scripts/node_csv_file_read/node_csv_file_read.yy",},}, {"id":{"name":"node_csv_file_read","path":"scripts/node_csv_file_read/node_csv_file_read.yy",},},
{"id":{"name":"node_csv_file_write","path":"scripts/node_csv_file_write/node_csv_file_write.yy",},}, {"id":{"name":"node_csv_file_write","path":"scripts/node_csv_file_write/node_csv_file_write.yy",},},
{"id":{"name":"node_curve_hsv","path":"scripts/node_curve_hsv/node_curve_hsv.yy",},},
{"id":{"name":"node_curve","path":"scripts/node_curve/node_curve.yy",},}, {"id":{"name":"node_curve","path":"scripts/node_curve/node_curve.yy",},},
{"id":{"name":"node_data","path":"scripts/node_data/node_data.yy",},}, {"id":{"name":"node_data","path":"scripts/node_data/node_data.yy",},},
{"id":{"name":"node_de_corner","path":"scripts/node_de_corner/node_de_corner.yy",},}, {"id":{"name":"node_de_corner","path":"scripts/node_de_corner/node_de_corner.yy",},},
@ -1805,6 +1806,7 @@
{"id":{"name":"sh_corner","path":"shaders/sh_corner/sh_corner.yy",},}, {"id":{"name":"sh_corner","path":"shaders/sh_corner/sh_corner.yy",},},
{"id":{"name":"sh_cross_histogram","path":"shaders/sh_cross_histogram/sh_cross_histogram.yy",},}, {"id":{"name":"sh_cross_histogram","path":"shaders/sh_cross_histogram/sh_cross_histogram.yy",},},
{"id":{"name":"sh_cross_section","path":"shaders/sh_cross_section/sh_cross_section.yy",},}, {"id":{"name":"sh_cross_section","path":"shaders/sh_cross_section/sh_cross_section.yy",},},
{"id":{"name":"sh_curve_hsv","path":"shaders/sh_curve_hsv/sh_curve_hsv.yy",},},
{"id":{"name":"sh_curve","path":"shaders/sh_curve/sh_curve.yy",},}, {"id":{"name":"sh_curve","path":"shaders/sh_curve/sh_curve.yy",},},
{"id":{"name":"sh_d3d_background","path":"shaders/sh_d3d_background/sh_d3d_background.yy",},}, {"id":{"name":"sh_d3d_background","path":"shaders/sh_d3d_background/sh_d3d_background.yy",},},
{"id":{"name":"sh_d3d_default","path":"shaders/sh_d3d_default/sh_d3d_default.yy",},}, {"id":{"name":"sh_d3d_default","path":"shaders/sh_d3d_default/sh_d3d_default.yy",},},
@ -2235,6 +2237,7 @@
{"id":{"name":"s_node_csv_parse","path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",},}, {"id":{"name":"s_node_csv_parse","path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",},},
{"id":{"name":"s_node_curve_edit","path":"sprites/s_node_curve_edit/s_node_curve_edit.yy",},}, {"id":{"name":"s_node_curve_edit","path":"sprites/s_node_curve_edit/s_node_curve_edit.yy",},},
{"id":{"name":"s_node_curve_eval","path":"sprites/s_node_curve_eval/s_node_curve_eval.yy",},}, {"id":{"name":"s_node_curve_eval","path":"sprites/s_node_curve_eval/s_node_curve_eval.yy",},},
{"id":{"name":"s_node_curve_hsv","path":"sprites/s_node_curve_hsv/s_node_curve_hsv.yy",},},
{"id":{"name":"s_node_curve","path":"sprites/s_node_curve/s_node_curve.yy",},}, {"id":{"name":"s_node_curve","path":"sprites/s_node_curve/s_node_curve.yy",},},
{"id":{"name":"s_node_decorner","path":"sprites/s_node_decorner/s_node_decorner.yy",},}, {"id":{"name":"s_node_decorner","path":"sprites/s_node_decorner/s_node_decorner.yy",},},
{"id":{"name":"s_node_delay","path":"sprites/s_node_delay/s_node_delay.yy",},}, {"id":{"name":"s_node_delay","path":"sprites/s_node_delay/s_node_delay.yy",},},

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "process",
"path": "folders/nodes/data/process.yy",
},
"resourceVersion": "1.0",
"name": "node_color_adjustment",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "process",
"path": "folders/nodes/data/process.yy",
},
"resourceVersion": "1.0",
"name": "node_color_replacement",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -0,0 +1,63 @@
function Node_Curve_HSV(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
name = "HSV Curve";
inputs[| 0] = nodeValue("Surface in", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 1] = nodeValue("Hue", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_01);
inputs[| 2] = nodeValue("Saturation", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_01);
inputs[| 3] = nodeValue("Value", self, JUNCTION_CONNECT.input, VALUE_TYPE.curve, CURVE_DEF_01);
inputs[| 4] = nodeValue("Mask", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone);
inputs[| 5] = nodeValue("Mix", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider);
inputs[| 6] = nodeValue("Active", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
active_index = 6;
inputs[| 7] = nodeValue("Channel", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0b1111)
.setDisplay(VALUE_DISPLAY.toggle, { data: array_create(4, THEME.inspector_channel) });
__init_mask_modifier(4); // inputs 8, 9,
outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone);
input_display_list = [ 6, 7,
["Surfaces", true], 0, 4, 5, 8, 9,
["Curve", false], 1, 2, 3,
];
attribute_surface_depth();
static step = function() { #region
__step_mask_modifier();
} #endregion
static processData = function(_outSurf, _data, _output_index, _array_index) { #region
var _hcur = _data[1];
var _scur = _data[2];
var _vcur = _data[3];
surface_set_shader(_outSurf, sh_curve_hsv);
shader_set_f("h_curve", _hcur);
shader_set_i("h_amount", array_length(_hcur));
shader_set_f("s_curve", _scur);
shader_set_i("s_amount", array_length(_scur));
shader_set_f("v_curve", _vcur);
shader_set_i("v_amount", array_length(_vcur));
draw_surface_safe(_data[0]);
surface_reset_shader();
__process_mask_modifier(_data);
_outSurf = mask_apply(_data[0], _outSurf, _data[4], _data[5]);
_outSurf = channel_apply(_data[0], _outSurf, _data[7]);
return _outSurf;
} #endregion
}

View file

@ -0,0 +1,13 @@
{
"$GMScript":"",
"%Name":"node_curve_hsv",
"isCompatibility":false,
"isDnD":false,
"name":"node_curve_hsv",
"parent":{
"name":"colors",
"path":"folders/nodes/data/filter/colors.yy",
},
"resourceType":"GMScript",
"resourceVersion":"2.0",
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "process",
"path": "folders/nodes/data/process.yy",
},
"resourceVersion": "1.0",
"name": "node_outline",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -622,6 +622,7 @@ function __initNodes() {
addNodeObject(filter, "Level", s_node_level, "Node_Level", [1, Node_Level],, "Adjust brightness of an image by changing its brightness range."); addNodeObject(filter, "Level", s_node_level, "Node_Level", [1, Node_Level],, "Adjust brightness of an image by changing its brightness range.");
addNodeObject(filter, "Level Selector", s_node_level_selector, "Node_Level_Selector", [1, Node_Level_Selector],, "Isolate part of the image that falls in the selected brightness range."); addNodeObject(filter, "Level Selector", s_node_level_selector, "Node_Level_Selector", [1, Node_Level_Selector],, "Isolate part of the image that falls in the selected brightness range.");
addNodeObject(filter, "Curve", s_node_curve_edit, "Node_Curve", [1, Node_Curve],, "Adjust brightness of an image using curves.").setVersion(1120); addNodeObject(filter, "Curve", s_node_curve_edit, "Node_Curve", [1, Node_Curve],, "Adjust brightness of an image using curves.").setVersion(1120);
addNodeObject(filter, "HSV Curve", s_node_curve_hsv, "Node_Curve_HSV", [1, Node_Curve_HSV],, "Adjust hsv values of an image using curves.").setVersion(11720);
addNodeObject(filter, "Threshold", s_node_threshold, "Node_Threshold", [1, Node_Threshold],, "Set a threshold where pixel darker will becomes black, and brighter to white. Also works with alpha.").setVersion(1080); addNodeObject(filter, "Threshold", s_node_threshold, "Node_Threshold", [1, Node_Threshold],, "Set a threshold where pixel darker will becomes black, and brighter to white. Also works with alpha.").setVersion(1080);
addNodeObject(filter, "Alpha Cutoff", s_node_alpha_cut, "Node_Alpha_Cutoff", [1, Node_Alpha_Cutoff], ["remove alpha"], "Remove pixel with low alpha value."); addNodeObject(filter, "Alpha Cutoff", s_node_alpha_cut, "Node_Alpha_Cutoff", [1, Node_Alpha_Cutoff], ["remove alpha"], "Remove pixel with low alpha value.");
addNodeObject(filter, "Normalize", s_node_normalize, "Node_Normalize", [1, Node_Normalize]).setVersion(11710); addNodeObject(filter, "Normalize", s_node_normalize, "Node_Normalize", [1, Node_Normalize]).setVersion(11710);

View file

@ -0,0 +1,126 @@
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform float h_curve[64];
uniform int h_amount;
uniform float s_curve[64];
uniform int s_amount;
uniform float v_curve[64];
uniform int v_amount;
float eval_curve_segment_t(in float _y0, in float ax0, in float ay0, in float bx1, in float by1, in float _y1, in float prog) {
return _y0 * pow(1. - prog, 3.) +
ay0 * 3. * pow(1. - prog, 2.) * prog +
by1 * 3. * (1. - prog) * pow(prog, 2.) +
_y1 * pow(prog, 3.);
}
float eval_curve_segment_x(in float _y0, in float ax0, in float ay0, in float bx1, in float by1, in float _y1, in float _x) {
float st = 0.;
float ed = 1.;
float _prec = 0.0001;
float _xt = _x;
int _binRep = 8;
if(_x <= 0.) return _y0;
if(_x >= 1.) return _y1;
if(_y0 == ay0 && _y0 == by1 && _y0 == _y1) return _y0;
for(int i = 0; i < _binRep; i++) {
float _ftx = 3. * pow(1. - _xt, 2.) * _xt * ax0
+ 3. * (1. - _xt) * pow(_xt, 2.) * bx1
+ pow(_xt, 3.);
if(abs(_ftx - _x) < _prec)
return eval_curve_segment_t(_y0, ax0, ay0, bx1, by1, _y1, _xt);
if(_xt < _x) st = _xt;
else ed = _xt;
_xt = (st + ed) / 2.;
}
int _newRep = 16;
for(int i = 0; i < _newRep; i++) {
float slope = ( 9. * ax0 - 9. * bx1 + 3.) * _xt * _xt
+ (-12. * ax0 + 6. * bx1) * _xt
+ 3. * ax0;
float _ftx = 3. * pow(1. - _xt, 2.) * _xt * ax0
+ 3. * (1. - _xt) * pow(_xt, 2.) * bx1
+ pow(_xt, 3.)
- _x;
_xt -= _ftx / slope;
if(abs(_ftx) < _prec)
break;
}
_xt = clamp(_xt, 0., 1.);
return eval_curve_segment_t(_y0, ax0, ay0, bx1, by1, _y1, _xt);
}
float curveEval(in float[64] curve, in int amo, in float _x) {
_x = clamp(_x, 0., 1.);
int segments = amo / 6 - 1;
for( int i = 0; i < segments; i++ ) {
int ind = i * 6;
float _x0 = curve[ind + 2];
float _y0 = curve[ind + 3];
//float bx0 = _x0 + curve[ind + 0];
//float by0 = _y0 + curve[ind + 1];
float ax0 = _x0 + curve[ind + 4];
float ay0 = _y0 + curve[ind + 5];
float _x1 = curve[ind + 6 + 2];
float _y1 = curve[ind + 6 + 3];
float bx1 = _x1 + curve[ind + 6 + 0];
float by1 = _y1 + curve[ind + 6 + 1];
//float ax1 = _x1 + curve[ind + 6 + 4];
//float ay1 = _y1 + curve[ind + 6 + 5];
if(_x < _x0) continue;
if(_x > _x1) continue;
return eval_curve_segment_x(_y0, ax0, ay0, bx1, by1, _y1, (_x - _x0) / (_x1 - _x0));
}
return curve[0];
}
#region =========================================== COLORS SPACES ===========================================
vec3 rgb2hsv(vec3 c) { #region
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 0.0000000001;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
} #endregion
vec3 hsv2rgb(vec3 c) { #region
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
} #endregion
#endregion =========================================== COLORS SPACES ===========================================
void main() {
vec4 col = texture2D( gm_BaseTexture, v_vTexcoord );
vec3 hsv = rgb2hsv(col.rgb);
hsv.r = curveEval(h_curve, h_amount, hsv.r);
hsv.g = curveEval(s_curve, s_amount, hsv.g);
hsv.b = curveEval(v_curve, v_amount, hsv.b);
vec3 rgb = hsv2rgb(hsv);
gl_FragColor = vec4(rgb, col.a);
}

View file

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

View file

@ -0,0 +1,12 @@
{
"$GMShader":"",
"%Name":"sh_curve_hsv",
"name":"sh_curve_hsv",
"parent":{
"name":"filter",
"path":"folders/shader/filter.yy",
},
"resourceType":"GMShader",
"resourceVersion":"2.0",
"type":1,
}

View file

@ -462,7 +462,7 @@ float marchDensity(vec3 camera, vec3 direction) {
float inst = (pos.y + objectScale) / (objectScale * 2.); float inst = (pos.y + objectScale) / (objectScale * 2.);
inst = inst <= 0.? 0. : pow(2., 10. * inst - 10.) * 10.; inst = inst <= 0.? 0. : pow(2., 10. * inst - 10.) * 10.;
if (hit <= 0.) dens += stp * inst; if (hit <= 0.) dens += stp;
} }
return dens; return dens;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,90 @@
{
"$GMSprite":"",
"%Name":"s_node_curve_hsv",
"bboxMode":0,
"bbox_bottom":61,
"bbox_left":2,
"bbox_right":61,
"bbox_top":2,
"collisionKind":1,
"collisionTolerance":0,
"DynamicTexturePage":false,
"edgeFiltering":false,
"For3D":false,
"frames":[
{"$GMSpriteFrame":"","%Name":"f2262182-4ebc-4362-bd6c-ae2591eef2f7","name":"f2262182-4ebc-4362-bd6c-ae2591eef2f7","resourceType":"GMSpriteFrame","resourceVersion":"2.0",},
],
"gridX":0,
"gridY":0,
"height":64,
"HTile":false,
"layers":[
{"$GMImageLayer":"","%Name":"42cf3477-e356-474f-bbfb-90f21d4c08aa","blendMode":0,"displayName":"default","isLocked":false,"name":"42cf3477-e356-474f-bbfb-90f21d4c08aa","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,},
],
"name":"s_node_curve_hsv",
"nineSlice":null,
"origin":4,
"parent":{
"name":"filter",
"path":"folders/nodes/icons/filter.yy",
},
"preMultiplyAlpha":false,
"resourceType":"GMSprite",
"resourceVersion":"2.0",
"sequence":{
"$GMSequence":"",
"%Name":"s_node_curve_hsv",
"autoRecord":true,
"backdropHeight":768,
"backdropImageOpacity":0.5,
"backdropImagePath":"",
"backdropWidth":1366,
"backdropXOffset":0.0,
"backdropYOffset":0.0,
"events":{
"$KeyframeStore<MessageEventKeyframe>":"",
"Keyframes":[],
"resourceType":"KeyframeStore<MessageEventKeyframe>",
"resourceVersion":"2.0",
},
"eventStubScript":null,
"eventToFunction":{},
"length":1.0,
"lockOrigin":false,
"moments":{
"$KeyframeStore<MomentsEventKeyframe>":"",
"Keyframes":[],
"resourceType":"KeyframeStore<MomentsEventKeyframe>",
"resourceVersion":"2.0",
},
"name":"s_node_curve_hsv",
"playback":1,
"playbackSpeed":30.0,
"playbackSpeedType":0,
"resourceType":"GMSequence",
"resourceVersion":"2.0",
"showBackdrop":true,
"showBackdropImage":false,
"timeUnits":1,
"tracks":[
{"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore<SpriteFrameKeyframe>":"","Keyframes":[
{"$Keyframe<SpriteFrameKeyframe>":"","Channels":{
"0":{"$SpriteFrameKeyframe":"","Id":{"name":"f2262182-4ebc-4362-bd6c-ae2591eef2f7","path":"sprites/s_node_curve_hsv/s_node_curve_hsv.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",},
},"Disabled":false,"id":"d8c6ba74-bd54-4f89-8766-0a3cd515c00a","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe<SpriteFrameKeyframe>","resourceVersion":"2.0","Stretch":false,},
],"resourceType":"KeyframeStore<SpriteFrameKeyframe>","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,},
],
"visibleRange":null,
"volume":1.0,
"xorigin":32,
"yorigin":32,
},
"swatchColours":null,
"swfPrecision":0.5,
"textureGroupId":{
"name":"Default",
"path":"texturegroups/Default",
},
"type":0,
"VTile":false,
"width":64,
}