FLIP improvements

This commit is contained in:
Tanasart 2024-03-22 15:44:11 +07:00
parent 0a7802759f
commit 15d1dc9df1
35 changed files with 530 additions and 67 deletions

View file

@ -1067,6 +1067,7 @@
{"name":"s_node_csv_parse","order":15,"path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",},
{"name":"sh_glow","order":19,"path":"shaders/sh_glow/sh_glow.yy",},
{"name":"sh_clean_shape","order":22,"path":"shaders/sh_clean_shape/sh_clean_shape.yy",},
{"name":"node_FLIP_repel","order":12,"path":"scripts/node_FLIP_repel/node_FLIP_repel.yy",},
{"name":"fd_rectangle_update","order":20,"path":"scripts/fd_rectangle_update/fd_rectangle_update.yy",},
{"name":"node_rigid_render_output","order":10,"path":"scripts/node_rigid_render_output/node_rigid_render_output.yy",},
{"name":"Obj_FirebaseFirestore_Collection_Query_options_value_path","order":12,"path":"objects/Obj_FirebaseFirestore_Collection_Query_options_value_path/Obj_FirebaseFirestore_Collection_Query_options_value_path.yy",},
@ -1169,6 +1170,7 @@
{"name":"sh_channel_R","order":4,"path":"shaders/sh_channel_R/sh_channel_R.yy",},
{"name":"draw_circle_functions","order":3,"path":"scripts/draw_circle_functions/draw_circle_functions.yy",},
{"name":"sliderRange","order":16,"path":"scripts/sliderRange/sliderRange.yy",},
{"name":"node_FLIP_to_VFX","order":14,"path":"scripts/node_FLIP_to_VFX/node_FLIP_to_VFX.yy",},
{"name":"point_rect_overlap","order":2,"path":"scripts/point_rect_overlap/point_rect_overlap.yy",},
{"name":"s_node_bevel","order":6,"path":"sprites/s_node_bevel/s_node_bevel.yy",},
{"name":"color_selector","order":4,"path":"scripts/color_selector/color_selector.yy",},
@ -1256,6 +1258,7 @@
{"name":"node_rigid_force_apply","order":4,"path":"scripts/node_rigid_force_apply/node_rigid_force_apply.yy",},
{"name":"checkboxActive","order":38,"path":"scripts/checkboxActive/checkboxActive.yy",},
{"name":"__node_shader","order":21,"path":"scripts/__node_shader/__node_shader.yy",},
{"name":"node_FLIP_vortex","order":13,"path":"scripts/node_FLIP_vortex/node_FLIP_vortex.yy",},
{"name":"__node_iterator","order":6,"path":"scripts/__node_iterator/__node_iterator.yy",},
{"name":"s_node_rigid_variable","order":8,"path":"sprites/s_node_rigid_variable/s_node_rigid_variable.yy",},
{"name":"safe_operation","order":6,"path":"scripts/safe_operation/safe_operation.yy",},
@ -1458,6 +1461,7 @@
{"name":"fd_rectangle_set_velocity_maccormack_weight","order":15,"path":"scripts/fd_rectangle_set_velocity_maccormack_weight/fd_rectangle_set_velocity_maccormack_weight.yy",},
{"name":"sh_pb_blob","order":1,"path":"shaders/sh_pb_blob/sh_pb_blob.yy",},
{"name":"s_node_array_sort","order":11,"path":"sprites/s_node_array_sort/s_node_array_sort.yy",},
{"name":"s_node_fluidSim_to_VFX","order":15,"path":"sprites/s_node_fluidSim_to_VFX/s_node_fluidSim_to_VFX.yy",},
{"name":"s_node_pb_fx_brick","order":28,"path":"sprites/s_node_pb_fx_brick/s_node_pb_fx_brick.yy",},
{"name":"s_node_pb_draw_roundrectangle","order":12,"path":"sprites/s_node_pb_draw_roundrectangle/s_node_pb_draw_roundrectangle.yy",},
{"name":"node_trail","order":15,"path":"scripts/node_trail/node_trail.yy",},

View file

@ -1365,6 +1365,7 @@
{"id":{"name":"s_node_csv_parse","path":"sprites/s_node_csv_parse/s_node_csv_parse.yy",},},
{"id":{"name":"sh_glow","path":"shaders/sh_glow/sh_glow.yy",},},
{"id":{"name":"sh_clean_shape","path":"shaders/sh_clean_shape/sh_clean_shape.yy",},},
{"id":{"name":"node_FLIP_repel","path":"scripts/node_FLIP_repel/node_FLIP_repel.yy",},},
{"id":{"name":"fd_rectangle_update","path":"scripts/fd_rectangle_update/fd_rectangle_update.yy",},},
{"id":{"name":"node_rigid_render_output","path":"scripts/node_rigid_render_output/node_rigid_render_output.yy",},},
{"id":{"name":"Obj_FirebaseFirestore_Collection_Query_options_value_path","path":"objects/Obj_FirebaseFirestore_Collection_Query_options_value_path/Obj_FirebaseFirestore_Collection_Query_options_value_path.yy",},},
@ -1480,6 +1481,7 @@
{"id":{"name":"sh_channel_R","path":"shaders/sh_channel_R/sh_channel_R.yy",},},
{"id":{"name":"draw_circle_functions","path":"scripts/draw_circle_functions/draw_circle_functions.yy",},},
{"id":{"name":"sliderRange","path":"scripts/sliderRange/sliderRange.yy",},},
{"id":{"name":"node_FLIP_to_VFX","path":"scripts/node_FLIP_to_VFX/node_FLIP_to_VFX.yy",},},
{"id":{"name":"point_rect_overlap","path":"scripts/point_rect_overlap/point_rect_overlap.yy",},},
{"id":{"name":"s_node_bevel","path":"sprites/s_node_bevel/s_node_bevel.yy",},},
{"id":{"name":"color_selector","path":"scripts/color_selector/color_selector.yy",},},
@ -1575,6 +1577,7 @@
{"id":{"name":"node_rigid_force_apply","path":"scripts/node_rigid_force_apply/node_rigid_force_apply.yy",},},
{"id":{"name":"checkboxActive","path":"scripts/checkboxActive/checkboxActive.yy",},},
{"id":{"name":"__node_shader","path":"scripts/__node_shader/__node_shader.yy",},},
{"id":{"name":"node_FLIP_vortex","path":"scripts/node_FLIP_vortex/node_FLIP_vortex.yy",},},
{"id":{"name":"__node_iterator","path":"scripts/__node_iterator/__node_iterator.yy",},},
{"id":{"name":"s_node_rigid_variable","path":"sprites/s_node_rigid_variable/s_node_rigid_variable.yy",},},
{"id":{"name":"safe_operation","path":"scripts/safe_operation/safe_operation.yy",},},
@ -1803,6 +1806,7 @@
{"id":{"name":"fd_rectangle_set_velocity_maccormack_weight","path":"scripts/fd_rectangle_set_velocity_maccormack_weight/fd_rectangle_set_velocity_maccormack_weight.yy",},},
{"id":{"name":"sh_pb_blob","path":"shaders/sh_pb_blob/sh_pb_blob.yy",},},
{"id":{"name":"s_node_array_sort","path":"sprites/s_node_array_sort/s_node_array_sort.yy",},},
{"id":{"name":"s_node_fluidSim_to_VFX","path":"sprites/s_node_fluidSim_to_VFX/s_node_fluidSim_to_VFX.yy",},},
{"id":{"name":"s_node_pb_fx_brick","path":"sprites/s_node_pb_fx_brick/s_node_pb_fx_brick.yy",},},
{"id":{"name":"s_node_pb_draw_roundrectangle","path":"sprites/s_node_pb_draw_roundrectangle/s_node_pb_draw_roundrectangle.yy",},},
{"id":{"name":"node_trail","path":"scripts/node_trail/node_trail.yy",},},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -2,6 +2,7 @@
#region params
domain = noone;
particlePosBuff = noone;
particleVelBuff = noone;
width = 0;
height = 0;
@ -20,6 +21,7 @@
numParticleIters = 2;
g = 1;
gDirection = 270;
flipRatio = 0.8;
overRelaxation = 1.5;
@ -30,10 +32,13 @@
skip_incompressible = false;
particleRadius = 0;
domain_preview = noone;
#endregion
function init(width, height, particleSize, density, maxParticles) { #region domain init
particlePos = array_create(maxParticles * 2);
particleVel = array_create(maxParticles * 2);
particleHist = array_create(maxParticles * 2 * TOTAL_FRAMES);
particleLife = array_create(maxParticles);
obstracles = [];
@ -57,9 +62,11 @@ function init(width, height, particleSize, density, maxParticles) { #region doma
self.maxParticles = maxParticles;
particlePosBuff = buffer_create(maxParticles * 2 * 8, buffer_grow, 8);
particleVelBuff = buffer_create(maxParticles * 2 * 8, buffer_grow, 8);
particleLifeBuff = buffer_create(maxParticles * 8, buffer_grow, 8);
aPosBuff = buffer_get_address(particlePosBuff);
aVelBuff = buffer_get_address(particleVelBuff);
aLifeBuff = buffer_get_address(particleLifeBuff);
domain = FLIP_initDomain(width, height, particleSize, density, maxParticles);
@ -67,11 +74,13 @@ function init(width, height, particleSize, density, maxParticles) { #region doma
cellX = floor(width / particleSize) + 1;
cellY = floor(height / particleSize) + 1;
domain_preview = surface_verify(domain_preview, width, height);
} #endregion
function update() { #region
FLIP_setQuality( domain, iteration, numPressureIters, numParticleIters);
FLIP_setGravity( domain, g);
FLIP_setGravity( domain, g, gDirection);
FLIP_setViscosity( domain, viscosity);
FLIP_setFriction( domain, friction);
FLIP_setFlipRatio( domain, flipRatio);
@ -110,15 +119,20 @@ function step() { #region
}
FLIP_setParticleBuffer(domain, aPosBuff, aLifeBuff);
FLIP_setParticleVelocityBuffer(domain, aVelBuff);
buffer_seek(particlePosBuff, buffer_seek_start, 0);
buffer_seek(particleVelBuff, buffer_seek_start, 0);
buffer_seek(particleLifeBuff, buffer_seek_start, 0);
for(var i = 0; i < maxParticles * 2; i++) {
particleHist[maxParticles * 2 * CURRENT_FRAME + i] = particlePos[i];
particlePos[i] = buffer_read(particlePosBuff, buffer_f64);
particleVel[i] = buffer_read(particleVelBuff, buffer_f64);
}
for(var i = 0; i < maxParticles; i++)
particleLife[i] = buffer_read(particleLifeBuff, buffer_f64);
domain_preview = surface_verify(domain_preview, width, height);
} #endregion

View file

@ -15,7 +15,20 @@ enum PARTICLE_RENDER_TYPE {
line,
}
function __part(_node) constructor {
function __particleObject() constructor {
active = false;
x = 0;
y = 0;
static kill = function() {}
static step = function() {}
static draw = function() {}
}
function __part(_node) : __particleObject() constructor {
seed = irandom(99999);
node = _node;
active = false;

View file

@ -16,12 +16,33 @@ function draw_polygon(x, y, r, sides, a = 0) { #region
draw_primitive_end();
} #endregion
function draw_circle_border(xx, yy, r, w) { #region
var step = 32;
var angle_step = 360 / step;
function draw_circle_color_alpha(_x, _y, _r, colI, colO, alpI, alpO) { #region
var _step = 32;
var angle_step = 360 / _step;
draw_primitive_begin(pr_trianglestrip);
for(var i = 0; i <= step; i++){
for(var i = 0; i <= _step; i++) {
var a0 = i * angle_step;
var a1 = i * angle_step + angle_step;
var p0x = _x + lengthdir_x(_r, a0);
var p0y = _y + lengthdir_y(_r, a0);
var p1x = _x + lengthdir_x(_r, a1);
var p1y = _y + lengthdir_y(_r, a1);
draw_vertex_color(_x, _y, colI, alpI);
draw_vertex_color(p0x, p0y, colO, alpO);
draw_vertex_color(p1x, p1y, colO, alpO);
}
draw_primitive_end();
} #endregion
function draw_circle_border(xx, yy, r, w) { #region
var _step = 32;
var angle_step = 360 / _step;
draw_primitive_begin(pr_trianglestrip);
for(var i = 0; i <= _step; i++){
var p0x = xx + lengthdir_x(r - w / 2, i * angle_step);
var p0y = yy + lengthdir_y(r - w / 2, i * angle_step);
var p1x = xx + lengthdir_x(r + w / 2, i * angle_step);

View file

@ -90,9 +90,9 @@ function gradientObject(color = c_black) constructor { #region
static evalFast = function(position) { #region
INLINE
var _len = array_length(keys);
if(position <= keys[0].time) return keys[0].value;
if(position >= keys[keyLength - 1].time) return keys[keyLength - 1].value;
if(position >= keys[_len - 1].time) return keys[_len - 1].value;
var _ind = round(position * cacheRes);
return caches[_ind];

View file

@ -80,6 +80,7 @@ function Node_FLIP_Apply_Force(_x, _y, _group = noone) : Node(_x, _y, _group) co
draw_surface_ext(_tex, _px - _sw / 2, _py - _sh / 2, _s, _s, 0, c_white, 1);
}
draw_set_circle_precision(32);
draw_set_color(COLORS._main_accent);
if(_shp == 0) draw_circle(_px, _py, _r, true);
else if(_shp == 1) draw_rectangle(_px - _w, _py - _h, _px + _w, _py + _h, true);
@ -126,4 +127,6 @@ function Node_FLIP_Apply_Force(_x, _y, _group = noone) : Node(_x, _y, _group) co
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_bbox(s_node_fluidSim_add_collider, 0, bbox);
} #endregion
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -57,7 +57,7 @@ function Node_FLIP_Apply_Velocity(_x, _y, _group = noone) : Node(_x, _y, _group)
var _h = _siz[1] * _s;
draw_set_color(COLORS._main_accent);
if(_shp == 0) draw_circle(_px, _py, _r, true);
if(_shp == 0) draw_circle_prec(_px, _py, _r, true, 32);
else if(_shp == 1) draw_rectangle(_px - _w, _py - _h, _px + _w, _py + _h, true);
draw_set_color(COLORS._main_accent);
@ -97,4 +97,6 @@ function Node_FLIP_Apply_Velocity(_x, _y, _group = noone) : Node(_x, _y, _group)
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_apply_velocity, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -76,4 +76,6 @@ function Node_FLIP_Destroy(_x, _y, _group = noone) : Node(_x, _y, _group) constr
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_destroy_fluid, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -29,8 +29,8 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
inputs[| 8] = nodeValue("Time Step", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.05);
inputs[| 9] = nodeValue("Wall type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1)
.setDisplay(VALUE_DISPLAY.enum_button, [ "None", "Surround", "Ground only" ]);
inputs[| 9] = nodeValue("Wall", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0b1111)
.setDisplay(VALUE_DISPLAY.toggle, { data: [ "T", "B", "L", "R" ] });
inputs[| 10] = nodeValue("Viscosity", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.)
.setDisplay(VALUE_DISPLAY.slider, { range: [ -1, 1, 0.01 ] });
@ -41,10 +41,13 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
inputs[| 12] = nodeValue("Wall Elasticity", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.)
.setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 2, 0.01 ] });
inputs[| 13] = nodeValue("Gravity Direction", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 270)
.setDisplay(VALUE_DISPLAY.rotation);
input_display_list = [
["Domain", false], 0, 1, 9, 12,
["Solver", true], 3, 8,
["Physics", false], 7, 10, 11,
["Physics", false], 7, 13, 10, 11,
]
outputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.output, VALUE_TYPE.fdomain, noone);
@ -118,6 +121,7 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _vis = getInputData(10);
var _fric = getInputData(11);
var _ela = getInputData(12);
var _gdir = getInputData(13);
var _ovr = attributes.overrelax;
@ -125,9 +129,10 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _itrP = attributes.iteration_pressure;
var _itrR = attributes.iteration_particle;
if(IS_FIRST_FRAME || toReset) {
var width = _dim[0] + _siz * 2;
var height = _dim[1] + _siz * 2;
if(IS_FIRST_FRAME || toReset) {
var particleSize = _siz;
var density = _den;
var maxParticles = attributes.max_particles;
@ -145,6 +150,7 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
domain.numParticleIters = _itrR;
domain.g = _grv;
domain.gDirection = _gdir;
domain.flipRatio = _flp;
domain.overRelaxation = _ovr;
domain.viscosity = _vis;
@ -163,4 +169,7 @@ function Node_FLIP_Domain(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_bbox(s_node_fluidSim_domain, 0, bbox);
} #endregion
static getPreviewValues = function() { return domain.domain_preview; }
}

View file

@ -14,7 +14,7 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
inputs[| 2] = nodeValue("Lifespan", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, [ 0, 0 ])
.setDisplay(VALUE_DISPLAY.range, { linked : true });
inputs[| 3] = nodeValue("Particle expansion", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 10);
inputs[| 3] = nodeValue("Particle expansion", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 20);
inputs[| 4] = nodeValue("Draw obstracles", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
@ -33,9 +33,14 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
inputs[| 10] = nodeValue("Segments", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1);
inputs[| 11] = nodeValue("Color Over Velocity", self, JUNCTION_CONNECT.input, VALUE_TYPE.gradient, new gradientObject(c_white));
inputs[| 12] = nodeValue("Velocity Map", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 10 ])
.setDisplay(VALUE_DISPLAY.range);
input_display_list = [ 0, 5,
["Rendering", false], 6, 10, 3, 4, 9,
["Effect", false], 2,
["Effect", false], 11, 12, 2,
["Post Processing", false], 8, 7, 1,
];
@ -53,22 +58,29 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
triggerRender();
})]);
attributes.debugDraw = false;
array_push(attributeEditors, ["Draw Fluid Particles", function() { return attributes.debugDraw; },
new checkBox(function() {
attributes.debugDraw = !attributes.debugDraw;
})]);
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var domain = getInputData(0);
if(!instance_exists(domain)) return;
if(domain.domain == noone) return;
if(attributes.debugDraw) {
var _m = min(array_length(domain.particlePos) / 2 - 1, domain.numParticles);
draw_set_color(COLORS._main_accent);
for( var i = 0; i < _m; i++ ) {
var _px = domain.particlePos[i * 2 + 0];
var _py = domain.particlePos[i * 2 + 1];
var _px = domain.particlePos[i * 2 + 0] - 1;
var _py = domain.particlePos[i * 2 + 1] - 1;
draw_circle(_x + _px * _s, _y + _py * _s, 1, false);
}
}
} #endregion
static step = function() {
@ -98,6 +110,8 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
var _add = getInputData(8);
var _alp = getInputData(9);
var _seg = getInputData(10);
var _cvl = getInputData(11);
var _vlr = getInputData(12);
var _outSurf = outputs[| 0].getValue();
var _maxpart = domain.maxParticles;
@ -110,7 +124,7 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
outputs[| 0].setValue(_outSurf);
var _x, _y, _px, _py, _r, _l, _a, _v;
var _x, _y, _px, _py, _r, _l, _a, _v, _sx, _sy;
var _rad = domain.particleRadius * _exp;
var _mx = min(array_length(domain.particlePos) / 2 - 1, domain.numParticles);
@ -126,6 +140,10 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
_sprh = 0.5 * surface_get_height_safe(_spr[0]);
}
var _useMapRange = array_length(_cvl.keys) > 1;
var _vMapRange = _vlr[1] - _vlr[0];
var _cc = _cvl.keys[0].value;
random_set_seed(seed);
surface_set_shader(temp_surface[0], _useSpr? noone : sh_FLIP_draw_droplet);
@ -136,6 +154,8 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
for( var i = 0; i < _mx; i++ ) {
_x = domain.particlePos[i * 2 + 0];
_y = domain.particlePos[i * 2 + 1];
_sx = domain.particleVel[i * 2 + 0];
_sy = domain.particleVel[i * 2 + 1];
_l = domain.particleLife[i];
if(_x == 0 && _y == 0) continue;
@ -151,20 +171,24 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
if(_r * _rad < 0.5) continue;
}
if(_useMapRange) {
var _vel = sqrt(_sx * _sx + _sy * _sy);
var _vmap = (_vel - _vlr[0]) / _vMapRange;
_vmap = power(clamp(_vmap, 0, 1), 5);
_cc = _cvl.eval(_vmap);
}
if(_useSpr) {
if(is_array(_spr)) draw_surface_ext(_spr[i % array_length(_spr)], _x - _sprw * _r, _y - _sprh * _r, _r, _r, 0, c_white, _a * _r);
else draw_surface_ext(_spr, _x - _sprw * _r, _y - _sprh * _r, _r, _r, 0, c_white, _a * _r);
if(is_array(_spr)) draw_surface_ext(_spr[i % array_length(_spr)], _x - _sprw * _r, _y - _sprh * _r, _r, _r, 0, _cc, _a * _r);
else draw_surface_ext(_spr, _x - _sprw * _r, _y - _sprh * _r, _r, _r, 0, _cc, _a * _r);
} else {
draw_set_alpha(_a * _r);
draw_circle_color(_x, _y, _rad, c_white, c_black, false);
draw_set_alpha(1);
draw_circle_color_alpha(_x, _y, _rad, _cc, _cc, _a * _r, 0);
}
}
} else if(_typ == 1) {
var _segg = min(_seg, CURRENT_FRAME);
var _ox, _oy, _nx, _ny;
draw_set_color(c_white);
for( var i = 0; i < _mx; i++ ) {
_l = domain.particleLife[i];
@ -189,9 +213,19 @@ function Node_FLIP_Render(_x, _y, _group = noone) : Node(_x, _y, _group) constru
if(_nx == 0 && _ny == 0) continue;
if(_useMapRange) {
var _dx = _ox - _nx;
var _dy = _oy - _ny;
var _vel = sqrt(_dx * _dx + _dy * _dy);
var _vmap = (_vel - _vlr[0]) / _vMapRange;
_vmap = power(clamp(_vmap, 0, 1), 5);
_cc = _cvl.eval(_vmap);
}
_nx -= _padd;
_ny -= _padd;
draw_set_color(_cc);
draw_line(_ox, _oy, _nx, _ny);
_ox = _nx;

View file

@ -0,0 +1,74 @@
function Node_FLIP_Repel(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Repel";
color = COLORS.node_blend_fluid;
icon = THEME.fluid_sim;
w = 96;
min_h = 96;
manual_ungroupable = false;
inputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.input, VALUE_TYPE.fdomain, noone )
.setVisible(true, true);
inputs[| 1] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector)
.setUnitRef(function(index) { return getDimension(); });
inputs[| 2] = nodeValue("Radius", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4 );
inputs[| 3] = nodeValue("Strength", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4 )
.setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 16, 0.1 ] });
input_display_list = [ 0,
["Repel", false], 1, 2, 3,
]
outputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.output, VALUE_TYPE.fdomain, noone );
static getDimension = function() { #region
var domain = getInputData(0);
if(!instance_exists(domain)) return [ 1, 1 ];
return [ domain.width, domain.height ];
} #endregion
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _posit = getInputData(1);
var _rad = getInputData(2);
var _px = _x + _posit[0] * _s;
var _py = _y + _posit[1] * _s;
var _r = _rad * _s;
draw_set_color(COLORS._main_accent);
draw_circle_prec(_px, _py, _r, true, 32);
if(inputs[| 1].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny)) { hover = false; active = false; }
} #endregion
static step = function() { #region
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
var domain = getInputData(0);
if(!instance_exists(domain)) return;
outputs[| 0].setValue(domain);
var _posit = getInputData(1);
var _rad = getInputData(2);
var _str = getInputData(3);
FLIP_Repel(domain.domain, _posit[0], _posit[1], _rad, _str * 8);
} #endregion
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_repulse, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_FLIP_repel",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "FLIP",
"path": "folders/nodes/data/simulation/FLIP.yy",
},
}

View file

@ -11,7 +11,7 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
.setVisible(true, true);
inputs[| 1] = nodeValue("Spawn Shape", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0 )
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Circle", "Surface" ]);
.setDisplay(VALUE_DISPLAY.enum_scroll, [ new scrollItem("Circle", s_node_shape_type, 1), new scrollItem("Rectangle", s_node_shape_type, 0), "Surface" ]);
inputs[| 2] = nodeValue("Spawn Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector)
@ -42,8 +42,11 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
inputs[| 12] = nodeValue("Spawn Duration", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 1 );
inputs[| 13] = nodeValue("Spawn Szie", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 2, 2 ] )
.setDisplay(VALUE_DISPLAY.vector);
input_display_list = [ 0, 9,
["Spawner", false], 1, 7, 8, 2, 3, 4, 12, 5,
["Spawner", false], 1, 7, 8, 13, 2, 3, 4, 12, 5,
["Physics", false], 10, 6, 11,
]
@ -65,7 +68,14 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
draw_set_color(COLORS._main_accent);
draw_circle(_px, _py, _rad * _s, true);
} else if(_shp == 1) {
var _siz = getInputData(13);
draw_set_color(COLORS._main_accent);
draw_rectangle(_px - _siz[0] * _s, _py - _siz[1] * _s, _px + _siz[0] * _s, _py + _siz[1] * _s, true);
} else if(_shp == 2) {
var _surf = getInputData(7);
if(!is_surface(_surf)) return;
@ -92,8 +102,10 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
inputs[| 4].setVisible(_typ == 1);
inputs[| 12].setVisible(_typ == 1);
inputs[| 7].setVisible(_shp == 1, _shp == 1);
inputs[| 7].setVisible(_shp == 2, _shp == 2);
inputs[| 8].setVisible(_shp == 0);
inputs[| 13].setVisible(_shp == 1);
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
@ -115,6 +127,7 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
var _dirr = getInputData(10);
var _ivel = getInputData(11);
var _sdur = getInputData(12);
var _siz = getInputData(13);
if(IS_FIRST_FRAME || toReset) spawn_amo = 0;
toReset = false;
@ -124,14 +137,14 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
if(spawn_amo < 1) return;
if(_type == 1 && (frame < _fra || frame >= _fra + _sdur)) return;
if(_shape == 1 && !is_surface(_surf)) return;
if(_shape == 2 && !is_surface(_surf)) return;
var _samo = floor(spawn_amo);
spawn_amo -= _samo;
var _points = [];
if(_shape == 1) {
if(_shape == 2) {
var _sw = surface_get_width(_surf);
var _sh = surface_get_height(_surf);
@ -163,7 +176,12 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
_x = _posit[0] + lengthdir_x(_dis, _dir);
_y = _posit[1] + lengthdir_y(_dis, _dir);
} else if(_shape == 1) {
_x = _posit[0] + random_range(-_siz[0], _siz[0]);
_y = _posit[1] + random_range(-_siz[1], _siz[1]);
} else if(_shape == 2) {
_x = _posit[0] - _sw / 2 + _points[ind][0] * _sw;
_y = _posit[1] - _sh / 2 + _points[ind][1] * _sh;
}
@ -196,4 +214,6 @@ function Node_FLIP_Spawner(_x, _y, _group = noone) : Node(_x, _y, _group) constr
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_add_fluid, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
} #endregion
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -0,0 +1,58 @@
function Node_FLIP_to_VFX(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "FLIP to VFX";
color = COLORS.node_blend_fluid;
icon = THEME.fluid_sim;
w = 96;
min_h = 96;
manual_ungroupable = false;
inputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.input, VALUE_TYPE.fdomain, noone)
.setVisible(true, true);
outputs[| 0] = nodeValue("Particles", self, JUNCTION_CONNECT.output, VALUE_TYPE.particle, [] );
attributes.part_amount = 512;
array_push(attributeEditors, ["Maximum particles", function() { return attributes.part_amount; },
new textBox(TEXTBOX_INPUT.number, function(val) { attributes.part_amount = val; }) ]);
for( var i = 0; i < attributes.part_amount; i++ )
parts[i] = new __particleObject();
static update = function(frame = CURRENT_FRAME) {
var domain = getInputData(0);
if(!instance_exists(domain)) return;
if(domain.domain == noone) return;
var _x, _y, _px, _py, _r, _l, _a, _v, _sx, _sy;
var _mx = min(array_length(domain.particlePos) / 2 - 1, domain.numParticles);
var _ind = 0, _p;
for( var i = 0; i < _mx; i++ ) {
_x = domain.particlePos[i * 2 + 0];
_y = domain.particlePos[i * 2 + 1];
if(_x == 0 && _y == 0) continue;
_p = parts[_ind++];
_p.active = true;
_p.x = _x;
_p.y = _y;
if(_ind >= attributes.part_amount) break;
}
for( ; _ind < attributes.part_amount; i++ ) {
_p = parts[_ind++];
_p.active = false;
}
outputs[| 0].setValue(parts);
}
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_to_VFX, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_FLIP_to_VFX",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "FLIP",
"path": "folders/nodes/data/simulation/FLIP.yy",
},
}

View file

@ -45,4 +45,6 @@ function Node_FLIP_Update(_x, _y, _group = noone) : Node(_x, _y, _group) constru
draw_sprite_fit(_active? s_node_fluidSim_update : s_node_fluidSim_update_paused, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -0,0 +1,78 @@
function Node_FLIP_Vortex(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Vortex";
color = COLORS.node_blend_fluid;
icon = THEME.fluid_sim;
w = 96;
min_h = 96;
manual_ungroupable = false;
inputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.input, VALUE_TYPE.fdomain, noone )
.setVisible(true, true);
inputs[| 1] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector)
.setUnitRef(function(index) { return getDimension(); });
inputs[| 2] = nodeValue("Radius", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4 );
inputs[| 3] = nodeValue("Strength", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4 )
.setDisplay(VALUE_DISPLAY.slider, { range: [ -8, 8, 0.01 ] });
inputs[| 4] = nodeValue("Attraction", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0 )
.setDisplay(VALUE_DISPLAY.slider, { range: [ -8, 8, 0.01 ] });
input_display_list = [ 0,
["Vertex", false], 1, 2, 3, 4,
]
outputs[| 0] = nodeValue("Domain", self, JUNCTION_CONNECT.output, VALUE_TYPE.fdomain, noone );
static getDimension = function() { #region
var domain = getInputData(0);
if(!instance_exists(domain)) return [ 1, 1 ];
return [ domain.width, domain.height ];
} #endregion
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
var _posit = getInputData(1);
var _rad = getInputData(2);
var _px = _x + _posit[0] * _s;
var _py = _y + _posit[1] * _s;
var _r = _rad * _s;
draw_set_color(COLORS._main_accent);
draw_circle_prec(_px, _py, _r, true, 32);
if(inputs[| 1].drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny)) { hover = false; active = false; }
} #endregion
static step = function() { #region
} #endregion
static update = function(frame = CURRENT_FRAME) { #region
var domain = getInputData(0);
if(!instance_exists(domain)) return;
outputs[| 0].setValue(domain);
var _posit = getInputData(1);
var _rad = getInputData(2);
var _str = getInputData(3);
var _attr = getInputData(4);
FLIP_Vortex(domain.domain, _posit[0], _posit[1], _rad, _str, _attr);
} #endregion
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_fluidSim_vortex, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
static getPreviewValues = function() { var domain = getInputData(0); return instance_exists(domain)? domain.domain_preview : noone; }
}

View file

@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "node_FLIP_vortex",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "FLIP",
"path": "folders/nodes/data/simulation/FLIP.yy",
},
}

View file

@ -16,7 +16,8 @@ function Node_Cellular(_x, _y, _group = noone) : Node_Processor(_x, _y, _group)
inputs[| 4] = nodeValue("Type", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_scroll, [ "Point", "Edge", "Cell", "Crystal" ]);
inputs[| 5] = nodeValue("Contrast", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1);
inputs[| 5] = nodeValue("Contrast", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1)
.setDisplay(VALUE_DISPLAY.slider, { range: [0, 4, 0.01] });
inputs[| 6] = nodeValue("Pattern", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0)
.setDisplay(VALUE_DISPLAY.enum_button, [ "Uniform", "Radial" ]);

View file

@ -443,8 +443,15 @@ function __initNodes() {
ds_list_add(flipSim, "Fluid");
addNodeObject(flipSim, "Spawner", s_node_fluidSim_add_fluid, "Node_FLIP_Spawner", [1, Node_FLIP_Spawner]).hideRecent().setVersion(11620);
addNodeObject(flipSim, "Destroy", s_node_fluidSim_destroy_fluid, "Node_FLIP_Destroy", [1, Node_FLIP_Destroy]).hideRecent().setVersion(11680);
ds_list_add(flipSim, "Affectors");
addNodeObject(flipSim, "Apply Velocity", s_node_fluidSim_apply_velocity, "Node_FLIP_Apply_Velocity", [1, Node_FLIP_Apply_Velocity]).hideRecent().setVersion(11620);
addNodeObject(flipSim, "Add Collider", s_node_fluidSim_force, "Node_FLIP_Apply_Force", [1, Node_FLIP_Apply_Force]).hideRecent().setVersion(11620);
addNodeObject(flipSim, "Repel", s_node_fluidSim_repulse, "Node_FLIP_Repel", [1, Node_FLIP_Repel]).hideRecent().setVersion(11680);
addNodeObject(flipSim, "Vortex", s_node_fluidSim_vortex, "Node_FLIP_Vortex", [1, Node_FLIP_Vortex]).hideRecent().setVersion(11680);
ds_list_add(flipSim, "Misc");
addNodeObject(flipSim, "FLIP to VFX", s_node_fluidSim_to_VFX, "Node_FLIP_to_VFX", [1, Node_FLIP_to_VFX]).hideRecent().setVersion(11680);
#endregion
var strandSim = ds_list_create(); #region

View file

@ -1927,7 +1927,7 @@ function Panel_Animation() : PanelContent() constructor {
draw_sprite_ui(THEME.animation_stretch, 1, stx, sty, 1, 1, 0, COLORS.panel_animation_end_line, 1);
} else {
if(pHOVER && point_in_circle(msx, msy, stx, sty, sty)) {
if(!IS_PLAYING && pHOVER && point_in_circle(msx, msy, stx, sty, sty)) {
if(key_mod_press(CTRL)) {
draw_sprite_ui(THEME.animation_stretch, 1, stx, sty, 1, 1, 0, COLORS._main_icon, 1);
TOOLTIP = __txtx("panel_animation_stretch", "Stretch animation");

View file

@ -975,6 +975,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor {
nodes_selecting = [ node_hovering ];
}
if(WIDGET_CURRENT) WIDGET_CURRENT.deactivate();
array_foreach(nodes_selecting, function(node) { bringNodeToFront(node); });
}
}
@ -1834,7 +1835,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor {
}
} #endregion
#region ++++ node manipulation ++++
#region ++++++++++++++++ node manipulation ++++++++++++++++
function doTransform() { #region
for( var i = 0; i < array_length(nodes_selecting); i++ ) {
var node = nodes_selecting[i];
@ -1860,6 +1861,8 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor {
APPENDING = true;
CLONING = true;
var _app = __APPEND_MAP(_map);
recordAction(ACTION_TYPE.collection_loaded, array_create_from_list(_app));
APPENDING = false;
CLONING = false;
@ -1868,6 +1871,14 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor {
return;
}
for(var i = 0; i < array_length(nodes_selecting); i++) {
var _orignal = nodes_selecting[i];
var _cloned = ds_map_try_get(APPEND_MAP, _orignal.node_id, "");
if(_orignal.inline_context != noone && _cloned != "")
_orignal.inline_context.addNode(PROJECT.nodeMap[? _cloned]);
}
var x0 = 99999999;
var y0 = 99999999;
for(var i = 0; i < ds_list_size(_app); i++) {

View file

@ -1,12 +1,8 @@
//
// Simple passthrough fragment shader
//
//varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main() {
float g = v_vColour.g;
g = pow(g, 5.);
float a = v_vColour.a;
a = pow(a, 5.);
gl_FragColor = vec4(vec3(g), v_vColour.a);
gl_FragColor = vec4(v_vColour.rgb, a);
}

View file

@ -10,6 +10,6 @@ void main() {
vec4 fluid = texture2D( gm_BaseTexture, v_vTexcoord );
gl_FragColor = vec4(0.);
if(fluid.r * fluid.a > threshold)
gl_FragColor = vec4(1.);
if(fluid.a > threshold)
gl_FragColor = vec4(fluid.rgb, 1.);
}

View file

@ -6,6 +6,8 @@ varying vec4 v_vColour;
uniform vec2 dimension;
uniform vec2 position;
uniform float time;
uniform float contrast;
uniform float middle;
uniform vec2 scale;
uniform int scaleUseSurf;
@ -57,6 +59,7 @@ void main() {
vec2 p = ((v_vTexcoord - position / dimension) * sca * 2.0 - 1.0);
float n = voronoi3d(vec3(p, time), sca);
n = middle + (n - middle) * contrast;
gl_FragColor = vec4(vec3(n), 1.);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,74 @@
{
"resourceType": "GMSprite",
"resourceVersion": "1.0",
"name": "s_node_fluidSim_to_VFX",
"bbox_bottom": 59,
"bbox_left": 3,
"bbox_right": 60,
"bbox_top": 3,
"bboxMode": 0,
"collisionKind": 1,
"collisionTolerance": 0,
"DynamicTexturePage": false,
"edgeFiltering": false,
"For3D": false,
"frames": [
{"resourceType":"GMSpriteFrame","resourceVersion":"1.1","name":"0b201479-38f2-408b-8cc7-b44246e1e61a",},
],
"gridX": 0,
"gridY": 0,
"height": 64,
"HTile": false,
"layers": [
{"resourceType":"GMImageLayer","resourceVersion":"1.0","name":"84439052-9d4d-4d0e-b151-6318351780ab","blendMode":0,"displayName":"default","isLocked":false,"opacity":100.0,"visible":true,},
],
"nineSlice": null,
"origin": 4,
"parent": {
"name": "fluidSim",
"path": "folders/nodes/icons/fluidSim.yy",
},
"preMultiplyAlpha": false,
"sequence": {
"resourceType": "GMSequence",
"resourceVersion": "1.4",
"name": "s_node_fluidSim_to_VFX",
"autoRecord": true,
"backdropHeight": 768,
"backdropImageOpacity": 0.5,
"backdropImagePath": "",
"backdropWidth": 1366,
"backdropXOffset": 0.0,
"backdropYOffset": 0.0,
"events": {"resourceType":"KeyframeStore<MessageEventKeyframe>","resourceVersion":"1.0","Keyframes":[],},
"eventStubScript": null,
"eventToFunction": {},
"length": 1.0,
"lockOrigin": false,
"moments": {"resourceType":"KeyframeStore<MomentsEventKeyframe>","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<SpriteFrameKeyframe>","resourceVersion":"1.0","Keyframes":[
{"resourceType":"Keyframe<SpriteFrameKeyframe>","resourceVersion":"1.0","Channels":{"0":{"resourceType":"SpriteFrameKeyframe","resourceVersion":"1.0","Id":{"name":"0b201479-38f2-408b-8cc7-b44246e1e61a","path":"sprites/s_node_fluidSim_to_VFX/s_node_fluidSim_to_VFX.yy",},},},"Disabled":false,"id":"00f935d5-1604-4bb4-835a-7033b78dfae4","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,
}