Pixel-Composer/scripts/gradients_function/gradients_function.gml

376 lines
9.9 KiB
Text
Raw Normal View History

2022-01-13 05:24:03 +01:00
enum GRADIENT_INTER {
smooth,
2022-11-14 03:16:15 +01:00
none,
2024-02-10 07:03:50 +01:00
hue,
2024-02-12 10:25:23 +01:00
oklab,
srgb
2022-01-13 05:24:03 +01:00
}
2024-05-25 10:07:11 +02:00
global.gradient_sort_list = ds_priority_create();
2024-07-27 07:10:34 +02:00
function gradientKey(time, value) constructor {
2023-02-14 05:32:32 +01:00
self.time = time;
self.value = value;
_hover = 0;
static clone = function() { return new gradientKey(time, value); }
2023-10-03 11:27:36 +02:00
static serialize = function() { return { time, value }; }
2024-07-27 07:10:34 +02:00
}
2023-02-14 05:32:32 +01:00
2024-07-27 07:10:34 +02:00
function gradientObject(color = c_black) constructor {
2023-07-28 19:41:57 +02:00
static GRADIENT_LIMIT = 128;
if(is_array(color)) keys = [ new gradientKey(0, cola(color[0])), new gradientKey(1, cola(color[1])) ];
else keys = [ new gradientKey(0, cola(color)) ];
2024-01-24 06:19:34 +01:00
type = GRADIENT_INTER.smooth;
surf = noone;
cacheRes = 128;
caches = array_create(cacheRes);
keyLength = 0;
2022-01-13 05:24:03 +01:00
2024-05-25 10:07:11 +02:00
static refresh = function() {
ds_priority_clear(global.gradient_sort_list);
for (var i = 0, n = array_length(keys); i < n; i++)
ds_priority_add(global.gradient_sort_list, keys[i], keys[i].time);
for (var i = 0, n = array_length(keys); i < n; i++)
keys[i] = ds_priority_delete_min(global.gradient_sort_list);
cache();
}
2024-07-27 07:10:34 +02:00
static clone = function() {
2023-03-02 07:59:14 +01:00
var g = new gradientObject();
2023-07-28 19:41:57 +02:00
for( var i = 0, n = array_length(keys); i < n; i++ )
2023-03-02 07:59:14 +01:00
g.keys[i] = keys[i].clone();
2024-01-08 08:10:50 +01:00
g.type = type;
2023-02-23 07:02:19 +01:00
2023-03-02 07:59:14 +01:00
return g;
2024-07-27 07:10:34 +02:00
}
2022-11-14 03:16:15 +01:00
2024-07-27 07:10:34 +02:00
static add = function(_addkey, _deleteDup = true) {
2023-07-28 19:41:57 +02:00
if(array_length(keys) > GRADIENT_LIMIT) return;
2023-03-02 07:59:14 +01:00
if(array_length(keys) == 0) {
array_push(keys, _addkey);
return;
}
2023-01-17 08:11:55 +01:00
2023-03-02 07:59:14 +01:00
for(var i = 0; i < array_length(keys); i++) {
var _key = keys[i];
2023-01-17 08:11:55 +01:00
2023-03-02 07:59:14 +01:00
if(_key.time == _addkey.time) {
if(_deleteDup)
_key.value = _addkey.value;
return;
} else if(_key.time > _addkey.time) {
array_insert(keys, i, _addkey);
return;
}
2022-01-13 05:24:03 +01:00
}
2023-03-02 07:59:14 +01:00
array_push(keys, _addkey);
2024-07-27 07:10:34 +02:00
}
2022-01-13 05:24:03 +01:00
2024-07-27 07:10:34 +02:00
static eval = function(position) {
var _len = array_length(keys);
if(_len == 0) return c_black;
if(_len == 1) return keys[0].value;
2024-01-08 08:10:50 +01:00
if(position <= keys[0].time) return keys[0].value;
if(position >= keys[_len - 1].time) return keys[_len - 1].value;
for(var i = 1; i < _len; i++) {
2024-02-06 13:53:08 +01:00
var _pkey = keys[i - 1];
var _key = keys[i];
if(_key.time < position) continue;
if(_key.time == position) return _key.value;
2024-01-08 08:10:50 +01:00
var rat = (position - _pkey.time) / (_key.time - _pkey.time);
switch(type) {
case GRADIENT_INTER.smooth : return merge_color_rgba (_pkey.value, _key.value, rat);
case GRADIENT_INTER.hue : return merge_color_hsva (_pkey.value, _key.value, rat);
2024-02-10 07:03:50 +01:00
case GRADIENT_INTER.oklab : return merge_color_oklab(_pkey.value, _key.value, rat);
2024-02-12 10:25:23 +01:00
case GRADIENT_INTER.srgb : return merge_color_srgb (_pkey.value, _key.value, rat);
2024-01-08 08:10:50 +01:00
case GRADIENT_INTER.none : return _pkey.value;
2023-03-02 07:59:14 +01:00
}
2022-01-13 05:24:03 +01:00
}
2023-03-02 07:59:14 +01:00
return keys[_len - 1].value; //after last color
2024-07-27 07:10:34 +02:00
}
2023-03-02 07:59:14 +01:00
2024-07-27 07:10:34 +02:00
static evalFast = function(position) {
2024-01-24 06:19:34 +01:00
INLINE
2024-03-22 09:44:11 +01:00
var _len = array_length(keys);
if(position <= keys[0].time) return keys[0].value;
if(position >= keys[_len - 1].time) return keys[_len - 1].value;
2024-01-24 06:19:34 +01:00
var _ind = round(position * cacheRes);
return caches[_ind];
2024-07-27 07:10:34 +02:00
}
2024-01-24 06:19:34 +01:00
2024-07-27 07:10:34 +02:00
static draw = function(_x, _y, _w, _h, _a = 1) {
2023-03-02 07:59:14 +01:00
var uniform_grad_blend = shader_get_uniform(sh_gradient_display, "gradient_blend");
var uniform_grad = shader_get_uniform(sh_gradient_display, "gradient_color");
var uniform_grad_time = shader_get_uniform(sh_gradient_display, "gradient_time");
var uniform_grad_key = shader_get_uniform(sh_gradient_display, "gradient_keys");
var _grad_color = [];
var _grad_time = [];
2023-07-28 19:41:57 +02:00
var len = min(128, array_length(keys));
2024-01-08 08:10:50 +01:00
var aa = false;
2023-07-28 19:41:57 +02:00
for(var i = 0; i < len; i++) {
2024-01-08 08:10:50 +01:00
var _val = keys[i].value;
if(_val == undefined) return;
_grad_color[i * 4 + 0] = _color_get_red(_val);
_grad_color[i * 4 + 1] = _color_get_green(_val);
_grad_color[i * 4 + 2] = _color_get_blue(_val);
_grad_color[i * 4 + 3] = _color_get_alpha(_val);
2023-12-29 14:30:54 +01:00
_grad_time[i] = keys[i].time;
2024-01-08 08:10:50 +01:00
if(_grad_color[i * 4 + 3] != 1) aa = true;
2023-03-02 07:59:14 +01:00
}
2023-12-29 14:30:54 +01:00
surf = surface_verify(surf, _w, _h);
surface_set_target(surf);
DRAW_CLEAR
2024-01-08 08:10:50 +01:00
var _gh = aa? _h - ui(8) : _h;
draw_sprite_stretched_ext(THEME.ui_panel_bg, 4, 0, 0, _w, _gh, c_white, _a)
2023-03-02 07:59:14 +01:00
2024-01-08 08:10:50 +01:00
if(len) {
BLEND_MULTIPLY
2023-12-29 14:30:54 +01:00
shader_set(sh_gradient_display);
shader_set_uniform_i(uniform_grad_blend, type);
shader_set_uniform_f_array_safe(uniform_grad, _grad_color, GRADIENT_LIMIT * 4);
shader_set_uniform_f_array_safe(uniform_grad_time, _grad_time);
shader_set_uniform_i(uniform_grad_key, len);
2024-01-08 08:10:50 +01:00
draw_sprite_stretched_ext(s_fx_pixel, 0, 0, 0, _w, _gh, c_white, 1);
2023-12-29 14:30:54 +01:00
shader_reset();
2024-01-08 08:10:50 +01:00
BLEND_NORMAL
2023-12-29 14:30:54 +01:00
}
2024-01-08 08:10:50 +01:00
if(aa) {
draw_sprite_stretched_ext(THEME.ui_panel_bg, 4, 0, _h - ui(6), _w, ui(6), c_white, _a)
2024-01-08 08:10:50 +01:00
BLEND_MULTIPLY
shader_set(sh_gradient_display_alpha);
shader_set_uniform_i(uniform_grad_blend, type);
shader_set_uniform_f_array_safe(uniform_grad, _grad_color, GRADIENT_LIMIT * 4);
shader_set_uniform_f_array_safe(uniform_grad_time, _grad_time);
shader_set_uniform_i(uniform_grad_key, len);
draw_sprite_stretched_ext(s_fx_pixel, 0, 0, _h - ui(6), _w, ui(6), c_white, 1);
shader_reset();
BLEND_NORMAL
}
2023-12-29 14:30:54 +01:00
surface_reset_target();
draw_surface(surf, _x, _y);
2024-07-27 07:10:34 +02:00
}
2023-03-02 07:59:14 +01:00
2024-07-27 07:10:34 +02:00
static cache = function(res = 128) {
2024-01-24 06:19:34 +01:00
cacheRes = res;
caches = array_verify(caches, cacheRes + 1);
keyLength = array_length(keys);
for( var i = 0; i <= cacheRes; i++ )
caches[i] = eval(i / cacheRes);
2024-07-27 07:10:34 +02:00
}
2024-01-24 06:19:34 +01:00
2024-07-27 07:10:34 +02:00
static toArray = function() {
2023-03-02 07:59:14 +01:00
var _grad_color = [], _grad_time = [];
2023-10-03 11:27:36 +02:00
2023-03-02 07:59:14 +01:00
for(var i = 0; i < array_length(keys); i++) {
2024-01-08 08:10:50 +01:00
var _val = keys[i].value;
if(is_undefined(_val)) continue;
2023-10-03 11:27:36 +02:00
2024-01-08 08:10:50 +01:00
_grad_color[i * 4 + 0] = _color_get_red(_val);
_grad_color[i * 4 + 1] = _color_get_green(_val);
_grad_color[i * 4 + 2] = _color_get_blue(_val);
_grad_color[i * 4 + 3] = _color_get_alpha(_val);
2023-03-08 12:14:01 +01:00
_grad_time[i] = keys[i].time;
2023-03-02 07:59:14 +01:00
}
return [ _grad_color, _grad_time ];
2024-07-27 07:10:34 +02:00
}
2023-02-14 05:32:32 +01:00
2024-07-27 07:10:34 +02:00
static lerpTo = function(target, amount) {
2023-07-11 14:18:23 +02:00
var grad = new gradientObject();
grad.keys = [];
grad.type = type;
var key_count = ceil(lerp(array_length(keys), array_length(target.keys), amount));
2024-04-11 15:43:03 +02:00
if(key_count == 0) return grad;
if(key_count == 1) {
grad.keys[0] = new gradientKey(0, merge_color(eval(0), target.eval(0), amount));
return grad;
}
2023-07-11 14:18:23 +02:00
for( var i = 0; i < key_count; i++ ) {
var rat = i / (key_count - 1);
var kf = keys[rat * (array_length(keys) - 1)];
var kt = target.keys[rat * (array_length(target.keys) - 1)];
var time = lerp(kf.time, kt.time, amount);
var value = merge_color(eval(time), target.eval(time), amount);
grad.keys[i] = new gradientKey(time, value);
}
return grad;
2024-07-27 07:10:34 +02:00
}
2023-07-11 14:18:23 +02:00
2024-07-27 07:10:34 +02:00
static shader_submit = function() {
var _grad = toArray();
var _grad_color = _grad[0];
var _grad_time = _grad[1];
shader_set_i("gradient_blend", type);
shader_set_f_array("gradient_color", _grad_color, GRADIENT_LIMIT * 4);
shader_set_f("gradient_time", _grad_time);
shader_set_i("gradient_keys", array_length(keys));
2024-07-27 07:10:34 +02:00
}
2024-07-27 07:10:34 +02:00
static clone = function() {
2023-07-11 14:18:23 +02:00
var g = new gradientObject();
g.keys = [];
g.type = type;
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(keys); i < n; i++ )
2023-07-11 14:18:23 +02:00
g.keys[i] = keys[i].clone();
return g;
2024-07-27 07:10:34 +02:00
}
2023-07-11 14:18:23 +02:00
2024-07-27 07:10:34 +02:00
static serialize = function() {
var s = { type, keys: [] };
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(keys); i < n; i++ )
2023-07-11 14:18:23 +02:00
s.keys[i] = keys[i].serialize();
2023-07-11 14:18:23 +02:00
return json_stringify(s, false);
2024-07-27 07:10:34 +02:00
}
2023-03-02 07:59:14 +01:00
2024-07-27 07:10:34 +02:00
static deserialize = function(str) {
2023-04-22 16:23:51 +02:00
var s;
2024-03-27 11:51:14 +01:00
if(is_array(str)) {
2023-04-22 16:23:51 +02:00
keys = [];
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(str); i < n; i++ )
2023-06-13 14:42:06 +02:00
keys[i] = new gradientKey(str[i].time, str[i].value);
2023-04-22 16:23:51 +02:00
return self;
}
2024-03-27 11:51:14 +01:00
if(is_string(str)) s = json_try_parse(str);
else if(is_struct(str)) s = str;
else return self;
2023-10-03 11:27:36 +02:00
type = struct_try_get(s, "type");
keys = array_create(array_length(s.keys));
2024-03-27 11:51:14 +01:00
2023-10-03 11:27:36 +02:00
for( var i = 0, n = array_length(s.keys); i < n; i++ ) {
2024-07-27 07:10:34 +02:00
var _time = s.keys[i].time;
var _value = s.keys[i].value;
2023-10-03 11:27:36 +02:00
2024-08-09 13:30:09 +02:00
if(LOADING_VERSION < 11660) _value = cola(_value);
2023-10-03 11:27:36 +02:00
keys[i] = new gradientKey(_time, _value);
}
2023-03-02 07:59:14 +01:00
return self;
2024-07-27 07:10:34 +02:00
}
}
2023-03-28 06:58:28 +02:00
2024-07-27 07:10:34 +02:00
function loadGradient(path) {
2023-03-28 06:58:28 +02:00
if(path == "") return noone;
2023-12-08 03:50:09 +01:00
if(!file_exists_empty(path)) return noone;
2023-03-28 06:58:28 +02:00
var grad = new gradientObject();
grad.keys = [];
var _t = file_text_open_read(path);
while(!file_text_eof(_t)) {
2023-05-30 11:09:15 +02:00
var key = string_trim(file_text_readln(_t));
2023-03-28 06:58:28 +02:00
var _col = 0, _pos = 0;
if(string_pos(",", key)) {
var keys = string_splice(key, ",");
2023-05-30 11:09:15 +02:00
if(array_length(keys) < 2) continue;
2023-03-28 06:58:28 +02:00
_col = toNumber(keys[0]);
_pos = toNumber(keys[1]);
2023-03-28 06:58:28 +02:00
} else {
_col = toNumber(key);
if(file_text_eof(_t)) break;
_pos = toNumber(file_text_readln(_t));
}
if(!is_int64(_col)) _col = cola(_col);
2023-03-28 06:58:28 +02:00
array_push(grad.keys, new gradientKey(_pos, _col));
}
file_text_close(_t);
2023-05-30 11:09:15 +02:00
2023-03-28 06:58:28 +02:00
return grad;
2024-07-27 07:10:34 +02:00
}
2024-07-27 07:10:34 +02:00
function shader_set_gradient(gradient, surface, range, junc) {
2024-01-22 10:26:25 +01:00
var use_map = junc.attributes.mapped && is_surface(surface);
shader_set_i("gradient_use_map", use_map);
shader_set_f("gradient_map_range", range);
var t = shader_set_surface("gradient_map", surface);
gpu_set_tex_filter_ext(t, true);
if(is_instanceof(gradient, gradientObject))
gradient.shader_submit();
2024-07-27 07:10:34 +02:00
}
2024-01-22 10:26:25 +01:00
2024-07-27 07:10:34 +02:00
function evaluate_gradient_map(_x, gradient, surface, range, junc, fast = false) {
2024-01-22 10:26:25 +01:00
var use_map = junc.attributes.mapped;
2024-01-24 06:19:34 +01:00
if(!use_map) return fast? gradient.evalFast(_x) : gradient.eval(_x);
if(!is_surface(surface)) return 0;
2024-01-24 06:19:34 +01:00
var _sw = surface_get_width(surface);
var _sh = surface_get_height(surface);
2024-01-22 10:26:25 +01:00
2024-01-24 06:19:34 +01:00
var _sx = lerp(range[0], range[2], _x) * _sw;
var _sy = lerp(range[1], range[3], _x) * _sh;
2024-01-22 10:26:25 +01:00
2024-01-24 06:19:34 +01:00
return surface_getpixel_ext(surface, _sx, _sy);
2024-07-27 07:10:34 +02:00
}
2024-01-22 10:26:25 +01:00
globalvar GRADIENTS;
GRADIENTS = [];
2024-07-27 07:10:34 +02:00
function __initGradient() {
GRADIENTS = [];
var path = DIRECTORY + "Gradients/"
var file = file_find_first(path + "*", 0);
while(file != "") {
array_push(GRADIENTS, {
name: filename_name_only(file),
path: path + file,
gradient: loadGradient(path + file)
});
file = file_find_next();
}
file_find_close();
2024-07-27 07:10:34 +02:00
}