Graph image exporter

This commit is contained in:
Tanasart 2023-05-29 13:06:05 +02:00
parent c80d53b4ec
commit 409ff0f49a
5 changed files with 214 additions and 27 deletions

View file

@ -5,6 +5,20 @@ function draw_sprite_ext_override(spr, ind, _x, _y, xscale = 1, yscale = 1, rot
__draw_sprite_ext(spr, ind, round(_x), round(_y), xscale, yscale, rot, color, alpha); __draw_sprite_ext(spr, ind, round(_x), round(_y), xscale, yscale, rot, color, alpha);
} }
#macro draw_sprite_stretched_ext draw_sprite_stretched_ext_override
#macro __draw_sprite_stretched_ext draw_sprite_stretched_ext
function draw_sprite_stretched_ext_override(spr, ind, _x, _y, w = 1, h = 1, color = c_white, alpha = 1) {
__draw_sprite_stretched_ext(spr, ind, round(_x), round(_y), round(w), round(h), color, alpha);
}
#macro draw_sprite_stretched draw_sprite_stretched_override
#macro __draw_sprite_stretched draw_sprite_stretched
function draw_sprite_stretched_override(spr, ind, _x, _y, w = 1, h = 1) {
__draw_sprite_stretched(spr, ind, round(_x), round(_y), round(w), round(h));
}
function draw_sprite_uniform(spr, ind, _x, _y, scale, color = c_white) { function draw_sprite_uniform(spr, ind, _x, _y, scale, color = c_white) {
draw_sprite_ext(spr, ind, round(_x), round(_y), scale, scale, 0, color, 1); draw_sprite_ext(spr, ind, round(_x), round(_y), scale, scale, 0, color, 1);
} }

View file

@ -125,6 +125,12 @@ function Panel_Graph() : PanelContent() constructor {
initSize(); initSize();
toolbars = [ toolbars = [
[
THEME.icon_preview_export,
function() { return 0; },
function() { return get_text("panel_graph_export_image", "Export graph as image"); },
function() { dialogPanelCall(new Panel_Graph_Export_Image(self)); }
],
[ [
THEME.icon_center_canvas, THEME.icon_center_canvas,
function() { return 0; }, function() { return 0; },
@ -364,17 +370,15 @@ function Panel_Graph() : PanelContent() constructor {
draw_set_alpha(grid_opacity * (graph_s >= 1? 1 : 0.5)); draw_set_alpha(grid_opacity * (graph_s >= 1? 1 : 0.5));
while(xx < w + gr_ls) { while(xx < w + gr_ls) {
draw_line(xx + xs, 0, xx + xs, h); draw_line(xx + xs, 0, xx + xs, h);
if(xx + xs - gr_x == 0) { if(xx + xs - gr_x == 0)
draw_line_width(xx + xs, 0, xx + xs, h, 3); draw_line_width(xx + xs, 0, xx + xs, h, 3);
}
xx += gr_ls; xx += gr_ls;
} }
while(yy < h + gr_ls) { while(yy < h + gr_ls) {
draw_line(0, yy + ys, w, yy + ys); draw_line(0, yy + ys, w, yy + ys);
if(yy + ys - gr_y == 0) { if(yy + ys - gr_y == 0)
draw_line_width(0, yy + ys, w, yy + ys, 3); draw_line_width(0, yy + ys, w, yy + ys, 3);
}
yy += gr_ls; yy += gr_ls;
} }
draw_set_alpha(1); draw_set_alpha(1);
@ -1875,8 +1879,4 @@ function Panel_Graph() : PanelContent() constructor {
ds_list_remove(nodes_list, node); ds_list_remove(nodes_list, node);
ds_list_add(nodes_list, node); ds_list_add(nodes_list, node);
} }
static exportNodeImage = function() {
var dia = dialogPanelCall(new Panel_Graph_Export_Image(self));
}
} }

View file

@ -1,13 +1,20 @@
function graph_export_image(nodeList, settings = {}) { function graph_export_image(allList, nodeList, settings = {}) {
var amo = ds_list_size(nodeList); var amo = ds_list_size(nodeList);
if(amo < 1) return; if(amo < 1) return;
var scale = struct_try_get(settings, "scale", 1); var scale = struct_try_get(settings, "scale", 1);
var padding = struct_try_get(settings, "padding", 0); var padding = struct_try_get(settings, "padding", 0);
var bgEnable = struct_try_get(settings, "bgEnable", false); var bgEnable = struct_try_get(settings, "bgEnable", false);
var bgColor = struct_try_get(settings, "bgColor", c_black); var bgColor = struct_try_get(settings, "bgColor", c_black);
var gridEnable = struct_try_get(settings, "gridEnable", false); var gridEnable = struct_try_get(settings, "gridEnable", false);
var gridColor = struct_try_get(settings, "gridColor", c_black); var gridColor = struct_try_get(settings, "gridColor", c_white);
var gridAlpha = struct_try_get(settings, "gridAlpha", 0);
var borderPad = struct_try_get(settings, "borderPad", 0);
var borderColor = struct_try_get(settings, "borderColor", c_white);
var borderAlpha = struct_try_get(settings, "borderAlpha", 0.5);
var bbox_x0 = nodeList[| 0].x * scale; var bbox_x0 = nodeList[| 0].x * scale;
var bbox_y0 = nodeList[| 0].y * scale; var bbox_y0 = nodeList[| 0].y * scale;
@ -43,8 +50,33 @@ function graph_export_image(nodeList, settings = {}) {
var gr_y = -bbox_y0; var gr_y = -bbox_y0;
var mx = gr_x, my = gr_y; var mx = gr_x, my = gr_y;
for(var i = 0; i < ds_list_size(nodeList); i++) if(gridEnable) {
nodeList[| i].preDraw(gr_x, gr_y, scale); var gls = 32;
var gr_ls = gls * scale;
var xx = -gr_ls, xs = safe_mod(gr_x, gr_ls);
var yy = -gr_ls, ys = safe_mod(gr_y, gr_ls);
draw_set_color(gridColor);
draw_set_alpha(gridAlpha);
while(xx < bbox_w + gr_ls) {
draw_line(xx + xs, 0, xx + xs, bbox_h);
if(xx + xs - gr_x == 0)
draw_line_width(xx + xs, 0, xx + xs, bbox_h, 3);
xx += gr_ls;
}
while(yy < bbox_h + gr_ls) {
draw_line(0, yy + ys, bbox_w, yy + ys);
if(yy + ys - gr_y == 0)
draw_line_width(0, yy + ys, bbox_w, yy + ys, 3);
yy += gr_ls;
}
draw_set_alpha(1);
}
for(var i = 0; i < ds_list_size(allList); i++)
allList[| i].preDraw(gr_x, gr_y, scale);
#region draw frame #region draw frame
for(var i = 0; i < ds_list_size(nodeList); i++) { for(var i = 0; i < ds_list_size(nodeList); i++) {
@ -81,5 +113,25 @@ function graph_export_image(nodeList, settings = {}) {
surface_reset_target(); surface_reset_target();
return s; if(borderPad == 0) return s;
var _sg = surface_create(bbox_w + borderPad * 2, bbox_h + borderPad * 2);
surface_set_target(_sg);
if(bgEnable) draw_clear(bgColor);
else draw_clear_alpha(0, 0);
draw_surface(s, borderPad, borderPad);
draw_set_color(borderColor);
draw_set_alpha(borderAlpha);
draw_rectangle(borderPad, borderPad, bbox_w + borderPad, bbox_h + borderPad, 1);
draw_set_alpha(1);
surface_reset_target();
surface_free(s);
return _sg;
} }

View file

@ -1,14 +1,99 @@
function Panel_Graph_Export_Image(targetPanel) : PanelContent() constructor { function Panel_Graph_Export_Image(targetPanel) : PanelContent() constructor {
title = "Export Graph"; title = "Export Graph";
w = ui(480); w = ui(360);
h = ui(640); h = ui(524);
min_h = h;
self.targetPanel = targetPanel; self.targetPanel = targetPanel;
nodeList = targetPanel.nodes_list;
surface = noone; surface = noone;
settings = {}; settings = {
scale : 1,
padding : 64,
nodeList = noone; bgEnable : false,
bgColor : COLORS.panel_bg_clear,
gridEnable : false,
gridColor : c_white,
gridAlpha : 0.05,
borderPad : 0,
borderColor : c_white,
borderAlpha : 0.05,
};
sel = 0;
nodes_select = [ "All nodes", "Selected" ];
widgets = [];
widgets[0] = [ "Nodes", new scrollBox(nodes_select, function(val) { sel = val; nodeList = val? targetPanel.nodes_select_list : targetPanel.nodes_list; refresh(); }, false),
function() { return nodes_select[sel] } ];
widgets[1] = [ "Scale", new textBox(TEXTBOX_INPUT.number, function(val) { settings.scale = val; refresh(); }),
function() { return settings.scale } ];
widgets[2] = [ "Padding", new textBox(TEXTBOX_INPUT.number, function(val) { settings.padding = val; refresh(); }),
function() { return settings.padding } ];
widgets[3] = [ "Solid Background", new checkBox(function() { settings.bgEnable = !settings.bgEnable; refresh(); }),
function() { return settings.bgEnable } ];
widgets[4] = [ "Background Color", new buttonColor(function(val) { settings.bgColor = val; refresh(); }),
function() { return settings.bgColor } ];
widgets[5] = [ "Render Grid", new checkBox(function() { settings.gridEnable = !settings.gridEnable; refresh(); }),
function() { return settings.gridEnable } ];
widgets[6] = [ "Grid Color", new buttonColor(function(val) { settings.gridColor = val; refresh(); }),
function() { return settings.gridColor } ];
widgets[7] = [ "Grid Opacity", new textBox(TEXTBOX_INPUT.number, function(val) { settings.gridAlpha = val; refresh(); }),
function() { return settings.gridAlpha } ];
widgets[8] = [ "Border", new textBox(TEXTBOX_INPUT.number, function(val) { settings.borderPad = val; refresh(); }),
function() { return settings.borderPad } ];
widgets[9] = [ "Border Color", new buttonColor(function(val) { settings.borderColor = val; refresh(); }),
function() { return settings.borderColor } ];
widgets[10] = [ "Border Opacity", new textBox(TEXTBOX_INPUT.number, function(val) { settings.borderAlpha = val; refresh(); }),
function() { return settings.borderAlpha } ];
b_export = button(function() {
if(!is_surface(surface)) return;
var path = get_save_filename("*.png", "Screenshot");
if(path == -1) return;
if(!filename_ext(path) != ".png") path += ".png";
surface_save(surface, path);
noti_status($"Graph image exported at {path}");
});
sc_settings = new scrollPane(w - ui(padding + padding), h - ui(title_height + padding + 204), function(_y, _m) {
draw_clear_alpha(COLORS.panel_bg_clear, 0);
var _ww = ui(160);
var _hh = ui(30);
var _ss = ui(28);
var ty = _y + _hh / 2;
var _tx = sc_settings.surface_w;
var wh = ui(36);
for( var i = 0; i < array_length(widgets); i++ ) {
draw_set_text(f_p1, fa_left, fa_center, COLORS._main_text);
draw_text_over(0, ty + wh * i, widgets[i][0]);
var _wid = widgets[i][1];
var _dat = widgets[i][2]();
_wid.setActiveFocus(pFOCUS, pHOVER);
switch(instanceof(widgets[i][1])) {
case "textBox" : _wid.draw(_tx - _ww, ty + wh * i - _hh / 2, _ww, _hh, _dat, _m); break;
case "checkBox" : _wid.draw(_tx - _ww / 2 - _ss / 2, ty + wh * i - _ss / 2, _dat, _m); break;
case "buttonColor" : _wid.draw(_tx - _ww, ty + wh * i - _hh / 2, _ww, _hh, _dat, _m); break;
case "scrollBox" : _wid.draw(_tx - _ww, ty + wh * i - _hh / 2, _ww, _hh, _dat, _m, sc_settings.x + x, sc_settings.y + y); break;
}
}
var _h = wh * array_length(widgets) + _hh;
return _h;
})
function onResize() {
sc_settings.resize(w - ui(padding + padding), h - ui(title_height + padding + 204));
}
function refresh() { function refresh() {
if(is_surface(surface)) if(is_surface(surface))
@ -18,17 +103,52 @@ function Panel_Graph_Export_Image(targetPanel) : PanelContent() constructor {
if(nodeList == noone) if(nodeList == noone)
return; return;
surface = graph_export_image(nodeList, settings); surface = graph_export_image(targetPanel.nodes_list, nodeList, settings);
} } refresh();
function drawContent(panel) { function drawContent(panel) {
var tx = padding;
var ty = padding;
var sh = 160;
if(is_surface(surface)) { if(is_surface(surface)) {
var _sw = surface_get_width(surface);
var _sh = surface_get_height(surface);
var ss = min((w - padding * 2) / _sw, sh / _sh);
draw_surface_ext(surface, w / 2 - _sw * ss / 2, ty + sh / 2 - _sh * ss / 2, ss, ss, 0, c_white, 1);
draw_set_text(f_p2, fa_center, fa_bottom, COLORS._main_text_sub);
draw_text_add(w / 2, ty + sh - ui(2), $"{surface_get_width(surface)} x {surface_get_height(surface)} px");
} }
var tx = 0; draw_set_color(COLORS._main_icon);
var ty = 0; draw_rectangle(tx, ty, tx + w - padding * 2, ty + sh, 1);
var bx = w - padding - ui(4) - ui(24);
var by = padding + ui(4);
var _m = [ mx, my ];
if(buttonInstant(THEME.button_hide, bx, by, ui(24), ui(24), _m, pFOCUS, pHOVER) == 2)
refresh();
draw_sprite_ui(THEME.refresh_s, 0, bx + ui(12), by + ui(12),,,, COLORS._main_icon, 1);
var sx = tx;
var sy = ty + sh + ui(16);
sc_settings.setActiveFocus(pFOCUS, pHOVER);
sc_settings.draw(sx, sy, mx - sx, my - sy);
if(is_surface(surface)) {
draw_set_text(f_p1, fa_left, fa_top, COLORS._main_text);
var _bw = string_width("Export") + ui(32);
var _bh = string_height("Export") + ui(12);
bx = w - padding - _bw;
by = h - padding - _bh;
b_export.setActiveFocus(pFOCUS, pHOVER);
b_export.draw(bx, by, _bw, _bh, _m);
draw_text(bx + ui(16), by + ui(6), "Export");
}
} }
} }

View file

@ -128,16 +128,17 @@ function Panel_Preview() : PanelContent() constructor {
]; ];
actions = [ actions = [
[
THEME.icon_center_canvas,
get_text("panel_preview_center_canvas", "Center canvas"),
function() { fullView(); }
],
[ [
THEME.icon_preview_export, THEME.icon_preview_export,
get_text("panel_preview_export_canvas", "Export canvas"), get_text("panel_preview_export_canvas", "Export canvas"),
function() { saveCurrentFrame(); } function() { saveCurrentFrame(); }
], ],
[
THEME.icon_center_canvas,
get_text("panel_preview_center_canvas", "Center canvas"),
function() { fullView(); }
],
] ]
tb_framerate = new textBox(TEXTBOX_INPUT.number, function(val) { preview_rate = real(val); }); tb_framerate = new textBox(TEXTBOX_INPUT.number, function(val) { preview_rate = real(val); });