├── README.md └── complexvisual.glsl /README.md: -------------------------------------------------------------------------------- 1 | # glsl-util 2 | 3 | A mixed bag of glsl functions covering: 4 | - Color blending/compositing, plus blend mode interpolation 5 | - Complex number operators 6 | - Complex plane transforms and transform interpolation 7 | - Procedural texture generation 8 | 9 | Originally this was an all-in-one shader for an old app I worked on as a glsl beginner, but now just placed here because it contains some useful functions. 10 | 11 | -------------------------------------------------------------------------------- /complexvisual.glsl: -------------------------------------------------------------------------------- 1 | #define PI 3.14159265 2 | #define TWOPI (2.0*PI) 3 | 4 | /* 5 | ** Float blending modes 6 | ** Adapted from here: http://www.nathanm.com/photoshop-blending-math/ 7 | ** But I modified the HardMix (wrong condition), Overlay, SoftLight, ColorDodge, ColorBurn, VividLight, PinLight (inverted layers) ones to have correct results 8 | */ 9 | #define BlendLinearDodgef BlendAddf 10 | #define BlendLinearBurnf BlendSubtractf 11 | #define BlendAddf(base, blend) min(base + blend, 1.0) 12 | #define BlendSubtractf(base, blend) max(base + blend - 1.0, 0.0) 13 | #define BlendLightenf(base, blend) max(blend, base) 14 | #define BlendDarkenf(base, blend) min(blend, base) 15 | #define BlendLinearLightf(base, blend) (blend < 0.5 ? BlendLinearBurnf(base, (2.0 * blend)) : BlendLinearDodgef(base, (2.0 * (blend - 0.5)))) 16 | #define BlendScreenf(base, blend) (1.0 - ((1.0 - base) * (1.0 - blend))) 17 | #define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))) 18 | #define BlendSoftLightf(base, blend) ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend))) 19 | #define BlendColorDodgef(base, blend) ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0)) 20 | #define BlendColorBurnf(base, blend) ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0)) 21 | #define BlendVividLightf(base, blend) ((blend < 0.5) ? BlendColorBurnf(base, (2.0 * blend)) : BlendColorDodgef(base, (2.0 * (blend - 0.5)))) 22 | #define BlendPinLightf(base, blend) ((blend < 0.5) ? BlendDarkenf(base, (2.0 * blend)) : BlendLightenf(base, (2.0 *(blend - 0.5)))) 23 | #define BlendHardMixf(base, blend) ((BlendVividLightf(base, blend) < 0.5) ? 0.0 : 1.0) 24 | #define BlendReflectf(base, blend) ((blend == 1.0) ? blend : min(base * base / (1.0 - blend), 1.0)) 25 | 26 | /* 27 | ** Vector3 blending modes 28 | */ 29 | 30 | // Component wise blending 31 | #define Blend(base, blend, funcf) vec3(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b)) 32 | 33 | #define BlendNormal(base, blend) (blend) 34 | #define BlendLighten BlendLightenf 35 | #define BlendDarken BlendDarkenf 36 | #define BlendMultiply(base, blend) (base * blend) 37 | #define BlendAverage(base, blend) ((base + blend) / 2.0) 38 | #define BlendAdd(base, blend) min(base + blend, vec3(1.0)) 39 | #define BlendSubtract(base, blend) max(base + blend - vec3(1.0), vec3(0.0)) 40 | #define BlendDifference(base, blend) abs(base - blend) 41 | #define BlendNegation(base, blend) (vec3(1.0) - abs(vec3(1.0) - base - blend)) 42 | #define BlendExclusion(base, blend) (base + blend - 2.0 * base * blend) 43 | #define BlendScreen(base, blend) Blend(base, blend, BlendScreenf) 44 | #define BlendOverlay(base, blend) Blend(base, blend, BlendOverlayf) 45 | #define BlendSoftLight(base, blend) Blend(base, blend, BlendSoftLightf) 46 | #define BlendHardLight(base, blend) BlendOverlay(blend, base) 47 | #define BlendColorDodge(base, blend) Blend(base, blend, BlendColorDodgef) 48 | #define BlendColorBurn(base, blend) Blend(base, blend, BlendColorBurnf) 49 | #define BlendLinearDodge BlendAdd 50 | #define BlendLinearBurn BlendSubtract 51 | // Linear Light is another contrast-increasing mode 52 | // If the blend color is darker than midgray, Linear Light darkens the image by decreasing the brightness. If the blend color is lighter than midgray, the result is a brighter image due to increased brightness. 53 | #define BlendLinearLight(base, blend) Blend(base, blend, BlendLinearLightf) 54 | #define BlendVividLight(base, blend) Blend(base, blend, BlendVividLightf) 55 | #define BlendPinLight(base, blend) Blend(base, blend, BlendPinLightf) 56 | #define BlendHardMix(base, blend) Blend(base, blend, BlendHardMixf) 57 | #define BlendReflect(base, blend) Blend(base, blend, BlendReflectf) 58 | #define BlendGlow(base, blend) BlendReflect(blend, base) 59 | #define BlendPhoenix(base, blend) (min(base, blend) - max(base, blend) + vec3(1.0)) 60 | #define BlendOpacity(base, blend, F, O) (F(base, blend) * O + base * (1.0 - O)) 61 | 62 | #define NUM_BLENDMODES 25 63 | 64 | 65 | int transform_sequence_ids[10]; 66 | 67 | float HueToRGB(float f1, float f2, float hue) { 68 | if (hue < 0.0) 69 | hue += 1.0; 70 | else if (hue > 1.0) 71 | hue -= 1.0; 72 | float res; 73 | if ((6.0 * hue) < 1.0) 74 | res = f1 + (f2 - f1) * 6.0 * hue; 75 | else if ((2.0 * hue) < 1.0) 76 | res = f2; 77 | else if ((3.0 * hue) < 2.0) 78 | res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; 79 | else 80 | res = f1; 81 | return res; 82 | } 83 | 84 | vec3 HSLToRGB(vec3 hsl) { 85 | vec3 rgb; 86 | 87 | if (hsl.y == 0.0) 88 | rgb = vec3(hsl.z); // Luminance 89 | else 90 | { 91 | float f2; 92 | 93 | if (hsl.z < 0.5) 94 | f2 = hsl.z * (1.0 + hsl.y); 95 | else 96 | f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z); 97 | 98 | float f1 = 2.0 * hsl.z - f2; 99 | 100 | rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0)); 101 | rgb.g = HueToRGB(f1, f2, hsl.x); 102 | rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0)); 103 | } 104 | 105 | return rgb; 106 | } 107 | 108 | vec3 blend_any_opacity(vec3 base, vec3 blend, int mode, float opacity) { 109 | if (mode==0) return BlendOpacity(base, blend, BlendNormal, opacity); 110 | else if(mode==1) return BlendOpacity(base,blend, BlendLighten, opacity); 111 | else if(mode==2) return BlendOpacity(base,blend, BlendDarken, opacity); 112 | else if(mode==3) return BlendOpacity(base, blend, BlendMultiply, opacity); 113 | else if(mode==4) return BlendOpacity(base, blend, BlendAverage, opacity); 114 | else if(mode==5) return BlendOpacity(base, blend, BlendAdd, opacity); 115 | else if(mode==6) return BlendOpacity(base, blend, BlendSubtract, opacity); 116 | else if(mode==7) return BlendOpacity(base, blend, BlendDifference, opacity); 117 | else if(mode==8) return BlendOpacity(base, blend, BlendNegation, opacity); 118 | else if(mode==9) return BlendOpacity(base, blend, BlendExclusion, opacity); 119 | else if(mode==10) return BlendOpacity(base, blend, BlendScreen, opacity); 120 | else if(mode==11) return BlendOpacity(base, blend, BlendOverlay, opacity); 121 | else if(mode==12) return BlendOpacity(base, blend, BlendSoftLight, opacity); 122 | else if(mode==13) return BlendOpacity(base, blend, BlendHardLight, opacity); 123 | else if(mode==14) return BlendOpacity(base, blend, BlendColorDodge, opacity); 124 | else if(mode==15) return BlendOpacity(base, blend, BlendColorBurn, opacity); 125 | else if(mode==16) return BlendOpacity(base, blend, BlendLinearDodge, opacity); 126 | else if(mode==17) return BlendOpacity(base, blend, BlendLinearBurn, opacity); 127 | else if(mode==18) return BlendOpacity(base, blend, BlendLinearLight, opacity); 128 | else if(mode==19) return BlendOpacity(base, blend, BlendVividLight, opacity); 129 | else if(mode==20) return BlendOpacity(base, blend, BlendPinLight, opacity); 130 | else if(mode==21) return BlendOpacity(base, blend, BlendHardMix, opacity); 131 | else if(mode==22) return BlendOpacity(base, blend, BlendReflect, opacity); 132 | else if(mode==23) return BlendOpacity(base, blend, BlendGlow, opacity); 133 | else if(mode==24) return BlendOpacity(base, blend, BlendPhoenix, opacity); 134 | else return vec3(1,0,0); 135 | } 136 | 137 | vec3 lerp_blendmode(vec3 base, vec3 blend, float opacity1, float opacity2, int mode1, int mode2, float t) { 138 | vec3 b1 = blend_any_opacity(base, blend, mode1, opacity1); 139 | vec3 b2 = blend_any_opacity(base, blend, mode2, opacity2); 140 | return mix(b1, b2, fract(t)); 141 | } 142 | 143 | vec3 blend_lerper(vec3 c1, vec3 c2, float o1, float o2, int blendmode_offset, float t) { 144 | int m1 = (blendmode_offset+int(t)) % NUM_BLENDMODES; 145 | int m2 = (m1+1) % NUM_BLENDMODES; 146 | return lerp_blendmode(c1, c2, o1, o2, m1, m2, t); 147 | } 148 | 149 | uniform float FrameCount; 150 | uniform float AnimateTime; 151 | uniform vec2 MousePos; 152 | uniform float Zoom; 153 | uniform float MaxIterations; 154 | 155 | uniform float LineWidth; 156 | uniform float JitterRadius; 157 | 158 | uniform float LayerBlendMode0; // should be int... lazy 159 | uniform float LayerBlendMode1; // should be int... lazy 160 | uniform float LayerBlendMode2; 161 | uniform float LayerBlendMode3; 162 | uniform float LayerBlendMode4; 163 | uniform float LayerBlendMode5; 164 | uniform float LayerBlendMode6; 165 | uniform float LayerBlendMode7; 166 | uniform float LayerOpacity0; 167 | uniform float LayerOpacity1; 168 | uniform float LayerOpacity2; 169 | uniform float LayerOpacity3; 170 | uniform float LayerOpacity4; 171 | uniform float LayerOpacity5; 172 | uniform float LayerOpacity6; 173 | uniform float LayerOpacity7; 174 | uniform float BlendmodeInterpolator; 175 | uniform float BlendmodeLerpSpeed; 176 | 177 | uniform float TransformSqrt; 178 | uniform float TransformLogOfZ; 179 | uniform float TransformSqrtOfZ; 180 | uniform float TransformInverse; // bool 181 | uniform float TransformMobius; // bool 182 | uniform float TransformZPlusOneOverZ; 183 | uniform float TransformSinOfZ; 184 | uniform float TransformTanOfZ; 185 | uniform float TransformZSquaredPlusC; 186 | uniform float TransformSinOfOneOverZ; 187 | 188 | uniform float TransformInterpolator; 189 | uniform float TransformLerpSpeed; 190 | 191 | uniform float NumTransformIterations; 192 | 193 | uniform vec4 BackgroundColor; 194 | uniform float LayerGridVisible; 195 | uniform float LayerMandelbrotVisible; 196 | uniform float LayerIntCirclesVisible; 197 | uniform float LayerHSBMapVisible; 198 | uniform float LayerImageVisible; 199 | uniform float LayerCheckerVisible; 200 | uniform float LayerCoordDotsVisible; 201 | uniform float LayerNoiseVisible; 202 | uniform float HSBMapAngleOffset; 203 | uniform float TextureRepeat; 204 | uniform sampler2D CurrentTexture; 205 | 206 | 207 | 208 | float cosine_lerp(float y1,float y2, float mu) { 209 | float mu2 = (1.0-cos(mu*PI))* 0.5; 210 | return(y1*(1.0-mu2)+y2*mu2); 211 | } 212 | 213 | /** 214 | * 215 | * Complex math functions 216 | * 217 | ((a.x*a.x)+(a.y*a.y)) 218 | */ 219 | 220 | 221 | #define cx_add(a, b) vec2(a.x + b.x, a.y + b.y) 222 | #define cx_sub(a, b) vec2(a.x - b.x, a.y - b.y) 223 | #define cx_mul(a, b) vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x) 224 | #define cx_div(a, b) vec2(((a.x*b.x+a.y*b.y)/(b.x*b.x+b.y*b.y)),((a.y*b.x-a.x*b.y)/(b.x*b.x+b.y*b.y))) 225 | #define cx_modulus(a) length(a) 226 | #define cx_conj(a) vec2(a.x,-a.y) 227 | #define cx_arg(a) atan2(a.y,a.x) 228 | #define cx_sin(a) vec2(sin(a.x) * cosh(a.y), cos(a.x) * sinh(a.y)) 229 | #define cx_cos(a) vec2(cos(a.x) * cosh(a.y), -sin(a.x) * sinh(a.y)) 230 | 231 | vec2 cx_to_polar(vec2 a) { 232 | float phi = atan(a.x, a.y); 233 | float r = sqrt(a.x * a.x + a.y * a.y); 234 | return vec2(r, phi); 235 | } 236 | 237 | vec2 cx_sqrt(vec2 a) { 238 | float r = sqrt(a.x*a.x+a.y*a.y); 239 | float rpart = sqrt(0.5*(r+a.x)); 240 | float ipart = sqrt(0.5*(r-a.x)); 241 | if (a.y < 0.0) ipart = -ipart; 242 | return vec2(rpart,ipart); 243 | } 244 | 245 | vec2 cx_tan(vec2 a) {return cx_div(cx_sin(a), cx_cos(a)); } 246 | 247 | vec2 cx_log(vec2 a) { 248 | float rpart = sqrt((a.x*a.x)+(a.y*a.y)); 249 | float ipart = atan2(a.y,a.x); 250 | if (ipart > PI) ipart=ipart-(2.0*PI); 251 | return vec2(log(rpart),ipart); 252 | } 253 | 254 | vec2 cx_mobius(vec2 a) { 255 | vec2 c1 = a - vec2(1.0,0.0); 256 | vec2 c2 = a + vec2(1.0,0.0); 257 | return cx_div(c1, c2); 258 | } 259 | 260 | vec2 cx_z_plus_one_over_z(vec2 a) { 261 | return a + cx_div(vec2(1.0,0.0), a); 262 | } 263 | 264 | vec2 cx_z_squared_plus_c(vec2 z, vec2 c) { 265 | return cx_mul(z, z) + c; 266 | } 267 | 268 | vec2 cx_sin_of_one_over_z(vec2 z) { 269 | return cx_sin(cx_div(vec2(1.0,0.0), z)); 270 | } 271 | 272 | 273 | 274 | #define TransformID_Identity 0 275 | #define TransformID_Inverse 1 276 | #define TransformID_Mobius 2 277 | #define TransformID_ZPlusOneOverZ 3 278 | #define TransformID_SinOfZ 4 279 | #define TransformID_TanOfZ 5 280 | #define TransformID_ZSquaredPlusC 6 281 | #define TransformID_SinOfOneOverZ 7 282 | #define TransformID_Sqrt 8 283 | #define TransformID_Log 9 284 | #define NUM_TRANSFORM_IDS 8 285 | 286 | vec2 cx_transform_by_id(int txid, vec2 a) { 287 | if (txid == TransformID_Identity) return a; 288 | if (txid == TransformID_Inverse) return cx_inv(a); 289 | if (txid == TransformID_Mobius) return cx_mobius(a); 290 | if (txid == TransformID_Sqrt) return cx_sqrt(a); 291 | if (txid == TransformID_Log) return cx_log(a); 292 | if (txid == TransformID_ZPlusOneOverZ) return cx_z_plus_one_over_z(a); 293 | if (txid == TransformID_SinOfZ) return cx_sin(a); 294 | if (txid == TransformID_TanOfZ) return cx_tan(a); 295 | if (txid == TransformID_ZSquaredPlusC) return cx_z_squared_plus_c(a, MousePos); 296 | if (txid == TransformID_SinOfOneOverZ) return cx_sin_of_one_over_z(a); 297 | } 298 | 299 | vec2 cx_transform_lerper(vec2 a, float t) { 300 | int num_transforms = 9; 301 | vec2 a1,a2; 302 | 303 | int tx1 = int(t) % NUM_TRANSFORM_IDS; 304 | int tx2 = (tx1+1) % NUM_TRANSFORM_IDS; 305 | a1 = cx_transform_by_id(tx1, a); 306 | a2 = cx_transform_by_id(tx2, a); 307 | return vec2(cosine_lerp(a1.x,a2.x,fract(t)), cosine_lerp(a1.y,a2.y, fract(t))); 308 | } 309 | 310 | 311 | 312 | //vec2 jitter(vec2 c) { return c + noise2(c) * JitterRadius; } 313 | // END Complex math functions 314 | 315 | float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);} 316 | 317 | vec2 jitter(vec2 c) { 318 | float xoff = ((rand(vec2(c.x,c.y))*2.0) -1.0) * JitterRadius; // * Zoom; 319 | float yoff = ((rand(vec2(c.y,c.x))*2.0) -1.0) * JitterRadius; // * Zoom; 320 | //vec2 n = noise2(ctmp); 321 | return (c + vec2(xoff,yoff)); 322 | } 323 | 324 | 325 | 326 | // 327 | // Noise 328 | vec4 rand(vec2 A,vec2 B,vec2 C,vec2 D){ 329 | vec2 s=vec2(12.9898,78.233); 330 | vec4 tmp=vec4(dot(A,s),dot(B,s),dot(C,s),dot(D,s)); 331 | return fract(sin(tmp) * 43758.5453)* 2.0 - 1.0; 332 | } 333 | 334 | float noise(vec2 coord,float d){ 335 | vec2 C[4]; 336 | float d1 = 1.0/d; 337 | C[0]=floor(coord*d)*d1; 338 | C[1]=C[0]+vec2(d1,0.0); 339 | C[2]=C[0]+vec2(d1,d1); 340 | C[3]=C[0]+vec2(0.0,d1); 341 | vec2 p=fract(coord*d); 342 | vec2 q=1.0-p; 343 | vec4 w=vec4(q.x*q.y,p.x*q.y,p.x*p.y,q.x*p.y); 344 | return dot(vec4(rand(C[0],C[1],C[2],C[3])),w); 345 | } 346 | 347 | vec4 get_noise_color(vec2 a) { 348 | float level= -log2(min(length(dFdx(a)),length(dFdy(a)))); 349 | level = min(level,13.0); //limit the level to avoid slowness 350 | float n = 0.5; 351 | for(int i = 3; i< int(level);i++){ //3 is the lowest noise level 352 | n += 0.12 * noise(a, exp2(float(i))); 353 | } 354 | return vec4(n,n,n,n); 355 | } 356 | 357 | 358 | // End Noise 359 | // 360 | 361 | 362 | float get_smooth_branch_factor(float u, float v) { 363 | float fmult = 2.0; // frequency multiplyer 364 | u = clamp(u,0.0,1.0); 365 | v = clamp(v,0.0,1.0); 366 | float a = 0.5 + (0.5 * -cos(u*fmult * (2.0*PI))); 367 | float b = 0.5 + (0.5 * -cos((u*2.0*fmult)*(2.0*PI))); 368 | return (a+((b-a)*v)); // lerp (a,b,v) 369 | } 370 | 371 | vec4 mandelbrot(vec2 z) { 372 | float real = z.x; // gl_TexCoord[0].s * Zoom + Position.x; 373 | float imag = z.y; //gl_TexCoord[0].t * Zoom + Position.y; 374 | float Creal = real; // Change this line... 375 | float Cimag = imag; // ...and this one to get a Julia set 376 | 377 | float r2 = 0.0; 378 | float iter; 379 | 380 | for (iter = 0.0; iter < MaxIterations && r2 < 16.0; ++iter) { 381 | float tempreal = real; 382 | real = (tempreal * tempreal) - (imag * imag) + Creal; 383 | imag = 2.0 * tempreal * imag + Cimag; 384 | r2 = (real * real) + (imag * imag); 385 | } 386 | 387 | if(r2 < 16.0) { 388 | return vec4(0.0,0.0,0.0,1.0); 389 | } 390 | 391 | 392 | float modulus = sqrt(r2); //sqrt (ReZ*ReZ + ImZ*ImZ); 393 | float mu = iter - (log (log (modulus)))/ log (2.0); 394 | 395 | mu += 0.5; 396 | float lo_boundary=0.0; 397 | float nearest_boundary = round(mu); 398 | if (nearest_boundary < mu) { 399 | lo_boundary = nearest_boundary; 400 | } 401 | else { 402 | lo_boundary = nearest_boundary - 1.0; 403 | } 404 | mu -= lo_boundary; 405 | 406 | float arg = atan2(imag,real); 407 | arg = ((arg + PI) / (2.0* PI)); 408 | 409 | 410 | // smooth branch shading 411 | float sbf = get_smooth_branch_factor(arg, mu); 412 | return vec4(sbf,sbf,sbf,sbf); 413 | 414 | // Base the color on the number of iterations 415 | /* 416 | vec3 color; 417 | if (r2 < 4.0) 418 | color = InnerColor; 419 | else 420 | color = mix(OuterColor1, OuterColor2, fract(iter * 0.05)); 421 | 422 | return vec4 (clamp(color, 0.0, 1.0), 1.0); 423 | */ 424 | } 425 | 426 | 427 | 428 | 429 | 430 | vec4 get_grid_pixel_color(vec2 c) { 431 | int grid_pixel = 0; 432 | float bri=0.; 433 | int val = 0; 434 | vec4 linecolor = vec4(1.0, 1.0, 1.0, 1.0); 435 | vec4 bgcolor = vec4(0.0,0.0,0.0,0.0); 436 | vec2 nearest_int = vec2(abs(c.x - round(c.x)), abs(c.y - round(c.y))); 437 | 438 | if ((nearest_int.x < LineWidth) && (nearest_int.y < LineWidth)) { // line intersection 439 | bri = 2.0 - (nearest_int.x+nearest_int.y) / LineWidth; // better 440 | return linecolor * bri; 441 | } 442 | else if ((nearest_int.x < LineWidth) || (nearest_int.y < LineWidth)) { 443 | if (nearest_int.x < LineWidth) { 444 | bri = ((1.-nearest_int.x/(LineWidth))); 445 | return linecolor * bri; 446 | } 447 | else if (nearest_int.y < LineWidth) { 448 | bri = ((1.-nearest_int.y/(LineWidth))); 449 | return linecolor * bri; 450 | } 451 | } 452 | else { 453 | linecolor = bgcolor; 454 | } 455 | return linecolor; 456 | } 457 | 458 | 459 | vec4 get_coord_dot_color(vec2 c, vec2 coord, vec3 dotcolor) { 460 | float rad = 0.3; 461 | float dist = distance(c, coord); 462 | float a = (dist= -1.0 && c.x <= 1.0 && c.y >= -1.0 && c.y <= 1.0) { 554 | color = vec4(blend_any_opacity(color.rgb, px_image.rgb, int(LayerBlendMode1), LayerOpacity1*px_image.a), 1.0); 555 | } 556 | } 557 | else { 558 | if (BlendmodeInterpolator == 1.0) { 559 | color = vec4(blend_lerper(color.rgb, px_image.rgb, LayerOpacity1, LayerOpacity1, int(LayerBlendMode1), blendtime), 1.0); 560 | } 561 | else { 562 | color = vec4(blend_any_opacity(color.rgb, px_image.rgb, int(LayerBlendMode1), LayerOpacity1*px_image.a), 1.0); 563 | } 564 | } 565 | } 566 | if (LayerCheckerVisible == 1.0) { 567 | vec4 px_checker = get_checkerboard_color(c); 568 | color = vec4(blend_any_opacity(color.rgb, px_checker.rgb, int(LayerBlendMode2), LayerOpacity2*px_checker.a), 1.0); 569 | } 570 | if (LayerGridVisible == 1.0) { 571 | vec4 px_grid = get_grid_pixel_color(c); 572 | if (BlendmodeInterpolator == 1.0) { 573 | color = vec4(blend_lerper(color.rgb, px_grid.rgb, LayerOpacity3, LayerOpacity3, int(LayerBlendMode3), blendtime), 1.0); 574 | } 575 | else { 576 | color = vec4(blend_any_opacity(color.rgb, px_grid.rgb, int(LayerBlendMode3), LayerOpacity3), 1.0); 577 | } 578 | } 579 | if (LayerIntCirclesVisible == 1.0) { 580 | vec4 px_intcircles = get_integer_circles_color(c); 581 | if (BlendmodeInterpolator == 1.0) { 582 | color = vec4(blend_lerper(color.rgb, px_intcircles.rgb, LayerOpacity4, LayerOpacity4, int(LayerBlendMode4), blendtime), 1.0); 583 | } 584 | else { 585 | color = vec4(blend_any_opacity(color.rgb, px_intcircles.rgb, int(LayerBlendMode4), LayerOpacity4), 1.0); 586 | } 587 | } 588 | if (LayerMandelbrotVisible == 1.0) { 589 | vec4 px_mandel = mandelbrot(c); 590 | if (BlendmodeInterpolator == 1.0) { 591 | color = vec4(blend_lerper(color.rgb, px_mandel.rgb, LayerOpacity5, LayerOpacity5, int(LayerBlendMode5), blendtime), 1.0); 592 | } 593 | else { 594 | color = vec4(blend_any_opacity(color.rgb, px_mandel.rgb, int(LayerBlendMode5), LayerOpacity5*px_mandel.a), 1.0); 595 | } 596 | } 597 | if (LayerNoiseVisible == 1.0) { 598 | vec4 px_noise = get_noise_color(c); 599 | if (BlendmodeInterpolator == 1.0) { 600 | color = vec4(blend_lerper(color.rgb, px_noise.rgb, LayerOpacity7, LayerOpacity7, int(LayerBlendMode7), blendtime), 1.0); 601 | } 602 | else { 603 | color = vec4(blend_any_opacity(color.rgb, px_noise.rgb, int(LayerBlendMode7), LayerOpacity7), 1.0); 604 | } 605 | } 606 | 607 | // test local space scaling metric 608 | if (LayerCoordDotsVisible == 1.0) { 609 | float s1 = get_local_space_scale_factor3(c_untransformed, c); 610 | 611 | float spscale = s1; // clamp(s1, 0.0,1.0); 612 | 613 | vec4 px_scalespace = vec4(spscale, spscale,spscale,spscale); 614 | 615 | color = vec4(blend_any_opacity(color.rgb, px_scalespace.rgb, int(LayerBlendMode6), LayerOpacity6), 1.0); 616 | } 617 | 618 | 619 | // implement wrapmode=background here 620 | // ... 621 | gl_FragColor = color; 622 | } 623 | 624 | 625 | --------------------------------------------------------------------------------