diff --git a/lib/app/view/home.dart b/lib/app/view/home.dart index 9e9d998..4a6cb03 100644 --- a/lib/app/view/home.dart +++ b/lib/app/view/home.dart @@ -9,6 +9,7 @@ import 'package:flutter_shaders_example/tutorial/ripple/view/ripple.dart'; import 'package:flutter_shaders_example/tutorial/shader_builder/view/shader_builder_page.dart'; import 'package:flutter_shaders_example/tutorial/shader_mask/view/shader_mask_page.dart'; import 'package:flutter_shaders_example/tutorial/water_ripple/view/water_ripple_page.dart'; +import 'package:flutter_shaders_example/showcase/gradient_flow/view/gradient_flow.dart'; class HomeView extends StatelessWidget { const HomeView({super.key, required this.shader}); @@ -125,6 +126,17 @@ class HomeView extends StatelessWidget { ), ), ), + const SizedBox(height: 16), + Card( + child: ListTile( + title: const Text('gradient flow'), + onTap: () => Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const GradientFlowPage(), + ), + ), + ), + ), ], ), ), diff --git a/lib/showcase/glow_stuff/view/glow_stuff_page.dart b/lib/showcase/glow_stuff/view/glow_stuff_page.dart index d842f6a..355c997 100644 --- a/lib/showcase/glow_stuff/view/glow_stuff_page.dart +++ b/lib/showcase/glow_stuff/view/glow_stuff_page.dart @@ -34,7 +34,7 @@ class GlowStuffView extends StatelessWidget { ), const SliverToBoxAdapter( child: ApplyGlow( - density: 0.40, + density: 0.4, weight: 0.2, child: LongTextExample(), ), diff --git a/lib/showcase/glow_stuff/widgets/apply_glow.dart b/lib/showcase/glow_stuff/widgets/apply_glow.dart index ce91da0..41b6374 100644 --- a/lib/showcase/glow_stuff/widgets/apply_glow.dart +++ b/lib/showcase/glow_stuff/widgets/apply_glow.dart @@ -47,9 +47,9 @@ class _ApplyGlowState extends State { final key = await assetImage.obtainKey(ImageConfiguration.empty); assetImage - .loadBuffer( + .loadImage( key, - PaintingBinding.instance.instantiateImageCodecFromBuffer, + PaintingBinding.instance.instantiateImageCodecWithSize, ) .addListener( ImageStreamListener((image, synchronousCall) { diff --git a/lib/showcase/gradient_flow/view/gradient_flow.dart b/lib/showcase/gradient_flow/view/gradient_flow.dart new file mode 100644 index 0000000..e0a25bd --- /dev/null +++ b/lib/showcase/gradient_flow/view/gradient_flow.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter_shaders/flutter_shaders.dart'; + +class GradientFlowPage extends StatefulWidget { + const GradientFlowPage({super.key}); + + @override + State createState() => _GradientFlowPageState(); +} + +class _GradientFlowPageState extends State + with SingleTickerProviderStateMixin { + late Ticker _ticker; + double _time = 0; + + @override + void initState() { + super.initState(); + _ticker = createTicker((elapsed) { + setState(() { + _time = elapsed.inMilliseconds / 100.0; + }); + }); + _ticker.start(); + } + + @override + void dispose() { + _ticker + ..stop() + ..dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: ShaderBuilder( + (context, shader, child) { + return CustomPaint( + painter: GradientFlowPainter( + shader: shader, + time: _time, + ), + size: MediaQuery.sizeOf(context), + ); + }, + assetKey: 'shaders/gradient_flow.frag', + ), + ); + } +} + +class GradientFlowPainter extends CustomPainter { + const GradientFlowPainter({ + required this.shader, + required this.time, + }); + final FragmentShader shader; + final double time; + + @override + void paint(Canvas canvas, Size size) { + const colorPrimary = Colors.red; + const colorSecondary = Colors.orange; + const colorAccent1 = Colors.redAccent; + const colorAccent2 = Colors.orangeAccent; + + shader + ..setFloat(0, size.width) + ..setFloat(1, size.height) + ..setFloat(2, time) + ..setFloat(3, colorPrimary.r / 255) + ..setFloat(4, colorPrimary.g / 255) + ..setFloat(5, colorPrimary.b / 255) + ..setFloat(6, colorSecondary.r / 255) + ..setFloat(7, colorSecondary.g / 255) + ..setFloat(8, colorSecondary.b / 255) + ..setFloat(9, colorAccent1.r / 255) + ..setFloat(10, colorAccent1.g / 255) + ..setFloat(11, colorAccent1.b / 255) + ..setFloat(12, colorAccent2.r / 255) + ..setFloat(13, colorAccent2.g / 255) + ..setFloat(14, colorAccent2.b / 255); + + final paint = Paint()..shader = shader; + canvas.drawRect(Offset.zero & size, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/tutorial/animated_shader_mask/view/animated_shader_mask_page.dart b/lib/tutorial/animated_shader_mask/view/animated_shader_mask_page.dart index c595e32..e8d5274 100644 --- a/lib/tutorial/animated_shader_mask/view/animated_shader_mask_page.dart +++ b/lib/tutorial/animated_shader_mask/view/animated_shader_mask_page.dart @@ -48,10 +48,11 @@ class _AnimatedShaderMaskPageState extends State shader ..setFloat(0, bounds.width * _controller.value) ..setFloat(1, bounds.height) - ..setFloat(2, color.red.toDouble() / 255) - ..setFloat(3, color.green.toDouble() / 255) - ..setFloat(4, color.blue.toDouble() / 255) - ..setFloat(5, color.alpha.toDouble() / 255); + ..setFloat(2, color.r.toDouble() / 255) + ..setFloat(3, color.g.toDouble() / 255) + ..setFloat(4, color.b.toDouble() / 255) + ..setFloat(5, color.a.toDouble() / 255); + return shader; }, child: child, diff --git a/lib/tutorial/animated_shader_mask_on_screen/view/animated_shader_mask_on_screen_page.dart b/lib/tutorial/animated_shader_mask_on_screen/view/animated_shader_mask_on_screen_page.dart index 6edd688..0f917d2 100644 --- a/lib/tutorial/animated_shader_mask_on_screen/view/animated_shader_mask_on_screen_page.dart +++ b/lib/tutorial/animated_shader_mask_on_screen/view/animated_shader_mask_on_screen_page.dart @@ -42,10 +42,11 @@ class _AnimatedShaderMaskOnScreenPageState shader ..setFloat(0, bounds.width * _controller.value) ..setFloat(1, bounds.height) - ..setFloat(2, color.red.toDouble() / 255) - ..setFloat(3, color.green.toDouble() / 255) - ..setFloat(4, color.blue.toDouble() / 255) - ..setFloat(5, color.alpha.toDouble() / 255); + ..setFloat(2, color.r.toDouble() / 255) + ..setFloat(3, color.g.toDouble() / 255) + ..setFloat(4, color.b.toDouble() / 255) + ..setFloat(5, color.a.toDouble() / 255); + return shader; }, child: child, diff --git a/lib/tutorial/gradient/view/gradient_page.dart b/lib/tutorial/gradient/view/gradient_page.dart index 163fb18..cff9441 100644 --- a/lib/tutorial/gradient/view/gradient_page.dart +++ b/lib/tutorial/gradient/view/gradient_page.dart @@ -59,10 +59,10 @@ class MyPainter extends CustomPainter { shader ..setFloat(0, size.width) ..setFloat(1, size.height) - ..setFloat(2, color.red.toDouble() / 255) - ..setFloat(3, color.green.toDouble() / 255) - ..setFloat(4, color.blue.toDouble() / 255) - ..setFloat(5, color.alpha.toDouble() / 255); + ..setFloat(2, color.r.toDouble() / 255) + ..setFloat(3, color.g.toDouble() / 255) + ..setFloat(4, color.b.toDouble() / 255) + ..setFloat(5, color.a.toDouble() / 255); canvas.drawRect( Offset.zero & size, diff --git a/lib/tutorial/ripple/view/ripple.dart b/lib/tutorial/ripple/view/ripple.dart index f0a9676..68734f4 100644 --- a/lib/tutorial/ripple/view/ripple.dart +++ b/lib/tutorial/ripple/view/ripple.dart @@ -19,7 +19,7 @@ class RipplePage extends StatefulWidget { class _RipplePageState extends State with SingleTickerProviderStateMixin { - double sliderValue = 0; + double _sliderValue = 0; late final AnimationController _controller = AnimationController( duration: const Duration(seconds: 2), vsync: this, @@ -95,10 +95,10 @@ class _RipplePageState extends State Slider( activeColor: Colors.purple, inactiveColor: Colors.blue, - value: sliderValue, + value: _sliderValue, onChanged: (value) { setState(() { - sliderValue = value; + _sliderValue = value; }); }, ), diff --git a/lib/tutorial/shader_mask/view/shader_mask_page.dart b/lib/tutorial/shader_mask/view/shader_mask_page.dart index 7f32734..09bd124 100644 --- a/lib/tutorial/shader_mask/view/shader_mask_page.dart +++ b/lib/tutorial/shader_mask/view/shader_mask_page.dart @@ -24,10 +24,11 @@ class ShaderMaskPage extends StatelessWidget { shader ..setFloat(0, bounds.width) ..setFloat(1, bounds.height) - ..setFloat(2, color.red.toDouble() / 255) - ..setFloat(3, color.green.toDouble() / 255) - ..setFloat(4, color.blue.toDouble() / 255) - ..setFloat(5, color.alpha.toDouble() / 255); + ..setFloat(2, color.r.toDouble() / 255) + ..setFloat(3, color.g.toDouble() / 255) + ..setFloat(4, color.b.toDouble() / 255) + ..setFloat(5, color.a.toDouble() / 255); + return shader; }, child: child, diff --git a/pubspec.yaml b/pubspec.yaml index c867392..7ad09d7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,5 +29,6 @@ flutter: - shaders/water_ripple.frag - shaders/dir_glow.glsl - shaders/halo.frag + - shaders/gradient_flow.frag assets: - assets/ diff --git a/shaders/gradient_flow.frag b/shaders/gradient_flow.frag new file mode 100644 index 0000000..cfec0d7 --- /dev/null +++ b/shaders/gradient_flow.frag @@ -0,0 +1,85 @@ +// shader by https://www.shadertoy.com/user/hahnzhu +// from https://www.shadertoy.com/view/wdyczG + +#version 460 core + +precision mediump float; + +#include + +uniform vec2 iResolution; +uniform float iTime; + +// Uniforms for the gradient colors +uniform vec3 colorPrimary; +uniform vec3 colorSecondary; +uniform vec3 colorAccent1; +uniform vec3 colorAccent2; + + +out vec4 fragColor; + +#define S(a,b,t) smoothstep(a,b,t) + +mat2 Rot(float a) +{ + float s = sin(a); + float c = cos(a); + return mat2(c, -s, s, c); +} + +// Created by inigo quilez - iq/2014 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +vec2 hash( vec2 p ) +{ + p = vec2( dot(p,vec2(2127.1,81.17)), dot(p,vec2(1269.5,283.37)) ); + return fract(sin(p)*43758.5453); +} + +float noise( in vec2 p ) +{ + vec2 i = floor( p ); + vec2 f = fract( p ); + + vec2 u = f*f*(3.0-2.0*f); + + float n = mix( mix( dot( -1.0+2.0*hash( i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), + dot( -1.0+2.0*hash( i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), + mix( dot( -1.0+2.0*hash( i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), + dot( -1.0+2.0*hash( i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y); + return 0.5 + 0.5*n; +} + +void main() { + vec2 fragCoord = FlutterFragCoord().xy; + + vec2 uv = fragCoord / iResolution.xy ; + float ratio = iResolution.x / iResolution.y; + + vec2 tuv = uv; + tuv -= .5; + + // rotate with Noise + float degree = noise(vec2(iTime*.1, tuv.x*tuv.y)); + + tuv.y *= 1./ratio; + tuv *= Rot(radians((degree-.5)*720.+180.)); + tuv.y *= ratio; + + // Wave warp with sin + float frequency = 5.; + float amplitude = 30.; + float speed = iTime * 2.; + tuv.x += sin(tuv.y*frequency+speed)/amplitude; + tuv.y += sin(tuv.x*frequency*1.5+speed)/(amplitude*.5); + + // draw the image + vec3 layer1 = mix(colorPrimary, colorSecondary, S(-.3, .2, (tuv*Rot(radians(-5.))).x)); + vec3 layer2 = mix(colorAccent1, colorAccent2, S(-.3, .2, (tuv*Rot(radians(-5.))).x)); + + vec3 finalComp = mix(layer1, layer2, S(.5, -.3, tuv.y)); + + vec3 col = finalComp; + + fragColor = vec4(col, 1.0); +} \ No newline at end of file