diff --git a/src/libprojectM/Renderer/CMakeLists.txt b/src/libprojectM/Renderer/CMakeLists.txt index 35b94b1e5..6ec823d6e 100644 --- a/src/libprojectM/Renderer/CMakeLists.txt +++ b/src/libprojectM/Renderer/CMakeLists.txt @@ -1,6 +1,10 @@ set(TRANSITION_SHADER_FILES + TransitionShaders/TransitionShaderBuiltInCircleGlsl330.frag + TransitionShaders/TransitionShaderBuiltInPlasmaGlsl330.frag TransitionShaders/TransitionShaderBuiltInSimpleBlendGlsl330.frag TransitionShaders/TransitionShaderBuiltInSweepGlsl330.frag + TransitionShaders/TransitionShaderBuiltInWarpGlsl330.frag + TransitionShaders/TransitionShaderBuiltInZoomBlurGlsl330.frag TransitionShaders/TransitionVertexShaderGlsl330.vert TransitionShaders/TransitionShaderHeaderGlsl330.frag TransitionShaders/TransitionShaderMainGlsl330.frag diff --git a/src/libprojectM/Renderer/TransitionShaderManager.cpp b/src/libprojectM/Renderer/TransitionShaderManager.cpp index 424f4ea3b..3e5a9a780 100644 --- a/src/libprojectM/Renderer/TransitionShaderManager.cpp +++ b/src/libprojectM/Renderer/TransitionShaderManager.cpp @@ -2,11 +2,17 @@ #include "BuiltInTransitionsResources.hpp" +#include + TransitionShaderManager::TransitionShaderManager() - : m_mersenneTwister(m_randomDevice()) + : m_transitionShaders({CompileTransitionShader(kTransitionShaderBuiltInCircleGlsl330), + CompileTransitionShader(kTransitionShaderBuiltInPlasmaGlsl330), + CompileTransitionShader(kTransitionShaderBuiltInSimpleBlendGlsl330), + CompileTransitionShader(kTransitionShaderBuiltInSweepGlsl330), + CompileTransitionShader(kTransitionShaderBuiltInWarpGlsl330), + CompileTransitionShader(kTransitionShaderBuiltInZoomBlurGlsl330)}) + , m_mersenneTwister(m_randomDevice()) { - m_transitionShaders.push_back(CompileTransitionShader(kTransitionShaderBuiltInSimpleBlendGlsl330)); - m_transitionShaders.push_back(CompileTransitionShader(kTransitionShaderBuiltInSweepGlsl330)); } auto TransitionShaderManager::RandomTransition() -> std::shared_ptr @@ -22,12 +28,12 @@ auto TransitionShaderManager::RandomTransition() -> std::shared_ptr auto TransitionShaderManager::CompileTransitionShader(const std::string& shaderBodyCode) -> std::shared_ptr { #if USE_GLES - std::string versionHeader{"#version 300 es\n\n"}; + constexpr char versionHeader[] = "#version 300 es\n\n"; #else - std::string versionHeader{"#version 330\n\n"}; + constexpr char versionHeader[] = "#version 330\n\n"; #endif - std::string fragmentShaderSource(versionHeader); + std::string fragmentShaderSource(static_cast(versionHeader)); fragmentShaderSource.append(kTransitionShaderHeaderGlsl330); fragmentShaderSource.append("\n"); fragmentShaderSource.append(shaderBodyCode); @@ -37,7 +43,7 @@ auto TransitionShaderManager::CompileTransitionShader(const std::string& shaderB try { auto transitionShader = std::make_shared(); - transitionShader->CompileProgram(versionHeader + kTransitionVertexShaderGlsl330, fragmentShaderSource); + transitionShader->CompileProgram(static_cast(versionHeader) + kTransitionVertexShaderGlsl330, fragmentShaderSource); return transitionShader; } catch (const ShaderException& ex) diff --git a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInCircleGlsl330.frag b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInCircleGlsl330.frag new file mode 100644 index 000000000..d940625a4 --- /dev/null +++ b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInCircleGlsl330.frag @@ -0,0 +1,52 @@ +// Circular blend with soft edge, inside-out or outside-in +// Source: https://www.shadertoy.com/view/NdGfzG +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord / iResolution.xy; + float aspect = iResolution.y / iResolution.x; + + // Randomize direction and edge width + float inOrOut = mod(float(iRandStatic.x) * .01, 2.); + + float progress; + vec3 imgInner, imgOuter; + if (inOrOut < 1.) + { + imgInner = texture(iChannel0, uv).xyz; + imgOuter = texture(iChannel1, uv).xyz; + progress = iProgressCosine; + } + else + { + imgOuter = texture(iChannel0, uv).xyz; + imgInner = texture(iChannel1, uv).xyz; + progress = 1. - iProgressCosine; + } + float blendWidth = mod(float(iRandStatic.y) * .001, .1) + .05; + progress = progress * (1. + blendWidth) - blendWidth; + + // Blending + vec2 center = vec2(.5); + float rad = sqrt(center.x / aspect * center.x / aspect + center.y * center.y) * progress; + float rad2 = rad + blendWidth; + float r1 = sqrt((uv.x - center.x) / aspect * (uv.x - center.x) / aspect + (uv.y - center.y) * (uv.y - center.y)); + + vec3 col; + if (r1 > rad2) + { + col = imgInner; + } + else if (r1 > rad) + { + float v1=(r1-rad)/(rad2-rad); + float v2 = 1.0 - v1; + col = v1 * imgInner + v2 * imgOuter; + } + else + { + col = imgOuter; + } + + // Output to screen + fragColor = vec4(col, 1.0); +} diff --git a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInPlasmaGlsl330.frag b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInPlasmaGlsl330.frag new file mode 100644 index 000000000..be2181a3d --- /dev/null +++ b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInPlasmaGlsl330.frag @@ -0,0 +1,55 @@ +// Fractal, plasma-like transition effect with random scales and noise seeds. +// Source: https://www.shadertoy.com/view/MstBzf + +float sinNoise(vec2 uv) +{ + return fract(abs(sin(uv.x * 180.0 + uv.y * 3077.0) * (float(iRandStatic.x) * .001))); +} + +float valueNoise(vec2 uv, float scale) +{ + vec2 luv = fract(uv * scale); + vec2 luvs = smoothstep(0.0, 1.0, fract(uv * scale)); + vec2 id = floor(uv * scale); + float tl = sinNoise(id + vec2(0.0, 1.0)); + float tr = sinNoise(id + vec2(1.0, 1.0)); + float t = mix(tl, tr, luvs.x); + + float bl = sinNoise(id + vec2(0.0, 0.0)); + float br = sinNoise(id + vec2(1.0, 0.0)); + float b = mix(bl, br, luvs.x); + + return mix(b, t, luvs.y) * 2.0 - 1.0; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord/iResolution.xy; + + vec3 imgOld = texture(iChannel0, uv).xyz; + vec3 imgNew = texture(iChannel1, uv).xyz; + + uv.y /= iResolution.x/iResolution.y; + + float sinN = sinNoise(uv); + + float scale = mod(float(iRandStatic.y) * .01, 7.) * 4. + 4.; + + float fractValue = 0.; + float amp = 1.; + for(int i = 0; i < 16; i++) + { + fractValue += valueNoise(uv, float(i + 1) * scale) * amp; + amp *= .5; + } + + fractValue *= .25; + fractValue += .5; + + float cutoff = smoothstep(iProgressCosine + .1, iProgressCosine - .1, fractValue); + vec3 col = mix(imgOld, imgNew, cutoff); + + // Output to screen + fragColor = vec4(col, 1.); +} \ No newline at end of file diff --git a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInSimpleBlendGlsl330.frag b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInSimpleBlendGlsl330.frag index 97e2f1469..2526b8f2c 100644 --- a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInSimpleBlendGlsl330.frag +++ b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInSimpleBlendGlsl330.frag @@ -2,12 +2,9 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord / iResolution.xy; - vec3 imgOld = texture(iChannel0, uv).xyz; - vec3 imgNew = texture(iChannel1, uv).xyz; // Blending - vec3 col = vec3((1.0 - iProgressCosine) * imgOld + iProgressCosine * imgNew); - - // Output to screen - fragColor = vec4(col, 1.0); + fragColor = vec4(mix(texture(iChannel0, uv).xyz, + texture(iChannel1, uv).xyz, + iProgressCosine), 1.0); } diff --git a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInWarpGlsl330.frag b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInWarpGlsl330.frag new file mode 100644 index 000000000..073a89be1 --- /dev/null +++ b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInWarpGlsl330.frag @@ -0,0 +1,20 @@ +// Horizontal/vertical warp effect +// Source: https://www.shadertoy.com/view/ssj3Dh +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord / iResolution.xy; + vec3 imgOld = texture(iChannel0, uv).xyz; + vec3 imgNew = texture(iChannel1, uv).xyz; + + // Randomize direction + float direction = mod(float(iRandStatic.x) * .01, 4.); + float coord; + if (direction < 1.) coord = uv.x; + else if (direction < 2.) coord = 1. - uv.x; + else if (direction < 3.) coord = uv.y; + else coord = 1. - uv.y; + + // Blending + float x = smoothstep(.0,1.0,(iProgressCosine * 2.0 + coord - 1.0)); + fragColor = mix(texture(iChannel0, (uv - .5) * (1. - x) + .5), texture(iChannel1, (uv - .5) * x + .5), x); +} diff --git a/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInZoomBlurGlsl330.frag b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInZoomBlurGlsl330.frag new file mode 100644 index 000000000..b7ffe1715 --- /dev/null +++ b/src/libprojectM/Renderer/TransitionShaders/TransitionShaderBuiltInZoomBlurGlsl330.frag @@ -0,0 +1,56 @@ +const float strength = 0.3; +const float PI = 3.141592653589793; + +float Linear_ease(in float begin, in float change, in float duration, in float time) { + return change * time / duration + begin; +} + +float Exponential_easeInOut(in float begin, in float change, in float duration, in float time) { + if (time == 0.0) + return begin; + else if (time == duration) + return begin + change; + time = time / (duration / 2.0); + if (time < 1.0) + return change / 2.0 * pow(2.0, 10.0 * (time - 1.0)) + begin; + return change / 2.0 * (-pow(2.0, -10.0 * (time - 1.0)) + 2.0) + begin; +} + +float Sinusoidal_easeInOut(in float begin, in float change, in float duration, in float time) { + return -change / 2.0 * (cos(PI * time / duration) - 1.0) + begin; +} + +float random(in vec3 scale, in float seed) { + return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed); +} + +vec3 crossFade(in vec2 uv, in float dissolve) { + return mix(texture(iChannel0, uv).rgb, texture(iChannel1, uv).rgb, dissolve); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 texCoord = fragCoord.xy / iResolution.xy; + float progress = iProgressCosine; + // Linear interpolate center across center half of the image + vec2 center = vec2(Linear_ease(0.5, 0.0, 1.0, progress),0.5); + float dissolve = Exponential_easeInOut(0.0, 1.0, 1.0, progress); + + // Mirrored sinusoidal loop. 0->strength then strength->0 + float strength = Sinusoidal_easeInOut(0.0, strength, 0.5, progress); + + vec3 color = vec3(0.0); + float total = 0.0; + vec2 toCenter = center - texCoord; + + /* randomize the lookup values to hide the fixed number of samples */ + float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0)*0.5; + + for (float t = 0.0; t <= 20.0; t++) { + float percent = (t + offset) / 20.0; + float weight = 1.0 * (percent - percent * percent); + color += crossFade(texCoord + toCenter * percent * strength, dissolve) * weight; + total += weight; + } + + fragColor = vec4(color / total, 1.0); +} \ No newline at end of file