1
0
mirror of https://github.com/rive-app/rive-flutter.git synced 2025-07-14 14:11:01 +08:00

Merge pull request from rive-app/better_controllers

Improving controllers so they can mix animations more easily.
This commit is contained in:
Matt Sullivan
2020-07-17 15:38:43 -07:00
committed by GitHub
9 changed files with 148 additions and 181 deletions

@ -94,7 +94,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.1+3"
version: "0.0.2"
sky_engine:
dependency: transitive
description: flutter

@ -2,9 +2,11 @@ library rive;
export 'package:rive/src/rive_file.dart';
export 'package:rive/src/rive.dart';
export 'package:rive/src/runtime_artboard.dart';
export 'package:rive/src/controllers/simple_controller.dart';
export 'package:rive/src/rive_core/rive_animation_controller.dart';
export 'package:rive/src/controllers/simple_controller.dart';
export 'package:rive/src/controllers/simple_controller.dart';
export 'package:rive/src/rive_core/animation/linear_animation.dart';
export 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
export 'package:rive/src/rive_core/artboard.dart';
export 'package:rive/src/rive_core/shapes/shape.dart';
export 'package:rive/src/rive_core/shapes/paint/fill.dart';

@ -1,5 +1,5 @@
import 'package:rive/src/rive_core/animation/linear_animation.dart';
import 'package:rive/src/rive_core/animation/loop.dart';
import 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
import 'package:rive/src/rive_core/rive_animation_controller.dart';
import 'package:rive/src/runtime_artboard.dart';
@ -7,70 +7,29 @@ import 'package:rive/src/runtime_artboard.dart';
/// by an artist. All playback parameters (looping, speed, keyframes) are artist
/// defined in the Rive editor.
class SimpleAnimation extends RiveAnimationController<RuntimeArtboard> {
LinearAnimation _animation;
double _time = 0;
int _direction = 1;
LinearAnimationInstance _instance;
final String animationName;
SimpleAnimation(this.animationName);
@override
bool init(RuntimeArtboard artboard) {
_animation = artboard.animations.firstWhere(
(animation) => animation.name == animationName,
var animation = artboard.animations.firstWhere(
(animation) =>
animation is LinearAnimation && animation.name == animationName,
orElse: () => null,
) as LinearAnimation;
);
if (animation != null) {
_instance = LinearAnimationInstance(animation as LinearAnimation);
}
isActive = true;
return _animation != null;
return _instance != null;
}
@override
void apply(RuntimeArtboard artboard, double elapsedSeconds) {
_animation.apply(_time, coreContext: artboard);
_time += elapsedSeconds * _animation.speed * _direction;
double frames = _time * _animation.fps;
var start = _animation.enableWorkArea ? _animation.workStart : 0;
var end =
_animation.enableWorkArea ? _animation.workEnd : _animation.duration;
var range = end - start;
switch (_animation.loop) {
case Loop.oneShot:
if (frames > end) {
isActive = false;
frames = end.toDouble();
_time = frames / _animation.fps;
}
break;
case Loop.loop:
if (frames >= end) {
frames = _time * _animation.fps;
frames = start + (frames - start) % range;
_time = frames / _animation.fps;
}
break;
case Loop.pingPong:
// ignore: literal_only_boolean_expressions
while (true) {
if (_direction == 1 && frames >= end) {
_direction = -1;
frames = end + (end - frames);
_time = frames / _animation.fps;
} else if (_direction == -1 && frames < start) {
_direction = 1;
frames = start + (start - frames);
_time = frames / _animation.fps;
} else {
// we're within the range, we can stop fixing. We do this in a
// loop to fix conditions when time has advanced so far that we've
// ping-ponged back and forth a few times in a single frame. We
// want to accomodate for this in cases where animations are not
// advanced on regular intervals.
break;
}
}
break;
_instance.animation.apply(_instance.time, coreContext: artboard);
if (!_instance.advance(elapsedSeconds)) {
isActive = false;
}
}

@ -0,0 +1,58 @@
import 'package:rive/src/rive_core/animation/linear_animation.dart';
import 'package:rive/src/rive_core/animation/loop.dart';
class LinearAnimationInstance {
final LinearAnimation animation;
double _time = 0;
int direction = 1;
LinearAnimationInstance(this.animation);
double get time => _time;
set time(double value) {
if (_time == value) {
return;
}
_time = value;
direction = 1;
}
bool advance(double elapsedSeconds) {
_time += elapsedSeconds * animation.speed * direction;
double frames = _time * animation.fps;
var start = animation.enableWorkArea ? animation.workStart : 0;
var end = animation.enableWorkArea ? animation.workEnd : animation.duration;
var range = end - start;
bool keepGoing = true;
switch (animation.loop) {
case Loop.oneShot:
if (frames > end) {
keepGoing = false;
frames = end.toDouble();
_time = frames / animation.fps;
}
break;
case Loop.loop:
if (frames >= end) {
frames = _time * animation.fps;
frames = start + (frames - start) % range;
_time = frames / animation.fps;
}
break;
case Loop.pingPong:
while (true) {
if (direction == 1 && frames >= end) {
direction = -1;
frames = end + (end - frames);
_time = frames / animation.fps;
} else if (direction == -1 && frames < start) {
direction = 1;
frames = start + (start - frames);
_time = frames / animation.fps;
} else {
break;
}
}
break;
}
return keepGoing;
}
}

@ -189,6 +189,7 @@ class Artboard extends ArtboardBase with ShapePaintContainer {
}
canvas.save();
canvas.clipRect(Rect.fromLTWH(0, 0, width, height));
canvas.translate(width * (originX ?? 0), height * (originY ?? 0));
for (final drawable in _drawables) {
drawable.draw(canvas);
}
@ -202,9 +203,15 @@ class Artboard extends ArtboardBase with ShapePaintContainer {
@override
Mat2D get worldTransform => Mat2D();
@override
void originXChanged(double from, double to) {}
void originXChanged(double from, double to) {
addDirt(ComponentDirt.worldTransform);
}
@override
void originYChanged(double from, double to) {}
void originYChanged(double from, double to) {
addDirt(ComponentDirt.worldTransform);
}
bool internalAddAnimation(Animation animation) {
if (_animations.contains(animation)) {
return false;

@ -12,7 +12,7 @@ class Segment2D {
Vec2D diff;
double lengthSquared;
Segment2D(this.start, this.end);
ProjectionResult projectPoint(Vec2D point) {
ProjectionResult projectPoint(Vec2D point, {bool clamp = true}) {
if (diff == null) {
diff = Vec2D.subtract(Vec2D(), start, end);
lengthSquared = Vec2D.squaredLength(diff);
@ -23,11 +23,13 @@ class Segment2D {
double t = ((point[0] - start[0]) * (end[0] - start[0]) +
(point[1] - start[1]) * (end[1] - start[1])) /
lengthSquared;
if (t < 0.0) {
return ProjectionResult(0, start);
}
if (t > 1.0) {
return ProjectionResult(1, end);
if (clamp) {
if (t < 0.0) {
return ProjectionResult(0, start);
}
if (t > 1.0) {
return ProjectionResult(1, end);
}
}
return ProjectionResult(
t,

@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:rive/src/rive_core/component_dirt.dart';
import 'package:rive/src/rive_core/container_component.dart';
import 'package:rive/src/rive_core/math/aabb.dart';
import 'package:rive/src/rive_core/math/mat2d.dart';
import 'package:rive/src/rive_core/math/vec2d.dart';
import 'package:rive/src/generated/node_base.dart';
@ -127,4 +128,6 @@ class Node extends NodeBase {
super.parentChanged(from, to);
markWorldTransformDirty();
}
AABB get localBounds => AABB.fromValues(x, y, x, y);
}

@ -204,7 +204,10 @@ abstract class Path extends PathBase {
return true;
}
AABB preciseComputeBounds(List<PathVertex> renderPoints, Mat2D transform) {
@override
AABB get localBounds => preciseComputeBounds(renderVertices, Mat2D());
AABB preciseComputeBounds(List<PathVertex> renderPoints, Mat2D transform,
{bool debug = false}) {
if (renderPoints.isEmpty) {
return AABB();
}
@ -230,7 +233,6 @@ abstract class Path extends PathBase {
cin = Vec2D.transformMat2D(Vec2D(), cin, transform);
cout = Vec2D.transformMat2D(Vec2D(), cout, transform);
}
const double epsilon = 0.000000001;
final double startX = lastPoint[0];
final double startY = lastPoint[1];
final double cpX1 = cout[0];
@ -240,121 +242,55 @@ abstract class Path extends PathBase {
final double endX = next[0];
final double endY = next[1];
lastPoint = next;
double extremaX;
double extremaY;
double a, b, c;
if (!(((startX < cpX1) && (cpX1 < cpX2) && (cpX2 < endX)) ||
((startX > cpX1) && (cpX1 > cpX2) && (cpX2 > endX)))) {
a = -startX + (3 * (cpX1 - cpX2)) + endX;
b = 2 * (startX - (2 * cpX1) + cpX2);
c = -startX + cpX1;
double s = (b * b) - (4 * a * c);
if ((s >= 0.0) && (a.abs() > epsilon)) {
if (s == 0.0) {
final double t = -b / (2 * a);
final double tprime = 1.0 - t;
if ((t >= 0.0) && (t <= 1.0)) {
extremaX = ((tprime * tprime * tprime) * startX) +
((3 * tprime * tprime * t) * cpX1) +
((3 * tprime * t * t) * cpX2) +
(t * t * t * endX);
if (extremaX < bounds[0]) {
bounds[0] = extremaX;
}
if (extremaX > bounds[2]) {
bounds[2] = extremaX;
}
}
} else {
s = sqrt(s);
double t = (-b - s) / (2 * a);
double tprime = 1.0 - t;
if ((t >= 0.0) && (t <= 1.0)) {
extremaX = ((tprime * tprime * tprime) * startX) +
((3 * tprime * tprime * t) * cpX1) +
((3 * tprime * t * t) * cpX2) +
(t * t * t * endX);
if (extremaX < bounds[0]) {
bounds[0] = extremaX;
}
if (extremaX > bounds[2]) {
bounds[2] = extremaX;
}
}
t = (-b + s) / (2 * a);
tprime = 1.0 - t;
if ((t >= 0.0) && (t <= 1.0)) {
extremaX = ((tprime * tprime * tprime) * startX) +
((3 * tprime * tprime * t) * cpX1) +
((3 * tprime * t * t) * cpX2) +
(t * t * t * endX);
if (extremaX < bounds[0]) {
bounds[0] = extremaX;
}
if (extremaX > bounds[2]) {
bounds[2] = extremaX;
}
}
}
}
}
if (!(((startY < cpY1) && (cpY1 < cpY2) && (cpY2 < endY)) ||
((startY > cpY1) && (cpY1 > cpY2) && (cpY2 > endY)))) {
a = -startY + (3 * (cpY1 - cpY2)) + endY;
b = 2 * (startY - (2 * cpY1) + cpY2);
c = -startY + cpY1;
double s = (b * b) - (4 * a * c);
if ((s >= 0.0) && (a.abs() > epsilon)) {
if (s == 0.0) {
final double t = -b / (2 * a);
final double tprime = 1.0 - t;
if ((t >= 0.0) && (t <= 1.0)) {
extremaY = ((tprime * tprime * tprime) * startY) +
((3 * tprime * tprime * t) * cpY1) +
((3 * tprime * t * t) * cpY2) +
(t * t * t * endY);
if (extremaY < bounds[1]) {
bounds[1] = extremaY;
}
if (extremaY > bounds[3]) {
bounds[3] = extremaY;
}
}
} else {
s = sqrt(s);
final double t = (-b - s) / (2 * a);
final double tprime = 1.0 - t;
if ((t >= 0.0) && (t <= 1.0)) {
extremaY = ((tprime * tprime * tprime) * startY) +
((3 * tprime * tprime * t) * cpY1) +
((3 * tprime * t * t) * cpY2) +
(t * t * t * endY);
if (extremaY < bounds[1]) {
bounds[1] = extremaY;
}
if (extremaY > bounds[3]) {
bounds[3] = extremaY;
}
}
final double t2 = (-b + s) / (2 * a);
final double tprime2 = 1.0 - t2;
if ((t2 >= 0.0) && (t2 <= 1.0)) {
extremaY = ((tprime2 * tprime2 * tprime2) * startY) +
((3 * tprime2 * tprime2 * t2) * cpY1) +
((3 * tprime2 * t2 * t2) * cpY2) +
(t2 * t2 * t2 * endY);
if (extremaY < bounds[1]) {
bounds[1] = extremaY;
}
if (extremaY > bounds[3]) {
bounds[3] = extremaY;
}
}
}
}
}
_expandBoundsForAxis(bounds, 0, startX, cpX1, cpX2, endX);
_expandBoundsForAxis(bounds, 1, startY, cpY1, cpY2, endY);
}
}
return bounds;
}
}
void _expandBoundsToCubicPoint(AABB bounds, int component, double t, double a,
double b, double c, double d) {
if (t >= 0 && t <= 1) {
var ti = 1 - t;
double extremaY = ((ti * ti * ti) * a) +
((3 * ti * ti * t) * b) +
((3 * ti * t * t) * c) +
(t * t * t * d);
if (extremaY < bounds[component]) {
bounds[component] = extremaY;
}
if (extremaY > bounds[component + 2]) {
bounds[component + 2] = extremaY;
}
}
}
void _expandBoundsForAxis(AABB bounds, int component, double start, double cp1,
double cp2, double end) {
if (!(((start < cp1) && (cp1 < cp2) && (cp2 < end)) ||
((start > cp1) && (cp1 > cp2) && (cp2 > end)))) {
var a = 3 * (cp1 - start);
var b = 3 * (cp2 - cp1);
var c = 3 * (end - cp2);
var d = a - 2 * b + c;
if (d != 0) {
var m1 = -sqrt(b * b - a * c);
var m2 = -a + b;
_expandBoundsToCubicPoint(
bounds, component, -(m1 + m2) / d, start, cp1, cp2, end);
_expandBoundsToCubicPoint(
bounds, component, -(-m1 + m2) / d, start, cp1, cp2, end);
} else if (b != c && d == 0) {
_expandBoundsToCubicPoint(
bounds, component, (2 * b - c) / (2 * (b - c)), start, cp1, cp2, end);
}
var d2a = 2 * (b - a);
var d2b = 2 * (c - b);
if (d2a != b) {
_expandBoundsToCubicPoint(
bounds, component, d2a / (d2a - d2b), start, cp1, cp2, end);
}
}
}

@ -1,6 +1,6 @@
name: rive
description: Rive 2 Flutter Runtime
version: 0.0.1+3
version: 0.0.2
repository: https://github.com/rive-app/rive-flutter
homepage: https://rive.app