diff --git a/.clang-format b/.clang-format index 07cf790..9bde7d9 100644 --- a/.clang-format +++ b/.clang-format @@ -3,4 +3,5 @@ AlignConsecutiveAssignments: true AlignAfterOpenBracket: Align ContinuationIndentWidth: 2 KeepEmptyLinesAtTheStartOfBlocks: true +SortIncludes: false ColumnLimit: 90 \ No newline at end of file diff --git a/docs/how-to-create-new-effects.md b/docs/how-to-create-new-effects.md index 0194691..c70a883 100644 --- a/docs/how-to-create-new-effects.md +++ b/docs/how-to-create-new-effects.md @@ -239,7 +239,7 @@ if (utils.isInShellProcess()) { // float uProgress: A value which transitions from 0 to 1 during the entire animation. // float uTime: A steadily increasing value in seconds. // vec2 uSize: The size of uTexture in pixels. - ${shaderSnippets.standardUniforms()} + #include "common/uniforms.glsl" // The width of the fading effect is loaded from the settings. uniform float uFadeWidth; diff --git a/resources/shaders/apparition-declarations.glsl b/resources/shaders/apparition-declarations.glsl new file mode 100644 index 0000000..4f7f156 --- /dev/null +++ b/resources/shaders/apparition-declarations.glsl @@ -0,0 +1,13 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" + +uniform vec2 uSeed; +uniform float uShake; +uniform float uTwirl; +uniform float uSuction; +uniform float uRandomness; + +const float ACTOR_SCALE = 2.0; +const float PADDING = ACTOR_SCALE / 2.0 - 0.5; \ No newline at end of file diff --git a/resources/shaders/apparition.glsl b/resources/shaders/apparition.glsl new file mode 100644 index 0000000..7694155 --- /dev/null +++ b/resources/shaders/apparition.glsl @@ -0,0 +1,33 @@ +// The math for the whirling is inspired by this post: +// http://www.geeks3d.com/20110428/shader-library-swirl-post-processing-filter-in-glsl +// We simply inverse the progress for opening windows. +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// Choose a random suction center. +vec2 center = uSeed * uRandomness + 0.5 * (1.0 - uRandomness); +vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - center; + +// Add some shaking. +coords.x += + progress * 0.05 * uShake * sin((progress + uSeed.x) * (1.0 + uSeed.x) * uShake); +coords.y += + progress * 0.05 * uShake * cos((progress + uSeed.y) * (1.0 + uSeed.y) * uShake); + +// "Suck" the texture into the center. +float dist = length(coords) / sqrt(2); +coords += progress * coords / dist * 0.5 * uSuction; + +// Apply some whirling. +float angle = pow(1.0 - dist, 2.0) * uTwirl * progress; +float s = sin(angle); +float c = cos(angle); +coords = vec2(dot(coords, vec2(c, -s)), dot(coords, vec2(s, c))); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +cogl_color_out = texture2D(uTexture, coords + center); +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +// Fade out the window texture. +cogl_color_out.a *= 1.0 - progress; \ No newline at end of file diff --git a/resources/shaders/broken-glass-declarations.glsl b/resources/shaders/broken-glass-declarations.glsl new file mode 100644 index 0000000..3c0836a --- /dev/null +++ b/resources/shaders/broken-glass-declarations.glsl @@ -0,0 +1,15 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" + +uniform sampler2D uShardTexture; +uniform vec2 uSeed; +uniform vec2 uEpicenter; +uniform float uShardScale; +uniform float uBlowForce; +uniform float uGravity; + +const float SHARD_LAYERS = 5; +const float ACTOR_SCALE = 2.0; +const float PADDING = ACTOR_SCALE / 2.0 - 0.5; \ No newline at end of file diff --git a/resources/shaders/broken-glass.glsl b/resources/shaders/broken-glass.glsl new file mode 100644 index 0000000..dccffa1 --- /dev/null +++ b/resources/shaders/broken-glass.glsl @@ -0,0 +1,49 @@ +cogl_color_out = vec4(0, 0, 0, 0); + +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// Draw the individual shard layers. +for (float i = 0; i < SHARD_LAYERS; ++i) { + + // To enable drawing shards outside of the window bounds, the actor was scaled + // by ACTOR_SCALE. Here we scale and move the texture coordinates so that the + // window gets drawn at the correct position again. + vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING; + + // Scale and rotate around our epicenter. + coords -= uEpicenter; + + // Scale each layer a bit differently. + coords /= mix(1.0, 1.0 + uBlowForce * (i + 2) / SHARD_LAYERS, progress); + + // Rotate each layer a bit differently. + float rotation = (mod(i, 2.0) - 0.5) * 0.2 * progress; + coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation), + coords.x * sin(rotation) + coords.y * cos(rotation)); + + // Move down each layer a bit. + float gravity = + (uForOpening ? -1.0 : 1.0) * uGravity * 0.1 * (i + 1) * progress * progress; + coords += vec2(0, gravity); + + // Restore correct position. + coords += uEpicenter; + + // Retrieve information from the shard texture for our layer. + vec2 shardCoords = (coords + uSeed) * uSize / uShardScale / 500.0; + vec2 shardMap = texture2D(uShardTexture, shardCoords).rg; + + // The green channel contains a random value in [0..1] for each shard. We + // discretize this into SHARD_LAYERS bins and check if our layer falls into + // the bin of the current shard. + float shardGroup = floor(shardMap.g * SHARD_LAYERS * 0.999); + + if (shardGroup == i && (shardMap.x - pow(progress + 0.1, 2)) > 0) { + cogl_color_out = texture2D(uTexture, coords); + } +} + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} \ No newline at end of file diff --git a/resources/shaders/common/compositing.glsl b/resources/shaders/common/compositing.glsl new file mode 100644 index 0000000..8222665 --- /dev/null +++ b/resources/shaders/common/compositing.glsl @@ -0,0 +1,6 @@ +// The Shell.GLSLEffect uses straight alpha blending. This helper method allows +// compositing color values in the shader in the same way. +vec4 alphaOver(vec4 under, vec4 over) { + float alpha = over.a + under.a * (1.0 - over.a); + return vec4((over.rgb * over.a + under.rgb * under.a * (1.0 - over.a)) / alpha, alpha); +} \ No newline at end of file diff --git a/resources/shaders/common/edgeMask.glsl b/resources/shaders/common/edgeMask.glsl new file mode 100644 index 0000000..8ad5f08 --- /dev/null +++ b/resources/shaders/common/edgeMask.glsl @@ -0,0 +1,22 @@ +// This method returns a mask which smoothly transitions towards zero when approaching +// the window's borders. There is a variant which takes the transition area width in +// pixels and one which takes this as a percentage. +float getEdgeMask(vec2 uv, vec2 maxUV, float fadeWidth) { + float mask = 1.0; + mask *= smoothstep(0, 1, clamp(uv.x / fadeWidth, 0, 1)); + mask *= smoothstep(0, 1, clamp(uv.y / fadeWidth, 0, 1)); + mask *= smoothstep(0, 1, clamp((maxUV.x - uv.x) / fadeWidth, 0, 1)); + mask *= smoothstep(0, 1, clamp((maxUV.y - uv.y) / fadeWidth, 0, 1)); + + return mask; +} + +float getAbsoluteEdgeMask(float fadePixels) { + vec2 uv = cogl_tex_coord_in[0].st * uSize; + return getEdgeMask(uv, uSize, fadePixels); +} + +float getRelativeEdgeMask(float fadeAmount) { + vec2 uv = cogl_tex_coord_in[0].st; + return getEdgeMask(uv, vec2(1.0), fadeAmount); +} \ No newline at end of file diff --git a/resources/shaders/common/math2D.glsl b/resources/shaders/common/math2D.glsl new file mode 100644 index 0000000..01a3620 --- /dev/null +++ b/resources/shaders/common/math2D.glsl @@ -0,0 +1,10 @@ +float distToLine(vec2 origin, vec2 direction, vec2 point) { + vec2 perpendicular = vec2(direction.y, -direction.x); + return abs(dot(normalize(perpendicular), origin - point)); +} + +float getWinding(vec2 a, vec2 b) { return cross(vec3(a, 0.0), vec3(b, 0.0)).z; } + +vec2 rotate(vec2 a, float angle) { + return vec2(a.x * cos(angle) - a.y * sin(angle), a.x * sin(angle) + a.y * cos(angle)); +} \ No newline at end of file diff --git a/resources/shaders/common/noise.glsl b/resources/shaders/common/noise.glsl new file mode 100644 index 0000000..5491b80 --- /dev/null +++ b/resources/shaders/common/noise.glsl @@ -0,0 +1,207 @@ +// These noise algorithms are based on implementations by various authors from +// shadertoy.com, which are all available under the MIT License. See the respective links +// in the comments below. + +//////////////////////////////////////////////////////////////////////////////////////// +// Hash without Sine // +// MIT License, https://www.shadertoy.com/view/4djSRW // +// Copyright (c) 2014 David Hoskins. // +//////////////////////////////////////////////////////////////////////////////////////// + +// 1 out, 1 in... +float hash11(float p) { + p = fract(p * .1031); + p *= p + 33.33; + p *= p + p; + return fract(p); +} + +// 1 out, 2 in... +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * .1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +// 1 out, 3 in... +float hash13(vec3 p3) { + p3 = fract(p3 * .1031); + p3 += dot(p3, p3.zyx + 31.32); + return fract((p3.x + p3.y) * p3.z); +} + +// 2 out, 1 in... +vec2 hash21(float p) { + vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.xx + p3.yz) * p3.zy); +} + +// 2 out, 2 in... +vec2 hash22(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.xx + p3.yz) * p3.zy); +} + +// 2 out, 3 in... +vec2 hash23(vec3 p3) { + p3 = fract(p3 * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.xx + p3.yz) * p3.zy); +} + +// 3 out, 1 in... +vec3 hash31(float p) { + vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.xxy + p3.yzz) * p3.zyx); +} + +// 3 out, 2 in... +vec3 hash32(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yxz + 33.33); + return fract((p3.xxy + p3.yzz) * p3.zyx); +} + +// 3 out, 3 in... +vec3 hash33(vec3 p3) { + p3 = fract(p3 * vec3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yxz + 33.33); + return fract((p3.xxy + p3.yxx) * p3.zyx); +} + +// 4 out, 1 in... +vec4 hash41(float p) { + vec4 p4 = fract(vec4(p) * vec4(.1031, .1030, .0973, .1099)); + p4 += dot(p4, p4.wzxy + 33.33); + return fract((p4.xxyz + p4.yzzw) * p4.zywx); +} + +// 4 out, 2 in... +vec4 hash42(vec2 p) { + vec4 p4 = fract(vec4(p.xyxy) * vec4(.1031, .1030, .0973, .1099)); + p4 += dot(p4, p4.wzxy + 33.33); + return fract((p4.xxyz + p4.yzzw) * p4.zywx); +} + +// 4 out, 3 in... +vec4 hash43(vec3 p) { + vec4 p4 = fract(vec4(p.xyzx) * vec4(.1031, .1030, .0973, .1099)); + p4 += dot(p4, p4.wzxy + 33.33); + return fract((p4.xxyz + p4.yzzw) * p4.zywx); +} + +// 4 out, 4 in... +vec4 hash44(vec4 p4) { + p4 = fract(p4 * vec4(.1031, .1030, .0973, .1099)); + p4 += dot(p4, p4.wzxy + 33.33); + return fract((p4.xxyz + p4.yzzw) * p4.zywx); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// 2D Simplex Noise // +// MIT License, https://www.shadertoy.com/view/Msf3WH // +// Copyright © 2013 Inigo Quilez // +//////////////////////////////////////////////////////////////////////////////////////// + +float simplex2D(vec2 p) { + const float K1 = 0.366025404; // (sqrt(3)-1)/2; + const float K2 = 0.211324865; // (3-sqrt(3))/6; + + vec2 i = floor(p + (p.x + p.y) * K1); + vec2 a = p - i + (i.x + i.y) * K2; + float m = step(a.y, a.x); + vec2 o = vec2(m, 1.0 - m); + vec2 b = a - o + K2; + vec2 c = a - 1.0 + 2.0 * K2; + vec3 h = max(0.5 - vec3(dot(a, a), dot(b, b), dot(c, c)), 0.0); + vec3 n = h * h * h * h * + vec3(dot(a, -1.0 + 2.0 * hash22(i + 0.0)), dot(b, -1.0 + 2.0 * hash22(i + o)), + dot(c, -1.0 + 2.0 * hash22(i + 1.0))); + return 0.5 + 0.5 * dot(n, vec3(70.0)); +} + +float simplex2DFractal(vec2 p) { + mat2 m = mat2(1.6, 1.2, -1.2, 1.6); + float f = 0.5000 * simplex2D(p); + p = m * p; + f += 0.2500 * simplex2D(p); + p = m * p; + f += 0.1250 * simplex2D(p); + p = m * p; + f += 0.0625 * simplex2D(p); + p = m * p; + + return f; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// 3D Simplex Noise // +// MIT License, https://www.shadertoy.com/view/XsX3zB // +// Copyright © 2013 Nikita Miropolskiy // +//////////////////////////////////////////////////////////////////////////////////////// + +float simplex3D(vec3 p) { + + // skew constants for 3D simplex functions + const float F3 = 0.3333333; + const float G3 = 0.1666667; + + // 1. find current tetrahedron T and it's four vertices + // s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices + // x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertice + + // calculate s and x + vec3 s = floor(p + dot(p, vec3(F3))); + vec3 x = p - s + dot(s, vec3(G3)); + + // calculate i1 and i2 + vec3 e = step(vec3(0.0), x - x.yzx); + vec3 i1 = e * (1.0 - e.zxy); + vec3 i2 = 1.0 - e.zxy * (1.0 - e); + + // x1, x2, x3 + vec3 x1 = x - i1 + G3; + vec3 x2 = x - i2 + 2.0 * G3; + vec3 x3 = x - 1.0 + 3.0 * G3; + + // 2. find four surflets and store them in d + vec4 w, d; + + // calculate surflet weights + w.x = dot(x, x); + w.y = dot(x1, x1); + w.z = dot(x2, x2); + w.w = dot(x3, x3); + + // w fades from 0.6 at the center of the surflet to 0.0 at the margin + w = max(0.6 - w, 0.0); + + // calculate surflet components + d.x = dot(-0.5 + hash33(s), x); + d.y = dot(-0.5 + hash33(s + i1), x1); + d.z = dot(-0.5 + hash33(s + i2), x2); + d.w = dot(-0.5 + hash33(s + 1.0), x3); + + // multiply d by w^4 + w *= w; + w *= w; + d *= w; + + // 3. return the sum of the four surflets + return dot(d, vec4(52.0)) * 0.5 + 0.5; +} + +// directional artifacts can be reduced by rotating each octave +float simplex3DFractal(vec3 m) { + + // const matrices for 3D rotation + const mat3 rot1 = mat3(-0.37, 0.36, 0.85, -0.14, -0.93, 0.34, 0.92, 0.01, 0.4); + const mat3 rot2 = mat3(-0.55, -0.39, 0.74, 0.33, -0.91, -0.24, 0.77, 0.12, 0.63); + const mat3 rot3 = mat3(-0.71, 0.52, -0.47, -0.08, -0.72, -0.68, -0.7, -0.45, 0.56); + + return 0.5333333 * simplex3D(m * rot1) + 0.2666667 * simplex3D(2.0 * m * rot2) + + 0.1333333 * simplex3D(4.0 * m * rot3) + 0.0666667 * simplex3D(8.0 * m); +} \ No newline at end of file diff --git a/resources/shaders/common/uniforms.glsl b/resources/shaders/common/uniforms.glsl new file mode 100644 index 0000000..a7db848 --- /dev/null +++ b/resources/shaders/common/uniforms.glsl @@ -0,0 +1,11 @@ +// These should be included in every shader. +// uForOpening: True if a window-open animation is ongoing, false otherwise. +// uTexture: Contains the texture of the window. +// uProgress: A value which transitions from 0 to 1 during the entire animation. +// uTime: A steadily increasing value in seconds. +// uSize: The size of uTexture in pixels. +uniform bool uForOpening; +uniform sampler2D uTexture; +uniform float uProgress; +uniform float uTime; +uniform vec2 uSize; \ No newline at end of file diff --git a/resources/shaders/energize-a-declarations.glsl b/resources/shaders/energize-a-declarations.glsl new file mode 100644 index 0000000..121d88f --- /dev/null +++ b/resources/shaders/energize-a-declarations.glsl @@ -0,0 +1,49 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/edgeMask.glsl" + +uniform vec3 uColor; +uniform float uScale; + +const float FADE_IN_TIME = 0.3; +const float FADE_OUT_TIME = 0.6; +const float HEART_FADE_TIME = 0.3; +const float EDGE_FADE_WIDTH = 50; + +// This method returns two values: +// result.x: A mask for the particles. +// result.y: The opacity of the fading window. +vec2 getMasks() { + float fadeInProgress = clamp(uProgress / FADE_IN_TIME, 0, 1); + float fadeOutProgress = clamp((uProgress - FADE_IN_TIME) / FADE_OUT_TIME, 0, 1); + float heartProgress = + clamp((uProgress - (1.0 - HEART_FADE_TIME)) / HEART_FADE_TIME, 0, 1); + + // Compute mask for the "atom" particles. + float dist = length(cogl_tex_coord_in[0].st - 0.5) * 4.0; + float atomMask = smoothstep(0.0, 1.0, (fadeInProgress * 2.0 - dist + 1.0)); + atomMask *= fadeInProgress; + atomMask *= smoothstep(1.0, 0.0, fadeOutProgress); + + // Fade-out the masks at the window edges. + float edgeFade = getAbsoluteEdgeMask(EDGE_FADE_WIDTH); + atomMask *= edgeFade; + + float heartMask = getRelativeEdgeMask(0.5); + heartMask = 3.0 * pow(heartMask, 5); + heartMask *= fadeOutProgress; + heartMask *= 1.0 - heartProgress; + atomMask = clamp(heartMask + atomMask, 0, 1); + + // Compute fading window opacity. + float windowMask = pow(1.0 - fadeOutProgress, 2.0); + + if (uForOpening) { + windowMask = 1.0 - windowMask; + } + + return vec2(atomMask, windowMask); +} \ No newline at end of file diff --git a/resources/shaders/energize-a.glsl b/resources/shaders/energize-a.glsl new file mode 100644 index 0000000..842b41d --- /dev/null +++ b/resources/shaders/energize-a.glsl @@ -0,0 +1,35 @@ +vec2 masks = getMasks(); +vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; +} + +// Dissolve window to effect color / transparency. +cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.2 * masks.y + 0.8); +cogl_color_out.a = windowColor.a * masks.y; + +vec2 scaledUV = (cogl_tex_coord_in[0].st - 0.5) * (1.0 + 0.1 * uProgress); +scaledUV /= uScale; + +// Add molecule particles. +vec2 uv = scaledUV + vec2(0, 0.1 * uTime); +uv *= 0.010598 * vec2(0.5 * uSize.x, uSize.y); +float particles = 0.2 * pow((simplex3D(vec3(uv, 0.0 * uTime))), 3.0); + +// Add more molecule particles. +for (int i = 1; i <= 3; ++i) { + vec2 uv = scaledUV * 0.12154 / pow(1.5, i) * uSize; + float atoms = simplex3D(vec3(uv, 2.0 * uTime / i)); + particles += 0.5 * pow(0.2 * (1.0 / (1.0 - atoms) - 1.0), 2); +} + +cogl_color_out.rgb += uColor * particles * masks.x; +cogl_color_out.a += particles * masks.x; + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(masks, 0.0, 1.0); +// cogl_color_out = vec4(vec3(masks.x), 1.0); +// cogl_color_out = vec4(vec3(masks.y), 1.0); +// cogl_color_out = vec4(vec3(particles), 1.0); \ No newline at end of file diff --git a/resources/shaders/energize-b-declarations.glsl b/resources/shaders/energize-b-declarations.glsl new file mode 100644 index 0000000..8079be0 --- /dev/null +++ b/resources/shaders/energize-b-declarations.glsl @@ -0,0 +1,66 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/edgeMask.glsl" + +uniform vec3 uColor; +uniform float uScale; + +const float SHOWER_TIME = 0.3; +const float SHOWER_WIDTH = 0.3; +const float STREAK_TIME = 0.6; +const float EDGE_FADE = 50; + +// This method returns four values: +// result.x: A mask for the particles which lead the shower. +// result.y: A mask for the streaks which follow the shower particles. +// result.z: A mask for the final "atom" particles. +// result.w: The opacity of the fading window. +vec4 getMasks() { + float showerProgress = uProgress / SHOWER_TIME; + float streakProgress = clamp((uProgress - SHOWER_TIME) / STREAK_TIME, 0, 1); + float fadeProgress = clamp((uProgress - SHOWER_TIME) / (1.0 - SHOWER_TIME), 0, 1); + + // Gradient from top to bottom. + float t = cogl_tex_coord_in[0].t; + + // A smooth gradient which moves to the bottom within the showerProgress. + float showerMask = + smoothstep(1, 0, abs(showerProgress - t - SHOWER_WIDTH) / SHOWER_WIDTH); + + // This is 1 above the streak mask. + float streakMask = (showerProgress - t - SHOWER_WIDTH) > 0 ? 1 : 0; + + // Compute mask for the "atom" particles. + float atomMask = getRelativeEdgeMask(0.2); + atomMask = max(0, atomMask - showerMask); + atomMask *= streakMask; + atomMask *= sqrt(1 - fadeProgress * fadeProgress); + + // Make some particles visible in the streaks. + showerMask += 0.05 * streakMask; + + // Add shower mask to streak mask. + streakMask = max(streakMask, showerMask); + + // Fade-out the masks at the window edges. + float edgeFade = getAbsoluteEdgeMask(EDGE_FADE); + streakMask *= edgeFade; + showerMask *= edgeFade; + + // Fade-out the masks from top to bottom. + float fade = smoothstep(0.0, 1.0, 1.0 + t - 2.0 * streakProgress); + streakMask *= fade; + showerMask *= fade; + + // Compute fading window opacity. + float windowMask = pow(1.0 - fadeProgress, 2.0); + + if (uForOpening) { + windowMask = 1.0 - windowMask; + } + + return vec4(showerMask, streakMask, atomMask, windowMask); +} \ No newline at end of file diff --git a/resources/shaders/energize-b.glsl b/resources/shaders/energize-b.glsl new file mode 100644 index 0000000..f6549b3 --- /dev/null +++ b/resources/shaders/energize-b.glsl @@ -0,0 +1,42 @@ +vec4 masks = getMasks(); +vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; +} + +// Dissolve window to effect color / transparency. +cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.5 * masks.w + 0.5); +cogl_color_out.a = windowColor.a * masks.w; + +// Add leading shower particles. +vec2 showerUV = cogl_tex_coord_in[0].st + vec2(0, -0.7 * uProgress / SHOWER_TIME); +showerUV *= 0.02 * uSize / uScale; +float shower = pow(simplex2D(showerUV), 10.0); +cogl_color_out.rgb += uColor * shower * masks.x; +cogl_color_out.a += shower * masks.x; + +// Add trailing streak lines. +vec2 streakUV = cogl_tex_coord_in[0].st + vec2(0, -uProgress / SHOWER_TIME); +streakUV *= vec2(0.05 * uSize.x, 0.001 * uSize.y) / uScale; +float streaks = simplex2DFractal(streakUV) * 0.5; +cogl_color_out.rgb += uColor * streaks * masks.y; +cogl_color_out.a += streaks * masks.y; + +// Add glimmering atoms. +vec2 atomUV = cogl_tex_coord_in[0].st + vec2(0, -0.025 * uProgress / SHOWER_TIME); +atomUV *= 0.2 * uSize / uScale; +float atoms = pow((simplex3D(vec3(atomUV, uTime))), 5.0); +cogl_color_out.rgb += uColor * atoms * masks.z; +cogl_color_out.a += atoms * masks.z; + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(masks.rgb, 1.0); +// cogl_color_out = vec4(vec3(masks.x), 1.0); +// cogl_color_out = vec4(vec3(masks.y), 1.0); +// cogl_color_out = vec4(vec3(masks.z), 1.0); +// cogl_color_out = vec4(vec3(masks.w), 1.0); +// cogl_color_out = vec4(vec3(shower), 1.0); +// cogl_color_out = vec4(vec3(streaks), 1.0); +// cogl_color_out = vec4(vec3(atoms), 1.0); \ No newline at end of file diff --git a/resources/shaders/fire-declarations.glsl b/resources/shaders/fire-declarations.glsl new file mode 100644 index 0000000..0f137be --- /dev/null +++ b/resources/shaders/fire-declarations.glsl @@ -0,0 +1,79 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/compositing.glsl" +#include "common/edgeMask.glsl" +#include "common/noise.glsl" + +uniform bool u3DNoise; +uniform float uScale; +uniform float uMovementSpeed; +uniform vec4 uGradient1; +uniform vec4 uGradient2; +uniform vec4 uGradient3; +uniform vec4 uGradient4; +uniform vec4 uGradient5; + +// These may be configurable in the future. +const float EDGE_FADE = 70; +const float FADE_WIDTH = 0.1; +const float HIDE_TIME = 0.4; + +// This maps the input value from [0..1] to a color from the gradient. +vec4 getFireColor(float v) { + const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8); + vec4 colors[5] = vec4[](uGradient1, uGradient2, uGradient3, uGradient4, uGradient5); + + if (v < steps[0]) { + return colors[0]; + } + + for (int i = 0; i < 4; ++i) { + if (v <= steps[i + 1]) { + return mix(colors[i], colors[i + 1], + vec4(v - steps[i]) / (steps[i + 1] - steps[i])); + } + } + + return colors[4]; +} + +// This method requires the uniforms from standardUniforms() to be available. +// It returns two values: The first is an alpha value which can be used for the window +// texture. This gradually dissolves the window from top to bottom. The second can be used +// to mask any effect, it will be most opaque where the window is currently fading and +// gradually dissolve to zero over time. +// hideTime: A value in [0..1]. It determines the percentage of the animation which +// is spent for hiding the window. 1-hideTime will be spent thereafter for +// dissolving the effect mask. +// fadeWidth: The relative size of the window-hiding gradient in [0..1]. +// edgeFadeWidth: The pixel width of the effect fading range at the edges of the window. +vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) { + float burnProgress = clamp(uProgress / hideTime, 0, 1); + float afterBurnProgress = clamp((uProgress - hideTime) / (1 - hideTime), 0, 1); + + // Gradient from top to bottom. + float t = cogl_tex_coord_in[0].t * (1 - fadeWidth); + + // Visible part of the window. Gradually dissolves towards the bottom. + float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1); + + // Gradient from top burning window. + float effectMask = clamp(t * (1 - windowMask) / burnProgress, 0, 1); + + // Fade-out when the window burned down. + if (uProgress > hideTime) { + float fade = sqrt(1 - afterBurnProgress * afterBurnProgress); + effectMask *= mix(1, 1 - t, afterBurnProgress) * fade; + } + + // Fade at window borders. + effectMask *= getAbsoluteEdgeMask(edgeFadeWidth); + + if (uForOpening) { + windowMask = 1.0 - windowMask; + } + + return vec2(windowMask, effectMask); +} \ No newline at end of file diff --git a/resources/shaders/fire.glsl b/resources/shaders/fire.glsl new file mode 100644 index 0000000..66e7fd8 --- /dev/null +++ b/resources/shaders/fire.glsl @@ -0,0 +1,32 @@ +// Get a noise value which moves vertically in time. +vec2 uv = cogl_tex_coord_in[0].st * uSize / vec2(400, 600) / uScale; +uv.y += uTime * uMovementSpeed; + +float noise = u3DNoise ? simplex3DFractal(vec3(uv * 4.0, uTime* uMovementSpeed * 1.5)) + : simplex2DFractal(uv * 4.0); + +// Modulate noise by effect mask. +vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE); +noise *= effectMask.y; + +// Map noise value to color. +vec4 fire = getFireColor(noise); + +// Get the window texture. +cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +// Fade the window according to the effect mask. +cogl_color_out.a *= effectMask.x; + +// Add the fire to the window. +cogl_color_out = alphaOver(cogl_color_out, fire); + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(noise), 1); +// cogl_color_out = vec4(vec3(effectMask.x), 1); +// cogl_color_out = vec4(vec3(effectMask.y), 1); \ No newline at end of file diff --git a/resources/shaders/hexagon-declarations.glsl b/resources/shaders/hexagon-declarations.glsl new file mode 100644 index 0000000..e683ee5 --- /dev/null +++ b/resources/shaders/hexagon-declarations.glsl @@ -0,0 +1,54 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" + +uniform bool uAdditiveBlending; +uniform vec2 uSeed; +uniform float uScale; +uniform float uLineWidth; +uniform vec4 uGlowColor; +uniform vec4 uLineColor; + +// This methods generates a procedural hexagonal pattern. It returns four values: +// result.xy: This contains cell-relative coordinates for the given point. +// [0, 0] is in the center of a cell, [0, 1] at the upper edge, +// [sqrt(4.0 / 3.0), 0] at the right tip and so on. +// result.z: This is the distance to the closest edge. This is used for shrinking +// of the tiles and the sharp overlay lines. +// result.w: This is the distance to the closest cell center. This is used for +// the glow effect. +vec4 getHexagons(vec2 p) { + + // Length of a cell's edge. + const float edgeLength = sqrt(4.0 / 3.0); + + // The hexgrid repeats after this distance. + const vec2 scale = vec2(3.0 * edgeLength, 2.0); + + // This is a repeating grid of scale-sized cells. Y-values are in the + // interval [-1...1], X-value in [-1.5*edgeLength...1.5*edgeLength]. + vec2 a = mod(p, scale) - scale * 0.5; + vec2 aAbs = abs(a); + + // This is the same as above, but offset by half scale. + vec2 b = mod(p + scale * 0.5, scale) - scale * 0.5; + vec2 bAbs = abs(b); + + // Distance to closer edge, diagonally or horizontally. + // Once for cell set A and once for cell set B. + float distA = max(aAbs.x / edgeLength + aAbs.y * 0.5, aAbs.y); + float distB = max(bAbs.x / edgeLength + bAbs.y * 0.5, bAbs.y); + + // Minimum of both is distance to closest edge. + float dist = 1.0 - min(distA, distB); + + // We use the radial distance to the center for glow. + float glow = min(dot(a, a), dot(b, b)) / 1.5; + + // Take cell-relative coordinates from the closer cell. + vec2 cellCoords = distA < distB ? a : b; + + return vec4(cellCoords, dist, glow); +} \ No newline at end of file diff --git a/resources/shaders/hexagon.glsl b/resources/shaders/hexagon.glsl new file mode 100644 index 0000000..6f0406a --- /dev/null +++ b/resources/shaders/hexagon.glsl @@ -0,0 +1,59 @@ +// We simply inverse the progress for opening windows. +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// Add some smooth noise to the progress so that not every tile behaves the +// same. +float noise = simplex2D(cogl_tex_coord_in[0].st + uSeed); +progress = clamp(mix(noise - 1.0, noise + 1.0, progress), 0.0, 1.0); + +// glowProgress fades in in the first half of the animation, tileProgress fades +// in in the second half. +float glowProgress = smoothstep(0, 1, clamp(progress / 0.5, 0, 1)); +float tileProgress = smoothstep(0, 1, clamp((progress - 0.5) / 0.5, 0, 1)); + +vec2 texScale = 0.1 * uSize / uScale; +vec4 hex = getHexagons(cogl_tex_coord_in[0].st * texScale); + +if (tileProgress > hex.z) { + + // Crop outer parts of the shrinking tiles. + cogl_color_out.a = 0.0; + +} else { + + // Make the tiles shrink by offsetting the texture lookup towards the edge + // of the cell. + vec2 lookupOffset = tileProgress * hex.xy / texScale / (1.0 - tileProgress); + cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st + lookupOffset); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + + vec4 glow = uGlowColor; + vec4 line = uLineColor; + + // For the glow, we accumulate a few exponentially scaled versions of hex.w. + glow.a *= pow(hex.w, 20.0) * 10.0 + pow(hex.w, 10.0) * 5.0 + pow(hex.w, 2.0) * 0.5; + + // Using step(uLineWidth, hex.z) would be simpler, but the below creates some + // fake antialiasing. + line.a *= 1.0 - smoothstep(uLineWidth * 0.02 * 0.5, uLineWidth * 0.02, hex.z); + + // Fade in the glowing lines. + glow.a *= glowProgress; + line.a *= glowProgress; + + // Do not add the hexagon lines onto transparent parts of the window. + glow *= cogl_color_out.a; + line *= cogl_color_out.a; + + if (uAdditiveBlending) { + cogl_color_out.rgb += glow.rgb * glow.a; + cogl_color_out.rgb += line.rgb * line.a; + } else { + cogl_color_out.rgb = mix(cogl_color_out.rgb, glow.rgb, glow.a); + cogl_color_out.rgb = mix(cogl_color_out.rgb, line.rgb, line.a); + } +} \ No newline at end of file diff --git a/resources/shaders/matrix-declarations.glsl b/resources/shaders/matrix-declarations.glsl new file mode 100644 index 0000000..d408bd1 --- /dev/null +++ b/resources/shaders/matrix-declarations.glsl @@ -0,0 +1,68 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/edgeMask.glsl" +#include "common/compositing.glsl" + +uniform sampler2D uFontTexture; +uniform vec3 uTrailColor; +uniform vec3 uTipColor; +uniform float uLetterSize; +uniform float uRandomness; +uniform float uOverShoot; + +// These may be configurable in the future. +const float EDGE_FADE = 30; +const float FADE_WIDTH = 150; +const float TRAIL_LENGTH = 0.2; +const float FINAL_FADE_START_TIME = 0.8; +const float LETTER_TILES = 16.0; +const float LETTER_FLICKER_SPEED = 2.0; + +// This returns a flickering grid of random letters. +float getText(vec2 fragCoord) { + vec2 pixelCoords = fragCoord * uSize; + vec2 uv = mod(pixelCoords.xy, uLetterSize) / uLetterSize; + vec2 block = pixelCoords / uLetterSize - uv; + + // Choose random letter. + uv += floor(hash22(floor(hash22(block) * vec2(12.9898, 78.233) + + LETTER_FLICKER_SPEED * uTime + 42.254)) * + LETTER_TILES); + + return texture2D(uFontTexture, uv / LETTER_TILES).r; +} + +// This returns two values: The first are gradients for the "raindrops" which move +// from top to bottom. This is used for fading the letters. The second value is set +// to one below each drop and to zero above it. This second value is used for fading +// the window texture. +vec2 getRain(vec2 fragCoord) { + float column = cogl_tex_coord_in[0].x * uSize.x; + column -= mod(column, uLetterSize); + + float delay = fract(sin(column) * 78.233) * mix(0.0, 1.0, uRandomness); + float speed = fract(cos(column) * 12.989) * mix(0.0, 0.3, uRandomness) + 1.5; + + float distToDrop = (uProgress * 2 - delay) * speed - cogl_tex_coord_in[0].y; + + float rainAlpha = distToDrop >= 0 ? exp(-distToDrop / TRAIL_LENGTH) : 0; + float windowAlpha = 1 - clamp(uSize.y * distToDrop, 0, FADE_WIDTH) / FADE_WIDTH; + + // Fade at window borders. + rainAlpha *= getAbsoluteEdgeMask(EDGE_FADE); + + // Add some variation to the drop start and end position. + float shorten = + fract(sin(column + 42.0) * 33.423) * mix(0.0, uOverShoot * 0.25, uRandomness); + rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1)); + rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1)); + + if (uForOpening) { + windowAlpha = 1.0 - windowAlpha; + } + + return vec2(rainAlpha, windowAlpha); +} \ No newline at end of file diff --git a/resources/shaders/matrix.glsl b/resources/shaders/matrix.glsl new file mode 100644 index 0000000..ace5ccb --- /dev/null +++ b/resources/shaders/matrix.glsl @@ -0,0 +1,32 @@ +vec2 coords = cogl_tex_coord_in[0].st; +coords.y = coords.y * (uOverShoot + 1.0) - uOverShoot * 0.5; + +// Get a cool matrix effect. See comments for those methods above. +vec2 rainMask = getRain(coords); +float textMask = getText(coords); + +// Get the window texture. +cogl_color_out = texture2D(uTexture, coords); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +// Fade the window according to the effect mask. +cogl_color_out.a *= rainMask.y; + +// This is used to fade out the remaining trails in the end. +float finalFade = + 1 - clamp((uProgress - FINAL_FADE_START_TIME) / (1 - FINAL_FADE_START_TIME), 0, 1); +float rainAlpha = finalFade * rainMask.x; + +// Add the matrix effect to the window. +vec4 text = + vec4(mix(uTrailColor, uTipColor, min(1, pow(rainAlpha + 0.1, 4))), rainAlpha* textMask); +cogl_color_out = alphaOver(cogl_color_out, text); + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(textMask), 1); +// cogl_color_out = vec4(vec3(rainMask.x), 1); +// cogl_color_out = vec4(vec3(rainMask.y), 1); \ No newline at end of file diff --git a/resources/shaders/snap-declarations.glsl b/resources/shaders/snap-declarations.glsl new file mode 100644 index 0000000..c704df5 --- /dev/null +++ b/resources/shaders/snap-declarations.glsl @@ -0,0 +1,18 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/math2D.glsl" + +uniform sampler2D uDustTexture; +uniform vec4 uDustColor; +uniform vec2 uSeed; +uniform float uDustScale; + +const float DUST_LAYERS = 4; +const float GROW_INTENSITY = 0.05; +const float SHRINK_INTENSITY = 0.05; +const float WIND_INTENSITY = 0.05; +const float ACTOR_SCALE = 1.2; +const float PADDING = ACTOR_SCALE / 2.0 - 0.5; \ No newline at end of file diff --git a/resources/shaders/snap.glsl b/resources/shaders/snap.glsl new file mode 100644 index 0000000..a94f946 --- /dev/null +++ b/resources/shaders/snap.glsl @@ -0,0 +1,71 @@ +// We simply inverse the progress for opening windows. +float progress = uForOpening ? uProgress : 1.0 - uProgress; + +float gradient = cogl_tex_coord_in[0].t * ACTOR_SCALE - PADDING; +progress = 2.0 - gradient - 2.0 * progress; +progress = progress + 0.25 - 0.5 * simplex2D((cogl_tex_coord_in[0].st + uSeed) * 2.0); +progress = pow(max(0, progress), 2.0); + +// This may help you to understand how this effect works. +// cogl_color_out = vec4(progress, 0, 0, 0); +// return; + +cogl_color_out = vec4(0, 0, 0, 0); + +for (float i = 0; i < DUST_LAYERS; ++i) { + + // Create a random direction. + float factor = DUST_LAYERS == 1 ? 0 : i / (DUST_LAYERS - 1); + float angle = 123.123 * (uSeed.x + factor); + vec2 direction = vec2(1.0, 0.0); + direction = rotate(direction, angle); + + // Flip direction for one side of the window. + vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - 0.5; + if (getWinding(direction, coords) > 0) { + direction *= -1; + } + + // Flip direction for half the layers. + if (factor > 0.5) { + direction *= -1; + } + + // We grow the layer along the random direction, shrink it orthogonally to it + // and scale it up slightly. + float dist = distToLine(vec2(0.0), direction, coords); + vec2 grow = direction * dist * mix(0, GROW_INTENSITY, progress); + vec2 shrink = + vec2(direction.y, -direction.x) * dist * mix(0, SHRINK_INTENSITY, progress); + float scale = mix(1.0, 1.05, factor * progress); + coords = (coords + grow + shrink) / scale; + + // Add some wind. + coords.x += WIND_INTENSITY * progress * (uForOpening ? 1.0 : -1.0); + + // Now check wether there is actually something in the current dust layer at + // the coords position. + vec2 dustCoords = (coords + uSeed) * uSize / uDustScale / 100.0; + vec2 dustMap = texture2D(uDustTexture, dustCoords).rg; + float dustGroup = floor(dustMap.g * DUST_LAYERS * 0.999); + + if (dustGroup == i) { + + // Get the window color. + vec4 windowColor = texture2D(uTexture, coords + 0.5); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; + } + + // Fade the window color to uDustColor. + vec3 dustColor = mix(windowColor.rgb, uDustColor.rgb, uDustColor.a); + windowColor.rgb = mix(windowColor.rgb, dustColor, progress); + + // Dissolve and blend the layers. + if (dustMap.x - progress > 0) { + cogl_color_out = windowColor; + } + } +} \ No newline at end of file diff --git a/resources/shaders/trex-declarations.glsl b/resources/shaders/trex-declarations.glsl new file mode 100644 index 0000000..df4bcfa --- /dev/null +++ b/resources/shaders/trex-declarations.glsl @@ -0,0 +1,57 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/compositing.glsl" + +// See assets/README.md for how this texture was created. +uniform sampler2D uClawTexture; +uniform vec4 uFlashColor; +uniform vec2 uSeed; +uniform float uClawSize; +uniform float uNumClaws; +uniform float uWarpIntensity; + +const float FLASH_INTENSITY = 0.1; +const float MAX_SPAWN_TIME = + 0.6; // Scratches will only start in the first half of the animation. +const float FF_TIME = 0.6; // Relative time for the final fade to transparency. + +// This method generates a grid of randomly rotated, slightly shifted and scaled +// UV squares. It returns the texture coords of the UV square at the given actor +// coordinates. If these do not fall into one of the UV grids, the coordinates of +// the closest UV grid will be clamped and returned. +vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) { + + // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. + vec2 coords = texCoords + hash22(seed); + coords *= uSize.x < uSize.y ? vec2(1.0, 1.0 * uSize.y / uSize.x) + : vec2(1.0 * uSize.x / uSize.y, 1.0); + + // Apply global scale. + coords *= gridScale; + + // Get grid cell coordinates in [0..1]. + vec2 cellUV = mod(coords, vec2(1)); + + // This is unique for each cell. + vec2 cellID = coords - cellUV + vec2(362.456); + + // Add random rotation, scale and offset to each grid cell. + float scale = mix(0.8, 1.0, hash12(cellID * seed * 134.451)); + float offsetX = mix(0.0, 1.0 - scale, hash12(cellID * seed * 54.4129)); + float offsetY = mix(0.0, 1.0 - scale, hash12(cellID * seed * 25.3089)); + float rotation = mix(0.0, 2.0 * 3.141, hash12(cellID * seed * 2.99837)); + + cellUV -= vec2(offsetX, offsetY); + cellUV /= scale; + + cellUV -= 0.5; + cellUV = vec2(cellUV.x * cos(rotation) - cellUV.y * sin(rotation), + cellUV.x * sin(rotation) + cellUV.y * cos(rotation)); + cellUV += 0.5; + + // Clamp resulting coordinates. + return clamp(cellUV, vec2(0), vec2(1)); +} \ No newline at end of file diff --git a/resources/shaders/trex.glsl b/resources/shaders/trex.glsl new file mode 100644 index 0000000..0f7426d --- /dev/null +++ b/resources/shaders/trex.glsl @@ -0,0 +1,51 @@ +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// Warp the texture coordinates to create a blow-up effect. +vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0; +float dist = length(coords); +coords = (coords / dist * pow(dist, 1.0 + uWarpIntensity)) * 0.5 + 0.5; +coords = mix(cogl_tex_coord_in[0].st, coords, progress); + +// Accumulate several random scratches. The color in the scratch map refers to the +// relative time when the respective part will become invisible. Therefore we can +// add a value to make the scratch appear later. +float scratchMap = 1.0; +for (int i = 0; i < uNumClaws; ++i) { + vec2 uv = getClawUV(coords, 1.0 / uClawSize, uSeed * (i + 1)); + float delay = i / uNumClaws * MAX_SPAWN_TIME; + scratchMap = min(scratchMap, clamp(texture2D(uClawTexture, uv).r + delay, 0, 1)); +} + +// Get the window texture. We shift the texture lookup by the local derivative of +// the claw texture in order to mimic some folding distortion. +vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5; +cogl_color_out = texture2D(uTexture, coords + offset); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +// Add colorful flashes. +float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1; +if (flashIntensity < 0 || flashIntensity >= 1) { + flashIntensity = 0; +} + +// Hide flashes where there is now window. +vec4 flash = uFlashColor; +flash.a *= flashIntensity * cogl_color_out.a * (1.0 - progress); + +// Hide scratched out parts. +cogl_color_out.a *= (scratchMap > progress ? 1 : 0); + +// Add flash color. +cogl_color_out = alphaOver(cogl_color_out, flash); + +// Fade out the remaining shards. +float fadeProgress = smoothstep(0, 1, (progress - 1.0 + FF_TIME) / FF_TIME); +cogl_color_out.a *= sqrt(1 - fadeProgress * fadeProgress); + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(flashIntensity), 1); +// cogl_color_out = vec4(vec3(scratchMap), 1); \ No newline at end of file diff --git a/resources/shaders/tv-declarations.glsl b/resources/shaders/tv-declarations.glsl new file mode 100644 index 0000000..5f5dec8 --- /dev/null +++ b/resources/shaders/tv-declarations.glsl @@ -0,0 +1,12 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" + +uniform vec3 uColor; + +const float BLUR_WIDTH = 0.01; // Width of the gradients. +const float TB_TIME = 0.7; // Relative time for the top/bottom animation. +const float LR_TIME = 0.4; // Relative time for the left/right animation. +const float LR_DELAY = 0.6; // Delay after which the left/right animation starts. +const float FF_TIME = 0.1; // Relative time for the final fade to transparency. \ No newline at end of file diff --git a/resources/shaders/tv.glsl b/resources/shaders/tv.glsl new file mode 100644 index 0000000..b73f731 --- /dev/null +++ b/resources/shaders/tv.glsl @@ -0,0 +1,42 @@ +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// All of these are in [0..1] during the different stages of the animation. +// tb refers to the top-bottom animation. +// lr refers to the left-right animation. +// ff refers to the final fade animation. +float tbProgress = smoothstep(0, 1, clamp(progress / TB_TIME, 0, 1)); +float lrProgress = smoothstep(0, 1, clamp((progress - LR_DELAY) / LR_TIME, 0, 1)); +float ffProgress = smoothstep(0, 1, clamp((progress - 1.0 + FF_TIME) / FF_TIME, 0, 1)); + +// This is a top-center-bottom gradient in [0..1..0] +float tb = cogl_tex_coord_in[0].t * 2; +tb = tb < 1 ? tb : 2 - tb; + +// This is a left-center-right gradient in [0..1..0] +float lr = cogl_tex_coord_in[0].s * 2; +lr = lr < 1 ? lr : 2 - lr; + +// Combine the progress values with the gradients to create the alpha masks. +float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1)); +float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1)); +float ffMask = 1 - smoothstep(0, 1, ffProgress); + +// Assemble the final alpha value. +float mask = tbMask * lrMask * ffMask; + +cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +cogl_color_out.rgb = + mix(cogl_color_out.rgb, uColor* cogl_color_out.a, smoothstep(0, 1, progress)); +cogl_color_out.a *= mask; + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(tbMask), 1); +// cogl_color_out = vec4(vec3(lrMask), 1); +// cogl_color_out = vec4(vec3(ffMask), 1); +// cogl_color_out = vec4(vec3(mask), 1); \ No newline at end of file diff --git a/resources/shaders/wisps-declarations.glsl b/resources/shaders/wisps-declarations.glsl new file mode 100644 index 0000000..8630a72 --- /dev/null +++ b/resources/shaders/wisps-declarations.glsl @@ -0,0 +1,56 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/edgeMask.glsl" +#include "common/compositing.glsl" + +uniform vec2 uSeed; +uniform vec3 uColor; +uniform float uScale; + +const float WISPS_RADIUS = 20.0; +const float WISPS_SPEED = 10.0; +const float WISPS_SPACING = 40 + WISPS_RADIUS; +const int WISPS_LAYERS = 8; +const float WISPS_IN_TIME = 0.5; +const float WINDOW_OUT_TIME = 1.0; + +// Returns a grid of randomly moving points. Each grid cell contains one point which +// moves on an ellipse. +float getWisps(vec2 texCoords, float gridSize, vec2 seed) { + + // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. + vec2 coords = (texCoords + hash22(seed)) * uSize; + + // Apply global scale. + coords /= gridSize; + + // Get grid cell coordinates in [0..1]. + vec2 cellUV = mod(coords, vec2(1)); + + // This is unique for each cell. + vec2 cellID = coords - cellUV + vec2(362.456); + + // Add random rotation, scale and offset to each grid cell. + float speed = mix(10.0, 15.0, hash12(cellID * seed * 134.451)) / gridSize * WISPS_SPEED; + float rotation = mix(0.0, 6.283, hash12(cellID * seed * 54.4129)); + float radius = mix(0.5, 1.0, hash12(cellID * seed * 19.1249)) * WISPS_RADIUS; + float roundness = mix(-1.0, 1.0, hash12(cellID * seed * 7.51949)); + + vec2 offset = vec2(sin(speed * (uTime + 1)) * roundness, cos(speed * (uTime + 1))); + offset *= 0.5 - 0.5 * radius / gridSize; + offset = vec2(offset.x * cos(rotation) - offset.y * sin(rotation), + offset.x * sin(rotation) + offset.y * cos(rotation)); + + cellUV += offset; + + // Use distance to center of shifted / rotated UV coordinates to draw a glaring point. + float dist = length(cellUV - 0.5) * gridSize / radius; + if (dist < 1.0) { + return min(5, 0.01 / pow(dist, 2.0)); + } + + return 0.0; +} \ No newline at end of file diff --git a/resources/shaders/wisps.glsl b/resources/shaders/wisps.glsl new file mode 100644 index 0000000..038ff67 --- /dev/null +++ b/resources/shaders/wisps.glsl @@ -0,0 +1,42 @@ +float progress = uForOpening ? 1.0 - uProgress : uProgress; + +// Get the color of the window. +cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + +// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. +if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; +} + +// Compute several layers of moving wisps. +vec2 uv = (cogl_tex_coord_in[0].st - 0.5) / mix(1.0, 0.5, progress) + 0.5; +uv /= uScale; +float wisps = 0; +for (int i = 0; i < WISPS_LAYERS; ++i) { + wisps += getWisps(uv * 0.3, WISPS_SPACING, uSeed * (i + 1)); +} + +// Compute shrinking edge mask. +float mask = getRelativeEdgeMask(mix(0.01, 0.5, progress)); + +// Compute three different progress values. +float wispsIn = smoothstep(0, 1, clamp(progress / WISPS_IN_TIME, 0, 1)); +float wispsOut = + smoothstep(0, 1, clamp((progress - WISPS_IN_TIME) / (1.0 - WISPS_IN_TIME), 0, 1)); +float windowOut = smoothstep(0, 1, clamp(progress / WINDOW_OUT_TIME, 0, 1)); + +// Use a noise function to dissolve the window. +float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * uSize / 250) - 1.0)); +float windowMask = 1.0 - (windowOut < 0.5 ? mix(0.0, noise, windowOut * 2.0) + : mix(noise, 1.0, windowOut * 2.0 - 1.0)); +cogl_color_out.a *= windowMask * mask; + +// Add the wisps. +vec4 wispColor = wisps * vec4(uColor, min(wispsIn, 1.0 - wispsOut) * mask); +cogl_color_out = alphaOver(cogl_color_out, wispColor); + +// These are pretty useful for understanding how this works. +// cogl_color_out = vec4(vec3(windowMask), 1.0); +// cogl_color_out = vec4(vec3(wisps), 1.0); +// cogl_color_out = vec4(vec3(noise), 1.0); +// cogl_color_out = vec4(vec3(mask*min(wispsIn, 1.0 - wispsOut)), 1.0); \ No newline at end of file diff --git a/scripts/cloc.sh b/scripts/cloc.sh index 76674df..43d377e 100755 --- a/scripts/cloc.sh +++ b/scripts/cloc.sh @@ -32,7 +32,7 @@ cd "$( cd "$( dirname "$0" )" && pwd )/.." || \ # Run cloc - this counts code lines, blank lines and comment lines for the specified # languages. We are only interested in the summary, therefore the tail -1 -SUMMARY="$(cloc . --include-lang="JavaScript" --md | tail -1)" +SUMMARY="$(cloc . --include-lang="JavaScript,GLSL" --md | tail -1)" # The $SUMMARY is one line of a markdown table and looks like this: # SUM:|101|3123|2238|10783 diff --git a/src/Apparition.js b/src/Apparition.js index df1a844..bbd1938 100644 --- a/src/Apparition.js +++ b/src/Apparition.js @@ -137,8 +137,7 @@ var Apparition = class Apparition { if (utils.isInShellProcess()) { - const Shell = imports.gi.Shell; - const shaderSnippets = Me.imports.src.shaderSnippets; + const Shell = imports.gi.Shell; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -177,55 +176,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} + const decl = + utils.loadGLSLResource(`/shaders/${Apparition.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${Apparition.getNick()}.glsl`); - uniform vec2 uSeed; - uniform float uShake; - uniform float uTwirl; - uniform float uSuction; - uniform float uRandomness; - - const float ACTOR_SCALE = 2.0; - const float PADDING = ACTOR_SCALE / 2.0 - 0.5; - `; - - // The math for the whirling is inspired by this post: - // http://www.geeks3d.com/20110428/shader-library-swirl-post-processing-filter-in-glsl - const code = ` - // We simply inverse the progress for opening windows. - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // Choose a random suction center. - vec2 center = uSeed * uRandomness + 0.5 * (1.0 - uRandomness); - vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - center; - - // Add some shaking. - coords.x += progress * 0.05 * uShake * sin((progress + uSeed.x) * (1.0 + uSeed.x) * uShake); - coords.y += progress * 0.05 * uShake * cos((progress + uSeed.y) * (1.0 + uSeed.y) * uShake); - - // "Suck" the texture into the center. - float dist = length(coords) / sqrt(2); - coords += progress * coords / dist * 0.5 * uSuction; - - // Apply some whirling. - float angle = pow(1.0 - dist, 2.0) * uTwirl * progress; - float s = sin(angle); - float c = cos(angle); - coords = vec2(dot(coords, vec2(c, -s)), dot(coords, vec2(s, c))); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - cogl_color_out = texture2D(uTexture, coords + center); - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - // Fade out the window texture. - cogl_color_out.a *= 1.0 - progress; - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/BrokenGlass.js b/src/BrokenGlass.js index be7b770..1cd42fb 100644 --- a/src/BrokenGlass.js +++ b/src/BrokenGlass.js @@ -142,7 +142,6 @@ var BrokenGlass = class BrokenGlass { if (utils.isInShellProcess()) { const {Clutter, GdkPixbuf, Cogl, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; // This shader creates a complex-looking effect with rather simple means. Here is how it // works: The window is drawn five times on top of each other (see the SHARD_LAYERS @@ -214,74 +213,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} + const decl = + utils.loadGLSLResource(`/shaders/${BrokenGlass.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${BrokenGlass.getNick()}.glsl`); - uniform sampler2D uShardTexture; - uniform vec2 uSeed; - uniform vec2 uEpicenter; - uniform float uShardScale; - uniform float uBlowForce; - uniform float uGravity; - - const float SHARD_LAYERS = 5; - const float ACTOR_SCALE = 2.0; - const float PADDING = ACTOR_SCALE / 2.0 - 0.5; - `; - - const code = ` - cogl_color_out = vec4(0, 0, 0, 0); - - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // Draw the individual shard layers. - for (float i=0; i 0) { - cogl_color_out = texture2D(uTexture, coords); - } - } - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } // This is overridden to bind the shard texture for drawing. Sadly, this seems to be diff --git a/src/EnergizeA.js b/src/EnergizeA.js index 8cfc328..fdd9547 100644 --- a/src/EnergizeA.js +++ b/src/EnergizeA.js @@ -132,7 +132,6 @@ var EnergizeA = class EnergizeA { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -164,94 +163,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.edgeMask()} + const decl = + utils.loadGLSLResource(`/shaders/${EnergizeA.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${EnergizeA.getNick()}.glsl`); - uniform vec3 uColor; - uniform float uScale; - - const float FADE_IN_TIME = 0.3; - const float FADE_OUT_TIME = 0.6; - const float HEART_FADE_TIME = 0.3; - const float EDGE_FADE_WIDTH = 50; - - // This method returns two values: - // result.x: A mask for the particles. - // result.y: The opacity of the fading window. - vec2 getMasks() { - float fadeInProgress = clamp(uProgress/FADE_IN_TIME, 0, 1); - float fadeOutProgress = clamp((uProgress-FADE_IN_TIME)/FADE_OUT_TIME, 0, 1); - float heartProgress = clamp((uProgress-(1.0-HEART_FADE_TIME))/HEART_FADE_TIME, 0, 1); - - // Compute mask for the "atom" particles. - float dist = length(cogl_tex_coord_in[0].st - 0.5) * 4.0; - float atomMask = smoothstep(0.0, 1.0, (fadeInProgress * 2.0 - dist + 1.0)); - atomMask *= fadeInProgress; - atomMask *= smoothstep(1.0, 0.0, fadeOutProgress); - - // Fade-out the masks at the window edges. - float edgeFade = getAbsoluteEdgeMask(EDGE_FADE_WIDTH); - atomMask *= edgeFade; - - float heartMask = getRelativeEdgeMask(0.5); - heartMask = 3.0 * pow(heartMask, 5); - heartMask *= fadeOutProgress; - heartMask *= 1.0 - heartProgress; - atomMask = clamp(heartMask+atomMask, 0, 1); - - // Compute fading window opacity. - float windowMask = pow(1.0 - fadeOutProgress, 2.0); - - if (uForOpening) { - windowMask = 1.0 - windowMask; - } - - return vec2(atomMask, windowMask); - } - `; - - const code = ` - vec2 masks = getMasks(); - vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (windowColor.a > 0) { - windowColor.rgb /= windowColor.a; - } - - // Dissolve window to effect color / transparency. - cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.2 * masks.y + 0.8); - cogl_color_out.a = windowColor.a * masks.y; - - vec2 scaledUV = (cogl_tex_coord_in[0].st-0.5) * (1.0 + 0.1*uProgress); - scaledUV /= uScale; - - // Add molecule particles. - vec2 uv = scaledUV + vec2(0, 0.1*uTime); - uv *= 0.010598 * vec2(0.5*uSize.x, uSize.y); - float particles = 0.2 * pow((simplex3D(vec3(uv, 0.0*uTime))), 3.0); - - // Add more molecule particles. - for (int i=1; i<=3;++i) { - vec2 uv = scaledUV * 0.12154 / pow(1.5, i) * uSize; - float atoms = simplex3D(vec3(uv, 2.0*uTime/i)); - particles += 0.5 * pow(0.2 * (1.0 / (1.0 - atoms)-1.0), 2); - } - - cogl_color_out.rgb += uColor * particles * masks.x; - cogl_color_out.a += particles * masks.x; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(masks, 0.0, 1.0); - // cogl_color_out = vec4(vec3(masks.x), 1.0); - // cogl_color_out = vec4(vec3(masks.y), 1.0); - // cogl_color_out = vec4(vec3(particles), 1.0); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/EnergizeB.js b/src/EnergizeB.js index 6a4486a..4319a54 100644 --- a/src/EnergizeB.js +++ b/src/EnergizeB.js @@ -132,7 +132,6 @@ var EnergizeB = class EnergizeB { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -164,118 +163,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.edgeMask()} + const decl = + utils.loadGLSLResource(`/shaders/${EnergizeB.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${EnergizeB.getNick()}.glsl`); - uniform vec3 uColor; - uniform float uScale; - - const float SHOWER_TIME = 0.3; - const float SHOWER_WIDTH = 0.3; - const float STREAK_TIME = 0.6; - const float EDGE_FADE = 50; - - // This method returns four values: - // result.x: A mask for the particles which lead the shower. - // result.y: A mask for the streaks which follow the shower particles. - // result.z: A mask for the final "atom" particles. - // result.w: The opacity of the fading window. - vec4 getMasks() { - float showerProgress = uProgress/SHOWER_TIME; - float streakProgress = clamp((uProgress-SHOWER_TIME)/STREAK_TIME, 0, 1); - float fadeProgress = clamp((uProgress-SHOWER_TIME)/(1.0 - SHOWER_TIME), 0, 1); - - // Gradient from top to bottom. - float t = cogl_tex_coord_in[0].t; - - // A smooth gradient which moves to the bottom within the showerProgress. - float showerMask = smoothstep(1, 0, abs(showerProgress - t - SHOWER_WIDTH) / SHOWER_WIDTH); - - // This is 1 above the streak mask. - float streakMask = (showerProgress - t - SHOWER_WIDTH) > 0 ? 1 : 0; - - // Compute mask for the "atom" particles. - float atomMask = getRelativeEdgeMask(0.2); - atomMask = max(0, atomMask - showerMask); - atomMask *= streakMask; - atomMask *= sqrt(1-fadeProgress*fadeProgress); - - // Make some particles visible in the streaks. - showerMask += 0.05 * streakMask; - - // Add shower mask to streak mask. - streakMask = max(streakMask, showerMask); - - // Fade-out the masks at the window edges. - float edgeFade = getAbsoluteEdgeMask(EDGE_FADE); - streakMask *= edgeFade; - showerMask *= edgeFade; - - // Fade-out the masks from top to bottom. - float fade = smoothstep(0.0, 1.0, 1.0 + t - 2.0 * streakProgress); - streakMask *= fade; - showerMask *= fade; - - // Compute fading window opacity. - float windowMask = pow(1.0 - fadeProgress, 2.0); - - if (uForOpening) { - windowMask = 1.0 - windowMask; - } - - return vec4(showerMask, streakMask, atomMask, windowMask); - } - `; - - const code = ` - vec4 masks = getMasks(); - vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (windowColor.a > 0) { - windowColor.rgb /= windowColor.a; - } - - // Dissolve window to effect color / transparency. - cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.5 * masks.w + 0.5); - cogl_color_out.a = windowColor.a * masks.w; - - // Add leading shower particles. - vec2 showerUV = cogl_tex_coord_in[0].st + vec2(0, -0.7*uProgress/SHOWER_TIME); - showerUV *= 0.02 * uSize / uScale; - float shower = pow(simplex2D(showerUV), 10.0); - cogl_color_out.rgb += uColor * shower * masks.x; - cogl_color_out.a += shower * masks.x; - - // Add trailing streak lines. - vec2 streakUV = cogl_tex_coord_in[0].st + vec2(0, -uProgress/SHOWER_TIME); - streakUV *= vec2(0.05 * uSize.x, 0.001 * uSize.y) / uScale; - float streaks = simplex2DFractal(streakUV) * 0.5; - cogl_color_out.rgb += uColor * streaks * masks.y; - cogl_color_out.a += streaks * masks.y; - - // Add glimmering atoms. - vec2 atomUV = cogl_tex_coord_in[0].st + vec2(0, -0.025*uProgress/SHOWER_TIME); - atomUV *= 0.2 * uSize / uScale; - float atoms = pow((simplex3D(vec3(atomUV, uTime))), 5.0); - cogl_color_out.rgb += uColor * atoms * masks.z; - cogl_color_out.a += atoms * masks.z; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(masks.rgb, 1.0); - // cogl_color_out = vec4(vec3(masks.x), 1.0); - // cogl_color_out = vec4(vec3(masks.y), 1.0); - // cogl_color_out = vec4(vec3(masks.z), 1.0); - // cogl_color_out = vec4(vec3(masks.w), 1.0); - // cogl_color_out = vec4(vec3(shower), 1.0); - // cogl_color_out = vec4(vec3(streaks), 1.0); - // cogl_color_out = vec4(vec3(atoms), 1.0); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/Fire.js b/src/Fire.js index 93a65ba..2b951f8 100644 --- a/src/Fire.js +++ b/src/Fire.js @@ -243,7 +243,6 @@ var Fire = class Fire { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -291,128 +290,10 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { + const decl = utils.loadGLSLResource(`/shaders/${Fire.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${Fire.getNick()}.glsl`); - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.edgeMask()} - ${shaderSnippets.compositing()} - - uniform bool u3DNoise; - uniform float uScale; - uniform float uMovementSpeed; - uniform vec4 uGradient1; - uniform vec4 uGradient2; - uniform vec4 uGradient3; - uniform vec4 uGradient4; - uniform vec4 uGradient5; - - // These may be configurable in the future. - const float EDGE_FADE = 70; - const float FADE_WIDTH = 0.1; - const float HIDE_TIME = 0.4; - - // This maps the input value from [0..1] to a color from the gradient. - vec4 getFireColor(float v) { - const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8); - vec4 colors[5] = vec4[]( - uGradient1, - uGradient2, - uGradient3, - uGradient4, - uGradient5 - ); - - if (v < steps[0]) { - return colors[0]; - } - - for (int i=0; i<4; ++i) { - if (v <= steps[i+1]) { - return mix(colors[i], colors[i+1], vec4(v - steps[i])/(steps[i+1]-steps[i])); - } - } - - return colors[4]; - } - - // This method requires the uniforms from standardUniforms() to be available. - // It returns two values: The first is an alpha value which can be used for the window - // texture. This gradually dissolves the window from top to bottom. The second can be used - // to mask any effect, it will be most opaque where the window is currently fading and - // gradually dissolve to zero over time. - // hideTime: A value in [0..1]. It determines the percentage of the animation which - // is spent for hiding the window. 1-hideTime will be spent thereafter for - // dissolving the effect mask. - // fadeWidth: The relative size of the window-hiding gradient in [0..1]. - // edgeFadeWidth: The pixel width of the effect fading range at the edges of the window. - vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) { - float burnProgress = clamp(uProgress/hideTime, 0, 1); - float afterBurnProgress = clamp((uProgress-hideTime)/(1-hideTime), 0, 1); - - // Gradient from top to bottom. - float t = cogl_tex_coord_in[0].t * (1 - fadeWidth); - - // Visible part of the window. Gradually dissolves towards the bottom. - float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1); - - // Gradient from top burning window. - float effectMask = clamp(t*(1-windowMask)/burnProgress, 0, 1); - - // Fade-out when the window burned down. - if (uProgress > hideTime) { - float fade = sqrt(1-afterBurnProgress*afterBurnProgress); - effectMask *= mix(1, 1-t, afterBurnProgress) * fade; - } - - // Fade at window borders. - effectMask *= getAbsoluteEdgeMask(edgeFadeWidth); - - if (uForOpening) { - windowMask = 1.0 - windowMask; - } - - return vec2(windowMask, effectMask); - } - `; - - const code = ` - // Get a noise value which moves vertically in time. - vec2 uv = cogl_tex_coord_in[0].st * uSize / vec2(400, 600) / uScale; - uv.y += uTime * uMovementSpeed; - - float noise = u3DNoise ? simplex3DFractal(vec3(uv*4.0, uTime*uMovementSpeed*1.5)) - : simplex2DFractal(uv * 4.0); - - // Modulate noise by effect mask. - vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE); - noise *= effectMask.y; - - // Map noise value to color. - vec4 fire = getFireColor(noise); - - // Get the window texture. - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - // Fade the window according to the effect mask. - cogl_color_out.a *= effectMask.x; - - // Add the fire to the window. - cogl_color_out = alphaOver(cogl_color_out, fire); - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(noise), 1); - // cogl_color_out = vec4(vec3(effectMask.x), 1); - // cogl_color_out = vec4(vec3(effectMask.y), 1); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/Hexagon.js b/src/Hexagon.js index 78f6fa1..8971219 100644 --- a/src/Hexagon.js +++ b/src/Hexagon.js @@ -136,7 +136,6 @@ var Hexagon = class Hexagon { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -183,129 +182,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { + const decl = + utils.loadGLSLResource(`/shaders/${Hexagon.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${Hexagon.getNick()}.glsl`); - // Feel free to read the inline comments below to learn how this shader works. - const declarations = ` - - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - - uniform bool uAdditiveBlending; - uniform vec2 uSeed; - uniform float uScale; - uniform float uLineWidth; - uniform vec4 uGlowColor; - uniform vec4 uLineColor; - - // This methods generates a procedural hexagonal pattern. It returns four values: - // result.xy: This contains cell-relative coordinates for the given point. - // [0, 0] is in the center of a cell, [0, 1] at the upper edge, - // [sqrt(4.0 / 3.0), 0] at the right tip and so on. - // result.z: This is the distance to the closest edge. This is used for shrinking - // of the tiles and the sharp overlay lines. - // result.w: This is the distance to the closest cell center. This is used for - // the glow effect. - vec4 getHexagons(vec2 p) { - - // Length of a cell's edge. - const float edgeLength = sqrt(4.0 / 3.0); - - // The hexgrid repeats after this distance. - const vec2 scale = vec2(3.0 * edgeLength, 2.0); - - // This is a repeating grid of scale-sized cells. Y-values are in the - // interval [-1...1], X-value in [-1.5*edgeLength...1.5*edgeLength]. - vec2 a = mod(p, scale) - scale * 0.5; - vec2 aAbs = abs(a); - - // This is the same as above, but offset by half scale. - vec2 b = mod(p + scale * 0.5, scale) - scale * 0.5; - vec2 bAbs = abs(b); - - // Distance to closer edge, diagonally or horizontally. - // Once for cell set A and once for cell set B. - float distA = max(aAbs.x / edgeLength + aAbs.y * 0.5, aAbs.y); - float distB = max(bAbs.x / edgeLength + bAbs.y * 0.5, bAbs.y); - - // Minimum of both is distance to closest edge. - float dist = 1.0 - min(distA, distB); - - // We use the radial distance to the center for glow. - float glow = min(dot(a, a), dot(b, b)) / 1.5; - - // Take cell-relative coordinates from the closer cell. - vec2 cellCoords = distA < distB ? a : b; - - return vec4(cellCoords, dist, glow); - } - `; - - const code = ` - // We simply inverse the progress for opening windows. - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // Add some smooth noise to the progress so that not every tile behaves the - // same. - float noise = simplex2D(cogl_tex_coord_in[0].st + uSeed); - progress = clamp(mix(noise - 1.0, noise + 1.0, progress), 0.0, 1.0); - - // glowProgress fades in in the first half of the animation, tileProgress fades - // in in the second half. - float glowProgress = smoothstep(0, 1, clamp(progress / 0.5, 0, 1)); - float tileProgress = smoothstep(0, 1, clamp((progress - 0.5) / 0.5, 0, 1)); - - vec2 texScale = 0.1 * uSize / uScale; - vec4 hex = getHexagons(cogl_tex_coord_in[0].st * texScale); - - if (tileProgress > hex.z) { - - // Crop outer parts of the shrinking tiles. - cogl_color_out.a = 0.0; - - } else { - - // Make the tiles shrink by offsetting the texture lookup towards the edge - // of the cell. - vec2 lookupOffset = tileProgress * hex.xy / texScale / (1.0 - tileProgress); - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st + lookupOffset); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - vec4 glow = uGlowColor; - vec4 line = uLineColor; - - // For the glow, we accumulate a few exponentially scaled versions of hex.w. - glow.a *= pow(hex.w, 20.0) * 10.0 + - pow(hex.w, 10.0) * 5.0 + - pow(hex.w, 2.0) * 0.5; - - // Using step(uLineWidth, hex.z) would be simpler, but the below creates some - // fake antialiasing. - line.a *= 1.0 - smoothstep(uLineWidth*0.02*0.5, uLineWidth*0.02, hex.z); - - // Fade in the glowing lines. - glow.a *= glowProgress; - line.a *= glowProgress; - - // Do not add the hexagon lines onto transparent parts of the window. - glow *= cogl_color_out.a; - line *= cogl_color_out.a; - - if (uAdditiveBlending) { - cogl_color_out.rgb += glow.rgb * glow.a; - cogl_color_out.rgb += line.rgb * line.a; - } else { - cogl_color_out.rgb = mix(cogl_color_out.rgb, glow.rgb, glow.a); - cogl_color_out.rgb = mix(cogl_color_out.rgb, line.rgb, line.a); - } - } - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/Matrix.js b/src/Matrix.js index 7b5161d..f0b0c04 100644 --- a/src/Matrix.js +++ b/src/Matrix.js @@ -145,7 +145,6 @@ var Matrix = class Matrix { if (utils.isInShellProcess()) { const {Clutter, GdkPixbuf, Cogl, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -197,107 +196,11 @@ if (utils.isInShellProcess()) { // https://www.shadertoy.com/view/ldccW4, however the implementation is quite // different as the letters drop only once and there is no need for a noise texture. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.edgeMask()} - ${shaderSnippets.compositing()} + const decl = + utils.loadGLSLResource(`/shaders/${Matrix.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${Matrix.getNick()}.glsl`); - uniform sampler2D uFontTexture; - uniform vec3 uTrailColor; - uniform vec3 uTipColor; - uniform float uLetterSize; - uniform float uRandomness; - uniform float uOverShoot; - - // These may be configurable in the future. - const float EDGE_FADE = 30; - const float FADE_WIDTH = 150; - const float TRAIL_LENGTH = 0.2; - const float FINAL_FADE_START_TIME = 0.8; - const float LETTER_TILES = 16.0; - const float LETTER_FLICKER_SPEED = 2.0; - - // This returns a flickering grid of random letters. - float getText(vec2 fragCoord) { - vec2 pixelCoords = fragCoord * uSize; - vec2 uv = mod(pixelCoords.xy, uLetterSize)/uLetterSize; - vec2 block = pixelCoords/uLetterSize - uv; - - // Choose random letter. - uv += floor(hash22(floor(hash22(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES); - - return texture2D(uFontTexture, uv/LETTER_TILES).r; - } - - // This returns two values: The first are gradients for the "raindrops" which move - // from top to bottom. This is used for fading the letters. The second value is set - // to one below each drop and to zero above it. This second value is used for fading - // the window texture. - vec2 getRain(vec2 fragCoord) { - float column = cogl_tex_coord_in[0].x * uSize.x; - column -= mod(column, uLetterSize); - - float delay = fract(sin(column)*78.233) * mix(0.0, 1.0, uRandomness); - float speed = fract(cos(column)*12.989) * mix(0.0, 0.3, uRandomness) + 1.5; - - float distToDrop = (uProgress*2-delay)*speed - cogl_tex_coord_in[0].y; - - float rainAlpha = distToDrop >= 0 ? exp(-distToDrop/TRAIL_LENGTH) : 0; - float windowAlpha = 1 - clamp(uSize.y*distToDrop, 0, FADE_WIDTH) / FADE_WIDTH; - - // Fade at window borders. - rainAlpha *= getAbsoluteEdgeMask(EDGE_FADE); - - // Add some variation to the drop start and end position. - float shorten = fract(sin(column+42.0)*33.423) * mix(0.0, uOverShoot*0.25, uRandomness); - rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1)); - rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1)); - - if (uForOpening) { - windowAlpha = 1.0 - windowAlpha; - } - - return vec2(rainAlpha, windowAlpha); - } - `; - - const code = ` - vec2 coords = cogl_tex_coord_in[0].st; - coords.y = coords.y * (uOverShoot + 1.0) - uOverShoot * 0.5; - - // Get a cool matrix effect. See comments for those methods above. - vec2 rainMask = getRain(coords); - float textMask = getText(coords); - - // Get the window texture. - cogl_color_out = texture2D(uTexture, coords); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - // Fade the window according to the effect mask. - cogl_color_out.a *= rainMask.y; - - // This is used to fade out the remaining trails in the end. - float finalFade = 1-clamp((uProgress-FINAL_FADE_START_TIME)/ - (1-FINAL_FADE_START_TIME), 0, 1); - float rainAlpha = finalFade * rainMask.x; - - // Add the matrix effect to the window. - vec4 text = vec4(mix(uTrailColor, uTipColor, min(1, pow(rainAlpha+0.1, 4))), rainAlpha * textMask); - cogl_color_out = alphaOver(cogl_color_out, text); - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(textMask), 1); - // cogl_color_out = vec4(vec3(rainMask.x), 1); - // cogl_color_out = vec4(vec3(rainMask.y), 1); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } // This is overridden to bind the font texture for drawing. Sadly, this seems to be diff --git a/src/SnapOfDisintegration.js b/src/SnapOfDisintegration.js index 983b0ed..1dcdf54 100644 --- a/src/SnapOfDisintegration.js +++ b/src/SnapOfDisintegration.js @@ -143,7 +143,6 @@ var SnapOfDisintegration = class SnapOfDisintegration { if (utils.isInShellProcess()) { const {Clutter, GdkPixbuf, Cogl, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -190,99 +189,12 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.math2D()} + const decl = utils.loadGLSLResource( + `/shaders/${SnapOfDisintegration.getNick()}-declarations.glsl`); + const code = + utils.loadGLSLResource(`/shaders/${SnapOfDisintegration.getNick()}.glsl`); - uniform sampler2D uDustTexture; - uniform vec4 uDustColor; - uniform vec2 uSeed; - uniform float uDustScale; - - const float DUST_LAYERS = 4; - const float GROW_INTENSITY = 0.05; - const float SHRINK_INTENSITY = 0.05; - const float WIND_INTENSITY = 0.05; - const float ACTOR_SCALE = 1.2; - const float PADDING = ACTOR_SCALE / 2.0 - 0.5; - `; - - const code = ` - // We simply inverse the progress for opening windows. - float progress = uForOpening ? uProgress : 1.0 - uProgress; - - float gradient = cogl_tex_coord_in[0].t * ACTOR_SCALE - PADDING; - progress = 2.0 - gradient - 2.0 * progress; - progress = progress + 0.25 - 0.5 * simplex2D((cogl_tex_coord_in[0].st + uSeed) * 2.0); - progress = pow(max(0, progress), 2.0); - - // This may help you to understand how this effect works. - // cogl_color_out = vec4(progress, 0, 0, 0); - // return; - - cogl_color_out = vec4(0, 0, 0, 0); - - for (float i=0; i 0) { - direction *= -1; - } - - // Flip direction for half the layers. - if (factor > 0.5) { - direction *= -1; - } - - // We grow the layer along the random direction, shrink it orthogonally to it - // and scale it up slightly. - float dist = distToLine(vec2(0.0), direction, coords); - vec2 grow = direction * dist * mix(0, GROW_INTENSITY, progress); - vec2 shrink = vec2(direction.y, -direction.x) * dist * mix(0, SHRINK_INTENSITY, progress); - float scale = mix(1.0, 1.05, factor * progress); - coords = (coords + grow + shrink) / scale; - - // Add some wind. - coords.x += WIND_INTENSITY * progress * (uForOpening ? 1.0 : -1.0); - - // Now check wether there is actually something in the current dust layer at - // the coords position. - vec2 dustCoords = (coords + uSeed) * uSize / uDustScale / 100.0; - vec2 dustMap = texture2D(uDustTexture, dustCoords).rg; - float dustGroup = floor(dustMap.g * DUST_LAYERS * 0.999); - - if (dustGroup == i) { - - // Get the window color. - vec4 windowColor = texture2D(uTexture, coords + 0.5); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (windowColor.a > 0) { - windowColor.rgb /= windowColor.a; - } - - // Fade the window color to uDustColor. - vec3 dustColor = mix(windowColor.rgb, uDustColor.rgb, uDustColor.a); - windowColor.rgb = mix(windowColor.rgb, dustColor, progress); - - // Dissolve and blend the layers. - if (dustMap.x - progress > 0) { - cogl_color_out = windowColor; - } - } - } - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } // This is overridden to bind the dust texture for drawing. Sadly, this seems to be diff --git a/src/TRexAttack.js b/src/TRexAttack.js index 31a4d1f..e2caa63 100644 --- a/src/TRexAttack.js +++ b/src/TRexAttack.js @@ -140,7 +140,6 @@ var TRexAttack = class TRexAttack { if (utils.isInShellProcess()) { const {Clutter, GdkPixbuf, Cogl, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -190,117 +189,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.compositing()} + const decl = + utils.loadGLSLResource(`/shaders/${TRexAttack.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${TRexAttack.getNick()}.glsl`); - // See assets/README.md for how this texture was created. - uniform sampler2D uClawTexture; - uniform vec4 uFlashColor; - uniform vec2 uSeed; - uniform float uClawSize; - uniform float uNumClaws; - uniform float uWarpIntensity; - - const float FLASH_INTENSITY = 0.1; - const float MAX_SPAWN_TIME = 0.6; // Scratches will only start in the first half of the animation. - const float FF_TIME = 0.6; // Relative time for the final fade to transparency. - - // This method generates a grid of randomly rotated, slightly shifted and scaled - // UV squares. It returns the texture coords of the UV square at the given actor - // coordinates. If these do not fall into one of the UV grids, the coordinates of - // the closest UV grid will be clamped and returned. - vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) { - - // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. - vec2 coords = texCoords + hash22(seed); - coords *= uSize.x < uSize.y ? vec2(1.0, 1.0 * uSize.y / uSize.x) : vec2(1.0 * uSize.x / uSize.y, 1.0); - - // Apply global scale. - coords *= gridScale; - - // Get grid cell coordinates in [0..1]. - vec2 cellUV = mod(coords, vec2(1)); - - // This is unique for each cell. - vec2 cellID = coords-cellUV + vec2(362.456); - - // Add random rotation, scale and offset to each grid cell. - float scale = mix(0.8, 1.0, hash12(cellID*seed*134.451)); - float offsetX = mix(0.0, 1.0 - scale, hash12(cellID*seed*54.4129)); - float offsetY = mix(0.0, 1.0 - scale, hash12(cellID*seed*25.3089)); - float rotation = mix(0.0, 2.0 * 3.141, hash12(cellID*seed*2.99837)); - - cellUV -= vec2(offsetX, offsetY); - cellUV /= scale; - - cellUV -= 0.5; - cellUV = vec2(cellUV.x * cos(rotation) - cellUV.y * sin(rotation), - cellUV.x * sin(rotation) + cellUV.y * cos(rotation)); - cellUV += 0.5; - - // Clamp resulting coordinates. - return clamp(cellUV, vec2(0), vec2(1)); - } - `; - - const code = ` - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // Warp the texture coordinates to create a blow-up effect. - vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0; - float dist = length(coords); - coords = (coords/dist * pow(dist, 1.0 + uWarpIntensity)) * 0.5 + 0.5; - coords = mix(cogl_tex_coord_in[0].st, coords, progress); - - // Accumulate several random scratches. The color in the scratch map refers to the - // relative time when the respective part will become invisible. Therefore we can - // add a value to make the scratch appear later. - float scratchMap = 1.0; - for (int i=0; i 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - // Add colorful flashes. - float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1; - if (flashIntensity < 0 || flashIntensity >= 1) { - flashIntensity = 0; - } - - // Hide flashes where there is now window. - vec4 flash = uFlashColor; - flash.a *= flashIntensity * cogl_color_out.a * (1.0 - progress); - - // Hide scratched out parts. - cogl_color_out.a *= (scratchMap > progress ? 1 : 0); - - // Add flash color. - cogl_color_out = alphaOver(cogl_color_out, flash); - - // Fade out the remaining shards. - float fadeProgress = smoothstep(0, 1, (progress - 1.0 + FF_TIME)/FF_TIME); - cogl_color_out.a *= sqrt(1-fadeProgress*fadeProgress); - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(flashIntensity), 1); - // cogl_color_out = vec4(vec3(scratchMap), 1); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } // This is overridden to bind the claw texture for drawing. Sadly, this seems to be diff --git a/src/TVEffect.js b/src/TVEffect.js index 19eb601..4e3ada6 100644 --- a/src/TVEffect.js +++ b/src/TVEffect.js @@ -133,7 +133,6 @@ var TVEffect = class TVEffect { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -160,64 +159,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} + const decl = + utils.loadGLSLResource(`/shaders/${TVEffect.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${TVEffect.getNick()}.glsl`); - uniform vec3 uColor; - - const float BLUR_WIDTH = 0.01; // Width of the gradients. - const float TB_TIME = 0.7; // Relative time for the top/bottom animation. - const float LR_TIME = 0.4; // Relative time for the left/right animation. - const float LR_DELAY = 0.6; // Delay after which the left/right animation starts. - const float FF_TIME = 0.1; // Relative time for the final fade to transparency. - `; - - const code = ` - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // All of these are in [0..1] during the different stages of the animation. - // tb refers to the top-bottom animation. - // lr refers to the left-right animation. - // ff refers to the final fade animation. - float tbProgress = smoothstep(0, 1, clamp(progress/TB_TIME, 0, 1)); - float lrProgress = smoothstep(0, 1, clamp((progress - LR_DELAY)/LR_TIME, 0, 1)); - float ffProgress = smoothstep(0, 1, clamp((progress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); - - // This is a top-center-bottom gradient in [0..1..0] - float tb = cogl_tex_coord_in[0].t * 2; - tb = tb < 1 ? tb : 2 - tb; - - // This is a left-center-right gradient in [0..1..0] - float lr = cogl_tex_coord_in[0].s * 2; - lr = lr < 1 ? lr : 2 - lr; - - // Combine the progress values with the gradients to create the alpha masks. - float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1)); - float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1)); - float ffMask = 1 - smoothstep(0, 1, ffProgress); - - // Assemble the final alpha value. - float mask = tbMask * lrMask * ffMask; - - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - cogl_color_out.rgb = mix(cogl_color_out.rgb, uColor * cogl_color_out.a, smoothstep(0, 1, progress)); - cogl_color_out.a *= mask; - - // These are pretty useful for understanding how this works. - // cogl_color_out = vec4(vec3(tbMask), 1); - // cogl_color_out = vec4(vec3(lrMask), 1); - // cogl_color_out = vec4(vec3(ffMask), 1); - // cogl_color_out = vec4(vec3(mask), 1); - `; - - this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, code, true); } }); } \ No newline at end of file diff --git a/src/Wisps.js b/src/Wisps.js index 6d3151e..a13987e 100644 --- a/src/Wisps.js +++ b/src/Wisps.js @@ -133,7 +133,6 @@ var Wisps = class Wisps { if (utils.isInShellProcess()) { const {Clutter, Shell} = imports.gi; - const shaderSnippets = Me.imports.src.shaderSnippets; ShaderClass = GObject.registerClass({}, class ShaderClass extends Shell.GLSLEffect { // This is called when the effect is used for the first time. This can be used to @@ -170,107 +169,11 @@ if (utils.isInShellProcess()) { // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { - const declarations = ` - // Inject some common shader snippets. - ${shaderSnippets.standardUniforms()} - ${shaderSnippets.noise()} - ${shaderSnippets.edgeMask()} - ${shaderSnippets.compositing()} + const decl = + utils.loadGLSLResource(`/shaders/${Wisps.getNick()}-declarations.glsl`); + const code = utils.loadGLSLResource(`/shaders/${Wisps.getNick()}.glsl`); - uniform vec2 uSeed; - uniform vec3 uColor; - uniform float uScale; - - const float WISPS_RADIUS = 20.0; - const float WISPS_SPEED = 10.0; - const float WISPS_SPACING = 40 + WISPS_RADIUS; - const int WISPS_LAYERS = 8; - const float WISPS_IN_TIME = 0.5; - const float WINDOW_OUT_TIME = 1.0; - - // Returns a grid of randomly moving points. Each grid cell contains one point which - // moves on an ellipse. - float getWisps(vec2 texCoords, float gridSize, vec2 seed) { - - // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. - vec2 coords = (texCoords + hash22(seed)) * uSize; - - // Apply global scale. - coords /= gridSize; - - // Get grid cell coordinates in [0..1]. - vec2 cellUV = mod(coords, vec2(1)); - - // This is unique for each cell. - vec2 cellID = coords-cellUV + vec2(362.456); - - // Add random rotation, scale and offset to each grid cell. - float speed = mix(10.0, 15.0, hash12(cellID*seed*134.451)) / gridSize * WISPS_SPEED; - float rotation = mix( 0.0, 6.283, hash12(cellID*seed*54.4129)); - float radius = mix( 0.5, 1.0, hash12(cellID*seed*19.1249)) * WISPS_RADIUS; - float roundness = mix(-1.0, 1.0, hash12(cellID*seed*7.51949)); - - vec2 offset = vec2(sin(speed * (uTime+1)) * roundness, cos(speed * (uTime+1))); - offset *= 0.5 - 0.5 * radius / gridSize; - offset = vec2(offset.x * cos(rotation) - offset.y * sin(rotation), - offset.x * sin(rotation) + offset.y * cos(rotation)); - - cellUV += offset; - - // Use distance to center of shifted / rotated UV coordinates to draw a glaring point. - float dist = length(cellUV - 0.5) * gridSize / radius; - if (dist < 1.0) { - return min(5, 0.01 / pow(dist, 2.0)); - } - - return 0.0; - } - `; - - const code = ` - float progress = uForOpening ? 1.0-uProgress : uProgress; - - // Get the color of the window. - cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); - - // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. - if (cogl_color_out.a > 0) { - cogl_color_out.rgb /= cogl_color_out.a; - } - - // Compute several layers of moving wisps. - vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, progress) + 0.5; - uv /= uScale; - float wisps = 0; - for (int i=0; i. The part between the + // brackets is captured in the named "file" capture group. + code = code.replaceAll(/#include ["<](?.+)[">]/g, (m, p1, p2, str, groups) => { + return loadStringResource('/shaders/' + groups.file); + }); + + // Add a trailing newline. Else the GLSL compiler complains... + return code + '\n'; } \ No newline at end of file