[Round Corner] Improve algorithm.

This commit is contained in:
Tanasart 2025-03-02 13:36:33 +07:00
parent 8d441aad2f
commit e26ec42524
13 changed files with 193 additions and 140 deletions

View file

@ -348,6 +348,7 @@
{"name":"o_dialog_textbox_autocomplete","order":7,"path":"objects/o_dialog_textbox_autocomplete/o_dialog_textbox_autocomplete.yy",},
{"name":"o_dialog_textbox_function_guide","order":8,"path":"objects/o_dialog_textbox_function_guide/o_dialog_textbox_function_guide.yy",},
{"name":"o_dialog_value_editor","order":9,"path":"objects/o_dialog_value_editor/o_dialog_value_editor.yy",},
{"name":"sh_corner_apply","order":1,"path":"shaders/sh_corner_apply/sh_corner_apply.yy",},
{"name":"o_dialog_warning","order":6,"path":"objects/o_dialog_warning/o_dialog_warning.yy",},
{"name":"o_pie_menu","order":14,"path":"objects/o_pie_menu/o_pie_menu.yy",},
{"name":"Obj_Debug_FallText_Firestore","order":6,"path":"objects/Obj_Debug_FallText_Firestore/Obj_Debug_FallText_Firestore.yy",},
@ -1462,6 +1463,7 @@
{"name":"type_conversion","order":7,"path":"scripts/type_conversion/type_conversion.yy",},
{"name":"value_snap","order":9,"path":"scripts/value_snap/value_snap.yy",},
{"name":"var_comparison","order":1,"path":"scripts/var_comparison/var_comparison.yy",},
{"name":"sh_corner_coord","order":4,"path":"shaders/sh_corner_coord/sh_corner_coord.yy",},
{"name":"vct_knob","order":2,"path":"scripts/vct_knob/vct_knob.yy",},
{"name":"vct_slider","order":1,"path":"scripts/vct_slider/vct_slider.yy",},
{"name":"vct_toggle","order":3,"path":"scripts/vct_toggle/vct_toggle.yy",},
@ -1583,8 +1585,8 @@
{"name":"sh_content_sampler","order":17,"path":"shaders/sh_content_sampler/sh_content_sampler.yy",},
{"name":"sh_convolution","order":9,"path":"shaders/sh_convolution/sh_convolution.yy",},
{"name":"sh_coord","order":14,"path":"shaders/sh_coord/sh_coord.yy",},
{"name":"sh_corner_erode","order":1,"path":"shaders/sh_corner_erode/sh_corner_erode.yy",},
{"name":"sh_corner_iterate","order":2,"path":"shaders/sh_corner_iterate/sh_corner_iterate.yy",},
{"name":"sh_corner_erode","order":2,"path":"shaders/sh_corner_erode/sh_corner_erode.yy",},
{"name":"sh_corner_iterate","order":3,"path":"shaders/sh_corner_iterate/sh_corner_iterate.yy",},
{"name":"sh_cross_section","order":17,"path":"shaders/sh_cross_section/sh_cross_section.yy",},
{"name":"sh_curve_hsv","order":5,"path":"shaders/sh_curve_hsv/sh_curve_hsv.yy",},
{"name":"sh_curve","order":3,"path":"shaders/sh_curve/sh_curve.yy",},

View file

@ -1313,11 +1313,7 @@
{"$GMIncludedFile":"","%Name":"Canvas.png","CopyToMask":-1,"filePath":"datafiles/data/Welcome files/Templates","name":"Canvas.png","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"Canvas.pxc","CopyToMask":-1,"filePath":"datafiles/data/Welcome files/Templates","name":"Canvas.pxc","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"Welcome files.zip","CopyToMask":-1,"filePath":"datafiles/data/Welcome files","name":"Welcome files.zip","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"dllcredits.txt","ConfigValues":{
"Itch":{
"CopyToMask":"0",
},
},"CopyToMask":0,"filePath":"datafiles","name":"dllcredits.txt","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"dllcredits.txt","ConfigValues":{"Itch":{"CopyToMask":"0",},},"CopyToMask":0,"filePath":"datafiles","name":"dllcredits.txt","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"dlltest1.dll","CopyToMask":-1,"filePath":"datafiles","name":"dlltest1.dll","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"ffmpeg.exe","CopyToMask":-1,"filePath":"datafiles/ffmpeg/bin","name":"ffmpeg.exe","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"LICENSE","CopyToMask":-1,"filePath":"datafiles/ffmpeg","name":"LICENSE","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
@ -1336,11 +1332,7 @@
{"$GMIncludedFile":"","%Name":"mf.dll","CopyToMask":-1,"filePath":"datafiles","name":"mf.dll","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"mfcore.dll","CopyToMask":-1,"filePath":"datafiles","name":"mfcore.dll","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"mfplat.dll","CopyToMask":-1,"filePath":"datafiles","name":"mfplat.dll","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"PixelComposer_profile-2.provisionprofile","ConfigValues":{
"Itch":{
"CopyToMask":"2",
},
},"CopyToMask":-1,"filePath":"datafiles","name":"PixelComposer_profile-2.provisionprofile","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"PixelComposer_profile-2.provisionprofile","ConfigValues":{"Itch":{"CopyToMask":"2",},},"CopyToMask":-1,"filePath":"datafiles","name":"PixelComposer_profile-2.provisionprofile","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"data.win","CopyToMask":-1,"filePath":"datafiles/report","name":"data.win","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"execute_shell_simple_ext_x64.dll","CopyToMask":-1,"filePath":"datafiles/report","name":"execute_shell_simple_ext_x64.dll","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
{"$GMIncludedFile":"","%Name":"options.ini","CopyToMask":-1,"filePath":"datafiles/report","name":"options.ini","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
@ -1984,6 +1976,7 @@
{"id":{"name":"node_color_adjust","path":"scripts/node_color_adjust/node_color_adjust.yy",},},
{"id":{"name":"node_color_data","path":"scripts/node_color_data/node_color_data.yy",},},
{"id":{"name":"node_color_hsv","path":"scripts/node_color_hsv/node_color_hsv.yy",},},
{"id":{"name":"sh_corner_coord","path":"shaders/sh_corner_coord/sh_corner_coord.yy",},},
{"id":{"name":"node_color_mix","path":"scripts/node_color_mix/node_color_mix.yy",},},
{"id":{"name":"node_color_oklch","path":"scripts/node_color_oklch/node_color_oklch.yy",},},
{"id":{"name":"node_color_remove","path":"scripts/node_color_remove/node_color_remove.yy",},},
@ -3202,6 +3195,7 @@
{"id":{"name":"s_filter_node_inspector","path":"sprites/s_filter_node_inspector/s_filter_node_inspector.yy",},},
{"id":{"name":"s_filter_node","path":"sprites/s_filter_node/s_filter_node.yy",},},
{"id":{"name":"s_filter","path":"sprites/s_filter/s_filter.yy",},},
{"id":{"name":"sh_corner_apply","path":"shaders/sh_corner_apply/sh_corner_apply.yy",},},
{"id":{"name":"s_flare_type","path":"sprites/s_flare_type/s_flare_type.yy",},},
{"id":{"name":"s_fx_pixel","path":"sprites/s_fx_pixel/s_fx_pixel.yy",},},
{"id":{"name":"s_gamemaker","path":"sprites/s_gamemaker/s_gamemaker.yy",},},

View file

@ -1,7 +1,8 @@
#region
FN_NODE_CONTEXT_INVOKE {
addHotkey("Node_Checker", "Amount > Set", KEY_GROUP.numeric, MOD_KEY.none, function() /*=>*/ { PANEL_GRAPH_FOCUS_STR _n.inputs[1].setValue(toNumber(chr(keyboard_key))); });
addHotkey("Node_Checker", "Type > Toggle", "T", MOD_KEY.none, function() /*=>*/ { PANEL_GRAPH_FOCUS_STR _n.inputs[8].setValue((_n.inputs[8].getValue() + 1) % 3); });
addHotkey("Node_Checker", "Diagonal > Toggle", "D", MOD_KEY.none, function() /*=>*/ { PANEL_GRAPH_FOCUS_STR _n.inputs[9].setValue(!_n.inputs[9].getValue()); });
addHotkey("Node_Checker", "Type > Toggle", "T", MOD_KEY.none, function() /*=>*/ { PANEL_GRAPH_FOCUS_STR _n.inputs[8].setValue((_n.inputs[8].getValue() + 1) % 3); });
});
#endregion

View file

@ -9,8 +9,8 @@ function Node_Corner(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co
newInput(0, nodeValue_Surface("Surface In", self));
newInput(1, nodeValue_Float("Radius", self, 2))
.setDisplay(VALUE_DISPLAY.slider, { range: [2, 16, 0.1] });
newInput(1, nodeValue_Int("Radius", self, 2))
.setDisplay(VALUE_DISPLAY.slider, { range: [1, 16, 0.1] });
newInput(2, nodeValue_Surface("Mask", self));
@ -24,44 +24,68 @@ function Node_Corner(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) co
__init_mask_modifier(2); // inputs 6, 7
newInput(8, nodeValue_Slider("Thershold", self, .5));
input_display_list = [ 4, 5,
["Surfaces", true], 0, 2, 3, 6, 7,
["Corner", false], 1,
["Corner", false], 1, 8,
]
newOutput(0, nodeValue_Output("Surface Out", self, VALUE_TYPE.surface, noone));
attribute_surface_depth();
attribute_oversample();
static step = function() { #region
temp_surface = array_create(2);
static step = function() {
__step_mask_modifier();
} #endregion
}
static processData = function(_outSurf, _data, _output_index, _array_index) {
var wd = _data[1];
var _surf = _data[0];
var _rad = _data[1];
var _thr = _data[8];
var temp = surface_create_valid(surface_get_width_safe(_data[0]), surface_get_height_safe(_data[0]), attrDepth());
var _sw = surface_get_width_safe(_surf);
var _sh = surface_get_height_safe(_surf);
var _dim = [ _sw, _sh ];
surface_set_shader(temp, sh_corner_erode);
shader_set_f("dimension", [surface_get_width_safe(_data[0]), surface_get_height_safe(_data[0])]);
shader_set_f("size", wd);
for( var i = 0, n = array_length(temp_surface); i < n; i++ ) {
temp_surface[i] = surface_verify(temp_surface[i], _sw, _sh);
surface_clear(temp_surface[i]);
}
draw_surface_safe(_data[0]);
surface_set_shader(temp_surface[0], sh_corner_coord);
draw_surface_safe(_surf);
surface_reset_shader();
surface_set_shader(_outSurf, sh_corner);
shader_set_f("dimension", [surface_get_width_safe(_data[0]), surface_get_height_safe(_data[0])]);
shader_set_f("rad", wd);
shader_set_surface("original", _data[0]);
var _itr = max(_sw, _sh) / 4;
var _bg = 1;
draw_surface_safe(temp);
repeat(_itr) {
surface_set_shader(temp_surface[_bg], sh_corner_iterate);
shader_set_2("dimension", _dim);
draw_surface_safe(temp_surface[!_bg]);
surface_reset_shader();
_bg = !_bg;
}
var _sam = getAttribute("oversample");
surface_set_shader(_outSurf, sh_corner_apply);
shader_set_2("dimension", _dim);
shader_set_f("radius", _rad);
shader_set_f("thershold", _thr);
shader_set_surface("original", _surf);
shader_set_i("sampleMode", _sam);
draw_surface_safe(temp_surface[!_bg]);
surface_reset_shader();
surface_free(temp);
__process_mask_modifier(_data);
_outSurf = mask_apply(_data[0], _outSurf, _data[2], _data[3]);
_outSurf = channel_apply(_data[0], _outSurf, _data[5]);
_outSurf = mask_apply(_surf, _outSurf, _data[2], _data[3]);
_outSurf = channel_apply(_surf, _outSurf, _data[5]);
return _outSurf;
}

View file

@ -1,54 +1,6 @@
//
// Simple passthrough fragment shader
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec2 dimension;
uniform float rad;
uniform sampler2D original;
#define TAU 6.283185307179586
void main() {
vec2 pixelPosition = v_vTexcoord * dimension;
gl_FragColor = texture2D( gm_BaseTexture, v_vTexcoord );
if(length(gl_FragColor.rgb) * gl_FragColor.a <= 0.) {
gl_FragColor.a = 1.;
return;
}
float maxCorner = 0.;
float minDistance = rad;
for(float i = rad; i >= 1.; i--) {
float base = 1.;
float top = 0.;
for(float j = 0.; j <= 64.; j++) {
float ang = top / base * TAU;
top += 2.;
if(top >= base) {
top = 1.;
base *= 2.;
}
vec2 pxs = (pixelPosition + vec2( cos(ang) * i, sin(ang) * i)) / dimension;
if(pxs.x < 0. || pxs.x > 1. || pxs.y < 0. || pxs.y > 1.)
continue;
float corn = floor(texture2D( gm_BaseTexture, pxs).r * rad);
if(corn >= maxCorner) {
maxCorner = corn;
minDistance = i;
}
}
}
if(minDistance < maxCorner)
gl_FragColor = texture2D(original, v_vTexcoord);
else
gl_FragColor = vec4(vec3(0.), 1.);
gl_FragColor = vec4(0., 0., 0., 1.);
}

View file

@ -0,0 +1,51 @@
#pragma use(sampler_simple)
#region -- sampler_simple -- [1729740692.1417658]
uniform int sampleMode;
vec4 sampleTexture( sampler2D texture, vec2 pos) {
if(pos.x >= 0. && pos.y >= 0. && pos.x <= 1. && pos.y <= 1.)
return texture2D(texture, pos);
if(sampleMode <= 1) return vec4(0.);
else if(sampleMode == 2) return texture2D(texture, clamp(pos, 0., 1.));
else if(sampleMode == 3) return texture2D(texture, fract(pos));
else if(sampleMode == 4) return vec4(vec3(0.), 1.);
return vec4(0.);
}
#endregion -- sampler_simple --
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec2 dimension;
uniform float radius;
uniform float thershold;
uniform sampler2D original;
void main() {
gl_FragColor = vec4(0., 0., 0., 1.);
vec4 cc = texture2D(gm_BaseTexture, v_vTexcoord);
if(cc.a == 0.) return;
vec2 tx = 1. / dimension;
float kfill = 0.;
float ksize = 0.;
for(float i = -16.; i <= 16.; i++)
for(float j = -16.; j <= 16.; j++) {
if(abs(i) > radius || abs(j) > radius) continue;
vec4 samp = sampleTexture(gm_BaseTexture, v_vTexcoord + vec2(i, j) * tx);
ksize++;
if(samp.rg != cc.rg) continue;
kfill += samp.a;
}
bool isCorner = (kfill / ksize) < thershold;
if(!isCorner) gl_FragColor = texture2D(original, v_vTexcoord);
}

View file

@ -0,0 +1,14 @@
attribute vec3 in_Position; // (x, y, z)
attribute vec4 in_Colour; // (r, g, b, a)
attribute vec2 in_TextureCoord; // (u, v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main() {
vec4 object_space_pos = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
}

View file

@ -0,0 +1,13 @@
{
"$GMShader":"",
"%Name":"sh_corner_apply",
"name":"sh_corner_apply",
"parent":{
"name":"corner",
"path":"folders/nodes/data/filter/effects/corner.yy",
},
"resourceType":"GMShader",
"resourceVersion":"2.0",
"tags":[],
"type":1,
}

View file

@ -0,0 +1,7 @@
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main() {
vec4 cc = texture2D(gm_BaseTexture, v_vTexcoord);
gl_FragColor = (cc.r + cc.g + cc.b) * cc.a / 3. > .5? vec4(v_vTexcoord, 0., 1.) : vec4(0.);
}

View file

@ -0,0 +1,14 @@
attribute vec3 in_Position; // (x, y, z)
attribute vec4 in_Colour; // (r, g, b, a)
attribute vec2 in_TextureCoord; // (u, v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
void main() {
vec4 object_space_pos = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
}

View file

@ -0,0 +1,13 @@
{
"$GMShader":"",
"%Name":"sh_corner_coord",
"name":"sh_corner_coord",
"parent":{
"name":"corner",
"path":"folders/nodes/data/filter/effects/corner.yy",
},
"resourceType":"GMShader",
"resourceVersion":"2.0",
"tags":[],
"type":1,
}

View file

@ -5,78 +5,45 @@ varying vec4 v_vColour;
uniform vec2 dimension;
vec2 min2(vec2 a, vec2 b) { return a.y < b.y? a : (a.x < b.x? a : b); }
void main() {
vec2 tx = 1. / dimension;
vec4 cc = texture2D( gm_BaseTexture, v_vTexcoord );
float hh = cc.r;
if(hh == 0.) {
gl_FragColor = vec4(vec3(0.), 1.);
return;
}
gl_FragColor = vec4(0.);
if(cc.a == 0.) return;
vec2 px, mn = cc.yz;
vec4 ss;
vec2 cx = cc.xy;
for(float i = 1.; i < SPAN; i++) {
px = v_vTexcoord + vec2(i * tx.x, 0.);
ss = texture2D( gm_BaseTexture, px );
for(float i = 1.; i <= SPAN; i++) {
ss = texture2D( gm_BaseTexture, v_vTexcoord + vec2(i * tx.x, 0.) );
if(ss.a == 0.) break;
if(ss.r == 0.) break;
if(ss.r > hh) {
hh = ss.r;
mn = ss.yz;
} else if(ss.r == hh) {
if(distance(v_vTexcoord, ss.yz) < distance(v_vTexcoord, mn))
mn = ss.yz;
}
cx = min(cx, ss.xy);
}
for(float i = 1.; i < SPAN; i++) {
px = v_vTexcoord - vec2(i * tx.x, 0.);
ss = texture2D( gm_BaseTexture, px );
for(float i = 1.; i <= SPAN; i++) {
ss = texture2D( gm_BaseTexture, v_vTexcoord - vec2(i * tx.x, 0.) );
if(ss.a == 0.) break;
if(ss.r == 0.) break;
if(ss.r > hh) {
hh = ss.r;
mn = ss.yz;
} else if(ss.r == hh) {
if(distance(v_vTexcoord, ss.yz) < distance(v_vTexcoord, mn))
mn = ss.yz;
}
cx = min(cx, ss.xy);
}
for(float i = 1.; i < SPAN; i++) {
px = v_vTexcoord + vec2(0., i * tx.y);
ss = texture2D( gm_BaseTexture, px );
for(float i = 1.; i <= SPAN; i++) {
ss = texture2D( gm_BaseTexture, v_vTexcoord + vec2(0., i * tx.y) );
if(ss.a == 0.) break;
if(ss.r == 0.) break;
if(ss.r > hh) {
hh = ss.r;
mn = ss.yz;
} else if(ss.r == hh) {
if(distance(v_vTexcoord, ss.yz) < distance(v_vTexcoord, mn))
mn = ss.yz;
}
cx = min(cx, ss.xy);
}
for(float i = 1.; i < SPAN; i++) {
px = v_vTexcoord - vec2(0., i * tx.y);
ss = texture2D( gm_BaseTexture, px );
for(float i = 1.; i <= SPAN; i++) {
ss = texture2D( gm_BaseTexture, v_vTexcoord - vec2(0., i * tx.y) );
if(ss.a == 0.) break;
if(ss.r == 0.) break;
if(ss.r > hh) {
hh = ss.r;
mn = ss.yz;
} else if(ss.r == hh) {
if(distance(v_vTexcoord, ss.yz) < distance(v_vTexcoord, mn))
mn = ss.yz;
}
cx = min(cx, ss.xy);
}
gl_FragColor = vec4(hh, mn, 1.);
gl_FragColor = vec4(cx, 0., 1.);
}

View file

@ -32,7 +32,8 @@ void main() {
ang = radians(ang);
#endregion
vec2 ntx = v_vTexcoord * vec2(1., dimension.y / dimension.x);
vec2 vtx = floor(v_vTexcoord * dimension) / dimension;
vec2 ntx = vtx * vec2(1., dimension.y / dimension.x);
vec2 pos = ntx - position;
float _cell = 1. / (amo * 2.);
pos.y -= _cell / 2.;