From 67080bb4cc0e920ce9b0f5c559908f3ed6a482a2 Mon Sep 17 00:00:00 2001 From: Grant Skinner Date: Mon, 29 Jan 2024 12:16:04 -0800 Subject: [PATCH] Use published verison of flutter_shaders And minor related doc updates --- example/lib/examples/everything_view.dart | 9 +- example/pubspec.lock | 12 +- lib/src/effects/effects.dart | 1 + lib/src/effects/shader_effect.dart | 290 +--------------------- pubspec.lock | 10 +- pubspec.yaml | 1 + 6 files changed, 36 insertions(+), 287 deletions(-) diff --git a/example/lib/examples/everything_view.dart b/example/lib/examples/everything_view.dart index 4d92d02..72c9dac 100644 --- a/example/lib/examples/everything_view.dart +++ b/example/lib/examples/everything_view.dart @@ -6,7 +6,6 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; -import 'package:flutter_animate/src/effects/shader_effect.dart'; // temporary class EverythingView extends StatelessWidget { static ui.FragmentShader? shader; @@ -129,7 +128,7 @@ class EverythingView extends StatelessWidget { ); })), - // callback + // .callback tile('custom', a.custom(builder: (_, val, child) { val = val * pi * 2 - pi / 2; @@ -139,7 +138,7 @@ class EverythingView extends StatelessWidget { ); })), - // effect + // .effect tile('elevation', a.elevation()), @@ -160,7 +159,7 @@ class EverythingView extends StatelessWidget { ), ), - // listen + // .listen //tile('move', a.move()), tile('moveX', a.moveX()), @@ -193,7 +192,7 @@ class EverythingView extends StatelessWidget { return Opacity(opacity: 0.5, child: child!); })), - // then + // .then tile('tint', a.tint()), tile('untint', a.untint()), diff --git a/example/pubspec.lock b/example/pubspec.lock index c23a505..d4cccbc 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -68,7 +68,7 @@ packages: path: ".." relative: true source: path - version: "4.3.0" + version: "4.4.1" flutter_lints: dependency: "direct dev" description: @@ -77,6 +77,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_shaders: + dependency: transitive + description: + name: flutter_shaders + sha256: "02750b545c01ff4d8e9bbe8f27a7731aa3778402506c67daa1de7f5fc3f4befe" + url: "https://pub.dev" + source: hosted + version: "0.1.2" flutter_test: dependency: "direct dev" description: flutter @@ -193,4 +201,4 @@ packages: version: "0.3.0" sdks: dart: ">=3.2.0-194.0.dev <4.0.0" - flutter: ">=2.0.0" + flutter: ">=3.7.0-0.0" diff --git a/lib/src/effects/effects.dart b/lib/src/effects/effects.dart index ed7f86d..3975b88 100644 --- a/lib/src/effects/effects.dart +++ b/lib/src/effects/effects.dart @@ -17,6 +17,7 @@ export 'move_effect.dart'; export 'rotate_effect.dart'; export 'saturate_effect.dart'; export 'scale_effect.dart'; +export 'shader_effect.dart'; export 'shake_effect.dart'; export 'shimmer_effect.dart'; export 'slide_effect.dart'; diff --git a/lib/src/effects/shader_effect.dart b/lib/src/effects/shader_effect.dart index 52dcbbe..f46161c 100644 --- a/lib/src/effects/shader_effect.dart +++ b/lib/src/effects/shader_effect.dart @@ -1,29 +1,10 @@ import 'dart:ui' as ui; -import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_shaders/flutter_shaders.dart'; import '../../flutter_animate.dart'; -/** - * This is a prerelease effect for Flutter Animate: - * https://pub.dev/packages/flutter_animate - * - * It includes a copy of `AnimatedSampler` from Flutter Shaders: - * https://github.com/jonahwilliams/flutter_shaders - * - * Once `AnimatedSampler` (or equivalent) is stable, or included in the core - * SDK, this effect will be updated, tested, refined, and added to the - * effects.dart file. - * - * To use this effect you must import it directly. It is _not_ included - * in the default exports. - */ - -/// **IMPORTANT:** This is a prerelease shader and may not work properly on all platforms. -/// It is not included in the default exports, you must import it directly to use it. -/// -/// /// Effect that applies an animated fragment shader to a target. See /// [Writing and using fragment shaders](https://docs.flutter.dev/development/ui/advanced/shaders) /// for information on how to include shaders in your app. @@ -41,7 +22,7 @@ import '../../flutter_animate.dart'; /// [update] is an optional callback that allows you to update the shader. It /// is called whenever the animation value changes. It accepts a /// [ShaderUpdateDetails] object. It can update uniforms directly via -/// `setFloat` or `setImageSampler`, or by using [ShaderUpdateDetails.updateUniforms]. +/// `setFloat` or `setImageSampler`, by using [ShaderUpdateDetails.updateUniforms]. /// /// If [update] is not specified, the shader will be updated automatically based /// on the "standardized" uniforms defined in [ShaderUpdateDetails.updateUniforms]. @@ -144,13 +125,16 @@ extension ShaderEffectExtensions> on T { enum ShaderLayer { foreground, background, replace } -/// Passed to the [ShaderEffect.update] callback. Contains information and -/// methods necessary for updating the shader. +/// Passed to the [ShaderEffect.update] callback. Contains information necessary +/// for updating the shader: /// /// [shader] is the shader to update. /// [value] is the current animation value of the effect. /// [size] is the on-screen dimensions of the target. /// [image] is a snapshot of the target, which can be used as an input texture. +/// +/// It also exposes the [updateUniforms] helper method which can be used to update +/// uniforms. Alternatively, you can simply set uniforms on the shader directly. class ShaderUpdateDetails { ShaderUpdateDetails({ required this.shader, @@ -164,8 +148,9 @@ class ShaderUpdateDetails { final Size size; final ui.Image image; - /// Updates uniforms on the shader. It assumes a standardized set of initial - /// uniforms: + /// Optional helper method that updates uniforms on the shader. + /// + /// It assumes a standardized set of initial uniforms: /// - float `0`: width /// - float `1`: height /// - float `2`: value @@ -178,7 +163,7 @@ class ShaderUpdateDetails { /// uniform sampler2D image; // image sampler 0 /// ``` /// - /// You can specify [value] to override the default animation value. + /// You can specify [value] to override the current animation value. /// /// You can also pass additional uniforms via [floats] and [images]. These /// will be set in the shader in the order they are passed. For example, @@ -206,256 +191,3 @@ class ShaderUpdateDetails { /// Function signature for [ShaderEffect] update handlers. typedef ShaderUpdateCallback = EdgeInsets? Function( ShaderUpdateDetails details); - -/******************************************************************************/ -// TODO: add this as a dependency instead of copying it in once it is stable: -// https://github.com/jonahwilliams/flutter_shaders - -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/// A callback for the [AnimatedSamplerBuilder] widget. -typedef AnimatedSamplerBuilder = void Function( - ui.Image image, - Size size, - ui.Canvas canvas, -); - -/// **NOTE: This is included in [ShaderEffect] for now, but will become a dependency -/// once `flutter_shaders` is stable, or similar functionality is added to the SDK.** -/// -/// A widget that allows access to a snapshot of the child widgets for painting -/// with a sampler applied to a [FragmentProgram]. -/// -/// When [enabled] is true, the child widgets will be painted into a texture -/// exposed as a [ui.Image]. This can then be passed to a [FragmentShader] -/// instance via [FragmentShader.setSampler]. -/// -/// If [enabled] is false, then the child widgets are painted as normal. -/// -/// Caveats: -/// * Platform views cannot be captured in a texture. If any are present they -/// will be excluded from the texture. Texture-based platform views are OK. -/// -/// Example: -/// -/// Providing an image to a fragment shader using -/// [FragmentShader.setImageSampler]. -/// -/// ```dart -/// Widget build(BuildContext context) { -/// return AnimatedSampler( -/// (ui.Image image, Size size, Canvas canvas) { -/// shader -/// ..setFloat(0, size.width) -/// ..setFloat(1, size.height) -/// ..setImageSampler(0, image); -/// canvas.drawRect(Offset.zero & size, Paint()..shader = shader); -/// }, -/// child: widget.child, -/// ); -/// } -/// ``` -/// -/// See also: -/// * [SnapshotWidget], which provides a similar API for the purpose of -/// caching during expensive animations. -class AnimatedSampler extends StatelessWidget { - /// Create a new [AnimatedSampler]. - const AnimatedSampler( - this.builder, { - required this.child, - super.key, - this.enabled = true, - }); - - /// A callback used by this widget to provide the children captured in - /// a texture. - final AnimatedSamplerBuilder builder; - - /// Whether the children should be captured in a texture or displayed as - /// normal. - final bool enabled; - - /// The child widget. - final Widget child; - - @override - Widget build(BuildContext context) { - return _ShaderSamplerBuilder( - builder, - enabled: enabled, - child: child, - ); - } -} - -class _ShaderSamplerBuilder extends SingleChildRenderObjectWidget { - const _ShaderSamplerBuilder( - this.builder, { - super.child, - required this.enabled, - }); - - final AnimatedSamplerBuilder builder; - final bool enabled; - - @override - RenderObject createRenderObject(BuildContext context) { - return _RenderShaderSamplerBuilderWidget( - devicePixelRatio: MediaQuery.of(context).devicePixelRatio, - builder: builder, - enabled: enabled, - ); - } - - @override - void updateRenderObject( - BuildContext context, covariant RenderObject renderObject) { - (renderObject as _RenderShaderSamplerBuilderWidget) - ..devicePixelRatio = MediaQuery.of(context).devicePixelRatio - ..builder = builder - ..enabled = enabled; - } -} - -// A render object that conditionally converts its child into a [ui.Image] -// and then paints it in place of the child. -class _RenderShaderSamplerBuilderWidget extends RenderProxyBox { - // Create a new [_RenderSnapshotWidget]. - _RenderShaderSamplerBuilderWidget({ - required double devicePixelRatio, - required AnimatedSamplerBuilder builder, - required bool enabled, - }) : _devicePixelRatio = devicePixelRatio, - _builder = builder, - _enabled = enabled; - - @override - OffsetLayer updateCompositedLayer( - {required covariant _ShaderSamplerBuilderLayer? oldLayer}) { - final _ShaderSamplerBuilderLayer layer = - oldLayer ?? _ShaderSamplerBuilderLayer(builder); - layer - ..callback = builder - ..size = size - ..devicePixelRatio = devicePixelRatio; - return layer; - } - - /// The device pixel ratio used to create the child image. - double get devicePixelRatio => _devicePixelRatio; - double _devicePixelRatio; - set devicePixelRatio(double value) { - if (value == devicePixelRatio) { - return; - } - _devicePixelRatio = value; - markNeedsCompositedLayerUpdate(); - } - - /// The painter used to paint the child snapshot or child widgets. - AnimatedSamplerBuilder get builder => _builder; - AnimatedSamplerBuilder _builder; - set builder(AnimatedSamplerBuilder value) { - if (value == builder) { - return; - } - _builder = value; - markNeedsCompositedLayerUpdate(); - } - - bool get enabled => _enabled; - bool _enabled; - set enabled(bool value) { - if (value == enabled) { - return; - } - _enabled = value; - markNeedsPaint(); - markNeedsCompositingBitsUpdate(); - } - - @override - bool get isRepaintBoundary => alwaysNeedsCompositing; - - @override - bool get alwaysNeedsCompositing => enabled; - - @override - void paint(PaintingContext context, Offset offset) { - if (size.isEmpty) { - return; - } - assert(!_enabled || offset == Offset.zero); - return super.paint(context, offset); - } -} - -/// A [Layer] that uses an [AnimatedSamplerBuilder] to create a [ui.Picture] -/// every time it is added to a scene. -class _ShaderSamplerBuilderLayer extends OffsetLayer { - _ShaderSamplerBuilderLayer(this._callback); - - Size get size => _size; - Size _size = Size.zero; - set size(Size value) { - if (value == size) { - return; - } - _size = value; - markNeedsAddToScene(); - } - - double get devicePixelRatio => _devicePixelRatio; - double _devicePixelRatio = 1.0; - set devicePixelRatio(double value) { - if (value == devicePixelRatio) { - return; - } - _devicePixelRatio = value; - markNeedsAddToScene(); - } - - AnimatedSamplerBuilder get callback => _callback; - AnimatedSamplerBuilder _callback; - set callback(AnimatedSamplerBuilder value) { - if (value == callback) { - return; - } - _callback = value; - markNeedsAddToScene(); - } - - ui.Image _buildChildScene(Rect bounds, double pixelRatio) { - final ui.SceneBuilder builder = ui.SceneBuilder(); - final Matrix4 transform = - Matrix4.diagonal3Values(pixelRatio, pixelRatio, 1); - builder.pushTransform(transform.storage); - addChildrenToScene(builder); - builder.pop(); - return builder.build().toImageSync( - (pixelRatio * bounds.width).ceil(), - (pixelRatio * bounds.height).ceil(), - ); - } - - @override - void addToScene(ui.SceneBuilder builder) { - if (size.isEmpty) return; - final ui.Image image = _buildChildScene( - offset & size, - devicePixelRatio, - ); - final ui.PictureRecorder pictureRecorder = ui.PictureRecorder(); - final Canvas canvas = Canvas(pictureRecorder); - try { - callback(image, size, canvas); - } finally { - image.dispose(); - } - final ui.Picture picture = pictureRecorder.endRecording(); - builder.addPicture(offset, picture); - } -} diff --git a/pubspec.lock b/pubspec.lock index 6e0e115..f1d55b9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -62,6 +62,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_shaders: + dependency: "direct main" + description: + name: flutter_shaders + sha256: "02750b545c01ff4d8e9bbe8f27a7731aa3778402506c67daa1de7f5fc3f4befe" + url: "https://pub.dev" + source: hosted + version: "0.1.2" flutter_test: dependency: "direct dev" description: flutter @@ -178,4 +186,4 @@ packages: version: "0.3.0" sdks: dart: ">=3.2.0-194.0.dev <4.0.0" - flutter: ">=2.0.0" + flutter: ">=3.7.0-0.0" diff --git a/pubspec.yaml b/pubspec.yaml index cb80e0b..54f8c1f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ environment: dependencies: flutter: sdk: flutter + flutter_shaders: ^0.1.2 dev_dependencies: flutter_test: