Skip to content

Commit

Permalink
Adding support for TransformConstraints.
Browse files Browse the repository at this point in the history
  • Loading branch information
luigi-rosso committed Jul 29, 2021
1 parent 1013fa5 commit 8214b5c
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 20 deletions.
78 changes: 78 additions & 0 deletions lib/src/generated/constraints/transform_constraint_base.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/// Core automatically generated
/// lib/src/generated/constraints/transform_constraint_base.dart.
/// Do not modify manually.
import 'package:rive/src/generated/component_base.dart';
import 'package:rive/src/generated/constraints/constraint_base.dart';
import 'package:rive/src/generated/constraints/targeted_constraint_base.dart';
import 'package:rive/src/rive_core/constraints/targeted_constraint.dart';

abstract class TransformConstraintBase extends TargetedConstraint {
static const int typeKey = 83;
@override
int get coreType => TransformConstraintBase.typeKey;
@override
Set<int> get coreTypes => {
TransformConstraintBase.typeKey,
TargetedConstraintBase.typeKey,
ConstraintBase.typeKey,
ComponentBase.typeKey
};

/// --------------------------------------------------------------------------
/// SourceSpaceValue field with key 179.
static const int sourceSpaceValueInitialValue = 0;
int _sourceSpaceValue = sourceSpaceValueInitialValue;
static const int sourceSpaceValuePropertyKey = 179;

/// The source transform space.
int get sourceSpaceValue => _sourceSpaceValue;

/// Change the [_sourceSpaceValue] field value.
/// [sourceSpaceValueChanged] will be invoked only if the field's value has
/// changed.
set sourceSpaceValue(int value) {
if (_sourceSpaceValue == value) {
return;
}
int from = _sourceSpaceValue;
_sourceSpaceValue = value;
if (hasValidated) {
sourceSpaceValueChanged(from, value);
}
}

void sourceSpaceValueChanged(int from, int to);

/// --------------------------------------------------------------------------
/// DestSpaceValue field with key 180.
static const int destSpaceValueInitialValue = 0;
int _destSpaceValue = destSpaceValueInitialValue;
static const int destSpaceValuePropertyKey = 180;

/// The destination transform space.
int get destSpaceValue => _destSpaceValue;

/// Change the [_destSpaceValue] field value.
/// [destSpaceValueChanged] will be invoked only if the field's value has
/// changed.
set destSpaceValue(int value) {
if (_destSpaceValue == value) {
return;
}
int from = _destSpaceValue;
_destSpaceValue = value;
if (hasValidated) {
destSpaceValueChanged(from, value);
}
}

void destSpaceValueChanged(int from, int to);

@override
void copy(TransformConstraintBase source) {
super.copy(source);
_sourceSpaceValue = source._sourceSpaceValue;
_destSpaceValue = source._destSpaceValue;
}
}
30 changes: 30 additions & 0 deletions lib/src/generated/rive_core_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import 'package:rive/src/generated/constraints/constraint_base.dart';
import 'package:rive/src/generated/constraints/distance_constraint_base.dart';
import 'package:rive/src/generated/constraints/ik_constraint_base.dart';
import 'package:rive/src/generated/constraints/targeted_constraint_base.dart';
import 'package:rive/src/generated/constraints/transform_constraint_base.dart';
import 'package:rive/src/generated/draw_rules_base.dart';
import 'package:rive/src/generated/draw_target_base.dart';
import 'package:rive/src/generated/drawable_base.dart';
Expand Down Expand Up @@ -113,6 +114,7 @@ import 'package:rive/src/rive_core/bones/tendon.dart';
import 'package:rive/src/rive_core/bones/weight.dart';
import 'package:rive/src/rive_core/constraints/distance_constraint.dart';
import 'package:rive/src/rive_core/constraints/ik_constraint.dart';
import 'package:rive/src/rive_core/constraints/transform_constraint.dart';
import 'package:rive/src/rive_core/draw_rules.dart';
import 'package:rive/src/rive_core/draw_target.dart';
import 'package:rive/src/rive_core/node.dart';
Expand Down Expand Up @@ -146,6 +148,8 @@ class RiveCoreContext {
return DistanceConstraint();
case IKConstraintBase.typeKey:
return IKConstraint();
case TransformConstraintBase.typeKey:
return TransformConstraint();
case AnimationStateBase.typeKey:
return AnimationState();
case KeyedObjectBase.typeKey:
Expand Down Expand Up @@ -313,6 +317,16 @@ class RiveCoreContext {
object.parentBoneCount = value;
}
break;
case TransformConstraintBase.sourceSpaceValuePropertyKey:
if (object is TransformConstraintBase && value is int) {
object.sourceSpaceValue = value;
}
break;
case TransformConstraintBase.destSpaceValuePropertyKey:
if (object is TransformConstraintBase && value is int) {
object.destSpaceValue = value;
}
break;
case AnimationStateBase.animationIdPropertyKey:
if (object is AnimationStateBase && value is int) {
object.animationId = value;
Expand Down Expand Up @@ -933,6 +947,8 @@ class RiveCoreContext {
case TargetedConstraintBase.targetIdPropertyKey:
case DistanceConstraintBase.modeValuePropertyKey:
case IKConstraintBase.parentBoneCountPropertyKey:
case TransformConstraintBase.sourceSpaceValuePropertyKey:
case TransformConstraintBase.destSpaceValuePropertyKey:
case AnimationStateBase.animationIdPropertyKey:
case KeyedObjectBase.objectIdPropertyKey:
case BlendAnimationBase.animationIdPropertyKey:
Expand Down Expand Up @@ -1089,6 +1105,10 @@ class RiveCoreContext {
return (object as DistanceConstraintBase).modeValue;
case IKConstraintBase.parentBoneCountPropertyKey:
return (object as IKConstraintBase).parentBoneCount;
case TransformConstraintBase.sourceSpaceValuePropertyKey:
return (object as TransformConstraintBase).sourceSpaceValue;
case TransformConstraintBase.destSpaceValuePropertyKey:
return (object as TransformConstraintBase).destSpaceValue;
case AnimationStateBase.animationIdPropertyKey:
return (object as AnimationStateBase).animationId;
case KeyedObjectBase.objectIdPropertyKey:
Expand Down Expand Up @@ -1405,6 +1425,16 @@ class RiveCoreContext {
object.parentBoneCount = value;
}
break;
case TransformConstraintBase.sourceSpaceValuePropertyKey:
if (object is TransformConstraintBase) {
object.sourceSpaceValue = value;
}
break;
case TransformConstraintBase.destSpaceValuePropertyKey:
if (object is TransformConstraintBase) {
object.destSpaceValue = value;
}
break;
case AnimationStateBase.animationIdPropertyKey:
if (object is AnimationStateBase) {
object.animationId = value;
Expand Down
18 changes: 18 additions & 0 deletions lib/src/rive_core/constraints/constraint.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/component.dart';
import 'package:rive/src/rive_core/math/mat2d.dart';
import 'package:rive/src/generated/constraints/constraint_base.dart';
import 'package:rive/src/rive_core/transform_component.dart';
export 'package:rive/src/generated/constraints/constraint_base.dart';
Expand Down Expand Up @@ -29,4 +32,19 @@ abstract class Constraint extends ConstraintBase {
void update(int dirt) {}

void markConstraintDirty() => constrainedComponent?.markTransformDirty();

@override
void onDirty(int mask) => markConstraintDirty();
}

/// Get the parent's world transform. Takes into consideration when the parent
/// is an artboard.
Mat2D parentWorld(TransformComponent component) {
var parent = component.parent;
if (parent is Artboard) {
return parent.worldTransform;
} else if (parent is TransformComponent) {
return parent.worldTransform;
}
return Mat2D();
}
4 changes: 1 addition & 3 deletions lib/src/rive_core/constraints/distance_constraint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:rive/src/generated/constraints/distance_constraint_base.dart';
import 'package:rive/src/rive_core/transform_component.dart';
export 'package:rive/src/generated/constraints/distance_constraint_base.dart';

/// [DistanceConstraint]'s logical distancing method.
enum DistanceConstraintMode { closer, further, exact }

const _distanceEpsilon = 0.001;
Expand Down Expand Up @@ -57,7 +58,4 @@ class DistanceConstraint extends DistanceConstraintBase {

DistanceConstraintMode get mode => DistanceConstraintMode.values[modeValue];
set mode(DistanceConstraintMode value) => modeValue = value.index;

@override
bool validate() => super.validate() && parent is TransformComponent;
}
24 changes: 7 additions & 17 deletions lib/src/rive_core/constraints/ik_constraint.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'dart:math';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/bones/bone.dart';
import 'package:rive/src/rive_core/constraints/constraint.dart';
import 'package:rive/src/rive_core/math/mat2d.dart';
import 'package:rive/src/rive_core/math/transform_components.dart';
import 'package:rive/src/rive_core/math/vec2d.dart';
Expand Down Expand Up @@ -68,7 +68,6 @@ class IKConstraint extends IKConstraintBase {
}
// Now put them in FK order (top to bottom).
for (final bone in bones.reversed) {
bone.addPeerConstraint(this);
nextFKChain.add(_BoneChainLink(
index: nextFKChain.length,
bone: bone,
Expand Down Expand Up @@ -117,9 +116,9 @@ class IKConstraint extends IKConstraintBase {
// Decompose the chain.
for (final item in _fkChain) {
var bone = item.bone;
Mat2D parentWorld = _parentWorld(bone);
Mat2D parentWorldTransform = parentWorld(bone);

Mat2D.invert(item.parentWorldInverse, parentWorld);
Mat2D.invert(item.parentWorldInverse, parentWorldTransform);

var boneTransform = bone.transform;
Mat2D.multiply(
Expand All @@ -145,7 +144,7 @@ class IKConstraint extends IKConstraintBase {
j < end;
j++) {
var fk = _fkChain[j];
Mat2D.invert(fk.parentWorldInverse, _parentWorld(fk.bone));
Mat2D.invert(fk.parentWorldInverse, parentWorld(fk.bone));
}
}
break;
Expand Down Expand Up @@ -249,7 +248,7 @@ class IKConstraint extends IKConstraintBase {
_constrainRotation(firstChild, r2);
if (firstChild != fk2) {
var bone = fk2.bone;
Mat2D.multiply(bone.worldTransform, _parentWorld(bone), bone.transform);
Mat2D.multiply(bone.worldTransform, parentWorld(bone), bone.transform);
}

// Simple storage, need this for interpolation.
Expand All @@ -273,7 +272,7 @@ class _BoneChainLink {

void _constrainRotation(_BoneChainLink link, double rotation) {
var bone = link.bone;
Mat2D parentWorld = _parentWorld(bone);
Mat2D parentWorldTransform = parentWorld(bone);
var boneTransform = bone.transform;
if (rotation == 0) {
Mat2D.setIdentity(boneTransform);
Expand All @@ -295,14 +294,5 @@ void _constrainRotation(_BoneChainLink link, double rotation) {
boneTransform[2] = boneTransform[0] * skew + boneTransform[2];
boneTransform[3] = boneTransform[1] * skew + boneTransform[3];
}
Mat2D.multiply(bone.worldTransform, parentWorld, boneTransform);
}

Mat2D _parentWorld(TransformComponent component) {
var parent = component.parent;
if (parent is Artboard) {
return parent.worldTransform;
} else {
return (parent as TransformComponent).worldTransform;
}
Mat2D.multiply(bone.worldTransform, parentWorldTransform, boneTransform);
}
74 changes: 74 additions & 0 deletions lib/src/rive_core/constraints/transform_constraint.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import 'dart:math';

import 'package:rive/src/rive_core/constraints/constraint.dart';
import 'package:rive/src/rive_core/math/mat2d.dart';
import 'package:rive/src/rive_core/math/transform_components.dart';
import 'package:rive/src/generated/constraints/transform_constraint_base.dart';
import 'package:rive/src/rive_core/transform_component.dart';
import 'package:rive/src/rive_core/transform_space.dart';
export 'package:rive/src/generated/constraints/transform_constraint_base.dart';

/// A constraint copies the transform from the target component to the
/// constrained component in world or local space.
class TransformConstraint extends TransformConstraintBase {
final TransformComponents componentsA = TransformComponents();
final TransformComponents componentsB = TransformComponents();

TransformSpace get destSpace => TransformSpace.values[destSpaceValue];
set destSpace(TransformSpace value) => destSpaceValue = value.index;

TransformSpace get sourceSpace => TransformSpace.values[sourceSpaceValue];
set sourceSpace(TransformSpace value) => sourceSpaceValue = value.index;

@override
void destSpaceValueChanged(int from, int to) => markConstraintDirty();

@override
void sourceSpaceValueChanged(int from, int to) => markConstraintDirty();

@override
void constrain(TransformComponent component) {
if (target == null) {
return;
}
var transformA = component.worldTransform;
var transformB = Mat2D.clone(target!.worldTransform);
if (sourceSpace == TransformSpace.local) {
var targetParentWorld = parentWorld(target!);

var inverse = Mat2D();
if (!Mat2D.invert(inverse, targetParentWorld)) {
return;
}
Mat2D.multiply(transformB, inverse, transformB);
}
if (destSpace == TransformSpace.local && component.parent != null) {
var targetParentWorld = parentWorld(component);
Mat2D.multiply(transformB, targetParentWorld, transformB);
}

Mat2D.decompose(transformA, componentsA);
Mat2D.decompose(transformB, componentsB);

var angleA = componentsA[4] % (pi * 2);
var angleB = componentsB[4] % (pi * 2);
var diff = angleB - angleA;
if (diff > pi) {
diff -= pi * 2;
} else if (diff < -pi) {
diff += pi * 2;
}

var t = strength;
var ti = 1 - t;

componentsB[4] = angleA + diff * t;
componentsB[0] = componentsA[0] * ti + componentsB[0] * t;
componentsB[1] = componentsA[1] * ti + componentsB[1] * t;
componentsB[2] = componentsA[2] * ti + componentsB[2] * t;
componentsB[3] = componentsA[3] * ti + componentsB[3] * t;
componentsB[5] = componentsA[5] * ti + componentsB[5] * t;

Mat2D.compose(component.worldTransform, componentsB);
}
}
3 changes: 3 additions & 0 deletions lib/src/rive_core/transform_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:rive/src/rive_core/component.dart';
import 'package:rive/src/rive_core/component_dirt.dart';
import 'package:rive/src/rive_core/constraints/constraint.dart';
import 'package:rive/src/rive_core/constraints/ik_constraint.dart';
import 'package:rive/src/rive_core/constraints/transform_constraint.dart';
import 'package:rive/src/rive_core/container_component.dart';
import 'package:rive/src/rive_core/draw_rules.dart';
import 'package:rive/src/rive_core/drawable.dart';
Expand Down Expand Up @@ -165,6 +166,7 @@ abstract class TransformComponent extends TransformComponentBase {
addDirt(ComponentDirt.clip, recurse: true);

break;
case TransformConstraintBase.typeKey:
case IKConstraintBase.typeKey:
case DistanceConstraintBase.typeKey:
_constraints.add(child as Constraint);
Expand All @@ -187,6 +189,7 @@ abstract class TransformComponent extends TransformComponentBase {
addDirt(ComponentDirt.clip, recurse: true);
}
break;
case TransformConstraintBase.typeKey:
case IKConstraintBase.typeKey:
case DistanceConstraintBase.typeKey:
_constraints.remove(child as Constraint);
Expand Down

0 comments on commit 8214b5c

Please sign in to comment.