From ee6d753836882bc8ef0a065a11faa13d0ae24bd9 Mon Sep 17 00:00:00 2001 From: Tanasart Date: Sun, 23 Jun 2024 13:34:04 +0700 Subject: [PATCH] - [Scale Algorithm] Add cleanShape algorithm. --- PixelComposer.resource_order | 1 + PixelComposer.yyp | 1 + scripts/node_registry/node_registry.gml | 2 +- scripts/node_scale_algo/node_scale_algo.gml | 45 ++- .../sh_scale_cleanedge/sh_scale_cleanedge.fsh | 348 ++++++++++++++++++ .../sh_scale_cleanedge/sh_scale_cleanedge.vsh | 19 + .../sh_scale_cleanedge/sh_scale_cleanedge.yy | 12 + 7 files changed, 409 insertions(+), 19 deletions(-) create mode 100644 shaders/sh_scale_cleanedge/sh_scale_cleanedge.fsh create mode 100644 shaders/sh_scale_cleanedge/sh_scale_cleanedge.vsh create mode 100644 shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index 179317b3f..5c2008e05 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -1542,6 +1542,7 @@ {"name":"sh_rsh_erode","order":2,"path":"shaders/sh_rsh_erode/sh_rsh_erode.yy",}, {"name":"sh_rsh_rotate","order":1,"path":"shaders/sh_rsh_rotate/sh_rsh_rotate.yy",}, {"name":"sh_sample_points","order":9,"path":"shaders/sh_sample_points/sh_sample_points.yy",}, + {"name":"sh_scale_cleanedge","order":57,"path":"shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy",}, {"name":"sh_scale2x","order":13,"path":"shaders/sh_scale2x/sh_scale2x.yy",}, {"name":"sh_scale3x","order":15,"path":"shaders/sh_scale3x/sh_scale3x.yy",}, {"name":"sh_sdf_dist","order":4,"path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index a9d706b93..94c3af5fd 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -2065,6 +2065,7 @@ {"id":{"name":"sh_rsh_rotate","path":"shaders/sh_rsh_rotate/sh_rsh_rotate.yy",},}, {"id":{"name":"sh_sample_points","path":"shaders/sh_sample_points/sh_sample_points.yy",},}, {"id":{"name":"sh_sample","path":"shaders/sh_sample/sh_sample.yy",},}, + {"id":{"name":"sh_scale_cleanedge","path":"shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy",},}, {"id":{"name":"sh_scale2x","path":"shaders/sh_scale2x/sh_scale2x.yy",},}, {"id":{"name":"sh_scale3x","path":"shaders/sh_scale3x/sh_scale3x.yy",},}, {"id":{"name":"sh_sdf_dist","path":"shaders/sh_sdf_dist/sh_sdf_dist.yy",},}, diff --git a/scripts/node_registry/node_registry.gml b/scripts/node_registry/node_registry.gml index f995f377d..21d67606c 100644 --- a/scripts/node_registry/node_registry.gml +++ b/scripts/node_registry/node_registry.gml @@ -530,7 +530,7 @@ function __initNodes() { ds_list_add(transform, "Transformations"); addNodeObject(transform, "Transform", s_node_transform, "Node_Transform", [1, Node_Transform], ["move", "rotate", "scale"], "Move, rotate, and scale image."); addNodeObject(transform, "Scale", s_node_scale, "Node_Scale", [1, Node_Scale], ["resize"], "Simple node for scaling image."); - addNodeObject(transform, "Scale Algorithm", s_node_scale_algo, "Node_Scale_Algo", [0, Node_create_Scale_Algo], ["scale2x", "scale3x"], "Scale image using scale2x, scale3x algorithm."); + addNodeObject(transform, "Scale Algorithm", s_node_scale_algo, "Node_Scale_Algo", [0, Node_create_Scale_Algo], ["scale2x", "scale3x", "cleanshape"], "Scale image using scale2x, scale3x algorithm."); addNodeObject(transform, "Flip", s_node_flip, "Node_Flip", [1, Node_Flip], ["mirror"], "Flip image horizontally or vertically."); addNodeObject(transform, "Offset", s_node_offset, "Node_Offset", [1, Node_Offset],, "Shift image with tiling."); diff --git a/scripts/node_scale_algo/node_scale_algo.gml b/scripts/node_scale_algo/node_scale_algo.gml index e73472f57..8535bbad4 100644 --- a/scripts/node_scale_algo/node_scale_algo.gml +++ b/scripts/node_scale_algo/node_scale_algo.gml @@ -3,8 +3,9 @@ function Node_create_Scale_Algo(_x, _y, _group = noone, _param = {}) { var node = new Node_Scale_Algo(_x, _y, _group); switch(query) { - case "scale2x" : node.inputs[| 1].setValue(0); break; - case "scale3x" : node.inputs[| 1].setValue(1); break; + case "scale2x" : node.inputs[| 1].setValue(0); break; + case "scale3x" : node.inputs[| 1].setValue(1); break; + case "cleanshape" : node.inputs[| 1].setValue(2); break; } return node; @@ -18,7 +19,7 @@ function Node_Scale_Algo(_x, _y, _group = noone) : Node_Processor(_x, _y, _group inputs[| 0] = nodeValue("Surface in", self, JUNCTION_CONNECT.input, VALUE_TYPE.surface, noone); inputs[| 1] = nodeValue("Algorithm", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 0) - .setDisplay(VALUE_DISPLAY.enum_scroll, [ "Scale2x", "Scale3x" ]); + .setDisplay(VALUE_DISPLAY.enum_scroll, [ "Scale2x", "Scale3x", "CleanEdge" ]); inputs[| 2] = nodeValue("Tolerance", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0) .setDisplay(VALUE_DISPLAY.slider); @@ -27,27 +28,32 @@ function Node_Scale_Algo(_x, _y, _group = noone) : Node_Processor(_x, _y, _group active_index = 3; inputs[| 4] = nodeValue("Scale atlas position", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true); + + inputs[| 5] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 4); outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); input_display_list = [ 3, ["Surfaces", false], 0, - ["Scale", false], 1, 2, 4, + ["Scale", false], 1, 2, 4, 5, ] attribute_surface_depth(); static step = function() { var _surf = getSingleValue(0); + var _type = getSingleValue(1); var _atlas = is_instanceof(_surf, SurfaceAtlas); inputs[| 4].setVisible(_atlas); + inputs[| 5].setVisible(_type == 2); } static processData = function(_outSurf, _data, _output_index, _array_index) { var inSurf = _data[0]; var algo = _data[1]; var _atlS = _data[4]; + var _scal = _data[5]; var ww = surface_get_width_safe(inSurf); var hh = surface_get_height_safe(inSurf); var cDep = attrDepth(); @@ -76,23 +82,26 @@ function Node_Scale_Algo(_x, _y, _group = noone) : Node_Processor(_x, _y, _group _surf = surface_verify(_surf, sw, sh, cDep); break; + case 2 : + shader = sh_scale_cleanedge; + sc = _scal; + ww *= sc; + hh *= sc; + + _surf = surface_verify(_surf, ww, hh, cDep); + // gpu_set_texfilter(true); + break; } - surface_set_target(_surf); - DRAW_CLEAR - BLEND_OVERRIDE; - - var uniform_dim = shader_get_uniform(shader, "dimension"); - var uniform_tol = shader_get_uniform(shader, "tol"); - - shader_set(shader); - shader_set_uniform_f_array_safe(uniform_dim, [ ww, hh ]); - shader_set_uniform_f(uniform_tol, _data[2]); + surface_set_shader(_surf, shader); + shader_set_f("dimension", [ ww, hh ]); + shader_set_f("tol", _data[2]); + shader_set_f("similarThreshold", _data[2]); + shader_set_f("scale", _data[5]); + draw_surface_ext_safe(_data[0], 0, 0, sc, sc, 0, c_white, 1); - shader_reset(); - - BLEND_NORMAL; - surface_reset_target(); + surface_reset_shader(); + gpu_set_texfilter(false); if(isAtlas) { if(_atlS) { diff --git a/shaders/sh_scale_cleanedge/sh_scale_cleanedge.fsh b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.fsh new file mode 100644 index 000000000..1039b16fe --- /dev/null +++ b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.fsh @@ -0,0 +1,348 @@ +/*** MIT LICENSE +Copyright (c) 2022 torcado + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +***/ + +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +//enables 2:1 slopes. otherwise only uses 45 degree slopes +#define SLOPE +//cleans up small detail slope transitions (if SLOPE is enabled) +//if only using for rotation, CLEANUP has negligable effect and should be disabled for speed +#define CLEANUP + +uniform vec2 dimension; +uniform float scale; + +//the color with the highest priority. +// other colors will be tested based on distance to this +// color to determine which colors take priority for overlaps. +/* uniform */ vec3 highestColor = vec3(1.,1.,1.); + +//how close two colors should be to be considered "similar". +// can group shapes of visually similar colors, but creates +// some artifacting and should be kept as low as possible. +uniform float similarThreshold; + +/* uniform */ float lineWidth = 1.0; + +const mat3 yuv_matrix = mat3(0.299, 0.587, 0.114, + -0.169, -0.331, 0.500, + 0.500, -0.419, -0.081); + +const mat3 yuv_matrix_transpose = mat3(0.299, -0.169, 0.500, + 0.587, -0.331, -0.419, + 0.114, 0.500, -0.081); + +vec3 yuv(vec3 col){ + return yuv_matrix_transpose * col; +} + +bool similar(vec4 col1, vec4 col2){ + return (col1.a == 0. && col2.a == 0.) || distance(col1, col2) <= similarThreshold; +} + +//multiple versions because godot doesn't support function overloading +//note: inner check should ideally check between all permutations +// but this is good enough, and faster +bool similar3(vec4 col1, vec4 col2, vec4 col3){ + return similar(col1, col2) && similar(col2, col3); +} + +bool similar4(vec4 col1, vec4 col2, vec4 col3, vec4 col4){ + return similar(col1, col2) && similar(col2, col3) && similar(col3, col4); +} + +bool similar5(vec4 col1, vec4 col2, vec4 col3, vec4 col4, vec4 col5){ + return similar(col1, col2) && similar(col2, col3) && similar(col3, col4) && similar(col4, col5); +} + +bool higher(vec4 thisCol, vec4 otherCol){ + if(similar(thisCol, otherCol)) return false; + if(thisCol.a == otherCol.a){ +// return yuv(thisCol.rgb).x > yuv(otherCol.rgb).x; +// return distance(yuv(thisCol.rgb), yuv(highestColor)) < distance(yuv(otherCol.rgb), yuv(highestColor)); + return distance(thisCol.rgb, highestColor) < distance(otherCol.rgb, highestColor); + } else { + return thisCol.a > otherCol.a; + } +} + +vec4 higherCol(vec4 thisCol, vec4 otherCol){ + return higher(thisCol, otherCol) ? thisCol : otherCol; +} + +//color distance +float cd(vec4 col1, vec4 col2){ + return distance(col1.rgba, col2.rgba); +} + +float distToLine(vec2 testPt, vec2 pt1, vec2 pt2, vec2 dir){ + vec2 lineDir = pt2 - pt1; + vec2 perpDir = vec2(lineDir.y, -lineDir.x); + vec2 dirToPt1 = pt1 - testPt; + return (dot(perpDir, dir) > 0.0 ? 1.0 : -1.0) * (dot(normalize(perpDir), dirToPt1)); +} + +//based on down-forward direction +vec4 sliceDist(vec2 point, vec2 mainDir, vec2 pointDir, vec4 u, vec4 uf, vec4 uff, vec4 b, vec4 c, vec4 f, vec4 ff, vec4 db, vec4 d, vec4 df, vec4 dff, vec4 ddb, vec4 dd, vec4 ddf){ + #ifdef SLOPE + float minWidth = 0.44; + float maxWidth = 1.142; + #else + float minWidth = 0.0; + float maxWidth = 1.4; + #endif + float _lineWidth = max(minWidth, min(maxWidth, lineWidth)); + point = mainDir * (point - 0.5) + 0.5; //flip point + + //edge detection + float distAgainst = 4.0*cd(f,d) + cd(uf,c) + cd(c,db) + cd(ff,df) + cd(df,dd); + float distTowards = 4.0*cd(c,df) + cd(u,f) + cd(f,dff) + cd(b,d) + cd(d,ddf); + bool shouldSlice = + (distAgainst < distTowards) + || (distAgainst < distTowards + 0.001) && !higher(c, f); //equivalent edges edge case + if(similar4(f, d, b, u) && similar3(uf, df, db/*, ub*/) && !similar(c, f)){ //checkerboard edge case + shouldSlice = false; + } + if(!shouldSlice) return vec4(-1.0); + + //only applicable for very large lineWidth (>1.3) +// if(similar3(c, f, df)){ //don't make slice for same color +// return vec4(-1.0); +// } + float dist = 1.0; + bool flip = false; + vec2 center = vec2(0.5,0.5); + + #ifdef SLOPE + if(similar3(f, d, db) && !similar3(f, d, b) && !similar(uf, db)){ //lower shallow 2:1 slant + if(similar(c, df) && higher(c, f)){ //single pixel wide diagonal, dont flip + + } else { + //priority edge cases + if(higher(c, f)){ + flip = true; + } + if(similar(u, f) && !similar(c, df) && !higher(c, u)){ + flip = true; + } + } + + if(flip){ + dist = _lineWidth-distToLine(point, center+vec2(1.5, -1.0)*pointDir, center+vec2(-0.5, 0.0)*pointDir, -pointDir); //midpoints of neighbor two-pixel groupings + } else { + dist = distToLine(point, center+vec2(1.5, 0.0)*pointDir, center+vec2(-0.5, 1.0)*pointDir, pointDir); //midpoints of neighbor two-pixel groupings + } + + //cleanup slant transitions + #ifdef CLEANUP + if(!flip && similar(c, uf) && !(similar3(c, uf, uff) && !similar3(c, uf, ff) && !similar(d, uff))){ //shallow + float dist2 = distToLine(point, center+vec2(2.0, -1.0)*pointDir, center+vec2(-0.0, 1.0)*pointDir, pointDir); + dist = min(dist, dist2); + } + #endif + + dist -= (_lineWidth/2.0); + return dist <= 0.0 ? ((cd(c,f) <= cd(c,d)) ? f : d) : vec4(-1.0); + } else if(similar3(uf, f, d) && !similar3(u, f, d) && !similar(uf, db)){ //forward steep 2:1 slant + if(similar(c, df) && higher(c, d)){ //single pixel wide diagonal, dont flip + + } else { + //priority edge cases + if(higher(c, d)){ + flip = true; + } + if(similar(b, d) && !similar(c, df) && !higher(c, d)){ + flip = true; + } + } + + if(flip){ + dist = _lineWidth-distToLine(point, center+vec2(0.0, -0.5)*pointDir, center+vec2(-1.0, 1.5)*pointDir, -pointDir); //midpoints of neighbor two-pixel groupings + } else { + dist = distToLine(point, center+vec2(1.0, -0.5)*pointDir, center+vec2(0.0, 1.5)*pointDir, pointDir); //midpoints of neighbor two-pixel groupings + } + + //cleanup slant transitions + #ifdef CLEANUP + if(!flip && similar(c, db) && !(similar3(c, db, ddb) && !similar3(c, db, dd) && !similar(f, ddb))){ //steep + float dist2 = distToLine(point, center+vec2(1.0, 0.0)*pointDir, center+vec2(-1.0, 2.0)*pointDir, pointDir); + dist = min(dist, dist2); + } + #endif + + dist -= (_lineWidth/2.0); + return dist <= 0.0 ? ((cd(c,f) <= cd(c,d)) ? f : d) : vec4(-1.0); + } else + #endif + if(similar(f, d)) { //45 diagonal + if(similar(c, df) && higher(c, f)){ //single pixel diagonal along neighbors, dont flip + if(!similar(c, dd) && !similar(c, ff)){ //line against triple color stripe edge case + flip = true; + } + } else { + //priority edge cases + if(higher(c, f)){ + flip = true; + } + if(!similar(c, b) && similar4(b, f, d, u)){ + flip = true; + } + } + //single pixel 2:1 slope, dont flip + if((( (similar(f, db) && similar3(u, f, df)) || (similar(uf, d) && similar3(b, d, df)) ) && !similar(c, df))){ + flip = true; + } + + if(flip){ + dist = _lineWidth-distToLine(point, center+vec2(1.0, -1.0)*pointDir, center+vec2(-1.0, 1.0)*pointDir, -pointDir); //midpoints of own diagonal pixels + } else { + dist = distToLine(point, center+vec2(1.0, 0.0)*pointDir, center+vec2(0.0, 1.0)*pointDir, pointDir); //midpoints of corner neighbor pixels + } + + //cleanup slant transitions + #ifdef SLOPE + #ifdef CLEANUP + if(!flip && similar3(c, uf, uff) && !similar3(c, uf, ff) && !similar(d, uff)){ //shallow + float dist2 = distToLine(point, center+vec2(1.5, 0.0)*pointDir, center+vec2(-0.5, 1.0)*pointDir, pointDir); + dist = max(dist, dist2); + } + + if(!flip && similar3(ddb, db, c) && !similar3(dd, db, c) && !similar(ddb, f)){ //steep + float dist2 = distToLine(point, center+vec2(1.0, -0.5)*pointDir, center+vec2(0.0, 1.5)*pointDir, pointDir); + dist = max(dist, dist2); + } + #endif + #endif + + dist -= (_lineWidth/2.0); + return dist <= 0.0 ? ((cd(c,f) <= cd(c,d)) ? f : d) : vec4(-1.0); + } + #ifdef SLOPE + else if(similar3(ff, df, d) && !similar3(ff, df, c) && !similar(uff, d)){ //far corner of shallow slant + + if(similar(f, dff) && higher(f, ff)){ //single pixel wide diagonal, dont flip + + } else { + //priority edge cases + if(higher(f, ff)){ + flip = true; + } + if(similar(uf, ff) && !similar(f, dff) && !higher(f, uf)){ + flip = true; + } + } + if(flip){ + dist = _lineWidth-distToLine(point, center+vec2(1.5+1.0, -1.0)*pointDir, center+vec2(-0.5+1.0, 0.0)*pointDir, -pointDir); //midpoints of neighbor two-pixel groupings + } else { + dist = distToLine(point, center+vec2(1.5+1.0, 0.0)*pointDir, center+vec2(-0.5+1.0, 1.0)*pointDir, pointDir); //midpoints of neighbor two-pixel groupings + } + + dist -= (_lineWidth/2.0); + return dist <= 0.0 ? ((cd(f,ff) <= cd(f,df)) ? ff : df) : vec4(-1.0); + } else if(similar3(f, df, dd) && !similar3(c, df, dd) && !similar(f, ddb)){ //far corner of steep slant + if(similar(d, ddf) && higher(d, dd)){ //single pixel wide diagonal, dont flip + + } else { + //priority edge cases + if(higher(d, dd)){ + flip = true; + } + if(similar(db, dd) && !similar(d, ddf) && !higher(d, dd)){ + flip = true; + } +// if(!higher(d, dd)){ +// return vec4(1.0); +// flip = true; +// } + } + + if(flip){ + dist = _lineWidth-distToLine(point, center+vec2(0.0, -0.5+1.0)*pointDir, center+vec2(-1.0, 1.5+1.0)*pointDir, -pointDir); //midpoints of neighbor two-pixel groupings + } else { + dist = distToLine(point, center+vec2(1.0, -0.5+1.0)*pointDir, center+vec2(0.0, 1.5+1.0)*pointDir, pointDir); //midpoints of neighbor two-pixel groupings + } + dist -= (_lineWidth/2.0); + return dist <= 0.0 ? ((cd(d,df) <= cd(d,dd)) ? df : dd) : vec4(-1.0); + } + #endif + return vec4(-1.0); +} + +float round(float val) { return fract(val) > 0.5? ceil(val) : floor(val); } +vec2 round(vec2 vec) { return vec2(round(vec.x), round(vec.y)); } + +void main() { + vec2 size = dimension + 0.0001; + vec2 px = v_vTexcoord * size / scale; + vec2 local = fract(px); + px = ceil(px); + + vec2 pointDir = round(local) * 2.0 - 1.0; + + //neighbor pixels + //Up, Down, Forward, and Back + //relative to quadrant of current location within pixel + + vec4 uub = texture2D( gm_BaseTexture, (px + vec2(-1.0, -2.0) * pointDir) / size * scale); + vec4 uu = texture2D( gm_BaseTexture, (px + vec2( 0.0, -2.0) * pointDir) / size * scale); + vec4 uuf = texture2D( gm_BaseTexture, (px + vec2( 1.0, -2.0) * pointDir) / size * scale); + + vec4 ubb = texture2D( gm_BaseTexture, (px + vec2(-2.0, -2.0) * pointDir) / size * scale); + vec4 ub = texture2D( gm_BaseTexture, (px + vec2(-1.0, -1.0) * pointDir) / size * scale); + vec4 u = texture2D( gm_BaseTexture, (px + vec2( 0.0, -1.0) * pointDir) / size * scale); + vec4 uf = texture2D( gm_BaseTexture, (px + vec2( 1.0, -1.0) * pointDir) / size * scale); + vec4 uff = texture2D( gm_BaseTexture, (px + vec2( 2.0, -1.0) * pointDir) / size * scale); + + vec4 bb = texture2D( gm_BaseTexture, (px + vec2(-2.0, 0.0) * pointDir) / size * scale); + vec4 b = texture2D( gm_BaseTexture, (px + vec2(-1.0, 0.0) * pointDir) / size * scale); + vec4 c = texture2D( gm_BaseTexture, (px + vec2( 0.0, 0.0) * pointDir) / size * scale); + vec4 f = texture2D( gm_BaseTexture, (px + vec2( 1.0, 0.0) * pointDir) / size * scale); + vec4 ff = texture2D( gm_BaseTexture, (px + vec2( 2.0, 0.0) * pointDir) / size * scale); + + vec4 dbb = texture2D( gm_BaseTexture, (px + vec2(-2.0, 1.0) * pointDir) / size * scale); + vec4 db = texture2D( gm_BaseTexture, (px + vec2(-1.0, 1.0) * pointDir) / size * scale); + vec4 d = texture2D( gm_BaseTexture, (px + vec2( 0.0, 1.0) * pointDir) / size * scale); + vec4 df = texture2D( gm_BaseTexture, (px + vec2( 1.0, 1.0) * pointDir) / size * scale); + vec4 dff = texture2D( gm_BaseTexture, (px + vec2( 2.0, 1.0) * pointDir) / size * scale); + + vec4 ddb = texture2D( gm_BaseTexture, (px + vec2(-1.0, 2.0) * pointDir) / size * scale); + vec4 dd = texture2D( gm_BaseTexture, (px + vec2( 0.0, 2.0) * pointDir) / size * scale); + vec4 ddf = texture2D( gm_BaseTexture, (px + vec2( 1.0, 2.0) * pointDir) / size * scale); + + vec4 col = c; + + //c_orner, b_ack, and u_p slices + // (slices from neighbor pixels will only ever reach these 3 quadrants + vec4 c_col = sliceDist(local, vec2( 1.0, 1.0), pointDir, u, uf, uff, b, c, f, ff, db, d, df, dff, ddb, dd, ddf); + vec4 b_col = sliceDist(local, vec2(-1.0, 1.0), pointDir, u, ub, ubb, f, c, b, bb, df, d, db, dbb, ddf, dd, ddb); + vec4 u_col = sliceDist(local, vec2( 1.0, -1.0), pointDir, d, df, dff, b, c, f, ff, ub, u, uf, uff, uub, uu, uuf); + + if(c_col.r >= 0.0) col = c_col; + if(b_col.r >= 0.0) col = b_col; + if(u_col.r >= 0.0) col = u_col; + + gl_FragColor = col; +} \ No newline at end of file diff --git a/shaders/sh_scale_cleanedge/sh_scale_cleanedge.vsh b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.vsh new file mode 100644 index 000000000..3900c20f4 --- /dev/null +++ b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.vsh @@ -0,0 +1,19 @@ +// +// Simple passthrough vertex shader +// +attribute vec3 in_Position; // (x,y,z) +//attribute vec3 in_Normal; // (x,y,z) unused in this shader. +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; +} diff --git a/shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy new file mode 100644 index 000000000..33248b0d8 --- /dev/null +++ b/shaders/sh_scale_cleanedge/sh_scale_cleanedge.yy @@ -0,0 +1,12 @@ +{ + "$GMShader":"", + "%Name":"sh_scale_cleanedge", + "name":"sh_scale_cleanedge", + "parent":{ + "name":"filter", + "path":"folders/shader/filter.yy", + }, + "resourceType":"GMShader", + "resourceVersion":"2.0", + "type":1, +} \ No newline at end of file