Adding support for TransformConstraints.

This commit is contained in:
Luigi Rosso
2021-07-28 18:16:53 -07:00
committed by Luigi Rosso
parent 1013fa5088
commit 8214b5cee8
7 changed files with 211 additions and 20 deletions

View File

@ -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;
}
}

View File

@ -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';
@ -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';
@ -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:
@ -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;
@ -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:
@ -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:
@ -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;

View File

@ -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';
@ -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();
}

View File

@ -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;
@ -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;
}

View File

@ -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';
@ -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,
@ -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(
@ -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;
@ -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.
@ -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);
@ -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);
}

View File

@ -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);
}
}

View File

@ -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';
@ -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);
@ -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);