/*{ "CATEGORIES": [ "Distortion Effect" ], "CREDIT": "VIDVOX", "DESCRIPTION": "Wraps an image into a shape that is created by morphing two primitive shapes together", "INPUTS": [ { "NAME": "inputImage", "TYPE": "image" }, { "DEFAULT": 0.5, "MAX": 1, "MIN": 0, "NAME": "mixPoint", "TYPE": "float" }, { "DEFAULT": 0, "LABELS": [ "Circle", "Triangle", "Rect", "Pentagram", "Hexagon", "Star1", "Star2", "Heart", "Rays" ], "NAME": "shape1", "TYPE": "long", "VALUES": [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] }, { "DEFAULT": 1, "LABELS": [ "Circle", "Triangle", "Rect", "Pentagram", "Hexagon", "Star1", "Star2", "Heart", "Rays" ], "NAME": "shape2", "TYPE": "long", "VALUES": [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] }, { "DEFAULT": 0, "MAX": 2, "MIN": 0, "NAME": "shapeWobble", "TYPE": "float" }, { "DEFAULT": 0, "MAX": 1, "MIN": 0, "NAME": "preRotateAngle", "TYPE": "float" }, { "DEFAULT": 0.75, "MAX": 1, "MIN": 0, "NAME": "angleShift", "TYPE": "float" }, { "DEFAULT": 0, "LABELS": [ "None", "Extend", "Repeat", "Reflect" ], "NAME": "repeatStyle", "TYPE": "long", "VALUES": [ 0, 1, 2, 3 ] }, { "DEFAULT": 0, "MAX": 1, "MIN": 0, "NAME": "repeatDecay", "TYPE": "float" }, { "DEFAULT": 1, "MAX": 1, "MIN": 0, "NAME": "resultSize", "TYPE": "float" }, { "DEFAULT": 1, "MAX": 2, "MIN": 0, "NAME": "resultWidth", "TYPE": "float" }, { "DEFAULT": 0.5, "MAX": 1, "MIN": 0, "NAME": "resultAngle", "TYPE": "float" }, { "DEFAULT": [ 0.5, 0.5 ], "MAX": [ 1, 1 ], "MIN": [ 0, 0 ], "NAME": "resultCenter", "TYPE": "point2D" }, { "DEFAULT": 1, "NAME": "mirrorX", "TYPE": "bool" }, { "DEFAULT": 0, "NAME": "mirrorY", "TYPE": "bool" } ], "ISFVSN": "2", "VSN": "1" } */ const float pi = 3.1415926535897932384626433832795; const float tau = 6.2831853071795864769252867665590; vec2 rotatePoint(vec2 pt, float rot) { vec2 returnMe = pt * RENDERSIZE; float r = distance(RENDERSIZE/2.0, returnMe); float a = atan ((returnMe.y-RENDERSIZE.y/2.0),(returnMe.x-RENDERSIZE.x/2.0)); returnMe.x = r * cos(a + 2.0 * pi * rot - pi) + 0.5; returnMe.y = r * sin(a + 2.0 * pi * rot - pi) + 0.5; returnMe = returnMe / RENDERSIZE + vec2(0.5); return returnMe; } vec2 rotatePointNorm(vec2 pt, float rot) { vec2 returnMe = pt; float r = distance(vec2(0.50), returnMe); float a = atan((returnMe.y-0.5),(returnMe.x-0.5)); returnMe.x = r * cos(a + 2.0 * pi * rot - pi) + 0.5; returnMe.y = r * sin(a + 2.0 * pi * rot - pi) + 0.5; returnMe = returnMe; return returnMe; } vec2 rotatePointNormPt(vec2 pt, float rot, vec2 rpt) { vec2 returnMe = pt; float r = distance(vec2(0.50), returnMe); float a = atan((returnMe.y-rpt.y),(returnMe.x-rpt.x)); returnMe.x = r * cos(a + 2.0 * pi * rot - pi) + rpt.x; returnMe.y = r * sin(a + 2.0 * pi * rot - pi) + rpt.y; returnMe = returnMe; return returnMe; } // borrowed from pixel spirit deck! // https://github.com/patriciogonzalezvivo/PixelSpiritDeck/tree/master/lib float triSDF(vec2 st) { st = (st*2.-1.)*2.; return max(abs(st.x) * 0.866025 + st.y * 0.5, -st.y * 0.5); } float circleSDF(vec2 st) { return length(st-.5)*2.; } float polySDF(vec2 st, int V) { st = st*2.-1.; float a = atan(st.x,st.y)+pi; float r = length(st); float v = tau/float(V); return cos(floor(.5+a/v)*v-a)*r; } float pentSDF(vec2 st) { vec2 pt = st; pt.y /= 0.89217; return polySDF(pt, 5); } float hexSDF(vec2 st) { st = abs(st*2.-1.); return max(abs(st.y), st.x * 0.866025 + st.y * 0.5); } float flowerSDF(vec2 st, int N) { st = st*2.-1.; float r = length(st)*2.; float a = atan(st.y,st.x); float v = float(N)*.5; return 1.-(abs(cos(a*v))*.5+.5)/r; } float heartSDF(vec2 st) { st -= vec2(.5,.8); float r = length(st)*5.5; st = normalize(st); return r - ((st.y*pow(abs(st.x),0.67))/ (st.y+1.5)-(2.)*st.y+1.26); } float starSDF(vec2 st, int V, float s) { st = st*4.-2.; float a = atan(st.y, st.x)/tau; float seg = a * float(V); a = ((floor(seg) + 0.5)/float(V) + mix(s,-s,step(.5,fract(seg)))) * tau; return abs(dot(vec2(cos(a),sin(a)), st)); } float raysSDF(vec2 st, int N) { st -= .5; return fract(atan(st.y,st.x)/tau*float(N)); } float shapeForType(vec2 st, int shape) { if (shape == 0) return circleSDF(st); else if (shape == 1) return triSDF(st); else if (shape == 2) return polySDF(st,4); else if (shape == 3) return pentSDF(st); else if (shape == 4) return hexSDF(st); else if (shape == 5) return starSDF(st,5,0.07); else if (shape == 6) return starSDF(st,12,0.12); else if (shape == 7) return heartSDF(st); else if (shape == 8) return raysSDF(st,6); } void main() { vec4 returnMe = vec4(0.0); vec2 st = gl_FragCoord.xy/RENDERSIZE; st += (0.5 - resultCenter); st = rotatePoint(st,resultAngle); // size st -= 0.5; //st += (0.5 - resultCenter); st /= max(0.000001,resultSize); st.x /= resultWidth; st += 0.5; st = mix(vec2((st.x*RENDERSIZE.x/RENDERSIZE.y)-(RENDERSIZE.x*.5-RENDERSIZE.y*.5)/RENDERSIZE.y,st.y), vec2(st.x,st.y*(RENDERSIZE.y/RENDERSIZE.x)-(RENDERSIZE.y*.5-RENDERSIZE.x*.5)/RENDERSIZE.x), step(RENDERSIZE.x,RENDERSIZE.y)); float val1 = shapeForType(st,shape1); float val2 = shapeForType(st,shape2); //val1 = min(max(val1,0.0),1.0); //val2 = min(max(val2,0.0),1.0); float val = mix(val1,val2,mixPoint); vec2 cnt = vec2(0.5,0.5); float a = (atan(cnt.y-st.y,cnt.x-st.x) + pi) / (tau); val += (shapeWobble == 0.0) ? 0.0 : shapeWobble * ((sin(TIME+10.0*tau*(a)))/13.0 + (sin(-TIME*2.1+17.0*tau*(a)))/17.0 + (sin(19.0*tau*(a)))/19.0); float r = val; if (repeatStyle == 1) r = max(0.0,min(r,1.0)); else if (repeatStyle == 2) r = mod(r,1.0); else if (repeatStyle == 3) { r = mod(r,2.0); r = (r > 1.0) ? 2.0 - r : r; } if (r <= 1.0) { a = mod(a + angleShift, 1.0); vec2 pt = vec2(a,r); //returnMe = vec4(r,a,0.0,1.0); if (mirrorX) { pt.x = (pt.x < 0.5) ? pt.x * 2.0 : 2.0 - pt.x * 2.0; } if (mirrorY) { pt.y = (pt.y < 0.5) ? pt.y * 2.0 : 2.0 - pt.y * 2.0; } pt = rotatePointNorm(pt,preRotateAngle); returnMe = IMG_NORM_PIXEL(inputImage,pt); if (repeatStyle > 0) { if (repeatStyle == 1) returnMe.a *= (val > 1.0) ? 1.0 - repeatDecay * (val) : 1.0; else { float repCount = 1.0 / (1.0+resultSize); returnMe.a *= 1.0 - repeatDecay * floor(val) / repCount; } } } gl_FragColor = returnMe; }