Pixel-Composer/scripts/surface_functions/surface_functions.gml

548 lines
14 KiB
Text
Raw Normal View History

2023-02-19 02:13:19 +01:00
//draw
2023-03-29 15:02:03 +02:00
function draw_surface_safe(surface, _x = 0, _y = 0) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.draw(_x, _y);
return;
}
2022-11-22 14:25:39 +01:00
if(!is_surface(surface)) return;
2023-03-19 09:17:39 +01:00
__channel_pre(surface);
draw_surface(surface, _x, _y);
__channel_pos(surface);
2022-01-13 05:24:03 +01:00
}
2023-09-08 21:09:09 +02:00
2023-01-25 06:49:00 +01:00
function draw_surface_stretched_safe(surface, _x, _y, _w, _h) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.drawStretch(_x, _y, _w, _h);
return;
}
2023-01-25 06:49:00 +01:00
if(!is_surface(surface)) return;
2023-03-19 09:17:39 +01:00
__channel_pre(surface);
draw_surface_stretched(surface, _x, _y, _w, _h);
__channel_pos(surface);
2023-01-25 06:49:00 +01:00
}
2023-09-08 21:09:09 +02:00
2022-11-22 14:25:39 +01:00
function draw_surface_ext_safe(surface, _x, _y, _xs = 1, _ys = 1, _rot = 0, _col = c_white, _alpha = 1) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.draw(_x, _y, _xs, _ys, _rot, _col, _alpha);
return;
}
2022-11-22 14:25:39 +01:00
if(!is_surface(surface)) return;
2023-03-19 09:17:39 +01:00
__channel_pre(surface);
draw_surface_ext(surface, _x, _y, _xs, _ys, _rot, _col, _alpha);
__channel_pos(surface);
}
2023-09-08 21:09:09 +02:00
2023-03-19 09:17:39 +01:00
function draw_surface_tiled_safe(surface, _x, _y) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.drawTile(_x, _y);
return;
}
2023-03-19 09:17:39 +01:00
if(!is_surface(surface)) return;
__channel_pre(surface);
draw_surface_tiled(surface, _x, _y);
__channel_pos(surface);
2022-01-13 05:24:03 +01:00
}
2023-09-08 21:09:09 +02:00
2022-11-22 14:25:39 +01:00
function draw_surface_tiled_ext_safe(surface, _x, _y, _xs = 1, _ys = 1, _col = c_white, _alpha = 1) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.drawTile(_x, _y, _xs, _ys, _col, _alpha);
return;
}
2022-11-22 14:25:39 +01:00
if(!is_surface(surface)) return;
2023-03-19 09:17:39 +01:00
__channel_pre(surface);
draw_surface_tiled_ext(surface, _x, _y, _xs, _ys, _col, _alpha);
__channel_pos(surface);
2022-01-13 05:24:03 +01:00
}
2023-09-08 21:09:09 +02:00
2022-11-22 14:25:39 +01:00
function draw_surface_part_ext_safe(surface, _l, _t, _w, _h, _x, _y, _xs = 1, _ys = 1, _rot = 0, _col = c_white, _alpha = 1) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
if(is_struct(surface) && is_instanceof(surface, dynaSurf)) {
2023-09-08 21:09:09 +02:00
surface.drawPart(_l, _t, _w, _h, _x, _y, _xs, _ys, _rot, _col, _alpha);
return;
}
2022-11-22 14:25:39 +01:00
if(!is_surface(surface)) return;
2023-03-19 09:17:39 +01:00
__channel_pre(surface);
draw_surface_part_ext(surface, _l, _t, _w, _h, _x, _y, _xs, _ys, _col, _alpha);
__channel_pos(surface);
}
2023-06-17 18:59:20 +02:00
#macro surface_free surface_free_safe
#macro __surface_free surface_free
function surface_free_safe(surface) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-06-17 18:59:20 +02:00
if(!is_surface(surface)) return;
__surface_free(surface);
}
2023-03-19 09:17:39 +01:00
function surface_save_safe(surface, path) {
if(!is_surface(surface)) return;
var f = surface_get_format(surface);
2023-04-10 20:02:59 +02:00
if(f == surface_rgba8unorm) {
surface_save(surface, path);
return;
}
2023-09-08 21:37:36 +02:00
var w = surface_get_width_safe(surface);
var h = surface_get_height_safe(surface);
2023-03-31 06:59:08 +02:00
var s = surface_create(w, h, surface_rgba8unorm);
2023-03-19 09:17:39 +01:00
switch(f) {
case surface_rgba4unorm :
case surface_rgba8unorm :
case surface_rgba16float :
case surface_rgba32float :
2023-03-31 06:59:08 +02:00
surface_set_shader(s, sh_draw_normal);
draw_surface(surface, 0, 0);
surface_reset_shader();
surface_save(s, path);
2023-03-19 09:17:39 +01:00
return;
case surface_r8unorm :
s = surface_create(w, h, surface_rgba8unorm);
break;
case surface_r16float :
s = surface_create(w, h, surface_rgba16float);
break;
case surface_r32float :
s = surface_create(w, h, surface_rgba32float);
break;
default:
return;
}
2023-03-31 06:59:08 +02:00
surface_set_shader(s, sh_draw_single_channel);
draw_surface(surface, 0, 0);
surface_reset_shader();
2023-03-19 09:17:39 +01:00
surface_save(s, path);
surface_free(s);
return;
}
2022-01-13 05:24:03 +01:00
2023-09-08 21:37:36 +02:00
function surface_get_width_safe(s) {
gml_pragma("forceinline");
return (is_struct(s) && is_instanceof(s, dynaSurf))? s.getWidth() : surface_get_width(s);
2023-09-08 21:37:36 +02:00
}
function surface_get_height_safe(s) {
gml_pragma("forceinline");
return (is_struct(s) && is_instanceof(s, dynaSurf))? s.getHeight() : surface_get_height(s);
2023-09-08 21:37:36 +02:00
}
2023-02-19 02:13:19 +01:00
//check
function is_surface(s) {
2023-04-16 16:24:17 +02:00
gml_pragma("forceinline");
2023-02-28 09:43:01 +01:00
if(is_undefined(s)) return false;
2023-02-19 02:13:19 +01:00
if(is_array(s)) return false;
if(is_struct(s) && is_instanceof(s, dynaSurf)) return true;
2023-02-19 02:13:19 +01:00
if(!is_real(s)) return false;
if(!s) return false;
if(!surface_exists(s)) return false;
2022-01-13 05:24:03 +01:00
2023-09-08 21:37:36 +02:00
if(surface_get_width_safe(s) <= 0) return false;
if(surface_get_height_safe(s) <= 0) return false;
2022-01-13 05:24:03 +01:00
2022-11-22 14:25:39 +01:00
return true;
2022-01-13 05:24:03 +01:00
}
2023-03-19 09:17:39 +01:00
function surface_verify(surf, w, h, format = surface_rgba8unorm) {
2023-04-16 16:24:17 +02:00
gml_pragma("forceinline");
2023-06-17 14:30:49 +02:00
w = round(w);
h = round(h);
var s = is_surface(surf);
2023-04-16 16:24:17 +02:00
if(!s) return surface_create_valid(w, h, format);
return surface_size_to(surf, w, h, format, true);
2022-12-10 05:06:01 +01:00
}
2023-03-31 06:59:08 +02:00
//get
function surface_get_pixel(surface, _x, _y) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-03-31 06:59:08 +02:00
if(!is_surface(surface)) return;
var f = surface_get_format(surface);
var px = surface_getpixel(surface, _x, _y);
if(is_real(px)) return px;
return round(px[0] * (255 * power(256, 0))) + round(px[1] * (255 * power(256, 1))) + round(px[2] * (255 * power(256, 2)));
}
function surface_get_pixel_ext(surface, _x, _y) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-03-31 06:59:08 +02:00
if(!is_surface(surface)) return;
var px = surface_getpixel_ext(surface, _x, _y);
if(is_real(px)) return px;
return round(px[0] * (255 * power(256, 0))) + round(px[1] * (255 * power(256, 1))) + round(px[2] * (255 * power(256, 2))) + round(px[3] * (255 * power(256, 3)));
}
2023-02-19 02:13:19 +01:00
//create
2023-07-29 10:10:48 +02:00
function surface_create_empty(w, h, format = surface_rgba8unorm) {
gml_pragma("forceinline");
var s = surface_create(w, h, format);
2023-07-14 20:34:35 +02:00
surface_clear(s);
return s;
}
2023-03-19 09:17:39 +01:00
function surface_create_size(surface, format = surface_rgba8unorm) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-09-08 21:37:36 +02:00
return surface_create_valid(surface_get_width_safe(surface), surface_get_height_safe(surface), format);
2022-01-13 05:24:03 +01:00
}
2023-03-19 09:17:39 +01:00
function surface_create_valid(w, h, format = surface_rgba8unorm) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
return surface_create_empty(surface_valid_size(w), surface_valid_size(h), format);
2022-01-13 05:24:03 +01:00
}
2023-03-19 09:17:39 +01:00
function surface_create_from_buffer(w, h, buff, format = surface_rgba8unorm) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-06-17 18:59:20 +02:00
if(buff < 0) return;
2023-03-19 09:17:39 +01:00
var s = surface_create_valid(surface_valid_size(w), surface_valid_size(h), format);
2023-02-19 02:13:19 +01:00
buffer_set_surface(buff, s, 0);
return s;
2022-11-01 03:06:03 +01:00
}
2023-06-24 22:12:35 +02:00
function surface_from_buffer(buff) {
static header_length = 24;
if(!buffer_exists(buff)) return noone;
buffer_seek(buff, buffer_seek_start, 0);
var text = "";
repeat(4) text += chr(buffer_read(buff, buffer_u8));
if(text != "PXCS") return noone;
var w = buffer_read(buff, buffer_u16);
var h = buffer_read(buff, buffer_u16);
var format = buffer_read(buff, buffer_u8);
//print($"Creating surface from buffer {buff}: size {buffer_get_size(buff) - 4}: w = {w}, h = {h}");
if(w < 1 || h < 1) return noone;
var s = surface_create(w, h, format);
buffer_set_surface(buff, s, header_length);
return s;
}
2023-02-19 02:13:19 +01:00
function surface_create_from_sprite(spr) {
if(!sprite_exists(spr)) return noone;
2022-01-13 05:24:03 +01:00
2023-02-19 02:13:19 +01:00
if(sprite_get_number(spr) == 1)
return surface_create_from_sprite_ext(spr, 0);
2022-01-13 05:24:03 +01:00
2023-02-19 02:13:19 +01:00
var s = [];
for( var i = 0; i < sprite_get_number(spr); i++ ) {
array_push(s, surface_create_from_sprite_ext(spr, i));
}
return s;
2022-09-27 06:37:28 +02:00
}
2023-03-19 09:17:39 +01:00
function surface_create_from_sprite_ext(spr, ind, format = surface_rgba8unorm) {
2022-09-27 06:37:28 +02:00
if(!sprite_exists(spr)) return noone;
var sw = sprite_get_width(spr);
var sh = sprite_get_height(spr);
2023-03-19 09:17:39 +01:00
var s = surface_create_valid(sw, sh, format);
2022-09-27 06:37:28 +02:00
surface_set_target(s);
2023-02-19 02:13:19 +01:00
BLEND_OVERRIDE;
2023-03-19 09:17:39 +01:00
DRAW_CLEAR
2022-09-27 06:37:28 +02:00
draw_sprite(spr, ind, sprite_get_xoffset(spr), sprite_get_yoffset(spr));
BLEND_NORMAL
surface_reset_target();
return s;
}
2023-03-21 03:01:53 +01:00
function surface_size_lim(surface, width, height) {
2023-09-08 21:37:36 +02:00
var sw = surface_get_width_safe(surface);
var sh = surface_get_height_safe(surface);
2023-03-21 03:01:53 +01:00
if(sw <= width && sh <= height) return surface;
var ss = min(width / sw, height / sh);
var s = surface_create(sw * ss, sh * ss);
surface_set_target(s);
DRAW_CLEAR;
2023-09-09 13:52:16 +02:00
draw_surface_ext_safe(surface, 0, 0, ss, ss, 0, c_white, 1);
2023-03-21 03:01:53 +01:00
surface_reset_target();
return s;
}
function surface_size_to(surface, width, height, format = noone, skipCheck = false) {
if(!skipCheck && !is_surface(surface)) return surface;
2023-03-19 09:17:39 +01:00
if(width < 1 && height < 1) return surface;
2023-05-03 21:42:17 +02:00
if(format != noone && format != surface_get_format(surface)) {
2023-03-19 09:17:39 +01:00
surface_free(surface);
return surface_create(width, height, format);
2023-03-19 09:17:39 +01:00
}
2022-09-27 06:37:28 +02:00
2023-03-19 09:17:39 +01:00
width = surface_valid_size(width);
2023-02-19 02:13:19 +01:00
height = surface_valid_size(height);
2022-09-27 06:37:28 +02:00
2023-09-08 21:37:36 +02:00
var ww = surface_get_width_safe(surface);
var hh = surface_get_height_safe(surface);
2022-09-27 06:37:28 +02:00
2023-03-19 09:17:39 +01:00
if(ww == width && hh == height) return surface;
//print($"Reset surface {ww}, {width} | {hh}, {height}");
2023-02-19 02:13:19 +01:00
surface_resize(surface, width, height);
2023-07-29 10:10:48 +02:00
surface_clear(surface);
2023-03-19 09:17:39 +01:00
return surface;
2022-12-27 04:00:50 +01:00
}
2023-07-14 20:34:35 +02:00
function surface_clear(surface) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-07-14 20:34:35 +02:00
if(!is_surface(surface)) return;
surface_set_target(surface);
DRAW_CLEAR
surface_reset_target();
}
2023-03-19 09:17:39 +01:00
function surface_copy_from(dst, src, format = noone) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-02-19 02:13:19 +01:00
surface_set_target(dst);
2023-03-19 09:17:39 +01:00
DRAW_CLEAR
2023-02-19 02:13:19 +01:00
BLEND_OVERRIDE;
draw_surface_safe(src, 0, 0);
BLEND_NORMAL
surface_reset_target();
}
2023-09-26 14:35:25 +02:00
function surface_clone(surface, destination = noone, format = noone) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-09-26 14:35:25 +02:00
if(is_struct(surface) && is_instanceof(surface, dynaSurf))
return surface.clone();
2023-02-19 02:13:19 +01:00
if(!is_surface(surface)) return noone;
2023-09-26 14:35:25 +02:00
destination = surface_verify(destination, surface_get_width_safe(surface), surface_get_height_safe(surface), format == noone? surface_get_format(surface) : format);
2023-02-19 02:13:19 +01:00
2023-09-26 14:35:25 +02:00
surface_set_target(destination);
2023-03-19 09:17:39 +01:00
DRAW_CLEAR
2023-02-19 02:13:19 +01:00
BLEND_OVERRIDE;
draw_surface_safe(surface, 0, 0);
BLEND_NORMAL
surface_reset_target();
2023-09-26 14:35:25 +02:00
return destination;
2023-02-19 02:13:19 +01:00
}
2023-07-23 20:21:35 +02:00
//in-place modification
function surface_stretch(surf, _w, _h) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-07-23 20:21:35 +02:00
if(!is_surface(surf)) return noone;
_w = surface_valid_size(_w);
_h = surface_valid_size(_h);
var _surf = surface_create(_w, _h);
surface_set_target(_surf);
DRAW_CLEAR
draw_surface_stretched(surf, 0, 0, _w, _h);
surface_reset_target();
surface_free(surf);
return _surf;
}
function surface_mirror(surf, _h, _v) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-07-23 20:21:35 +02:00
if(!is_surface(surf)) return noone;
var _surf = surface_create_size(surf);
surface_set_target(_surf);
DRAW_CLEAR
2023-09-08 21:37:36 +02:00
var x0 = _h * surface_get_width_safe(_surf);
var y0 = _v * surface_get_height_safe(_surf);
2023-07-23 20:21:35 +02:00
2023-09-09 13:52:16 +02:00
draw_surface_ext_safe(surf, x0, y0, _h * 2 - 1, _v * 2 - 1, 0, c_white, 1);
2023-07-23 20:21:35 +02:00
surface_reset_target();
surface_free(surf);
return _surf;
}
//others
2023-03-19 09:17:39 +01:00
function surface_copy_size(dest, source, format = noone) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-02-19 02:13:19 +01:00
if(!is_surface(dest)) return;
if(!is_surface(source)) return;
2023-09-08 21:37:36 +02:00
surface_size_to(dest, surface_get_width_safe(source), surface_get_height_safe(source), format);
2023-02-19 02:13:19 +01:00
surface_set_target(dest);
2023-03-19 09:17:39 +01:00
DRAW_CLEAR
2023-02-19 02:13:19 +01:00
surface_reset_target();
surface_copy_from(dest, source);
}
function surface_valid_size(s) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-02-19 02:13:19 +01:00
if(is_infinity(s)) return 1;
2023-07-05 15:09:52 +02:00
s = toNumber(s);
2023-06-17 18:59:20 +02:00
if(!is_real(s)) return 1;
return clamp(s, 1, 8196);
2023-02-14 13:44:46 +01:00
}
function surface_array_free(arr) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-02-14 13:44:46 +01:00
if(!is_array(arr)) {
if(is_surface(arr)) surface_free(arr);
return;
}
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(arr); i < n; i++ )
2023-02-14 13:44:46 +01:00
surface_array_free(arr[i]);
}
function surface_array_clone(arr) {
if(!is_array(arr)) {
if(is_surface(arr))
return surface_clone(arr);
else
return arr;
}
var _arr = [];
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(arr); i < n; i++ )
2023-02-14 13:44:46 +01:00
_arr[i] = surface_array_clone(arr[i]);
2023-03-02 07:59:14 +01:00
return _arr;
}
function surface_array_serialize(arr) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-03-02 07:59:14 +01:00
var _arr = __surface_array_serialize(arr);
return json_stringify(_arr);
}
function __surface_array_serialize(arr) {
if(!is_array(arr)) {
if(is_surface(arr)) {
2023-09-08 21:37:36 +02:00
var buff = buffer_create(surface_get_width_safe(arr) * surface_get_height_safe(arr) * 4, buffer_fixed, 1);
2023-03-02 07:59:14 +01:00
buffer_get_surface(buff, arr, 0);
var comp = buffer_compress(buff, 0, buffer_get_size(buff));
2023-03-13 10:45:56 +01:00
var enc = buffer_base64_encode(comp, 0, buffer_get_size(comp));
2023-03-02 07:59:14 +01:00
buffer_delete(buff);
2023-09-08 21:37:36 +02:00
return { width: surface_get_width_safe(arr), height: surface_get_height_safe(arr), buffer: enc };
2023-03-02 07:59:14 +01:00
} else
return arr;
}
var _arr = [];
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(arr); i < n; i++ )
2023-03-02 07:59:14 +01:00
_arr[i] = __surface_array_serialize(arr[i]);
return _arr;
}
function surface_array_deserialize(arr, index = -1) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-03-05 07:16:44 +01:00
var _arr = json_try_parse(arr);
2023-03-13 10:45:56 +01:00
return index == -1? __surface_array_deserialize(_arr) : __surface_array_deserialize(_arr[index]);
2023-03-02 07:59:14 +01:00
}
function __surface_array_deserialize(arr) {
if(!is_array(arr)) {
2023-07-23 20:21:35 +02:00
if(!is_struct(arr) || !struct_has(arr, "buffer"))
return noone;
2023-03-02 07:59:14 +01:00
var buff = buffer_base64_decode(arr.buffer);
2023-03-13 10:45:56 +01:00
buff = buffer_decompress(buff);
2023-03-02 07:59:14 +01:00
return surface_create_from_buffer(arr.width, arr.height, buff);
}
var _arr = [];
2023-07-25 20:12:40 +02:00
for( var i = 0, n = array_length(arr); i < n; i++ )
2023-03-02 07:59:14 +01:00
_arr[i] = __surface_array_deserialize(arr[i]);
2023-02-14 13:44:46 +01:00
return _arr;
2023-03-05 07:16:44 +01:00
}
function surface_encode(surface) {
if(!is_surface(surface)) return "";
2023-09-08 21:37:36 +02:00
var buff = buffer_create(surface_get_width_safe(surface) * surface_get_height_safe(surface) * 4, buffer_fixed, 1);
2023-03-05 07:16:44 +01:00
buffer_get_surface(buff, surface, 0);
var comp = buffer_compress(buff, 0, buffer_get_size(buff));
var enc = buffer_base64_encode(comp, 0, buffer_get_size(comp));
buffer_delete(buff);
2023-09-08 21:37:36 +02:00
var str = { width: surface_get_width_safe(surface), height: surface_get_height_safe(surface), buffer: enc };
2023-03-05 07:16:44 +01:00
return json_stringify(str);
}
function surface_decode(struct) {
var buff = buffer_base64_decode(struct.buffer);
var buff = buffer_decompress(buff);
return surface_create_from_buffer(struct.width, struct.height, buff);
2023-03-19 09:17:39 +01:00
}
2023-06-24 22:12:35 +02:00
function surface_format_get_bytes(format) {
2023-03-19 09:17:39 +01:00
switch(format) {
case surface_rgba4unorm : return 4 * 0.5; break;
case surface_rgba8unorm : return 4 * 1; break;
case surface_rgba16float : return 4 * 2; break;
case surface_rgba32float : return 4 * 4; break;
case surface_r8unorm : return 1 * 1; break;
case surface_r16float : return 1 * 2; break;
case surface_r32float : return 1 * 3; break;
}
return 1;
}
function surface_get_size(surface) {
2023-07-29 10:10:48 +02:00
gml_pragma("forceinline");
2023-09-08 21:37:36 +02:00
var sw = surface_get_width_safe(surface);
var sh = surface_get_height_safe(surface);
2023-06-24 22:12:35 +02:00
var sz = sw * sh * surface_format_get_bytes(surface_get_format(surface));
2023-03-19 09:17:39 +01:00
return sz;
2023-08-17 16:56:54 +02:00
}
function surface_texture(surface) {
gml_pragma("forceinline");
if(!is_surface(surface)) return -1;
return surface_get_texture(surface);
2022-01-13 05:24:03 +01:00
}