Pixel-Composer/scripts/_smokeSim_domain/_smokeSim_domain.gml
2024-11-22 15:43:50 +07:00

348 lines
No EOL
12 KiB
Text

enum FD_TARGET_TYPE {
REPLACE_MATERIAL,
ADD_MATERIAL,
REPLACE_VELOCITY,
ADD_VELOCITY,
}
enum FD_BOUNDARY_TYPE {
empty,
wall,
wrap
}
function smokeSim_Domain(_width, _height) constructor {
sf_world = noone;
sf_world_update = true;
material_surface_was_created = false;
acceleration_type = 0;
acceleration_a = 0;
acceleration_b = 0;
acceleration_x = 0;
acceleration_y = 0;
time_step = 1;
initial_value_pressure = 0.5;
material_dissipation_type = 0;
material_dissipation_value = 1;
velocity_dissipation_type = 1;
velocity_dissipation_value = 0;
velocity_maccormack_weight = 0.5;
material_maccormack_weight = 0;
pressure_type = -3;
pressure_relax = 0;
texture_repeat = false;
texture_wall = false;
sf_world = 0;
sf_pressure = 0; sf_pressure_t = 0;
sf_velocity = 0; sf_velocity_t = 0;
sf_material = 0; sf_material_t = 0;
max_force = 10;
static setSize = function(_width, _height) {
width = _width;
height = _height;
tx_width = 1 / width;
tx_height = 1 / height;
verify();
return self;
}
static resetSize = function(_width, _height) {
free();
setSize(_width, _height);
return self;
}
static verify = function() {
var _f = surface_rgba32float;
if(!surface_valid(sf_pressure, width, height, _f)) { sf_pressure = surface_verify(sf_pressure, width, height, _f); surface_clear(sf_pressure); }
if(!surface_valid(sf_pressure_t, width, height, _f)) { sf_pressure_t = surface_verify(sf_pressure_t, width, height, _f); surface_clear(sf_pressure_t); }
if(!surface_valid(sf_velocity, width, height, _f)) { sf_velocity = surface_verify(sf_velocity, width, height, _f); surface_clear(sf_velocity); }
if(!surface_valid(sf_velocity_t, width, height, _f)) { sf_velocity_t = surface_verify(sf_velocity_t, width, height, _f); surface_clear(sf_velocity_t); }
if(!surface_valid(sf_material, width, height, _f)) { sf_material = surface_verify(sf_material, width, height, _f); surface_clear(sf_material); }
if(!surface_valid(sf_material_t, width, height, _f)) { sf_material_t = surface_verify(sf_material_t, width, height, _f); surface_clear(sf_material_t); }
sf_world = surface_verify(sf_world, width, height, _f);
if (sf_world_update) {
surface_set_target(sf_world);
draw_clear_alpha(0, 0);
surface_reset_target();
sf_world_update = false;
}
}
static setAcceleration = function(xacc, yacc, a = 0, b = 0) {
acceleration_x = xacc;
acceleration_y = yacc;
acceleration_a = a;
acceleration_b = b;
acceleration_type = 1;
if ((xacc == 0 && yacc == 0) || (acceleration_a == 0 && acceleration_b == 0))
acceleration_type = 0;
return self;
}
static setMaterial = function(type, value) {
material_dissipation_type = type;
material_dissipation_value = value;
return self;
}
static setVelocity = function(type, value) {
velocity_dissipation_type = type;
velocity_dissipation_value = value;
return self;
}
static setMaccormack = function(vel, mat) {
velocity_maccormack_weight = vel;
material_maccormack_weight = mat;
return self;
}
static setPressure = function(iteration) {
pressure_type = iteration;
pressure_relax = 0;
if (iteration >= 0) return;
var i = 0, j = 0;
switch (iteration) {
case -1:
for (j = 0; j < 1; ++j) pressure_relax[i++] = j == 0? 32.6 : -1;
for (j = 0; j < 15; ++j) pressure_relax[i++] = j == 0? 0.8630 : -1;
break;
case -2:
for (j = 0; j < 1; ++j) pressure_relax[i++] = j == 0? 81.22 : -1;
for (j = 0; j < 30; ++j) pressure_relax[i++] = j == 0? 0.9178 : -1;
break;
case -3:
for (j = 0; j < 1; ++j) pressure_relax[i++] = j == 0? 190.2 : -1;
for (j = 0; j < 63; ++j) pressure_relax[i++] = j == 0? 0.9532 : -1;
break;
case -4:
for (j = 0; j < 1; ++j) pressure_relax[i++] = j == 0? 425.8 : -1;
for (j = 0; j < 130; ++j) pressure_relax[i++] = j == 0? 0.9742 : -1;
break;
}
}
static setBoundary = function(boundary) {
switch(boundary) {
case FD_BOUNDARY_TYPE.empty :
texture_repeat = false;
texture_wall = false;
break;
case FD_BOUNDARY_TYPE.wall :
texture_repeat = false;
texture_wall = true;
break;
case FD_BOUNDARY_TYPE.wrap :
texture_repeat = true;
texture_wall = false;
break;
}
return self;
}
static addMaterial = function(surface, _x, _y, xscale, yscale, color, alpha) {
setTarget(FD_TARGET_TYPE.ADD_MATERIAL);
draw_surface_ext_safe(surface, _x, _y, xscale, yscale, 0, color, alpha);
resetTarget();
}
static addVelocity = function(surface, _x = 0, _y = 0, xscale = 1, yscale = 1, xvelo = 1, yvelo = 1) {
setTarget(FD_TARGET_TYPE.ADD_VELOCITY);
shader_set(sh_fd_add_velocity);
shader_set_f("velo", xvelo, yvelo);
draw_surface_ext_safe(surface, _x, _y, xscale, yscale);
shader_reset();
resetTarget();
}
static update = function() {
updateVelocity();
updateMaterial();
}
static updateVelocity = function() {
var temporary = noone;
gpu_set_texrepeat(texture_repeat);
gpu_set_texfilter(true);
gpu_set_blendenable(false);
verify();
surface_set_target(sf_velocity_t);
shader_set(sh_fd_advect_velocity);
shader_set_surface("texture_world", sf_world);
shader_set_surface("texture_material", sf_material);
shader_set_f("max_force", max_force);
shader_set_i("mode", acceleration_type);
shader_set_i("repeat", texture_repeat);
shader_set_i("wall", texture_wall);
shader_set_f("precalculated", time_step * tx_width, time_step * tx_height, tx_width, tx_height);
shader_set_f("precalculated_1", velocity_dissipation_type, velocity_dissipation_value, velocity_maccormack_weight * 0.5);
shader_set_f("acceleration", acceleration_x, acceleration_y, acceleration_a, acceleration_b);
shader_set_f("texel_size", tx_width, tx_height);
draw_surface_safe(sf_velocity);
shader_reset();
surface_reset_target();
temporary = sf_velocity;
sf_velocity = sf_velocity_t;
sf_velocity_t = temporary;
// Calculates divergence of velocity.
surface_set_target(sf_pressure);
shader_set(sh_fd_velocity_divergence);
shader_set_f("max_force", max_force);
shader_set_i("repeat", texture_repeat);
shader_set_i("wall", texture_wall);
shader_set_f("initial_value_pressure", initial_value_pressure);
shader_set_f("texel_size", tx_width, tx_height);
draw_surface_safe(sf_velocity);
shader_reset();
surface_reset_target();
shader_set(sh_fd_pressure_srj);
shader_set_f("texel_size", tx_width, tx_height);
shader_set_f("max_force", max_force);
shader_set_i("repeat", texture_repeat);
shader_set_i("wall", texture_wall);
var length = array_length(pressure_relax);
for (var i = 0; i < length; ++i) {
if (pressure_relax[i] != -1) shader_set_f("precalculated", 1 - pressure_relax[i], 0.25 * pressure_relax[i]);
surface_set_target(sf_pressure_t);
draw_surface_safe(sf_pressure);
surface_reset_target();
temporary = sf_pressure;
sf_pressure = sf_pressure_t;
sf_pressure_t = temporary;
}
shader_reset();
// Calculates the gradient of pressure and subtracts it from the velocity.
surface_set_target(sf_velocity_t);
shader_set(sh_fd_subtract_pressure_gradient);
shader_set_surface("texture_pressure", sf_pressure);
shader_set_f("texel_size", tx_width, tx_height);
shader_set_f("max_force", max_force);
shader_set_i("repeat", texture_repeat);
shader_set_i("wall", texture_wall);
draw_surface_safe(sf_velocity);
shader_reset();
surface_reset_target();
temporary = sf_velocity;
sf_velocity = sf_velocity_t;
sf_velocity_t = temporary;
gpu_set_blendenable(true);
}
static updateMaterial = function() {
var temporary = noone;
gpu_set_texrepeat(texture_repeat);
gpu_set_texfilter(true);
gpu_set_blendenable(false);
verify();
var _scale = .5;
surface_set_target(sf_material_t);
shader_set(sh_fd_advect_material);
shader_set_surface("texture_velocity", sf_velocity);
shader_set_surface("texture_world", sf_world);
shader_set_i("repeat", texture_repeat);
shader_set_i("wall", texture_wall);
shader_set_f("max_force", max_force);
shader_set_f("texel_size", tx_width, tx_height);
shader_set_f("precalculated", time_step * tx_width, time_step * tx_height);
shader_set_f("precalculated_1", tx_width * _scale, tx_height * _scale, -tx_width * _scale, -tx_height * _scale);
shader_set_f("precalculated_2", material_dissipation_type, material_dissipation_value, material_maccormack_weight * 0.5);
draw_surface_safe(sf_material);
shader_reset();
surface_reset_target();
temporary = sf_material;
sf_material = sf_material_t;
sf_material_t = temporary;
gpu_set_blendenable(true);
}
target_type = noone;
static setTarget = function(type) {
target_type = type;
verify();
switch (type) {
case FD_TARGET_TYPE.REPLACE_MATERIAL:
surface_set_target(sf_material);
break;
case FD_TARGET_TYPE.ADD_MATERIAL:
surface_set_target(sf_material);
gpu_set_blendmode_ext(bm_one, bm_one);
break;
case FD_TARGET_TYPE.REPLACE_VELOCITY:
surface_set_target(sf_velocity);
break;
case FD_TARGET_TYPE.ADD_VELOCITY:
surface_set_target(sf_velocity);
gpu_set_blendmode_ext(bm_one, bm_one);
break;
}
}
static resetTarget = function() {
surface_reset_target();
BLEND_NORMAL
}
static free = function() {
surface_free_safe(sf_world);
surface_free_safe(sf_pressure);
surface_free_safe(sf_pressure_t);
surface_free_safe(sf_velocity);
surface_free_safe(sf_velocity_t);
surface_free_safe(sf_material);
surface_free_safe(sf_material_t);
}
setSize(_width, _height);
setPressure(-3);
}