From 5c0d8929787a3fe6986240acbd9080477463ce8e Mon Sep 17 00:00:00 2001 From: Arpan Sarkar Date: Thu, 6 Dec 2018 14:32:56 +0530 Subject: [PATCH] Reformat code. --- lib/flare.dart | 1571 ++++++------ lib/flare/actor.dart | 308 ++- lib/flare/actor_artboard.dart | 1196 +++++---- lib/flare/actor_axis_constraint.dart | 227 +- lib/flare/actor_bone.dart | 70 +- lib/flare/actor_bone_base.dart | 97 +- lib/flare/actor_color.dart | 603 +++-- lib/flare/actor_component.dart | 105 +- lib/flare/actor_constraint.dart | 112 +- lib/flare/actor_distance_constraint.dart | 176 +- lib/flare/actor_drawable.dart | 33 +- lib/flare/actor_ellipse.dart | 125 +- lib/flare/actor_event.dart | 40 +- lib/flare/actor_flags.dart | 9 +- lib/flare/actor_ik_constraint.dart | 749 +++--- lib/flare/actor_image.dart | 1110 ++++---- lib/flare/actor_jelly_bone.dart | 39 +- lib/flare/actor_loader.dart | 30 +- lib/flare/actor_node.dart | 860 +++---- lib/flare/actor_node_solo.dart | 113 +- lib/flare/actor_path.dart | 646 +++-- lib/flare/actor_polygon.dart | 101 +- lib/flare/actor_rectangle.dart | 145 +- lib/flare/actor_root_bone.dart | 68 +- lib/flare/actor_rotation_constraint.dart | 353 ++- lib/flare/actor_scale_constraint.dart | 272 +- lib/flare/actor_shape.dart | 384 ++- lib/flare/actor_skin.dart | 170 +- lib/flare/actor_skinnable.dart | 130 +- lib/flare/actor_star.dart | 148 +- lib/flare/actor_targeted_constraint.dart | 57 +- lib/flare/actor_transform_constraint.dart | 178 +- lib/flare/actor_translation_constraint.dart | 216 +- lib/flare/actor_triangle.dart | 94 +- lib/flare/animation/actor_animation.dart | 952 ++++--- lib/flare/animation/interpolation/cubic.dart | 32 +- lib/flare/animation/interpolation/hold.dart | 19 +- .../animation/interpolation/interpolator.dart | 5 +- lib/flare/animation/interpolation/linear.dart | 19 +- lib/flare/animation/keyframe.dart | 2256 ++++++++--------- lib/flare/animation/property_types.dart | 139 +- lib/flare/binary_reader.dart | 371 ++- lib/flare/block_reader.dart | 45 +- lib/flare/block_types.dart | 191 +- lib/flare/dependency_sorter.dart | 82 +- lib/flare/jelly_component.dart | 823 +++--- lib/flare/json_block_reader.dart | 125 +- lib/flare/json_reader.dart | 378 ++- lib/flare/math/aabb.dart | 217 +- lib/flare/math/mat2d.dart | 370 +-- lib/flare/math/transform_components.dart | 177 +- lib/flare/math/vec2d.dart | 260 +- lib/flare/path_point.dart | 547 ++-- lib/flare/stream_reader.dart | 128 +- lib/flare/transform_space.dart | 7 +- lib/flare_actor.dart | 835 +++--- 56 files changed, 8723 insertions(+), 9790 deletions(-) diff --git a/lib/flare.dart b/lib/flare.dart index 8dcd907..511df4b 100644 --- a/lib/flare.dart +++ b/lib/flare.dart @@ -29,882 +29,807 @@ export "flare/actor_node.dart"; import "package:flutter/services.dart" show rootBundle; -abstract class FlutterFill -{ - ui.Paint getPaint(Float64List transform, double opacity); +abstract class FlutterFill { + ui.Paint getPaint(Float64List transform, double opacity); } -abstract class FlutterStroke -{ - ui.Paint getPaint(Float64List transform, double opacity); +abstract class FlutterStroke { + ui.Paint getPaint(Float64List transform, double opacity); } -class FlutterActorShape extends ActorShape -{ - List _fills; - List _flutterStrokes; - ui.Path _path; - - @override - void invalidateShape() - { - _path = null; - } - - ui.Path get path - { - if(_path != null) - { - return _path; - } - _path = new ui.Path(); - _path.fillType = ui.PathFillType.nonZero; - _path.reset(); - - for(ActorNode node in children) - { - FlutterPath flutterPath = node as FlutterPath; - if(flutterPath != null) - { - - Mat2D transform = (node as ActorBasePath).pathTransform; - _path.addPath(flutterPath.path, ui.Offset.zero, matrix4:transform == null ? null : transform.mat4); - } - } - return _path; - - } - - void addFlutterStroke(FlutterStroke stroke) - { - if(_flutterStrokes == null) - { - _flutterStrokes = new List(); - } - _flutterStrokes.add(stroke); - } - - void addFill(FlutterFill fill) - { - if(_fills == null) - { - _fills = new List(); - } - _fills.add(fill); - } - - List getClips() - { - ActorNode clipSearch = this; - List clips; - while(clipSearch != null) - { - if(clipSearch.clips != null) - { - clips = clipSearch.clips; - break; - } - clipSearch = clipSearch.parent; - } - - return clips; - } - - void draw(ui.Canvas canvas, double opacity, ui.Color overrideColor) - { - opacity *= renderOpacity; - if(opacity <= 0 || !this.doesDraw) - { - return; - } - - canvas.save(); - - ui.Path renderPath = path; - Float64List paintTransform = worldTransform.mat4; - - // Get Clips - List clipList = getClips(); - if(clipList != null) - { - for(ActorClip clip in clipList) - { - clip.node.all((ActorNode childNode) - { - if(childNode is FlutterActorShape) - { - ui.Path clippingPath = childNode.path; - canvas.clipPath(clippingPath); - } - }); - } - } - //canvas.transform(paintTransform); - if(_fills != null) - { - for(FlutterFill fill in _fills) - { - ui.Paint paint = fill.getPaint(paintTransform, opacity); - if(paint == null) - { - continue; - } - if(overrideColor != null) - { - paint.color = overrideColor.withOpacity(overrideColor.opacity*paint.color.opacity); - } - canvas.drawPath(renderPath, paint); - } - } - if(_flutterStrokes != null) - { - for(FlutterStroke stroke in _flutterStrokes) - { - ui.Paint paint = stroke.getPaint(paintTransform, opacity); - if(paint == null) - { - continue; - } - if(overrideColor != null) - { - paint.color = overrideColor.withOpacity(overrideColor.opacity*paint.color.opacity); - } - canvas.drawPath(renderPath, paint); - } - } - - canvas.restore(); - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorShape instanceNode = new FlutterActorShape(); - instanceNode.copyShape(this, resetArtboard); - return instanceNode; - } -} +class FlutterActorShape extends ActorShape { + List _fills; + List _flutterStrokes; + ui.Path _path; -class FlutterColorFill extends ColorFill implements FlutterFill -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - ui.Paint paint = new ui.Paint() - ..color = new ui.Color.fromRGBO((color[0]*255.0).round(), (color[1]*255.0).round(), (color[2]*255.0).round(), color[3]*modulateOpacity*opacity) - ..style = ui.PaintingStyle.fill; - return paint; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFill(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterColorFill instanceNode = new FlutterColorFill(); - instanceNode.copyColorFill(this, resetArtboard); - return instanceNode; - } -} + @override + void invalidateShape() { + _path = null; + } -class FlutterColorStroke extends ColorStroke implements FlutterStroke -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - if(width == 0) - { - return null; - } - ui.Paint paint = new ui.Paint() - ..color = new ui.Color.fromRGBO((color[0]*255.0).round(), (color[1]*255.0).round(), (color[2]*255.0).round(), color[3]*modulateOpacity*opacity) - ..strokeWidth = width - ..style = ui.PaintingStyle.stroke; - return paint; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFlutterStroke(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterColorStroke instanceNode = new FlutterColorStroke(); - instanceNode.copyColorStroke(this, resetArtboard); - return instanceNode; - } -} + ui.Path get path { + if (_path != null) { + return _path; + } + _path = new ui.Path(); + _path.fillType = ui.PathFillType.nonZero; + _path.reset(); + + for (ActorNode node in children) { + FlutterPath flutterPath = node as FlutterPath; + if (flutterPath != null) { + Mat2D transform = (node as ActorBasePath).pathTransform; + _path.addPath(flutterPath.path, ui.Offset.zero, + matrix4: transform == null ? null : transform.mat4); + } + } + return _path; + } -class FlutterGradientFill extends GradientFill implements FlutterFill -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - List colors = new List(); - List stops = new List(); - int numStops = (colorStops.length/5).round(); - - int idx = 0; - for(int i = 0; i < numStops; i++) - { - ui.Color color = new ui.Color.fromRGBO((colorStops[idx]*255.0).round(), (colorStops[idx+1]*255.0).round(), (colorStops[idx+2]*255.0).round(), colorStops[idx+3]); - colors.add(color); - stops.add(colorStops[idx+4]); - idx += 5; - } - ui.Paint paint = new ui.Paint() - ..color = Colors.white.withOpacity(modulateOpacity*opacity) - ..shader = new ui.Gradient.linear(new ui.Offset(renderStart[0], renderStart[1]), new ui.Offset(renderEnd[0], renderEnd[1]), colors, stops) - ..style = ui.PaintingStyle.fill; - return paint; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFill(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterGradientFill instanceNode = new FlutterGradientFill(); - instanceNode.copyGradientFill(this, resetArtboard); - return instanceNode; - } -} + void addFlutterStroke(FlutterStroke stroke) { + if (_flutterStrokes == null) { + _flutterStrokes = new List(); + } + _flutterStrokes.add(stroke); + } -class FlutterGradientStroke extends GradientStroke implements FlutterStroke -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - List colors = new List(); - List stops = new List(); - int numStops = (colorStops.length/5).round(); - - int idx = 0; - for(int i = 0; i < numStops; i++) - { - ui.Color color = new ui.Color.fromRGBO((colorStops[idx]*255.0).round(), (colorStops[idx+1]*255.0).round(), (colorStops[idx+2]*255.0).round(), colorStops[idx+3]); - colors.add(color); - stops.add(colorStops[idx+4]); - idx += 5; - } - - ui.Paint paint = new ui.Paint() - ..color = Colors.white.withOpacity(modulateOpacity*opacity) - ..shader = new ui.Gradient.linear(new ui.Offset(renderStart[0], renderStart[1]), new ui.Offset(renderEnd[0], renderEnd[1]), colors, stops) - ..strokeWidth = width - ..style = ui.PaintingStyle.stroke; - return paint; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFlutterStroke(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterGradientStroke instanceNode = new FlutterGradientStroke(); - instanceNode.copyGradientStroke(this, resetArtboard); - return instanceNode; - } -} + void addFill(FlutterFill fill) { + if (_fills == null) { + _fills = new List(); + } + _fills.add(fill); + } + + List getClips() { + ActorNode clipSearch = this; + List clips; + while (clipSearch != null) { + if (clipSearch.clips != null) { + clips = clipSearch.clips; + break; + } + clipSearch = clipSearch.parent; + } -class FlutterRadialFill extends RadialGradientFill implements FlutterFill -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - // double squash = max(0.00001, secondaryRadiusScale); - // Vec2D diff = Vec2D.subtract(new Vec2D(), end, start); - // double angle = atan2(diff[1], diff[0]); - // Mat2D transform = new Mat2D(); - - // Mat2D translate = new Mat2D(); - // translate[4] = start[0]; - // translate[5] = start[1]; - - // Mat2D rotation = new Mat2D(); - // Mat2D.fromRotation(rotation, angle); - - // transform[4] = start[0]; - // transform[5] = start[1]; - - // Mat2D scaling = new Mat2D(); - // scaling[0] = 1.0; - // scaling[3] = squash; - - // Mat2D.multiply(transform, translate, rotation); - // Mat2D.multiply(transform, transform, scaling); - - double radius = Vec2D.distance(renderStart, renderEnd); - List colors = new List(); - List stops = new List(); - int numStops = (colorStops.length/5).round(); - - int idx = 0; - for(int i = 0; i < numStops; i++) - { - ui.Color color = new ui.Color.fromRGBO((colorStops[idx]*255.0).round(), (colorStops[idx+1]*255.0).round(), (colorStops[idx+2]*255.0).round(), colorStops[idx+3]); - colors.add(color); - stops.add(colorStops[idx+4]); - idx += 5; - } - ui.Gradient radial = new ui.Gradient.radial(Offset(renderStart[0], renderStart[1]), radius, colors, stops, ui.TileMode.clamp);//, transform.mat4); - ui.Paint paint = new ui.Paint() - ..color = Colors.white.withOpacity(modulateOpacity*opacity) - ..shader = radial - ..style = ui.PaintingStyle.fill; - - return paint; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFill(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterRadialFill instanceNode = new FlutterRadialFill(); - instanceNode.copyRadialFill(this, resetArtboard); - return instanceNode; - } -} + return clips; + } -class FlutterRadialStroke extends RadialGradientStroke implements FlutterStroke -{ - ui.Paint getPaint(Float64List transform, double modulateOpacity) - { - // double squash = max(0.00001, secondaryRadiusScale); - // Vec2D diff = Vec2D.subtract(new Vec2D(), end, start); - // double angle = atan2(diff[1], diff[0]); - // Mat2D transform = new Mat2D(); - - // Mat2D translate = new Mat2D(); - // translate[4] = start[0]; - // translate[5] = start[1]; - - // Mat2D rotation = new Mat2D(); - // Mat2D.fromRotation(rotation, angle); - - // transform[4] = start[0]; - // transform[5] = start[1]; - - // Mat2D scaling = new Mat2D(); - // scaling[0] = 1.0; - // scaling[3] = squash; - - // Mat2D.multiply(transform, translate, rotation); - // Mat2D.multiply(transform, transform, scaling); - - double radius = Vec2D.distance(renderStart, renderEnd); - List colors = new List(); - List stops = new List(); - int numStops = (colorStops.length/5).round(); - - int idx = 0; - for(int i = 0; i < numStops; i++) - { - ui.Color color = new ui.Color.fromRGBO((colorStops[idx]*255.0).round(), (colorStops[idx+1]*255.0).round(), (colorStops[idx+2]*255.0).round(), colorStops[idx+3]); - colors.add(color); - stops.add(colorStops[idx+4]); - idx += 5; - } - return new ui.Paint() - ..color = Colors.white.withOpacity(modulateOpacity*opacity) - ..shader = new ui.Gradient.radial(Offset(renderStart[0], renderStart[1]), radius, colors, stops, ui.TileMode.clamp)//, transform.mat4) - // ..shader = new ui.Gradient.radial(new ui.Offset(center[0], center[1]), radius, colors, stops) - ..strokeWidth = width - ..style = ui.PaintingStyle.stroke; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is FlutterActorShape) - { - parentNode.addFlutterStroke(this); - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterRadialStroke instanceNode = new FlutterRadialStroke(); - instanceNode.copyRadialStroke(this, resetArtboard); - return instanceNode; - } -} + void draw(ui.Canvas canvas, double opacity, ui.Color overrideColor) { + opacity *= renderOpacity; + if (opacity <= 0 || !this.doesDraw) { + return; + } + + canvas.save(); + + ui.Path renderPath = path; + Float64List paintTransform = worldTransform.mat4; + + // Get Clips + List clipList = getClips(); + if (clipList != null) { + for (ActorClip clip in clipList) { + clip.node.all((ActorNode childNode) { + if (childNode is FlutterActorShape) { + ui.Path clippingPath = childNode.path; + canvas.clipPath(clippingPath); + } + }); + } + } + //canvas.transform(paintTransform); + if (_fills != null) { + for (FlutterFill fill in _fills) { + ui.Paint paint = fill.getPaint(paintTransform, opacity); + if (paint == null) { + continue; + } + if (overrideColor != null) { + paint.color = overrideColor.withOpacity( + overrideColor.opacity * paint.color.opacity); + } + canvas.drawPath(renderPath, paint); + } + } + if (_flutterStrokes != null) { + for (FlutterStroke stroke in _flutterStrokes) { + ui.Paint paint = stroke.getPaint(paintTransform, opacity); + if (paint == null) { + continue; + } + if (overrideColor != null) { + paint.color = overrideColor.withOpacity( + overrideColor.opacity * paint.color.opacity); + } + canvas.drawPath(renderPath, paint); + } + } + + canvas.restore(); + } -class FlutterActor extends Actor -{ - List _images; + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorShape instanceNode = new FlutterActorShape(); + instanceNode.copyShape(this, resetArtboard); + return instanceNode; + } +} - List get images - { - return _images; +class FlutterColorFill extends ColorFill + implements FlutterFill { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + ui.Paint paint = new ui.Paint() + ..color = new ui.Color.fromRGBO( + (color[0] * 255.0).round(), (color[1] * 255.0).round(), + (color[2] * 255.0).round(), color[3] * modulateOpacity * opacity) + ..style = ui.PaintingStyle.fill; + return paint; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFill(this); } + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterColorFill instanceNode = new FlutterColorFill(); + instanceNode.copyColorFill(this, resetArtboard); + return instanceNode; + } +} - ActorArtboard makeArtboard() - { - return new FlutterActorArtboard(this); - } - - ActorShape makeShapeNode() - { - return new FlutterActorShape(); - } - - ActorPath makePathNode() - { - return new FlutterActorPath(); - } - - ActorRectangle makeRectangle() - { - return new FlutterActorRectangle(); +class FlutterColorStroke extends ColorStroke + implements FlutterStroke { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + if (width == 0) { + return null; } + ui.Paint paint = new ui.Paint() + ..color = new ui.Color.fromRGBO( + (color[0] * 255.0).round(), (color[1] * 255.0).round(), + (color[2] * 255.0).round(), color[3] * modulateOpacity * opacity) + ..strokeWidth = width + ..style = ui.PaintingStyle.stroke; + return paint; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFlutterStroke(this); + } + } - ActorTriangle makeTriangle() - { - return new FlutterActorTriangle(); + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterColorStroke instanceNode = new FlutterColorStroke(); + instanceNode.copyColorStroke(this, resetArtboard); + return instanceNode; + } +} + +class FlutterGradientFill extends GradientFill + implements FlutterFill { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + List colors = new List(); + List stops = new List(); + int numStops = (colorStops.length / 5).round(); + + int idx = 0; + for (int i = 0; i < numStops; i++) { + ui.Color color = new ui.Color.fromRGBO((colorStops[idx] * 255.0).round(), + (colorStops[idx + 1] * 255.0).round(), + (colorStops[idx + 2] * 255.0).round(), colorStops[idx + 3]); + colors.add(color); + stops.add(colorStops[idx + 4]); + idx += 5; + } + ui.Paint paint = new ui.Paint() + ..color = Colors.white.withOpacity(modulateOpacity * opacity) + ..shader = new ui.Gradient.linear( + new ui.Offset(renderStart[0], renderStart[1]), + new ui.Offset(renderEnd[0], renderEnd[1]), colors, stops) + ..style = ui.PaintingStyle.fill; + return paint; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFill(this); } + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterGradientFill instanceNode = new FlutterGradientFill(); + instanceNode.copyGradientFill(this, resetArtboard); + return instanceNode; + } +} - ActorStar makeStar() - { - return new FlutterActorStar(); +class FlutterGradientStroke extends GradientStroke + implements FlutterStroke { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + List colors = new List(); + List stops = new List(); + int numStops = (colorStops.length / 5).round(); + + int idx = 0; + for (int i = 0; i < numStops; i++) { + ui.Color color = new ui.Color.fromRGBO((colorStops[idx] * 255.0).round(), + (colorStops[idx + 1] * 255.0).round(), + (colorStops[idx + 2] * 255.0).round(), colorStops[idx + 3]); + colors.add(color); + stops.add(colorStops[idx + 4]); + idx += 5; } - ActorPolygon makePolygon() - { - return new FlutterActorPolygon(); + ui.Paint paint = new ui.Paint() + ..color = Colors.white.withOpacity(modulateOpacity * opacity) + ..shader = new ui.Gradient.linear( + new ui.Offset(renderStart[0], renderStart[1]), + new ui.Offset(renderEnd[0], renderEnd[1]), colors, stops) + ..strokeWidth = width + ..style = ui.PaintingStyle.stroke; + return paint; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFlutterStroke(this); } + } - ActorEllipse makeEllipse() - { - return new FlutterActorEllipse(); + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterGradientStroke instanceNode = new FlutterGradientStroke(); + instanceNode.copyGradientStroke(this, resetArtboard); + return instanceNode; + } +} + +class FlutterRadialFill extends RadialGradientFill + implements FlutterFill { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + // double squash = max(0.00001, secondaryRadiusScale); + // Vec2D diff = Vec2D.subtract(new Vec2D(), end, start); + // double angle = atan2(diff[1], diff[0]); + // Mat2D transform = new Mat2D(); + + // Mat2D translate = new Mat2D(); + // translate[4] = start[0]; + // translate[5] = start[1]; + + // Mat2D rotation = new Mat2D(); + // Mat2D.fromRotation(rotation, angle); + + // transform[4] = start[0]; + // transform[5] = start[1]; + + // Mat2D scaling = new Mat2D(); + // scaling[0] = 1.0; + // scaling[3] = squash; + + // Mat2D.multiply(transform, translate, rotation); + // Mat2D.multiply(transform, transform, scaling); + + double radius = Vec2D.distance(renderStart, renderEnd); + List colors = new List(); + List stops = new List(); + int numStops = (colorStops.length / 5).round(); + + int idx = 0; + for (int i = 0; i < numStops; i++) { + ui.Color color = new ui.Color.fromRGBO((colorStops[idx] * 255.0).round(), + (colorStops[idx + 1] * 255.0).round(), + (colorStops[idx + 2] * 255.0).round(), colorStops[idx + 3]); + colors.add(color); + stops.add(colorStops[idx + 4]); + idx += 5; + } + ui.Gradient radial = new ui.Gradient.radial( + Offset(renderStart[0], renderStart[1]), radius, colors, stops, + ui.TileMode.clamp); //, transform.mat4); + ui.Paint paint = new ui.Paint() + ..color = Colors.white.withOpacity(modulateOpacity * opacity) + ..shader = radial + ..style = ui.PaintingStyle.fill; + + return paint; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFill(this); } + } - ColorFill makeColorFill() - { - return new FlutterColorFill(); - } - - ColorStroke makeColorStroke() - { - return new FlutterColorStroke(); - } - - GradientFill makeGradientFill() - { - return new FlutterGradientFill(); - } - - GradientStroke makeGradientStroke() - { - return new FlutterGradientStroke(); - } - - RadialGradientFill makeRadialFill() - { - return new FlutterRadialFill(); - } - - RadialGradientStroke makeRadialStroke() - { - return new FlutterRadialStroke(); - } - - Future loadFromBundle(String filename) async - { - Completer completer = new Completer(); - rootBundle.load(filename).then((ByteData data) - { - super.load(data); - completer.complete(true); - }); - return completer.future; - } - - dispose() - {} + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterRadialFill instanceNode = new FlutterRadialFill(); + instanceNode.copyRadialFill(this, resetArtboard); + return instanceNode; + } } -class FlutterActorArtboard extends ActorArtboard -{ - FlutterActorArtboard(FlutterActor actor) : super(actor); - - void advance(double seconds) - { - super.advance(seconds); +class FlutterRadialStroke extends RadialGradientStroke + implements FlutterStroke { + ui.Paint getPaint(Float64List transform, double modulateOpacity) { + // double squash = max(0.00001, secondaryRadiusScale); + // Vec2D diff = Vec2D.subtract(new Vec2D(), end, start); + // double angle = atan2(diff[1], diff[0]); + // Mat2D transform = new Mat2D(); + + // Mat2D translate = new Mat2D(); + // translate[4] = start[0]; + // translate[5] = start[1]; + + // Mat2D rotation = new Mat2D(); + // Mat2D.fromRotation(rotation, angle); + + // transform[4] = start[0]; + // transform[5] = start[1]; + + // Mat2D scaling = new Mat2D(); + // scaling[0] = 1.0; + // scaling[3] = squash; + + // Mat2D.multiply(transform, translate, rotation); + // Mat2D.multiply(transform, transform, scaling); + + double radius = Vec2D.distance(renderStart, renderEnd); + List colors = new List(); + List stops = new List(); + int numStops = (colorStops.length / 5).round(); + + int idx = 0; + for (int i = 0; i < numStops; i++) { + ui.Color color = new ui.Color.fromRGBO((colorStops[idx] * 255.0).round(), + (colorStops[idx + 1] * 255.0).round(), + (colorStops[idx + 2] * 255.0).round(), colorStops[idx + 3]); + colors.add(color); + stops.add(colorStops[idx + 4]); + idx += 5; } + return new ui.Paint() + ..color = Colors.white.withOpacity(modulateOpacity * opacity) + ..shader = new ui.Gradient.radial( + Offset(renderStart[0], renderStart[1]), radius, colors, stops, + ui.TileMode.clamp) //, transform.mat4) + // ..shader = new ui.Gradient.radial(new ui.Offset(center[0], center[1]), radius, colors, stops) + ..strokeWidth = width + ..style = ui.PaintingStyle.stroke; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is FlutterActorShape) { + parentNode.addFlutterStroke(this); + } + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterRadialStroke instanceNode = new FlutterRadialStroke(); + instanceNode.copyRadialStroke(this, resetArtboard); + return instanceNode; + } +} + +class FlutterActor extends Actor { + List _images; + + List get images { + return _images; + } + + ActorArtboard makeArtboard() { + return new FlutterActorArtboard(this); + } - void draw(ui.Canvas canvas, {ui.Color overrideColor, double opacity = 1.0}) - { - for(ActorDrawable drawable in drawableNodes) - { - if(drawable is FlutterActorShape) - { - drawable.draw(canvas, opacity, overrideColor); - } - } - } - - ActorArtboard makeInstance() - { - FlutterActorArtboard artboardInstance = new FlutterActorArtboard(actor); - artboardInstance.copyArtboard(this); - return artboardInstance; + ActorShape makeShapeNode() { + return new FlutterActorShape(); + } + + ActorPath makePathNode() { + return new FlutterActorPath(); + } + + ActorRectangle makeRectangle() { + return new FlutterActorRectangle(); + } + + ActorTriangle makeTriangle() { + return new FlutterActorTriangle(); + } + + ActorStar makeStar() { + return new FlutterActorStar(); + } + + ActorPolygon makePolygon() { + return new FlutterActorPolygon(); + } + + ActorEllipse makeEllipse() { + return new FlutterActorEllipse(); + } + + ColorFill makeColorFill() { + return new FlutterColorFill(); + } + + ColorStroke makeColorStroke() { + return new FlutterColorStroke(); + } + + GradientFill makeGradientFill() { + return new FlutterGradientFill(); + } + + GradientStroke makeGradientStroke() { + return new FlutterGradientStroke(); + } + + RadialGradientFill makeRadialFill() { + return new FlutterRadialFill(); + } + + RadialGradientStroke makeRadialStroke() { + return new FlutterRadialStroke(); + } + + Future loadFromBundle(String filename) async + { + Completer completer = new Completer(); + rootBundle.load(filename).then((ByteData data) { + super.load(data); + completer.complete(true); + }); + return completer.future; + } + + dispose() {} +} + +class FlutterActorArtboard extends ActorArtboard { + FlutterActorArtboard(FlutterActor actor) : super(actor); + + void advance(double seconds) { + super.advance(seconds); + } + + void draw(ui.Canvas canvas, {ui.Color overrideColor, double opacity = 1.0}) { + for (ActorDrawable drawable in drawableNodes) { + if (drawable is FlutterActorShape) { + drawable.draw(canvas, opacity, overrideColor); + } } - - void dispose() {} + } + + ActorArtboard makeInstance() { + FlutterActorArtboard artboardInstance = new FlutterActorArtboard(actor); + artboardInstance.copyArtboard(this); + return artboardInstance; + } + + void dispose() {} } -class FlutterActorPath extends ActorPath with FlutterPathPointsPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorPath instanceNode = new FlutterActorPath(); - instanceNode.copyPath(this, resetArtboard); - return instanceNode; - } +class FlutterActorPath extends ActorPath + with FlutterPathPointsPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorPath instanceNode = new FlutterActorPath(); + instanceNode.copyPath(this, resetArtboard); + return instanceNode; + } } -class FlutterActorEllipse extends ActorEllipse with FlutterPathPointsPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorEllipse instanceNode = new FlutterActorEllipse(); - instanceNode.copyPath(this, resetArtboard); - return instanceNode; - } - // updatePath(ui.Path path) - // { - // List pts = points; - // int len = pts.length; - // path.moveTo(0.0, -radiusY); - - // for(int i = 0; i < len; i++) - // { - // CubicPathPoint point = pts[i]; - // CubicPathPoint nextPoint = pts[(i+1)%len]; - // Vec2D t = nextPoint.translation; - // Vec2D cin = nextPoint.inPoint; - // Vec2D cout = point.outPoint; - // path.cubicTo( - // cout[0], cout[1], - // cin[0], cin[1], - // t[0], t[1] - // ); - // } - // path.close(); - // } +class FlutterActorEllipse extends ActorEllipse + with FlutterPathPointsPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorEllipse instanceNode = new FlutterActorEllipse(); + instanceNode.copyPath(this, resetArtboard); + return instanceNode; + } +// updatePath(ui.Path path) +// { +// List pts = points; +// int len = pts.length; +// path.moveTo(0.0, -radiusY); + +// for(int i = 0; i < len; i++) +// { +// CubicPathPoint point = pts[i]; +// CubicPathPoint nextPoint = pts[(i+1)%len]; +// Vec2D t = nextPoint.translation; +// Vec2D cin = nextPoint.inPoint; +// Vec2D cout = point.outPoint; +// path.cubicTo( +// cout[0], cout[1], +// cin[0], cin[1], +// t[0], t[1] +// ); +// } +// path.close(); +// } } -class FlutterActorPolygon extends ActorPolygon with FlutterPathPointsPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorPolygon instanceNode = new FlutterActorPolygon(); - instanceNode.copyPolygon(this, resetArtboard); - return instanceNode; - } - // updatePath(ui.Path path) - // { - // Mat2D xform = this.transform; - // List pts = points; - // for(PathPoint p in pts) - // { - // p = p.transformed(xform); - // } - - // path.moveTo(0.0, -radiusY); - // double angle = -pi/2.0; - // double inc = (pi*2.0)/sides; - - // for(int i = 0; i < sides; i++) - // { - // path.lineTo(cos(angle)*radiusX, sin(angle)*radiusY); - // angle += inc; - // } - - // path.close(); - // } +class FlutterActorPolygon extends ActorPolygon + with FlutterPathPointsPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorPolygon instanceNode = new FlutterActorPolygon(); + instanceNode.copyPolygon(this, resetArtboard); + return instanceNode; + } +// updatePath(ui.Path path) +// { +// Mat2D xform = this.transform; +// List pts = points; +// for(PathPoint p in pts) +// { +// p = p.transformed(xform); +// } + +// path.moveTo(0.0, -radiusY); +// double angle = -pi/2.0; +// double inc = (pi*2.0)/sides; + +// for(int i = 0; i < sides; i++) +// { +// path.lineTo(cos(angle)*radiusX, sin(angle)*radiusY); +// angle += inc; +// } + +// path.close(); +// } } -class FlutterActorStar extends ActorStar with FlutterPathPointsPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorStar instanceNode = new FlutterActorStar(); - instanceNode.copyStar(this, resetArtboard); - return instanceNode; - } - // onPathInvalid() - // { - // (parent as FlutterActorShape).invalidatePath(); - // } - - // markPathDirty() - // { - // actor.addDirt(this, ActorBasePath.PathDirty, false); - // this.onPathInvalid(); - // } - - // updatePath(ui.Path path) - // { - // path.moveTo(0.0, -radiusY); - // double angle = -pi/2.0; - // double inc = (pi*2.0)/sides; - // Vec2D sx = Vec2D.fromValues(radiusX, radiusX*innerRadius); - // Vec2D sy = Vec2D.fromValues(radiusY, radiusY*innerRadius); - - // for(int i = 0; i < sides; i++) - // { - // path.lineTo(cos(angle)*sx[i%2], sin(angle)*sy[i%2]); - // angle += inc; - // } - // path.close(); - // } +class FlutterActorStar extends ActorStar + with FlutterPathPointsPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorStar instanceNode = new FlutterActorStar(); + instanceNode.copyStar(this, resetArtboard); + return instanceNode; + } +// onPathInvalid() +// { +// (parent as FlutterActorShape).invalidatePath(); +// } + +// markPathDirty() +// { +// actor.addDirt(this, ActorBasePath.PathDirty, false); +// this.onPathInvalid(); +// } + +// updatePath(ui.Path path) +// { +// path.moveTo(0.0, -radiusY); +// double angle = -pi/2.0; +// double inc = (pi*2.0)/sides; +// Vec2D sx = Vec2D.fromValues(radiusX, radiusX*innerRadius); +// Vec2D sy = Vec2D.fromValues(radiusY, radiusY*innerRadius); + +// for(int i = 0; i < sides; i++) +// { +// path.lineTo(cos(angle)*sx[i%2], sin(angle)*sy[i%2]); +// angle += inc; +// } +// path.close(); +// } } // Example of how to directly use a base FlutterPath and do drawing directly with SKIA high level paths // This is more efficient, particularly when using a lot of procedural shapes. -class FlutterActorRectangle extends ActorRectangle with FlutterPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorRectangle instanceNode = new FlutterActorRectangle(); - instanceNode.copyRectangle(this, resetArtboard); - return instanceNode; - } - - ui.Path _path; - - ui.Path get path - { - if(_path != null) - { - return _path; - } - return (_path = _makePath()); - } - - @override - void invalidatePath() - { - _path = null; - } - - ui.Path _makePath() - { - ui.Path p = new ui.Path(); - double halfWidth = width/2.0; - double halfHeight = height/2.0; - Vec2D topLeft = Vec2D.fromValues(-halfWidth, halfHeight); - Vec2D bottomRight = Vec2D.fromValues(halfWidth, -halfHeight); - p.moveTo(x, y); - - p.addRRect( - new ui.RRect.fromLTRBR( - topLeft[0], - topLeft[1], - bottomRight[0], - bottomRight[1], - ui.Radius.circular(radius) - ) - ); - - return p; +class FlutterActorRectangle extends ActorRectangle + with FlutterPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorRectangle instanceNode = new FlutterActorRectangle(); + instanceNode.copyRectangle(this, resetArtboard); + return instanceNode; + } + + ui.Path _path; + + ui.Path get path { + if (_path != null) { + return _path; } + return (_path = _makePath()); + } + + @override + void invalidatePath() { + _path = null; + } + + ui.Path _makePath() { + ui.Path p = new ui.Path(); + double halfWidth = width / 2.0; + double halfHeight = height / 2.0; + Vec2D topLeft = Vec2D.fromValues(-halfWidth, halfHeight); + Vec2D bottomRight = Vec2D.fromValues(halfWidth, -halfHeight); + p.moveTo(x, y); + + p.addRRect( + new ui.RRect.fromLTRBR( + topLeft[0], + topLeft[1], + bottomRight[0], + bottomRight[1], + ui.Radius.circular(radius) + ) + ); + + return p; + } } -class FlutterActorTriangle extends ActorTriangle with FlutterPathPointsPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - FlutterActorTriangle instanceNode = new FlutterActorTriangle(); - instanceNode.copyPath(this, resetArtboard); - return instanceNode; - } - // updatePath(ui.Path path) - // { - // path.moveTo(0.0, -radiusY); - // path.lineTo(radiusX, radiusY); - // path.lineTo(-radiusX, radiusY); - // path.close(); - // } +class FlutterActorTriangle extends ActorTriangle + with FlutterPathPointsPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + FlutterActorTriangle instanceNode = new FlutterActorTriangle(); + instanceNode.copyPath(this, resetArtboard); + return instanceNode; + } +// updatePath(ui.Path path) +// { +// path.moveTo(0.0, -radiusY); +// path.lineTo(radiusX, radiusY); +// path.lineTo(-radiusX, radiusY); +// path.close(); +// } } // Abstract base path that can be invalidated and somehow regenerates, no concrete logic -abstract class FlutterPath -{ - ui.Path get path; +abstract class FlutterPath { + ui.Path get path; } // Abstract path that uses Actor PathPoints, slightly higher level that FlutterPath. // Most shapes can use this, but if they want to use a different procedural backing call, // they should implement FlutterPath and generate the path another way. -abstract class FlutterPathPointsPath implements FlutterPath -{ - ui.Path _path; - List get deformedPoints; - bool get isClosed; - - ui.Path get path - { - if(_path != null) - { - return _path; - } - return (_path = _makePath()); - } - - void invalidatePath() - { - _path = null; +abstract class FlutterPathPointsPath + implements FlutterPath { + ui.Path _path; + + List get deformedPoints; + + bool get isClosed; + + ui.Path get path { + if (_path != null) { + return _path; + } + return (_path = _makePath()); + } + + void invalidatePath() { + _path = null; + } + + ui.Path _makePath() { + ui.Path p = new ui.Path(); + + List pts = this.deformedPoints; + if (pts == null || pts.length == 0) { + return p; + } + + List renderPoints = new List(); + int pl = pts.length; + + const double arcConstant = 0.55; + const double iarcConstant = 1.0 - arcConstant; + PathPoint previous = isClosed ? pts[pl - 1] : null; + for (int i = 0; i < pl; i++) { + PathPoint point = pts[i]; + switch (point.pointType) { + case PointType.Straight: + { + StraightPathPoint straightPoint = point as StraightPathPoint; + double radius = straightPoint.radius; + if (radius > 0) { + if (!isClosed && (i == 0 || i == pl - 1)) { + renderPoints.add(point); + previous = point; + } + else { + PathPoint next = pts[(i + 1) % pl]; + Vec2D prevPoint = previous is CubicPathPoint + ? previous.outPoint + : previous.translation; + Vec2D nextPoint = next is CubicPathPoint ? next.inPoint : next + .translation; + Vec2D pos = point.translation; + + Vec2D toPrev = Vec2D.subtract(new Vec2D(), prevPoint, pos); + double toPrevLength = Vec2D.length(toPrev); + toPrev[0] /= toPrevLength; + toPrev[1] /= toPrevLength; + + Vec2D toNext = Vec2D.subtract(new Vec2D(), nextPoint, pos); + double toNextLength = Vec2D.length(toNext); + toNext[0] /= toNextLength; + toNext[1] /= toNextLength; + + double renderRadius = min( + toPrevLength, min(toNextLength, radius)); + + Vec2D translation = Vec2D.scaleAndAdd( + new Vec2D(), pos, toPrev, renderRadius); + renderPoints.add(new CubicPathPoint.fromValues( + translation, translation, Vec2D.scaleAndAdd( + new Vec2D(), pos, toPrev, iarcConstant * renderRadius))); + translation = + Vec2D.scaleAndAdd(new Vec2D(), pos, toNext, renderRadius); + previous = new CubicPathPoint.fromValues(translation, + Vec2D.scaleAndAdd( + new Vec2D(), pos, toNext, iarcConstant * renderRadius), + translation); + renderPoints.add(previous); + } + } + else { + renderPoints.add(point); + previous = point; + } + break; + } + default: + renderPoints.add(point); + previous = point; + break; + } + } + + PathPoint firstPoint = renderPoints[0]; + p.moveTo(firstPoint.translation[0], firstPoint.translation[1]); + for (int i = 0, + l = isClosed ? renderPoints.length : renderPoints.length - 1, + pl = renderPoints.length; i < l; i++) { + PathPoint point = renderPoints[i]; + PathPoint nextPoint = renderPoints[(i + 1) % pl]; + Vec2D cin = nextPoint is CubicPathPoint ? nextPoint.inPoint : null; + Vec2D cout = point is CubicPathPoint ? point.outPoint : null; + if (cin == null && cout == null) { + p.lineTo(nextPoint.translation[0], nextPoint.translation[1]); + } + else { + if (cout == null) { + cout = point.translation; + } + if (cin == null) { + cin = nextPoint.translation; + } + + p.cubicTo( + cout[0], cout[1], + + cin[0], cin[1], + + nextPoint.translation[0], nextPoint.translation[1]); + } + } + + if (isClosed) { + p.close(); } - ui.Path _makePath() - { - ui.Path p = new ui.Path(); - - List pts = this.deformedPoints; - if(pts == null || pts.length == 0) - { - return p; - } - - List renderPoints = new List(); - int pl = pts.length; - - const double arcConstant = 0.55; - const double iarcConstant = 1.0-arcConstant; - PathPoint previous = isClosed ? pts[pl-1] : null; - for(int i = 0; i < pl; i++) - { - PathPoint point = pts[i]; - switch(point.pointType) - { - case PointType.Straight: - { - StraightPathPoint straightPoint = point as StraightPathPoint; - double radius = straightPoint.radius; - if(radius > 0) - { - if(!isClosed && (i == 0 || i == pl-1)) - { - renderPoints.add(point); - previous = point; - } - else - { - PathPoint next = pts[(i+1)%pl]; - Vec2D prevPoint = previous is CubicPathPoint ? previous.outPoint : previous.translation; - Vec2D nextPoint = next is CubicPathPoint ? next.inPoint : next.translation; - Vec2D pos = point.translation; - - Vec2D toPrev = Vec2D.subtract(new Vec2D(), prevPoint, pos); - double toPrevLength = Vec2D.length(toPrev); - toPrev[0] /= toPrevLength; - toPrev[1] /= toPrevLength; - - Vec2D toNext = Vec2D.subtract(new Vec2D(), nextPoint, pos); - double toNextLength = Vec2D.length(toNext); - toNext[0] /= toNextLength; - toNext[1] /= toNextLength; - - double renderRadius = min(toPrevLength, min(toNextLength, radius)); - - Vec2D translation = Vec2D.scaleAndAdd(new Vec2D(), pos, toPrev, renderRadius); - renderPoints.add(new CubicPathPoint.fromValues(translation, translation, Vec2D.scaleAndAdd(new Vec2D(), pos, toPrev, iarcConstant*renderRadius))); - translation = Vec2D.scaleAndAdd(new Vec2D(), pos, toNext, renderRadius); - previous = new CubicPathPoint.fromValues(translation, Vec2D.scaleAndAdd(new Vec2D(), pos, toNext, iarcConstant*renderRadius), translation); - renderPoints.add(previous); - } - } - else - { - renderPoints.add(point); - previous = point; - } - break; - } - default: - renderPoints.add(point); - previous = point; - break; - } - } - - PathPoint firstPoint = renderPoints[0]; - p.moveTo(firstPoint.translation[0], firstPoint.translation[1]); - for(int i = 0, l = isClosed ? renderPoints.length : renderPoints.length-1, pl = renderPoints.length; i < l; i++) - { - PathPoint point = renderPoints[i]; - PathPoint nextPoint = renderPoints[(i+1)%pl]; - Vec2D cin = nextPoint is CubicPathPoint ? nextPoint.inPoint : null; - Vec2D cout = point is CubicPathPoint ? point.outPoint : null; - if(cin == null && cout == null) - { - p.lineTo(nextPoint.translation[0], nextPoint.translation[1]); - } - else - { - if(cout == null) - { - cout = point.translation; - } - if(cin == null) - { - cin = nextPoint.translation; - } - - p.cubicTo( - cout[0], cout[1], - - cin[0], cin[1], - - nextPoint.translation[0], nextPoint.translation[1]); - } - } - - if(isClosed) - { - p.close(); - } - - return p; - } + return p; + } } \ No newline at end of file diff --git a/lib/flare/actor.dart b/lib/flare/actor.dart index 11826ce..f3d3b27 100644 --- a/lib/flare/actor.dart +++ b/lib/flare/actor.dart @@ -13,172 +13,154 @@ import "stream_reader.dart"; import "block_types.dart"; import "actor_artboard.dart"; -class Actor -{ - int maxTextureIndex = 0; - int _version = 0; - int _artboardCount = 0; - List _artboards; - - Actor(); - - ActorArtboard get artboard => _artboards.length > 0 ? _artboards.first : null; - - int get version - { - return _version; - } - - int get texturesUsed - { - return maxTextureIndex + 1; - } - - void copyActor(Actor actor) - { - maxTextureIndex = actor.maxTextureIndex; - _artboardCount = actor._artboardCount; - if(_artboardCount > 0) - { - int idx = 0; - _artboards = new List(_artboardCount); - for(ActorArtboard artboard in actor._artboards) - { - if(artboard == null) - { - _artboards[idx++] = null; - continue; - } - ActorArtboard instanceArtboard = artboard.makeInstance(); - _artboards[idx++] = instanceArtboard; - } - } - } - - ActorArtboard makeArtboard() - { - return new ActorArtboard(this); - } - - ActorImage makeImageNode() - { - return new ActorImage(); - } - - ActorPath makePathNode() - { - return new ActorPath(); - } - ActorShape makeShapeNode() - { - return new ActorShape(); - } - ActorRectangle makeRectangle() - { - return new ActorRectangle(); +class Actor { + int maxTextureIndex = 0; + int _version = 0; + int _artboardCount = 0; + List _artboards; + + Actor(); + + ActorArtboard get artboard => _artboards.length > 0 ? _artboards.first : null; + + int get version { + return _version; + } + + int get texturesUsed { + return maxTextureIndex + 1; + } + + void copyActor(Actor actor) { + maxTextureIndex = actor.maxTextureIndex; + _artboardCount = actor._artboardCount; + if (_artboardCount > 0) { + int idx = 0; + _artboards = new List(_artboardCount); + for (ActorArtboard artboard in actor._artboards) { + if (artboard == null) { + _artboards[idx++] = null; + continue; + } + ActorArtboard instanceArtboard = artboard.makeInstance(); + _artboards[idx++] = instanceArtboard; + } } - ActorTriangle makeTriangle() - { - return new ActorTriangle(); + } + + ActorArtboard makeArtboard() { + return new ActorArtboard(this); + } + + ActorImage makeImageNode() { + return new ActorImage(); + } + + ActorPath makePathNode() { + return new ActorPath(); + } + + ActorShape makeShapeNode() { + return new ActorShape(); + } + + ActorRectangle makeRectangle() { + return new ActorRectangle(); + } + + ActorTriangle makeTriangle() { + return new ActorTriangle(); + } + + ActorStar makeStar() { + return new ActorStar(); + } + + ActorPolygon makePolygon() { + return new ActorPolygon(); + } + + ActorEllipse makeEllipse() { + return new ActorEllipse(); + } + + ColorFill makeColorFill() { + return new ColorFill(); + } + + ColorStroke makeColorStroke() { + return new ColorStroke(); + } + + GradientFill makeGradientFill() { + return new GradientFill(); + } + + GradientStroke makeGradientStroke() { + return new GradientStroke(); + } + + RadialGradientFill makeRadialFill() { + return new RadialGradientFill(); + } + + RadialGradientStroke makeRadialStroke() { + return new RadialGradientStroke(); + } + + void load(ByteData data) { + if (data.lengthInBytes < 5) { + throw new UnsupportedError("Not a valid Flare file."); } - ActorStar makeStar() - { - return new ActorStar(); + int F = data.getUint8(0); + int L = data.getUint8(1); + int A = data.getUint8(2); + int R = data.getUint8(3); + int E = data.getUint8(4); + + dynamic inputData = data; + + if (F != 70 || L != 76 || A != 65 || R != 82 || E != 69) { + Uint8List charCodes = data.buffer.asUint8List(); + String stringData = String.fromCharCodes(charCodes); + var jsonActor = jsonDecode(stringData); + Map jsonObject = new Map(); + jsonObject["container"] = jsonActor; + inputData = jsonObject; } - ActorPolygon makePolygon() - { - return new ActorPolygon(); + + StreamReader reader = new StreamReader(inputData); + _version = reader.readVersion(); + + StreamReader block; + while ((block = reader.readNextBlock(BlockTypesMap)) != null) { + switch (block.blockType) { + case BlockTypes.Artboards: + readArtboardsBlock(block); + break; + } } - ActorEllipse makeEllipse() - { - return new ActorEllipse(); + } + + void readArtboardsBlock(StreamReader block) { + int artboardCount = block.readUint16Length(); + _artboards = new List(artboardCount); + + for (int artboardIndex = 0, end = _artboards.length; artboardIndex < end; + artboardIndex++) { + StreamReader artboardBlock = block.readNextBlock(BlockTypesMap); + if (artboardBlock == null) { + break; + } + switch (artboardBlock.blockType) { + case BlockTypes.ActorArtboard: + { + ActorArtboard artboard = makeArtboard(); + artboard.read(artboardBlock); + _artboards[artboardIndex] = artboard; + break; + } + } } - ColorFill makeColorFill() - { - return new ColorFill(); - } - ColorStroke makeColorStroke() - { - return new ColorStroke(); - } - GradientFill makeGradientFill() - { - return new GradientFill(); - } - GradientStroke makeGradientStroke() - { - return new GradientStroke(); - } - RadialGradientFill makeRadialFill() - { - return new RadialGradientFill(); - } - RadialGradientStroke makeRadialStroke() - { - return new RadialGradientStroke(); - } - - void load(ByteData data) - { - if(data.lengthInBytes < 5) - { - throw new UnsupportedError("Not a valid Flare file."); - } - int F = data.getUint8(0); - int L = data.getUint8(1); - int A = data.getUint8(2); - int R = data.getUint8(3); - int E = data.getUint8(4); - - dynamic inputData = data; - - if(F != 70 || L != 76 || A != 65 || R != 82 || E != 69) - { - Uint8List charCodes = data.buffer.asUint8List(); - String stringData = String.fromCharCodes(charCodes); - var jsonActor = jsonDecode(stringData); - Map jsonObject = new Map(); - jsonObject["container"] = jsonActor; - inputData = jsonObject; - } - - StreamReader reader = new StreamReader(inputData); - _version = reader.readVersion(); - - StreamReader block; - while((block=reader.readNextBlock(BlockTypesMap)) != null) - { - switch(block.blockType) - { - case BlockTypes.Artboards: - readArtboardsBlock(block); - break; - } - } - } - - void readArtboardsBlock(StreamReader block) - { - int artboardCount = block.readUint16Length(); - _artboards = new List(artboardCount); - - for(int artboardIndex = 0, end = _artboards.length; artboardIndex < end; artboardIndex++) - { - StreamReader artboardBlock = block.readNextBlock(BlockTypesMap); - if(artboardBlock == null) - { - break; - } - switch(artboardBlock.blockType) - { - case BlockTypes.ActorArtboard: - { - ActorArtboard artboard = makeArtboard(); - artboard.read(artboardBlock); - _artboards[artboardIndex] = artboard; - break; - } - } - } - } + } } \ No newline at end of file diff --git a/lib/flare/actor_artboard.dart b/lib/flare/actor_artboard.dart index d731cbe..960e01f 100644 --- a/lib/flare/actor_artboard.dart +++ b/lib/flare/actor_artboard.dart @@ -34,628 +34,576 @@ import "dart:typed_data"; import "math/aabb.dart"; import "dart:math"; -class ActorArtboard -{ - int _flags = ActorFlags.IsDrawOrderDirty | ActorFlags.IsVertexDeformDirty; - int _drawableNodeCount = 0; - int _nodeCount = 0; - int _dirtDepth = 0; - ActorNode _root; - List _components; - List _nodes; - List _drawableNodes; - List _animations; - List _dependencyOrder; - Actor _actor; - String _name; - Vec2D _translation = new Vec2D(); - double _width = 0.0; - double _height = 0.0; - Vec2D _origin = new Vec2D(); - bool _clipContents = true; - Float32List _color = new Float32List(4); - - String get name => _name; - double get width => _width; - double get height => _height; - Vec2D get origin => _origin; - Vec2D get translation => _translation; - bool get clipContents => _clipContents; - - ActorArtboard(Actor actor) - { - _actor = actor; - _root = new ActorNode.withArtboard(this); - } - - Actor get actor => _actor; - List get components => _components; - List get nodes => _nodes; - List get animations => _animations; - List get drawableNodes => _drawableNodes; - ActorComponent operator[](int index) - { - return _components[index]; - } - int get componentCount => _components.length; - int get nodeCount => _nodeCount; - int get drawNodeCount => _drawableNodeCount; - ActorNode get root => _root; - - bool addDependency(ActorComponent a, ActorComponent b) - { - List dependents = b.dependents; - if(dependents == null) - { - b.dependents = dependents = new List(); - } - if(dependents.contains(a)) - { - return false; - } - dependents.add(a); - return true; - } - - void sortDependencies() - { - DependencySorter sorter = new DependencySorter(); - _dependencyOrder = sorter.sort(_root); - int graphOrder = 0; - for(ActorComponent component in _dependencyOrder) - { - component.graphOrder = graphOrder++; - component.dirtMask = 255; - } - _flags |= ActorFlags.IsDirty; - } - - bool addDirt(ActorComponent component, int value, bool recurse) - { - if((component.dirtMask & value) == value) - { - // Already marked. - return false; - } - - // Make sure dirt is set before calling anything that can set more dirt. - int dirt = component.dirtMask | value; - component.dirtMask = dirt; - - _flags |= ActorFlags.IsDirty; - - component.onDirty(dirt); - - // If the order of this component is less than the current dirt depth, update the dirt depth - // so that the update loop can break out early and re-run (something up the tree is dirty). - if(component.graphOrder < _dirtDepth) - { - _dirtDepth = component.graphOrder; - } - if(!recurse) - { - return true; - } - List dependents = component.dependents; - if(dependents != null) - { - for(ActorComponent d in dependents) - { - addDirt(d, value, recurse); - } - } - - return true; - } - - ActorAnimation getAnimation(String name) - { - for(ActorAnimation a in _animations) - { - if(a.name == name) - { - return a; - } - } - return null; - } - - ActorNode getNode(String name) - { - for(ActorNode node in _nodes) - { - if(node != null && node.name == name) - { - return node; - } - } - return null; - } - - void markDrawOrderDirty() - { - _flags |= ActorFlags.IsDrawOrderDirty; - } - - bool get isVertexDeformDirty - { - return (_flags & ActorFlags.IsVertexDeformDirty) != 0x00; - } - - ActorArtboard makeInstance() - { - ActorArtboard artboardInstance = new ActorArtboard(_actor); - artboardInstance.copyArtboard(this); - return artboardInstance; - } - - void copyArtboard(ActorArtboard artboard) - { - _name = artboard._name; - Vec2D.copy(_translation, artboard._translation); - _width = artboard._width; - _height = artboard._height; - Vec2D.copy(_origin, artboard._origin); - _clipContents = artboard._clipContents; - - _color[0] = artboard._color[0]; - _color[1] = artboard._color[1]; - _color[2] = artboard._color[2]; - _color[3] = artboard._color[3]; - - _actor = artboard._actor; - _animations = artboard._animations; - _drawableNodeCount = artboard._drawableNodeCount; - _nodeCount = artboard._nodeCount; - - if(artboard.componentCount != 0) - { - _components = new List(artboard.componentCount); - } - if(_nodeCount != 0) // This will always be at least 1. - { - _nodes = new List(_nodeCount); - } - if(_drawableNodeCount != 0) - { - _drawableNodes = new List(_drawableNodeCount); - } - - if(artboard.componentCount != 0) - { - int idx = 0; - int drwIdx = 0; - int ndIdx = 0; - - for(ActorComponent component in artboard.components) - { - if(component == null) - { - _components[idx++] = null; - continue; - } - ActorComponent instanceComponent = component.makeInstance(this); - _components[idx++] = instanceComponent; - if(instanceComponent is ActorNode) - { - _nodes[ndIdx++] = instanceComponent; - } - - if(instanceComponent is ActorDrawable) - { - _drawableNodes[drwIdx++] = instanceComponent as ActorDrawable; - } - } - } - - _root = _components[0] as ActorNode; - - for(ActorComponent component in _components) - { - if(_root == component || component == null) - { - continue; - } - component.resolveComponentIndices(_components); - } - - for(ActorComponent component in _components) - { - if(_root == component || component == null) - { - continue; - } - component.completeResolve(); - } - - sortDependencies(); - - if (_drawableNodes != null) - { - _drawableNodes.sort((a,b) => a.drawOrder.compareTo(b.drawOrder)); - for(int i = 0; i < _drawableNodes.length; i++) - { - _drawableNodes[i].drawIndex = i; - } - } - } - - void advance(double seconds) - { - if((_flags & ActorFlags.IsDirty) != 0) - { - const int MaxSteps = 100; - int step = 0; - int count = _dependencyOrder.length; - while((_flags & ActorFlags.IsDirty) != 0 && step < MaxSteps) - { - _flags &= ~ActorFlags.IsDirty; - // Track dirt depth here so that if something else marks dirty, we restart. - for(int i = 0; i < count; i++) - { - ActorComponent component = _dependencyOrder[i]; - _dirtDepth = i; - int d = component.dirtMask; - if(d == 0) - { - continue; - } - component.dirtMask = 0; - component.update(d); - if(_dirtDepth < i) - { - break; - } - } - step++; - } - } - - if((_flags & ActorFlags.IsDrawOrderDirty) != 0) - { - _flags &= ~ActorFlags.IsDrawOrderDirty; - - if (_drawableNodes != null) - { - _drawableNodes.sort((a,b) => a.drawOrder.compareTo(b.drawOrder)); - for(int i = 0; i < _drawableNodes.length; i++) - { - _drawableNodes[i].drawIndex = i; - } - } - } - if((_flags & ActorFlags.IsVertexDeformDirty) != 0) - { - _flags &= ~ActorFlags.IsVertexDeformDirty; - for(int i = 0; i < _drawableNodeCount; i++) - { - ActorDrawable drawable = _drawableNodes[i]; - if(drawable is ActorImage && drawable.isVertexDeformDirty) - { - drawable.isVertexDeformDirty = false; - //updateVertexDeform(drawable); - } - } - } - } - - void read(StreamReader reader) - { - _name = reader.readString("name"); - reader.readFloat32Array(_translation.values, "translation"); - _width = reader.readFloat32("width"); - _height = reader.readFloat32("height"); - reader.readFloat32Array(_origin.values, "origin"); - _clipContents = reader.readBool("clipContents"); - reader.readFloat32Array(_color, "color"); - - StreamReader block; - while((block=reader.readNextBlock(BlockTypesMap)) != null) - { - switch(block.blockType) - { - case BlockTypes.Components: - readComponentsBlock(block); - break; - case BlockTypes.Animations: - readAnimationsBlock(block); - break; - } - } - } - - void readComponentsBlock(StreamReader block) - { - int componentCount = block.readUint16Length(); - _components = new List(componentCount+1); - _components[0] = _root; - - // Guaranteed from the exporter to be in index order. - _nodeCount = 1; - for(int componentIndex = 1, end = componentCount+1; componentIndex < end; componentIndex++) - { - StreamReader nodeBlock = block.readNextBlock(BlockTypesMap); - if(nodeBlock == null) - { - break; - } - ActorComponent component; - switch(nodeBlock.blockType) - { - case BlockTypes.ActorNode: - component = ActorNode.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorBone: - component = ActorBone.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorRootBone: - component = ActorRootBone.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorImageSequence: - component = ActorImage.readSequence(this, nodeBlock, actor.makeImageNode()); - ActorImage ai = component as ActorImage; - actor.maxTextureIndex = ai.sequenceFrames.last.atlasIndex; // Last atlasIndex is the biggest - break; - - case BlockTypes.ActorImage: - component = ActorImage.read(this, nodeBlock, actor.makeImageNode()); - if((component as ActorImage).textureIndex > actor.maxTextureIndex) - { - actor.maxTextureIndex = (component as ActorImage).textureIndex; - } - break; - - case BlockTypes.ActorIKTarget: - //component = ActorIKTarget.Read(this, nodeBlock); - break; - - case BlockTypes.ActorEvent: - component = ActorEvent.read(this, nodeBlock, null); - break; - - case BlockTypes.CustomIntProperty: - //component = CustomIntProperty.Read(this, nodeBlock); - break; - - case BlockTypes.CustomFloatProperty: - //component = CustomFloatProperty.Read(this, nodeBlock); - break; - - case BlockTypes.CustomStringProperty: - //component = CustomStringProperty.Read(this, nodeBlock); - break; - - case BlockTypes.CustomBooleanProperty: - //component = CustomBooleanProperty.Read(this, nodeBlock); - break; - - case BlockTypes.ActorColliderRectangle: - //component = ActorColliderRectangle.Read(this, nodeBlock); - break; - - case BlockTypes.ActorColliderTriangle: - //component = ActorColliderTriangle.Read(this, nodeBlock); - break; - - case BlockTypes.ActorColliderCircle: - //component = ActorColliderCircle.Read(this, nodeBlock); - break; - - case BlockTypes.ActorColliderPolygon: - //component = ActorColliderPolygon.Read(this, nodeBlock); - break; - - case BlockTypes.ActorColliderLine: - //component = ActorColliderLine.Read(this, nodeBlock); - break; - - case BlockTypes.ActorNodeSolo: - component = ActorNodeSolo.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorJellyBone: - component = ActorJellyBone.read(this, nodeBlock, null); - break; - - case BlockTypes.JellyComponent: - component = JellyComponent.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorIKConstraint: - component = ActorIKConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorDistanceConstraint: - component = ActorDistanceConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorTranslationConstraint: - component = ActorTranslationConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorScaleConstraint: - component = ActorScaleConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorRotationConstraint: - component = ActorRotationConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorTransformConstraint: - component = ActorTransformConstraint.read(this, nodeBlock, null); - break; - - case BlockTypes.ActorShape: - component = ActorShape.read(this, nodeBlock, actor.makeShapeNode()); - break; - - case BlockTypes.ActorPath: - component = ActorPath.read(this, nodeBlock, actor.makePathNode()); - break; - - case BlockTypes.ColorFill: - component = ColorFill.read(this, nodeBlock, actor.makeColorFill()); - break; - - case BlockTypes.ColorStroke: - component = ColorStroke.read(this, nodeBlock, actor.makeColorStroke()); - break; - - case BlockTypes.GradientFill: - component = GradientFill.read(this, nodeBlock, actor.makeGradientFill()); - break; - - case BlockTypes.GradientStroke: - component = GradientStroke.read(this, nodeBlock, actor.makeGradientStroke()); - break; - - case BlockTypes.RadialGradientFill: - component = RadialGradientFill.read(this, nodeBlock, actor.makeRadialFill()); - break; - - case BlockTypes.RadialGradientStroke: - component = RadialGradientStroke.read(this, nodeBlock, actor.makeRadialStroke()); - break; - - case BlockTypes.ActorEllipse: - component = ActorEllipse.read(this, nodeBlock, actor.makeEllipse()); - break; - - case BlockTypes.ActorRectangle: - component = ActorRectangle.read(this, nodeBlock, actor.makeRectangle()); - break; - - case BlockTypes.ActorTriangle: - component = ActorTriangle.read(this, nodeBlock, actor.makeTriangle()); - break; - - case BlockTypes.ActorStar: - component = ActorStar.read(this, nodeBlock, actor.makeStar()); - break; - - case BlockTypes.ActorPolygon: - component = ActorPolygon.read(this, nodeBlock, actor.makePolygon()); - break; - case BlockTypes.ActorSkin: - component = ActorComponent.read(this, nodeBlock, new ActorSkin()); - break; - } - if(component is ActorDrawable) - { - _drawableNodeCount++; - } - - if(component is ActorNode) - { - _nodeCount++; - } - _components[componentIndex] = component; - if(component != null) - { - component.idx = componentIndex; - } - } - - _drawableNodes = new List(_drawableNodeCount); - _nodes = new List(_nodeCount); - _nodes[0] = _root; - - // Resolve nodes. - int drwIdx = 0; - int anIdx = 0; - - for(int i = 1; i <= componentCount; i++) - { - ActorComponent c = _components[i]; - // Nodes can be null if we read from a file version that contained nodes that we don't interpret in this runtime. - if(c != null) - { - c.resolveComponentIndices(_components); - } - - if(c is ActorDrawable) - { - _drawableNodes[drwIdx++] = c as ActorDrawable; - } - - if(c is ActorNode) - { - ActorNode an = c; - if(an != null) - { - _nodes[anIdx++] = an; - } - } - } - - for(int i = 1; i <= componentCount; i++) - { - ActorComponent c = components[i]; - if(c != null) - { - c.completeResolve(); - } - } - - sortDependencies(); - } - - void readAnimationsBlock(StreamReader block) - { - // Read animations. - int animationCount = block.readUint16Length(); - _animations = new List(animationCount); - StreamReader animationBlock; - int animationIndex = 0; - - while((animationBlock=block.readNextBlock(BlockTypesMap)) != null) - { - switch(animationBlock.blockType) - { - case BlockTypes.Animation: - ActorAnimation anim = ActorAnimation.read(animationBlock, _components); - _animations[animationIndex++] = anim; - break; - } - } - } - - AABB artboardAABB() - { - double minX = -_origin[0] * width; - double minY = -_origin[1] * height; - return new AABB.fromValues(minX, minY, minX + _width, minY + height); - } - - AABB computeAABB() - { - AABB aabb; - for(ActorDrawable drawable in _drawableNodes) - { - // This is the axis aligned bounding box in the space of the parent (this case our shape). - AABB pathAABB = drawable.computeAABB(); - if(pathAABB == null) - { - continue; - } - if(aabb == null) - { - aabb = pathAABB; - } - else - { - // Combine. - aabb[0] = min(aabb[0], pathAABB[0]); - aabb[1] = min(aabb[1], pathAABB[1]); - - aabb[2] = max(aabb[2], pathAABB[2]); - aabb[3] = max(aabb[3], pathAABB[3]); - } - } - - return aabb; - } +class ActorArtboard { + int _flags = ActorFlags.IsDrawOrderDirty | ActorFlags.IsVertexDeformDirty; + int _drawableNodeCount = 0; + int _nodeCount = 0; + int _dirtDepth = 0; + ActorNode _root; + List _components; + List _nodes; + List _drawableNodes; + List _animations; + List _dependencyOrder; + Actor _actor; + String _name; + Vec2D _translation = new Vec2D(); + double _width = 0.0; + double _height = 0.0; + Vec2D _origin = new Vec2D(); + bool _clipContents = true; + Float32List _color = new Float32List(4); + + String get name => _name; + + double get width => _width; + + double get height => _height; + + Vec2D get origin => _origin; + + Vec2D get translation => _translation; + + bool get clipContents => _clipContents; + + ActorArtboard(Actor actor) { + _actor = actor; + _root = new ActorNode.withArtboard(this); + } + + Actor get actor => _actor; + + List get components => _components; + + List get nodes => _nodes; + + List get animations => _animations; + + List get drawableNodes => _drawableNodes; + + ActorComponent operator [](int index) { + return _components[index]; + } + + int get componentCount => _components.length; + + int get nodeCount => _nodeCount; + + int get drawNodeCount => _drawableNodeCount; + + ActorNode get root => _root; + + bool addDependency(ActorComponent a, ActorComponent b) { + List dependents = b.dependents; + if (dependents == null) { + b.dependents = dependents = new List(); + } + if (dependents.contains(a)) { + return false; + } + dependents.add(a); + return true; + } + + void sortDependencies() { + DependencySorter sorter = new DependencySorter(); + _dependencyOrder = sorter.sort(_root); + int graphOrder = 0; + for (ActorComponent component in _dependencyOrder) { + component.graphOrder = graphOrder++; + component.dirtMask = 255; + } + _flags |= ActorFlags.IsDirty; + } + + bool addDirt(ActorComponent component, int value, bool recurse) { + if ((component.dirtMask & value) == value) { + // Already marked. + return false; + } + + // Make sure dirt is set before calling anything that can set more dirt. + int dirt = component.dirtMask | value; + component.dirtMask = dirt; + + _flags |= ActorFlags.IsDirty; + + component.onDirty(dirt); + + // If the order of this component is less than the current dirt depth, update the dirt depth + // so that the update loop can break out early and re-run (something up the tree is dirty). + if (component.graphOrder < _dirtDepth) { + _dirtDepth = component.graphOrder; + } + if (!recurse) { + return true; + } + List dependents = component.dependents; + if (dependents != null) { + for (ActorComponent d in dependents) { + addDirt(d, value, recurse); + } + } + + return true; + } + + ActorAnimation getAnimation(String name) { + for (ActorAnimation a in _animations) { + if (a.name == name) { + return a; + } + } + return null; + } + + ActorNode getNode(String name) { + for (ActorNode node in _nodes) { + if (node != null && node.name == name) { + return node; + } + } + return null; + } + + void markDrawOrderDirty() { + _flags |= ActorFlags.IsDrawOrderDirty; + } + + bool get isVertexDeformDirty { + return (_flags & ActorFlags.IsVertexDeformDirty) != 0x00; + } + + ActorArtboard makeInstance() { + ActorArtboard artboardInstance = new ActorArtboard(_actor); + artboardInstance.copyArtboard(this); + return artboardInstance; + } + + void copyArtboard(ActorArtboard artboard) { + _name = artboard._name; + Vec2D.copy(_translation, artboard._translation); + _width = artboard._width; + _height = artboard._height; + Vec2D.copy(_origin, artboard._origin); + _clipContents = artboard._clipContents; + + _color[0] = artboard._color[0]; + _color[1] = artboard._color[1]; + _color[2] = artboard._color[2]; + _color[3] = artboard._color[3]; + + _actor = artboard._actor; + _animations = artboard._animations; + _drawableNodeCount = artboard._drawableNodeCount; + _nodeCount = artboard._nodeCount; + + if (artboard.componentCount != 0) { + _components = new List(artboard.componentCount); + } + if (_nodeCount != 0) // This will always be at least 1. + { + _nodes = new List(_nodeCount); + } + if (_drawableNodeCount != 0) { + _drawableNodes = new List(_drawableNodeCount); + } + + if (artboard.componentCount != 0) { + int idx = 0; + int drwIdx = 0; + int ndIdx = 0; + + for (ActorComponent component in artboard.components) { + if (component == null) { + _components[idx++] = null; + continue; + } + ActorComponent instanceComponent = component.makeInstance(this); + _components[idx++] = instanceComponent; + if (instanceComponent is ActorNode) { + _nodes[ndIdx++] = instanceComponent; + } + + if (instanceComponent is ActorDrawable) { + _drawableNodes[drwIdx++] = instanceComponent as ActorDrawable; + } + } + } + + _root = _components[0] as ActorNode; + + for (ActorComponent component in _components) { + if (_root == component || component == null) { + continue; + } + component.resolveComponentIndices(_components); + } + + for (ActorComponent component in _components) { + if (_root == component || component == null) { + continue; + } + component.completeResolve(); + } + + sortDependencies(); + + if (_drawableNodes != null) { + _drawableNodes.sort((a, b) => a.drawOrder.compareTo(b.drawOrder)); + for (int i = 0; i < _drawableNodes.length; i++) { + _drawableNodes[i].drawIndex = i; + } + } + } + + void advance(double seconds) { + if ((_flags & ActorFlags.IsDirty) != 0) { + const int MaxSteps = 100; + int step = 0; + int count = _dependencyOrder.length; + while ((_flags & ActorFlags.IsDirty) != 0 && step < MaxSteps) { + _flags &= ~ActorFlags.IsDirty; + // Track dirt depth here so that if something else marks dirty, we restart. + for (int i = 0; i < count; i++) { + ActorComponent component = _dependencyOrder[i]; + _dirtDepth = i; + int d = component.dirtMask; + if (d == 0) { + continue; + } + component.dirtMask = 0; + component.update(d); + if (_dirtDepth < i) { + break; + } + } + step++; + } + } + + if ((_flags & ActorFlags.IsDrawOrderDirty) != 0) { + _flags &= ~ActorFlags.IsDrawOrderDirty; + + if (_drawableNodes != null) { + _drawableNodes.sort((a, b) => a.drawOrder.compareTo(b.drawOrder)); + for (int i = 0; i < _drawableNodes.length; i++) { + _drawableNodes[i].drawIndex = i; + } + } + } + if ((_flags & ActorFlags.IsVertexDeformDirty) != 0) { + _flags &= ~ActorFlags.IsVertexDeformDirty; + for (int i = 0; i < _drawableNodeCount; i++) { + ActorDrawable drawable = _drawableNodes[i]; + if (drawable is ActorImage && drawable.isVertexDeformDirty) { + drawable.isVertexDeformDirty = false; + //updateVertexDeform(drawable); + } + } + } + } + + void read(StreamReader reader) { + _name = reader.readString("name"); + reader.readFloat32Array(_translation.values, "translation"); + _width = reader.readFloat32("width"); + _height = reader.readFloat32("height"); + reader.readFloat32Array(_origin.values, "origin"); + _clipContents = reader.readBool("clipContents"); + reader.readFloat32Array(_color, "color"); + + StreamReader block; + while ((block = reader.readNextBlock(BlockTypesMap)) != null) { + switch (block.blockType) { + case BlockTypes.Components: + readComponentsBlock(block); + break; + case BlockTypes.Animations: + readAnimationsBlock(block); + break; + } + } + } + + void readComponentsBlock(StreamReader block) { + int componentCount = block.readUint16Length(); + _components = new List(componentCount + 1); + _components[0] = _root; + + // Guaranteed from the exporter to be in index order. + _nodeCount = 1; + for (int componentIndex = 1, end = componentCount + 1; componentIndex < end; + componentIndex++) { + StreamReader nodeBlock = block.readNextBlock(BlockTypesMap); + if (nodeBlock == null) { + break; + } + ActorComponent component; + switch (nodeBlock.blockType) { + case BlockTypes.ActorNode: + component = ActorNode.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorBone: + component = ActorBone.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorRootBone: + component = ActorRootBone.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorImageSequence: + component = + ActorImage.readSequence(this, nodeBlock, actor.makeImageNode()); + ActorImage ai = component as ActorImage; + actor.maxTextureIndex = ai.sequenceFrames.last + .atlasIndex; // Last atlasIndex is the biggest + break; + + case BlockTypes.ActorImage: + component = ActorImage.read(this, nodeBlock, actor.makeImageNode()); + if ((component as ActorImage).textureIndex > actor.maxTextureIndex) { + actor.maxTextureIndex = (component as ActorImage).textureIndex; + } + break; + + case BlockTypes.ActorIKTarget: + //component = ActorIKTarget.Read(this, nodeBlock); + break; + + case BlockTypes.ActorEvent: + component = ActorEvent.read(this, nodeBlock, null); + break; + + case BlockTypes.CustomIntProperty: + //component = CustomIntProperty.Read(this, nodeBlock); + break; + + case BlockTypes.CustomFloatProperty: + //component = CustomFloatProperty.Read(this, nodeBlock); + break; + + case BlockTypes.CustomStringProperty: + //component = CustomStringProperty.Read(this, nodeBlock); + break; + + case BlockTypes.CustomBooleanProperty: + //component = CustomBooleanProperty.Read(this, nodeBlock); + break; + + case BlockTypes.ActorColliderRectangle: + //component = ActorColliderRectangle.Read(this, nodeBlock); + break; + + case BlockTypes.ActorColliderTriangle: + //component = ActorColliderTriangle.Read(this, nodeBlock); + break; + + case BlockTypes.ActorColliderCircle: + //component = ActorColliderCircle.Read(this, nodeBlock); + break; + + case BlockTypes.ActorColliderPolygon: + //component = ActorColliderPolygon.Read(this, nodeBlock); + break; + + case BlockTypes.ActorColliderLine: + //component = ActorColliderLine.Read(this, nodeBlock); + break; + + case BlockTypes.ActorNodeSolo: + component = ActorNodeSolo.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorJellyBone: + component = ActorJellyBone.read(this, nodeBlock, null); + break; + + case BlockTypes.JellyComponent: + component = JellyComponent.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorIKConstraint: + component = ActorIKConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorDistanceConstraint: + component = ActorDistanceConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorTranslationConstraint: + component = ActorTranslationConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorScaleConstraint: + component = ActorScaleConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorRotationConstraint: + component = ActorRotationConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorTransformConstraint: + component = ActorTransformConstraint.read(this, nodeBlock, null); + break; + + case BlockTypes.ActorShape: + component = ActorShape.read(this, nodeBlock, actor.makeShapeNode()); + break; + + case BlockTypes.ActorPath: + component = ActorPath.read(this, nodeBlock, actor.makePathNode()); + break; + + case BlockTypes.ColorFill: + component = ColorFill.read(this, nodeBlock, actor.makeColorFill()); + break; + + case BlockTypes.ColorStroke: + component = + ColorStroke.read(this, nodeBlock, actor.makeColorStroke()); + break; + + case BlockTypes.GradientFill: + component = + GradientFill.read(this, nodeBlock, actor.makeGradientFill()); + break; + + case BlockTypes.GradientStroke: + component = + GradientStroke.read(this, nodeBlock, actor.makeGradientStroke()); + break; + + case BlockTypes.RadialGradientFill: + component = + RadialGradientFill.read(this, nodeBlock, actor.makeRadialFill()); + break; + + case BlockTypes.RadialGradientStroke: + component = RadialGradientStroke.read( + this, nodeBlock, actor.makeRadialStroke()); + break; + + case BlockTypes.ActorEllipse: + component = ActorEllipse.read(this, nodeBlock, actor.makeEllipse()); + break; + + case BlockTypes.ActorRectangle: + component = + ActorRectangle.read(this, nodeBlock, actor.makeRectangle()); + break; + + case BlockTypes.ActorTriangle: + component = ActorTriangle.read(this, nodeBlock, actor.makeTriangle()); + break; + + case BlockTypes.ActorStar: + component = ActorStar.read(this, nodeBlock, actor.makeStar()); + break; + + case BlockTypes.ActorPolygon: + component = ActorPolygon.read(this, nodeBlock, actor.makePolygon()); + break; + case BlockTypes.ActorSkin: + component = ActorComponent.read(this, nodeBlock, new ActorSkin()); + break; + } + if (component is ActorDrawable) { + _drawableNodeCount++; + } + + if (component is ActorNode) { + _nodeCount++; + } + _components[componentIndex] = component; + if (component != null) { + component.idx = componentIndex; + } + } + + _drawableNodes = new List(_drawableNodeCount); + _nodes = new List(_nodeCount); + _nodes[0] = _root; + + // Resolve nodes. + int drwIdx = 0; + int anIdx = 0; + + for (int i = 1; i <= componentCount; i++) { + ActorComponent c = _components[i]; + // Nodes can be null if we read from a file version that contained nodes that we don't interpret in this runtime. + if (c != null) { + c.resolveComponentIndices(_components); + } + + if (c is ActorDrawable) { + _drawableNodes[drwIdx++] = c as ActorDrawable; + } + + if (c is ActorNode) { + ActorNode an = c; + if (an != null) { + _nodes[anIdx++] = an; + } + } + } + + for (int i = 1; i <= componentCount; i++) { + ActorComponent c = components[i]; + if (c != null) { + c.completeResolve(); + } + } + + sortDependencies(); + } + + void readAnimationsBlock(StreamReader block) { + // Read animations. + int animationCount = block.readUint16Length(); + _animations = new List(animationCount); + StreamReader animationBlock; + int animationIndex = 0; + + while ((animationBlock = block.readNextBlock(BlockTypesMap)) != null) { + switch (animationBlock.blockType) { + case BlockTypes.Animation: + ActorAnimation anim = ActorAnimation.read( + animationBlock, _components); + _animations[animationIndex++] = anim; + break; + } + } + } + + AABB artboardAABB() { + double minX = -_origin[0] * width; + double minY = -_origin[1] * height; + return new AABB.fromValues(minX, minY, minX + _width, minY + height); + } + + AABB computeAABB() { + AABB aabb; + for (ActorDrawable drawable in _drawableNodes) { + // This is the axis aligned bounding box in the space of the parent (this case our shape). + AABB pathAABB = drawable.computeAABB(); + if (pathAABB == null) { + continue; + } + if (aabb == null) { + aabb = pathAABB; + } + else { + // Combine. + aabb[0] = min(aabb[0], pathAABB[0]); + aabb[1] = min(aabb[1], pathAABB[1]); + + aabb[2] = max(aabb[2], pathAABB[2]); + aabb[3] = max(aabb[3], pathAABB[3]); + } + } + + return aabb; + } } \ No newline at end of file diff --git a/lib/flare/actor_axis_constraint.dart b/lib/flare/actor_axis_constraint.dart index fc04bef..1ad56e9 100644 --- a/lib/flare/actor_axis_constraint.dart +++ b/lib/flare/actor_axis_constraint.dart @@ -3,120 +3,127 @@ import "actor_targeted_constraint.dart"; import "transform_space.dart"; import "stream_reader.dart"; -abstract class ActorAxisConstraint extends ActorTargetedConstraint -{ - bool _copyX = false; - bool _copyY = false; - bool _enableMinX = false; - bool _enableMaxX = false; - bool _enableMinY = false; - bool _enableMaxY = false; - bool _offset = false; - - double _scaleX = 1.0; - double _scaleY = 1.0; - double _minX = 0.0; - double _maxX = 0.0; - double _minY = 0.0; - double _maxY = 0.0; - - int _sourceSpace = TransformSpace.World; - int _destSpace = TransformSpace.World; - int _minMaxSpace = TransformSpace.World; - - ActorAxisConstraint() : super(); - - static ActorAxisConstraint read(ActorArtboard artboard, StreamReader reader, ActorAxisConstraint component) - { - ActorTargetedConstraint.read(artboard, reader, component); - component._copyX = reader.readBool("copyX"); - if(component._copyX) - { - component._scaleX = reader.readFloat32("scaleX"); - } - - component._enableMinX = reader.readBool("enableMinX"); - if(component._enableMinX) - { - component._minX = reader.readFloat32("minX"); - } - - component._enableMaxX = reader.readBool("enableMaxX"); - if(component._enableMaxX) - { - component._maxX = reader.readFloat32("maxX"); - } - - component._copyY = reader.readBool("copyY"); - if(component._copyY) - { - component._scaleY = reader.readFloat32("scaleY"); - } - - component._enableMinY = reader.readBool("enableMinY"); - if(component._enableMinY) - { - component._minY = reader.readFloat32("minY"); - } - - component._enableMaxY = reader.readBool("enableMaxY"); - if(component._enableMaxY) - { - component._maxY = reader.readFloat32("maxY"); - } - - component._offset = reader.readBool("offset"); - component._sourceSpace = reader.readUint8("sourceSpaceId"); - component._destSpace = reader.readUint8("destSpaceId"); - component._minMaxSpace = reader.readUint8("minMaxSpaceId"); - - return component; +abstract class ActorAxisConstraint extends ActorTargetedConstraint { + bool _copyX = false; + bool _copyY = false; + bool _enableMinX = false; + bool _enableMaxX = false; + bool _enableMinY = false; + bool _enableMaxY = false; + bool _offset = false; + + double _scaleX = 1.0; + double _scaleY = 1.0; + double _minX = 0.0; + double _maxX = 0.0; + double _minY = 0.0; + double _maxY = 0.0; + + int _sourceSpace = TransformSpace.World; + int _destSpace = TransformSpace.World; + int _minMaxSpace = TransformSpace.World; + + ActorAxisConstraint() : super(); + + static ActorAxisConstraint read(ActorArtboard artboard, StreamReader reader, + ActorAxisConstraint component) { + ActorTargetedConstraint.read(artboard, reader, component); + component._copyX = reader.readBool("copyX"); + if (component._copyX) { + component._scaleX = reader.readFloat32("scaleX"); } - void copyAxisConstraint(ActorAxisConstraint node, ActorArtboard resetArtboard) - { - copyTargetedConstraint(node, resetArtboard); - - _copyX = node._copyX; - _copyY = node._copyY; - _enableMinX = node._enableMinX; - _enableMaxX = node._enableMaxX; - _enableMinY = node._enableMinY; - _enableMaxY = node._enableMaxY; - _offset = node._offset; - - _scaleX = node._scaleX; - _scaleY = node._scaleY; - _minX = node._minX; - _maxX = node._maxX; - _minY = node._minY; - _maxY = node._maxY; - - _sourceSpace = node._sourceSpace; - _destSpace = node._destSpace; - _minMaxSpace = node._minMaxSpace; + component._enableMinX = reader.readBool("enableMinX"); + if (component._enableMinX) { + component._minX = reader.readFloat32("minX"); } - @override - onDirty(int dirt) - { - markDirty(); + component._enableMaxX = reader.readBool("enableMaxX"); + if (component._enableMaxX) { + component._maxX = reader.readFloat32("maxX"); } - get copyX => _copyX; - get copyY => _copyY; - get destSpace => _destSpace; - get enableMaxX => _enableMaxX; - get enableMaxY => _enableMaxY; - get enableMinX => _enableMinX; - get enableMinY => _enableMinY; - get maxX => _maxX; - get maxY => _maxY; - get minMaxSpace => _minMaxSpace; - get minX => _minX; - get minY => _minY; - get offset => _offset; - get scaleX => _scaleX; - get scaleY => _scaleY; - get sourceSpace => _sourceSpace; + component._copyY = reader.readBool("copyY"); + if (component._copyY) { + component._scaleY = reader.readFloat32("scaleY"); + } + + component._enableMinY = reader.readBool("enableMinY"); + if (component._enableMinY) { + component._minY = reader.readFloat32("minY"); + } + + component._enableMaxY = reader.readBool("enableMaxY"); + if (component._enableMaxY) { + component._maxY = reader.readFloat32("maxY"); + } + + component._offset = reader.readBool("offset"); + component._sourceSpace = reader.readUint8("sourceSpaceId"); + component._destSpace = reader.readUint8("destSpaceId"); + component._minMaxSpace = reader.readUint8("minMaxSpaceId"); + + return component; + } + + void copyAxisConstraint(ActorAxisConstraint node, + ActorArtboard resetArtboard) { + copyTargetedConstraint(node, resetArtboard); + + _copyX = node._copyX; + _copyY = node._copyY; + _enableMinX = node._enableMinX; + _enableMaxX = node._enableMaxX; + _enableMinY = node._enableMinY; + _enableMaxY = node._enableMaxY; + _offset = node._offset; + + _scaleX = node._scaleX; + _scaleY = node._scaleY; + _minX = node._minX; + _maxX = node._maxX; + _minY = node._minY; + _maxY = node._maxY; + + _sourceSpace = node._sourceSpace; + _destSpace = node._destSpace; + _minMaxSpace = node._minMaxSpace; + } + + @override + onDirty(int dirt) { + markDirty(); + } + + get copyX => _copyX; + + get copyY => _copyY; + + get destSpace => _destSpace; + + get enableMaxX => _enableMaxX; + + get enableMaxY => _enableMaxY; + + get enableMinX => _enableMinX; + + get enableMinY => _enableMinY; + + get maxX => _maxX; + + get maxY => _maxY; + + get minMaxSpace => _minMaxSpace; + + get minX => _minX; + + get minY => _minY; + + get offset => _offset; + + get scaleX => _scaleX; + + get scaleY => _scaleY; + + get sourceSpace => _sourceSpace; } \ No newline at end of file diff --git a/lib/flare/actor_bone.dart b/lib/flare/actor_bone.dart index 0a5ef94..8757774 100644 --- a/lib/flare/actor_bone.dart +++ b/lib/flare/actor_bone.dart @@ -5,47 +5,39 @@ import "actor_component.dart"; import "actor_node.dart"; import "jelly_component.dart"; -class ActorBone extends ActorBoneBase -{ - ActorBone _firstBone; - JellyComponent jelly; +class ActorBone extends ActorBoneBase { + ActorBone _firstBone; + JellyComponent jelly; - ActorBone get firstBone - { - return _firstBone; - } + ActorBone get firstBone { + return _firstBone; + } - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorBone instanceNode = new ActorBone(); - instanceNode.copyBoneBase(this, resetArtboard); - return instanceNode; - } + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorBone instanceNode = new ActorBone(); + instanceNode.copyBoneBase(this, resetArtboard); + return instanceNode; + } - void completeResolve() - { - super.completeResolve(); - if(children == null) - { - return; - } - for(ActorNode node in children) - { - if(node is ActorBone) - { - _firstBone = node; - return; - } - } - } + void completeResolve() { + super.completeResolve(); + if (children == null) { + return; + } + for (ActorNode node in children) { + if (node is ActorBone) { + _firstBone = node; + return; + } + } + } - static ActorBone read(ActorArtboard artboard, StreamReader reader, ActorBone node) - { - if(node == null) - { - node = new ActorBone(); - } - ActorBoneBase.read(artboard, reader, node); - return node; - } + static ActorBone read(ActorArtboard artboard, StreamReader reader, + ActorBone node) { + if (node == null) { + node = new ActorBone(); + } + ActorBoneBase.read(artboard, reader, node); + return node; + } } \ No newline at end of file diff --git a/lib/flare/actor_bone_base.dart b/lib/flare/actor_bone_base.dart index 59707f1..bc74f67 100644 --- a/lib/flare/actor_bone_base.dart +++ b/lib/flare/actor_bone_base.dart @@ -4,57 +4,48 @@ import "actor_node.dart"; import "math/vec2d.dart"; import "math/mat2d.dart"; -class ActorBoneBase extends ActorNode -{ - double _length; - - double get length - { - return _length; - } - - set length(double value) - { - if(_length == value) - { - return; - } - _length = value; - if(children == null) - { - return; - } - for(ActorNode node in children) - { - if(node is ActorBoneBase) - { - node.x = value; - } - } - } - - Vec2D getTipWorldTranslation(Vec2D vec) - { - Mat2D transform = new Mat2D(); - transform[4] = _length; - Mat2D.multiply(transform, worldTransform, transform); - vec[0] = transform[4]; - vec[1] = transform[5]; - return vec; - } - - static ActorBoneBase read(ActorArtboard artboard, StreamReader reader, ActorBoneBase node) - { - ActorNode.read(artboard, reader, node); - - node._length = reader.readFloat32("length"); - - return node; - } - - void copyBoneBase(ActorBoneBase node, ActorArtboard resetArtboard) - { - super.copyNode(node, resetArtboard); - _length = node._length; - } +class ActorBoneBase extends ActorNode { + double _length; + + double get length { + return _length; + } + + set length(double value) { + if (_length == value) { + return; + } + _length = value; + if (children == null) { + return; + } + for (ActorNode node in children) { + if (node is ActorBoneBase) { + node.x = value; + } + } + } + + Vec2D getTipWorldTranslation(Vec2D vec) { + Mat2D transform = new Mat2D(); + transform[4] = _length; + Mat2D.multiply(transform, worldTransform, transform); + vec[0] = transform[4]; + vec[1] = transform[5]; + return vec; + } + + static ActorBoneBase read(ActorArtboard artboard, StreamReader reader, + ActorBoneBase node) { + ActorNode.read(artboard, reader, node); + + node._length = reader.readFloat32("length"); + + return node; + } + + void copyBoneBase(ActorBoneBase node, ActorArtboard resetArtboard) { + super.copyNode(node, resetArtboard); + _length = node._length; + } } \ No newline at end of file diff --git a/lib/flare/actor_color.dart b/lib/flare/actor_color.dart index 043fa49..3f2803c 100644 --- a/lib/flare/actor_color.dart +++ b/lib/flare/actor_color.dart @@ -11,358 +11,321 @@ import "dart:collection"; import "stream_reader.dart"; import "math/vec2d.dart"; -enum FillRule -{ - EvenOdd, - NonZero +enum FillRule { + EvenOdd, + NonZero } -HashMap fillRuleLookup = new HashMap.fromIterables([0,1], [FillRule.EvenOdd, FillRule.NonZero]); +HashMap fillRuleLookup = new HashMap.fromIterables([0, 1], [FillRule.EvenOdd, FillRule.NonZero]); -abstract class ActorPaint extends ActorComponent -{ - double opacity = 1.0; +abstract class ActorPaint extends ActorComponent { + double opacity = 1.0; - void copyPaint(ActorPaint component, ActorArtboard resetArtboard) - { - copyComponent(component, resetArtboard); - opacity = component.opacity; - } + void copyPaint(ActorPaint component, ActorArtboard resetArtboard) { + copyComponent(component, resetArtboard); + opacity = component.opacity; + } - static ActorPaint read(ActorArtboard artboard, StreamReader reader, ActorPaint component) - { - ActorComponent.read(artboard, reader, component); - component.opacity = reader.readFloat32("opacity"); + static ActorPaint read(ActorArtboard artboard, StreamReader reader, + ActorPaint component) { + ActorComponent.read(artboard, reader, component); + component.opacity = reader.readFloat32("opacity"); - return component; - } + return component; + } - completeResolve() - { - artboard.addDependency(this, parent); - } + completeResolve() { + artboard.addDependency(this, parent); + } } -abstract class ActorColor extends ActorPaint -{ - Float32List _color = new Float32List(4); - - Float32List get color - { - return _color; - } - - void copyColor(ActorColor node, ActorArtboard resetArtboard) - { - copyPaint(node, resetArtboard); - _color[0] = node._color[0]; - _color[1] = node._color[1]; - _color[2] = node._color[2]; - _color[3] = node._color[3]; - } - - static ActorColor read(ActorArtboard artboard, StreamReader reader, ActorColor component) - { - ActorPaint.read(artboard, reader, component); - - reader.readFloat32ArrayOffset(component._color, 4, 0, "color"); - - return component; - } - - void onDirty(int dirt) {} - void update(int dirt) {} +abstract class ActorColor extends ActorPaint { + Float32List _color = new Float32List(4); + + Float32List get color { + return _color; + } + + void copyColor(ActorColor node, ActorArtboard resetArtboard) { + copyPaint(node, resetArtboard); + _color[0] = node._color[0]; + _color[1] = node._color[1]; + _color[2] = node._color[2]; + _color[3] = node._color[3]; + } + + static ActorColor read(ActorArtboard artboard, StreamReader reader, + ActorColor component) { + ActorPaint.read(artboard, reader, component); + + reader.readFloat32ArrayOffset(component._color, 4, 0, "color"); + + return component; + } + + void onDirty(int dirt) {} + + void update(int dirt) {} } -class ColorFill extends ActorColor -{ - FillRule _fillRule = FillRule.EvenOdd; - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ColorFill instanceEvent = new ColorFill(); - instanceEvent.copyColorFill(this, resetArtboard); - return instanceEvent; - } - - void copyColorFill(ColorFill node, ActorArtboard resetArtboard) - { - copyColor(node, resetArtboard); - _fillRule = node._fillRule; - } - - static ColorFill read(ActorArtboard artboard, StreamReader reader, ColorFill component) - { - if(component == null) - { - component = new ColorFill(); - } - ActorColor.read(artboard, reader, component); - component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; - return component; - } +class ColorFill extends ActorColor { + FillRule _fillRule = FillRule.EvenOdd; + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ColorFill instanceEvent = new ColorFill(); + instanceEvent.copyColorFill(this, resetArtboard); + return instanceEvent; + } + + void copyColorFill(ColorFill node, ActorArtboard resetArtboard) { + copyColor(node, resetArtboard); + _fillRule = node._fillRule; + } + + static ColorFill read(ActorArtboard artboard, StreamReader reader, + ColorFill component) { + if (component == null) { + component = new ColorFill(); + } + ActorColor.read(artboard, reader, component); + component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; + return component; + } } -abstract class ActorStroke -{ - double get width; +abstract class ActorStroke { + double get width; } -class ColorStroke extends ActorColor implements ActorStroke -{ - double width = 1.0; +class ColorStroke extends ActorColor implements ActorStroke { + double width = 1.0; + + double get opacity => _color[3]; + + set opacity(double val) { + this.color[3] = val; + } - double get opacity => _color[3]; + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ColorStroke instanceEvent = new ColorStroke(); + instanceEvent.copyColorStroke(this, resetArtboard); + return instanceEvent; + } - set opacity(double val) - { - this.color[3] = val; + void copyColorStroke(ColorStroke node, ActorArtboard resetArtboard) { + copyColor(node, resetArtboard); + width = node.width; + } + + static ColorStroke read(ActorArtboard artboard, StreamReader reader, + ColorStroke component) { + if (component == null) { + component = new ColorStroke(); + } + ActorColor.read(artboard, reader, component); + component.width = reader.readFloat32("width"); + return component; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is ActorShape) { + parentNode.addStroke(this); } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ColorStroke instanceEvent = new ColorStroke(); - instanceEvent.copyColorStroke(this, resetArtboard); - return instanceEvent; - } - - void copyColorStroke(ColorStroke node, ActorArtboard resetArtboard) - { - copyColor(node, resetArtboard); - width = node.width; - } - - static ColorStroke read(ActorArtboard artboard, StreamReader reader, ColorStroke component) - { - if(component == null) - { - component = new ColorStroke(); - } - ActorColor.read(artboard, reader, component); - component.width = reader.readFloat32("width"); - return component; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is ActorShape) - { - parentNode.addStroke(this); - } - } + } } -abstract class GradientColor extends ActorPaint -{ - Float32List _colorStops = new Float32List(10); - Vec2D _start = new Vec2D(); - Vec2D _end = new Vec2D(); - Vec2D _renderStart = new Vec2D(); - Vec2D _renderEnd = new Vec2D(); - double opacity = 1.0; - - Vec2D get start => _start; - Vec2D get end => _end; - Vec2D get renderStart => _renderStart; - Vec2D get renderEnd => _renderEnd; - - Float32List get colorStops - { - return _colorStops; - } - - void copyGradient(GradientColor node, ActorArtboard resetArtboard) - { - copyPaint(node, resetArtboard); - _colorStops = new Float32List.fromList(node._colorStops); - Vec2D.copy(_start, node._start); - Vec2D.copy(_end, node._end); - opacity = node.opacity; - } - - static GradientColor read(ActorArtboard artboard, StreamReader reader, GradientColor component) - { - ActorPaint.read(artboard, reader, component); - - int numStops = reader.readUint8("numColorStops"); - Float32List stops = new Float32List(numStops*5); - reader.readFloat32ArrayOffset(stops, numStops*5, 0, "colorStops"); - component._colorStops = stops; - - reader.readFloat32ArrayOffset(component._start.values, 2, 0, "start"); - reader.readFloat32ArrayOffset(component._end.values, 2, 0, "end"); - - return component; - } - - void onDirty(int dirt) {} - void update(int dirt) - { - ActorShape shape = parent; - Mat2D world = shape.worldTransform; - Vec2D.transformMat2D(_renderStart, _start, world); - Vec2D.transformMat2D(_renderEnd, _end, world); - } +abstract class GradientColor extends ActorPaint { + Float32List _colorStops = new Float32List(10); + Vec2D _start = new Vec2D(); + Vec2D _end = new Vec2D(); + Vec2D _renderStart = new Vec2D(); + Vec2D _renderEnd = new Vec2D(); + double opacity = 1.0; + + Vec2D get start => _start; + + Vec2D get end => _end; + + Vec2D get renderStart => _renderStart; + + Vec2D get renderEnd => _renderEnd; + + Float32List get colorStops { + return _colorStops; + } + + void copyGradient(GradientColor node, ActorArtboard resetArtboard) { + copyPaint(node, resetArtboard); + _colorStops = new Float32List.fromList(node._colorStops); + Vec2D.copy(_start, node._start); + Vec2D.copy(_end, node._end); + opacity = node.opacity; + } + + static GradientColor read(ActorArtboard artboard, StreamReader reader, + GradientColor component) { + ActorPaint.read(artboard, reader, component); + + int numStops = reader.readUint8("numColorStops"); + Float32List stops = new Float32List(numStops * 5); + reader.readFloat32ArrayOffset(stops, numStops * 5, 0, "colorStops"); + component._colorStops = stops; + + reader.readFloat32ArrayOffset(component._start.values, 2, 0, "start"); + reader.readFloat32ArrayOffset(component._end.values, 2, 0, "end"); + + return component; + } + + void onDirty(int dirt) {} + + void update(int dirt) { + ActorShape shape = parent; + Mat2D world = shape.worldTransform; + Vec2D.transformMat2D(_renderStart, _start, world); + Vec2D.transformMat2D(_renderEnd, _end, world); + } } -class GradientFill extends GradientColor -{ - FillRule _fillRule = FillRule.EvenOdd; - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - GradientFill instanceEvent = new GradientFill(); - instanceEvent.copyGradientFill(this, resetArtboard); - return instanceEvent; - } - - void copyGradientFill(GradientFill node, ActorArtboard resetArtboard) - { - copyGradient(node, resetArtboard); - _fillRule = node._fillRule; - } - - static GradientFill read(ActorArtboard artboard, StreamReader reader, GradientFill component) - { - if(component == null) - { - component = new GradientFill(); - } - GradientColor.read(artboard, reader, component); - component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; - return component; - } +class GradientFill extends GradientColor { + FillRule _fillRule = FillRule.EvenOdd; + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + GradientFill instanceEvent = new GradientFill(); + instanceEvent.copyGradientFill(this, resetArtboard); + return instanceEvent; + } + + void copyGradientFill(GradientFill node, ActorArtboard resetArtboard) { + copyGradient(node, resetArtboard); + _fillRule = node._fillRule; + } + + static GradientFill read(ActorArtboard artboard, StreamReader reader, + GradientFill component) { + if (component == null) { + component = new GradientFill(); + } + GradientColor.read(artboard, reader, component); + component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; + return component; + } } -class GradientStroke extends GradientColor implements ActorStroke -{ - double width = 1.0; - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - GradientStroke instanceEvent = new GradientStroke(); - instanceEvent.copyGradientStroke(this, resetArtboard); - return instanceEvent; - } - - void copyGradientStroke(GradientStroke node, ActorArtboard resetArtboard) - { - copyGradient(node, resetArtboard); - width = node.width; - } - - static GradientStroke read(ActorArtboard artboard, StreamReader reader, GradientStroke component) - { - if(component == null) - { - component = new GradientStroke(); - } - GradientColor.read(artboard, reader, component); - component.width = reader.readFloat32("width"); - return component; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is ActorShape) - { - parentNode.addStroke(this); - } - } +class GradientStroke extends GradientColor implements ActorStroke { + double width = 1.0; + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + GradientStroke instanceEvent = new GradientStroke(); + instanceEvent.copyGradientStroke(this, resetArtboard); + return instanceEvent; + } + + void copyGradientStroke(GradientStroke node, ActorArtboard resetArtboard) { + copyGradient(node, resetArtboard); + width = node.width; + } + + static GradientStroke read(ActorArtboard artboard, StreamReader reader, + GradientStroke component) { + if (component == null) { + component = new GradientStroke(); + } + GradientColor.read(artboard, reader, component); + component.width = reader.readFloat32("width"); + return component; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is ActorShape) { + parentNode.addStroke(this); + } + } } -abstract class RadialGradientColor extends GradientColor -{ - double secondaryRadiusScale = 1.0; +abstract class RadialGradientColor extends GradientColor { + double secondaryRadiusScale = 1.0; - void copyRadialGradient(RadialGradientColor node, ActorArtboard resetArtboard) - { - copyGradient(node, resetArtboard); - secondaryRadiusScale = node.secondaryRadiusScale; - } + void copyRadialGradient(RadialGradientColor node, + ActorArtboard resetArtboard) { + copyGradient(node, resetArtboard); + secondaryRadiusScale = node.secondaryRadiusScale; + } - static RadialGradientColor read(ActorArtboard artboard, StreamReader reader, RadialGradientColor component) - { - GradientColor.read(artboard, reader, component); + static RadialGradientColor read(ActorArtboard artboard, StreamReader reader, + RadialGradientColor component) { + GradientColor.read(artboard, reader, component); - component.secondaryRadiusScale = reader.readFloat32("secondaryRadiusScale"); - - return component; - } + component.secondaryRadiusScale = reader.readFloat32("secondaryRadiusScale"); + + return component; + } } -class RadialGradientFill extends RadialGradientColor -{ - FillRule _fillRule = FillRule.EvenOdd; - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - RadialGradientFill instanceEvent = new RadialGradientFill(); - instanceEvent.copyRadialFill(this, resetArtboard); - return instanceEvent; - } - - void copyRadialFill(RadialGradientFill node, ActorArtboard resetArtboard) - { - copyRadialGradient(node, resetArtboard); - _fillRule = node._fillRule; - } - - static RadialGradientFill read(ActorArtboard artboard, StreamReader reader, RadialGradientFill component) - { - if(component == null) - { - component = new RadialGradientFill(); - } - RadialGradientColor.read(artboard, reader, component); - component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; - return component; - } +class RadialGradientFill extends RadialGradientColor { + FillRule _fillRule = FillRule.EvenOdd; + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + RadialGradientFill instanceEvent = new RadialGradientFill(); + instanceEvent.copyRadialFill(this, resetArtboard); + return instanceEvent; + } + + void copyRadialFill(RadialGradientFill node, ActorArtboard resetArtboard) { + copyRadialGradient(node, resetArtboard); + _fillRule = node._fillRule; + } + + static RadialGradientFill read(ActorArtboard artboard, StreamReader reader, + RadialGradientFill component) { + if (component == null) { + component = new RadialGradientFill(); + } + RadialGradientColor.read(artboard, reader, component); + component._fillRule = fillRuleLookup[reader.readUint8("fillRule")]; + return component; + } } -class RadialGradientStroke extends RadialGradientColor implements ActorStroke -{ - double width = 1.0; - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - RadialGradientStroke instanceEvent = new RadialGradientStroke(); - instanceEvent.copyRadialStroke(this, resetArtboard); - return instanceEvent; - } - - void copyRadialStroke(RadialGradientStroke node, ActorArtboard resetArtboard) - { - copyRadialGradient(node, resetArtboard); - width = node.width; - } - - static RadialGradientStroke read(ActorArtboard artboard, StreamReader reader, RadialGradientStroke component) - { - if(component == null) - { - component = new RadialGradientStroke(); - } - RadialGradientColor.read(artboard, reader, component); - component.width = reader.readFloat32("width"); - return component; - } - - void completeResolve() - { - super.completeResolve(); - - ActorNode parentNode = parent; - if(parentNode is ActorShape) - { - parentNode.addStroke(this); - } - } +class RadialGradientStroke extends RadialGradientColor implements ActorStroke { + double width = 1.0; + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + RadialGradientStroke instanceEvent = new RadialGradientStroke(); + instanceEvent.copyRadialStroke(this, resetArtboard); + return instanceEvent; + } + + void copyRadialStroke(RadialGradientStroke node, + ActorArtboard resetArtboard) { + copyRadialGradient(node, resetArtboard); + width = node.width; + } + + static RadialGradientStroke read(ActorArtboard artboard, StreamReader reader, + RadialGradientStroke component) { + if (component == null) { + component = new RadialGradientStroke(); + } + RadialGradientColor.read(artboard, reader, component); + component.width = reader.readFloat32("width"); + return component; + } + + void completeResolve() { + super.completeResolve(); + + ActorNode parentNode = parent; + if (parentNode is ActorShape) { + parentNode.addStroke(this); + } + } } \ No newline at end of file diff --git a/lib/flare/actor_component.dart b/lib/flare/actor_component.dart index e259945..e9c6801 100644 --- a/lib/flare/actor_component.dart +++ b/lib/flare/actor_component.dart @@ -2,68 +2,63 @@ import "stream_reader.dart"; import "actor_artboard.dart"; import "actor_node.dart"; -abstract class ActorComponent -{ - String _name = "Unnamed"; - ActorNode parent; - ActorArtboard artboard; - int _parentIdx = 0; - int idx = 0; - int graphOrder = 0; - int dirtMask = 0; - List dependents; +abstract class ActorComponent { + String _name = "Unnamed"; + ActorNode parent; + ActorArtboard artboard; + int _parentIdx = 0; + int idx = 0; + int graphOrder = 0; + int dirtMask = 0; + List dependents; - ActorComponent.withArtboard(ActorArtboard artboard) - { - this.artboard = artboard; - } + ActorComponent.withArtboard(ActorArtboard artboard) + { + this.artboard = artboard; + } - ActorComponent() - { + ActorComponent() { - } + } - String get name - { - return _name; - } + String get name { + return _name; + } - void resolveComponentIndices(List components) - { - ActorNode node = components[_parentIdx] as ActorNode; - if(node != null) - { - if(this is ActorNode) - { - node.addChild(this as ActorNode); - } - else - { - parent = node; - } - artboard.addDependency(this, node); - } - } + void resolveComponentIndices(List components) { + ActorNode node = components[_parentIdx] as ActorNode; + if (node != null) { + if (this is ActorNode) { + node.addChild(this as ActorNode); + } + else { + parent = node; + } + artboard.addDependency(this, node); + } + } - void completeResolve(); - ActorComponent makeInstance(ActorArtboard resetArtboard); - void onDirty(int dirt); - void update(int dirt); + void completeResolve(); - static ActorComponent read(ActorArtboard artboard, StreamReader reader, ActorComponent component) - { - component.artboard = artboard; - component._name = reader.readString("name"); - component._parentIdx = reader.readId("parent"); + ActorComponent makeInstance(ActorArtboard resetArtboard); - return component; - } + void onDirty(int dirt); - void copyComponent(ActorComponent component, ActorArtboard resetArtboard) - { - _name = component._name; - artboard = resetArtboard; - _parentIdx = component._parentIdx; - idx = component.idx; - } + void update(int dirt); + + static ActorComponent read(ActorArtboard artboard, StreamReader reader, + ActorComponent component) { + component.artboard = artboard; + component._name = reader.readString("name"); + component._parentIdx = reader.readId("parent"); + + return component; + } + + void copyComponent(ActorComponent component, ActorArtboard resetArtboard) { + _name = component._name; + artboard = resetArtboard; + _parentIdx = component._parentIdx; + idx = component.idx; + } } \ No newline at end of file diff --git a/lib/flare/actor_constraint.dart b/lib/flare/actor_constraint.dart index 567e0f1..715cc5b 100644 --- a/lib/flare/actor_constraint.dart +++ b/lib/flare/actor_constraint.dart @@ -3,77 +3,65 @@ import "actor_node.dart"; import "actor_artboard.dart"; import "stream_reader.dart"; -abstract class ActorConstraint extends ActorComponent -{ - bool _isEnabled; - double _strength; +abstract class ActorConstraint extends ActorComponent { + bool _isEnabled; + double _strength; - bool get isEnabled - { - return _isEnabled; - } + bool get isEnabled { + return _isEnabled; + } - set isEnabled(bool value) - { - if(value == _isEnabled) - { - return; - } - _isEnabled = value; - markDirty(); - } + set isEnabled(bool value) { + if (value == _isEnabled) { + return; + } + _isEnabled = value; + markDirty(); + } - void onDirty(int dirt) - { - markDirty(); - } + void onDirty(int dirt) { + markDirty(); + } - double get strength - { - return _strength; - } - - set strength(double value) - { - if(value == _strength) - { - return; - } - _strength = value; - markDirty(); - } + double get strength { + return _strength; + } - void markDirty() - { - parent.markTransformDirty(); - } + set strength(double value) { + if (value == _strength) { + return; + } + _strength = value; + markDirty(); + } - void constrain(ActorNode node); + void markDirty() { + parent.markTransformDirty(); + } - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - if(parent != null) - { - // This works because nodes are exported in hierarchy order, so we are assured constraints get added in order as we resolve indices. - parent.addConstraint(this); - } - } + void constrain(ActorNode node); - static ActorConstraint read(ActorArtboard artboard, StreamReader reader, ActorConstraint component) - { - ActorComponent.read(artboard, reader, component); - component._strength = reader.readFloat32("strength"); - component._isEnabled = reader.readBool("isEnabled"); + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + if (parent != null) { + // This works because nodes are exported in hierarchy order, so we are assured constraints get added in order as we resolve indices. + parent.addConstraint(this); + } + } - return component; - } + static ActorConstraint read(ActorArtboard artboard, StreamReader reader, + ActorConstraint component) { + ActorComponent.read(artboard, reader, component); + component._strength = reader.readFloat32("strength"); + component._isEnabled = reader.readBool("isEnabled"); - void copyConstraint(ActorConstraint node, ActorArtboard resetArtboard) - { - copyComponent(node, resetArtboard); + return component; + } - _isEnabled = node._isEnabled; - _strength = node._strength; - } + void copyConstraint(ActorConstraint node, ActorArtboard resetArtboard) { + copyComponent(node, resetArtboard); + + _isEnabled = node._isEnabled; + _strength = node._strength; + } } \ No newline at end of file diff --git a/lib/flare/actor_distance_constraint.dart b/lib/flare/actor_distance_constraint.dart index ce96b00..3284639 100644 --- a/lib/flare/actor_distance_constraint.dart +++ b/lib/flare/actor_distance_constraint.dart @@ -5,116 +5,106 @@ import "stream_reader.dart"; import "math/vec2d.dart"; import "math/mat2d.dart"; -class DistanceMode -{ - static const int Closer = 0; - static const int Further = 1; - static const int Exact = 2; +class DistanceMode { + static const int Closer = 0; + static const int Further = 1; + static const int Exact = 2; } -class ActorDistanceConstraint extends ActorTargetedConstraint -{ - double _distance = 100.0; - int _mode = DistanceMode.Closer; +class ActorDistanceConstraint extends ActorTargetedConstraint { + double _distance = 100.0; + int _mode = DistanceMode.Closer; - ActorDistanceConstraint() : super(); + ActorDistanceConstraint() : super(); - static ActorDistanceConstraint read(ActorArtboard artboard, StreamReader reader, ActorDistanceConstraint component) - { - if(component == null) - { - component = new ActorDistanceConstraint(); - } - ActorTargetedConstraint.read(artboard, reader, component); - - component._distance = reader.readFloat32("distance"); - component._mode = reader.readUint8("modeId"); - - return component; - } - - @override - ActorDistanceConstraint makeInstance(ActorArtboard resetArtboard) - { - ActorDistanceConstraint node = new ActorDistanceConstraint(); - node.copyDistanceConstraint(this, resetArtboard); - return node; + static ActorDistanceConstraint read(ActorArtboard artboard, + StreamReader reader, ActorDistanceConstraint component) { + if (component == null) { + component = new ActorDistanceConstraint(); } - - void copyDistanceConstraint(ActorDistanceConstraint node, ActorArtboard resetArtboard) - { - copyTargetedConstraint(node, resetArtboard); - _distance = node._distance; - _mode = node._mode; + ActorTargetedConstraint.read(artboard, reader, component); + + component._distance = reader.readFloat32("distance"); + component._mode = reader.readUint8("modeId"); + + return component; + } + + @override + ActorDistanceConstraint makeInstance(ActorArtboard resetArtboard) { + ActorDistanceConstraint node = new ActorDistanceConstraint(); + node.copyDistanceConstraint(this, resetArtboard); + return node; + } + + void copyDistanceConstraint(ActorDistanceConstraint node, + ActorArtboard resetArtboard) { + copyTargetedConstraint(node, resetArtboard); + _distance = node._distance; + _mode = node._mode; + } + + @override + constrain(ActorNode node) { + ActorNode t = this.target; + if (t == null) { + return; } - @override - constrain(ActorNode node) - { - ActorNode t = this.target; - if(t == null) - { - return; + ActorNode p = this.parent; + Vec2D targetTranslation = t.getWorldTranslation(new Vec2D()); + Vec2D ourTranslation = p.getWorldTranslation(new Vec2D()); + + Vec2D toTarget = Vec2D.subtract( + new Vec2D(), ourTranslation, targetTranslation); + double currentDistance = Vec2D.length(toTarget); + switch (_mode) { + case DistanceMode.Closer: + if (currentDistance < _distance) { + return; } + break; - ActorNode p = this.parent; - Vec2D targetTranslation = t.getWorldTranslation(new Vec2D()); - Vec2D ourTranslation = p.getWorldTranslation(new Vec2D()); - - Vec2D toTarget = Vec2D.subtract(new Vec2D(), ourTranslation, targetTranslation); - double currentDistance = Vec2D.length(toTarget); - switch(_mode) - { - case DistanceMode.Closer: - if(currentDistance < _distance) - { - return; - } - break; - - case DistanceMode.Further: - if(currentDistance > _distance) - { - return; - } - break; + case DistanceMode.Further: + if (currentDistance > _distance) { + return; } + break; + } - if(currentDistance < 0.001) - { - return; - } + if (currentDistance < 0.001) { + return; + } - Vec2D.scale(toTarget, toTarget, 1.0/currentDistance); - Vec2D.scale(toTarget, toTarget, _distance); + Vec2D.scale(toTarget, toTarget, 1.0 / currentDistance); + Vec2D.scale(toTarget, toTarget, _distance); - Mat2D world = p.worldTransform; - Vec2D position = Vec2D.lerp(new Vec2D(), ourTranslation, Vec2D.add(new Vec2D(), targetTranslation, toTarget), strength); - world[4] = position[0]; - world[5] = position[1]; - } + Mat2D world = p.worldTransform; + Vec2D position = Vec2D.lerp(new Vec2D(), ourTranslation, + Vec2D.add(new Vec2D(), targetTranslation, toTarget), strength); + world[4] = position[0]; + world[5] = position[1]; + } - void update(int dirt) {} - void completeResolve() {} + void update(int dirt) {} - get distance => _distance; - get mode => _mode; + void completeResolve() {} - set distance(double d) - { - if(_distance != d) - { - _distance = d; - this.markDirty(); - } + get distance => _distance; + + get mode => _mode; + + set distance(double d) { + if (_distance != d) { + _distance = d; + this.markDirty(); } + } - set mode(int m) - { - if(_mode != m) - { - _mode = m; - this.markDirty(); - } + set mode(int m) { + if (_mode != m) { + _mode = m; + this.markDirty(); } + } } \ No newline at end of file diff --git a/lib/flare/actor_drawable.dart b/lib/flare/actor_drawable.dart index 7264bbb..fe33718 100644 --- a/lib/flare/actor_drawable.dart +++ b/lib/flare/actor_drawable.dart @@ -1,21 +1,22 @@ import "math/aabb.dart"; -enum BlendModes -{ - Normal, - Multiply, - Screen, - Additive +enum BlendModes { + Normal, + Multiply, + Screen, + Additive } -abstract class ActorDrawable -{ - // Editor set draw index. - int get drawOrder; - set drawOrder(int value); - // Computed draw index in the draw list. - int get drawIndex; - set drawIndex(int value); - - AABB computeAABB(); +abstract class ActorDrawable { + // Editor set draw index. + int get drawOrder; + + set drawOrder(int value); + + // Computed draw index in the draw list. + int get drawIndex; + + set drawIndex(int value); + + AABB computeAABB(); } \ No newline at end of file diff --git a/lib/flare/actor_ellipse.dart b/lib/flare/actor_ellipse.dart index ae973e5..3090497 100644 --- a/lib/flare/actor_ellipse.dart +++ b/lib/flare/actor_ellipse.dart @@ -8,77 +8,72 @@ import "path_point.dart"; const double CircleConstant = 0.55; -class ActorEllipse extends ActorProceduralPath -{ - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorEllipse instance = new ActorEllipse(); - instance.copyPath(this, resetArtboard); - return instance; +class ActorEllipse extends ActorProceduralPath { + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorEllipse instance = new ActorEllipse(); + instance.copyPath(this, resetArtboard); + return instance; + } + + @override + void invalidatePath() { + } + + static ActorEllipse read(ActorArtboard artboard, StreamReader reader, + ActorEllipse component) { + if (component == null) { + component = new ActorEllipse(); } - @override - void invalidatePath() - { - } - - static ActorEllipse read(ActorArtboard artboard, StreamReader reader, ActorEllipse component) - { - if(component == null) - { - component = new ActorEllipse(); - } + ActorNode.read(artboard, reader, component); - ActorNode.read(artboard, reader, component); + component.width = reader.readFloat32("width"); + component.height = reader.readFloat32("height"); + return component; + } - component.width = reader.readFloat32("width"); - component.height = reader.readFloat32("height"); - return component; - } + @override + List get points { + List _ellipsePathPoints = []; + _ellipsePathPoints.add( + new CubicPathPoint.fromValues( + Vec2D.fromValues(0.0, -radiusY), + Vec2D.fromValues(-radiusX * CircleConstant, -radiusY), + Vec2D.fromValues(radiusX * CircleConstant, -radiusY) + ) + ); + _ellipsePathPoints.add( + new CubicPathPoint.fromValues( + Vec2D.fromValues(radiusX, 0.0), + Vec2D.fromValues(radiusX, CircleConstant * -radiusY), + Vec2D.fromValues(radiusX, CircleConstant * radiusY) + ) + ); + _ellipsePathPoints.add( + new CubicPathPoint.fromValues( + Vec2D.fromValues(0.0, radiusY), + Vec2D.fromValues(radiusX * CircleConstant, radiusY), + Vec2D.fromValues(-radiusX * CircleConstant, radiusY) + ) + ); + _ellipsePathPoints.add( + new CubicPathPoint.fromValues( + Vec2D.fromValues(-radiusX, 0.0), + Vec2D.fromValues(-radiusX, radiusY * CircleConstant), + Vec2D.fromValues(-radiusX, -radiusY * CircleConstant) + ) + ); - @override - List get points - { - List _ellipsePathPoints = []; - _ellipsePathPoints.add( - new CubicPathPoint.fromValues( - Vec2D.fromValues(0.0, -radiusY), - Vec2D.fromValues(-radiusX * CircleConstant, -radiusY), - Vec2D.fromValues(radiusX * CircleConstant, -radiusY) - ) - ); - _ellipsePathPoints.add( - new CubicPathPoint.fromValues( - Vec2D.fromValues(radiusX, 0.0), - Vec2D.fromValues(radiusX, CircleConstant * -radiusY), - Vec2D.fromValues(radiusX, CircleConstant * radiusY) - ) - ); - _ellipsePathPoints.add( - new CubicPathPoint.fromValues( - Vec2D.fromValues(0.0, radiusY), - Vec2D.fromValues(radiusX * CircleConstant, radiusY), - Vec2D.fromValues(-radiusX * CircleConstant, radiusY) - ) - ); - _ellipsePathPoints.add( - new CubicPathPoint.fromValues( - Vec2D.fromValues(-radiusX, 0.0), - Vec2D.fromValues(-radiusX, radiusY * CircleConstant), - Vec2D.fromValues(-radiusX, -radiusY * CircleConstant) - ) - ); + return _ellipsePathPoints; + } - return _ellipsePathPoints; - } + bool get isClosed => true; - bool get isClosed => true; - - bool get doesDraw - { - return !this.renderCollapsed; - } + bool get doesDraw { + return !this.renderCollapsed; + } + + double get radiusX => this.width / 2; - double get radiusX => this.width/2; - double get radiusY => this.height/2; + double get radiusY => this.height / 2; } \ No newline at end of file diff --git a/lib/flare/actor_event.dart b/lib/flare/actor_event.dart index 2f609c3..58713b6 100644 --- a/lib/flare/actor_event.dart +++ b/lib/flare/actor_event.dart @@ -1,30 +1,28 @@ - import "actor_component.dart"; import "actor_artboard.dart"; import "stream_reader.dart"; -class ActorEvent extends ActorComponent -{ - static ActorComponent read(ActorArtboard artboard, StreamReader reader, ActorEvent component) - { - if(component == null) - { - component = new ActorEvent(); - } +class ActorEvent extends ActorComponent { + static ActorComponent read(ActorArtboard artboard, StreamReader reader, + ActorEvent component) { + if (component == null) { + component = new ActorEvent(); + } + + ActorComponent.read(artboard, reader, component); + + return component; + } - ActorComponent.read(artboard, reader, component); + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorEvent instanceEvent = new ActorEvent(); + instanceEvent.copyComponent(this, resetArtboard); + return instanceEvent; + } - return component; - } + void completeResolve() {} - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorEvent instanceEvent = new ActorEvent(); - instanceEvent.copyComponent(this, resetArtboard); - return instanceEvent; - } + void onDirty(int dirt) {} - void completeResolve() {} - void onDirty(int dirt) {} - void update(int dirt) {} + void update(int dirt) {} } diff --git a/lib/flare/actor_flags.dart b/lib/flare/actor_flags.dart index c4a71fc..15cc642 100644 --- a/lib/flare/actor_flags.dart +++ b/lib/flare/actor_flags.dart @@ -1,6 +1,5 @@ -class ActorFlags -{ - static const int IsDrawOrderDirty = 1<<0; - static const int IsVertexDeformDirty = 1<<1; - static const int IsDirty = 1<<2; +class ActorFlags { + static const int IsDrawOrderDirty = 1 << 0; + static const int IsVertexDeformDirty = 1 << 1; + static const int IsDirty = 1 << 2; } \ No newline at end of file diff --git a/lib/flare/actor_ik_constraint.dart b/lib/flare/actor_ik_constraint.dart index 813e9d1..da9cabb 100644 --- a/lib/flare/actor_ik_constraint.dart +++ b/lib/flare/actor_ik_constraint.dart @@ -9,407 +9,358 @@ import "math/mat2d.dart"; import "math/vec2d.dart"; import "dart:math"; -class InfluencedBone -{ - int boneIdx; - ActorBone bone; +class InfluencedBone { + int boneIdx; + ActorBone bone; } -class BoneChain -{ - int index; - ActorBone bone; - double angle; - bool included; - TransformComponents transformComponents; - Mat2D parentWorldInverse; +class BoneChain { + int index; + ActorBone bone; + double angle; + bool included; + TransformComponents transformComponents; + Mat2D parentWorldInverse; } -class ActorIKConstraint extends ActorTargetedConstraint -{ - static const double PI2 = pi*2.0; - bool _invertDirection = false; - List _influencedBones; - List _fkChain; - List _boneData; - - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - - if(_influencedBones != null) - { - for(InfluencedBone influenced in _influencedBones) - { - influenced.bone = components[influenced.boneIdx] as ActorBone; - // Mark peer constraints, N.B. that we're not adding it to the parent bone - // as we're constraining it anyway. - if(influenced.bone != parent) - { - influenced.bone.addPeerConstraint(this); - } - } - } - } - - void completeResolve() - { - if(_influencedBones == null || _influencedBones.length == 0) - { - return; - } - - // Initialize solver. - ActorBone start = _influencedBones[0].bone; - ActorNode end = _influencedBones[_influencedBones.length-1].bone; - int count = 0; - while(end != null && end != start.parent) - { - count++; - end = end.parent; - } - - bool allIn = count < 3; - end = _influencedBones[_influencedBones.length-1].bone; - _fkChain = new List(count); - int idx = count-1; - while(end != null && end != start.parent) - { - BoneChain bc = new BoneChain(); - bc.bone = end; - bc.angle = 0.0; - bc.included = allIn; - bc.transformComponents = new TransformComponents(); - bc.parentWorldInverse = new Mat2D(); - bc.index = idx; - _fkChain[idx--] = bc; - end = end.parent; - } - - // Make sure bones are good. - _boneData = new List(); - for(InfluencedBone bone in _influencedBones) - { - BoneChain item = _fkChain.firstWhere((chainItem) => chainItem.bone == bone.bone, orElse: () => null); - if(item == null) - { - print("Bone not in chain: " + bone.bone.name); - continue; - } - _boneData.add(item); - } - if(!allIn) - { - // Influenced bones are in the IK chain. - for(int i = 0; i < _boneData.length-1; i++) - { - BoneChain item = _boneData[i]; - item.included = true; - _fkChain[item.index+1].included = true; - } - - } - - // Finally mark dependencies. - for(InfluencedBone bone in _influencedBones) - { - // Don't mark dependency on parent as ActorComponent already does this. - if(bone.bone == parent) - { - continue; - } - - artboard.addDependency(this, bone.bone); - } - - if(target != null) - { - artboard.addDependency(this, target); - } - - // All the first level children of the influenced bones should depend on the final bone. - BoneChain tip = _fkChain[_fkChain.length-1]; - for(BoneChain fk in _fkChain) - { - if(fk == tip) - { - continue; - } - - ActorBone bone = fk.bone; - for(ActorNode node in bone.children) - { - BoneChain item = _fkChain.firstWhere((chainItem) => chainItem.bone == node, orElse: () => null); - if(item != null) - { - // node is in the FK chain. - continue; - } - artboard.addDependency(node, tip.bone); - } - } - } - - static ActorIKConstraint read(ActorArtboard artboard, StreamReader reader, ActorIKConstraint component) - { - if(component == null) - { - component = new ActorIKConstraint(); - } - ActorTargetedConstraint.read(artboard, reader, component); - component._invertDirection = reader.readBool("isInverted"); - - reader.openArray("bones"); - int numInfluencedBones = reader.readUint8Length(); - if(numInfluencedBones > 0) - { - component._influencedBones = new List(numInfluencedBones); - - for(int i = 0; i < numInfluencedBones; i++) - { - InfluencedBone ib = new InfluencedBone(); - ib.boneIdx = reader.readId("");// No label here, we're just clearing the elements from the array. - component._influencedBones[i] = ib; - } - } - reader.closeArray(); - return component; - } - - void constrain(ActorNode node) - { - ActorNode target = this.target; - if(target == null) - { - return; - } - Vec2D worldTargetTranslation = new Vec2D(); - target.getWorldTranslation(worldTargetTranslation); - - if(_influencedBones.length == 0) - { - return; - } - - // Decompose the chain. - for(BoneChain item in _fkChain) - { - ActorBone bone = item.bone; - Mat2D parentWorld = bone.parent.worldTransform; - Mat2D.invert(item.parentWorldInverse, parentWorld); - Mat2D.multiply(bone.transform, item.parentWorldInverse, bone.worldTransform); - Mat2D.decompose(bone.transform, item.transformComponents); - } - - int count = _boneData.length; - if(count == 1) - { - solve1(_boneData[0], worldTargetTranslation); - } - else if(count == 2) - { - solve2(_boneData[0], _boneData[1], worldTargetTranslation); - } - else - { - BoneChain tip = _boneData[count-1]; - for(int i = 0; i < count-1; i++) - { - BoneChain item = _boneData[i]; - solve2(item, tip, worldTargetTranslation); - for(int j = item.index+1; j < _fkChain.length-1; j++) - { - BoneChain fk = _fkChain[j]; - Mat2D.invert(fk.parentWorldInverse, fk.bone.parent.worldTransform); - } - } - } - - // At the end, mix the FK angle with the IK angle by strength - if(strength != 1.0) - { - for(BoneChain fk in _fkChain) - { - if(!fk.included) - { - ActorBone bone = fk.bone; - Mat2D.multiply(bone.worldTransform, bone.parent.worldTransform, bone.transform); - continue; - } - double fromAngle = fk.transformComponents.rotation%PI2; - double toAngle = fk.angle%PI2; - double diff = toAngle - fromAngle; - if(diff > pi) - { - diff -= PI2; - } - else if(diff < -pi) - { - diff += PI2; - } - double angle = fromAngle + diff * strength; - constrainRotation(fk, angle); - } - } - } - - void constrainRotation(BoneChain fk, double rotation) - { - ActorBone bone = fk.bone; - Mat2D parentWorld = bone.parent.worldTransform; - Mat2D transform = bone.transform; - TransformComponents c = fk.transformComponents; - - if(rotation == 0.0) - { - Mat2D.identity(transform); - } - else - { - Mat2D.fromRotation(transform, rotation); - } - // Translate - transform[4] = c.x; - transform[5] = c.y; - // Scale - double scaleX = c.scaleX; - double scaleY = c.scaleY; - transform[0] *= scaleX; - transform[1] *= scaleX; - transform[2] *= scaleY; - transform[3] *= scaleY; - // Skew - double skew = c.skew; - if(skew != 0.0) - { - transform[2] = transform[0] * skew + transform[2]; - transform[3] = transform[1] * skew + transform[3]; - } - - Mat2D.multiply(bone.worldTransform, parentWorld, transform); - } - - void solve1(BoneChain fk1, Vec2D worldTargetTranslation) - { - Mat2D iworld = fk1.parentWorldInverse; - var pA = new Vec2D(); - fk1.bone.getWorldTranslation(pA); - var pBT = new Vec2D.clone(worldTargetTranslation); - - // To target in worldspace - Vec2D toTarget = Vec2D.subtract(new Vec2D(), pBT, pA); - // Note this is directional, hence not transformMat2d - Vec2D toTargetLocal = Vec2D.transformMat2(new Vec2D(), toTarget, iworld); - double r = atan2(toTargetLocal[1], toTargetLocal[0]); - - constrainRotation(fk1, r); - fk1.angle = r; - - } - - void solve2(BoneChain fk1, BoneChain fk2, Vec2D worldTargetTranslation) - { - ActorBone b1 = fk1.bone; - ActorBone b2 = fk2.bone; - BoneChain firstChild = _fkChain[fk1.index+1]; - - Mat2D iworld = fk1.parentWorldInverse; - - Vec2D pA = b1.getWorldTranslation(new Vec2D()); - Vec2D pC = firstChild.bone.getWorldTranslation(new Vec2D()); - Vec2D pB = b2.getTipWorldTranslation(new Vec2D());; - Vec2D pBT = new Vec2D.clone(worldTargetTranslation); - - pA = Vec2D.transformMat2D(pA, pA, iworld); - pC = Vec2D.transformMat2D(pC, pC, iworld); - pB = Vec2D.transformMat2D(pB, pB, iworld); - pBT = Vec2D.transformMat2D(pBT, pBT, iworld); - - // http://mathworld.wolfram.com/LawofCosines.html - Vec2D av = Vec2D.subtract(new Vec2D(), pB, pC); - double a = Vec2D.length(av); - - Vec2D bv = Vec2D.subtract(new Vec2D(), pC, pA); - double b = Vec2D.length(bv); - - Vec2D cv = Vec2D.subtract(new Vec2D(), pBT, pA); - double c = Vec2D.length(cv); - - double A = acos(max(-1,min(1,(-a*a+b*b+c*c)/(2*b*c)))); - double C = acos(max(-1, min(1,(a*a+b*b-c*c)/(2*a*b)))); - - double r1, r2; - if(b2.parent != b1) - { - BoneChain secondChild = _fkChain[fk1.index+2]; - - Mat2D secondChildWorldInverse = secondChild.parentWorldInverse; - - pC = firstChild.bone.getWorldTranslation(new Vec2D()); - pB = b2.getTipWorldTranslation(new Vec2D()); - - Vec2D avec = Vec2D.subtract(new Vec2D(), pB, pC); - Vec2D avLocal = Vec2D.transformMat2(new Vec2D(), avec, secondChildWorldInverse); - double angleCorrection = -atan2(avLocal[1], avLocal[0]); - - if(_invertDirection) - { - r1 = atan2(cv[1],cv[0]) - A; - r2 = -C+pi + angleCorrection; - } - else - { - r1 = A + atan2(cv[1],cv[0]); - r2 = C-pi + angleCorrection; - } - } - else if(_invertDirection) - { - r1 = atan2(cv[1],cv[0]) - A; - r2 = -C+pi; - } - else - { - r1 = A + atan2(cv[1],cv[0]); - r2 = C-pi; - } - - constrainRotation(fk1, r1); - constrainRotation(firstChild, r2); - if(firstChild != fk2) - { - ActorBone bone = fk2.bone; - Mat2D.multiply(bone.worldTransform, bone.parent.worldTransform, bone.transform); - } - - // Simple storage, need this for interpolation. - fk1.angle = r1; - firstChild.angle = r2; - } - - ActorComponent makeInstance(ActorArtboard artboard) - { - ActorIKConstraint instance = new ActorIKConstraint(); - instance.copyIKConstraint(this, artboard); - return instance; - } - - void copyIKConstraint(ActorIKConstraint node, ActorArtboard artboard) - { - copyTargetedConstraint(node, artboard); - - _invertDirection = node._invertDirection; - if(node._influencedBones != null) - { - _influencedBones = new List(node._influencedBones.length); - for(int i = 0; i < _influencedBones.length; i++) - { - InfluencedBone ib = new InfluencedBone(); - ib.boneIdx = node._influencedBones[i].boneIdx; - _influencedBones[i] = ib; - } - } - } - - void update(int dirt) {} +class ActorIKConstraint extends ActorTargetedConstraint { + static const double PI2 = pi * 2.0; + bool _invertDirection = false; + List _influencedBones; + List _fkChain; + List _boneData; + + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + + if (_influencedBones != null) { + for (InfluencedBone influenced in _influencedBones) { + influenced.bone = components[influenced.boneIdx] as ActorBone; + // Mark peer constraints, N.B. that we're not adding it to the parent bone + // as we're constraining it anyway. + if (influenced.bone != parent) { + influenced.bone.addPeerConstraint(this); + } + } + } + } + + void completeResolve() { + if (_influencedBones == null || _influencedBones.length == 0) { + return; + } + + // Initialize solver. + ActorBone start = _influencedBones[0].bone; + ActorNode end = _influencedBones[_influencedBones.length - 1].bone; + int count = 0; + while (end != null && end != start.parent) { + count++; + end = end.parent; + } + + bool allIn = count < 3; + end = _influencedBones[_influencedBones.length - 1].bone; + _fkChain = new List(count); + int idx = count - 1; + while (end != null && end != start.parent) { + BoneChain bc = new BoneChain(); + bc.bone = end; + bc.angle = 0.0; + bc.included = allIn; + bc.transformComponents = new TransformComponents(); + bc.parentWorldInverse = new Mat2D(); + bc.index = idx; + _fkChain[idx--] = bc; + end = end.parent; + } + + // Make sure bones are good. + _boneData = new List(); + for (InfluencedBone bone in _influencedBones) { + BoneChain item = _fkChain.firstWhere((chainItem) => + chainItem.bone == bone.bone, orElse: () => null); + if (item == null) { + print("Bone not in chain: " + bone.bone.name); + continue; + } + _boneData.add(item); + } + if (!allIn) { + // Influenced bones are in the IK chain. + for (int i = 0; i < _boneData.length - 1; i++) { + BoneChain item = _boneData[i]; + item.included = true; + _fkChain[item.index + 1].included = true; + } + } + + // Finally mark dependencies. + for (InfluencedBone bone in _influencedBones) { + // Don't mark dependency on parent as ActorComponent already does this. + if (bone.bone == parent) { + continue; + } + + artboard.addDependency(this, bone.bone); + } + + if (target != null) { + artboard.addDependency(this, target); + } + + // All the first level children of the influenced bones should depend on the final bone. + BoneChain tip = _fkChain[_fkChain.length - 1]; + for (BoneChain fk in _fkChain) { + if (fk == tip) { + continue; + } + + ActorBone bone = fk.bone; + for (ActorNode node in bone.children) { + BoneChain item = _fkChain.firstWhere((chainItem) => + chainItem.bone == node, orElse: () => null); + if (item != null) { + // node is in the FK chain. + continue; + } + artboard.addDependency(node, tip.bone); + } + } + } + + static ActorIKConstraint read(ActorArtboard artboard, StreamReader reader, + ActorIKConstraint component) { + if (component == null) { + component = new ActorIKConstraint(); + } + ActorTargetedConstraint.read(artboard, reader, component); + component._invertDirection = reader.readBool("isInverted"); + + reader.openArray("bones"); + int numInfluencedBones = reader.readUint8Length(); + if (numInfluencedBones > 0) { + component._influencedBones = new List(numInfluencedBones); + + for (int i = 0; i < numInfluencedBones; i++) { + InfluencedBone ib = new InfluencedBone(); + ib.boneIdx = reader.readId( + ""); // No label here, we're just clearing the elements from the array. + component._influencedBones[i] = ib; + } + } + reader.closeArray(); + return component; + } + + void constrain(ActorNode node) { + ActorNode target = this.target; + if (target == null) { + return; + } + Vec2D worldTargetTranslation = new Vec2D(); + target.getWorldTranslation(worldTargetTranslation); + + if (_influencedBones.length == 0) { + return; + } + + // Decompose the chain. + for (BoneChain item in _fkChain) { + ActorBone bone = item.bone; + Mat2D parentWorld = bone.parent.worldTransform; + Mat2D.invert(item.parentWorldInverse, parentWorld); + Mat2D.multiply( + bone.transform, item.parentWorldInverse, bone.worldTransform); + Mat2D.decompose(bone.transform, item.transformComponents); + } + + int count = _boneData.length; + if (count == 1) { + solve1(_boneData[0], worldTargetTranslation); + } + else if (count == 2) { + solve2(_boneData[0], _boneData[1], worldTargetTranslation); + } + else { + BoneChain tip = _boneData[count - 1]; + for (int i = 0; i < count - 1; i++) { + BoneChain item = _boneData[i]; + solve2(item, tip, worldTargetTranslation); + for (int j = item.index + 1; j < _fkChain.length - 1; j++) { + BoneChain fk = _fkChain[j]; + Mat2D.invert(fk.parentWorldInverse, fk.bone.parent.worldTransform); + } + } + } + + // At the end, mix the FK angle with the IK angle by strength + if (strength != 1.0) { + for (BoneChain fk in _fkChain) { + if (!fk.included) { + ActorBone bone = fk.bone; + Mat2D.multiply( + bone.worldTransform, bone.parent.worldTransform, bone.transform); + continue; + } + double fromAngle = fk.transformComponents.rotation % PI2; + double toAngle = fk.angle % PI2; + double diff = toAngle - fromAngle; + if (diff > pi) { + diff -= PI2; + } + else if (diff < -pi) { + diff += PI2; + } + double angle = fromAngle + diff * strength; + constrainRotation(fk, angle); + } + } + } + + void constrainRotation(BoneChain fk, double rotation) { + ActorBone bone = fk.bone; + Mat2D parentWorld = bone.parent.worldTransform; + Mat2D transform = bone.transform; + TransformComponents c = fk.transformComponents; + + if (rotation == 0.0) { + Mat2D.identity(transform); + } + else { + Mat2D.fromRotation(transform, rotation); + } + // Translate + transform[4] = c.x; + transform[5] = c.y; + // Scale + double scaleX = c.scaleX; + double scaleY = c.scaleY; + transform[0] *= scaleX; + transform[1] *= scaleX; + transform[2] *= scaleY; + transform[3] *= scaleY; + // Skew + double skew = c.skew; + if (skew != 0.0) { + transform[2] = transform[0] * skew + transform[2]; + transform[3] = transform[1] * skew + transform[3]; + } + + Mat2D.multiply(bone.worldTransform, parentWorld, transform); + } + + void solve1(BoneChain fk1, Vec2D worldTargetTranslation) { + Mat2D iworld = fk1.parentWorldInverse; + var pA = new Vec2D(); + fk1.bone.getWorldTranslation(pA); + var pBT = new Vec2D.clone(worldTargetTranslation); + + // To target in worldspace + Vec2D toTarget = Vec2D.subtract(new Vec2D(), pBT, pA); + // Note this is directional, hence not transformMat2d + Vec2D toTargetLocal = Vec2D.transformMat2(new Vec2D(), toTarget, iworld); + double r = atan2(toTargetLocal[1], toTargetLocal[0]); + + constrainRotation(fk1, r); + fk1.angle = r; + } + + void solve2(BoneChain fk1, BoneChain fk2, Vec2D worldTargetTranslation) { + ActorBone b1 = fk1.bone; + ActorBone b2 = fk2.bone; + BoneChain firstChild = _fkChain[fk1.index + 1]; + + Mat2D iworld = fk1.parentWorldInverse; + + Vec2D pA = b1.getWorldTranslation(new Vec2D()); + Vec2D pC = firstChild.bone.getWorldTranslation(new Vec2D()); + Vec2D pB = b2.getTipWorldTranslation(new Vec2D()); + ; + Vec2D pBT = new Vec2D.clone(worldTargetTranslation); + + pA = Vec2D.transformMat2D(pA, pA, iworld); + pC = Vec2D.transformMat2D(pC, pC, iworld); + pB = Vec2D.transformMat2D(pB, pB, iworld); + pBT = Vec2D.transformMat2D(pBT, pBT, iworld); + + // http://mathworld.wolfram.com/LawofCosines.html + Vec2D av = Vec2D.subtract(new Vec2D(), pB, pC); + double a = Vec2D.length(av); + + Vec2D bv = Vec2D.subtract(new Vec2D(), pC, pA); + double b = Vec2D.length(bv); + + Vec2D cv = Vec2D.subtract(new Vec2D(), pBT, pA); + double c = Vec2D.length(cv); + + double A = acos(max(-1, min(1, (-a * a + b * b + c * c) / (2 * b * c)))); + double C = acos(max(-1, min(1, (a * a + b * b - c * c) / (2 * a * b)))); + + double r1, r2; + if (b2.parent != b1) { + BoneChain secondChild = _fkChain[fk1.index + 2]; + + Mat2D secondChildWorldInverse = secondChild.parentWorldInverse; + + pC = firstChild.bone.getWorldTranslation(new Vec2D()); + pB = b2.getTipWorldTranslation(new Vec2D()); + + Vec2D avec = Vec2D.subtract(new Vec2D(), pB, pC); + Vec2D avLocal = Vec2D.transformMat2( + new Vec2D(), avec, secondChildWorldInverse); + double angleCorrection = -atan2(avLocal[1], avLocal[0]); + + if (_invertDirection) { + r1 = atan2(cv[1], cv[0]) - A; + r2 = -C + pi + angleCorrection; + } + else { + r1 = A + atan2(cv[1], cv[0]); + r2 = C - pi + angleCorrection; + } + } + else if (_invertDirection) { + r1 = atan2(cv[1], cv[0]) - A; + r2 = -C + pi; + } + else { + r1 = A + atan2(cv[1], cv[0]); + r2 = C - pi; + } + + constrainRotation(fk1, r1); + constrainRotation(firstChild, r2); + if (firstChild != fk2) { + ActorBone bone = fk2.bone; + Mat2D.multiply( + bone.worldTransform, bone.parent.worldTransform, bone.transform); + } + + // Simple storage, need this for interpolation. + fk1.angle = r1; + firstChild.angle = r2; + } + + ActorComponent makeInstance(ActorArtboard artboard) { + ActorIKConstraint instance = new ActorIKConstraint(); + instance.copyIKConstraint(this, artboard); + return instance; + } + + void copyIKConstraint(ActorIKConstraint node, ActorArtboard artboard) { + copyTargetedConstraint(node, artboard); + + _invertDirection = node._invertDirection; + if (node._influencedBones != null) { + _influencedBones = new List(node._influencedBones.length); + for (int i = 0; i < _influencedBones.length; i++) { + InfluencedBone ib = new InfluencedBone(); + ib.boneIdx = node._influencedBones[i].boneIdx; + _influencedBones[i] = ib; + } + } + } + + void update(int dirt) {} } \ No newline at end of file diff --git a/lib/flare/actor_image.dart b/lib/flare/actor_image.dart index d6bc05a..a9a68ff 100644 --- a/lib/flare/actor_image.dart +++ b/lib/flare/actor_image.dart @@ -8,590 +8,536 @@ import "actor_component.dart"; import "actor_drawable.dart"; import "math/aabb.dart"; -class BoneConnection -{ - int boneIdx; - ActorNode node; - Mat2D bind = new Mat2D(); - Mat2D inverseBind = new Mat2D(); +class BoneConnection { + int boneIdx; + ActorNode node; + Mat2D bind = new Mat2D(); + Mat2D inverseBind = new Mat2D(); } -class SequenceFrame -{ - int _atlasIndex; - int _offset; - SequenceFrame(this._atlasIndex, this._offset); - - @override - String toString() - { - return "(" + this._atlasIndex.toString() + ", " + this._offset.toString() + ")"; - } - - int get atlasIndex - { - return this._atlasIndex; - } - - int get offset - { - return this._offset; - } +class SequenceFrame { + int _atlasIndex; + int _offset; + + SequenceFrame(this._atlasIndex, this._offset); + + @override + String toString() { + return "(" + this._atlasIndex.toString() + ", " + this._offset.toString() + + ")"; + } + + int get atlasIndex { + return this._atlasIndex; + } + + int get offset { + return this._offset; + } } -class ActorImage extends ActorNode implements ActorDrawable -{ - @override - int drawIndex; - - @override - int drawOrder; - BlendModes blendMode; - - int _textureIndex = -1; - Float32List _vertices; - Uint16List _triangles; - int _vertexCount = 0; - int _triangleCount = 0; - Float32List _animationDeformedVertices; - bool isVertexDeformDirty = false; - - List _boneConnections; - Float32List _boneMatrices; - - List _sequenceFrames; - Float32List _sequenceUVs; - int _sequenceFrame = 0; - - int get sequenceFrame - { - return this._sequenceFrame; - } - - Float32List get sequenceUVs - { - return this._sequenceUVs; - } - - List get sequenceFrames - { - return this._sequenceFrames; - } - - set sequenceFrame(int value) - { - this._sequenceFrame = value; - } - - int get connectedBoneCount - { - return _boneConnections == null ? 0 : _boneConnections.length; - } - - List get boneConnections - { - return _boneConnections; - } - - int get textureIndex - { - return _textureIndex; - } - - - int get vertexCount - { - return _vertexCount; - } - - int get triangleCount - { - return _triangleCount; - } - - Uint16List get triangles - { - return _triangles; - } - - Float32List get vertices - { - return _vertices; - } - - int get vertexPositionOffset - { - return 0; - } - - int get vertexUVOffset - { - return 2; - } - - int get vertexBoneIndexOffset - { - return 4; - } - - int get vertexBoneWeightOffset - { - return 8; - } - - int get vertexStride - { - return _boneConnections != null ? 12 : 4; - } - - bool get isSkinned - { - return _boneConnections != null; - } - - bool get doesAnimationVertexDeform - { - return _animationDeformedVertices != null; - } - - set doesAnimationVertexDeform(bool value) - { - if(value) - { - if(_animationDeformedVertices == null || _animationDeformedVertices.length != _vertexCount * 2) - { - _animationDeformedVertices = new Float32List(vertexCount*2); - // Copy the deform verts from the rig verts. - int writeIdx = 0; - int readIdx = 0; - int readStride = vertexStride; - for(int i = 0; i < _vertexCount; i++) - { - _animationDeformedVertices[writeIdx++] = _vertices[readIdx]; - _animationDeformedVertices[writeIdx++] = _vertices[readIdx+1]; - readIdx += readStride; - } - } - } - else - { - _animationDeformedVertices = null; - } - } - - Float32List get animationDeformedVertices - { - return _animationDeformedVertices; - } - - ActorImage(); - - void disposeGeometry() - { - // Delete vertices only if we do not vertex deform at runtime. - if(_animationDeformedVertices == null) - { - _vertices = null; - } - _triangles = null; - } - - // We don't do this at initialization as some engines (like Unity) - // don't need us to handle the bone matrix transforms ourselves. - // This helps keep memory a little lower when this code runs in those engines. - void instanceBoneMatrices() - { - if(_boneMatrices == null) - { - int numConnectedBones = _boneConnections.length; - _boneMatrices = new Float32List((numConnectedBones+1)*6); - // First bone transform is always identity. - _boneMatrices[0] = 1.0; - _boneMatrices[1] = 0.0; - _boneMatrices[2] = 0.0; - _boneMatrices[3] = 1.0; - _boneMatrices[4] = 0.0; - _boneMatrices[5] = 0.0; - } - } - - Float32List get boneInfluenceMatrices - { - instanceBoneMatrices(); - - Mat2D mat = new Mat2D(); - int bidx = 6; - for(BoneConnection bc in _boneConnections) - { - Mat2D.multiply(mat, bc.node.worldTransform, bc.inverseBind); - - _boneMatrices[bidx++] = mat[0]; - _boneMatrices[bidx++] = mat[1]; - _boneMatrices[bidx++] = mat[2]; - _boneMatrices[bidx++] = mat[3]; - _boneMatrices[bidx++] = mat[4]; - _boneMatrices[bidx++] = mat[5]; - } - - return _boneMatrices; - } - - Float32List get boneTransformMatrices - { - instanceBoneMatrices(); - - int bidx = 6; - for(BoneConnection bc in _boneConnections) - { - Mat2D mat = bc.node.worldTransform; - - _boneMatrices[bidx++] = mat[0]; - _boneMatrices[bidx++] = mat[1]; - _boneMatrices[bidx++] = mat[2]; - _boneMatrices[bidx++] = mat[3]; - _boneMatrices[bidx++] = mat[4]; - _boneMatrices[bidx++] = mat[5]; - } - - return _boneMatrices; - } - - static ActorImage read(ActorArtboard artboard, StreamReader reader, ActorImage node) - { - if(node == null) - { - node = new ActorImage(); - } - - ActorNode.read(artboard, reader, node); - - bool isVisible = reader.readBool("isVisible"); - if(isVisible) - { - int blendModeId = reader.readUint8("blendMode"); - BlendModes blendMode = BlendModes.Normal; - switch(blendModeId) - { - case 0: - blendMode = BlendModes.Normal; - break; - case 1: - blendMode = BlendModes.Multiply; - break; - case 2: - blendMode = BlendModes.Screen; - break; - case 3: - blendMode = BlendModes.Additive; - break; - } - node.blendMode = blendMode; - node.drawOrder = reader.readUint16("drawOrder"); - node._textureIndex = reader.readUint8("atlas"); - - reader.openArray("bones"); - int numConnectedBones = reader.readUint8Length(); - if(numConnectedBones != 0) - { - node._boneConnections = new List(numConnectedBones); - - for(int i = 0; i < numConnectedBones; i++) - { - BoneConnection bc = new BoneConnection(); - reader.openObject("bone"); - bc.boneIdx = reader.readId("component"); - reader.readFloat32ArrayOffset(bc.bind.values, 6, 0, "bind"); - reader.closeObject(); - Mat2D.invert(bc.inverseBind, bc.bind); - node._boneConnections[i] = bc; - } - reader.closeArray(); - Mat2D worldOverride = new Mat2D(); - reader.readFloat32ArrayOffset(worldOverride.values, 6, 0, "worldTransform"); - node.worldTransformOverride = worldOverride; - } - else - { - reader.closeArray(); - } - - int numVertices = reader.readUint32("numVertices"); - int vertexStride = numConnectedBones > 0 ? 12 : 4; - node._vertexCount = numVertices; - node._vertices = new Float32List(numVertices * vertexStride); - reader.readFloat32ArrayOffset(node._vertices, node._vertices.length, 0, "vertices"); - - int numTris = reader.readUint32("numTriangles"); - node._triangles = new Uint16List(numTris*3); - node._triangleCount = numTris; - reader.readUint16Array(node._triangles, node._triangles.length, 0, "triangles"); - } - - return node; - } - - static ActorImage readSequence(ActorArtboard artboard, StreamReader reader, ActorImage node) - { - ActorImage.read(artboard, reader, node); - - if(node._textureIndex != -1) - { - reader.openArray("frames"); - int frameAssetCount = reader.readUint16Length(); - // node._sequenceFrames = []; - Float32List uvs = new Float32List(node._vertexCount*2*frameAssetCount); - int uvStride = node._vertexCount * 2; - node._sequenceUVs = uvs; - SequenceFrame firstFrame = new SequenceFrame(node._textureIndex, 0); - node._sequenceFrames = new List(); - node._sequenceFrames.add(firstFrame); - int readIdx = 2; - int writeIdx = 0; - int vertexStride = 4; - if(node._boneConnections != null && node._boneConnections.length > 0) - { - vertexStride = 12; - } - for(int i = 0; i < node._vertexCount; i++) - { - uvs[writeIdx++] = node._vertices[readIdx]; - uvs[writeIdx++] = node._vertices[readIdx+1]; - readIdx += vertexStride; - } - - int offset = uvStride; - for(int i = 1; i < frameAssetCount; i++) - { - reader.openObject("frame"); - - SequenceFrame frame = new SequenceFrame(reader.readUint8("atlas"), offset*4); - node._sequenceFrames.add(frame); - reader.readFloat32ArrayOffset(uvs, uvStride, offset, "uv"); - offset += uvStride; - - reader.closeObject(); - } - - reader.closeArray(); - } - - return node; - } - - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - if(_boneConnections != null) - { - for(int i = 0; i < _boneConnections.length; i++) - { - BoneConnection bc = _boneConnections[i]; - bc.node = components[bc.boneIdx] as ActorNode; - } - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorImage instanceNode = new ActorImage(); - instanceNode.copyImage(this, resetArtboard); - return instanceNode; - } - - void copyImage(ActorImage node, ActorArtboard resetArtboard) - { - drawOrder = node.drawOrder; - blendMode = node.blendMode; - _textureIndex = node._textureIndex; - _vertexCount = node._vertexCount; - _triangleCount = node._triangleCount; - _vertices = node._vertices; - _triangles = node._triangles; - if(node._animationDeformedVertices != null) - { - _animationDeformedVertices = new Float32List.fromList(node._animationDeformedVertices); - } - - if(node._boneConnections != null) - { - _boneConnections = new List(node._boneConnections.length); - for(int i = 0; i < node._boneConnections.length; i++) - { - BoneConnection bc = new BoneConnection(); - bc.boneIdx = node._boneConnections[i].boneIdx; - Mat2D.copy(bc.bind, node._boneConnections[i].bind); - Mat2D.copy(bc.inverseBind, node._boneConnections[i].inverseBind); - _boneConnections[i] = bc; - } - } - } - - void transformBind(Mat2D xform) - { - if(_boneConnections != null) - { - for(BoneConnection bc in _boneConnections) - { - Mat2D.multiply(bc.bind, xform, bc.bind); - Mat2D.invert(bc.inverseBind, bc.bind); - } - } - } - - Float32List makeVertexPositionBuffer() - { - return new Float32List(_vertexCount * 2); - } - - Float32List makeVertexUVBuffer() - { - return new Float32List(_vertexCount * 2); - } - - void transformDeformVertices(Mat2D wt) - { - if(_animationDeformedVertices == null) - { - return; - } - - Float32List fv = _animationDeformedVertices; - - int vidx = 0; - for(int j = 0; j < _vertexCount; j++) - { - double x = fv[vidx]; - double y = fv[vidx+1]; - - fv[vidx] = wt[0] * x + wt[2] * y + wt[4]; - fv[vidx+1] = wt[1] * x + wt[3] * y + wt[5]; - - vidx += 2; - } - } - - void updateVertexUVBuffer(Float32List buffer) - { - int readIdx = vertexUVOffset; - int writeIdx = 0; - int stride = vertexStride; - - Float32List v = _vertices; - for(int i = 0; i < _vertexCount; i++) - { - buffer[writeIdx++] = v[readIdx]; - buffer[writeIdx++] = v[readIdx+1]; - readIdx += stride; - } - } - - void updateVertexPositionBuffer(Float32List buffer, bool isSkinnedDeformInWorld) - { - Mat2D worldTransform = this.worldTransform; - int readIdx = 0; - int writeIdx = 0; - - Float32List v = _animationDeformedVertices != null ? _animationDeformedVertices : _vertices; - int stride = _animationDeformedVertices != null ? 2 : vertexStride; - - if(isSkinned) - { - Float32List boneTransforms = boneInfluenceMatrices; - - //Mat2D inverseWorldTransform = Mat2D.Invert(new Mat2D(), worldTransform); - Float32List influenceMatrix = new Float32List.fromList([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - - - // if(this.name == "evolution_1_0001s_0003_evolution_1_weapo") - // { - // // print("TEST!"); - // int boneIndexOffset = vertexBoneIndexOffset; - // int weightOffset = vertexBoneWeightOffset; - // for(int i = 0; i < _vertexCount; i++) - // { - // for(int wi = 0; wi < 4; wi++) - // { - // int boneIndex = _vertices[boneIndexOffset+wi].toInt(); - // double weight = _vertices[weightOffset+wi]; - // if(boneIndex == 1) - // { - // _vertices[weightOffset+wi] = 1.0; - // } - // else if(boneIndex == 2) - // { - // _vertices[weightOffset+wi] = 0.0; - // } - // //print("BI $boneIndex $weight"); - // } - // boneIndexOffset += vertexStride; - // weightOffset += vertexStride; - // } - // } - int boneIndexOffset = vertexBoneIndexOffset; - int weightOffset = vertexBoneWeightOffset; - for(int i = 0; i < _vertexCount; i++) - { - double x = v[readIdx]; - double y = v[readIdx+1]; - - double px, py; - - if(_animationDeformedVertices != null && isSkinnedDeformInWorld) - { - px = x; - py = y; - } - else - { - px = worldTransform[0] * x + worldTransform[2] * y + worldTransform[4]; - py = worldTransform[1] * x + worldTransform[3] * y + worldTransform[5]; - } - - influenceMatrix[0] = influenceMatrix[1] = influenceMatrix[2] = influenceMatrix[3] = influenceMatrix[4] = influenceMatrix[5] = 0.0; - - for(int wi = 0; wi < 4; wi++) - { - int boneIndex = _vertices[boneIndexOffset+wi].toInt(); - double weight = _vertices[weightOffset+wi]; - - int boneTransformIndex = boneIndex*6; - for(int j = 0; j < 6; j++) - { - influenceMatrix[j] += boneTransforms[boneTransformIndex+j] * weight; - } - } - - x = influenceMatrix[0] * px + influenceMatrix[2] * py + influenceMatrix[4]; - y = influenceMatrix[1] * px + influenceMatrix[3] * py + influenceMatrix[5]; - - readIdx += stride; - boneIndexOffset += vertexStride; - weightOffset += vertexStride; - - buffer[writeIdx++] = x; - buffer[writeIdx++] = y; - } - } - else - { - Vec2D tempVec = new Vec2D(); - for(int i = 0; i < _vertexCount; i++) - { - tempVec[0] = v[readIdx]; - tempVec[1] = v[readIdx+1]; - Vec2D.transformMat2D(tempVec, tempVec, worldTransform); - readIdx += stride; - - buffer[writeIdx++] = tempVec[0]; - buffer[writeIdx++] = tempVec[1]; - } - } - } - - AABB computeAABB() - { - // Todo: implement for image. - Mat2D worldTransform = this.worldTransform; - return new AABB.fromValues(worldTransform[4], worldTransform[5], worldTransform[4], worldTransform[5]); - } +class ActorImage extends ActorNode + implements ActorDrawable { + @override + int drawIndex; + + @override + int drawOrder; + BlendModes blendMode; + + int _textureIndex = -1; + Float32List _vertices; + Uint16List _triangles; + int _vertexCount = 0; + int _triangleCount = 0; + Float32List _animationDeformedVertices; + bool isVertexDeformDirty = false; + + List _boneConnections; + Float32List _boneMatrices; + + List _sequenceFrames; + Float32List _sequenceUVs; + int _sequenceFrame = 0; + + int get sequenceFrame { + return this._sequenceFrame; + } + + Float32List get sequenceUVs { + return this._sequenceUVs; + } + + List get sequenceFrames { + return this._sequenceFrames; + } + + set sequenceFrame(int value) { + this._sequenceFrame = value; + } + + int get connectedBoneCount { + return _boneConnections == null ? 0 : _boneConnections.length; + } + + List get boneConnections { + return _boneConnections; + } + + int get textureIndex { + return _textureIndex; + } + + + int get vertexCount { + return _vertexCount; + } + + int get triangleCount { + return _triangleCount; + } + + Uint16List get triangles { + return _triangles; + } + + Float32List get vertices { + return _vertices; + } + + int get vertexPositionOffset { + return 0; + } + + int get vertexUVOffset { + return 2; + } + + int get vertexBoneIndexOffset { + return 4; + } + + int get vertexBoneWeightOffset { + return 8; + } + + int get vertexStride { + return _boneConnections != null ? 12 : 4; + } + + bool get isSkinned { + return _boneConnections != null; + } + + bool get doesAnimationVertexDeform { + return _animationDeformedVertices != null; + } + + set doesAnimationVertexDeform(bool value) { + if (value) { + if (_animationDeformedVertices == null || + _animationDeformedVertices.length != _vertexCount * 2) { + _animationDeformedVertices = new Float32List(vertexCount * 2); + // Copy the deform verts from the rig verts. + int writeIdx = 0; + int readIdx = 0; + int readStride = vertexStride; + for (int i = 0; i < _vertexCount; i++) { + _animationDeformedVertices[writeIdx++] = _vertices[readIdx]; + _animationDeformedVertices[writeIdx++] = _vertices[readIdx + 1]; + readIdx += readStride; + } + } + } + else { + _animationDeformedVertices = null; + } + } + + Float32List get animationDeformedVertices { + return _animationDeformedVertices; + } + + ActorImage(); + + void disposeGeometry() { + // Delete vertices only if we do not vertex deform at runtime. + if (_animationDeformedVertices == null) { + _vertices = null; + } + _triangles = null; + } + + // We don't do this at initialization as some engines (like Unity) + // don't need us to handle the bone matrix transforms ourselves. + // This helps keep memory a little lower when this code runs in those engines. + void instanceBoneMatrices() { + if (_boneMatrices == null) { + int numConnectedBones = _boneConnections.length; + _boneMatrices = new Float32List((numConnectedBones + 1) * 6); + // First bone transform is always identity. + _boneMatrices[0] = 1.0; + _boneMatrices[1] = 0.0; + _boneMatrices[2] = 0.0; + _boneMatrices[3] = 1.0; + _boneMatrices[4] = 0.0; + _boneMatrices[5] = 0.0; + } + } + + Float32List get boneInfluenceMatrices { + instanceBoneMatrices(); + + Mat2D mat = new Mat2D(); + int bidx = 6; + for (BoneConnection bc in _boneConnections) { + Mat2D.multiply(mat, bc.node.worldTransform, bc.inverseBind); + + _boneMatrices[bidx++] = mat[0]; + _boneMatrices[bidx++] = mat[1]; + _boneMatrices[bidx++] = mat[2]; + _boneMatrices[bidx++] = mat[3]; + _boneMatrices[bidx++] = mat[4]; + _boneMatrices[bidx++] = mat[5]; + } + + return _boneMatrices; + } + + Float32List get boneTransformMatrices { + instanceBoneMatrices(); + + int bidx = 6; + for (BoneConnection bc in _boneConnections) { + Mat2D mat = bc.node.worldTransform; + + _boneMatrices[bidx++] = mat[0]; + _boneMatrices[bidx++] = mat[1]; + _boneMatrices[bidx++] = mat[2]; + _boneMatrices[bidx++] = mat[3]; + _boneMatrices[bidx++] = mat[4]; + _boneMatrices[bidx++] = mat[5]; + } + + return _boneMatrices; + } + + static ActorImage read(ActorArtboard artboard, StreamReader reader, + ActorImage node) { + if (node == null) { + node = new ActorImage(); + } + + ActorNode.read(artboard, reader, node); + + bool isVisible = reader.readBool("isVisible"); + if (isVisible) { + int blendModeId = reader.readUint8("blendMode"); + BlendModes blendMode = BlendModes.Normal; + switch (blendModeId) { + case 0: + blendMode = BlendModes.Normal; + break; + case 1: + blendMode = BlendModes.Multiply; + break; + case 2: + blendMode = BlendModes.Screen; + break; + case 3: + blendMode = BlendModes.Additive; + break; + } + node.blendMode = blendMode; + node.drawOrder = reader.readUint16("drawOrder"); + node._textureIndex = reader.readUint8("atlas"); + + reader.openArray("bones"); + int numConnectedBones = reader.readUint8Length(); + if (numConnectedBones != 0) { + node._boneConnections = new List(numConnectedBones); + + for (int i = 0; i < numConnectedBones; i++) { + BoneConnection bc = new BoneConnection(); + reader.openObject("bone"); + bc.boneIdx = reader.readId("component"); + reader.readFloat32ArrayOffset(bc.bind.values, 6, 0, "bind"); + reader.closeObject(); + Mat2D.invert(bc.inverseBind, bc.bind); + node._boneConnections[i] = bc; + } + reader.closeArray(); + Mat2D worldOverride = new Mat2D(); + reader.readFloat32ArrayOffset( + worldOverride.values, 6, 0, "worldTransform"); + node.worldTransformOverride = worldOverride; + } + else { + reader.closeArray(); + } + + int numVertices = reader.readUint32("numVertices"); + int vertexStride = numConnectedBones > 0 ? 12 : 4; + node._vertexCount = numVertices; + node._vertices = new Float32List(numVertices * vertexStride); + reader.readFloat32ArrayOffset( + node._vertices, node._vertices.length, 0, "vertices"); + + int numTris = reader.readUint32("numTriangles"); + node._triangles = new Uint16List(numTris * 3); + node._triangleCount = numTris; + reader.readUint16Array( + node._triangles, node._triangles.length, 0, "triangles"); + } + + return node; + } + + static ActorImage readSequence(ActorArtboard artboard, StreamReader reader, + ActorImage node) { + ActorImage.read(artboard, reader, node); + + if (node._textureIndex != -1) { + reader.openArray("frames"); + int frameAssetCount = reader.readUint16Length(); + // node._sequenceFrames = []; + Float32List uvs = new Float32List( + node._vertexCount * 2 * frameAssetCount); + int uvStride = node._vertexCount * 2; + node._sequenceUVs = uvs; + SequenceFrame firstFrame = new SequenceFrame(node._textureIndex, 0); + node._sequenceFrames = new List(); + node._sequenceFrames.add(firstFrame); + int readIdx = 2; + int writeIdx = 0; + int vertexStride = 4; + if (node._boneConnections != null && node._boneConnections.length > 0) { + vertexStride = 12; + } + for (int i = 0; i < node._vertexCount; i++) { + uvs[writeIdx++] = node._vertices[readIdx]; + uvs[writeIdx++] = node._vertices[readIdx + 1]; + readIdx += vertexStride; + } + + int offset = uvStride; + for (int i = 1; i < frameAssetCount; i++) { + reader.openObject("frame"); + + SequenceFrame frame = new SequenceFrame( + reader.readUint8("atlas"), offset * 4); + node._sequenceFrames.add(frame); + reader.readFloat32ArrayOffset(uvs, uvStride, offset, "uv"); + offset += uvStride; + + reader.closeObject(); + } + + reader.closeArray(); + } + + return node; + } + + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + if (_boneConnections != null) { + for (int i = 0; i < _boneConnections.length; i++) { + BoneConnection bc = _boneConnections[i]; + bc.node = components[bc.boneIdx] as ActorNode; + } + } + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorImage instanceNode = new ActorImage(); + instanceNode.copyImage(this, resetArtboard); + return instanceNode; + } + + void copyImage(ActorImage node, ActorArtboard resetArtboard) { + drawOrder = node.drawOrder; + blendMode = node.blendMode; + _textureIndex = node._textureIndex; + _vertexCount = node._vertexCount; + _triangleCount = node._triangleCount; + _vertices = node._vertices; + _triangles = node._triangles; + if (node._animationDeformedVertices != null) { + _animationDeformedVertices = + new Float32List.fromList(node._animationDeformedVertices); + } + + if (node._boneConnections != null) { + _boneConnections = new List(node._boneConnections.length); + for (int i = 0; i < node._boneConnections.length; i++) { + BoneConnection bc = new BoneConnection(); + bc.boneIdx = node._boneConnections[i].boneIdx; + Mat2D.copy(bc.bind, node._boneConnections[i].bind); + Mat2D.copy(bc.inverseBind, node._boneConnections[i].inverseBind); + _boneConnections[i] = bc; + } + } + } + + void transformBind(Mat2D xform) { + if (_boneConnections != null) { + for (BoneConnection bc in _boneConnections) { + Mat2D.multiply(bc.bind, xform, bc.bind); + Mat2D.invert(bc.inverseBind, bc.bind); + } + } + } + + Float32List makeVertexPositionBuffer() { + return new Float32List(_vertexCount * 2); + } + + Float32List makeVertexUVBuffer() { + return new Float32List(_vertexCount * 2); + } + + void transformDeformVertices(Mat2D wt) { + if (_animationDeformedVertices == null) { + return; + } + + Float32List fv = _animationDeformedVertices; + + int vidx = 0; + for (int j = 0; j < _vertexCount; j++) { + double x = fv[vidx]; + double y = fv[vidx + 1]; + + fv[vidx] = wt[0] * x + wt[2] * y + wt[4]; + fv[vidx + 1] = wt[1] * x + wt[3] * y + wt[5]; + + vidx += 2; + } + } + + void updateVertexUVBuffer(Float32List buffer) { + int readIdx = vertexUVOffset; + int writeIdx = 0; + int stride = vertexStride; + + Float32List v = _vertices; + for (int i = 0; i < _vertexCount; i++) { + buffer[writeIdx++] = v[readIdx]; + buffer[writeIdx++] = v[readIdx + 1]; + readIdx += stride; + } + } + + void updateVertexPositionBuffer(Float32List buffer, + bool isSkinnedDeformInWorld) { + Mat2D worldTransform = this.worldTransform; + int readIdx = 0; + int writeIdx = 0; + + Float32List v = _animationDeformedVertices != null + ? _animationDeformedVertices + : _vertices; + int stride = _animationDeformedVertices != null ? 2 : vertexStride; + + if (isSkinned) { + Float32List boneTransforms = boneInfluenceMatrices; + + //Mat2D inverseWorldTransform = Mat2D.Invert(new Mat2D(), worldTransform); + Float32List influenceMatrix = new Float32List.fromList( + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); + + + // if(this.name == "evolution_1_0001s_0003_evolution_1_weapo") + // { + // // print("TEST!"); + // int boneIndexOffset = vertexBoneIndexOffset; + // int weightOffset = vertexBoneWeightOffset; + // for(int i = 0; i < _vertexCount; i++) + // { + // for(int wi = 0; wi < 4; wi++) + // { + // int boneIndex = _vertices[boneIndexOffset+wi].toInt(); + // double weight = _vertices[weightOffset+wi]; + // if(boneIndex == 1) + // { + // _vertices[weightOffset+wi] = 1.0; + // } + // else if(boneIndex == 2) + // { + // _vertices[weightOffset+wi] = 0.0; + // } + // //print("BI $boneIndex $weight"); + // } + // boneIndexOffset += vertexStride; + // weightOffset += vertexStride; + // } + // } + int boneIndexOffset = vertexBoneIndexOffset; + int weightOffset = vertexBoneWeightOffset; + for (int i = 0; i < _vertexCount; i++) { + double x = v[readIdx]; + double y = v[readIdx + 1]; + + double px, py; + + if (_animationDeformedVertices != null && isSkinnedDeformInWorld) { + px = x; + py = y; + } + else { + px = + worldTransform[0] * x + worldTransform[2] * y + worldTransform[4]; + py = + worldTransform[1] * x + worldTransform[3] * y + worldTransform[5]; + } + + influenceMatrix[0] = influenceMatrix[1] = influenceMatrix[2] = + influenceMatrix[3] = influenceMatrix[4] = influenceMatrix[5] = 0.0; + + for (int wi = 0; wi < 4; wi++) { + int boneIndex = _vertices[boneIndexOffset + wi].toInt(); + double weight = _vertices[weightOffset + wi]; + + int boneTransformIndex = boneIndex * 6; + for (int j = 0; j < 6; j++) { + influenceMatrix[j] += + boneTransforms[boneTransformIndex + j] * weight; + } + } + + x = influenceMatrix[0] * px + influenceMatrix[2] * py + + influenceMatrix[4]; + y = influenceMatrix[1] * px + influenceMatrix[3] * py + + influenceMatrix[5]; + + readIdx += stride; + boneIndexOffset += vertexStride; + weightOffset += vertexStride; + + buffer[writeIdx++] = x; + buffer[writeIdx++] = y; + } + } + else { + Vec2D tempVec = new Vec2D(); + for (int i = 0; i < _vertexCount; i++) { + tempVec[0] = v[readIdx]; + tempVec[1] = v[readIdx + 1]; + Vec2D.transformMat2D(tempVec, tempVec, worldTransform); + readIdx += stride; + + buffer[writeIdx++] = tempVec[0]; + buffer[writeIdx++] = tempVec[1]; + } + } + } + + AABB computeAABB() { + // Todo: implement for image. + Mat2D worldTransform = this.worldTransform; + return new AABB.fromValues( + worldTransform[4], worldTransform[5], worldTransform[4], + worldTransform[5]); + } } \ No newline at end of file diff --git a/lib/flare/actor_jelly_bone.dart b/lib/flare/actor_jelly_bone.dart index 1183396..473b720 100644 --- a/lib/flare/actor_jelly_bone.dart +++ b/lib/flare/actor_jelly_bone.dart @@ -3,27 +3,24 @@ import "actor_artboard.dart"; import "actor_bone_base.dart"; import "actor_component.dart"; -class ActorJellyBone extends ActorBoneBase -{ - ActorComponent makeInstance(ActorArtboard artboard) - { - ActorJellyBone instanceNode = new ActorJellyBone(); - instanceNode.copyBoneBase(this, artboard); - return instanceNode; - } +class ActorJellyBone extends ActorBoneBase { + ActorComponent makeInstance(ActorArtboard artboard) { + ActorJellyBone instanceNode = new ActorJellyBone(); + instanceNode.copyBoneBase(this, artboard); + return instanceNode; + } - static ActorJellyBone read(ActorArtboard artboard, StreamReader reader, ActorJellyBone node) - { - if(node == null) - { - node = new ActorJellyBone(); - } + static ActorJellyBone read(ActorArtboard artboard, StreamReader reader, + ActorJellyBone node) { + if (node == null) { + node = new ActorJellyBone(); + } - // The Jelly Bone has a specialized read that doesn't go down the typical node path, this is because majority of the transform properties - // of the Jelly Bone are controlled by the Jelly Controller and are unnecessary for serialization. - ActorComponent.read(artboard, reader, node); - node.opacity = reader.readFloat32("opacity"); - node.collapsedVisibility = reader.readBool("isCollapsed"); - return node; - } + // The Jelly Bone has a specialized read that doesn't go down the typical node path, this is because majority of the transform properties + // of the Jelly Bone are controlled by the Jelly Controller and are unnecessary for serialization. + ActorComponent.read(artboard, reader, node); + node.opacity = reader.readFloat32("opacity"); + node.collapsedVisibility = reader.readBool("isCollapsed"); + return node; + } } \ No newline at end of file diff --git a/lib/flare/actor_loader.dart b/lib/flare/actor_loader.dart index 76d1e4c..9028c6b 100644 --- a/lib/flare/actor_loader.dart +++ b/lib/flare/actor_loader.dart @@ -2,20 +2,18 @@ import 'package:flutter/services.dart' show rootBundle; import 'dart:typed_data'; import "stream_reader.dart"; -class ActorLoader -{ - void load(String filename) async - { - print("Loading actor filename $filename"); - ByteData data = await rootBundle.load(filename + ".nima"); - StreamReader reader = new StreamReader(data); - if(data.getUint8(0) != 78 || data.getUint8(1) != 73 || data.getUint8(2) != 77 || data.getUint8(3) != 65) - { - print("Not nima"); - } - else - { - print("Nima!"); - } - } +class ActorLoader { + void load(String filename) async + { + print("Loading actor filename $filename"); + ByteData data = await rootBundle.load(filename + ".nima"); + StreamReader reader = new StreamReader(data); + if (data.getUint8(0) != 78 || data.getUint8(1) != 73 || + data.getUint8(2) != 77 || data.getUint8(3) != 65) { + print("Not nima"); + } + else { + print("Nima!"); + } + } } \ No newline at end of file diff --git a/lib/flare/actor_node.dart b/lib/flare/actor_node.dart index 9075850..538d1cd 100644 --- a/lib/flare/actor_node.dart +++ b/lib/flare/actor_node.dart @@ -7,477 +7,395 @@ import "actor_constraint.dart"; typedef bool NodeWalkCallback(ActorNode node); -class ActorClip -{ - int clipIdx; - ActorNode node; - - ActorClip(int idx) - { - clipIdx = idx; - } +class ActorClip { + int clipIdx; + ActorNode node; + + ActorClip(int idx) { + clipIdx = idx; + } } -class ActorNode extends ActorComponent -{ - List _children; - //List m_Dependents; - Mat2D _transform = new Mat2D(); - Mat2D _worldTransform = new Mat2D(); - - Vec2D _translation = new Vec2D(); - double _rotation = 0.0; - Vec2D _scale = new Vec2D.fromValues(1.0, 1.0); - double _opacity = 1.0; - double _renderOpacity = 1.0; - - bool _overrideWorldTransform = false; - bool _isCollapsedVisibility = false; - - bool _renderCollapsed = false; - List _clips; - - List _constraints; - List _peerConstraints; - - static const int TransformDirty = 1<<0; - static const int WorldTransformDirty = 1<<1; - - ActorNode(); - ActorNode.withArtboard(ActorArtboard artboard) : super.withArtboard(artboard); - - Mat2D get transform - { - return _transform; - } - - List get clips - { - return _clips; - } - - Mat2D get worldTransformOverride - { - return _overrideWorldTransform ? _worldTransform : null; - } - - set worldTransformOverride(Mat2D value) - { - if(value == null) - { - _overrideWorldTransform = false; - } - else - { - _overrideWorldTransform = true; - Mat2D.copy(worldTransform, value); - } - markTransformDirty(); - } - - Mat2D get worldTransform - { - return _worldTransform; - } - - // N.B. this should only be done if you really know what you're doing. Generally you want to manipulate the local translation, rotation, and scale of a Node. - set worldTransform(Mat2D value) - { - Mat2D.copy(_worldTransform, value); - } - - double get x - { - return _translation[0]; - } - - set x(double value) - { - if(_translation[0] == value) - { - return; - } - _translation[0] = value; - markTransformDirty(); - } - - double get y - { - return _translation[1]; - } - - set y(double value) - { - if(_translation[1] == value) - { - return; - } - _translation[1] = value; - markTransformDirty(); - } - - Vec2D get translation - { - return new Vec2D.clone(_translation); - } - - set translation(Vec2D value) - { - Vec2D.copy(_translation, value); - markTransformDirty(); - } - - double get rotation - { - return _rotation; - } - - set rotation(double value) - { - if(_rotation == value) - { - return; - } - _rotation = value; - markTransformDirty(); - } - - double get scaleX - { - return _scale[0]; - } - - set scaleX(double value) - { - if(_scale[0] == value) - { - return; - } - _scale[0] = value; - markTransformDirty(); - } - - double get scaleY - { - return _scale[1]; - } - - set scaleY(double value) - { - if(_scale[1] == value) - { - return; - } - _scale[1] = value; - markTransformDirty(); - } - - double get opacity - { - return _opacity; - } - - set opacity(double value) - { - if(_opacity == value) - { - return; - } - _opacity = value; - markTransformDirty(); - } - - double get renderOpacity - { - return _renderOpacity; - } - - bool get renderCollapsed - { - return _renderCollapsed; - } - - bool get collapsedVisibility - { - return _isCollapsedVisibility; - } - - set collapsedVisibility(bool value) - { - if(_isCollapsedVisibility != value) - { - _isCollapsedVisibility = value; - markTransformDirty(); - } - } - - List get allClips - { - // Find clips. - List all = null; - ActorNode clipSearch = this; - while(clipSearch != null) - { - if(clipSearch.clips != null) - { - if(all == null) - { - all = clipSearch.clips; - } - else - { - all += clipSearch.clips; - } - } - clipSearch = clipSearch.parent; - } - - return all; - } - - void markTransformDirty() - { - if(artboard == null) - { - // Still loading? - return; - } - if(!artboard.addDirt(this, TransformDirty, false)) - { - return; - } - artboard.addDirt(this, WorldTransformDirty, true); - } - - void updateTransform() - { - Mat2D.fromRotation(_transform, _rotation); - _transform[4] = _translation[0]; - _transform[5] = _translation[1]; - Mat2D.scale(_transform, _transform, _scale); - } - - Vec2D getWorldTranslation(Vec2D vec) - { - vec[0] = _worldTransform[4]; - vec[1] = _worldTransform[5]; - return vec; - } - - void updateWorldTransform() - { - _renderOpacity = _opacity; - - if(parent != null) - { - _renderCollapsed = _isCollapsedVisibility || parent._renderCollapsed; - _renderOpacity *= parent._renderOpacity; - if(!_overrideWorldTransform) - { - Mat2D.multiply(_worldTransform, parent._worldTransform, _transform); - } - } - else - { - Mat2D.copy(_worldTransform, _transform); - } - } - - static ActorNode read(ActorArtboard artboard, StreamReader reader, ActorNode node) - { - if(node == null) - { - node = new ActorNode(); - } - ActorComponent.read(artboard, reader, node); - reader.readFloat32ArrayOffset(node._translation.values, 2, 0, "translation"); - node._rotation = reader.readFloat32("rotation"); - reader.readFloat32ArrayOffset(node._scale.values, 2, 0, "scale"); - node._opacity = reader.readFloat32("opacity"); - node._isCollapsedVisibility = reader.readBool("isCollapsed"); - - reader.openArray("clips"); - int clipCount = reader.readUint8Length(); - if(clipCount > 0) - { - node._clips = new List(clipCount); - for(int i = 0; i < clipCount; i++) - { - node._clips[i] = new ActorClip(reader.readId("clip")); - } - } - reader.closeArray(); - return node; - } - - void addChild(ActorNode node) - { - if(node.parent != null) - { - node.parent._children.remove(node); - } - node.parent = this; - if(_children == null) - { - _children = new List(); - } - _children.add(node); - } - - List get children - { - return _children; - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorNode instanceNode = new ActorNode(); - instanceNode.copyNode(this, resetArtboard); - return instanceNode; - } - - void copyNode(ActorNode node, ActorArtboard resetArtboard) - { - copyComponent(node, resetArtboard); - _transform = new Mat2D.clone(node._transform); - _worldTransform = new Mat2D.clone(node._worldTransform); - _translation = new Vec2D.clone(node._translation); - _scale = new Vec2D.clone(node._scale); - _rotation = node._rotation; - _opacity = node._opacity; - _renderOpacity = node._renderOpacity; - _overrideWorldTransform = node._overrideWorldTransform; - - if(node._clips != null) - { - _clips = new List(node._clips.length); - for(int i = 0, l = node._clips.length; i < l; i++) - { - _clips[i] = new ActorClip(node._clips[i].clipIdx); - } - } - else - { - _clips = null; - } - } - - void onDirty(int dirt) - { - - } - - bool addConstraint(ActorConstraint constraint) - { - if(_constraints == null) - { - _constraints = new List(); - } - if(_constraints.contains(constraint)) - { - return false; - } - _constraints.add(constraint); - return true; - } - - bool addPeerConstraint(ActorConstraint constraint) - { - if(_peerConstraints == null) - { - _peerConstraints = new List(); - } - if(_peerConstraints.contains(constraint)) - { - return false; - } - _peerConstraints.add(constraint); - return true; - } - - List get allConstraints => (_constraints == null ? _peerConstraints : _peerConstraints == null ? _constraints : _constraints + _peerConstraints) ?? []; - - void update(int dirt) - { - if((dirt & TransformDirty) == TransformDirty) - { - updateTransform(); - } - if((dirt & WorldTransformDirty) == WorldTransformDirty) - { - updateWorldTransform(); - if(_constraints != null) - { - for(ActorConstraint constraint in _constraints) - { - if(constraint.isEnabled) - { - constraint.constrain(this); - } - } - } - } - } - - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - - if(_clips == null) - { - return; - } - - for(ActorClip clip in _clips) - { - clip.node = components[clip.clipIdx]; - } - } - - void completeResolve() - { - // Nothing to complete for actornode. - } - - bool eachChildRecursive(NodeWalkCallback cb) - { - if(_children != null) - { - for(ActorNode child in _children) - { - if(cb(child) == false) - { - return false; - } - - if(child.eachChildRecursive(cb) == false) - { - return false; - } - } - } - return true; - } - - bool all(NodeWalkCallback cb) - { - if(cb(this) == false) - { - return false; - } - - for(ActorNode child in _children) - { - if(cb(child) == false) - { - return false; - } - - child.eachChildRecursive(cb); - } - - return true; - } - - void invalidateShape() {} +class ActorNode extends ActorComponent { + List _children; + + //List m_Dependents; + Mat2D _transform = new Mat2D(); + Mat2D _worldTransform = new Mat2D(); + + Vec2D _translation = new Vec2D(); + double _rotation = 0.0; + Vec2D _scale = new Vec2D.fromValues(1.0, 1.0); + double _opacity = 1.0; + double _renderOpacity = 1.0; + + bool _overrideWorldTransform = false; + bool _isCollapsedVisibility = false; + + bool _renderCollapsed = false; + List _clips; + + List _constraints; + List _peerConstraints; + + static const int TransformDirty = 1 << 0; + static const int WorldTransformDirty = 1 << 1; + + ActorNode(); + + ActorNode.withArtboard(ActorArtboard artboard) : super.withArtboard(artboard); + + Mat2D get transform { + return _transform; + } + + List get clips { + return _clips; + } + + Mat2D get worldTransformOverride { + return _overrideWorldTransform ? _worldTransform : null; + } + + set worldTransformOverride(Mat2D value) { + if (value == null) { + _overrideWorldTransform = false; + } + else { + _overrideWorldTransform = true; + Mat2D.copy(worldTransform, value); + } + markTransformDirty(); + } + + Mat2D get worldTransform { + return _worldTransform; + } + + // N.B. this should only be done if you really know what you're doing. Generally you want to manipulate the local translation, rotation, and scale of a Node. + set worldTransform(Mat2D value) { + Mat2D.copy(_worldTransform, value); + } + + double get x { + return _translation[0]; + } + + set x(double value) { + if (_translation[0] == value) { + return; + } + _translation[0] = value; + markTransformDirty(); + } + + double get y { + return _translation[1]; + } + + set y(double value) { + if (_translation[1] == value) { + return; + } + _translation[1] = value; + markTransformDirty(); + } + + Vec2D get translation { + return new Vec2D.clone(_translation); + } + + set translation(Vec2D value) { + Vec2D.copy(_translation, value); + markTransformDirty(); + } + + double get rotation { + return _rotation; + } + + set rotation(double value) { + if (_rotation == value) { + return; + } + _rotation = value; + markTransformDirty(); + } + + double get scaleX { + return _scale[0]; + } + + set scaleX(double value) { + if (_scale[0] == value) { + return; + } + _scale[0] = value; + markTransformDirty(); + } + + double get scaleY { + return _scale[1]; + } + + set scaleY(double value) { + if (_scale[1] == value) { + return; + } + _scale[1] = value; + markTransformDirty(); + } + + double get opacity { + return _opacity; + } + + set opacity(double value) { + if (_opacity == value) { + return; + } + _opacity = value; + markTransformDirty(); + } + + double get renderOpacity { + return _renderOpacity; + } + + bool get renderCollapsed { + return _renderCollapsed; + } + + bool get collapsedVisibility { + return _isCollapsedVisibility; + } + + set collapsedVisibility(bool value) { + if (_isCollapsedVisibility != value) { + _isCollapsedVisibility = value; + markTransformDirty(); + } + } + + List get allClips { + // Find clips. + List all = null; + ActorNode clipSearch = this; + while (clipSearch != null) { + if (clipSearch.clips != null) { + if (all == null) { + all = clipSearch.clips; + } + else { + all += clipSearch.clips; + } + } + clipSearch = clipSearch.parent; + } + + return all; + } + + void markTransformDirty() { + if (artboard == null) { + // Still loading? + return; + } + if (!artboard.addDirt(this, TransformDirty, false)) { + return; + } + artboard.addDirt(this, WorldTransformDirty, true); + } + + void updateTransform() { + Mat2D.fromRotation(_transform, _rotation); + _transform[4] = _translation[0]; + _transform[5] = _translation[1]; + Mat2D.scale(_transform, _transform, _scale); + } + + Vec2D getWorldTranslation(Vec2D vec) { + vec[0] = _worldTransform[4]; + vec[1] = _worldTransform[5]; + return vec; + } + + void updateWorldTransform() { + _renderOpacity = _opacity; + + if (parent != null) { + _renderCollapsed = _isCollapsedVisibility || parent._renderCollapsed; + _renderOpacity *= parent._renderOpacity; + if (!_overrideWorldTransform) { + Mat2D.multiply(_worldTransform, parent._worldTransform, _transform); + } + } + else { + Mat2D.copy(_worldTransform, _transform); + } + } + + static ActorNode read(ActorArtboard artboard, StreamReader reader, + ActorNode node) { + if (node == null) { + node = new ActorNode(); + } + ActorComponent.read(artboard, reader, node); + reader.readFloat32ArrayOffset( + node._translation.values, 2, 0, "translation"); + node._rotation = reader.readFloat32("rotation"); + reader.readFloat32ArrayOffset(node._scale.values, 2, 0, "scale"); + node._opacity = reader.readFloat32("opacity"); + node._isCollapsedVisibility = reader.readBool("isCollapsed"); + + reader.openArray("clips"); + int clipCount = reader.readUint8Length(); + if (clipCount > 0) { + node._clips = new List(clipCount); + for (int i = 0; i < clipCount; i++) { + node._clips[i] = new ActorClip(reader.readId("clip")); + } + } + reader.closeArray(); + return node; + } + + void addChild(ActorNode node) { + if (node.parent != null) { + node.parent._children.remove(node); + } + node.parent = this; + if (_children == null) { + _children = new List(); + } + _children.add(node); + } + + List get children { + return _children; + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorNode instanceNode = new ActorNode(); + instanceNode.copyNode(this, resetArtboard); + return instanceNode; + } + + void copyNode(ActorNode node, ActorArtboard resetArtboard) { + copyComponent(node, resetArtboard); + _transform = new Mat2D.clone(node._transform); + _worldTransform = new Mat2D.clone(node._worldTransform); + _translation = new Vec2D.clone(node._translation); + _scale = new Vec2D.clone(node._scale); + _rotation = node._rotation; + _opacity = node._opacity; + _renderOpacity = node._renderOpacity; + _overrideWorldTransform = node._overrideWorldTransform; + + if (node._clips != null) { + _clips = new List(node._clips.length); + for (int i = 0, l = node._clips.length; i < l; i++) { + _clips[i] = new ActorClip(node._clips[i].clipIdx); + } + } + else { + _clips = null; + } + } + + void onDirty(int dirt) { + + } + + bool addConstraint(ActorConstraint constraint) { + if (_constraints == null) { + _constraints = new List(); + } + if (_constraints.contains(constraint)) { + return false; + } + _constraints.add(constraint); + return true; + } + + bool addPeerConstraint(ActorConstraint constraint) { + if (_peerConstraints == null) { + _peerConstraints = new List(); + } + if (_peerConstraints.contains(constraint)) { + return false; + } + _peerConstraints.add(constraint); + return true; + } + + List get allConstraints => + (_constraints == null ? _peerConstraints : _peerConstraints == null + ? _constraints + : _constraints + _peerConstraints) ?? []; + + void update(int dirt) { + if ((dirt & TransformDirty) == TransformDirty) { + updateTransform(); + } + if ((dirt & WorldTransformDirty) == WorldTransformDirty) { + updateWorldTransform(); + if (_constraints != null) { + for (ActorConstraint constraint in _constraints) { + if (constraint.isEnabled) { + constraint.constrain(this); + } + } + } + } + } + + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + + if (_clips == null) { + return; + } + + for (ActorClip clip in _clips) { + clip.node = components[clip.clipIdx]; + } + } + + void completeResolve() { + // Nothing to complete for actornode. + } + + bool eachChildRecursive(NodeWalkCallback cb) { + if (_children != null) { + for (ActorNode child in _children) { + if (cb(child) == false) { + return false; + } + + if (child.eachChildRecursive(cb) == false) { + return false; + } + } + } + return true; + } + + bool all(NodeWalkCallback cb) { + if (cb(this) == false) { + return false; + } + + for (ActorNode child in _children) { + if (cb(child) == false) { + return false; + } + + child.eachChildRecursive(cb); + } + + return true; + } + + void invalidateShape() {} } \ No newline at end of file diff --git a/lib/flare/actor_node_solo.dart b/lib/flare/actor_node_solo.dart index 46049d2..cec8d40 100644 --- a/lib/flare/actor_node_solo.dart +++ b/lib/flare/actor_node_solo.dart @@ -4,67 +4,56 @@ import "actor_node.dart"; import "stream_reader.dart"; import "dart:math"; -class ActorNodeSolo extends ActorNode -{ - int _activeChildIndex = 0; - - set activeChildIndex(int idx) - { - if(idx != this._activeChildIndex) - { - this.setActiveChildIndex(idx); - } - } - - int get activeChildIndex - { - return this._activeChildIndex; - } - - void setActiveChildIndex(int idx) - { - if(this.children != null) - { - this._activeChildIndex = min(this.children.length, max(0, idx)); - for(int i = 0; i < this.children.length; i++) - { - var child = this.children[i]; - bool cv = (i != (this._activeChildIndex - 1)); - child.collapsedVisibility = cv; // Setter - } - } - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorNodeSolo soloInstance = new ActorNodeSolo(); - soloInstance.copySolo(this, resetArtboard); - return soloInstance; - } - - void copySolo(ActorNodeSolo node, ActorArtboard resetArtboard) - { - copyNode(node, resetArtboard); - _activeChildIndex = node._activeChildIndex; - } - - - static ActorNodeSolo read(ActorArtboard artboard, StreamReader reader, ActorNodeSolo node) - { - if(node == null) - { - node = new ActorNodeSolo(); - } - - ActorNode.read(artboard, reader, node); - node._activeChildIndex = reader.readUint32("activeChild"); - return node; - } - - void completeResolve() - { - super.completeResolve(); - this.setActiveChildIndex(this.activeChildIndex); - } +class ActorNodeSolo extends ActorNode { + int _activeChildIndex = 0; + + set activeChildIndex(int idx) { + if (idx != this._activeChildIndex) { + this.setActiveChildIndex(idx); + } + } + + int get activeChildIndex { + return this._activeChildIndex; + } + + void setActiveChildIndex(int idx) { + if (this.children != null) { + this._activeChildIndex = min(this.children.length, max(0, idx)); + for (int i = 0; i < this.children.length; i++) { + var child = this.children[i]; + bool cv = (i != (this._activeChildIndex - 1)); + child.collapsedVisibility = cv; // Setter + } + } + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorNodeSolo soloInstance = new ActorNodeSolo(); + soloInstance.copySolo(this, resetArtboard); + return soloInstance; + } + + void copySolo(ActorNodeSolo node, ActorArtboard resetArtboard) { + copyNode(node, resetArtboard); + _activeChildIndex = node._activeChildIndex; + } + + + static ActorNodeSolo read(ActorArtboard artboard, StreamReader reader, + ActorNodeSolo node) { + if (node == null) { + node = new ActorNodeSolo(); + } + + ActorNode.read(artboard, reader, node); + node._activeChildIndex = reader.readUint32("activeChild"); + return node; + } + + void completeResolve() { + super.completeResolve(); + this.setActiveChildIndex(this.activeChildIndex); + } } \ No newline at end of file diff --git a/lib/flare/actor_path.dart b/lib/flare/actor_path.dart index 4f2c407..93419c5 100644 --- a/lib/flare/actor_path.dart +++ b/lib/flare/actor_path.dart @@ -11,356 +11,314 @@ import "math/vec2d.dart"; import "math/mat2d.dart"; import "math/aabb.dart"; -abstract class ActorBasePath -{ - //bool get isClosed; - List get points; - ActorNode get parent; - void invalidatePath(); - bool get isPathInWorldSpace => false; - Mat2D get pathTransform; - Mat2D get transform; - List get allClips; - List get deformedPoints => points; - - AABB getPathAABB() - { - double minX = double.maxFinite; - double minY = double.maxFinite; - double maxX = -double.maxFinite; - double maxY = -double.maxFinite; - - AABB obb = getPathOBB(); - - List pts = [ - new Vec2D.fromValues(obb[0], obb[1]), - new Vec2D.fromValues(obb[2], obb[1]), - new Vec2D.fromValues(obb[2], obb[3]), - new Vec2D.fromValues(obb[0], obb[3]) - ]; - - Mat2D localTransform; - if(isPathInWorldSpace) - { - // convert the path coordinates into local parent space. - localTransform = new Mat2D(); - Mat2D.invert(localTransform, parent.worldTransform); - } - else - { - localTransform = transform; - } - - for(Vec2D p in pts) - { - Vec2D wp = Vec2D.transformMat2D(p, p, localTransform); - if(wp[0] < minX) - { - minX = wp[0]; - } - if(wp[1] < minY) - { - minY = wp[1]; - } - - if(wp[0] > maxX) - { - maxX = wp[0]; - } - if(wp[1] > maxY) - { - maxY = wp[1]; - } +abstract class ActorBasePath { + //bool get isClosed; + List get points; + + ActorNode get parent; + + void invalidatePath(); + + bool get isPathInWorldSpace => false; + + Mat2D get pathTransform; + + Mat2D get transform; + + List get allClips; + + List get deformedPoints => points; + + AABB getPathAABB() { + double minX = double.maxFinite; + double minY = double.maxFinite; + double maxX = -double.maxFinite; + double maxY = -double.maxFinite; + + AABB obb = getPathOBB(); + + List pts = [ + new Vec2D.fromValues(obb[0], obb[1]), + new Vec2D.fromValues(obb[2], obb[1]), + new Vec2D.fromValues(obb[2], obb[3]), + new Vec2D.fromValues(obb[0], obb[3]) + ]; + + Mat2D localTransform; + if (isPathInWorldSpace) { + // convert the path coordinates into local parent space. + localTransform = new Mat2D(); + Mat2D.invert(localTransform, parent.worldTransform); + } + else { + localTransform = transform; + } + + for (Vec2D p in pts) { + Vec2D wp = Vec2D.transformMat2D(p, p, localTransform); + if (wp[0] < minX) { + minX = wp[0]; + } + if (wp[1] < minY) { + minY = wp[1]; + } + + if (wp[0] > maxX) { + maxX = wp[0]; + } + if (wp[1] > maxY) { + maxY = wp[1]; + } + } + return AABB.fromValues(minX, minY, maxX, maxY); + } + + markPathDirty() { + invalidatePath(); + if (parent is ActorShape) { + parent.invalidateShape(); + } + } + + AABB getPathOBB() { + double minX = double.maxFinite; + double minY = double.maxFinite; + double maxX = -double.maxFinite; + double maxY = -double.maxFinite; + + List renderPoints = points; + for (PathPoint point in renderPoints) { + Vec2D t = point.translation; + double x = t[0]; + double y = t[1]; + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + + if (point is CubicPathPoint) { + Vec2D t = point.inPoint; + x = t[0]; + y = t[1]; + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; } - return AABB.fromValues(minX, minY, maxX, maxY); + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + + t = point.outPoint; + x = t[0]; + y = t[1]; + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } } - markPathDirty() - { - invalidatePath(); - if(parent is ActorShape) - { - parent.invalidateShape(); - } - } - - AABB getPathOBB() - { - double minX = double.maxFinite; - double minY = double.maxFinite; - double maxX = -double.maxFinite; - double maxY = -double.maxFinite; - - List renderPoints = points; - for(PathPoint point in renderPoints) - { - Vec2D t = point.translation; - double x = t[0]; - double y = t[1]; - if(x < minX) - { - minX = x; - } - if(y < minY) - { - minY = y; - } - if(x > maxX) - { - maxX = x; - } - if(y > maxY) - { - maxY = y; - } - - if(point is CubicPathPoint) - { - Vec2D t = point.inPoint; - x = t[0]; - y = t[1]; - if(x < minX) - { - minX = x; - } - if(y < minY) - { - minY = y; - } - if(x > maxX) - { - maxX = x; - } - if(y > maxY) - { - maxY = y; - } - - t = point.outPoint; - x = t[0]; - y = t[1]; - if(x < minX) - { - minX = x; - } - if(y < minY) - { - minY = y; - } - if(x > maxX) - { - maxX = x; - } - if(y > maxY) - { - maxY = y; - } - } - } - - return new AABB.fromValues(minX, minY, maxX, maxY); - } + return new AABB.fromValues(minX, minY, maxX, maxY); + } } -abstract class ActorProceduralPath extends ActorNode with ActorBasePath -{ - double _width; - double _height; - - double get width => _width; - double get height => _height; - - @override - Mat2D get pathTransform => worldTransform; - - set width(double w) - { - if(w != _width) - { - _width = w; - markPathDirty(); - } - } - - set height(double w) - { - if(w != _height) - { - _height = w; - markPathDirty(); - } - } - - void copyPath(ActorBasePath node, ActorArtboard resetArtboard) - { - ActorProceduralPath nodePath = node as ActorProceduralPath; - copyNode(nodePath, resetArtboard); - _width = nodePath.width; - _height = nodePath.height; +abstract class ActorProceduralPath extends ActorNode + with ActorBasePath { + double _width; + double _height; + + double get width => _width; + + double get height => _height; + + @override + Mat2D get pathTransform => worldTransform; + + set width(double w) { + if (w != _width) { + _width = w; + markPathDirty(); + } + } + + set height(double w) { + if (w != _height) { + _height = w; + markPathDirty(); } + } + + void copyPath(ActorBasePath node, ActorArtboard resetArtboard) { + ActorProceduralPath nodePath = node as ActorProceduralPath; + copyNode(nodePath, resetArtboard); + _width = nodePath.width; + _height = nodePath.height; + } } -class ActorPath extends ActorSkinnable with ActorBasePath -{ - bool _isHidden; - bool _isClosed; - List _points; - Float32List vertexDeform; - ActorSkin skin; - - @override - bool get isPathInWorldSpace => isConnectedToBones; - - @override - void invalidatePath() - { - // Up to the implementation. - } - - - @override - Mat2D get pathTransform => isConnectedToBones ? null : worldTransform; - - static const int VertexDeformDirty = 1<<1; - - @override - List get points => _points; - - @override - List get deformedPoints - { - if(!isConnectedToBones || skin == null) - { - return _points; - } - - Float32List boneMatrices = skin.boneMatrices; - List deformed = []; - for(PathPoint point in _points) - { - deformed.add(point.skin(worldTransform, boneMatrices)); - } - return deformed; - } - - bool get isClosed - { - return _isClosed; - } - - void markVertexDeformDirty() - { - if(artboard == null) - { - return; - } - artboard.addDirt(this, VertexDeformDirty, false); - } - - void update(int dirt) - { - if(vertexDeform != null && (dirt & VertexDeformDirty) == VertexDeformDirty) - { - int readIdx = 0; - for(PathPoint point in _points) - { - point.translation[0] = vertexDeform[readIdx++]; - point.translation[1] = vertexDeform[readIdx++]; - switch(point.pointType) - { - case PointType.Straight: - (point as StraightPathPoint).radius = vertexDeform[readIdx++]; - break; - - default: - CubicPathPoint cubicPoint = point as CubicPathPoint; - cubicPoint.inPoint[0] = vertexDeform[readIdx++]; - cubicPoint.inPoint[1] = vertexDeform[readIdx++]; - cubicPoint.outPoint[0] = vertexDeform[readIdx++]; - cubicPoint.outPoint[1] = vertexDeform[readIdx++]; - break; - } - } - } - markPathDirty(); - - super.update(dirt); - } - - static ActorPath read(ActorArtboard artboard, StreamReader reader, ActorPath component) - { - if(component == null) - { - component = new ActorPath(); - } - - ActorSkinnable.read(artboard, reader, component); - - component._isHidden = !reader.readBool("isVisible"); - component._isClosed = reader.readBool("isClosed"); - - reader.openArray("points"); - int pointCount = reader.readUint16Length(); - component._points = new List(pointCount); - for(int i = 0; i < pointCount; i++) - { - reader.openObject("point"); - PathPoint point; - PointType type = pointTypeLookup[reader.readUint8("pointType")]; - switch(type) - { - case PointType.Straight: - { - point = new StraightPathPoint(); - break; - } - default: - { - point = new CubicPathPoint(type); - break; - } - } - if(point == null) - { - throw new UnsupportedError("Invalid point type " + type.toString()); - } - else - { - point.read(reader, component.isConnectedToBones); - } - reader.closeObject(); - - component._points[i] = point; - } - reader.closeArray(); - return component; - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorPath instanceEvent = new ActorPath(); - instanceEvent.copyPath(this, resetArtboard); - return instanceEvent; - } - - void copyPath(ActorBasePath node, ActorArtboard resetArtboard) - { - ActorPath nodePath = node as ActorPath; - copySkinnable(nodePath, resetArtboard); - _isHidden = nodePath._isHidden; - _isClosed = nodePath._isClosed; - - int pointCount = nodePath._points.length; - - _points = new List(pointCount); - for(int i = 0; i < pointCount; i++) - { - _points[i] = nodePath._points[i].makeInstance(); - } - - if(nodePath.vertexDeform != null) - { - vertexDeform = new Float32List.fromList(nodePath.vertexDeform); - } - } +class ActorPath extends ActorSkinnable + with ActorBasePath { + bool _isHidden; + bool _isClosed; + List _points; + Float32List vertexDeform; + ActorSkin skin; + + @override + bool get isPathInWorldSpace => isConnectedToBones; + + @override + void invalidatePath() { + // Up to the implementation. + } + + + @override + Mat2D get pathTransform => isConnectedToBones ? null : worldTransform; + + static const int VertexDeformDirty = 1 << 1; + + @override + List get points => _points; + + @override + List get deformedPoints { + if (!isConnectedToBones || skin == null) { + return _points; + } + + Float32List boneMatrices = skin.boneMatrices; + List deformed = []; + for (PathPoint point in _points) { + deformed.add(point.skin(worldTransform, boneMatrices)); + } + return deformed; + } + + bool get isClosed { + return _isClosed; + } + + void markVertexDeformDirty() { + if (artboard == null) { + return; + } + artboard.addDirt(this, VertexDeformDirty, false); + } + + void update(int dirt) { + if (vertexDeform != null && + (dirt & VertexDeformDirty) == VertexDeformDirty) { + int readIdx = 0; + for (PathPoint point in _points) { + point.translation[0] = vertexDeform[readIdx++]; + point.translation[1] = vertexDeform[readIdx++]; + switch (point.pointType) { + case PointType.Straight: + (point as StraightPathPoint).radius = vertexDeform[readIdx++]; + break; + + default: + CubicPathPoint cubicPoint = point as CubicPathPoint; + cubicPoint.inPoint[0] = vertexDeform[readIdx++]; + cubicPoint.inPoint[1] = vertexDeform[readIdx++]; + cubicPoint.outPoint[0] = vertexDeform[readIdx++]; + cubicPoint.outPoint[1] = vertexDeform[readIdx++]; + break; + } + } + } + markPathDirty(); + + super.update(dirt); + } + + static ActorPath read(ActorArtboard artboard, StreamReader reader, + ActorPath component) { + if (component == null) { + component = new ActorPath(); + } + + ActorSkinnable.read(artboard, reader, component); + + component._isHidden = !reader.readBool("isVisible"); + component._isClosed = reader.readBool("isClosed"); + + reader.openArray("points"); + int pointCount = reader.readUint16Length(); + component._points = new List(pointCount); + for (int i = 0; i < pointCount; i++) { + reader.openObject("point"); + PathPoint point; + PointType type = pointTypeLookup[reader.readUint8("pointType")]; + switch (type) { + case PointType.Straight: + { + point = new StraightPathPoint(); + break; + } + default: + { + point = new CubicPathPoint(type); + break; + } + } + if (point == null) { + throw new UnsupportedError("Invalid point type " + type.toString()); + } + else { + point.read(reader, component.isConnectedToBones); + } + reader.closeObject(); + + component._points[i] = point; + } + reader.closeArray(); + return component; + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorPath instanceEvent = new ActorPath(); + instanceEvent.copyPath(this, resetArtboard); + return instanceEvent; + } + + void copyPath(ActorBasePath node, ActorArtboard resetArtboard) { + ActorPath nodePath = node as ActorPath; + copySkinnable(nodePath, resetArtboard); + _isHidden = nodePath._isHidden; + _isClosed = nodePath._isClosed; + + int pointCount = nodePath._points.length; + + _points = new List(pointCount); + for (int i = 0; i < pointCount; i++) { + _points[i] = nodePath._points[i].makeInstance(); + } + + if (nodePath.vertexDeform != null) { + vertexDeform = new Float32List.fromList(nodePath.vertexDeform); + } + } } diff --git a/lib/flare/actor_polygon.dart b/lib/flare/actor_polygon.dart index e17b4b9..4256f3f 100644 --- a/lib/flare/actor_polygon.dart +++ b/lib/flare/actor_polygon.dart @@ -7,65 +7,62 @@ import "actor_path.dart"; import "path_point.dart"; import "actor_component.dart"; -class ActorPolygon extends ActorProceduralPath -{ - int sides = 5; - @override - void invalidatePath() - { - } - - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorPolygon instance = new ActorPolygon(); - instance.copyPolygon(this, resetArtboard); - return instance; - } +class ActorPolygon extends ActorProceduralPath { + int sides = 5; + + @override + void invalidatePath() { + } - void copyPolygon(ActorPolygon node, ActorArtboard resetArtboard) - { - copyPath(node, resetArtboard); - sides = node.sides; - } - static ActorPolygon read(ActorArtboard artboard, StreamReader reader, ActorPolygon component) - { - if(component == null) - { - component = new ActorPolygon(); - } + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorPolygon instance = new ActorPolygon(); + instance.copyPolygon(this, resetArtboard); + return instance; + } - ActorNode.read(artboard, reader, component); + void copyPolygon(ActorPolygon node, ActorArtboard resetArtboard) { + copyPath(node, resetArtboard); + sides = node.sides; + } - component.width = reader.readFloat32("width"); - component.height = reader.readFloat32("height"); - component.sides = reader.readUint32("sides"); - return component; + static ActorPolygon read(ActorArtboard artboard, StreamReader reader, + ActorPolygon component) { + if (component == null) { + component = new ActorPolygon(); } - @override - List get points - { - List _polygonPoints = []; - double angle = -pi/2.0; - double inc = (pi*2.0)/sides; + ActorNode.read(artboard, reader, component); + + component.width = reader.readFloat32("width"); + component.height = reader.readFloat32("height"); + component.sides = reader.readUint32("sides"); + return component; + } + + @override + List get points { + List _polygonPoints = []; + double angle = -pi / 2.0; + double inc = (pi * 2.0) / sides; - for(int i=0; i < sides; i++) - { - _polygonPoints.add( - new StraightPathPoint.fromTranslation( - Vec2D.fromValues(cos(angle)*radiusX, sin(angle)*radiusY) - ) - ); - angle += inc; - } - - return _polygonPoints; + for (int i = 0; i < sides; i++) { + _polygonPoints.add( + new StraightPathPoint.fromTranslation( + Vec2D.fromValues(cos(angle) * radiusX, sin(angle) * radiusY) + ) + ); + angle += inc; } - bool get isClosed => true; - bool get doesDraw => !this.renderCollapsed; - double get radiusX => this.width/2; - double get radiusY => this.height/2; + return _polygonPoints; + } + + bool get isClosed => true; + + bool get doesDraw => !this.renderCollapsed; + + double get radiusX => this.width / 2; + + double get radiusY => this.height / 2; } \ No newline at end of file diff --git a/lib/flare/actor_rectangle.dart b/lib/flare/actor_rectangle.dart index c7bb7e8..ea24c34 100644 --- a/lib/flare/actor_rectangle.dart +++ b/lib/flare/actor_rectangle.dart @@ -8,93 +8,84 @@ import "actor_component.dart"; const double CircleConstant = 0.55; -class ActorRectangle extends ActorProceduralPath -{ - double _radius = 0.0; +class ActorRectangle extends ActorProceduralPath { + double _radius = 0.0; - @override - void invalidatePath() - { - } - - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorRectangle instance = new ActorRectangle(); - instance.copyRectangle(this, resetArtboard); - return instance; - } + @override + void invalidatePath() { + } - void copyRectangle(ActorRectangle node, ActorArtboard resetArtboard) - { - copyPath(node, resetArtboard); - _radius = node._radius; - } - static ActorRectangle read(ActorArtboard artboard, StreamReader reader, ActorRectangle component) - { - if(component == null) - { - component = new ActorRectangle(); - } + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorRectangle instance = new ActorRectangle(); + instance.copyRectangle(this, resetArtboard); + return instance; + } - ActorNode.read(artboard, reader, component); + void copyRectangle(ActorRectangle node, ActorArtboard resetArtboard) { + copyPath(node, resetArtboard); + _radius = node._radius; + } - component.width = reader.readFloat32("width"); - component.height = reader.readFloat32("height"); - component._radius = reader.readFloat32("cornerRadius"); - return component; + static ActorRectangle read(ActorArtboard artboard, StreamReader reader, + ActorRectangle component) { + if (component == null) { + component = new ActorRectangle(); } - @override - List get points - { - double halfWidth = width/2.0; - double halfHeight = height/2.0; - List _rectanglePathPoints = []; - _rectanglePathPoints.add( - new StraightPathPoint.fromValues( - Vec2D.fromValues(-halfWidth, -halfHeight), - _radius - ) - ); - _rectanglePathPoints.add( - new StraightPathPoint.fromValues( - Vec2D.fromValues(halfWidth, -halfHeight), - _radius - ) - ); - _rectanglePathPoints.add( - new StraightPathPoint.fromValues( - Vec2D.fromValues(halfWidth, halfHeight), - _radius - ) - ); - _rectanglePathPoints.add( - new StraightPathPoint.fromValues( - Vec2D.fromValues(-halfWidth, halfHeight), - _radius - ) - ); + ActorNode.read(artboard, reader, component); - return _rectanglePathPoints; - } + component.width = reader.readFloat32("width"); + component.height = reader.readFloat32("height"); + component._radius = reader.readFloat32("cornerRadius"); + return component; + } - set radius(double rd) - { - if(rd != _radius) - { - _radius = rd; - markPathDirty(); - } - } + @override + List get points { + double halfWidth = width / 2.0; + double halfHeight = height / 2.0; + List _rectanglePathPoints = []; + _rectanglePathPoints.add( + new StraightPathPoint.fromValues( + Vec2D.fromValues(-halfWidth, -halfHeight), + _radius + ) + ); + _rectanglePathPoints.add( + new StraightPathPoint.fromValues( + Vec2D.fromValues(halfWidth, -halfHeight), + _radius + ) + ); + _rectanglePathPoints.add( + new StraightPathPoint.fromValues( + Vec2D.fromValues(halfWidth, halfHeight), + _radius + ) + ); + _rectanglePathPoints.add( + new StraightPathPoint.fromValues( + Vec2D.fromValues(-halfWidth, halfHeight), + _radius + ) + ); - bool get isClosed => true; - - bool get doesDraw - { - return !renderCollapsed; + return _rectanglePathPoints; + } + + set radius(double rd) { + if (rd != _radius) { + _radius = rd; + markPathDirty(); } + } + + bool get isClosed => true; + + bool get doesDraw { + return !renderCollapsed; + } - double get radius => _radius; + double get radius => _radius; } \ No newline at end of file diff --git a/lib/flare/actor_root_bone.dart b/lib/flare/actor_root_bone.dart index a1e3dac..c639db6 100644 --- a/lib/flare/actor_root_bone.dart +++ b/lib/flare/actor_root_bone.dart @@ -4,46 +4,38 @@ import "actor_node.dart"; import "actor_bone.dart"; import "actor_component.dart"; -class ActorRootBone extends ActorNode -{ - ActorBone _firstBone; +class ActorRootBone extends ActorNode { + ActorBone _firstBone; - ActorBone get firstBone - { - return _firstBone; - } + ActorBone get firstBone { + return _firstBone; + } - void completeResolve() - { - super.completeResolve(); - if(children == null) - { - return; - } - for(ActorNode node in children) - { - if(node is ActorBone) - { - _firstBone = node; - return; - } - } - } + void completeResolve() { + super.completeResolve(); + if (children == null) { + return; + } + for (ActorNode node in children) { + if (node is ActorBone) { + _firstBone = node; + return; + } + } + } - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorRootBone instanceNode = new ActorRootBone(); - instanceNode.copyNode(this, resetArtboard); - return instanceNode; - } + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorRootBone instanceNode = new ActorRootBone(); + instanceNode.copyNode(this, resetArtboard); + return instanceNode; + } - static ActorRootBone read(ActorArtboard artboard, StreamReader reader, ActorRootBone node) - { - if(node == null) - { - node = new ActorRootBone(); - } - ActorNode.read(artboard, reader, node); - return node; - } + static ActorRootBone read(ActorArtboard artboard, StreamReader reader, + ActorRootBone node) { + if (node == null) { + node = new ActorRootBone(); + } + ActorNode.read(artboard, reader, node); + return node; + } } \ No newline at end of file diff --git a/lib/flare/actor_rotation_constraint.dart b/lib/flare/actor_rotation_constraint.dart index 67c757d..3d7f203 100644 --- a/lib/flare/actor_rotation_constraint.dart +++ b/lib/flare/actor_rotation_constraint.dart @@ -8,191 +8,170 @@ import "math/mat2d.dart"; import "dart:math"; import "transform_space.dart"; -class ActorRotationConstraint extends ActorTargetedConstraint -{ - static const double PI2 = pi*2.0; - - bool _copy = false; - double _scale = 1.0; - bool _enableMin = false; - bool _enableMax = false; - double _max = PI2; - double _min = -PI2; - bool _offset = false; - int _sourceSpace = TransformSpace.World; - int _destSpace = TransformSpace.World; - int _minMaxSpace = TransformSpace.World; - TransformComponents _componentsA = new TransformComponents(); - TransformComponents _componentsB = new TransformComponents(); - - static ActorRotationConstraint read(ActorArtboard artboard, StreamReader reader, ActorRotationConstraint component) - { - if(component == null) - { - component = new ActorRotationConstraint(); - } - ActorTargetedConstraint.read(artboard, reader, component); - component._copy = reader.readBool("copy"); - if(component._copy) - { - component._scale = reader.readFloat32("scale"); - } - component._enableMin = reader.readBool("enableMin"); - if(component._enableMin) - { - component._min = reader.readFloat32("min"); - } - component._enableMax = reader.readBool("enableMax"); - if(component._enableMax) - { - component._max = reader.readFloat32("max"); - } - - component._offset = reader.readBool("offset"); - component._sourceSpace = reader.readUint8("sourceSpaceId"); - component._destSpace = reader.readUint8("destSpaceId"); - component._minMaxSpace = reader.readUint8("minMaxSpaceId"); - - return component; - } - - void constrain(ActorNode node) - { - ActorNode target = this.target; - ActorNode grandParent = parent.parent; - - Mat2D transformA = parent.worldTransform; - Mat2D transformB = new Mat2D(); - Mat2D.decompose(transformA, _componentsA); - if(target == null) - { - Mat2D.copy(transformB, transformA); - _componentsB[0] = _componentsA[0]; - _componentsB[1] = _componentsA[1]; - _componentsB[2] = _componentsA[2]; - _componentsB[3] = _componentsA[3]; - _componentsB[4] = _componentsA[4]; - _componentsB[5] = _componentsA[5]; - } - else - { - Mat2D.copy(transformB, target.worldTransform); - if(_sourceSpace == TransformSpace.Local) - { - ActorNode sourceGrandParent = target.parent; - if(sourceGrandParent != null) - { - Mat2D inverse = new Mat2D(); - if(!Mat2D.invert(inverse, sourceGrandParent.worldTransform)) - { - return; - } - Mat2D.multiply(transformB, inverse, transformB); - } - } - Mat2D.decompose(transformB, _componentsB); - - if(!_copy) - { - _componentsB.rotation = _destSpace == TransformSpace.Local ? 1.0 : _componentsA.rotation; - } - else - { - _componentsB.rotation *= _scale; - if(_offset) - { - _componentsB.rotation += parent.rotation; - } - } - - if(_destSpace == TransformSpace.Local) - { - // Destination space is in parent transform coordinates. - // Recompose the parent local transform and get it in world, then decompose the world for interpolation. - if(grandParent != null) - { - Mat2D.compose(transformB, _componentsB); - Mat2D.multiply(transformB, grandParent.worldTransform, transformB); - Mat2D.decompose(transformB, _componentsB); - } - } - } - - bool clampLocal = _minMaxSpace == TransformSpace.Local && grandParent != null; - if(clampLocal) - { - // Apply min max in local space, so transform to local coordinates first. - Mat2D.compose(transformB, _componentsB); - Mat2D inverse = new Mat2D(); - if(!Mat2D.invert(inverse, grandParent.worldTransform)) - { - return; - } - Mat2D.multiply(transformB, inverse, transformB); - Mat2D.decompose(transformB, _componentsB); - } - if(_enableMax && _componentsB.rotation > _max) - { - _componentsB.rotation = _max; - } - if(_enableMin && _componentsB.rotation < _min) - { - _componentsB.rotation = _min; - } - if(clampLocal) - { - // Transform back to world. - Mat2D.compose(transformB, _componentsB); - Mat2D.multiply(transformB, grandParent.worldTransform, transformB); - Mat2D.decompose(transformB, _componentsB); - } - - double angleA = _componentsA.rotation%PI2; - double angleB = _componentsB.rotation%PI2; - double diff = angleB - angleA; - - if(diff > pi) - { - diff -= PI2; - } - else if(diff < -pi) - { - diff += PI2; - } - _componentsB.rotation = _componentsA.rotation + diff * strength; - _componentsB.x = _componentsA.x; - _componentsB.y = _componentsA.y; - _componentsB.scaleX = _componentsA.scaleX; - _componentsB.scaleY = _componentsA.scaleY; - _componentsB.skew = _componentsA.skew; - - Mat2D.compose(parent.worldTransform, _componentsB); - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorRotationConstraint instance = new ActorRotationConstraint(); - instance.copyRotationConstraint(this, resetArtboard); - return instance; - } - - void copyRotationConstraint(ActorRotationConstraint node, ActorArtboard resetArtboard) - { - copyTargetedConstraint(node, resetArtboard); - - _copy = node._copy; - _scale = node._scale; - _enableMin = node._enableMin; - _enableMax = node._enableMax; - _min = node._min; - _max = node._max; - - _offset = node._offset; - _sourceSpace = node._sourceSpace; - _destSpace = node._destSpace; - _minMaxSpace = node._minMaxSpace; - } - - void update(int dirt) {} - void completeResolve() {} +class ActorRotationConstraint extends ActorTargetedConstraint { + static const double PI2 = pi * 2.0; + + bool _copy = false; + double _scale = 1.0; + bool _enableMin = false; + bool _enableMax = false; + double _max = PI2; + double _min = -PI2; + bool _offset = false; + int _sourceSpace = TransformSpace.World; + int _destSpace = TransformSpace.World; + int _minMaxSpace = TransformSpace.World; + TransformComponents _componentsA = new TransformComponents(); + TransformComponents _componentsB = new TransformComponents(); + + static ActorRotationConstraint read(ActorArtboard artboard, + StreamReader reader, ActorRotationConstraint component) { + if (component == null) { + component = new ActorRotationConstraint(); + } + ActorTargetedConstraint.read(artboard, reader, component); + component._copy = reader.readBool("copy"); + if (component._copy) { + component._scale = reader.readFloat32("scale"); + } + component._enableMin = reader.readBool("enableMin"); + if (component._enableMin) { + component._min = reader.readFloat32("min"); + } + component._enableMax = reader.readBool("enableMax"); + if (component._enableMax) { + component._max = reader.readFloat32("max"); + } + + component._offset = reader.readBool("offset"); + component._sourceSpace = reader.readUint8("sourceSpaceId"); + component._destSpace = reader.readUint8("destSpaceId"); + component._minMaxSpace = reader.readUint8("minMaxSpaceId"); + + return component; + } + + void constrain(ActorNode node) { + ActorNode target = this.target; + ActorNode grandParent = parent.parent; + + Mat2D transformA = parent.worldTransform; + Mat2D transformB = new Mat2D(); + Mat2D.decompose(transformA, _componentsA); + if (target == null) { + Mat2D.copy(transformB, transformA); + _componentsB[0] = _componentsA[0]; + _componentsB[1] = _componentsA[1]; + _componentsB[2] = _componentsA[2]; + _componentsB[3] = _componentsA[3]; + _componentsB[4] = _componentsA[4]; + _componentsB[5] = _componentsA[5]; + } + else { + Mat2D.copy(transformB, target.worldTransform); + if (_sourceSpace == TransformSpace.Local) { + ActorNode sourceGrandParent = target.parent; + if (sourceGrandParent != null) { + Mat2D inverse = new Mat2D(); + if (!Mat2D.invert(inverse, sourceGrandParent.worldTransform)) { + return; + } + Mat2D.multiply(transformB, inverse, transformB); + } + } + Mat2D.decompose(transformB, _componentsB); + + if (!_copy) { + _componentsB.rotation = + _destSpace == TransformSpace.Local ? 1.0 : _componentsA.rotation; + } + else { + _componentsB.rotation *= _scale; + if (_offset) { + _componentsB.rotation += parent.rotation; + } + } + + if (_destSpace == TransformSpace.Local) { + // Destination space is in parent transform coordinates. + // Recompose the parent local transform and get it in world, then decompose the world for interpolation. + if (grandParent != null) { + Mat2D.compose(transformB, _componentsB); + Mat2D.multiply(transformB, grandParent.worldTransform, transformB); + Mat2D.decompose(transformB, _componentsB); + } + } + } + + bool clampLocal = _minMaxSpace == TransformSpace.Local && + grandParent != null; + if (clampLocal) { + // Apply min max in local space, so transform to local coordinates first. + Mat2D.compose(transformB, _componentsB); + Mat2D inverse = new Mat2D(); + if (!Mat2D.invert(inverse, grandParent.worldTransform)) { + return; + } + Mat2D.multiply(transformB, inverse, transformB); + Mat2D.decompose(transformB, _componentsB); + } + if (_enableMax && _componentsB.rotation > _max) { + _componentsB.rotation = _max; + } + if (_enableMin && _componentsB.rotation < _min) { + _componentsB.rotation = _min; + } + if (clampLocal) { + // Transform back to world. + Mat2D.compose(transformB, _componentsB); + Mat2D.multiply(transformB, grandParent.worldTransform, transformB); + Mat2D.decompose(transformB, _componentsB); + } + + double angleA = _componentsA.rotation % PI2; + double angleB = _componentsB.rotation % PI2; + double diff = angleB - angleA; + + if (diff > pi) { + diff -= PI2; + } + else if (diff < -pi) { + diff += PI2; + } + _componentsB.rotation = _componentsA.rotation + diff * strength; + _componentsB.x = _componentsA.x; + _componentsB.y = _componentsA.y; + _componentsB.scaleX = _componentsA.scaleX; + _componentsB.scaleY = _componentsA.scaleY; + _componentsB.skew = _componentsA.skew; + + Mat2D.compose(parent.worldTransform, _componentsB); + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorRotationConstraint instance = new ActorRotationConstraint(); + instance.copyRotationConstraint(this, resetArtboard); + return instance; + } + + void copyRotationConstraint(ActorRotationConstraint node, + ActorArtboard resetArtboard) { + copyTargetedConstraint(node, resetArtboard); + + _copy = node._copy; + _scale = node._scale; + _enableMin = node._enableMin; + _enableMax = node._enableMax; + _min = node._min; + _max = node._max; + + _offset = node._offset; + _sourceSpace = node._sourceSpace; + _destSpace = node._destSpace; + _minMaxSpace = node._minMaxSpace; + } + + void update(int dirt) {} + + void completeResolve() {} } \ No newline at end of file diff --git a/lib/flare/actor_scale_constraint.dart b/lib/flare/actor_scale_constraint.dart index 6b499ad..7a512e1 100644 --- a/lib/flare/actor_scale_constraint.dart +++ b/lib/flare/actor_scale_constraint.dart @@ -6,155 +6,137 @@ import "math/mat2d.dart"; import "math/transform_components.dart"; import "transform_space.dart"; -class ActorScaleConstraint extends ActorAxisConstraint -{ - TransformComponents _componentsA = new TransformComponents(); - TransformComponents _componentsB = new TransformComponents(); - - ActorScaleConstraint() : super(); - - static ActorScaleConstraint read(ActorArtboard artboard, StreamReader reader, ActorScaleConstraint component) - { - if(component == null) - { - component = new ActorScaleConstraint(); - } - ActorAxisConstraint.read(artboard, reader, component); - return component; +class ActorScaleConstraint extends ActorAxisConstraint { + TransformComponents _componentsA = new TransformComponents(); + TransformComponents _componentsB = new TransformComponents(); + + ActorScaleConstraint() : super(); + + static ActorScaleConstraint read(ActorArtboard artboard, StreamReader reader, + ActorScaleConstraint component) { + if (component == null) { + component = new ActorScaleConstraint(); } + ActorAxisConstraint.read(artboard, reader, component); + return component; + } - @override - makeInstance(ActorArtboard resetArtboard) - { - ActorScaleConstraint node = new ActorScaleConstraint(); - node.copyAxisConstraint(this, resetArtboard); - return node; + @override + makeInstance(ActorArtboard resetArtboard) { + ActorScaleConstraint node = new ActorScaleConstraint(); + node.copyAxisConstraint(this, resetArtboard); + return node; + } + + @override + constrain(ActorNode node) { + ActorNode t = this.target; + ActorNode p = this.parent; + ActorNode grandParent = p.parent; + + Mat2D transformA = parent.worldTransform; + Mat2D transformB = new Mat2D(); + Mat2D.decompose(transformA, _componentsA); + if (t == null) { + Mat2D.copy(transformB, transformA); + _componentsB[0] = _componentsA[0]; + _componentsB[1] = _componentsA[1]; + _componentsB[2] = _componentsA[2]; + _componentsB[3] = _componentsA[3]; + _componentsB[4] = _componentsA[4]; + _componentsB[5] = _componentsA[5]; } + else { + Mat2D.copy(transformB, t.worldTransform); + if (sourceSpace == TransformSpace.Local) { + ActorNode sourceGrandParent = t.parent; + if (sourceGrandParent != null) { + Mat2D inverse = new Mat2D(); + Mat2D.invert(inverse, sourceGrandParent.worldTransform); + Mat2D.multiply(transformB, inverse, transformB); + } + } + Mat2D.decompose(transformB, _componentsB); - @override - constrain(ActorNode node) - { - ActorNode t = this.target; - ActorNode p = this.parent; - ActorNode grandParent = p.parent; - - Mat2D transformA = parent.worldTransform; - Mat2D transformB = new Mat2D(); - Mat2D.decompose(transformA, _componentsA); - if(t == null) - { - Mat2D.copy(transformB, transformA); - _componentsB[0] = _componentsA[0]; - _componentsB[1] = _componentsA[1]; - _componentsB[2] = _componentsA[2]; - _componentsB[3] = _componentsA[3]; - _componentsB[4] = _componentsA[4]; - _componentsB[5] = _componentsA[5]; + if (!this.copyX) { + _componentsB[2] = + this.destSpace == TransformSpace.Local ? 1.0 : _componentsA[2]; + } + else { + _componentsB[2] *= this.scaleX; + if (this.offset) { + _componentsB[2] *= parent.scaleX; } - else - { - Mat2D.copy(transformB, t.worldTransform); - if(sourceSpace == TransformSpace.Local) - { - ActorNode sourceGrandParent = t.parent; - if(sourceGrandParent != null) - { - Mat2D inverse = new Mat2D(); - Mat2D.invert(inverse, sourceGrandParent.worldTransform); - Mat2D.multiply(transformB, inverse, transformB); - } - } - Mat2D.decompose(transformB, _componentsB); - - if(!this.copyX) - { - _componentsB[2] = this.destSpace == TransformSpace.Local ? 1.0 : _componentsA[2]; - } - else - { - _componentsB[2] *= this.scaleX; - if(this.offset) - { - _componentsB[2] *= parent.scaleX; - } - } - - if(!this.copyY) - { - _componentsB[3] = this.destSpace == TransformSpace.Local ? 0.0 : _componentsA[3]; - } - else - { - _componentsB[3] *= this.scaleY; - - if(this.offset) - { - _componentsB[3] *= parent.scaleY; - } - } - - if(destSpace == TransformSpace.Local) - { - // Destination space is in parent transform coordinates. - // Recompose the parent local transform and get it in world, then decompose the world for interpolation. - if(grandParent != null) - { - Mat2D.compose(transformB, _componentsB); - Mat2D.multiply(transformB, grandParent.worldTransform, transformB); - Mat2D.decompose(transformB, _componentsB); - } - } - } - - bool clampLocal = (minMaxSpace == TransformSpace.Local && grandParent != null); - if(clampLocal) - { - // Apply min max in local space, so transform to local coordinates first. - Mat2D.compose(transformB, _componentsB); - Mat2D inverse = new Mat2D(); - Mat2D.invert(inverse, grandParent.worldTransform); - Mat2D.multiply(transformB, inverse, transformB); - Mat2D.decompose(transformB, _componentsB); - } - if(this.enableMaxX && _componentsB[2] > this.maxX) - { - _componentsB[2] = this.maxX; - } - if(this.enableMinX && _componentsB[2] < this.minX) - { - _componentsB[2] = this.minX; - } - if(this.enableMaxY && _componentsB[3] > this.maxY) - { - _componentsB[3] = this.maxY; - } - if(this.enableMinY && _componentsB[3] < this.minY) - { - _componentsB[3] = this.minY; - } - if(clampLocal) - { - // Transform back to world. - Mat2D.compose(transformB, _componentsB); - Mat2D.multiply(transformB, grandParent.worldTransform, transformB); - Mat2D.decompose(transformB, _componentsB); - } - - double ti = 1.0 - this.strength; - - _componentsB[4] = _componentsA[4]; - _componentsB[0] = _componentsA[0]; - _componentsB[1] = _componentsA[1]; - _componentsB[2] = _componentsA[2] * ti + _componentsB[2] * this.strength; - _componentsB[3] = _componentsA[3] * ti + _componentsB[3] * this.strength; - _componentsB[5] = _componentsA[5]; - - Mat2D.compose(parent.worldTransform, _componentsB); - } - - @override - void update(int dirt) {} - @override - void completeResolve() {} + } + + if (!this.copyY) { + _componentsB[3] = + this.destSpace == TransformSpace.Local ? 0.0 : _componentsA[3]; + } + else { + _componentsB[3] *= this.scaleY; + + if (this.offset) { + _componentsB[3] *= parent.scaleY; + } + } + + if (destSpace == TransformSpace.Local) { + // Destination space is in parent transform coordinates. + // Recompose the parent local transform and get it in world, then decompose the world for interpolation. + if (grandParent != null) { + Mat2D.compose(transformB, _componentsB); + Mat2D.multiply(transformB, grandParent.worldTransform, transformB); + Mat2D.decompose(transformB, _componentsB); + } + } + } + + bool clampLocal = (minMaxSpace == TransformSpace.Local && + grandParent != null); + if (clampLocal) { + // Apply min max in local space, so transform to local coordinates first. + Mat2D.compose(transformB, _componentsB); + Mat2D inverse = new Mat2D(); + Mat2D.invert(inverse, grandParent.worldTransform); + Mat2D.multiply(transformB, inverse, transformB); + Mat2D.decompose(transformB, _componentsB); + } + if (this.enableMaxX && _componentsB[2] > this.maxX) { + _componentsB[2] = this.maxX; + } + if (this.enableMinX && _componentsB[2] < this.minX) { + _componentsB[2] = this.minX; + } + if (this.enableMaxY && _componentsB[3] > this.maxY) { + _componentsB[3] = this.maxY; + } + if (this.enableMinY && _componentsB[3] < this.minY) { + _componentsB[3] = this.minY; + } + if (clampLocal) { + // Transform back to world. + Mat2D.compose(transformB, _componentsB); + Mat2D.multiply(transformB, grandParent.worldTransform, transformB); + Mat2D.decompose(transformB, _componentsB); + } + + double ti = 1.0 - this.strength; + + _componentsB[4] = _componentsA[4]; + _componentsB[0] = _componentsA[0]; + _componentsB[1] = _componentsA[1]; + _componentsB[2] = _componentsA[2] * ti + _componentsB[2] * this.strength; + _componentsB[3] = _componentsA[3] * ti + _componentsB[3] * this.strength; + _componentsB[5] = _componentsA[5]; + + Mat2D.compose(parent.worldTransform, _componentsB); + } + + @override + void update(int dirt) {} + + @override + void completeResolve() {} } \ No newline at end of file diff --git a/lib/flare/actor_shape.dart b/lib/flare/actor_shape.dart index 067c9a5..8a389af 100644 --- a/lib/flare/actor_shape.dart +++ b/lib/flare/actor_shape.dart @@ -10,213 +10,179 @@ import "math/mat2d.dart"; import "math/vec2d.dart"; import "math/aabb.dart"; -class ActorShape extends ActorNode implements ActorDrawable -{ - @override - int drawIndex; - - int _drawOrder; - @override - int get drawOrder => _drawOrder; - - set drawOrder(int value) - { - if(_drawOrder == value) - { - return; - } - _drawOrder = value; - artboard.markDrawOrderDirty(); - } - - bool _isHidden; - List _strokes; - - bool get isHidden - { - return _isHidden; - } - - bool get doesDraw - { - return !_isHidden && !this.renderCollapsed; - } - - void update(int dirt) - { - super.update(dirt); - invalidateShape(); - } - - static ActorShape read(ActorArtboard artboard, StreamReader reader, ActorShape component) - { - if(component == null) - { - component = new ActorShape(); - } - - ActorNode.read(artboard, reader, component); - - component._isHidden = !reader.readBool("isVisible"); - /*blendMode*/ reader.readUint8("blendMode"); - component.drawOrder = reader.readUint16("drawOrder"); - return component; - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorShape instanceEvent = new ActorShape(); - instanceEvent.copyShape(this, resetArtboard); - return instanceEvent; - } - - void copyShape(ActorShape node, ActorArtboard resetArtboard) - { - copyNode(node, resetArtboard); - drawOrder = node.drawOrder; - _isHidden = node._isHidden; - } - - AABB computeAABB() - { - AABB aabb; - List clippers = allClips; - if(clippers != null) - { - for(ActorClip clip in clippers) - { - clip.node.all((ActorNode node) - { - if(node is ActorShape) - { - AABB bounds = node.computeAABB(); - if(bounds == null) - { - return; - } - if(aabb == null) - { - aabb = bounds; - } - else - { - if(bounds[0] < aabb[0]) - { - aabb[0] = bounds[0]; - } - if(bounds[1] < aabb[1]) - { - aabb[1] = bounds[1]; - } - if(bounds[2] > aabb[2]) - { - aabb[2] = bounds[2]; - } - if(bounds[3] > aabb[3]) - { - aabb[3] = bounds[3]; - } - } - } - }); - } - if(aabb != null) - { - //print("AA $aabb"); - return aabb; - } - } - - for(ActorNode node in children) - { - ActorBasePath path = node as ActorBasePath; - if(path == null) - { - continue; - } - // This is the axis aligned bounding box in the space of the parent (this case our shape). - AABB pathAABB = path.getPathAABB(); - - if(aabb == null) - { - aabb = pathAABB; - } - else - { - // Combine. - aabb[0] = min(aabb[0], pathAABB[0]); - aabb[1] = min(aabb[1], pathAABB[1]); - - aabb[2] = max(aabb[2], pathAABB[2]); - aabb[3] = max(aabb[3], pathAABB[3]); - } - } - - double minX = double.maxFinite; - double minY = double.maxFinite; - double maxX = -double.maxFinite; - double maxY = -double.maxFinite; - - if(aabb == null) - { - return new AABB.fromValues(minX, minY, maxX, maxY); - } - Mat2D world = worldTransform; - - if(_strokes != null) - { - double maxStroke = 0; - for(ActorStroke stroke in _strokes) - { - if(stroke.width > maxStroke) - { - maxStroke = stroke.width; - } - } - double padStroke = maxStroke/2.0; - aabb[0] -= padStroke; - aabb[2] += padStroke; - aabb[1] -= padStroke; - aabb[3] += padStroke; - } - - List points = [ - new Vec2D.fromValues(aabb[0], aabb[1]), - new Vec2D.fromValues(aabb[2], aabb[1]), - new Vec2D.fromValues(aabb[2], aabb[3]), - new Vec2D.fromValues(aabb[0], aabb[3]) - ]; - for(var i = 0; i < points.length; i++) - { - Vec2D pt = points[i]; - Vec2D wp = Vec2D.transformMat2D(pt, pt, world); - if(wp[0] < minX) - { - minX = wp[0]; - } - if(wp[1] < minY) - { - minY = wp[1]; - } - - if(wp[0] > maxX) - { - maxX = wp[0]; - } - if(wp[1] > maxY) - { - maxY = wp[1]; - } - } - return new AABB.fromValues(minX, minY, maxX, maxY); - } - - void addStroke(ActorStroke stroke) - { - if(_strokes == null) - { - _strokes = new List(); - } - _strokes.add(stroke); - } +class ActorShape extends ActorNode + implements ActorDrawable { + @override + int drawIndex; + + int _drawOrder; + + @override + int get drawOrder => _drawOrder; + + set drawOrder(int value) { + if (_drawOrder == value) { + return; + } + _drawOrder = value; + artboard.markDrawOrderDirty(); + } + + bool _isHidden; + List _strokes; + + bool get isHidden { + return _isHidden; + } + + bool get doesDraw { + return !_isHidden && !this.renderCollapsed; + } + + void update(int dirt) { + super.update(dirt); + invalidateShape(); + } + + static ActorShape read(ActorArtboard artboard, StreamReader reader, + ActorShape component) { + if (component == null) { + component = new ActorShape(); + } + + ActorNode.read(artboard, reader, component); + + component._isHidden = !reader.readBool("isVisible"); + /*blendMode*/ + reader.readUint8("blendMode"); + component.drawOrder = reader.readUint16("drawOrder"); + return component; + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorShape instanceEvent = new ActorShape(); + instanceEvent.copyShape(this, resetArtboard); + return instanceEvent; + } + + void copyShape(ActorShape node, ActorArtboard resetArtboard) { + copyNode(node, resetArtboard); + drawOrder = node.drawOrder; + _isHidden = node._isHidden; + } + + AABB computeAABB() { + AABB aabb; + List clippers = allClips; + if (clippers != null) { + for (ActorClip clip in clippers) { + clip.node.all((ActorNode node) { + if (node is ActorShape) { + AABB bounds = node.computeAABB(); + if (bounds == null) { + return; + } + if (aabb == null) { + aabb = bounds; + } + else { + if (bounds[0] < aabb[0]) { + aabb[0] = bounds[0]; + } + if (bounds[1] < aabb[1]) { + aabb[1] = bounds[1]; + } + if (bounds[2] > aabb[2]) { + aabb[2] = bounds[2]; + } + if (bounds[3] > aabb[3]) { + aabb[3] = bounds[3]; + } + } + } + }); + } + if (aabb != null) { + //print("AA $aabb"); + return aabb; + } + } + + for (ActorNode node in children) { + ActorBasePath path = node as ActorBasePath; + if (path == null) { + continue; + } + // This is the axis aligned bounding box in the space of the parent (this case our shape). + AABB pathAABB = path.getPathAABB(); + + if (aabb == null) { + aabb = pathAABB; + } + else { + // Combine. + aabb[0] = min(aabb[0], pathAABB[0]); + aabb[1] = min(aabb[1], pathAABB[1]); + + aabb[2] = max(aabb[2], pathAABB[2]); + aabb[3] = max(aabb[3], pathAABB[3]); + } + } + + double minX = double.maxFinite; + double minY = double.maxFinite; + double maxX = -double.maxFinite; + double maxY = -double.maxFinite; + + if (aabb == null) { + return new AABB.fromValues(minX, minY, maxX, maxY); + } + Mat2D world = worldTransform; + + if (_strokes != null) { + double maxStroke = 0; + for (ActorStroke stroke in _strokes) { + if (stroke.width > maxStroke) { + maxStroke = stroke.width; + } + } + double padStroke = maxStroke / 2.0; + aabb[0] -= padStroke; + aabb[2] += padStroke; + aabb[1] -= padStroke; + aabb[3] += padStroke; + } + + List points = [ + new Vec2D.fromValues(aabb[0], aabb[1]), + new Vec2D.fromValues(aabb[2], aabb[1]), + new Vec2D.fromValues(aabb[2], aabb[3]), + new Vec2D.fromValues(aabb[0], aabb[3]) + ]; + for (var i = 0; i < points.length; i++) { + Vec2D pt = points[i]; + Vec2D wp = Vec2D.transformMat2D(pt, pt, world); + if (wp[0] < minX) { + minX = wp[0]; + } + if (wp[1] < minY) { + minY = wp[1]; + } + + if (wp[0] > maxX) { + maxX = wp[0]; + } + if (wp[1] > maxY) { + maxY = wp[1]; + } + } + return new AABB.fromValues(minX, minY, maxX, maxY); + } + + void addStroke(ActorStroke stroke) { + if (_strokes == null) { + _strokes = new List(); + } + _strokes.add(stroke); + } } diff --git a/lib/flare/actor_skin.dart b/lib/flare/actor_skin.dart index 160d4f3..bde4af2 100644 --- a/lib/flare/actor_skin.dart +++ b/lib/flare/actor_skin.dart @@ -6,107 +6,93 @@ import "actor_component.dart"; import "math/mat2d.dart"; import "actor_constraint.dart"; -class ActorSkin extends ActorComponent -{ - Float32List _boneMatrices; - Float32List get boneMatrices => _boneMatrices; +class ActorSkin extends ActorComponent { + Float32List _boneMatrices; - @override - void onDirty(int dirt) - { - // Intentionally empty. Doesn't throw dirt around. - } + Float32List get boneMatrices => _boneMatrices; - @override - void update(int dirt) - { - ActorPath path = parent as ActorPath; - if(path == null) - { - return; - } + @override + void onDirty(int dirt) { + // Intentionally empty. Doesn't throw dirt around. + } - if(path.isConnectedToBones) - { - List connectedBones = path.connectedBones; - int length = (connectedBones.length+1) * 6; - if(_boneMatrices == null || _boneMatrices.length != length) - { - _boneMatrices = new Float32List(length); - // First bone transform is always identity. - _boneMatrices[0] = 1; - _boneMatrices[1] = 0; - _boneMatrices[2] = 0; - _boneMatrices[3] = 1; - _boneMatrices[4] = 0; - _boneMatrices[5] = 0; - } + @override + void update(int dirt) { + ActorPath path = parent as ActorPath; + if (path == null) { + return; + } - int bidx = 6; // Start after first identity. + if (path.isConnectedToBones) { + List connectedBones = path.connectedBones; + int length = (connectedBones.length + 1) * 6; + if (_boneMatrices == null || _boneMatrices.length != length) { + _boneMatrices = new Float32List(length); + // First bone transform is always identity. + _boneMatrices[0] = 1; + _boneMatrices[1] = 0; + _boneMatrices[2] = 0; + _boneMatrices[3] = 1; + _boneMatrices[4] = 0; + _boneMatrices[5] = 0; + } - Mat2D mat = new Mat2D(); + int bidx = 6; // Start after first identity. - for(SkinnedBone cb in connectedBones) - { - if(cb.node == null) - { - _boneMatrices[bidx++] = 1; - _boneMatrices[bidx++] = 0; - _boneMatrices[bidx++] = 0; - _boneMatrices[bidx++] = 1; - _boneMatrices[bidx++] = 0; - _boneMatrices[bidx++] = 0; - continue; - } + Mat2D mat = new Mat2D(); - Mat2D.multiply(mat, cb.node.worldTransform, cb.inverseBind); + for (SkinnedBone cb in connectedBones) { + if (cb.node == null) { + _boneMatrices[bidx++] = 1; + _boneMatrices[bidx++] = 0; + _boneMatrices[bidx++] = 0; + _boneMatrices[bidx++] = 1; + _boneMatrices[bidx++] = 0; + _boneMatrices[bidx++] = 0; + continue; + } - _boneMatrices[bidx++] = mat[0]; - _boneMatrices[bidx++] = mat[1]; - _boneMatrices[bidx++] = mat[2]; - _boneMatrices[bidx++] = mat[3]; - _boneMatrices[bidx++] = mat[4]; - _boneMatrices[bidx++] = mat[5]; - } - } + Mat2D.multiply(mat, cb.node.worldTransform, cb.inverseBind); - path.markPathDirty(); - } + _boneMatrices[bidx++] = mat[0]; + _boneMatrices[bidx++] = mat[1]; + _boneMatrices[bidx++] = mat[2]; + _boneMatrices[bidx++] = mat[3]; + _boneMatrices[bidx++] = mat[4]; + _boneMatrices[bidx++] = mat[5]; + } + } - @override - void completeResolve() - { - ActorPath path = parent as ActorPath; - if(path == null) - { - return; - } - path.skin = this; - artboard.addDependency(this, path); - if(path.isConnectedToBones) - { - List connectedBones = path.connectedBones; - for(SkinnedBone skinnedBone in connectedBones) - { - artboard.addDependency(this, skinnedBone.node); - List constraints = skinnedBone.node.allConstraints; - - if(constraints != null) - { - for(ActorConstraint constraint in constraints) - { - artboard.addDependency(this, constraint); - } - } - } - } - } + path.markPathDirty(); + } - @override - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorSkin instance = new ActorSkin(); - instance.copyComponent(this, resetArtboard); - return instance; - } + @override + void completeResolve() { + ActorPath path = parent as ActorPath; + if (path == null) { + return; + } + path.skin = this; + artboard.addDependency(this, path); + if (path.isConnectedToBones) { + List connectedBones = path.connectedBones; + for (SkinnedBone skinnedBone in connectedBones) { + artboard.addDependency(this, skinnedBone.node); + List constraints = skinnedBone.node.allConstraints; + + if (constraints != null) { + for (ActorConstraint constraint in constraints) { + artboard.addDependency(this, constraint); + } + } + } + } + } + + @override + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorSkin instance = new ActorSkin(); + instance.copyComponent(this, resetArtboard); + return instance; + } } \ No newline at end of file diff --git a/lib/flare/actor_skinnable.dart b/lib/flare/actor_skinnable.dart index 6a0bb24..59b3714 100644 --- a/lib/flare/actor_skinnable.dart +++ b/lib/flare/actor_skinnable.dart @@ -4,83 +4,75 @@ import "math/mat2d.dart"; import "actor_node.dart"; import "actor_component.dart"; -class SkinnedBone -{ - int boneIdx; - ActorNode node; - Mat2D bind = new Mat2D(); - Mat2D inverseBind = new Mat2D(); +class SkinnedBone { + int boneIdx; + ActorNode node; + Mat2D bind = new Mat2D(); + Mat2D inverseBind = new Mat2D(); } -abstract class ActorSkinnable extends ActorNode -{ - List _connectedBones; +abstract class ActorSkinnable extends ActorNode { + List _connectedBones; - List get connectedBones => _connectedBones; - bool get isConnectedToBones => _connectedBones != null && _connectedBones.length > 0; + List get connectedBones => _connectedBones; - static ActorSkinnable read(ActorArtboard artboard, StreamReader reader, ActorSkinnable node) - { - ActorNode.read(artboard, reader, node); + bool get isConnectedToBones => + _connectedBones != null && _connectedBones.length > 0; - reader.openArray("bones"); - int numConnectedBones = reader.readUint8Length(); - if(numConnectedBones != 0) - { - node._connectedBones = new List(numConnectedBones); + static ActorSkinnable read(ActorArtboard artboard, StreamReader reader, + ActorSkinnable node) { + ActorNode.read(artboard, reader, node); - for(int i = 0; i < numConnectedBones; i++) - { - SkinnedBone bc = new SkinnedBone(); - reader.openObject("bone"); - bc.boneIdx = reader.readId("component"); - reader.readFloat32ArrayOffset(bc.bind.values, 6, 0, "bind"); - reader.closeObject(); - Mat2D.invert(bc.inverseBind, bc.bind); - node._connectedBones[i] = bc; - } - reader.closeArray(); - Mat2D worldOverride = new Mat2D(); - reader.readFloat32ArrayOffset(worldOverride.values, 6, 0, "worldTransform"); - node.worldTransformOverride = worldOverride; - } - else - { - reader.closeArray(); - } + reader.openArray("bones"); + int numConnectedBones = reader.readUint8Length(); + if (numConnectedBones != 0) { + node._connectedBones = new List(numConnectedBones); - return node; - } + for (int i = 0; i < numConnectedBones; i++) { + SkinnedBone bc = new SkinnedBone(); + reader.openObject("bone"); + bc.boneIdx = reader.readId("component"); + reader.readFloat32ArrayOffset(bc.bind.values, 6, 0, "bind"); + reader.closeObject(); + Mat2D.invert(bc.inverseBind, bc.bind); + node._connectedBones[i] = bc; + } + reader.closeArray(); + Mat2D worldOverride = new Mat2D(); + reader.readFloat32ArrayOffset( + worldOverride.values, 6, 0, "worldTransform"); + node.worldTransformOverride = worldOverride; + } + else { + reader.closeArray(); + } - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - if(_connectedBones != null) - { - for(int i = 0; i < _connectedBones.length; i++) - { - SkinnedBone bc = _connectedBones[i]; - bc.node = components[bc.boneIdx] as ActorNode; - } - } - } + return node; + } - void copySkinnable(ActorSkinnable node, ActorArtboard resetArtboard) - { - copyNode(node, resetArtboard); + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + if (_connectedBones != null) { + for (int i = 0; i < _connectedBones.length; i++) { + SkinnedBone bc = _connectedBones[i]; + bc.node = components[bc.boneIdx] as ActorNode; + } + } + } - if(node._connectedBones != null) - { - _connectedBones = new List(node._connectedBones.length); - for(int i = 0; i < node._connectedBones.length; i++) - { - SkinnedBone from = node._connectedBones[i]; - SkinnedBone bc = new SkinnedBone(); - bc.boneIdx = from.boneIdx; - Mat2D.copy(bc.bind, from.bind); - Mat2D.copy(bc.inverseBind, from.inverseBind); - _connectedBones[i] = bc; - } - } - } + void copySkinnable(ActorSkinnable node, ActorArtboard resetArtboard) { + copyNode(node, resetArtboard); + + if (node._connectedBones != null) { + _connectedBones = new List(node._connectedBones.length); + for (int i = 0; i < node._connectedBones.length; i++) { + SkinnedBone from = node._connectedBones[i]; + SkinnedBone bc = new SkinnedBone(); + bc.boneIdx = from.boneIdx; + Mat2D.copy(bc.bind, from.bind); + Mat2D.copy(bc.inverseBind, from.inverseBind); + _connectedBones[i] = bc; + } + } + } } \ No newline at end of file diff --git a/lib/flare/actor_star.dart b/lib/flare/actor_star.dart index 332e6a7..5834725 100644 --- a/lib/flare/actor_star.dart +++ b/lib/flare/actor_star.dart @@ -7,90 +7,86 @@ import "actor_path.dart"; import "path_point.dart"; import "actor_component.dart"; -class ActorStar extends ActorProceduralPath -{ - int _numPoints = 5; - double _innerRadius = 0.0; - - @override - void invalidatePath() - { - } - - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorStar instance = new ActorStar(); - instance.copyStar(this, resetArtboard); - return instance; - } +class ActorStar extends ActorProceduralPath { + int _numPoints = 5; + double _innerRadius = 0.0; - void copyStar(ActorStar node, ActorArtboard resetArtboard) - { - copyPath(node, resetArtboard); - _numPoints = node._numPoints; - _innerRadius = node._innerRadius; - } + @override + void invalidatePath() { + } - static ActorStar read(ActorArtboard artboard, StreamReader reader, ActorStar component) - { - if(component == null) - { - component = new ActorStar(); - } - ActorNode.read(artboard, reader, component); + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorStar instance = new ActorStar(); + instance.copyStar(this, resetArtboard); + return instance; + } - component.width = reader.readFloat32("width"); - component.height = reader.readFloat32("height"); - component._numPoints = reader.readUint32("points"); - component._innerRadius = reader.readFloat32("innerRadius"); - return component; + void copyStar(ActorStar node, ActorArtboard resetArtboard) { + copyPath(node, resetArtboard); + _numPoints = node._numPoints; + _innerRadius = node._innerRadius; + } + + static ActorStar read(ActorArtboard artboard, StreamReader reader, + ActorStar component) { + if (component == null) { + component = new ActorStar(); } - @override - List get points - { - List _starPoints = [ - new StraightPathPoint.fromTranslation(Vec2D.fromValues(0.0, -radiusY)) - ]; - - double angle = pi/2.0; - double inc = (pi*2.0)/sides; - Vec2D sx = Vec2D.fromValues(radiusX, radiusX*_innerRadius); - Vec2D sy = Vec2D.fromValues(radiusY, radiusY*_innerRadius); - - for(int i = 0; i < sides; i++) - { - _starPoints.add( - new StraightPathPoint.fromTranslation( - Vec2D.fromValues( - cos(angle)*sx[i%2], - sin(angle)*sy[i%2] - ) - ) - ); - angle += inc; - } - return _starPoints; + ActorNode.read(artboard, reader, component); + + component.width = reader.readFloat32("width"); + component.height = reader.readFloat32("height"); + component._numPoints = reader.readUint32("points"); + component._innerRadius = reader.readFloat32("innerRadius"); + return component; + } + + @override + List get points { + List _starPoints = [ + new StraightPathPoint.fromTranslation(Vec2D.fromValues(0.0, -radiusY)) + ]; + + double angle = pi / 2.0; + double inc = (pi * 2.0) / sides; + Vec2D sx = Vec2D.fromValues(radiusX, radiusX * _innerRadius); + Vec2D sy = Vec2D.fromValues(radiusY, radiusY * _innerRadius); + + for (int i = 0; i < sides; i++) { + _starPoints.add( + new StraightPathPoint.fromTranslation( + Vec2D.fromValues( + cos(angle) * sx[i % 2], + sin(angle) * sy[i % 2] + ) + ) + ); + angle += inc; } - - - set innerRadius(double val) - { - if(val != _innerRadius) - { - _innerRadius = val; - markPathDirty(); - } + return _starPoints; + } + + + set innerRadius(double val) { + if (val != _innerRadius) { + _innerRadius = val; + markPathDirty(); } + } + + get innerRadius => _innerRadius; + + bool get isClosed => true; + + bool get doesDraw => !this.renderCollapsed; + + double get radiusX => this.width / 2; + + double get radiusY => this.height / 2; - get innerRadius => _innerRadius; + int get numPoints => _numPoints; - bool get isClosed => true; - bool get doesDraw => !this.renderCollapsed; - double get radiusX => this.width/2; - double get radiusY => this.height/2; - int get numPoints => _numPoints; - int get sides => _numPoints*2; + int get sides => _numPoints * 2; } \ No newline at end of file diff --git a/lib/flare/actor_targeted_constraint.dart b/lib/flare/actor_targeted_constraint.dart index 4e2ac5f..cbfc9fb 100644 --- a/lib/flare/actor_targeted_constraint.dart +++ b/lib/flare/actor_targeted_constraint.dart @@ -3,41 +3,36 @@ import "actor_constraint.dart"; import "actor_artboard.dart"; import "stream_reader.dart"; -abstract class ActorTargetedConstraint extends ActorConstraint -{ - int _targetIdx; - ActorComponent _target; +abstract class ActorTargetedConstraint extends ActorConstraint { + int _targetIdx; + ActorComponent _target; - ActorComponent get target - { - return _target; - } + ActorComponent get target { + return _target; + } - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - if(_targetIdx != 0) - { - _target = components[_targetIdx]; - if(_target != null) - { - artboard.addDependency(parent, _target); - } - } - } + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + if (_targetIdx != 0) { + _target = components[_targetIdx]; + if (_target != null) { + artboard.addDependency(parent, _target); + } + } + } - static ActorTargetedConstraint read(ActorArtboard artboard, StreamReader reader, ActorTargetedConstraint component) - { - ActorConstraint.read(artboard, reader, component); - component._targetIdx = reader.readId("target"); + static ActorTargetedConstraint read(ActorArtboard artboard, + StreamReader reader, ActorTargetedConstraint component) { + ActorConstraint.read(artboard, reader, component); + component._targetIdx = reader.readId("target"); - return component; - } + return component; + } - void copyTargetedConstraint(ActorTargetedConstraint node, ActorArtboard resetArtboard) - { - copyConstraint(node, resetArtboard); + void copyTargetedConstraint(ActorTargetedConstraint node, + ActorArtboard resetArtboard) { + copyConstraint(node, resetArtboard); - _targetIdx = node._targetIdx; - } + _targetIdx = node._targetIdx; + } } \ No newline at end of file diff --git a/lib/flare/actor_transform_constraint.dart b/lib/flare/actor_transform_constraint.dart index cef957c..75d8ca3 100644 --- a/lib/flare/actor_transform_constraint.dart +++ b/lib/flare/actor_transform_constraint.dart @@ -7,106 +7,96 @@ import "math/transform_components.dart"; import "transform_space.dart"; import "stream_reader.dart"; -const pi2 = pi*2; +const pi2 = pi * 2; -class ActorTransformConstraint extends ActorTargetedConstraint -{ - int _sourceSpace = TransformSpace.World; - int _destSpace = TransformSpace.World; - TransformComponents _componentsA = new TransformComponents(); - TransformComponents _componentsB = new TransformComponents(); +class ActorTransformConstraint extends ActorTargetedConstraint { + int _sourceSpace = TransformSpace.World; + int _destSpace = TransformSpace.World; + TransformComponents _componentsA = new TransformComponents(); + TransformComponents _componentsB = new TransformComponents(); - ActorTransformConstraint() : super(); + ActorTransformConstraint() : super(); - static ActorTransformConstraint read(ActorArtboard artboard, StreamReader reader, ActorTransformConstraint component) - { - if(component == null) - { - component = new ActorTransformConstraint(); - } - ActorTargetedConstraint.read(artboard, reader, component); - - component._sourceSpace = reader.readUint8("sourceSpaceId"); - component._destSpace = reader.readUint8("destSpaceId"); - - return component; + static ActorTransformConstraint read(ActorArtboard artboard, + StreamReader reader, ActorTransformConstraint component) { + if (component == null) { + component = new ActorTransformConstraint(); } - - @override - makeInstance(ActorArtboard resetArtboard) - { - ActorTransformConstraint node = new ActorTransformConstraint(); - node.copyTransformConstraint(this, resetArtboard); - return node; + ActorTargetedConstraint.read(artboard, reader, component); + + component._sourceSpace = reader.readUint8("sourceSpaceId"); + component._destSpace = reader.readUint8("destSpaceId"); + + return component; + } + + @override + makeInstance(ActorArtboard resetArtboard) { + ActorTransformConstraint node = new ActorTransformConstraint(); + node.copyTransformConstraint(this, resetArtboard); + return node; + } + + copyTransformConstraint(ActorTransformConstraint node, + ActorArtboard resetArtboard) { + copyTargetedConstraint(node, resetArtboard); + _sourceSpace = node._sourceSpace; + _destSpace = node._destSpace; + } + + @override + constrain(ActorNode node) { + ActorNode t = this.target; + if (t == null) { + return; } - copyTransformConstraint(ActorTransformConstraint node, ActorArtboard resetArtboard) - { - copyTargetedConstraint(node, resetArtboard); - _sourceSpace = node._sourceSpace; - _destSpace = node._destSpace; + ActorNode parent = this.parent; + + Mat2D transformA = parent.worldTransform; + Mat2D transformB = Mat2D.clone(t.worldTransform); + if (_sourceSpace == TransformSpace.Local) { + ActorNode grandParent = target.parent; + if (grandParent != null) { + Mat2D inverse = new Mat2D(); + Mat2D.invert(inverse, grandParent.worldTransform); + Mat2D.multiply(transformB, inverse, transformB); + } + } + if (_destSpace == TransformSpace.Local) { + ActorNode grandParent = parent.parent; + if (grandParent != null) { + Mat2D.multiply(transformB, grandParent.worldTransform, transformB); + } + } + Mat2D.decompose(transformA, _componentsA); + Mat2D.decompose(transformB, _componentsB); + + double angleA = _componentsA[4] % pi2; + double angleB = _componentsB[4] % pi2; + double diff = angleB - angleA; + if (diff > pi) { + diff -= pi2; } + else if (diff < -pi) { + diff += pi2; + } + + double ti = 1.0 - this.strength; + + _componentsB[4] = angleA + diff * this.strength; + _componentsB[0] = _componentsA[0] * ti + _componentsB[0] * this.strength; + _componentsB[1] = _componentsA[1] * ti + _componentsB[1] * this.strength; + _componentsB[2] = _componentsA[2] * ti + _componentsB[2] * this.strength; + _componentsB[3] = _componentsA[3] * ti + _componentsB[3] * this.strength; + _componentsB[5] = _componentsA[5] * ti + _componentsB[5] * this.strength; + + Mat2D.compose(parent.worldTransform, _componentsB); + } + + @override + void update(int dirt) {} - @override - constrain(ActorNode node) - { - ActorNode t = this.target; - if(t == null) - { - return; - } - - ActorNode parent = this.parent; - - Mat2D transformA = parent.worldTransform; - Mat2D transformB = Mat2D.clone(t.worldTransform); - if(_sourceSpace == TransformSpace.Local) - { - ActorNode grandParent = target.parent; - if(grandParent != null) - { - Mat2D inverse = new Mat2D(); - Mat2D.invert(inverse, grandParent.worldTransform); - Mat2D.multiply(transformB, inverse, transformB); - } - } - if(_destSpace == TransformSpace.Local) - { - ActorNode grandParent = parent.parent; - if(grandParent != null) - { - Mat2D.multiply(transformB, grandParent.worldTransform, transformB); - } - } - Mat2D.decompose(transformA, _componentsA); - Mat2D.decompose(transformB, _componentsB); - - double angleA = _componentsA[4]%pi2; - double angleB = _componentsB[4]%pi2; - double diff = angleB - angleA; - if(diff > pi) - { - diff -= pi2; - } - else if(diff < -pi) - { - diff += pi2; - } - - double ti = 1.0 - this.strength; - - _componentsB[4] = angleA + diff * this.strength; - _componentsB[0] = _componentsA[0] * ti + _componentsB[0] * this.strength; - _componentsB[1] = _componentsA[1] * ti + _componentsB[1] * this.strength; - _componentsB[2] = _componentsA[2] * ti + _componentsB[2] * this.strength; - _componentsB[3] = _componentsA[3] * ti + _componentsB[3] * this.strength; - _componentsB[5] = _componentsA[5] * ti + _componentsB[5] * this.strength; - - Mat2D.compose(parent.worldTransform, _componentsB); - } - - @override - void update(int dirt) {} - @override - void completeResolve() {} + @override + void completeResolve() {} } \ No newline at end of file diff --git a/lib/flare/actor_translation_constraint.dart b/lib/flare/actor_translation_constraint.dart index 0c3f595..7318d1c 100644 --- a/lib/flare/actor_translation_constraint.dart +++ b/lib/flare/actor_translation_constraint.dart @@ -6,135 +6,119 @@ import "math/mat2d.dart"; import "transform_space.dart"; import "stream_reader.dart"; -class ActorTranslationConstraint extends ActorAxisConstraint -{ - ActorTranslationConstraint() : super(); +class ActorTranslationConstraint extends ActorAxisConstraint { + ActorTranslationConstraint() : super(); - static ActorTranslationConstraint read(ActorArtboard artboard, StreamReader reader, ActorTranslationConstraint component) - { - if(component == null) - { - component = new ActorTranslationConstraint(); - } - ActorAxisConstraint.read(artboard, reader, component); - - return component; + static ActorTranslationConstraint read(ActorArtboard artboard, + StreamReader reader, ActorTranslationConstraint component) { + if (component == null) { + component = new ActorTranslationConstraint(); } + ActorAxisConstraint.read(artboard, reader, component); - @override - makeInstance(ActorArtboard resetArtboard) - { - ActorTranslationConstraint node = new ActorTranslationConstraint(); - node.copyAxisConstraint(this, resetArtboard); - return node; - } + return component; + } - @override - constrain(ActorNode node) - { - ActorNode t = this.target; - ActorNode p = this.parent; - ActorNode grandParent = p.parent; + @override + makeInstance(ActorArtboard resetArtboard) { + ActorTranslationConstraint node = new ActorTranslationConstraint(); + node.copyAxisConstraint(this, resetArtboard); + return node; + } - Mat2D transformA = parent.worldTransform; - Vec2D translationA = new Vec2D.fromValues(transformA[4], transformA[5]); - Vec2D translationB = new Vec2D(); - - if(t == null) - { - Vec2D.copy(translationB, translationA); - } - else - { - Mat2D transformB = new Mat2D.clone(t.worldTransform); - if(this.sourceSpace == TransformSpace.Local) - { - ActorNode sourceGrandParent = t.parent; - if(sourceGrandParent != null) - { - Mat2D inverse = new Mat2D(); - Mat2D.invert(inverse, sourceGrandParent.worldTransform); - Mat2D.multiply(transformB, inverse, transformB); - } - } - translationB[0] = transformB[4]; - translationB[1] = transformB[5]; + @override + constrain(ActorNode node) { + ActorNode t = this.target; + ActorNode p = this.parent; + ActorNode grandParent = p.parent; - if(!this.copyX) - { - translationB[0] = destSpace == TransformSpace.Local ? 0.0 : translationA[0]; - } - else - { - translationB[0] *= this.scaleX; - if(this.offset) - { - translationB[0] += parent.translation[0]; - } - } + Mat2D transformA = parent.worldTransform; + Vec2D translationA = new Vec2D.fromValues(transformA[4], transformA[5]); + Vec2D translationB = new Vec2D(); - if(!this.copyY) - { - translationB[1] = destSpace == TransformSpace.Local ? 0.0 : translationA[1]; - } - else - { - translationB[1] *= this.scaleY; - if(this.offset) - { - translationB[1] += parent.translation[1]; - } - } + if (t == null) { + Vec2D.copy(translationB, translationA); + } + else { + Mat2D transformB = new Mat2D.clone(t.worldTransform); + if (this.sourceSpace == TransformSpace.Local) { + ActorNode sourceGrandParent = t.parent; + if (sourceGrandParent != null) { + Mat2D inverse = new Mat2D(); + Mat2D.invert(inverse, sourceGrandParent.worldTransform); + Mat2D.multiply(transformB, inverse, transformB); + } + } + translationB[0] = transformB[4]; + translationB[1] = transformB[5]; - if(destSpace == TransformSpace.Local) - { - if(grandParent != null) - { - Vec2D.transformMat2D(translationB, translationB, grandParent.worldTransform); - } - } + if (!this.copyX) { + translationB[0] = + destSpace == TransformSpace.Local ? 0.0 : translationA[0]; + } + else { + translationB[0] *= this.scaleX; + if (this.offset) { + translationB[0] += parent.translation[0]; } + } - bool clampLocal = (minMaxSpace == TransformSpace.Local && grandParent != null); - if(clampLocal) - { - // Apply min max in local space, so transform to local coordinates first. - Mat2D temp = new Mat2D(); - Mat2D.invert(temp, grandParent.worldTransform); - // Get our target world coordinates in parent local. - Vec2D.transformMat2D(translationB, translationB, temp); + if (!this.copyY) { + translationB[1] = + destSpace == TransformSpace.Local ? 0.0 : translationA[1]; + } + else { + translationB[1] *= this.scaleY; + if (this.offset) { + translationB[1] += parent.translation[1]; } - if(this.enableMaxX && translationB[0] > this.maxX) - { - translationB[0] = this.maxX; - } - if(this.enableMinX && translationB[0] < this.minX) - { - translationB[0] = this.minX; - } - if(this.enableMaxY && translationB[1] > this.maxY) - { - translationB[1] = this.maxY; - } - if(this.enableMinY && translationB[1] < this.minY) - { - translationB[1] = this.minY; - } - if(clampLocal) - { - // Transform back to world. - Vec2D.transformMat2D(translationB, translationB, grandParent.worldTransform); - } + } - double ti = 1.0 - this.strength; + if (destSpace == TransformSpace.Local) { + if (grandParent != null) { + Vec2D.transformMat2D( + translationB, translationB, grandParent.worldTransform); + } + } + } - // Just interpolate world translation - transformA[4] = translationA[0] * ti + translationB[0] * this.strength; - transformA[5] = translationA[1] * ti + translationB[1] * this.strength; + bool clampLocal = (minMaxSpace == TransformSpace.Local && + grandParent != null); + if (clampLocal) { + // Apply min max in local space, so transform to local coordinates first. + Mat2D temp = new Mat2D(); + Mat2D.invert(temp, grandParent.worldTransform); + // Get our target world coordinates in parent local. + Vec2D.transformMat2D(translationB, translationB, temp); } + if (this.enableMaxX && translationB[0] > this.maxX) { + translationB[0] = this.maxX; + } + if (this.enableMinX && translationB[0] < this.minX) { + translationB[0] = this.minX; + } + if (this.enableMaxY && translationB[1] > this.maxY) { + translationB[1] = this.maxY; + } + if (this.enableMinY && translationB[1] < this.minY) { + translationB[1] = this.minY; + } + if (clampLocal) { + // Transform back to world. + Vec2D.transformMat2D( + translationB, translationB, grandParent.worldTransform); + } + + double ti = 1.0 - this.strength; + + // Just interpolate world translation + transformA[4] = translationA[0] * ti + translationB[0] * this.strength; + transformA[5] = translationA[1] * ti + translationB[1] * this.strength; + } + + @override + void update(int dirt) {} - @override - void update(int dirt) {} - @override - void completeResolve() {} + @override + void completeResolve() {} } \ No newline at end of file diff --git a/lib/flare/actor_triangle.dart b/lib/flare/actor_triangle.dart index cfc4e06..2bd62b0 100644 --- a/lib/flare/actor_triangle.dart +++ b/lib/flare/actor_triangle.dart @@ -6,59 +6,57 @@ import "actor_path.dart"; import "path_point.dart"; import "actor_component.dart"; -class ActorTriangle extends ActorProceduralPath -{ - @override - void invalidatePath() - { - } - - ActorComponent makeInstance(ActorArtboard resetArtboard) - { - ActorTriangle instance = new ActorTriangle(); - instance.copyPath(this, resetArtboard); - return instance; +class ActorTriangle extends ActorProceduralPath { + @override + void invalidatePath() { + } + + ActorComponent makeInstance(ActorArtboard resetArtboard) { + ActorTriangle instance = new ActorTriangle(); + instance.copyPath(this, resetArtboard); + return instance; + } + + static ActorTriangle read(ActorArtboard artboard, StreamReader reader, + ActorTriangle component) { + if (component == null) { + component = new ActorTriangle(); } - static ActorTriangle read(ActorArtboard artboard, StreamReader reader, ActorTriangle component) - { - if(component == null) - { - component = new ActorTriangle(); - } + ActorNode.read(artboard, reader, component); - ActorNode.read(artboard, reader, component); + component.width = reader.readFloat32("width"); + component.height = reader.readFloat32("height"); + return component; + } - component.width = reader.readFloat32("width"); - component.height = reader.readFloat32("height"); - return component; - } + @override + List get points { + List _trianglePoints = []; + _trianglePoints.add( + new StraightPathPoint.fromTranslation( + Vec2D.fromValues(0.0, -radiusY) + ) + ); + _trianglePoints.add( + new StraightPathPoint.fromTranslation( + Vec2D.fromValues(radiusX, radiusY) + ) + ); + _trianglePoints.add( + new StraightPathPoint.fromTranslation( + Vec2D.fromValues(-radiusX, radiusY) + ) + ); - @override - List get points - { - List _trianglePoints = []; - _trianglePoints.add( - new StraightPathPoint.fromTranslation( - Vec2D.fromValues(0.0, -radiusY) - ) - ); - _trianglePoints.add( - new StraightPathPoint.fromTranslation( - Vec2D.fromValues(radiusX, radiusY) - ) - ); - _trianglePoints.add( - new StraightPathPoint.fromTranslation( - Vec2D.fromValues(-radiusX, radiusY) - ) - ); + return _trianglePoints; + } - return _trianglePoints; - } + bool get isClosed => true; + + bool get doesDraw => !this.renderCollapsed; + + double get radiusX => this.width / 2; - bool get isClosed => true; - bool get doesDraw => !this.renderCollapsed; - double get radiusX => this.width/2; - double get radiusY => this.height/2; + double get radiusY => this.height / 2; } \ No newline at end of file diff --git a/lib/flare/animation/actor_animation.dart b/lib/flare/animation/actor_animation.dart index 4c88923..bc68b81 100644 --- a/lib/flare/animation/actor_animation.dart +++ b/lib/flare/animation/actor_animation.dart @@ -7,525 +7,475 @@ import "keyframe.dart"; typedef KeyFrame KeyFrameReader(StreamReader reader, ActorComponent component); -class PropertyAnimation -{ - int _type; - List _keyFrames; - - int get propertyType - { - return _type; - } - - List get keyFrames - { - return _keyFrames; - } - - static PropertyAnimation read(StreamReader reader, ActorComponent component) - { - StreamReader propertyBlock = reader.readNextBlock(PropertyTypesMap); - if(propertyBlock == null) - { - return null; - } - PropertyAnimation propertyAnimation = new PropertyAnimation(); - int type = propertyBlock.blockType; - // Wish there were a way do to this in Dart without having to create my own hash set. - // if(!Enum.IsDefined(typeof(PropertyTypes), type)) - // { - // return null; - // } - // else - // { - propertyAnimation._type = type; - - KeyFrameReader keyFrameReader; - switch(propertyAnimation._type) - { - case PropertyTypes.PosX: - keyFrameReader = KeyFramePosX.read; - break; - case PropertyTypes.PosY: - keyFrameReader = KeyFramePosY.read; - break; - case PropertyTypes.ScaleX: - keyFrameReader = KeyFrameScaleX.read; - break; - case PropertyTypes.ScaleY: - keyFrameReader = KeyFrameScaleY.read; - break; - case PropertyTypes.Rotation: - keyFrameReader = KeyFrameRotation.read; - break; - case PropertyTypes.Opacity: - keyFrameReader = KeyFrameOpacity.read; - break; - case PropertyTypes.DrawOrder: - keyFrameReader = KeyFrameDrawOrder.read; - break; - case PropertyTypes.Length: - keyFrameReader = KeyFrameLength.read; - break; - case PropertyTypes.VertexDeform: - keyFrameReader = KeyFrameVertexDeform.read; - break; - case PropertyTypes.ConstraintStrength: - keyFrameReader = KeyFrameConstraintStrength.read; - break; - case PropertyTypes.Trigger: - keyFrameReader = KeyFrameTrigger.read; - break; - case PropertyTypes.IntProperty: - keyFrameReader = KeyFrameIntProperty.read; - break; - case PropertyTypes.FloatProperty: - keyFrameReader = KeyFrameFloatProperty.read; - break; - case PropertyTypes.StringProperty: - keyFrameReader = KeyFrameStringProperty.read; - break; - case PropertyTypes.BooleanProperty: - keyFrameReader = KeyFrameBooleanProperty.read; - break; - case PropertyTypes.CollisionEnabled: - keyFrameReader = KeyFrameCollisionEnabledProperty.read; - break; - case PropertyTypes.ActiveChildIndex: - keyFrameReader = KeyFrameActiveChild.read; - break; - case PropertyTypes.Sequence: - keyFrameReader = KeyFrameSequence.read; - break; - case PropertyTypes.PathVertices: - keyFrameReader = KeyFramePathVertices.read; - break; - case PropertyTypes.FillColor: - keyFrameReader = KeyFrameFillColor.read; - break; - case PropertyTypes.FillGradient: - keyFrameReader = KeyFrameGradient.read; - break; - case PropertyTypes.StrokeGradient: - keyFrameReader = KeyFrameGradient.read; - break; - case PropertyTypes.FillRadial: - keyFrameReader = KeyFrameRadial.read; - break; - case PropertyTypes.StrokeRadial: - keyFrameReader = KeyFrameRadial.read; - break; - case PropertyTypes.StrokeColor: - keyFrameReader = KeyFrameStrokeColor.read; - break; - case PropertyTypes.StrokeWidth: - keyFrameReader = KeyFrameStrokeWidth.read; - break; - case PropertyTypes.StrokeOpacity: - keyFrameReader = KeyFrameStrokeOpacity.read; - break; - case PropertyTypes.FillOpacity: - keyFrameReader = KeyFrameFillOpacity.read; - break; - case PropertyTypes.ShapeWidth: - keyFrameReader = KeyFrameShapeWidth.read; - break; - case PropertyTypes.ShapeHeight: - keyFrameReader = KeyFrameShapeHeight.read; - break; - case PropertyTypes.CornerRadius: - keyFrameReader = KeyFrameCornerRadius.read; - break; - case PropertyTypes.InnerRadius: - keyFrameReader = KeyFrameInnerRadius.read; - break; - } - - if(keyFrameReader == null) - { - return null; - } - - propertyBlock.openArray("frames"); - int keyFrameCount = propertyBlock.readUint16Length(); - propertyAnimation._keyFrames = new List(keyFrameCount); - KeyFrame lastKeyFrame; - for(int i = 0; i < keyFrameCount; i++) - { - propertyBlock.openObject("frame"); - KeyFrame frame = keyFrameReader(propertyBlock, component); - propertyAnimation._keyFrames[i] = frame; - if(lastKeyFrame != null) - { - lastKeyFrame.setNext(frame); - } - lastKeyFrame = frame; - propertyBlock.closeObject(); - } - propertyBlock.closeArray(); - //} - - return propertyAnimation; - } - - void apply(double time, ActorComponent component, double mix) - { - if(_keyFrames.length == 0) - { - return; - } - - int idx = 0; - // Binary find the keyframe index. - { - int mid = 0; - double element = 0.0; - int start = 0; - int end = _keyFrames.length-1; - - while (start <= end) - { - mid = ((start + end) >> 1); - element = _keyFrames[mid].time; - if (element < time) - { - start = mid + 1; - } - else if (element > time) - { - end = mid - 1; - } - else - { - start = mid; - break; - } - } - - idx = start; - } - - if(idx == 0) - { - _keyFrames[0].apply(component, mix); - } - else - { - if(idx < _keyFrames.length) - { - KeyFrame fromFrame = _keyFrames[idx-1]; - KeyFrame toFrame = _keyFrames[idx]; - if(time == toFrame.time) - { - toFrame.apply(component, mix); - } - else - { - fromFrame.applyInterpolation(component, time, toFrame, mix); - } - } - else - { - _keyFrames[idx-1].apply(component, mix); - } - } - } +class PropertyAnimation { + int _type; + List _keyFrames; + + int get propertyType { + return _type; + } + + List get keyFrames { + return _keyFrames; + } + + static PropertyAnimation read(StreamReader reader, ActorComponent component) { + StreamReader propertyBlock = reader.readNextBlock(PropertyTypesMap); + if (propertyBlock == null) { + return null; + } + PropertyAnimation propertyAnimation = new PropertyAnimation(); + int type = propertyBlock.blockType; + // Wish there were a way do to this in Dart without having to create my own hash set. + // if(!Enum.IsDefined(typeof(PropertyTypes), type)) + // { + // return null; + // } + // else + // { + propertyAnimation._type = type; + + KeyFrameReader keyFrameReader; + switch (propertyAnimation._type) { + case PropertyTypes.PosX: + keyFrameReader = KeyFramePosX.read; + break; + case PropertyTypes.PosY: + keyFrameReader = KeyFramePosY.read; + break; + case PropertyTypes.ScaleX: + keyFrameReader = KeyFrameScaleX.read; + break; + case PropertyTypes.ScaleY: + keyFrameReader = KeyFrameScaleY.read; + break; + case PropertyTypes.Rotation: + keyFrameReader = KeyFrameRotation.read; + break; + case PropertyTypes.Opacity: + keyFrameReader = KeyFrameOpacity.read; + break; + case PropertyTypes.DrawOrder: + keyFrameReader = KeyFrameDrawOrder.read; + break; + case PropertyTypes.Length: + keyFrameReader = KeyFrameLength.read; + break; + case PropertyTypes.VertexDeform: + keyFrameReader = KeyFrameVertexDeform.read; + break; + case PropertyTypes.ConstraintStrength: + keyFrameReader = KeyFrameConstraintStrength.read; + break; + case PropertyTypes.Trigger: + keyFrameReader = KeyFrameTrigger.read; + break; + case PropertyTypes.IntProperty: + keyFrameReader = KeyFrameIntProperty.read; + break; + case PropertyTypes.FloatProperty: + keyFrameReader = KeyFrameFloatProperty.read; + break; + case PropertyTypes.StringProperty: + keyFrameReader = KeyFrameStringProperty.read; + break; + case PropertyTypes.BooleanProperty: + keyFrameReader = KeyFrameBooleanProperty.read; + break; + case PropertyTypes.CollisionEnabled: + keyFrameReader = KeyFrameCollisionEnabledProperty.read; + break; + case PropertyTypes.ActiveChildIndex: + keyFrameReader = KeyFrameActiveChild.read; + break; + case PropertyTypes.Sequence: + keyFrameReader = KeyFrameSequence.read; + break; + case PropertyTypes.PathVertices: + keyFrameReader = KeyFramePathVertices.read; + break; + case PropertyTypes.FillColor: + keyFrameReader = KeyFrameFillColor.read; + break; + case PropertyTypes.FillGradient: + keyFrameReader = KeyFrameGradient.read; + break; + case PropertyTypes.StrokeGradient: + keyFrameReader = KeyFrameGradient.read; + break; + case PropertyTypes.FillRadial: + keyFrameReader = KeyFrameRadial.read; + break; + case PropertyTypes.StrokeRadial: + keyFrameReader = KeyFrameRadial.read; + break; + case PropertyTypes.StrokeColor: + keyFrameReader = KeyFrameStrokeColor.read; + break; + case PropertyTypes.StrokeWidth: + keyFrameReader = KeyFrameStrokeWidth.read; + break; + case PropertyTypes.StrokeOpacity: + keyFrameReader = KeyFrameStrokeOpacity.read; + break; + case PropertyTypes.FillOpacity: + keyFrameReader = KeyFrameFillOpacity.read; + break; + case PropertyTypes.ShapeWidth: + keyFrameReader = KeyFrameShapeWidth.read; + break; + case PropertyTypes.ShapeHeight: + keyFrameReader = KeyFrameShapeHeight.read; + break; + case PropertyTypes.CornerRadius: + keyFrameReader = KeyFrameCornerRadius.read; + break; + case PropertyTypes.InnerRadius: + keyFrameReader = KeyFrameInnerRadius.read; + break; + } + + if (keyFrameReader == null) { + return null; + } + + propertyBlock.openArray("frames"); + int keyFrameCount = propertyBlock.readUint16Length(); + propertyAnimation._keyFrames = new List(keyFrameCount); + KeyFrame lastKeyFrame; + for (int i = 0; i < keyFrameCount; i++) { + propertyBlock.openObject("frame"); + KeyFrame frame = keyFrameReader(propertyBlock, component); + propertyAnimation._keyFrames[i] = frame; + if (lastKeyFrame != null) { + lastKeyFrame.setNext(frame); + } + lastKeyFrame = frame; + propertyBlock.closeObject(); + } + propertyBlock.closeArray(); + //} + + return propertyAnimation; + } + + void apply(double time, ActorComponent component, double mix) { + if (_keyFrames.length == 0) { + return; + } + + int idx = 0; + // Binary find the keyframe index. + { + int mid = 0; + double element = 0.0; + int start = 0; + int end = _keyFrames.length - 1; + + while (start <= end) { + mid = ((start + end) >> 1); + element = _keyFrames[mid].time; + if (element < time) { + start = mid + 1; + } + else if (element > time) { + end = mid - 1; + } + else { + start = mid; + break; + } + } + + idx = start; + } + + if (idx == 0) { + _keyFrames[0].apply(component, mix); + } + else { + if (idx < _keyFrames.length) { + KeyFrame fromFrame = _keyFrames[idx - 1]; + KeyFrame toFrame = _keyFrames[idx]; + if (time == toFrame.time) { + toFrame.apply(component, mix); + } + else { + fromFrame.applyInterpolation(component, time, toFrame, mix); + } + } + else { + _keyFrames[idx - 1].apply(component, mix); + } + } + } } -class ComponentAnimation -{ - int _componentIndex; - List _properties; - - int get componentIndex - { - return _componentIndex; - } - - List get properties - { - return _properties; - } - - static ComponentAnimation read(StreamReader reader, List components) - { - reader.openObject("component"); - ComponentAnimation componentAnimation = new ComponentAnimation(); - - componentAnimation._componentIndex = reader.readId("component"); - int numProperties = reader.readUint16Length(); - componentAnimation._properties = new List(numProperties); - for(int i = 0; i < numProperties; i++) - { - componentAnimation._properties[i] = PropertyAnimation.read(reader, components[componentAnimation._componentIndex]); - } - reader.closeObject(); - - return componentAnimation; - } - - void apply(double time, List components, double mix) - { - for(PropertyAnimation propertyAnimation in _properties) - { - if(propertyAnimation != null) - { - propertyAnimation.apply(time, components[_componentIndex], mix); - } - } - } +class ComponentAnimation { + int _componentIndex; + List _properties; + + int get componentIndex { + return _componentIndex; + } + + List get properties { + return _properties; + } + + static ComponentAnimation read(StreamReader reader, + List components) { + reader.openObject("component"); + ComponentAnimation componentAnimation = new ComponentAnimation(); + + componentAnimation._componentIndex = reader.readId("component"); + int numProperties = reader.readUint16Length(); + componentAnimation._properties = new List(numProperties); + for (int i = 0; i < numProperties; i++) { + componentAnimation._properties[i] = PropertyAnimation.read( + reader, components[componentAnimation._componentIndex]); + } + reader.closeObject(); + + return componentAnimation; + } + + void apply(double time, List components, double mix) { + for (PropertyAnimation propertyAnimation in _properties) { + if (propertyAnimation != null) { + propertyAnimation.apply(time, components[_componentIndex], mix); + } + } + } } -class AnimationEventArgs -{ - String _name; - ActorComponent _component; - int _propertyType; - double _keyFrameTime; - double _elapsedTime; - - AnimationEventArgs(String name, ActorComponent component, int type, double keyframeTime, double elapsedTime) - { - _name = name; - _component = component; - _propertyType = type; - _keyFrameTime = keyframeTime; - _elapsedTime = elapsedTime; - } - - String get name - { - return _name; - } - - ActorComponent get component - { - return _component; - } - - int get propertyType - { - return _propertyType; - } - - double get keyFrameTime - { - return _keyFrameTime; - } - - double get elapsedTime - { - return _elapsedTime; - } +class AnimationEventArgs { + String _name; + ActorComponent _component; + int _propertyType; + double _keyFrameTime; + double _elapsedTime; + + AnimationEventArgs(String name, ActorComponent component, int type, + double keyframeTime, double elapsedTime) { + _name = name; + _component = component; + _propertyType = type; + _keyFrameTime = keyframeTime; + _elapsedTime = elapsedTime; + } + + String get name { + return _name; + } + + ActorComponent get component { + return _component; + } + + int get propertyType { + return _propertyType; + } + + double get keyFrameTime { + return _keyFrameTime; + } + + double get elapsedTime { + return _elapsedTime; + } } -class ActorAnimation -{ - String _name; - int _fps; - double _duration; - bool _isLooping; - List _components; - List _triggerComponents; - double start = 0.0, end = 0.0; - - String get name - { - return _name; - } - - bool get isLooping - { - return _isLooping; - } - - double get duration - { - return _duration; - } - - List get animatedComponents - { - return _components; - } - - //Animation.prototype.triggerEvents = function(actorComponents, fromTime, toTime, triggered) - /* +class ActorAnimation { + String _name; + int _fps; + double _duration; + bool _isLooping; + List _components; + List _triggerComponents; + double start = 0.0, + end = 0.0; + + String get name { + return _name; + } + + bool get isLooping { + return _isLooping; + } + + double get duration { + return _duration; + } + + List get animatedComponents { + return _components; + } + + //Animation.prototype.triggerEvents = function(actorComponents, fromTime, toTime, triggered) + /* name:component._Name, component:component, propertyType:property._Type, keyFrameTime:toTime, elapsed:0*/ - void triggerEvents(List components, double fromTime, double toTime, List triggerEvents) - { - for(int i = 0; i < _triggerComponents.length; i++) - { - ComponentAnimation keyedComponent = _triggerComponents[i]; - for(PropertyAnimation property in keyedComponent.properties) - { - switch(property.propertyType) - { - case PropertyTypes.Trigger: - List keyFrames = property.keyFrames; - - int kfl = keyFrames.length; - if(kfl == 0) - { - continue; - } - - int idx = 0; - // Binary find the keyframe index. - { - int mid = 0; - double element = 0.0; - int start = 0; - int end = kfl-1; - - while (start <= end) - { - mid = ((start + end) >> 1); - element = keyFrames[mid].time; - if (element < toTime) - { - start = mid + 1; - } - else if (element > toTime) - { - end = mid - 1; - } - else - { - start = mid; - break; - } - } - - idx = start; - } - - //int idx = keyFrameLocation(toTime, keyFrames, 0, keyFrames.length-1); - if(idx == 0) - { - if(kfl > 0 && keyFrames[0].time == toTime) - { - ActorComponent component = components[keyedComponent.componentIndex]; - triggerEvents.add(new AnimationEventArgs(component.name, component, property.propertyType, toTime, 0.0)); - } - } - else - { - for(int k = idx-1; k >= 0; k--) - { - KeyFrame frame = keyFrames[k]; - - if(frame.time > fromTime) - { - ActorComponent component = components[keyedComponent.componentIndex]; - triggerEvents.add(new AnimationEventArgs(component.name, component, property.propertyType, frame.time, toTime-frame.time)); - /*triggered.push({ + void triggerEvents(List components, double fromTime, + double toTime, List triggerEvents) { + for (int i = 0; i < _triggerComponents.length; i++) { + ComponentAnimation keyedComponent = _triggerComponents[i]; + for (PropertyAnimation property in keyedComponent.properties) { + switch (property.propertyType) { + case PropertyTypes.Trigger: + List keyFrames = property.keyFrames; + + int kfl = keyFrames.length; + if (kfl == 0) { + continue; + } + + int idx = 0; + // Binary find the keyframe index. + { + int mid = 0; + double element = 0.0; + int start = 0; + int end = kfl - 1; + + while (start <= end) { + mid = ((start + end) >> 1); + element = keyFrames[mid].time; + if (element < toTime) { + start = mid + 1; + } + else if (element > toTime) { + end = mid - 1; + } + else { + start = mid; + break; + } + } + + idx = start; + } + + //int idx = keyFrameLocation(toTime, keyFrames, 0, keyFrames.length-1); + if (idx == 0) { + if (kfl > 0 && keyFrames[0].time == toTime) { + ActorComponent component = components[keyedComponent + .componentIndex]; + triggerEvents.add(new AnimationEventArgs( + component.name, component, property.propertyType, toTime, + 0.0)); + } + } + else { + for (int k = idx - 1; k >= 0; k--) { + KeyFrame frame = keyFrames[k]; + + if (frame.time > fromTime) { + ActorComponent component = components[keyedComponent + .componentIndex]; + triggerEvents.add(new AnimationEventArgs( + component.name, component, property.propertyType, + frame.time, toTime - frame.time)); + /*triggered.push({ name:component._Name, component:component, propertyType:property._Type, keyFrameTime:frame._Time, elapsed:toTime-frame._Time });*/ - } - else - { - break; - } - } - } - break; - default: - break; - } - } - } - } - - void apply(double time, ActorArtboard artboard, double mix) - { - for(ComponentAnimation componentAnimation in _components) - { - componentAnimation.apply(time, artboard.components, mix); - } - } - - static ActorAnimation read(StreamReader reader, List components) - { - ActorAnimation animation = new ActorAnimation(); - animation._name = reader.readString("name"); - animation._fps = reader.readUint8("fps"); - animation._duration = reader.readFloat32("duration"); - animation._isLooping = reader.readBool("isLooping"); - - reader.openArray("keyed"); - int numKeyedComponents = reader.readUint16Length(); - //animation._components = new ComponentAnimation[numKeyedComponents]; - - // We distinguish between animated and triggered components as ActorEvents are currently only used to trigger events and don't need - // the full animation cycle. This lets them optimize them out of the regular animation cycle. - int animatedComponentCount = 0; - int triggerComponentCount = 0; - - List animatedComponents = new List(numKeyedComponents); - for(int i = 0; i < numKeyedComponents; i++) - { - ComponentAnimation componentAnimation = ComponentAnimation.read(reader, components); - animatedComponents[i] = componentAnimation; - if(componentAnimation != null) - { - ActorComponent actorComponent = components[componentAnimation.componentIndex]; - if(actorComponent != null) - { - if(actorComponent is ActorEvent) - { - triggerComponentCount++; - } - else - { - animatedComponentCount++; - } - } - } - } - reader.closeArray(); - if(numKeyedComponents > 0) - { - animation.start = reader.readFloat32("animationStart"); - animation.end = reader.readFloat32("animationEnd"); + } + else { + break; + } + } + } + break; + default: + break; + } + } + } + } + + void apply(double time, ActorArtboard artboard, double mix) { + for (ComponentAnimation componentAnimation in _components) { + componentAnimation.apply(time, artboard.components, mix); + } + } + + static ActorAnimation read(StreamReader reader, + List components) { + ActorAnimation animation = new ActorAnimation(); + animation._name = reader.readString("name"); + animation._fps = reader.readUint8("fps"); + animation._duration = reader.readFloat32("duration"); + animation._isLooping = reader.readBool("isLooping"); + + reader.openArray("keyed"); + int numKeyedComponents = reader.readUint16Length(); + //animation._components = new ComponentAnimation[numKeyedComponents]; + + // We distinguish between animated and triggered components as ActorEvents are currently only used to trigger events and don't need + // the full animation cycle. This lets them optimize them out of the regular animation cycle. + int animatedComponentCount = 0; + int triggerComponentCount = 0; + + List animatedComponents = new List( + numKeyedComponents); + for (int i = 0; i < numKeyedComponents; i++) { + ComponentAnimation componentAnimation = ComponentAnimation.read( + reader, components); + animatedComponents[i] = componentAnimation; + if (componentAnimation != null) { + ActorComponent actorComponent = components[componentAnimation + .componentIndex]; + if (actorComponent != null) { + if (actorComponent is ActorEvent) { + triggerComponentCount++; + } + else { + animatedComponentCount++; + } } + } + } + reader.closeArray(); + if (numKeyedComponents > 0) { + animation.start = reader.readFloat32("animationStart"); + animation.end = reader.readFloat32("animationEnd"); + } + + animation._components = + new List(animatedComponentCount); + animation._triggerComponents = + new List(triggerComponentCount); + + // Put them in their respective lists. + int animatedComponentIndex = 0; + int triggerComponentIndex = 0; + for (int i = 0; i < numKeyedComponents; i++) { + ComponentAnimation componentAnimation = animatedComponents[i]; + if (componentAnimation != null) { + ActorComponent actorComponent = components[componentAnimation + .componentIndex]; + if (actorComponent != null) { + if (actorComponent is ActorEvent) { + animation._triggerComponents[triggerComponentIndex++] = + componentAnimation; + } + else { + animation._components[animatedComponentIndex++] = + componentAnimation; + } + } + } + } - animation._components = new List(animatedComponentCount); - animation._triggerComponents = new List(triggerComponentCount); - - // Put them in their respective lists. - int animatedComponentIndex = 0; - int triggerComponentIndex = 0; - for(int i = 0; i < numKeyedComponents; i++) - { - ComponentAnimation componentAnimation = animatedComponents[i]; - if(componentAnimation != null) - { - ActorComponent actorComponent = components[componentAnimation.componentIndex]; - if(actorComponent != null) - { - if(actorComponent is ActorEvent) - { - animation._triggerComponents[triggerComponentIndex++] = componentAnimation; - } - else - { - animation._components[animatedComponentIndex++] = componentAnimation; - } - } - } - } - - return animation; - } + return animation; + } } // class ActorAnimationInstance @@ -560,7 +510,7 @@ class ActorAnimation // { // return _max; // } - + // double get time // { // return _time; diff --git a/lib/flare/animation/interpolation/cubic.dart b/lib/flare/animation/interpolation/cubic.dart index 92b2aae..ce0bf5b 100644 --- a/lib/flare/animation/interpolation/cubic.dart +++ b/lib/flare/animation/interpolation/cubic.dart @@ -3,22 +3,20 @@ import "../../stream_reader.dart"; import "package:flutter/animation.dart"; -class CubicInterpolator extends Interpolator -{ - Cubic _cubic; - double getEasedMix(double mix) - { - return _cubic.transform(mix); - } +class CubicInterpolator extends Interpolator { + Cubic _cubic; - bool read(StreamReader reader) - { - _cubic = new Cubic( - reader.readFloat32("cubicX1"), - reader.readFloat32("cubicY1"), - reader.readFloat32("cubicX2"), - reader.readFloat32("cubicY2") - ); - return true; - } + double getEasedMix(double mix) { + return _cubic.transform(mix); + } + + bool read(StreamReader reader) { + _cubic = new Cubic( + reader.readFloat32("cubicX1"), + reader.readFloat32("cubicY1"), + reader.readFloat32("cubicX2"), + reader.readFloat32("cubicY2") + ); + return true; + } } \ No newline at end of file diff --git a/lib/flare/animation/interpolation/hold.dart b/lib/flare/animation/interpolation/hold.dart index e6ee9fe..ebcb676 100644 --- a/lib/flare/animation/interpolation/hold.dart +++ b/lib/flare/animation/interpolation/hold.dart @@ -1,16 +1,13 @@ import "./interpolator.dart"; -class HoldInterpolator extends Interpolator -{ - static get instance - { - return _instance; - } - - double getEasedMix(double mix) - { - return 0.0; - } +class HoldInterpolator extends Interpolator { + static get instance { + return _instance; + } + + double getEasedMix(double mix) { + return 0.0; + } } HoldInterpolator _instance = new HoldInterpolator(); \ No newline at end of file diff --git a/lib/flare/animation/interpolation/interpolator.dart b/lib/flare/animation/interpolation/interpolator.dart index 8863ae2..8ae56c4 100644 --- a/lib/flare/animation/interpolation/interpolator.dart +++ b/lib/flare/animation/interpolation/interpolator.dart @@ -1,4 +1,3 @@ -abstract class Interpolator -{ - double getEasedMix(double mix); +abstract class Interpolator { + double getEasedMix(double mix); } \ No newline at end of file diff --git a/lib/flare/animation/interpolation/linear.dart b/lib/flare/animation/interpolation/linear.dart index cad7934..f1fdb16 100644 --- a/lib/flare/animation/interpolation/linear.dart +++ b/lib/flare/animation/interpolation/linear.dart @@ -1,16 +1,13 @@ import "./interpolator.dart"; -class LinearInterpolator extends Interpolator -{ - static get instance - { - return _instance; - } - - double getEasedMix(double mix) - { - return mix; - } +class LinearInterpolator extends Interpolator { + static get instance { + return _instance; + } + + double getEasedMix(double mix) { + return mix; + } } LinearInterpolator _instance = new LinearInterpolator(); \ No newline at end of file diff --git a/lib/flare/animation/keyframe.dart b/lib/flare/animation/keyframe.dart index 2e0180e..818b6f0 100644 --- a/lib/flare/animation/keyframe.dart +++ b/lib/flare/animation/keyframe.dart @@ -20,109 +20,100 @@ import "../actor_path.dart"; import "../path_point.dart"; import "../actor_color.dart"; -enum InterpolationTypes -{ - Hold, - Linear, - Cubic +enum InterpolationTypes { + Hold, + Linear, + Cubic } -HashMap interpolationTypesLookup = new HashMap.fromIterables([0,1,2], [InterpolationTypes.Hold, InterpolationTypes.Linear, InterpolationTypes.Cubic]); +HashMap interpolationTypesLookup = new HashMap< + int, + InterpolationTypes>.fromIterables([0, 1, 2], [ + InterpolationTypes.Hold, InterpolationTypes.Linear, InterpolationTypes.Cubic +]); -abstract class KeyFrame -{ - double _time; +abstract class KeyFrame { + double _time; - double get time - { - return _time; - } + double get time { + return _time; + } - static bool read(StreamReader reader, KeyFrame frame) - { - frame._time = reader.readFloat64("time"); + static bool read(StreamReader reader, KeyFrame frame) { + frame._time = reader.readFloat64("time"); - return true; - } + return true; + } - void setNext(KeyFrame frame); - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix); - void apply(ActorComponent component, double mix); + void setNext(KeyFrame frame); + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix); + + void apply(ActorComponent component, double mix); } -abstract class KeyFrameWithInterpolation extends KeyFrame -{ - Interpolator _interpolator; +abstract class KeyFrameWithInterpolation extends KeyFrame { + Interpolator _interpolator; - Interpolator get interpolator - { - return _interpolator; - } + Interpolator get interpolator { + return _interpolator; + } - static bool read(StreamReader reader, KeyFrameWithInterpolation frame) - { - if(!KeyFrame.read(reader, frame)) - { - return false; - } - int type = reader.readUint8("interpolatorType"); - - InterpolationTypes actualType = interpolationTypesLookup[type]; - if(actualType == null) - { - actualType = InterpolationTypes.Linear; - } - - switch(actualType) - { - case InterpolationTypes.Hold: - frame._interpolator = HoldInterpolator.instance; - break; - case InterpolationTypes.Linear: - frame._interpolator = LinearInterpolator.instance; - break; - case InterpolationTypes.Cubic: - { - CubicInterpolator interpolator = new CubicInterpolator(); - if(interpolator.read(reader)) - { - frame._interpolator = interpolator; - } - break; - } - default: - frame._interpolator = null; - } - return true; - } - - void setNext(KeyFrame frame) - { - // Null out the interpolator if the next frame doesn't validate. - // if(_interpolator != null && !_interpolator.setNextFrame(this, frame)) - // { - // _interpolator = null; - // } - } + static bool read(StreamReader reader, KeyFrameWithInterpolation frame) { + if (!KeyFrame.read(reader, frame)) { + return false; + } + int type = reader.readUint8("interpolatorType"); + + InterpolationTypes actualType = interpolationTypesLookup[type]; + if (actualType == null) { + actualType = InterpolationTypes.Linear; + } + + switch (actualType) { + case InterpolationTypes.Hold: + frame._interpolator = HoldInterpolator.instance; + break; + case InterpolationTypes.Linear: + frame._interpolator = LinearInterpolator.instance; + break; + case InterpolationTypes.Cubic: + { + CubicInterpolator interpolator = new CubicInterpolator(); + if (interpolator.read(reader)) { + frame._interpolator = interpolator; + } + break; + } + default: + frame._interpolator = null; + } + return true; + } + + void setNext(KeyFrame frame) { + // Null out the interpolator if the next frame doesn't validate. + // if(_interpolator != null && !_interpolator.setNextFrame(this, frame)) + // { + // _interpolator = null; + // } + } } -abstract class KeyFrameNumeric extends KeyFrameWithInterpolation -{ - double _value; +abstract class KeyFrameNumeric extends KeyFrameWithInterpolation { + double _value; - double get value - { - return _value; - } + double get value { + return _value; + } - static bool read(StreamReader reader, KeyFrameNumeric frame) - { - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return false; - } - frame._value = reader.readFloat32("value"); - /*if(frame._interpolator != null) + static bool read(StreamReader reader, KeyFrameNumeric frame) { + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return false; + } + frame._value = reader.readFloat32("value"); + /*if(frame._interpolator != null) { // TODO: in the future, this could also be a progression curve. ValueTimeCurveInterpolator vtci = frame._interpolator as ValueTimeCurveInterpolator; @@ -131,1260 +122,1059 @@ abstract class KeyFrameNumeric extends KeyFrameWithInterpolation vtci.SetKeyFrameValue(m_Value); } }*/ - return true; - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - KeyFrameNumeric to = toFrame as KeyFrameNumeric; - double f = (time - _time)/(to._time-_time); - if(_interpolator != null) - { - f = _interpolator.getEasedMix(f); - } - setValue(component, _value * (1.0-f) + to._value * f, mix); - } - - void apply(ActorComponent component, double mix) - { - setValue(component, _value, mix); - } - - void setValue(ActorComponent component, double value, double mix); + return true; + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + KeyFrameNumeric to = toFrame as KeyFrameNumeric; + double f = (time - _time) / (to._time - _time); + if (_interpolator != null) { + f = _interpolator.getEasedMix(f); + } + setValue(component, _value * (1.0 - f) + to._value * f, mix); + } + + void apply(ActorComponent component, double mix) { + setValue(component, _value, mix); + } + + void setValue(ActorComponent component, double value, double mix); } -abstract class KeyFrameInt extends KeyFrameWithInterpolation -{ - double _value; +abstract class KeyFrameInt extends KeyFrameWithInterpolation { + double _value; - double get value - { - return _value; - } + double get value { + return _value; + } - static bool read(StreamReader reader, KeyFrameInt frame) - { - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return false; - } - frame._value = reader.readInt32("value").toDouble(); - return true; - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - KeyFrameNumeric to = toFrame as KeyFrameNumeric; - double f = (time - _time)/(to._time-_time); - if(_interpolator != null) - { - f = _interpolator.getEasedMix(f); - } - setValue(component, _value * (1.0-f) + to._value * f, mix); - } - - void apply(ActorComponent component, double mix) - { - setValue(component, _value, mix); - } - - void setValue(ActorComponent component, double value, double mix); + static bool read(StreamReader reader, KeyFrameInt frame) { + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return false; + } + frame._value = reader.readInt32("value").toDouble(); + return true; + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + KeyFrameNumeric to = toFrame as KeyFrameNumeric; + double f = (time - _time) / (to._time - _time); + if (_interpolator != null) { + f = _interpolator.getEasedMix(f); + } + setValue(component, _value * (1.0 - f) + to._value * f, mix); + } + + void apply(ActorComponent component, double mix) { + setValue(component, _value, mix); + } + + void setValue(ActorComponent component, double value, double mix); } -class KeyFrameIntProperty extends KeyFrameInt -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameIntProperty frame = new KeyFrameIntProperty(); - if(KeyFrameInt.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - // TODO - //CustomIntProperty node = component as CustomIntProperty; - //node.value = (node.value * (1.0 - mix) + value * mix).round(); - } +class KeyFrameIntProperty extends KeyFrameInt { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameIntProperty frame = new KeyFrameIntProperty(); + if (KeyFrameInt.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + // TODO + //CustomIntProperty node = component as CustomIntProperty; + //node.value = (node.value * (1.0 - mix) + value * mix).round(); + } } -class KeyFrameFloatProperty extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameFloatProperty frame = new KeyFrameFloatProperty(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - // TODO - // CustomFloatProperty node = component as CustomFloatProperty; - // node.value = node.value * (1.0 - mix) + value * mix; - } +class KeyFrameFloatProperty extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameFloatProperty frame = new KeyFrameFloatProperty(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + // TODO + // CustomFloatProperty node = component as CustomFloatProperty; + // node.value = node.value * (1.0 - mix) + value * mix; + } } -class KeyFrameStringProperty extends KeyFrame -{ - String _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameStringProperty frame = new KeyFrameStringProperty(); - if(!KeyFrame.read(reader, frame)) - { - return null; - } - frame._value = reader.readString("value"); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - apply(component, mix); - } - - void apply(ActorComponent component, double mix) - { - // CustomStringProperty prop = component as CustomStringProperty; - // prop.value = _value; - } +class KeyFrameStringProperty extends KeyFrame { + String _value; + + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameStringProperty frame = new KeyFrameStringProperty(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + frame._value = reader.readString("value"); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + apply(component, mix); + } + + void apply(ActorComponent component, double mix) { + // CustomStringProperty prop = component as CustomStringProperty; + // prop.value = _value; + } } -class KeyFrameBooleanProperty extends KeyFrame -{ - bool _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameBooleanProperty frame = new KeyFrameBooleanProperty(); - if(!KeyFrame.read(reader, frame)) - { - return null; - } - frame._value = reader.readBool("value"); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - apply(component, mix); - } - - void apply(ActorComponent component, double mix) - { - // CustomBooleanProperty prop = component as CustomBooleanProperty; - // prop.value = _value; - } +class KeyFrameBooleanProperty extends KeyFrame { + bool _value; + + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameBooleanProperty frame = new KeyFrameBooleanProperty(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + frame._value = reader.readBool("value"); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + apply(component, mix); + } + + void apply(ActorComponent component, double mix) { + // CustomBooleanProperty prop = component as CustomBooleanProperty; + // prop.value = _value; + } } -class KeyFrameCollisionEnabledProperty extends KeyFrame -{ - bool _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameCollisionEnabledProperty frame = new KeyFrameCollisionEnabledProperty(); - if(!KeyFrame.read(reader, frame)) - { - return null; - } - frame._value = reader.readBool("value"); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - apply(component, mix); - } - - void apply(ActorComponent component, double mix) - { - // ActorCollider collider = component as ActorCollider; - // collider.isCollisionEnabled = _value; - } +class KeyFrameCollisionEnabledProperty extends KeyFrame { + bool _value; + + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameCollisionEnabledProperty frame = new KeyFrameCollisionEnabledProperty(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + frame._value = reader.readBool("value"); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + apply(component, mix); + } + + void apply(ActorComponent component, double mix) { + // ActorCollider collider = component as ActorCollider; + // collider.isCollisionEnabled = _value; + } } -class KeyFramePosX extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFramePosX frame = new KeyFramePosX(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.x = node.x * (1.0 - mix) + value * mix; - } +class KeyFramePosX extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFramePosX frame = new KeyFramePosX(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.x = node.x * (1.0 - mix) + value * mix; + } } -class KeyFramePosY extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFramePosY frame = new KeyFramePosY(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.y = node.y * (1.0 - mix) + value * mix; - } +class KeyFramePosY extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFramePosY frame = new KeyFramePosY(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.y = node.y * (1.0 - mix) + value * mix; + } } -class KeyFrameScaleX extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameScaleX frame = new KeyFrameScaleX(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.scaleX = node.scaleX * (1.0 - mix) + value * mix; - } +class KeyFrameScaleX extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameScaleX frame = new KeyFrameScaleX(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.scaleX = node.scaleX * (1.0 - mix) + value * mix; + } } -class KeyFrameScaleY extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameScaleY frame = new KeyFrameScaleY(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.scaleY = node.scaleY * (1.0 - mix) + value * mix; - } +class KeyFrameScaleY extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameScaleY frame = new KeyFrameScaleY(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.scaleY = node.scaleY * (1.0 - mix) + value * mix; + } } -class KeyFrameRotation extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameRotation frame = new KeyFrameRotation(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.rotation = node.rotation * (1.0 - mix) + value * mix; - } +class KeyFrameRotation extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameRotation frame = new KeyFrameRotation(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.rotation = node.rotation * (1.0 - mix) + value * mix; + } } -class KeyFrameOpacity extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameOpacity frame = new KeyFrameOpacity(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorNode node = component as ActorNode; - node.opacity = node.opacity * (1.0 - mix) + value * mix; - } +class KeyFrameOpacity extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameOpacity frame = new KeyFrameOpacity(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorNode node = component as ActorNode; + node.opacity = node.opacity * (1.0 - mix) + value * mix; + } } -class KeyFrameLength extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameLength frame = new KeyFrameLength(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorBoneBase bone = component as ActorBoneBase; - if(bone == null) - { - return; - } - bone.length = bone.length * (1.0 - mix) + value * mix; - } +class KeyFrameLength extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameLength frame = new KeyFrameLength(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorBoneBase bone = component as ActorBoneBase; + if (bone == null) { + return; + } + bone.length = bone.length * (1.0 - mix) + value * mix; + } } -class KeyFrameConstraintStrength extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameConstraintStrength frame = new KeyFrameConstraintStrength(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorConstraint constraint = component as ActorConstraint; - constraint.strength = constraint.strength * (1.0 - mix) + value * mix; - } +class KeyFrameConstraintStrength extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameConstraintStrength frame = new KeyFrameConstraintStrength(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorConstraint constraint = component as ActorConstraint; + constraint.strength = constraint.strength * (1.0 - mix) + value * mix; + } } -class DrawOrderIndex -{ - int componentIndex; - int order; +class DrawOrderIndex { + int componentIndex; + int order; } -class KeyFrameDrawOrder extends KeyFrame -{ - List _orderedNodes; +class KeyFrameDrawOrder extends KeyFrame { + List _orderedNodes; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameDrawOrder frame = new KeyFrameDrawOrder(); - if(!KeyFrame.read(reader, frame)) - { - return null; - } - reader.openArray("drawOrder"); - int numOrderedNodes = reader.readUint16Length(); - frame._orderedNodes = new List(numOrderedNodes); - for(int i = 0; i < numOrderedNodes; i++) - { - reader.openObject("order"); - DrawOrderIndex drawOrder = new DrawOrderIndex(); - drawOrder.componentIndex = reader.readId("component"); - drawOrder.order = reader.readUint16("order"); - reader.closeObject(); - frame._orderedNodes[i] = drawOrder; - } - reader.closeArray(); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - apply(component, mix); - } - - void apply(ActorComponent component, double mix) - { - ActorArtboard artboard = component.artboard; - - for(DrawOrderIndex doi in _orderedNodes) - { - ActorDrawable drawable = artboard[doi.componentIndex] as ActorDrawable; - if(drawable != null) - { - drawable.drawOrder = doi.order; - } - } - } + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameDrawOrder frame = new KeyFrameDrawOrder(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + reader.openArray("drawOrder"); + int numOrderedNodes = reader.readUint16Length(); + frame._orderedNodes = new List(numOrderedNodes); + for (int i = 0; i < numOrderedNodes; i++) { + reader.openObject("order"); + DrawOrderIndex drawOrder = new DrawOrderIndex(); + drawOrder.componentIndex = reader.readId("component"); + drawOrder.order = reader.readUint16("order"); + reader.closeObject(); + frame._orderedNodes[i] = drawOrder; + } + reader.closeArray(); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + apply(component, mix); + } + + void apply(ActorComponent component, double mix) { + ActorArtboard artboard = component.artboard; + + for (DrawOrderIndex doi in _orderedNodes) { + ActorDrawable drawable = artboard[doi.componentIndex] as ActorDrawable; + if (drawable != null) { + drawable.drawOrder = doi.order; + } + } + } } -class KeyFrameVertexDeform extends KeyFrameWithInterpolation -{ - Float32List _vertices; +class KeyFrameVertexDeform extends KeyFrameWithInterpolation { + Float32List _vertices; - Float32List get vertices - { - return _vertices; - } + Float32List get vertices { + return _vertices; + } - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameVertexDeform frame = new KeyFrameVertexDeform(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameVertexDeform frame = new KeyFrameVertexDeform(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } - ActorImage imageNode = component as ActorImage; - frame._vertices = new Float32List(imageNode.vertexCount * 2); - reader.readFloat32ArrayOffset(frame._vertices, frame._vertices.length, 0, "value"); - - imageNode.doesAnimationVertexDeform = true; + ActorImage imageNode = component as ActorImage; + frame._vertices = new Float32List(imageNode.vertexCount * 2); + reader.readFloat32ArrayOffset( + frame._vertices, frame._vertices.length, 0, "value"); - return frame; - } + imageNode.doesAnimationVertexDeform = true; - void transformVertices(Mat2D wt) - { - int aiVertexCount = _vertices.length ~/ 2; - Float32List fv = _vertices; + return frame; + } - int vidx = 0; - for(int j = 0; j < aiVertexCount; j++) - { - double x = fv[vidx]; - double y = fv[vidx+1]; - - fv[vidx] = wt[0] * x + wt[2] * y + wt[4]; - fv[vidx+1] = wt[1] * x + wt[3] * y + wt[5]; - - vidx += 2; - } - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - ActorImage imageNode = component as ActorImage; - Float32List wr = imageNode.animationDeformedVertices; - Float32List to = (toFrame as KeyFrameVertexDeform)._vertices; - int l = _vertices.length; - - double f = (time - _time)/(toFrame.time-_time); - if(_interpolator != null) - { - f = _interpolator.getEasedMix(f); - } + void transformVertices(Mat2D wt) { + int aiVertexCount = _vertices.length ~/ 2; + Float32List fv = _vertices; - double fi = 1.0 - f; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _vertices[i] * fi + to[i] * f; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - double v = _vertices[i] * fi + to[i] * f; + int vidx = 0; + for (int j = 0; j < aiVertexCount; j++) { + double x = fv[vidx]; + double y = fv[vidx + 1]; - wr[i] = wr[i] * mixi + v * mix; - } - } - - imageNode.isVertexDeformDirty = true; - } - - void apply(ActorComponent component, double mix) - { - ActorImage imageNode = component as ActorImage; - int l = _vertices.length; - Float32List wr = imageNode.animationDeformedVertices; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _vertices[i]; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - wr[i] = wr[i] * mixi + _vertices[i] * mix; - } - } + fv[vidx] = wt[0] * x + wt[2] * y + wt[4]; + fv[vidx + 1] = wt[1] * x + wt[3] * y + wt[5]; + + vidx += 2; + } + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + ActorImage imageNode = component as ActorImage; + Float32List wr = imageNode.animationDeformedVertices; + Float32List to = (toFrame as KeyFrameVertexDeform)._vertices; + int l = _vertices.length; + + double f = (time - _time) / (toFrame.time - _time); + if (_interpolator != null) { + f = _interpolator.getEasedMix(f); + } + + double fi = 1.0 - f; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _vertices[i] * fi + to[i] * f; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + double v = _vertices[i] * fi + to[i] * f; + + wr[i] = wr[i] * mixi + v * mix; + } + } - imageNode.isVertexDeformDirty = true; - } + imageNode.isVertexDeformDirty = true; + } + + void apply(ActorComponent component, double mix) { + ActorImage imageNode = component as ActorImage; + int l = _vertices.length; + Float32List wr = imageNode.animationDeformedVertices; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _vertices[i]; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + wr[i] = wr[i] * mixi + _vertices[i] * mix; + } + } + + imageNode.isVertexDeformDirty = true; + } } -class KeyFrameTrigger extends KeyFrame -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameTrigger frame = new KeyFrameTrigger(); - if(!KeyFrame.read(reader, frame)) - { - return null; - } - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - } - - void apply(ActorComponent component, double mix) - { - } +class KeyFrameTrigger extends KeyFrame { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameTrigger frame = new KeyFrameTrigger(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + } + + void apply(ActorComponent component, double mix) { + } } -class KeyFrameActiveChild extends KeyFrame -{ - int _value; +class KeyFrameActiveChild extends KeyFrame { + int _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameActiveChild frame = new KeyFrameActiveChild(); - if (!KeyFrame.read(reader, frame)) - { - return null; - } - frame._value = reader.readFloat32("value").toInt(); - return frame; - } - - void setNext(KeyFrame frame) - { - // No Interpolation - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - apply(component, mix); - } - - void apply(ActorComponent component, double mix) - { - ActorNodeSolo soloNode = component as ActorNodeSolo; - soloNode.activeChildIndex = _value; - } + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameActiveChild frame = new KeyFrameActiveChild(); + if (!KeyFrame.read(reader, frame)) { + return null; + } + frame._value = reader.readFloat32("value").toInt(); + return frame; + } + + void setNext(KeyFrame frame) { + // No Interpolation + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + apply(component, mix); + } + + void apply(ActorComponent component, double mix) { + ActorNodeSolo soloNode = component as ActorNodeSolo; + soloNode.activeChildIndex = _value; + } } -class KeyFrameSequence extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameSequence frame = new KeyFrameSequence(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorImage node = component as ActorImage; - int frameIndex = value.floor() % node.sequenceFrames.length; - if(frameIndex < 0) - { - frameIndex += node.sequenceFrames.length; - } - node.sequenceFrame = frameIndex; - } +class KeyFrameSequence extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameSequence frame = new KeyFrameSequence(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorImage node = component as ActorImage; + int frameIndex = value.floor() % node.sequenceFrames.length; + if (frameIndex < 0) { + frameIndex += node.sequenceFrames.length; + } + node.sequenceFrame = frameIndex; + } } -class KeyFrameFillColor extends KeyFrameWithInterpolation -{ - Float32List _value; +class KeyFrameFillColor extends KeyFrameWithInterpolation { + Float32List _value; - Float32List get value - { - return _value; - } + Float32List get value { + return _value; + } - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameFillColor frame = new KeyFrameFillColor(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } - - frame._value = new Float32List(4); - reader.readFloat32ArrayOffset(frame._value, 4, 0, "value"); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - ActorColor ac = component as ActorColor; - Float32List wr = ac.color; - Float32List to = (toFrame as KeyFrameFillColor)._value; - int l = _value.length; - - double f = (time - _time)/(toFrame.time-_time); - double fi = 1.0 - f; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _value[i] * fi + to[i] * f; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - double v = _value[i] * fi + to[i] * f; + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameFillColor frame = new KeyFrameFillColor(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } - wr[i] = wr[i] * mixi + v * mix; - } - } - - //path.markVertexDeformDirty(); - } - - void apply(ActorComponent component, double mix) - { - ActorColor ac = component as ActorColor; - int l = _value.length; - Float32List wr = ac.color; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _value[i]; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - wr[i] = wr[i] * mixi + _value[i] * mix; - } - } - } + frame._value = new Float32List(4); + reader.readFloat32ArrayOffset(frame._value, 4, 0, "value"); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + ActorColor ac = component as ActorColor; + Float32List wr = ac.color; + Float32List to = (toFrame as KeyFrameFillColor)._value; + int l = _value.length; + + double f = (time - _time) / (toFrame.time - _time); + double fi = 1.0 - f; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _value[i] * fi + to[i] * f; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + double v = _value[i] * fi + to[i] * f; + + wr[i] = wr[i] * mixi + v * mix; + } + } + + //path.markVertexDeformDirty(); + } + + void apply(ActorComponent component, double mix) { + ActorColor ac = component as ActorColor; + int l = _value.length; + Float32List wr = ac.color; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _value[i]; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + wr[i] = wr[i] * mixi + _value[i] * mix; + } + } + } } -class KeyFramePathVertices extends KeyFrameWithInterpolation -{ - Float32List _vertices; +class KeyFramePathVertices extends KeyFrameWithInterpolation { + Float32List _vertices; - Float32List get vertices - { - return _vertices; - } + Float32List get vertices { + return _vertices; + } - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFramePathVertices frame = new KeyFramePathVertices(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFramePathVertices frame = new KeyFramePathVertices(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } - ActorPath pathNode = component as ActorPath; + ActorPath pathNode = component as ActorPath; + + int length = pathNode.points.fold(0, (int previous, PathPoint point) { + return previous + 2 + (point.pointType == PointType.Straight ? 1 : 4); + }); + frame._vertices = new Float32List(length); + int readIdx = 0; + for (PathPoint point in pathNode.points) { + reader.readFloat32ArrayOffset(frame._vertices, 2, readIdx, "translation"); + if (point.pointType == PointType.Straight) { + // radius + reader.readFloat32ArrayOffset( + frame._vertices, 1, readIdx + 2, "radius"); + + readIdx += 3; + } + else { + // in/out + reader.readFloat32ArrayOffset( + frame._vertices, 2, readIdx + 2, "inValue"); + reader.readFloat32ArrayOffset( + frame._vertices, 2, readIdx + 4, "outValue"); + readIdx += 6; + } + } - int length = pathNode.points.fold(0, (int previous, PathPoint point) - { - return previous + 2 + (point.pointType == PointType.Straight ? 1 : 4); - }); - frame._vertices = new Float32List(length); - int readIdx = 0; - for(PathPoint point in pathNode.points) - { - reader.readFloat32ArrayOffset(frame._vertices, 2, readIdx, "translation"); - if(point.pointType == PointType.Straight) - { - // radius - reader.readFloat32ArrayOffset(frame._vertices, 1, readIdx+2, "radius"); + pathNode.vertexDeform = new Float32List.fromList(frame._vertices); + return frame; + } + + void setNext(KeyFrame frame) { + // Do nothing. + } + + void applyInterpolation(ActorComponent component, double time, + KeyFrame toFrame, double mix) { + ActorPath path = component as ActorPath; + Float32List wr = path.vertexDeform; + Float32List to = (toFrame as KeyFramePathVertices)._vertices; + int l = _vertices.length; + + double f = (time - _time) / (toFrame.time - _time); + double fi = 1.0 - f; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _vertices[i] * fi + to[i] * f; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + double v = _vertices[i] * fi + to[i] * f; - readIdx += 3; - } - else - { - // in/out - reader.readFloat32ArrayOffset(frame._vertices, 2, readIdx+2, "inValue"); - reader.readFloat32ArrayOffset(frame._vertices, 2, readIdx+4, "outValue"); - readIdx += 6; - } - } - - pathNode.vertexDeform = new Float32List.fromList(frame._vertices); - return frame; - } - - void setNext(KeyFrame frame) - { - // Do nothing. - } - - void applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - ActorPath path = component as ActorPath; - Float32List wr = path.vertexDeform; - Float32List to = (toFrame as KeyFramePathVertices)._vertices; - int l = _vertices.length; - - double f = (time - _time)/(toFrame.time-_time); - double fi = 1.0 - f; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _vertices[i] * fi + to[i] * f; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - double v = _vertices[i] * fi + to[i] * f; + wr[i] = wr[i] * mixi + v * mix; + } + } - wr[i] = wr[i] * mixi + v * mix; - } - } - - path.markVertexDeformDirty(); - } - - void apply(ActorComponent component, double mix) - { - ActorPath path = component as ActorPath; - int l = _vertices.length; - Float32List wr = path.vertexDeform; - if(mix == 1.0) - { - for(int i = 0; i < l; i++) - { - wr[i] = _vertices[i]; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < l; i++) - { - wr[i] = wr[i] * mixi + _vertices[i] * mix; - } - } + path.markVertexDeformDirty(); + } + + void apply(ActorComponent component, double mix) { + ActorPath path = component as ActorPath; + int l = _vertices.length; + Float32List wr = path.vertexDeform; + if (mix == 1.0) { + for (int i = 0; i < l; i++) { + wr[i] = _vertices[i]; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < l; i++) { + wr[i] = wr[i] * mixi + _vertices[i] * mix; + } + } - path.markVertexDeformDirty(); - } + path.markVertexDeformDirty(); + } } -class KeyFrameFillOpacity extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameFillOpacity frame = new KeyFrameFillOpacity(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - // GradientFill node = component as GradientFill; - ActorPaint node = component as ActorPaint; - node.opacity = node.opacity * (1.0 - mix) + value * mix; - } +class KeyFrameFillOpacity extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameFillOpacity frame = new KeyFrameFillOpacity(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + // GradientFill node = component as GradientFill; + ActorPaint node = component as ActorPaint; + node.opacity = node.opacity * (1.0 - mix) + value * mix; + } } -class KeyFrameStrokeColor extends KeyFrameWithInterpolation -{ - Float32List _value; +class KeyFrameStrokeColor extends KeyFrameWithInterpolation { + Float32List _value; - Float32List get value - { - return _value; - } - - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameStrokeColor frame = new KeyFrameStrokeColor(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } - frame._value = new Float32List(4); - reader.readFloat32ArrayOffset(frame._value, 4, 0, "value"); - return frame; - } - - @override - applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - ColorStroke cs = component as ColorStroke; - Float32List wr = cs.color; - Float32List to = (toFrame as KeyFrameStrokeColor)._value; - int len = _value.length; - - double f = (time - _time)/(toFrame.time - _time); - double fi = 1.0 - f; - if(mix == 1.0) - { - for(int i = 0; i < len; i++) - { - wr[i] = _value[i] * fi + to[i] * f; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < len; i++) - { - double v = _value[i] * fi + to[i] * f; + Float32List get value { + return _value; + } - wr[i] = wr[i] * mixi + v * mix; - } - } + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameStrokeColor frame = new KeyFrameStrokeColor(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } + frame._value = new Float32List(4); + reader.readFloat32ArrayOffset(frame._value, 4, 0, "value"); + return frame; + } + + @override + applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, + double mix) { + ColorStroke cs = component as ColorStroke; + Float32List wr = cs.color; + Float32List to = (toFrame as KeyFrameStrokeColor)._value; + int len = _value.length; + + double f = (time - _time) / (toFrame.time - _time); + double fi = 1.0 - f; + if (mix == 1.0) { + for (int i = 0; i < len; i++) { + wr[i] = _value[i] * fi + to[i] * f; + } } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < len; i++) { + double v = _value[i] * fi + to[i] * f; - @override - apply(ActorComponent component, double mix) - { - ColorStroke node = component as ColorStroke; - Float32List wr = node.color; - int len = wr.length; - if(mix == 1.0) - { - for(int i = 0; i < len; i++) - { - wr[i] = _value[i]; - } - } - else - { - double mixi = 1.0 - mix; - for(int i = 0; i < len; i++) - { - wr[i] = wr[i] * mixi + _value[i] * mix; - } - } + wr[i] = wr[i] * mixi + v * mix; + } } + } + + @override + apply(ActorComponent component, double mix) { + ColorStroke node = component as ColorStroke; + Float32List wr = node.color; + int len = wr.length; + if (mix == 1.0) { + for (int i = 0; i < len; i++) { + wr[i] = _value[i]; + } + } + else { + double mixi = 1.0 - mix; + for (int i = 0; i < len; i++) { + wr[i] = wr[i] * mixi + _value[i] * mix; + } + } + } } -class KeyFrameCornerRadius extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameCornerRadius frame = new KeyFrameCornerRadius(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - ActorRectangle node = component as ActorRectangle; - node.radius = node.radius * (1.0 - mix) + value * mix; - } +class KeyFrameCornerRadius extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameCornerRadius frame = new KeyFrameCornerRadius(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + ActorRectangle node = component as ActorRectangle; + node.radius = node.radius * (1.0 - mix) + value * mix; + } } -class KeyFrameGradient extends KeyFrameWithInterpolation -{ - Float32List _value; - get value => _value; +class KeyFrameGradient extends KeyFrameWithInterpolation { + Float32List _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameGradient frame = new KeyFrameGradient(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } - int len = reader.readUint16("length"); - frame._value = new Float32List(len); - reader.readFloat32Array(frame._value, "value"); - return frame; - } - - @override - applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - GradientColor gradient = component as GradientColor; - Float32List v = (toFrame as KeyFrameGradient)._value; - - double f = (time - _time)/(toFrame.time - _time); - if(_interpolator != null) - { - f = _interpolator.getEasedMix(f); - } - double fi = 1.0 - f; + get value => _value; - int ridx = 0; - int wi = 0; + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameGradient frame = new KeyFrameGradient(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } + int len = reader.readUint16("length"); + frame._value = new Float32List(len); + reader.readFloat32Array(frame._value, "value"); + return frame; + } + + @override + applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, + double mix) { + GradientColor gradient = component as GradientColor; + Float32List v = (toFrame as KeyFrameGradient)._value; + + double f = (time - _time) / (toFrame.time - _time); + if (_interpolator != null) { + f = _interpolator.getEasedMix(f); + } + double fi = 1.0 - f; - if(mix == 1.0) - { - gradient.start[0] = _value[ridx] * fi + v[ridx++] * f; - gradient.start[1] = _value[ridx] * fi + v[ridx++] * f; - gradient.end[0] = _value[ridx] * fi + v[ridx++] * f; - gradient.end[1] = _value[ridx] * fi + v[ridx++] * f; - - while(ridx < v.length && wi < gradient.colorStops.length) - { - gradient.colorStops[wi++] = _value[ridx] * fi + v[ridx++] * f; - } - } - else - { - double imix = 1.0 - mix; - - // Mix : first interpolate the KeyFrames, and then mix on top of the current value. - double val = _value[ridx]*fi + v[ridx]*f; - gradient.start[0] = gradient.start[0]*imix + val*mix; - ridx++; - - val = _value[ridx]*fi + v[ridx]*f; - gradient.start[1] = gradient.start[1]*imix + val*mix; - ridx++; - - val = _value[ridx]*fi + v[ridx]*f; - gradient.end[0] = gradient.end[0]*imix + val*mix; - ridx++; - - val = _value[ridx]*fi + v[ridx]*f; - gradient.end[1] = gradient.end[1]*imix + val*mix; - ridx++; - - while(ridx < v.length && wi < gradient.colorStops.length) - { - val = _value[ridx]*fi + v[ridx]*f; - gradient.colorStops[wi] = gradient.colorStops[wi]*imix + val*mix; - - ridx++; - wi++; - } - } - } - - - - @override - apply(ActorComponent component, double mix) - { - GradientColor gradient = component as GradientColor; - - int ridx = 0; - int wi = 0; - - if(mix == 1.0) - { - gradient.start[0] = _value[ridx++]; - gradient.start[1] = _value[ridx++]; - gradient.end[0] = _value[ridx++]; - gradient.end[1] = _value[ridx++]; - - while(ridx < _value.length && wi < gradient.colorStops.length) - { - gradient.colorStops[wi++] = _value[ridx++]; - } - } - else - { - double imix = 1.0 - mix; - gradient.start[0] = gradient.start[0]*imix + _value[ridx++]*mix; - gradient.start[1] = gradient.start[1]*imix + _value[ridx++]*mix; - gradient.end[0] = gradient.end[0]*imix + _value[ridx++]*mix; - gradient.end[1] = gradient.end[1]*imix + _value[ridx++]*mix; - - while(ridx < _value.length && wi < gradient.colorStops.length) - { - gradient.colorStops[wi] = gradient.colorStops[wi]*imix + _value[ridx++]; - wi++; - } - } + int ridx = 0; + int wi = 0; + + if (mix == 1.0) { + gradient.start[0] = _value[ridx] * fi + v[ridx++] * f; + gradient.start[1] = _value[ridx] * fi + v[ridx++] * f; + gradient.end[0] = _value[ridx] * fi + v[ridx++] * f; + gradient.end[1] = _value[ridx] * fi + v[ridx++] * f; + + while (ridx < v.length && wi < gradient.colorStops.length) { + gradient.colorStops[wi++] = _value[ridx] * fi + v[ridx++] * f; + } } + else { + double imix = 1.0 - mix; + + // Mix : first interpolate the KeyFrames, and then mix on top of the current value. + double val = _value[ridx] * fi + v[ridx] * f; + gradient.start[0] = gradient.start[0] * imix + val * mix; + ridx++; + + val = _value[ridx] * fi + v[ridx] * f; + gradient.start[1] = gradient.start[1] * imix + val * mix; + ridx++; + + val = _value[ridx] * fi + v[ridx] * f; + gradient.end[0] = gradient.end[0] * imix + val * mix; + ridx++; + + val = _value[ridx] * fi + v[ridx] * f; + gradient.end[1] = gradient.end[1] * imix + val * mix; + ridx++; + + while (ridx < v.length && wi < gradient.colorStops.length) { + val = _value[ridx] * fi + v[ridx] * f; + gradient.colorStops[wi] = gradient.colorStops[wi] * imix + val * mix; + + ridx++; + wi++; + } + } + } + + + @override + apply(ActorComponent component, double mix) { + GradientColor gradient = component as GradientColor; + + int ridx = 0; + int wi = 0; + + if (mix == 1.0) { + gradient.start[0] = _value[ridx++]; + gradient.start[1] = _value[ridx++]; + gradient.end[0] = _value[ridx++]; + gradient.end[1] = _value[ridx++]; + + while (ridx < _value.length && wi < gradient.colorStops.length) { + gradient.colorStops[wi++] = _value[ridx++]; + } + } + else { + double imix = 1.0 - mix; + gradient.start[0] = gradient.start[0] * imix + _value[ridx++] * mix; + gradient.start[1] = gradient.start[1] * imix + _value[ridx++] * mix; + gradient.end[0] = gradient.end[0] * imix + _value[ridx++] * mix; + gradient.end[1] = gradient.end[1] * imix + _value[ridx++] * mix; + + while (ridx < _value.length && wi < gradient.colorStops.length) { + gradient.colorStops[wi] = + gradient.colorStops[wi] * imix + _value[ridx++]; + wi++; + } + } + } } -class KeyFrameRadial extends KeyFrameWithInterpolation -{ - Float32List _value; - get value => _value; +class KeyFrameRadial extends KeyFrameWithInterpolation { + Float32List _value; - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameRadial frame = new KeyFrameRadial(); - if(!KeyFrameWithInterpolation.read(reader, frame)) - { - return null; - } - int len = reader.readUint16("length"); - frame._value = new Float32List(len); - reader.readFloat32Array(frame._value, "value"); - return frame; - } - - @override - applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, double mix) - { - RadialGradientColor radial = component as RadialGradientColor; - Float32List v = (toFrame as KeyFrameRadial)._value; - - double f = (time - _time)/(toFrame.time - _time); - if(_interpolator != null) - { - f = _interpolator.getEasedMix(f); - } - double fi = 1.0 - f; + get value => _value; - int ridx = 0; - int wi = 0; + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameRadial frame = new KeyFrameRadial(); + if (!KeyFrameWithInterpolation.read(reader, frame)) { + return null; + } + int len = reader.readUint16("length"); + frame._value = new Float32List(len); + reader.readFloat32Array(frame._value, "value"); + return frame; + } + + @override + applyInterpolation(ActorComponent component, double time, KeyFrame toFrame, + double mix) { + RadialGradientColor radial = component as RadialGradientColor; + Float32List v = (toFrame as KeyFrameRadial)._value; + + double f = (time - _time) / (toFrame.time - _time); + if (_interpolator != null) { + f = _interpolator.getEasedMix(f); + } + double fi = 1.0 - f; - if(mix == 1.0) - { - radial.secondaryRadiusScale = _value[ridx] * fi + v[ridx++] * f; - radial.start[0] = _value[ridx] * fi + v[ridx++] * f; - radial.start[1] = _value[ridx] * fi + v[ridx++] * f; - radial.end[0] = _value[ridx] * fi + v[ridx++] * f; - radial.end[1] = _value[ridx] * fi + v[ridx++] * f; - - while(ridx < v.length && wi < radial.colorStops.length) - { - radial.colorStops[wi++] = _value[ridx] * fi + v[ridx++] * f; - } - } - else - { - double imix = 1.0 - mix; - - // Mix : first interpolate the KeyFrames, and then mix on top of the current value. - double val = _value[ridx]*fi + v[ridx]*f; - radial.secondaryRadiusScale = _value[ridx] * fi + v[ridx++] * f; - val = _value[ridx]*fi + v[ridx]*f; - radial.start[0] = _value[ridx++]*imix + val*mix; - val = _value[ridx]*fi + v[ridx]*f; - radial.start[1] = _value[ridx++]*imix + val*mix; - val = _value[ridx]*fi + v[ridx]*f; - radial.end[0] = _value[ridx++]*imix + val*mix; - val = _value[ridx]*fi + v[ridx]*f; - radial.end[1] = _value[ridx++]*imix + val*mix; - - while(ridx < v.length && wi < radial.colorStops.length) - { - val = _value[ridx]*fi + v[ridx]*f; - radial.colorStops[wi] = radial.colorStops[wi]*imix + val*mix; - - ridx++; - wi++; - } - } - } - - @override - apply(ActorComponent component, double mix) - { - RadialGradientColor radial = component as RadialGradientColor; - - int ridx = 0; - int wi = 0; - - if(mix == 1.0) - { - radial.secondaryRadiusScale = value[ridx++]; - radial.start[0] = _value[ridx++]; - radial.start[1] = _value[ridx++]; - radial.end[0] = _value[ridx++]; - radial.end[1] = _value[ridx++]; - - while(ridx < _value.length && wi < radial.colorStops.length) - { - radial.colorStops[wi++] = _value[ridx++]; - } - } - else - { - double imix = 1.0 - mix; - radial.secondaryRadiusScale = radial.secondaryRadiusScale*imix + value[ridx++]*mix; - radial.start[0] = radial.start[0]*imix + _value[ridx++]*mix; - radial.start[1] = radial.start[1]*imix + _value[ridx++]*mix; - radial.end[0] = radial.end[0]*imix + _value[ridx++]*mix; - radial.end[1] = radial.end[1]*imix + _value[ridx++]*mix; - - while(ridx < _value.length && wi < radial.colorStops.length) - { - radial.colorStops[wi] = radial.colorStops[wi]*imix + _value[ridx++]; - wi++; - } - } + int ridx = 0; + int wi = 0; + + if (mix == 1.0) { + radial.secondaryRadiusScale = _value[ridx] * fi + v[ridx++] * f; + radial.start[0] = _value[ridx] * fi + v[ridx++] * f; + radial.start[1] = _value[ridx] * fi + v[ridx++] * f; + radial.end[0] = _value[ridx] * fi + v[ridx++] * f; + radial.end[1] = _value[ridx] * fi + v[ridx++] * f; + + while (ridx < v.length && wi < radial.colorStops.length) { + radial.colorStops[wi++] = _value[ridx] * fi + v[ridx++] * f; + } + } + else { + double imix = 1.0 - mix; + + // Mix : first interpolate the KeyFrames, and then mix on top of the current value. + double val = _value[ridx] * fi + v[ridx] * f; + radial.secondaryRadiusScale = _value[ridx] * fi + v[ridx++] * f; + val = _value[ridx] * fi + v[ridx] * f; + radial.start[0] = _value[ridx++] * imix + val * mix; + val = _value[ridx] * fi + v[ridx] * f; + radial.start[1] = _value[ridx++] * imix + val * mix; + val = _value[ridx] * fi + v[ridx] * f; + radial.end[0] = _value[ridx++] * imix + val * mix; + val = _value[ridx] * fi + v[ridx] * f; + radial.end[1] = _value[ridx++] * imix + val * mix; + + while (ridx < v.length && wi < radial.colorStops.length) { + val = _value[ridx] * fi + v[ridx] * f; + radial.colorStops[wi] = radial.colorStops[wi] * imix + val * mix; + + ridx++; + wi++; + } } + } + + @override + apply(ActorComponent component, double mix) { + RadialGradientColor radial = component as RadialGradientColor; + + int ridx = 0; + int wi = 0; + + if (mix == 1.0) { + radial.secondaryRadiusScale = value[ridx++]; + radial.start[0] = _value[ridx++]; + radial.start[1] = _value[ridx++]; + radial.end[0] = _value[ridx++]; + radial.end[1] = _value[ridx++]; + + while (ridx < _value.length && wi < radial.colorStops.length) { + radial.colorStops[wi++] = _value[ridx++]; + } + } + else { + double imix = 1.0 - mix; + radial.secondaryRadiusScale = + radial.secondaryRadiusScale * imix + value[ridx++] * mix; + radial.start[0] = radial.start[0] * imix + _value[ridx++] * mix; + radial.start[1] = radial.start[1] * imix + _value[ridx++] * mix; + radial.end[0] = radial.end[0] * imix + _value[ridx++] * mix; + radial.end[1] = radial.end[1] * imix + _value[ridx++] * mix; + + while (ridx < _value.length && wi < radial.colorStops.length) { + radial.colorStops[wi] = radial.colorStops[wi] * imix + _value[ridx++]; + wi++; + } + } + } } -class KeyFrameShapeWidth extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameShapeWidth frame = new KeyFrameShapeWidth(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } +class KeyFrameShapeWidth extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameShapeWidth frame = new KeyFrameShapeWidth(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } - void setValue(ActorComponent component, double value, double mix) - { - if(component == null) return; + void setValue(ActorComponent component, double value, double mix) { + if (component == null) return; - if(component is ActorProceduralPath) - { - component.width = component.width * (1.0 - mix) + value * mix; - } - } + if (component is ActorProceduralPath) { + component.width = component.width * (1.0 - mix) + value * mix; + } + } } -class KeyFrameShapeHeight extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameShapeHeight frame = new KeyFrameShapeHeight(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } +class KeyFrameShapeHeight extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameShapeHeight frame = new KeyFrameShapeHeight(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } - void setValue(ActorComponent component, double value, double mix) - { - if(component == null) return; + void setValue(ActorComponent component, double value, double mix) { + if (component == null) return; - if(component is ActorProceduralPath) - { - component.height = component.height * (1.0 - mix) + value * mix; - //print("YEAHe ${component.name} ${component.height}"); - } - } + if (component is ActorProceduralPath) { + component.height = component.height * (1.0 - mix) + value * mix; + //print("YEAHe ${component.name} ${component.height}"); + } + } } -class KeyFrameStrokeWidth extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameStrokeWidth frame = new KeyFrameStrokeWidth(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } +class KeyFrameStrokeWidth extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameStrokeWidth frame = new KeyFrameStrokeWidth(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } - void setValue(ActorComponent component, double value, double mix) - { - if(component == null) return; + void setValue(ActorComponent component, double value, double mix) { + if (component == null) return; - if(component is GradientStroke) - { - component.width = component.width * (1.0 - mix) + value * mix; - } - else if(component is RadialGradientStroke) - { - component.width = component.width * (1.0 - mix) + value * mix; - } - else if(component is ColorStroke) - { - component.width = component.width * (1.0 - mix) + value * mix; - } - } + if (component is GradientStroke) { + component.width = component.width * (1.0 - mix) + value * mix; + } + else if (component is RadialGradientStroke) { + component.width = component.width * (1.0 - mix) + value * mix; + } + else if (component is ColorStroke) { + component.width = component.width * (1.0 - mix) + value * mix; + } + } } -class KeyFrameStrokeOpacity extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameStrokeOpacity frame = new KeyFrameStrokeOpacity(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } +class KeyFrameStrokeOpacity extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameStrokeOpacity frame = new KeyFrameStrokeOpacity(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } - void setValue(ActorComponent component, double value, double mix) - { - if(component == null) return; + void setValue(ActorComponent component, double value, double mix) { + if (component == null) return; - if(component is GradientColor) - { - component.opacity = component.opacity * (1.0 - mix) + value * mix; - } - else if(component is ColorStroke) - { - component.opacity = component.opacity * (1.0 - mix) + value * mix; - } - } + if (component is GradientColor) { + component.opacity = component.opacity * (1.0 - mix) + value * mix; + } + else if (component is ColorStroke) { + component.opacity = component.opacity * (1.0 - mix) + value * mix; + } + } } -class KeyFrameInnerRadius extends KeyFrameNumeric -{ - static KeyFrame read(StreamReader reader, ActorComponent component) - { - KeyFrameInnerRadius frame = new KeyFrameInnerRadius(); - if(KeyFrameNumeric.read(reader, frame)) - { - return frame; - } - return null; - } - - void setValue(ActorComponent component, double value, double mix) - { - if(component == null) return; - - ActorStar star = component as ActorStar; - star.innerRadius = star.innerRadius * (1.0-mix) + value*mix; - } +class KeyFrameInnerRadius extends KeyFrameNumeric { + static KeyFrame read(StreamReader reader, ActorComponent component) { + KeyFrameInnerRadius frame = new KeyFrameInnerRadius(); + if (KeyFrameNumeric.read(reader, frame)) { + return frame; + } + return null; + } + + void setValue(ActorComponent component, double value, double mix) { + if (component == null) return; + + ActorStar star = component as ActorStar; + star.innerRadius = star.innerRadius * (1.0 - mix) + value * mix; + } } \ No newline at end of file diff --git a/lib/flare/animation/property_types.dart b/lib/flare/animation/property_types.dart index 42fca78..a410fef 100644 --- a/lib/flare/animation/property_types.dart +++ b/lib/flare/animation/property_types.dart @@ -1,74 +1,73 @@ -class PropertyTypes -{ - static const int Unknown = 0; - static const int PosX = 1; - static const int PosY = 2; - static const int ScaleX = 3; - static const int ScaleY = 4; - static const int Rotation = 5; - static const int Opacity = 6; - static const int DrawOrder = 7; - static const int Length = 8; - static const int VertexDeform = 9; - static const int ConstraintStrength = 10; - static const int Trigger = 11; - static const int IntProperty = 12; - static const int FloatProperty = 13; - static const int StringProperty = 14; - static const int BooleanProperty = 15; - static const int CollisionEnabled = 16; - static const int Sequence = 17; - static const int ActiveChildIndex = 18; - static const int PathVertices = 19; - static const int FillColor = 20; - static const int FillGradient = 21; - static const int FillRadial = 22; - static const int StrokeColor = 23; - static const int StrokeGradient = 24; - static const int StrokeRadial = 25; - static const int StrokeWidth = 26; - static const int StrokeOpacity = 27; - static const int FillOpacity = 28; - static const int ShapeWidth = 29; - static const int ShapeHeight = 30; - static const int CornerRadius = 31; - static const int InnerRadius = 32; +class PropertyTypes { + static const int Unknown = 0; + static const int PosX = 1; + static const int PosY = 2; + static const int ScaleX = 3; + static const int ScaleY = 4; + static const int Rotation = 5; + static const int Opacity = 6; + static const int DrawOrder = 7; + static const int Length = 8; + static const int VertexDeform = 9; + static const int ConstraintStrength = 10; + static const int Trigger = 11; + static const int IntProperty = 12; + static const int FloatProperty = 13; + static const int StringProperty = 14; + static const int BooleanProperty = 15; + static const int CollisionEnabled = 16; + static const int Sequence = 17; + static const int ActiveChildIndex = 18; + static const int PathVertices = 19; + static const int FillColor = 20; + static const int FillGradient = 21; + static const int FillRadial = 22; + static const int StrokeColor = 23; + static const int StrokeGradient = 24; + static const int StrokeRadial = 25; + static const int StrokeWidth = 26; + static const int StrokeOpacity = 27; + static const int FillOpacity = 28; + static const int ShapeWidth = 29; + static const int ShapeHeight = 30; + static const int CornerRadius = 31; + static const int InnerRadius = 32; } -const Map PropertyTypesMap = +const Map PropertyTypesMap = { - - "unknown": PropertyTypes.Unknown, - "posX": PropertyTypes.PosX, - "posY": PropertyTypes.PosY, - "scaleX": PropertyTypes.ScaleX, - "scaleY": PropertyTypes.ScaleY, - "rotation": PropertyTypes.Rotation, - "opacity": PropertyTypes.Opacity, - "drawOrder": PropertyTypes.DrawOrder, - "length": PropertyTypes.Length, - "vertices": PropertyTypes.VertexDeform, - "strength": PropertyTypes.ConstraintStrength, - "trigger": PropertyTypes.Trigger, - "intValue": PropertyTypes.IntProperty, - "floatValue": PropertyTypes.FloatProperty, - "stringValue": PropertyTypes.StringProperty, - "boolValue": PropertyTypes.BooleanProperty, - "isCollisionEnabled": PropertyTypes.CollisionEnabled, - "sequence": PropertyTypes.Sequence, - "activeChild": PropertyTypes.ActiveChildIndex, - "pathVertices": PropertyTypes.PathVertices, - "fillColor": PropertyTypes.FillColor, - "fillGradient": PropertyTypes.FillGradient, - "fillRadial": PropertyTypes.FillRadial, - "strokeColor": PropertyTypes.StrokeColor, - "strokeGradient": PropertyTypes.StrokeGradient, - "strokeRadial": PropertyTypes.StrokeRadial, - "strokeWidth": PropertyTypes.StrokeWidth, - "strokeOpacity": PropertyTypes.StrokeOpacity, - "fillOpacity": PropertyTypes.FillOpacity, - "width": PropertyTypes.ShapeWidth, - "height": PropertyTypes.ShapeHeight, - "cornerRadius": PropertyTypes.CornerRadius, - "innerRadius": PropertyTypes.InnerRadius, + + "unknown": PropertyTypes.Unknown, + "posX": PropertyTypes.PosX, + "posY": PropertyTypes.PosY, + "scaleX": PropertyTypes.ScaleX, + "scaleY": PropertyTypes.ScaleY, + "rotation": PropertyTypes.Rotation, + "opacity": PropertyTypes.Opacity, + "drawOrder": PropertyTypes.DrawOrder, + "length": PropertyTypes.Length, + "vertices": PropertyTypes.VertexDeform, + "strength": PropertyTypes.ConstraintStrength, + "trigger": PropertyTypes.Trigger, + "intValue": PropertyTypes.IntProperty, + "floatValue": PropertyTypes.FloatProperty, + "stringValue": PropertyTypes.StringProperty, + "boolValue": PropertyTypes.BooleanProperty, + "isCollisionEnabled": PropertyTypes.CollisionEnabled, + "sequence": PropertyTypes.Sequence, + "activeChild": PropertyTypes.ActiveChildIndex, + "pathVertices": PropertyTypes.PathVertices, + "fillColor": PropertyTypes.FillColor, + "fillGradient": PropertyTypes.FillGradient, + "fillRadial": PropertyTypes.FillRadial, + "strokeColor": PropertyTypes.StrokeColor, + "strokeGradient": PropertyTypes.StrokeGradient, + "strokeRadial": PropertyTypes.StrokeRadial, + "strokeWidth": PropertyTypes.StrokeWidth, + "strokeOpacity": PropertyTypes.StrokeOpacity, + "fillOpacity": PropertyTypes.FillOpacity, + "width": PropertyTypes.ShapeWidth, + "height": PropertyTypes.ShapeHeight, + "cornerRadius": PropertyTypes.CornerRadius, + "innerRadius": PropertyTypes.InnerRadius, }; \ No newline at end of file diff --git a/lib/flare/binary_reader.dart b/lib/flare/binary_reader.dart index 69c83a1..52bc86e 100644 --- a/lib/flare/binary_reader.dart +++ b/lib/flare/binary_reader.dart @@ -1,217 +1,188 @@ import 'dart:typed_data'; import "stream_reader.dart"; -abstract class BinaryReader implements StreamReader -{ - ByteData _raw; - int _readIndex; - - BinaryReader(ByteData data) - { - _raw = data; - _readIndex = 0; - } - - double readFloat32([String label]) - { - double value = _raw.getFloat32(_readIndex, Endian.little); - _readIndex += 4; - - return value; - } - - Float32List readFloat32ArrayOffset(Float32List list, int length, int offset, [String label]) - { - int end = offset + length; - for (int i = offset; i < end; i++) - { - list[i] = _raw.getFloat32(_readIndex, Endian.little); - _readIndex += 4; - } - return list; - } - - double readFloat64([String label]) - { - double value = _raw.getFloat64(_readIndex, Endian.little); - _readIndex += 8; - - return value; - } - - int readUint8([String label]) - { - return _raw.getUint8(_readIndex++); - } - - bool isEOF() - { - return _readIndex >= _raw.lengthInBytes; - } - - int readInt8([String label]) - { - return _raw.getInt8(_readIndex++); - } - - int readUint16([String label]) - { - int value = _raw.getUint16(_readIndex, Endian.little); - _readIndex += 2; - - return value; - } - - Uint16List readUint16Array(Uint16List list, int length, int offset, [String label]) - { - int end = offset + length; - for (int i = offset; i < end; i++) - { - list[i] = _raw.getUint16(_readIndex, Endian.little); - _readIndex += 2; - } - return list; - } - - int readInt16([String label]) - { - int value = _raw.getInt16(_readIndex, Endian.little); - _readIndex += 2; - - return value; - } - - int readUint32([String label]) - { - int value = _raw.getUint32(_readIndex, Endian.little); - _readIndex += 4; - - return value; - } - - int readInt32([String label]) - { - int value = _raw.getInt32(_readIndex, Endian.little); - _readIndex += 4; - - return value; - } - - String readString([String label]) - { - int length = readUint32(); - int end = _readIndex + length; - StringBuffer stringBuffer = new StringBuffer(); - - while(_readIndex < end) - { - int c1 = readUint8(); - if(c1 < 128) - { - stringBuffer.writeCharCode(c1); - } - else if(c1 > 191 && c1 < 224) - { - int c2 = readUint8(); - stringBuffer.writeCharCode((c1 & 31) << 6 | c2 & 63); - } - else if (c1 > 239 && c1 < 365) - { - int c2 = readUint8(); - int c3 = readUint8(); - int c4 = readUint8(); - int u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) - 0x10000; - stringBuffer.writeCharCode(0xD800 + (u >> 10)); - stringBuffer.writeCharCode(0xDC00 + (u & 1023)); - } - else - { - int c2 = readUint8(); - int c3 = readUint8(); - stringBuffer.writeCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); - } - } - - return stringBuffer.toString(); - } - - @override - Uint8List readUint8Array(Uint8List list, int length, int offset, [String label]) - { - int end = offset + length; - for (int i = offset; i < end; i++) - { - list[i] = _raw.getUint8(_readIndex++); - } - return list; - } - - @override - int readVersion() - { - return this.readUint32(); +abstract class BinaryReader + implements StreamReader { + ByteData _raw; + int _readIndex; + + BinaryReader(ByteData data) { + _raw = data; + _readIndex = 0; + } + + double readFloat32([String label]) { + double value = _raw.getFloat32(_readIndex, Endian.little); + _readIndex += 4; + + return value; + } + + Float32List readFloat32ArrayOffset(Float32List list, int length, int offset, + [String label]) { + int end = offset + length; + for (int i = offset; i < end; i++) { + list[i] = _raw.getFloat32(_readIndex, Endian.little); + _readIndex += 4; } + return list; + } - @override - int readUint8Length() - { - return readUint8(); - } + double readFloat64([String label]) { + double value = _raw.getFloat64(_readIndex, Endian.little); + _readIndex += 8; - @override - int readUint32Length() - { - return readUint32(); - } + return value; + } - @override - int readUint16Length() - { - return readUint16(); - } + int readUint8([String label]) { + return _raw.getUint8(_readIndex++); + } - @override - int readId(String label) - { - return readUint16(label); - } + bool isEOF() { + return _readIndex >= _raw.lengthInBytes; + } - @override - Float32List readFloat32Array(Float32List ar, String label) - { - return readFloat32ArrayOffset(ar, ar.length, 0, label); - } + int readInt8([String label]) { + return _raw.getInt8(_readIndex++); + } - @override - bool readBool(String label) - { - return readUint8(label) == 1; - } + int readUint16([String label]) { + int value = _raw.getUint16(_readIndex, Endian.little); + _readIndex += 2; - @override - openArray(String label) - { - /* NOP */ - } + return value; + } - @override - closeArray() - { - /* NOP */ + Uint16List readUint16Array(Uint16List list, int length, int offset, + [String label]) { + int end = offset + length; + for (int i = offset; i < end; i++) { + list[i] = _raw.getUint16(_readIndex, Endian.little); + _readIndex += 2; } - - @override - openObject(String label) - { - /* NOP */ + return list; + } + + int readInt16([String label]) { + int value = _raw.getInt16(_readIndex, Endian.little); + _readIndex += 2; + + return value; + } + + int readUint32([String label]) { + int value = _raw.getUint32(_readIndex, Endian.little); + _readIndex += 4; + + return value; + } + + int readInt32([String label]) { + int value = _raw.getInt32(_readIndex, Endian.little); + _readIndex += 4; + + return value; + } + + String readString([String label]) { + int length = readUint32(); + int end = _readIndex + length; + StringBuffer stringBuffer = new StringBuffer(); + + while (_readIndex < end) { + int c1 = readUint8(); + if (c1 < 128) { + stringBuffer.writeCharCode(c1); + } + else if (c1 > 191 && c1 < 224) { + int c2 = readUint8(); + stringBuffer.writeCharCode((c1 & 31) << 6 | c2 & 63); + } + else if (c1 > 239 && c1 < 365) { + int c2 = readUint8(); + int c3 = readUint8(); + int c4 = readUint8(); + int u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) - + 0x10000; + stringBuffer.writeCharCode(0xD800 + (u >> 10)); + stringBuffer.writeCharCode(0xDC00 + (u & 1023)); + } + else { + int c2 = readUint8(); + int c3 = readUint8(); + stringBuffer.writeCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63); + } } - @override - closeObject() - { - /* NOP */ - } + return stringBuffer.toString(); + } - @override - String get containerType => "bin"; + @override + Uint8List readUint8Array(Uint8List list, int length, int offset, + [String label]) { + int end = offset + length; + for (int i = offset; i < end; i++) { + list[i] = _raw.getUint8(_readIndex++); + } + return list; + } + + @override + int readVersion() { + return this.readUint32(); + } + + @override + int readUint8Length() { + return readUint8(); + } + + @override + int readUint32Length() { + return readUint32(); + } + + @override + int readUint16Length() { + return readUint16(); + } + + @override + int readId(String label) { + return readUint16(label); + } + + @override + Float32List readFloat32Array(Float32List ar, String label) { + return readFloat32ArrayOffset(ar, ar.length, 0, label); + } + + @override + bool readBool(String label) { + return readUint8(label) == 1; + } + + @override + openArray(String label) { + /* NOP */ + } + + @override + closeArray() { + /* NOP */ + } + + @override + openObject(String label) { + /* NOP */ + } + + @override + closeObject() { + /* NOP */ + } + + @override + String get containerType => "bin"; } \ No newline at end of file diff --git a/lib/flare/block_reader.dart b/lib/flare/block_reader.dart index fd1e30f..7d32273 100644 --- a/lib/flare/block_reader.dart +++ b/lib/flare/block_reader.dart @@ -1,33 +1,30 @@ import "binary_reader.dart"; import 'dart:typed_data'; -class BlockReader extends BinaryReader -{ - @override - int blockType; +class BlockReader extends BinaryReader { + @override + int blockType; - BlockReader(ByteData data) : super(data) - { - blockType = 0; - } + BlockReader(ByteData data) : super(data) { + blockType = 0; + } - BlockReader.fromBlock(int type, ByteData stream) : super(stream) - { - blockType = type; - } + BlockReader.fromBlock(int type, ByteData stream) : super(stream) + { + blockType = type; + } - // A block is defined as a TLV with type of one byte, length of 4 bytes, and then the value following. - BlockReader readNextBlock(Map types) - { - if(isEOF()) - { - return null; - } - int blockType = readUint8(); - int length = readUint32(); + // A block is defined as a TLV with type of one byte, length of 4 bytes, and then the value following. + BlockReader readNextBlock(Map types) { + if (isEOF()) { + return null; + } + int blockType = readUint8(); + int length = readUint32(); - Uint8List buffer = new Uint8List(length); + Uint8List buffer = new Uint8List(length); - return new BlockReader.fromBlock(blockType, new ByteData.view(readUint8Array(buffer, buffer.length, 0).buffer)); - } + return new BlockReader.fromBlock(blockType, + new ByteData.view(readUint8Array(buffer, buffer.length, 0).buffer)); + } } \ No newline at end of file diff --git a/lib/flare/block_types.dart b/lib/flare/block_types.dart index ff147df..786c3d3 100644 --- a/lib/flare/block_types.dart +++ b/lib/flare/block_types.dart @@ -1,101 +1,100 @@ const Map BlockTypesMap = { - "unknown": BlockTypes.Unknown, - "nodes": BlockTypes.Components, - "node": BlockTypes.ActorNode, - "bone": BlockTypes.ActorBone, - "rootBone": BlockTypes.ActorRootBone, - "image": BlockTypes.ActorImage, - "view": BlockTypes.View, - "animation": BlockTypes.Animation, - "animations": BlockTypes.Animations, - "atlases": BlockTypes.Atlases, - "atlas": BlockTypes.Atlas, - "event": BlockTypes.ActorEvent, - "customInt": BlockTypes.CustomIntProperty, - "customFloat": BlockTypes.CustomFloatProperty, - "customString": BlockTypes.CustomStringProperty, - "customBoolean": BlockTypes.CustomBooleanProperty, - "rectangleCollider": BlockTypes.ActorColliderRectangle, - "triangleCollider": BlockTypes.ActorColliderTriangle, - "circleCollider": BlockTypes.ActorColliderCircle, - "polygonCollider": BlockTypes.ActorColliderPolygon, - "lineCollider": BlockTypes.ActorColliderLine, - "imageSequence": BlockTypes.ActorImageSequence, - "solo": BlockTypes.ActorNodeSolo, - "jelly": BlockTypes.JellyComponent, - "jellyBone": BlockTypes.ActorJellyBone, - "ikConstraint": BlockTypes.ActorIKConstraint, - "distanceConstraint": BlockTypes.ActorDistanceConstraint, - "translationConstraint": BlockTypes.ActorTranslationConstraint, - "rotationConstraint": BlockTypes.ActorRotationConstraint, - "scaleConstraint": BlockTypes.ActorScaleConstraint, - "transformConstraint": BlockTypes.ActorTransformConstraint, - "shape": BlockTypes.ActorShape, - "path": BlockTypes.ActorPath, - "colorFill": BlockTypes.ColorFill, - "colorStroke": BlockTypes.ColorStroke, - "gradientFill": BlockTypes.GradientFill, - "gradientStroke": BlockTypes.GradientStroke, - "radialGradientFill": BlockTypes.RadialGradientFill, - "radialGradientStroke": BlockTypes.RadialGradientStroke, - "ellipse": BlockTypes.ActorEllipse, - "rectangle": BlockTypes.ActorRectangle, - "triangle": BlockTypes.ActorTriangle, - "star": BlockTypes.ActorStar, - "polygon": BlockTypes.ActorPolygon, - "artboards": BlockTypes.Artboards, - "artboard": BlockTypes.ActorArtboard + "unknown": BlockTypes.Unknown, + "nodes": BlockTypes.Components, + "node": BlockTypes.ActorNode, + "bone": BlockTypes.ActorBone, + "rootBone": BlockTypes.ActorRootBone, + "image": BlockTypes.ActorImage, + "view": BlockTypes.View, + "animation": BlockTypes.Animation, + "animations": BlockTypes.Animations, + "atlases": BlockTypes.Atlases, + "atlas": BlockTypes.Atlas, + "event": BlockTypes.ActorEvent, + "customInt": BlockTypes.CustomIntProperty, + "customFloat": BlockTypes.CustomFloatProperty, + "customString": BlockTypes.CustomStringProperty, + "customBoolean": BlockTypes.CustomBooleanProperty, + "rectangleCollider": BlockTypes.ActorColliderRectangle, + "triangleCollider": BlockTypes.ActorColliderTriangle, + "circleCollider": BlockTypes.ActorColliderCircle, + "polygonCollider": BlockTypes.ActorColliderPolygon, + "lineCollider": BlockTypes.ActorColliderLine, + "imageSequence": BlockTypes.ActorImageSequence, + "solo": BlockTypes.ActorNodeSolo, + "jelly": BlockTypes.JellyComponent, + "jellyBone": BlockTypes.ActorJellyBone, + "ikConstraint": BlockTypes.ActorIKConstraint, + "distanceConstraint": BlockTypes.ActorDistanceConstraint, + "translationConstraint": BlockTypes.ActorTranslationConstraint, + "rotationConstraint": BlockTypes.ActorRotationConstraint, + "scaleConstraint": BlockTypes.ActorScaleConstraint, + "transformConstraint": BlockTypes.ActorTransformConstraint, + "shape": BlockTypes.ActorShape, + "path": BlockTypes.ActorPath, + "colorFill": BlockTypes.ColorFill, + "colorStroke": BlockTypes.ColorStroke, + "gradientFill": BlockTypes.GradientFill, + "gradientStroke": BlockTypes.GradientStroke, + "radialGradientFill": BlockTypes.RadialGradientFill, + "radialGradientStroke": BlockTypes.RadialGradientStroke, + "ellipse": BlockTypes.ActorEllipse, + "rectangle": BlockTypes.ActorRectangle, + "triangle": BlockTypes.ActorTriangle, + "star": BlockTypes.ActorStar, + "polygon": BlockTypes.ActorPolygon, + "artboards": BlockTypes.Artboards, + "artboard": BlockTypes.ActorArtboard }; -class BlockTypes -{ - static const int Unknown = 0; - static const int Components = 1; - static const int ActorNode = 2; - static const int ActorBone = 3; - static const int ActorRootBone = 4; - static const int ActorImage = 5; - static const int View = 6; - static const int Animation = 7; - static const int Animations = 8; - static const int Atlases = 9; - static const int Atlas = 10; - static const int ActorIKTarget = 11; - static const int ActorEvent = 12; - static const int CustomIntProperty = 13; - static const int CustomFloatProperty = 14; - static const int CustomStringProperty = 15; - static const int CustomBooleanProperty = 16; - static const int ActorColliderRectangle = 17; - static const int ActorColliderTriangle = 18; - static const int ActorColliderCircle = 19; - static const int ActorColliderPolygon = 20; - static const int ActorColliderLine = 21; - static const int ActorImageSequence = 22; - static const int ActorNodeSolo = 23; - static const int JellyComponent = 28; - static const int ActorJellyBone = 29; - static const int ActorIKConstraint = 30; - static const int ActorDistanceConstraint = 31; - static const int ActorTranslationConstraint = 32; - static const int ActorRotationConstraint = 33; - static const int ActorScaleConstraint = 34; - static const int ActorTransformConstraint = 35; - static const int ActorShape = 100; - static const int ActorPath = 101; - static const int ColorFill = 102; - static const int ColorStroke = 103; - static const int GradientFill = 104; - static const int GradientStroke = 105; - static const int RadialGradientFill = 106; - static const int RadialGradientStroke = 107; - static const int ActorEllipse = 108; - static const int ActorRectangle = 109; - static const int ActorTriangle = 110; - static const int ActorStar = 111; - static const int ActorPolygon = 112; - static const int ActorSkin = 113; - static const int ActorArtboard = 114; - static const int Artboards = 115; +class BlockTypes { + static const int Unknown = 0; + static const int Components = 1; + static const int ActorNode = 2; + static const int ActorBone = 3; + static const int ActorRootBone = 4; + static const int ActorImage = 5; + static const int View = 6; + static const int Animation = 7; + static const int Animations = 8; + static const int Atlases = 9; + static const int Atlas = 10; + static const int ActorIKTarget = 11; + static const int ActorEvent = 12; + static const int CustomIntProperty = 13; + static const int CustomFloatProperty = 14; + static const int CustomStringProperty = 15; + static const int CustomBooleanProperty = 16; + static const int ActorColliderRectangle = 17; + static const int ActorColliderTriangle = 18; + static const int ActorColliderCircle = 19; + static const int ActorColliderPolygon = 20; + static const int ActorColliderLine = 21; + static const int ActorImageSequence = 22; + static const int ActorNodeSolo = 23; + static const int JellyComponent = 28; + static const int ActorJellyBone = 29; + static const int ActorIKConstraint = 30; + static const int ActorDistanceConstraint = 31; + static const int ActorTranslationConstraint = 32; + static const int ActorRotationConstraint = 33; + static const int ActorScaleConstraint = 34; + static const int ActorTransformConstraint = 35; + static const int ActorShape = 100; + static const int ActorPath = 101; + static const int ColorFill = 102; + static const int ColorStroke = 103; + static const int GradientFill = 104; + static const int GradientStroke = 105; + static const int RadialGradientFill = 106; + static const int RadialGradientStroke = 107; + static const int ActorEllipse = 108; + static const int ActorRectangle = 109; + static const int ActorTriangle = 110; + static const int ActorStar = 111; + static const int ActorPolygon = 112; + static const int ActorSkin = 113; + static const int ActorArtboard = 114; + static const int Artboards = 115; } \ No newline at end of file diff --git a/lib/flare/dependency_sorter.dart b/lib/flare/dependency_sorter.dart index fbe6d1a..f1badea 100644 --- a/lib/flare/dependency_sorter.dart +++ b/lib/flare/dependency_sorter.dart @@ -1,56 +1,46 @@ import "dart:collection"; import "actor_component.dart"; -class DependencySorter -{ - HashSet _perm; - HashSet _temp; - List _order; +class DependencySorter { + HashSet _perm; + HashSet _temp; + List _order; - DependencySorter() - { - _perm = new HashSet(); - _temp = new HashSet(); - } + DependencySorter() { + _perm = new HashSet(); + _temp = new HashSet(); + } - List sort(ActorComponent root) - { - _order = new List(); - if(!visit(root)) - { - return null; - } - return _order; - } + List sort(ActorComponent root) { + _order = new List(); + if (!visit(root)) { + return null; + } + return _order; + } - bool visit(ActorComponent n) - { - if(_perm.contains(n)) - { - return true; - } - if(_temp.contains(n)) - { - print("Dependency cycle!"); - return false; - } + bool visit(ActorComponent n) { + if (_perm.contains(n)) { + return true; + } + if (_temp.contains(n)) { + print("Dependency cycle!"); + return false; + } - _temp.add(n); + _temp.add(n); - List dependents = n.dependents; - if(dependents != null) - { - for(ActorComponent d in dependents) - { - if(!visit(d)) - { - return false; - } - } - } - _perm.add(n); - _order.insert(0, n); + List dependents = n.dependents; + if (dependents != null) { + for (ActorComponent d in dependents) { + if (!visit(d)) { + return false; + } + } + } + _perm.add(n); + _order.insert(0, n); - return true; - } + return true; + } } \ No newline at end of file diff --git a/lib/flare/jelly_component.dart b/lib/flare/jelly_component.dart index 613d9f4..a47cbe5 100644 --- a/lib/flare/jelly_component.dart +++ b/lib/flare/jelly_component.dart @@ -10,423 +10,408 @@ import "dart:math"; import "actor_root_bone.dart"; import "actor_constraint.dart"; -class JellyComponent extends ActorComponent -{ - static const int JellyMax = 16; - static double OptimalDistance = 4.0*(sqrt(2.0)-1.0)/3.0; - static double CurveConstant = OptimalDistance * sqrt(2.0) * 0.5; - static const double Epsilon = 0.001; // Intentionally agressive. - - static bool fuzzyEquals(Vec2D a, Vec2D b) - { - double a0 = a[0], a1 = a[1]; - double b0 = b[0], b1 = b[1]; - return ((a0 - b0).abs() <= Epsilon*max(1.0, max(a0.abs(),b0.abs())) && - (a1 - b1).abs() <= Epsilon*max(1.0, max(a1.abs(), b1.abs()))); - } - - static void forwardDiffBezier(double c0, double c1, double c2, double c3, List points, int count, int offset) - { - double f = count.toDouble(); - - double p0 = c0; - - double p1 = 3.0 * (c1 - c0) / f; - - f *= count; - double p2 = 3.0 * (c0 - 2.0 * c1 + c2) / f; - - f *= count; - double p3 = (c3 - c0 + 3.0 * (c1 - c2)) / f; - - c0 = p0; - c1 = p1 + p2 + p3; - c2 = 2 * p2 + 6 * p3; - c3 = 6 * p3; - - for (int a = 0; a <= count; a++) - { - points[a][offset] = c0; - c0 += c1; - c1 += c2; - c2 += c3; - } - } - - List normalizeCurve(List curve, int numSegments) - { - List points = new List(); - int curvePointCount = curve.length; - List distances = new List(curvePointCount); - distances[0] = 0.0; - for(int i = 0; i < curvePointCount-1; i++) - { - Vec2D p1 = curve[i]; - Vec2D p2 = curve[i+1]; - distances[i + 1] = distances[i] + Vec2D.distance(p1, p2); - } - double totalDistance = distances[curvePointCount-1]; - - double segmentLength = totalDistance/numSegments; - int pointIndex = 1; - for(int i = 1; i <= numSegments; i++) - { - double distance = segmentLength * i; - - while(pointIndex < curvePointCount-1 && distances[pointIndex] < distance) - { - pointIndex++; - } - - double d = distances[pointIndex]; - double lastCurveSegmentLength = d - distances[pointIndex-1]; - double remainderOfDesired = d - distance; - double ratio = remainderOfDesired / lastCurveSegmentLength; - double iratio = 1.0-ratio; - - Vec2D p1 = curve[pointIndex-1]; - Vec2D p2 = curve[pointIndex]; - points.add(new Vec2D.fromValues(p1[0]*ratio+p2[0]*iratio, p1[1]*ratio+p2[1]*iratio)); - } - - return points; - } - - double _easeIn; - double _easeOut; - double _scaleIn; - double _scaleOut; - int _inTargetIdx; - int _outTargetIdx; - ActorNode _inTarget; - ActorNode _outTarget; - List _bones; - Vec2D _inPoint; - Vec2D _inDirection; - Vec2D _outPoint; - Vec2D _outDirection; - - Vec2D _cachedTip; - Vec2D _cachedOut; - Vec2D _cachedIn; - double _cachedScaleIn; - double _cachedScaleOut; - - List _jellyPoints; - - ActorNode get inTarget => _inTarget; - ActorNode get outTarget => _inTarget; - - JellyComponent() - { - _inPoint = new Vec2D(); - _inDirection = new Vec2D(); - _outPoint = new Vec2D(); - _outDirection = new Vec2D(); - _cachedTip = new Vec2D(); - _cachedOut = new Vec2D(); - _cachedIn = new Vec2D(); - - _jellyPoints = new List(JellyMax+1); - for(var i = 0; i <= JellyMax; i++) - { - _jellyPoints[i] = new Vec2D(); - } - } - ActorComponent makeInstance(ActorArtboard artboard) - { - JellyComponent instance = new JellyComponent(); - instance.copyJelly(this, artboard); - return instance; - } - - void copyJelly(JellyComponent component, ActorArtboard artboard) - { - super.copyComponent(component, artboard); - _easeIn = component._easeIn; - _easeOut = component._easeOut; - _scaleIn = component._scaleIn; - _scaleOut = component._scaleOut; - _inTargetIdx = component._inTargetIdx; - _outTargetIdx = component._outTargetIdx; - - } - - void resolveComponentIndices(List components) - { - super.resolveComponentIndices(components); - - if(_inTargetIdx != 0) - { - _inTarget = components[_inTargetIdx] as ActorNode; - } - if(_outTargetIdx != 0) - { - _outTarget = components[_outTargetIdx] as ActorNode; - } - - List dependencyConstraints = []; - ActorBone bone = parent as ActorBone; - if(bone != null) - { - artboard.addDependency(this, bone); - dependencyConstraints += bone.allConstraints; - ActorBone firstBone = bone.firstBone; - if(firstBone != null) - { - artboard.addDependency(this, firstBone); - dependencyConstraints += firstBone.allConstraints; - - // If we don't have an out target and the child jelly does have an in target - // we are dependent on that target's position. - if(_outTarget == null && firstBone.jelly != null && firstBone.jelly.inTarget != null) - { - artboard.addDependency(this, firstBone.jelly.inTarget); - dependencyConstraints += firstBone.jelly.inTarget.allConstraints; - } - } - if(bone.parent is ActorBone) - { - ActorBone parentBone = bone.parent; - JellyComponent parentBoneJelly = parentBone.jelly; - if(parentBoneJelly != null && parentBoneJelly.outTarget != null) - { - artboard.addDependency(this, parentBoneJelly.outTarget); - dependencyConstraints += parentBoneJelly.outTarget.allConstraints; - } - } - } - - if(_inTarget != null) - { - artboard.addDependency(this, _inTarget); - dependencyConstraints += _inTarget.allConstraints; - } - if(_outTarget != null) - { - artboard.addDependency(this, _outTarget); - dependencyConstraints += _outTarget.allConstraints; - } - - // We want to depend on any and all constraints that our dependents have. - Set constraints = new Set.from(dependencyConstraints); - for(ActorConstraint constraint in constraints) - { - artboard.addDependency(this, constraint); - } - } - - void completeResolve() - { - //super.completeResolve(); - ActorBone bone = parent as ActorBone; - bone.jelly = this; - - // Get jellies. - List children = bone.children; - if(children == null) - { - return; - } - - _bones = new List(); - for(ActorNode child in children) - { - if(child is ActorJellyBone) - { - _bones.add(child); - // Make sure the jelly doesn't update until the jelly component has updated - artboard.addDependency(child, this); - } - } - } - - static JellyComponent read(ActorArtboard artboard, StreamReader reader, JellyComponent node) - { - if(node == null) - { - node = new JellyComponent(); - } - ActorComponent.read(artboard, reader, node); - - node._easeIn = reader.readFloat32("easeIn"); - node._easeOut = reader.readFloat32("easeOut"); - node._scaleIn = reader.readFloat32("scaleIn"); - node._scaleOut = reader.readFloat32("scaleOut"); - node._inTargetIdx = reader.readId("inTargetId"); - node._outTargetIdx = reader.readId("outTargetId"); - - return node; - } - - void updateJellies() - { - if(_bones == null) - { - return; - } - ActorBone bone = parent as ActorBone; - // We are in local bone space. - Vec2D tipPosition = new Vec2D.fromValues(bone.length, 0.0); - - if(fuzzyEquals(_cachedTip, tipPosition) && fuzzyEquals(_cachedOut, _outPoint) && fuzzyEquals(_cachedIn, _inPoint) && _cachedScaleIn == _scaleIn && _cachedScaleOut == _scaleOut) - { - return; - } - - Vec2D.copy(_cachedTip, tipPosition); - Vec2D.copy(_cachedOut, _outPoint); - Vec2D.copy(_cachedIn, _inPoint); - _cachedScaleIn = _scaleIn; - _cachedScaleOut = _scaleOut; - - Vec2D q0 = new Vec2D(); - Vec2D q1 = _inPoint; - Vec2D q2 = _outPoint; - Vec2D q3 = tipPosition; - - forwardDiffBezier(q0[0], q1[0], q2[0], q3[0], _jellyPoints, JellyMax, 0); - forwardDiffBezier(q0[1], q1[1], q2[1], q3[1], _jellyPoints, JellyMax, 1); - - List normalizedPoints = normalizeCurve(_jellyPoints, _bones.length); - - Vec2D lastPoint = _jellyPoints[0]; - - double scale = _scaleIn; - double scaleInc = (_scaleOut - _scaleIn)/(_bones.length-1); - for(int i = 0; i < normalizedPoints.length; i++) - { - ActorJellyBone jelly = _bones[i]; - Vec2D p = normalizedPoints[i]; - - jelly.translation = lastPoint; - jelly.length = Vec2D.distance(p, lastPoint); - jelly.scaleY = scale; - scale += scaleInc; - - Vec2D diff = Vec2D.subtract(new Vec2D(), p, lastPoint); - jelly.rotation = atan2(diff[1], diff[0]); - lastPoint = p; - } - } - - @override - void onDirty(int dirt) - { - // Intentionally empty. Doesn't throw dirt around. - } - - @override - void update(int dirt) - { - ActorBone bone = parent as ActorBone; - ActorNode parentBone = bone.parent; - JellyComponent parentBoneJelly; - if(parentBone is ActorBone) - { - parentBoneJelly = parentBone.jelly; - } - - Mat2D inverseWorld = new Mat2D(); - if(!Mat2D.invert(inverseWorld, bone.worldTransform)) - { - return; - } - - if(_inTarget != null) - { - Vec2D translation = _inTarget.getWorldTranslation(new Vec2D()); - Vec2D.transformMat2D(_inPoint, translation, inverseWorld); - Vec2D.normalize(_inDirection, _inPoint); - } - else if(parentBone != null) - { - ActorBone firstBone; - if(parentBone is ActorBone) - { - firstBone = parentBone.firstBone; - } - else if(parentBone is ActorRootBone) - { - firstBone = parentBone.firstBone; - } - if(firstBone == bone && parentBoneJelly != null && parentBoneJelly._outTarget != null) - { - Vec2D translation = parentBoneJelly._outTarget.getWorldTranslation(new Vec2D()); - Vec2D localParentOut = Vec2D.transformMat2D(new Vec2D(), translation, inverseWorld); - Vec2D.normalize(localParentOut, localParentOut); - Vec2D.negate(_inDirection, localParentOut); - } - else - { - Vec2D d1 = new Vec2D.fromValues(1.0, 0.0); - Vec2D d2 = new Vec2D.fromValues(1.0, 0.0); - - Vec2D.transformMat2(d1, d1, parentBone.worldTransform); - Vec2D.transformMat2(d2, d2, bone.worldTransform); - - Vec2D sum = Vec2D.add(new Vec2D(), d1, d2); - Vec2D.transformMat2(_inDirection, sum, inverseWorld); - Vec2D.normalize(_inDirection, _inDirection); - } - _inPoint[0] = _inDirection[0] * _easeIn * bone.length * CurveConstant; - _inPoint[1] = _inDirection[1] * _easeIn * bone.length * CurveConstant; - } - else - { - _inDirection[0] = 1.0; - _inDirection[1] = 0.0; - _inPoint[0] = _inDirection[0] * _easeIn * bone.length * CurveConstant; - } - - if(_outTarget != null) - { - Vec2D translation = _outTarget.getWorldTranslation(new Vec2D()); - Vec2D.transformMat2D(_outPoint, translation, inverseWorld); - Vec2D tip = new Vec2D.fromValues(bone.length, 0.0); - Vec2D.subtract(_outDirection, _outPoint, tip); - Vec2D.normalize(_outDirection, _outDirection); - } - else if(bone.firstBone != null) - { - ActorBone firstBone = bone.firstBone; - JellyComponent firstBoneJelly = firstBone.jelly; - if(firstBoneJelly != null && firstBoneJelly._inTarget != null) - { - Vec2D translation = firstBoneJelly._inTarget.getWorldTranslation(new Vec2D()); - Vec2D worldChildInDir = Vec2D.subtract(new Vec2D(), firstBone.getWorldTranslation(new Vec2D()), translation); - Vec2D.transformMat2(_outDirection, worldChildInDir, inverseWorld); - } - else - { - Vec2D d1 = new Vec2D.fromValues(1.0, 0.0); - Vec2D d2 = new Vec2D.fromValues(1.0, 0.0); - - Vec2D.transformMat2(d1, d1, firstBone.worldTransform); - Vec2D.transformMat2(d2, d2, bone.worldTransform); - - Vec2D sum = Vec2D.add(new Vec2D(), d1, d2); - Vec2D negativeSum = Vec2D.negate(new Vec2D(), sum); - Vec2D.transformMat2(_outDirection, negativeSum, inverseWorld); - Vec2D.normalize(_outDirection, _outDirection); - } - Vec2D.normalize(_outDirection, _outDirection); - Vec2D scaledOut = Vec2D.scale(new Vec2D(), _outDirection, _easeOut*bone.length*CurveConstant); - _outPoint[0] = bone.length; - _outPoint[1] = 0.0; - Vec2D.add(_outPoint, _outPoint, scaledOut); - } - else - { - _outDirection[0] = -1.0; - _outDirection[1] = 0.0; - - Vec2D scaledOut = Vec2D.scale(new Vec2D(), _outDirection, _easeOut*bone.length*CurveConstant); - _outPoint[0] = bone.length; - _outPoint[1] = 0.0; - Vec2D.add(_outPoint, _outPoint, scaledOut); - } - - updateJellies(); - } +class JellyComponent extends ActorComponent { + static const int JellyMax = 16; + static double OptimalDistance = 4.0 * (sqrt(2.0) - 1.0) / 3.0; + static double CurveConstant = OptimalDistance * sqrt(2.0) * 0.5; + static const double Epsilon = 0.001; // Intentionally agressive. + + static bool fuzzyEquals(Vec2D a, Vec2D b) { + double a0 = a[0], + a1 = a[1]; + double b0 = b[0], + b1 = b[1]; + return ((a0 - b0).abs() <= Epsilon * max(1.0, max(a0.abs(), b0.abs())) && + (a1 - b1).abs() <= Epsilon * max(1.0, max(a1.abs(), b1.abs()))); + } + + static void forwardDiffBezier(double c0, double c1, double c2, double c3, + List points, int count, int offset) { + double f = count.toDouble(); + + double p0 = c0; + + double p1 = 3.0 * (c1 - c0) / f; + + f *= count; + double p2 = 3.0 * (c0 - 2.0 * c1 + c2) / f; + + f *= count; + double p3 = (c3 - c0 + 3.0 * (c1 - c2)) / f; + + c0 = p0; + c1 = p1 + p2 + p3; + c2 = 2 * p2 + 6 * p3; + c3 = 6 * p3; + + for (int a = 0; a <= count; a++) { + points[a][offset] = c0; + c0 += c1; + c1 += c2; + c2 += c3; + } + } + + List normalizeCurve(List curve, int numSegments) { + List points = new List(); + int curvePointCount = curve.length; + List distances = new List(curvePointCount); + distances[0] = 0.0; + for (int i = 0; i < curvePointCount - 1; i++) { + Vec2D p1 = curve[i]; + Vec2D p2 = curve[i + 1]; + distances[i + 1] = distances[i] + Vec2D.distance(p1, p2); + } + double totalDistance = distances[curvePointCount - 1]; + + double segmentLength = totalDistance / numSegments; + int pointIndex = 1; + for (int i = 1; i <= numSegments; i++) { + double distance = segmentLength * i; + + while (pointIndex < curvePointCount - 1 && + distances[pointIndex] < distance) { + pointIndex++; + } + + double d = distances[pointIndex]; + double lastCurveSegmentLength = d - distances[pointIndex - 1]; + double remainderOfDesired = d - distance; + double ratio = remainderOfDesired / lastCurveSegmentLength; + double iratio = 1.0 - ratio; + + Vec2D p1 = curve[pointIndex - 1]; + Vec2D p2 = curve[pointIndex]; + points.add(new Vec2D.fromValues( + p1[0] * ratio + p2[0] * iratio, p1[1] * ratio + p2[1] * iratio)); + } + + return points; + } + + double _easeIn; + double _easeOut; + double _scaleIn; + double _scaleOut; + int _inTargetIdx; + int _outTargetIdx; + ActorNode _inTarget; + ActorNode _outTarget; + List _bones; + Vec2D _inPoint; + Vec2D _inDirection; + Vec2D _outPoint; + Vec2D _outDirection; + + Vec2D _cachedTip; + Vec2D _cachedOut; + Vec2D _cachedIn; + double _cachedScaleIn; + double _cachedScaleOut; + + List _jellyPoints; + + ActorNode get inTarget => _inTarget; + + ActorNode get outTarget => _inTarget; + + JellyComponent() { + _inPoint = new Vec2D(); + _inDirection = new Vec2D(); + _outPoint = new Vec2D(); + _outDirection = new Vec2D(); + _cachedTip = new Vec2D(); + _cachedOut = new Vec2D(); + _cachedIn = new Vec2D(); + + _jellyPoints = new List(JellyMax + 1); + for (var i = 0; i <= JellyMax; i++) { + _jellyPoints[i] = new Vec2D(); + } + } + + ActorComponent makeInstance(ActorArtboard artboard) { + JellyComponent instance = new JellyComponent(); + instance.copyJelly(this, artboard); + return instance; + } + + void copyJelly(JellyComponent component, ActorArtboard artboard) { + super.copyComponent(component, artboard); + _easeIn = component._easeIn; + _easeOut = component._easeOut; + _scaleIn = component._scaleIn; + _scaleOut = component._scaleOut; + _inTargetIdx = component._inTargetIdx; + _outTargetIdx = component._outTargetIdx; + } + + void resolveComponentIndices(List components) { + super.resolveComponentIndices(components); + + if (_inTargetIdx != 0) { + _inTarget = components[_inTargetIdx] as ActorNode; + } + if (_outTargetIdx != 0) { + _outTarget = components[_outTargetIdx] as ActorNode; + } + + List dependencyConstraints = []; + ActorBone bone = parent as ActorBone; + if (bone != null) { + artboard.addDependency(this, bone); + dependencyConstraints += bone.allConstraints; + ActorBone firstBone = bone.firstBone; + if (firstBone != null) { + artboard.addDependency(this, firstBone); + dependencyConstraints += firstBone.allConstraints; + + // If we don't have an out target and the child jelly does have an in target + // we are dependent on that target's position. + if (_outTarget == null && firstBone.jelly != null && + firstBone.jelly.inTarget != null) { + artboard.addDependency(this, firstBone.jelly.inTarget); + dependencyConstraints += firstBone.jelly.inTarget.allConstraints; + } + } + if (bone.parent is ActorBone) { + ActorBone parentBone = bone.parent; + JellyComponent parentBoneJelly = parentBone.jelly; + if (parentBoneJelly != null && parentBoneJelly.outTarget != null) { + artboard.addDependency(this, parentBoneJelly.outTarget); + dependencyConstraints += parentBoneJelly.outTarget.allConstraints; + } + } + } + + if (_inTarget != null) { + artboard.addDependency(this, _inTarget); + dependencyConstraints += _inTarget.allConstraints; + } + if (_outTarget != null) { + artboard.addDependency(this, _outTarget); + dependencyConstraints += _outTarget.allConstraints; + } + + // We want to depend on any and all constraints that our dependents have. + Set constraints = new Set.from( + dependencyConstraints); + for (ActorConstraint constraint in constraints) { + artboard.addDependency(this, constraint); + } + } + + void completeResolve() { + //super.completeResolve(); + ActorBone bone = parent as ActorBone; + bone.jelly = this; + + // Get jellies. + List children = bone.children; + if (children == null) { + return; + } + + _bones = new List(); + for (ActorNode child in children) { + if (child is ActorJellyBone) { + _bones.add(child); + // Make sure the jelly doesn't update until the jelly component has updated + artboard.addDependency(child, this); + } + } + } + + static JellyComponent read(ActorArtboard artboard, StreamReader reader, + JellyComponent node) { + if (node == null) { + node = new JellyComponent(); + } + ActorComponent.read(artboard, reader, node); + + node._easeIn = reader.readFloat32("easeIn"); + node._easeOut = reader.readFloat32("easeOut"); + node._scaleIn = reader.readFloat32("scaleIn"); + node._scaleOut = reader.readFloat32("scaleOut"); + node._inTargetIdx = reader.readId("inTargetId"); + node._outTargetIdx = reader.readId("outTargetId"); + + return node; + } + + void updateJellies() { + if (_bones == null) { + return; + } + ActorBone bone = parent as ActorBone; + // We are in local bone space. + Vec2D tipPosition = new Vec2D.fromValues(bone.length, 0.0); + + if (fuzzyEquals(_cachedTip, tipPosition) && + fuzzyEquals(_cachedOut, _outPoint) && + fuzzyEquals(_cachedIn, _inPoint) && _cachedScaleIn == _scaleIn && + _cachedScaleOut == _scaleOut) { + return; + } + + Vec2D.copy(_cachedTip, tipPosition); + Vec2D.copy(_cachedOut, _outPoint); + Vec2D.copy(_cachedIn, _inPoint); + _cachedScaleIn = _scaleIn; + _cachedScaleOut = _scaleOut; + + Vec2D q0 = new Vec2D(); + Vec2D q1 = _inPoint; + Vec2D q2 = _outPoint; + Vec2D q3 = tipPosition; + + forwardDiffBezier( + q0[0], + q1[0], + q2[0], + q3[0], + _jellyPoints, + JellyMax, + 0); + forwardDiffBezier( + q0[1], + q1[1], + q2[1], + q3[1], + _jellyPoints, + JellyMax, + 1); + + List normalizedPoints = normalizeCurve(_jellyPoints, _bones.length); + + Vec2D lastPoint = _jellyPoints[0]; + + double scale = _scaleIn; + double scaleInc = (_scaleOut - _scaleIn) / (_bones.length - 1); + for (int i = 0; i < normalizedPoints.length; i++) { + ActorJellyBone jelly = _bones[i]; + Vec2D p = normalizedPoints[i]; + + jelly.translation = lastPoint; + jelly.length = Vec2D.distance(p, lastPoint); + jelly.scaleY = scale; + scale += scaleInc; + + Vec2D diff = Vec2D.subtract(new Vec2D(), p, lastPoint); + jelly.rotation = atan2(diff[1], diff[0]); + lastPoint = p; + } + } + + @override + void onDirty(int dirt) { + // Intentionally empty. Doesn't throw dirt around. + } + + @override + void update(int dirt) { + ActorBone bone = parent as ActorBone; + ActorNode parentBone = bone.parent; + JellyComponent parentBoneJelly; + if (parentBone is ActorBone) { + parentBoneJelly = parentBone.jelly; + } + + Mat2D inverseWorld = new Mat2D(); + if (!Mat2D.invert(inverseWorld, bone.worldTransform)) { + return; + } + + if (_inTarget != null) { + Vec2D translation = _inTarget.getWorldTranslation(new Vec2D()); + Vec2D.transformMat2D(_inPoint, translation, inverseWorld); + Vec2D.normalize(_inDirection, _inPoint); + } + else if (parentBone != null) { + ActorBone firstBone; + if (parentBone is ActorBone) { + firstBone = parentBone.firstBone; + } + else if (parentBone is ActorRootBone) { + firstBone = parentBone.firstBone; + } + if (firstBone == bone && parentBoneJelly != null && + parentBoneJelly._outTarget != null) { + Vec2D translation = parentBoneJelly._outTarget.getWorldTranslation( + new Vec2D()); + Vec2D localParentOut = Vec2D.transformMat2D( + new Vec2D(), translation, inverseWorld); + Vec2D.normalize(localParentOut, localParentOut); + Vec2D.negate(_inDirection, localParentOut); + } + else { + Vec2D d1 = new Vec2D.fromValues(1.0, 0.0); + Vec2D d2 = new Vec2D.fromValues(1.0, 0.0); + + Vec2D.transformMat2(d1, d1, parentBone.worldTransform); + Vec2D.transformMat2(d2, d2, bone.worldTransform); + + Vec2D sum = Vec2D.add(new Vec2D(), d1, d2); + Vec2D.transformMat2(_inDirection, sum, inverseWorld); + Vec2D.normalize(_inDirection, _inDirection); + } + _inPoint[0] = _inDirection[0] * _easeIn * bone.length * CurveConstant; + _inPoint[1] = _inDirection[1] * _easeIn * bone.length * CurveConstant; + } + else { + _inDirection[0] = 1.0; + _inDirection[1] = 0.0; + _inPoint[0] = _inDirection[0] * _easeIn * bone.length * CurveConstant; + } + + if (_outTarget != null) { + Vec2D translation = _outTarget.getWorldTranslation(new Vec2D()); + Vec2D.transformMat2D(_outPoint, translation, inverseWorld); + Vec2D tip = new Vec2D.fromValues(bone.length, 0.0); + Vec2D.subtract(_outDirection, _outPoint, tip); + Vec2D.normalize(_outDirection, _outDirection); + } + else if (bone.firstBone != null) { + ActorBone firstBone = bone.firstBone; + JellyComponent firstBoneJelly = firstBone.jelly; + if (firstBoneJelly != null && firstBoneJelly._inTarget != null) { + Vec2D translation = firstBoneJelly._inTarget.getWorldTranslation( + new Vec2D()); + Vec2D worldChildInDir = Vec2D.subtract( + new Vec2D(), firstBone.getWorldTranslation(new Vec2D()), + translation); + Vec2D.transformMat2(_outDirection, worldChildInDir, inverseWorld); + } + else { + Vec2D d1 = new Vec2D.fromValues(1.0, 0.0); + Vec2D d2 = new Vec2D.fromValues(1.0, 0.0); + + Vec2D.transformMat2(d1, d1, firstBone.worldTransform); + Vec2D.transformMat2(d2, d2, bone.worldTransform); + + Vec2D sum = Vec2D.add(new Vec2D(), d1, d2); + Vec2D negativeSum = Vec2D.negate(new Vec2D(), sum); + Vec2D.transformMat2(_outDirection, negativeSum, inverseWorld); + Vec2D.normalize(_outDirection, _outDirection); + } + Vec2D.normalize(_outDirection, _outDirection); + Vec2D scaledOut = Vec2D.scale( + new Vec2D(), _outDirection, _easeOut * bone.length * CurveConstant); + _outPoint[0] = bone.length; + _outPoint[1] = 0.0; + Vec2D.add(_outPoint, _outPoint, scaledOut); + } + else { + _outDirection[0] = -1.0; + _outDirection[1] = 0.0; + + Vec2D scaledOut = Vec2D.scale( + new Vec2D(), _outDirection, _easeOut * bone.length * CurveConstant); + _outPoint[0] = bone.length; + _outPoint[1] = 0.0; + Vec2D.add(_outPoint, _outPoint, scaledOut); + } + + updateJellies(); + } } \ No newline at end of file diff --git a/lib/flare/json_block_reader.dart b/lib/flare/json_block_reader.dart index 33583ea..b55d1c6 100644 --- a/lib/flare/json_block_reader.dart +++ b/lib/flare/json_block_reader.dart @@ -1,80 +1,69 @@ import "json_reader.dart"; -class JSONBlockReader extends JSONReader -{ - @override - int blockType; +class JSONBlockReader extends JSONReader { + @override + int blockType; - JSONBlockReader(Map object) : blockType = 0, super(object); + JSONBlockReader(Map object) + : blockType = 0, + super(object); - JSONBlockReader.fromObject(int type, Map object) : super(object) - { - blockType = type; + JSONBlockReader.fromObject(int type, Map object) : super(object) + { + blockType = type; + } + + JSONBlockReader readNextBlock([Map blockTypes]) { + if (isEOF()) { + return null; } - JSONBlockReader readNextBlock([Map blockTypes]) - { - if(isEOF()) - { - return null; - } + var obj = new Map(); + obj["container"] = this._peek(); + var type = this.readBlockType(blockTypes); + var c = this.context.first; + if (c is Map) { + c.remove(this.nextKey); + } + else if (c is List) { + c.removeAt(0); + } - var obj = new Map(); - obj["container"] = this._peek(); - var type = this.readBlockType(blockTypes); - var c = this.context.first; - if(c is Map) - { - c.remove(this.nextKey); - } - else if(c is List) - { - c.removeAt(0); - } + return JSONBlockReader.fromObject(type, obj); + } - return JSONBlockReader.fromObject(type, obj); + readBlockType(Map blockTypes) { + var next = this._peek(); + var bType; + if (next is Map) { + var c = this.context.first; + if (c is Map) { + bType = blockTypes[this.nextKey]; + } + else if (c is List) { + // Objects are serialized with "type" property. + var nType = next["type"]; + bType = blockTypes[nType]; + } } + else if (next is List) { + // Arrays are serialized as "type": [Array]. + bType = blockTypes[this.nextKey]; + } + return bType; + } - readBlockType(Map blockTypes) - { - var next = this._peek(); - var bType; - if(next is Map) - { - var c = this.context.first; - if(c is Map) - { - bType = blockTypes[this.nextKey]; - } - else if(c is List) - { - // Objects are serialized with "type" property. - var nType = next["type"]; - bType = blockTypes[nType]; - } - } - else if(next is List) - { - // Arrays are serialized as "type": [Array]. - bType = blockTypes[this.nextKey]; - } - return bType; - } - - _peek() - { - var stream = this.context.first; - var next; - if(stream is Map) - { - next = stream[this.nextKey]; - } - else if(stream is List) - { - next = stream[0]; - } - return next; - } + _peek() { + var stream = this.context.first; + var next; + if (stream is Map) { + next = stream[this.nextKey]; + } + else if (stream is List) { + next = stream[0]; + } + return next; + } - get nextKey => this.context.first.keys.first; + get nextKey => this.context.first.keys.first; } \ No newline at end of file diff --git a/lib/flare/json_reader.dart b/lib/flare/json_reader.dart index b50a32c..77b243b 100644 --- a/lib/flare/json_reader.dart +++ b/lib/flare/json_reader.dart @@ -3,213 +3,183 @@ import "dart:typed_data"; import "stream_reader.dart"; -abstract class JSONReader implements StreamReader -{ - @override - int blockType; - - dynamic _readObject; - ListQueue _context; - - JSONReader(Map object) - { - _readObject = object["container"]; - _context = new ListQueue(); - _context.addFirst(_readObject); - } - - dynamic readProp(String label) - { - var head = _context.first; - if(head is Map) - { - var prop = head[label]; - head.remove(label); - return prop; - } - else if(head is List) - { - return head.removeAt(0); - } - return null; - } - - @override - readFloat32(label) - { - num f = this.readProp(label); - return f.toDouble(); - } - - // Reads the array into ar - @override - readFloat32Array(Float32List ar, String label) - { - this._readArray(ar, label); - } - - @override - readFloat32ArrayOffset(Float32List ar, int length, int offset, String label) - { - this._readArrayOffset(ar, length, offset, label); - } - - _readArrayOffset(List ar, int length, int offset, String label) - { - List array = this.readProp(label); - num listElement = ar.first; - for(int i = 0; i < length; i++) - { - num val = array[i]; - ar[offset + i] = listElement is double ? val.toDouble() : val.toInt(); - } +abstract class JSONReader + implements StreamReader { + @override + int blockType; + + dynamic _readObject; + ListQueue _context; + + JSONReader(Map object) { + _readObject = object["container"]; + _context = new ListQueue(); + _context.addFirst(_readObject); + } + + dynamic readProp(String label) { + var head = _context.first; + if (head is Map) { + var prop = head[label]; + head.remove(label); + return prop; } - - _readArray(List ar, String label) - { - List array = this.readProp(label); - for (int i = 0; i < ar.length; i++) - { - num val = array[i]; - ar[i] = ar.first is double ? val.toDouble() : val.toInt(); - } - } - - @override - readFloat64(label) - { - num f = this.readProp(label); - return f.toDouble(); - } - - @override - readUint8(label) - { - return this.readProp(label); - } - - @override - readUint8Length() - { - return this._readLength(); - } - - @override - bool isEOF() - { - return _context.length <= 1 && _readObject.length == 0; - } - - @override - readInt8(label) - { - return this.readProp(label); - } - - @override - readUint16(label) - { - return this.readProp(label); - } - - @override - readUint8Array(Uint8List ar, int length, int offset, String label) - { - return this._readArrayOffset(ar, length, offset, label); - } - - @override - readUint16Array(Uint16List ar, int length, int offset, String label) - { - return this._readArrayOffset(ar, length, offset, label); - } - - @override - readInt16(label) - { - return this.readProp(label); - } - - @override - readUint16Length() - { - return this._readLength(); - } - - @override - readUint32Length() - { - return this._readLength(); - } - - @override - readUint32(label) - { - return this.readProp(label); + else if (head is List) { + return head.removeAt(0); } - - @override - readInt32(label) - { - return this.readProp(label); + return null; + } + + @override + readFloat32(label) { + num f = this.readProp(label); + return f.toDouble(); + } + + // Reads the array into ar + @override + readFloat32Array(Float32List ar, String label) { + this._readArray(ar, label); + } + + @override + readFloat32ArrayOffset(Float32List ar, int length, int offset, String label) { + this._readArrayOffset(ar, length, offset, label); + } + + _readArrayOffset(List ar, int length, int offset, String label) { + List array = this.readProp(label); + num listElement = ar.first; + for (int i = 0; i < length; i++) { + num val = array[i]; + ar[offset + i] = listElement is double ? val.toDouble() : val.toInt(); } + } - @override - int readVersion() - { - return this.readProp("version"); + _readArray(List ar, String label) { + List array = this.readProp(label); + for (int i = 0; i < ar.length; i++) { + num val = array[i]; + ar[i] = ar.first is double ? val.toDouble() : val.toInt(); } - - @override - readString(label) - { - return this.readProp(label); - } - - @override - readBool(String label) - { - return this.readProp(label); - } - - - // @hasOffset flag is needed for older (up until version 14) files. - // Since the JSON Reader has been added in version 15, the field here is optional. - @override - readId(String label) - { - var val = this.readProp(label); - return val is num ? val+1 : 0; - } - - @override - openArray(label) - { - var array = this.readProp(label); - _context.addFirst(array); - } - - @override - closeArray() - { - _context.removeFirst(); - } - - @override - openObject(label) - { - var o = this.readProp(label); - _context.addFirst(o); - } - - @override - closeObject() - { - this._context.removeFirst(); - } - - int _readLength() => _context.first.length; // Maps and Lists both have a `length` property. - @override - String get containerType => "json"; - ListQueue get context => _context; + } + + @override + readFloat64(label) { + num f = this.readProp(label); + return f.toDouble(); + } + + @override + readUint8(label) { + return this.readProp(label); + } + + @override + readUint8Length() { + return this._readLength(); + } + + @override + bool isEOF() { + return _context.length <= 1 && _readObject.length == 0; + } + + @override + readInt8(label) { + return this.readProp(label); + } + + @override + readUint16(label) { + return this.readProp(label); + } + + @override + readUint8Array(Uint8List ar, int length, int offset, String label) { + return this._readArrayOffset(ar, length, offset, label); + } + + @override + readUint16Array(Uint16List ar, int length, int offset, String label) { + return this._readArrayOffset(ar, length, offset, label); + } + + @override + readInt16(label) { + return this.readProp(label); + } + + @override + readUint16Length() { + return this._readLength(); + } + + @override + readUint32Length() { + return this._readLength(); + } + + @override + readUint32(label) { + return this.readProp(label); + } + + @override + readInt32(label) { + return this.readProp(label); + } + + @override + int readVersion() { + return this.readProp("version"); + } + + @override + readString(label) { + return this.readProp(label); + } + + @override + readBool(String label) { + return this.readProp(label); + } + + + // @hasOffset flag is needed for older (up until version 14) files. + // Since the JSON Reader has been added in version 15, the field here is optional. + @override + readId(String label) { + var val = this.readProp(label); + return val is num ? val + 1 : 0; + } + + @override + openArray(label) { + var array = this.readProp(label); + _context.addFirst(array); + } + + @override + closeArray() { + _context.removeFirst(); + } + + @override + openObject(label) { + var o = this.readProp(label); + _context.addFirst(o); + } + + @override + closeObject() { + this._context.removeFirst(); + } + + int _readLength() => + _context.first.length; // Maps and Lists both have a `length` property. + @override + String get containerType => "json"; + + ListQueue get context => _context; } \ No newline at end of file diff --git a/lib/flare/math/aabb.dart b/lib/flare/math/aabb.dart index 0b404c4..df0cff1 100644 --- a/lib/flare/math/aabb.dart +++ b/lib/flare/math/aabb.dart @@ -2,122 +2,107 @@ import "dart:typed_data"; import "dart:math"; import "vec2d.dart"; -class AABB -{ - Float32List _buffer; - - Float32List get values - { - return _buffer; - } - - AABB() - { - this._buffer = new Float32List.fromList([0.0, 0.0, 0.0, 0.0]); - } - - AABB.clone(AABB a) - { - this._buffer = new Float32List.fromList(a.values); - } - - AABB.fromValues(double a, double b, double c, double d) - { - _buffer = new Float32List.fromList([a, b, c, d]); - } - - double operator[](int idx) - { - return this._buffer[idx]; - } - - operator[]=(int idx, double v) - { - this._buffer[idx] = v; - } - - static AABB copy(AABB out, AABB a) - { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; - } - - static Vec2D center(Vec2D out, AABB a) - { - out[0] = (a[0] + a[2]) * 0.5; - out[1] = (a[1] + a[3]) * 0.5; - return out; - } - - static Vec2D size(Vec2D out, AABB a) - { - out[0] = a[2] - a[0]; - out[1] = a[3] - a[1]; - return out; - } - - static Vec2D extents(Vec2D out, AABB a) - { - out[0] = (a[2] - a[0]) * 0.5; - out[1] = (a[3] - a[1]) * 0.5; - return out; - } - - static double perimeter(AABB a) - { - double wx = a[2] - a[0]; - double wy = a[3] - a[1]; - return 2.0 * (wx + wy); - } - - static AABB combine(AABB out, AABB a, AABB b) - { - out[0] = min(a[0], b[0]); - out[1] = min(a[1], b[1]); - out[2] = max(a[2], b[2]); - out[3] = max(a[3], b[3]); - return out; - } - - static bool contains(AABB a, AABB b) - { - return a[0] <= b[0] && a[1] <= b[1] && b[2] <= a[2] && b[3] <= a[3]; - } - - static bool isValid(AABB a) - { - double dx = a[2] - a[0]; - double dy = a[3] - a[1]; - return dx >= 0 && dy >= 0 && a[0] <= double.maxFinite && a[1] <= double.maxFinite && a[2] <= double.maxFinite && a[3] <= double.maxFinite; - } - - static bool testOverlap(AABB a, AABB b) - { - double d1x = b[0] - a[2]; - double d1y = b[1] - a[3]; - - double d2x = a[0] - b[2]; - double d2y = a[1] - b[3]; - - if (d1x > 0.0 || d1y > 0.0) - { - return false; - } - - if (d2x > 0.0 || d2y > 0.0) - { - return false; - } - - return true; +class AABB { + Float32List _buffer; + + Float32List get values { + return _buffer; + } + + AABB() { + this._buffer = new Float32List.fromList([0.0, 0.0, 0.0, 0.0]); + } + + AABB.clone(AABB a) + { + this._buffer = new Float32List.fromList(a.values); + } + + AABB.fromValues(double a, double b, double c, double d) + { + _buffer = new Float32List.fromList([a, b, c, d]); + } + + double operator [](int idx) { + return this._buffer[idx]; + } + + operator []=(int idx, double v) { + this._buffer[idx] = v; + } + + static AABB copy(AABB out, AABB a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + + static Vec2D center(Vec2D out, AABB a) { + out[0] = (a[0] + a[2]) * 0.5; + out[1] = (a[1] + a[3]) * 0.5; + return out; + } + + static Vec2D size(Vec2D out, AABB a) { + out[0] = a[2] - a[0]; + out[1] = a[3] - a[1]; + return out; + } + + static Vec2D extents(Vec2D out, AABB a) { + out[0] = (a[2] - a[0]) * 0.5; + out[1] = (a[3] - a[1]) * 0.5; + return out; + } + + static double perimeter(AABB a) { + double wx = a[2] - a[0]; + double wy = a[3] - a[1]; + return 2.0 * (wx + wy); + } + + static AABB combine(AABB out, AABB a, AABB b) { + out[0] = min(a[0], b[0]); + out[1] = min(a[1], b[1]); + out[2] = max(a[2], b[2]); + out[3] = max(a[3], b[3]); + return out; + } + + static bool contains(AABB a, AABB b) { + return a[0] <= b[0] && a[1] <= b[1] && b[2] <= a[2] && b[3] <= a[3]; + } + + static bool isValid(AABB a) { + double dx = a[2] - a[0]; + double dy = a[3] - a[1]; + return dx >= 0 && dy >= 0 && a[0] <= double.maxFinite && + a[1] <= double.maxFinite && a[2] <= double.maxFinite && + a[3] <= double.maxFinite; + } + + static bool testOverlap(AABB a, AABB b) { + double d1x = b[0] - a[2]; + double d1y = b[1] - a[3]; + + double d2x = a[0] - b[2]; + double d2y = a[1] - b[3]; + + if (d1x > 0.0 || d1y > 0.0) { + return false; } - @override - String toString() - { - return _buffer.toString(); - } + if (d2x > 0.0 || d2y > 0.0) { + return false; + } + + return true; + } + + @override + String toString() { + return _buffer.toString(); + } } \ No newline at end of file diff --git a/lib/flare/math/mat2d.dart b/lib/flare/math/mat2d.dart index 8ff471e..a180170 100644 --- a/lib/flare/math/mat2d.dart +++ b/lib/flare/math/mat2d.dart @@ -3,190 +3,194 @@ import "dart:math"; import "vec2d.dart"; import "transform_components.dart"; -double sign(double value) -{ - return value > 0.0 ? 1.0 : -1.0; +double sign(double value) { + return value > 0.0 ? 1.0 : -1.0; } -class Mat2D -{ - Float32List _buffer; - - Float32List get values - { - return _buffer; - } - - Float64List get mat4 - { - return new Float64List.fromList([ - _buffer[0], _buffer[1], 0.0, 0.0, - _buffer[2], _buffer[3], 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - _buffer[4], _buffer[5], 0.0, 1.0]); - } - - double operator[](int index) - { - return _buffer[index]; - } - - void operator[]=(int index, double value) - { - _buffer[index] = value; - } - - Mat2D() - { - _buffer = new Float32List.fromList([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]); - } - - Mat2D.clone(Mat2D copy) - { - _buffer = new Float32List.fromList(copy.values); - } - - static void fromRotation(Mat2D o, double rad) - { - double s = sin(rad); - double c = cos(rad); - o[0] = c; - o[1] = s; - o[2] = -s; - o[3] = c; - o[4] = 0.0; - o[5] = 0.0; - } - - static void copy(Mat2D o, Mat2D f) - { - o[0] = f[0]; - o[1] = f[1]; - o[2] = f[2]; - o[3] = f[3]; - o[4] = f[4]; - o[5] = f[5]; - } - - static void scale(Mat2D o, Mat2D a, Vec2D v) - { - double a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], v0 = v[0], v1 = v[1]; - o[0] = a0 * v0; - o[1] = a1 * v0; - o[2] = a2 * v1; - o[3] = a3 * v1; - o[4] = a4; - o[5] = a5; - } - - static void multiply(Mat2D o, Mat2D a, Mat2D b) - { - double a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; - o[0] = a0 * b0 + a2 * b1; - o[1] = a1 * b0 + a3 * b1; - o[2] = a0 * b2 + a2 * b3; - o[3] = a1 * b2 + a3 * b3; - o[4] = a0 * b4 + a2 * b5 + a4; - o[5] = a1 * b4 + a3 * b5 + a5; - } - - static void cCopy(Mat2D o, Mat2D a) - { - o[0] = a[0]; - o[1] = a[1]; - o[2] = a[2]; - o[3] = a[3]; - o[4] = a[4]; - o[5] = a[5]; - } - - static bool invert(Mat2D o, Mat2D a) - { - double aa = a[0], ab = a[1], ac = a[2], ad = a[3], atx = a[4], aty = a[5]; - - double det = aa * ad - ab * ac; - if(det == 0.0) - { - return false; - } - det = 1.0 / det; - - o[0] = ad * det; - o[1] = -ab * det; - o[2] = -ac * det; - o[3] = aa * det; - o[4] = (ac * aty - ad * atx) * det; - o[5] = (ab * atx - aa * aty) * det; - return true; - } - - static void getScale(Mat2D m, Vec2D s) - { - double x = m[0]; - double y = m[1]; - s[0] = sign(x) * sqrt(x*x + y*y); - - x = m[2]; - y = m[3]; - s[1] = sign(y) * sqrt(x*x + y*y); - } - - static void identity(Mat2D mat) - { - mat[0] = 1.0; - mat[1] = 0.0; - mat[2] = 0.0; - mat[3] = 1.0; - mat[4] = 0.0; - mat[5] = 0.0; - } - - static void decompose(Mat2D m, TransformComponents result) - { - double m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; - - double rotation = atan2(m1, m0); - double denom = m0*m0 + m1*m1; - double scaleX = sqrt(denom); - double scaleY = (m0 * m3 - m2 * m1) / scaleX; - double skewX = atan2(m0 * m2 + m1 * m3, denom); - - result[0] = m[4]; - result[1] = m[5]; - result[2] = scaleX; - result[3] = scaleY; - result[4] = rotation; - result[5] = skewX; - } - - static void compose(Mat2D m, TransformComponents result) - { - double r = result[4]; - - if(r != 0.0) - { - Mat2D.fromRotation(m, r); - } - else - { - Mat2D.identity(m); - } - m[4] = result[0]; - m[5] = result[1]; - Mat2D.scale(m, m, result.scale); - - double sk = result[5]; - if(sk != 0.0) - { - m[2] = m[0] * sk + m[2]; - m[3] = m[1] * sk + m[3]; - } - } - - @override - String toString() - { - return _buffer.toString(); +class Mat2D { + Float32List _buffer; + + Float32List get values { + return _buffer; + } + + Float64List get mat4 { + return new Float64List.fromList([ + _buffer[0], _buffer[1], 0.0, 0.0, + _buffer[2], _buffer[3], 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + _buffer[4], _buffer[5], 0.0, 1.0 + ]); + } + + double operator [](int index) { + return _buffer[index]; + } + + void operator []=(int index, double value) { + _buffer[index] = value; + } + + Mat2D() { + _buffer = new Float32List.fromList([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]); + } + + Mat2D.clone(Mat2D copy) + { + _buffer = new Float32List.fromList(copy.values); + } + + static void fromRotation(Mat2D o, double rad) { + double s = sin(rad); + double c = cos(rad); + o[0] = c; + o[1] = s; + o[2] = -s; + o[3] = c; + o[4] = 0.0; + o[5] = 0.0; + } + + static void copy(Mat2D o, Mat2D f) { + o[0] = f[0]; + o[1] = f[1]; + o[2] = f[2]; + o[3] = f[3]; + o[4] = f[4]; + o[5] = f[5]; + } + + static void scale(Mat2D o, Mat2D a, Vec2D v) { + double a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + v0 = v[0], + v1 = v[1]; + o[0] = a0 * v0; + o[1] = a1 * v0; + o[2] = a2 * v1; + o[3] = a3 * v1; + o[4] = a4; + o[5] = a5; + } + + static void multiply(Mat2D o, Mat2D a, Mat2D b) { + double a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5]; + o[0] = a0 * b0 + a2 * b1; + o[1] = a1 * b0 + a3 * b1; + o[2] = a0 * b2 + a2 * b3; + o[3] = a1 * b2 + a3 * b3; + o[4] = a0 * b4 + a2 * b5 + a4; + o[5] = a1 * b4 + a3 * b5 + a5; + } + + static void cCopy(Mat2D o, Mat2D a) { + o[0] = a[0]; + o[1] = a[1]; + o[2] = a[2]; + o[3] = a[3]; + o[4] = a[4]; + o[5] = a[5]; + } + + static bool invert(Mat2D o, Mat2D a) { + double aa = a[0], + ab = a[1], + ac = a[2], + ad = a[3], + atx = a[4], + aty = a[5]; + + double det = aa * ad - ab * ac; + if (det == 0.0) { + return false; } + det = 1.0 / det; + + o[0] = ad * det; + o[1] = -ab * det; + o[2] = -ac * det; + o[3] = aa * det; + o[4] = (ac * aty - ad * atx) * det; + o[5] = (ab * atx - aa * aty) * det; + return true; + } + + static void getScale(Mat2D m, Vec2D s) { + double x = m[0]; + double y = m[1]; + s[0] = sign(x) * sqrt(x * x + y * y); + + x = m[2]; + y = m[3]; + s[1] = sign(y) * sqrt(x * x + y * y); + } + + static void identity(Mat2D mat) { + mat[0] = 1.0; + mat[1] = 0.0; + mat[2] = 0.0; + mat[3] = 1.0; + mat[4] = 0.0; + mat[5] = 0.0; + } + + static void decompose(Mat2D m, TransformComponents result) { + double m0 = m[0], + m1 = m[1], + m2 = m[2], + m3 = m[3]; + + double rotation = atan2(m1, m0); + double denom = m0 * m0 + m1 * m1; + double scaleX = sqrt(denom); + double scaleY = (m0 * m3 - m2 * m1) / scaleX; + double skewX = atan2(m0 * m2 + m1 * m3, denom); + + result[0] = m[4]; + result[1] = m[5]; + result[2] = scaleX; + result[3] = scaleY; + result[4] = rotation; + result[5] = skewX; + } + + static void compose(Mat2D m, TransformComponents result) { + double r = result[4]; + + if (r != 0.0) { + Mat2D.fromRotation(m, r); + } + else { + Mat2D.identity(m); + } + m[4] = result[0]; + m[5] = result[1]; + Mat2D.scale(m, m, result.scale); + + double sk = result[5]; + if (sk != 0.0) { + m[2] = m[0] * sk + m[2]; + m[3] = m[1] * sk + m[3]; + } + } + + @override + String toString() { + return _buffer.toString(); + } } \ No newline at end of file diff --git a/lib/flare/math/transform_components.dart b/lib/flare/math/transform_components.dart index 47777b4..bff0190 100644 --- a/lib/flare/math/transform_components.dart +++ b/lib/flare/math/transform_components.dart @@ -1,102 +1,83 @@ import "dart:typed_data"; import "vec2d.dart"; -class TransformComponents -{ - Float32List _buffer; - - Float32List get values - { - return _buffer; - } - - double operator[](int index) - { - return _buffer[index]; - } - - void operator[]=(int index, double value) - { - _buffer[index] = value; - } - - TransformComponents() - { - _buffer = new Float32List.fromList([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]); - } - - TransformComponents.clone(TransformComponents copy) - { - _buffer = new Float32List.fromList(copy.values); - } - - double get x - { - return _buffer[0]; - } - - set x(double value) - { - _buffer[0] = value; - } - - double get y - { - return _buffer[1]; - } - - set y(double value) - { - _buffer[1] = value; - } - - double get scaleX - { - return _buffer[2]; - } - - set scaleX(double value) - { - _buffer[2] = value; - } - - double get scaleY - { - return _buffer[3]; - } - - set scaleY(double value) - { - _buffer[3] = value; - } - - double get rotation - { - return _buffer[4]; - } - - set rotation(double value) - { - _buffer[4] = value; - } - - double get skew - { - return _buffer[5]; - } - - set skew(double value) - { - _buffer[5] = value; - } - - Vec2D get translation - { - return new Vec2D.fromValues(_buffer[0], _buffer[1]); - } - - Vec2D get scale - { - return new Vec2D.fromValues(_buffer[2], _buffer[3]); - } +class TransformComponents { + Float32List _buffer; + + Float32List get values { + return _buffer; + } + + double operator [](int index) { + return _buffer[index]; + } + + void operator []=(int index, double value) { + _buffer[index] = value; + } + + TransformComponents() { + _buffer = new Float32List.fromList([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]); + } + + TransformComponents.clone(TransformComponents copy) + { + _buffer = new Float32List.fromList(copy.values); + } + + double get x { + return _buffer[0]; + } + + set x(double value) { + _buffer[0] = value; + } + + double get y { + return _buffer[1]; + } + + set y(double value) { + _buffer[1] = value; + } + + double get scaleX { + return _buffer[2]; + } + + set scaleX(double value) { + _buffer[2] = value; + } + + double get scaleY { + return _buffer[3]; + } + + set scaleY(double value) { + _buffer[3] = value; + } + + double get rotation { + return _buffer[4]; + } + + set rotation(double value) { + _buffer[4] = value; + } + + double get skew { + return _buffer[5]; + } + + set skew(double value) { + _buffer[5] = value; + } + + Vec2D get translation { + return new Vec2D.fromValues(_buffer[0], _buffer[1]); + } + + Vec2D get scale { + return new Vec2D.fromValues(_buffer[2], _buffer[3]); + } } \ No newline at end of file diff --git a/lib/flare/math/vec2d.dart b/lib/flare/math/vec2d.dart index b5e611a..07d6941 100644 --- a/lib/flare/math/vec2d.dart +++ b/lib/flare/math/vec2d.dart @@ -2,145 +2,125 @@ import "dart:typed_data"; import "dart:math"; import "mat2d.dart"; -class Vec2D -{ - Float32List _buffer; - - Float32List get values - { - return _buffer; - } - - double operator[](int index) - { - return _buffer[index]; - } - - void operator[]=(int index, double value) - { - _buffer[index] = value; - } - - Vec2D() - { - _buffer = new Float32List.fromList([0.0, 0.0]); - } - - Vec2D.clone(Vec2D copy) - { - _buffer = new Float32List.fromList(copy._buffer); - } - - Vec2D.fromValues(double x, double y) - { - _buffer = new Float32List.fromList([x, y]); - } - - static void copy(Vec2D o, Vec2D a) - { - o[0] = a[0]; - o[1] = a[1]; - } - - static Vec2D transformMat2D(Vec2D o, Vec2D a, Mat2D m) - { - double x = a[0]; - double y = a[1]; - o[0] = m[0] * x + m[2] * y + m[4]; - o[1] = m[1] * x + m[3] * y + m[5]; - return o; - } - - static Vec2D transformMat2(Vec2D o, Vec2D a, Mat2D m) - { - double x = a[0]; - double y = a[1]; - o[0] = m[0] * x + m[2] * y; - o[1] = m[1] * x + m[3] * y; - return o; - } - - static Vec2D subtract(Vec2D o, Vec2D a, Vec2D b) - { - o[0] = a[0] - b[0]; - o[1] = a[1] - b[1]; - return o; - } - - static Vec2D add(Vec2D o, Vec2D a, Vec2D b) - { - o[0] = a[0] + b[0]; - o[1] = a[1] + b[1]; - return o; - } - - static Vec2D scale(Vec2D o, Vec2D a, double scale) - { - o[0] = a[0] * scale; - o[1] = a[1] * scale; - return o; - } - - static Vec2D lerp(Vec2D o, Vec2D a, Vec2D b, double f) - { - double ax = a[0]; - double ay = a[1]; - o[0] = ax + f * (b[0] - ax); - o[1] = ay + f * (b[1] - ay); - return o; - } - - static double length(Vec2D a) - { - double x = a[0]; - double y = a[1]; - return sqrt(x*x + y*y); - } - - static double distance(Vec2D a, Vec2D b) - { - double x = b[0] - a[0]; - double y = b[1] - a[1]; - return sqrt(x*x + y*y); - } - - static Vec2D negate(Vec2D result, Vec2D a) - { - result[0] = -a[0]; - result[1] = -a[1]; - - return result; - } - - static void normalize(Vec2D result, Vec2D a) - { - double x = a[0]; - double y = a[1]; - double len = x*x + y*y; - if (len > 0.0) - { - len = 1.0 / sqrt(len); - result[0] = a[0] * len; - result[1] = a[1] * len; - } - } - - static double dot(Vec2D a, Vec2D b) - { - return a[0] * b[0] + a[1] * b[1]; - } - - static Vec2D scaleAndAdd(Vec2D result, Vec2D a, Vec2D b, double scale) - { - result[0] = a[0] + (b[0] * scale); - result[1] = a[1] + (b[1] * scale); - return result; - } - - @override - String toString() - { - String v = _buffer[0].toString() + ", "; - return v + _buffer[1].toString(); +class Vec2D { + Float32List _buffer; + + Float32List get values { + return _buffer; + } + + double operator [](int index) { + return _buffer[index]; + } + + void operator []=(int index, double value) { + _buffer[index] = value; + } + + Vec2D() { + _buffer = new Float32List.fromList([0.0, 0.0]); + } + + Vec2D.clone(Vec2D copy) + { + _buffer = new Float32List.fromList(copy._buffer); + } + + Vec2D.fromValues(double x, double y) + { + _buffer = new Float32List.fromList([x, y]); + } + + static void copy(Vec2D o, Vec2D a) { + o[0] = a[0]; + o[1] = a[1]; + } + + static Vec2D transformMat2D(Vec2D o, Vec2D a, Mat2D m) { + double x = a[0]; + double y = a[1]; + o[0] = m[0] * x + m[2] * y + m[4]; + o[1] = m[1] * x + m[3] * y + m[5]; + return o; + } + + static Vec2D transformMat2(Vec2D o, Vec2D a, Mat2D m) { + double x = a[0]; + double y = a[1]; + o[0] = m[0] * x + m[2] * y; + o[1] = m[1] * x + m[3] * y; + return o; + } + + static Vec2D subtract(Vec2D o, Vec2D a, Vec2D b) { + o[0] = a[0] - b[0]; + o[1] = a[1] - b[1]; + return o; + } + + static Vec2D add(Vec2D o, Vec2D a, Vec2D b) { + o[0] = a[0] + b[0]; + o[1] = a[1] + b[1]; + return o; + } + + static Vec2D scale(Vec2D o, Vec2D a, double scale) { + o[0] = a[0] * scale; + o[1] = a[1] * scale; + return o; + } + + static Vec2D lerp(Vec2D o, Vec2D a, Vec2D b, double f) { + double ax = a[0]; + double ay = a[1]; + o[0] = ax + f * (b[0] - ax); + o[1] = ay + f * (b[1] - ay); + return o; + } + + static double length(Vec2D a) { + double x = a[0]; + double y = a[1]; + return sqrt(x * x + y * y); + } + + static double distance(Vec2D a, Vec2D b) { + double x = b[0] - a[0]; + double y = b[1] - a[1]; + return sqrt(x * x + y * y); + } + + static Vec2D negate(Vec2D result, Vec2D a) { + result[0] = -a[0]; + result[1] = -a[1]; + + return result; + } + + static void normalize(Vec2D result, Vec2D a) { + double x = a[0]; + double y = a[1]; + double len = x * x + y * y; + if (len > 0.0) { + len = 1.0 / sqrt(len); + result[0] = a[0] * len; + result[1] = a[1] * len; } + } + + static double dot(Vec2D a, Vec2D b) { + return a[0] * b[0] + a[1] * b[1]; + } + + static Vec2D scaleAndAdd(Vec2D result, Vec2D a, Vec2D b, double scale) { + result[0] = a[0] + (b[0] * scale); + result[1] = a[1] + (b[1] * scale); + return result; + } + + @override + String toString() { + String v = _buffer[0].toString() + ", "; + return v + _buffer[1].toString(); + } } \ No newline at end of file diff --git a/lib/flare/path_point.dart b/lib/flare/path_point.dart index 4ea0e53..d03c78c 100644 --- a/lib/flare/path_point.dart +++ b/lib/flare/path_point.dart @@ -4,288 +4,289 @@ import "dart:collection"; import "stream_reader.dart"; import "math/mat2d.dart"; -enum PointType -{ - Straight, - Mirror, - Disconnected, - Asymmetric +enum PointType { + Straight, + Mirror, + Disconnected, + Asymmetric } -HashMap pointTypeLookup = new HashMap.fromIterables([0,1,2,3], [PointType.Straight, PointType.Mirror, PointType.Disconnected, PointType.Asymmetric]); - -abstract class PathPoint -{ - PointType _type; - Vec2D _translation = new Vec2D(); - Float32List _weights; - - PathPoint(PointType type) - { - _type = type; - } - - PointType get pointType - { - return _type; - } - - Vec2D get translation - { - return _translation; - } - - PathPoint makeInstance(); - - copy(PathPoint from) - { - this._type = from._type; - Vec2D.copy(_translation, from._translation); - if(from._weights != null) - { - _weights = new Float32List.fromList(from._weights); - } - } - - void read(StreamReader reader, bool isConnectedToBones) - { - reader.readFloat32ArrayOffset(_translation.values, 2, 0, "translation"); - readPoint(reader, isConnectedToBones); - if(_weights != null) - { - reader.readFloat32Array(_weights, "weights"); - } - } - - void readPoint(StreamReader reader, bool isConnectedToBones); - - PathPoint transformed(Mat2D transform) - { - PathPoint result = makeInstance(); - Vec2D.transformMat2D(result.translation, result.translation, transform); - return result; - } - - PathPoint skin(Mat2D world, Float32List bones); +HashMap pointTypeLookup = new HashMap.fromIterables([0, 1, 2, 3], [ + PointType.Straight, + PointType.Mirror, + PointType.Disconnected, + PointType.Asymmetric +]); + +abstract class PathPoint { + PointType _type; + Vec2D _translation = new Vec2D(); + Float32List _weights; + + PathPoint(PointType type) { + _type = type; + } + + PointType get pointType { + return _type; + } + + Vec2D get translation { + return _translation; + } + + PathPoint makeInstance(); + + copy(PathPoint from) { + this._type = from._type; + Vec2D.copy(_translation, from._translation); + if (from._weights != null) { + _weights = new Float32List.fromList(from._weights); + } + } + + void read(StreamReader reader, bool isConnectedToBones) { + reader.readFloat32ArrayOffset(_translation.values, 2, 0, "translation"); + readPoint(reader, isConnectedToBones); + if (_weights != null) { + reader.readFloat32Array(_weights, "weights"); + } + } + + void readPoint(StreamReader reader, bool isConnectedToBones); + + PathPoint transformed(Mat2D transform) { + PathPoint result = makeInstance(); + Vec2D.transformMat2D(result.translation, result.translation, transform); + return result; + } + + PathPoint skin(Mat2D world, Float32List bones); +} + +class StraightPathPoint extends PathPoint { + double radius = 0.0; + + StraightPathPoint() : super(PointType.Straight); + + StraightPathPoint.fromTranslation(Vec2D translation) + : super(PointType.Straight) + { + this._translation = translation; + } + + StraightPathPoint.fromValues(Vec2D translation, double r) + : super(PointType.Straight) + { + _translation = translation; + radius = r; + } + + PathPoint makeInstance() { + StraightPathPoint node = new StraightPathPoint(); + node.copyStraight(this); + return node; + } + + copyStraight(StraightPathPoint from) { + super.copy(from); + radius = from.radius; + } + + void readPoint(StreamReader reader, bool isConnectedToBones) { + radius = reader.readFloat32("radius"); + if (isConnectedToBones) { + _weights = new Float32List(8); + } + } + + @override + PathPoint skin(Mat2D world, Float32List bones) { + StraightPathPoint point = new StraightPathPoint() + ..radius = radius; + + double px = world[0] * translation[0] + world[2] * translation[1] + + world[4]; + double py = world[1] * translation[0] + world[3] * translation[1] + + world[5]; + + double a = 0.0, + b = 0.0, + c = 0.0, + d = 0.0, + e = 0.0, + f = 0.0; + + for (int i = 0; i < 4; i++) { + int boneIndex = _weights[i].floor(); + double weight = _weights[i + 4]; + if (weight > 0) { + int bb = boneIndex * 6; + + a += bones[bb] * weight; + b += bones[bb + 1] * weight; + c += bones[bb + 2] * weight; + d += bones[bb + 3] * weight; + e += bones[bb + 4] * weight; + f += bones[bb + 5] * weight; + } + } + + Vec2D pos = point.translation; + pos[0] = a * px + c * py + e; + pos[1] = b * px + d * py + f; + + return point; + } } -class StraightPathPoint extends PathPoint -{ - double radius = 0.0; +class CubicPathPoint extends PathPoint { + Vec2D _in = new Vec2D(); + Vec2D _out = new Vec2D(); + + CubicPathPoint(PointType type) : super(type); + + Vec2D get inPoint { + return _in; + } + + Vec2D get outPoint { + return _out; + } + + CubicPathPoint.fromValues(Vec2D translation, Vec2D inPoint, Vec2D outPoint) + : super(PointType.Disconnected) + { + _translation = translation; + _in = inPoint; + _out = outPoint; + } + + PathPoint makeInstance() { + CubicPathPoint node = new CubicPathPoint(_type); + node.copyCubic(this); + return node; + } + + copyCubic(from) { + super.copy(from); + Vec2D.copy(_in, from._in); + Vec2D.copy(_out, from._out); + } + + void readPoint(StreamReader reader, bool isConnectedToBones) { + reader.readFloat32ArrayOffset(_in.values, 2, 0, "in"); + reader.readFloat32ArrayOffset(_out.values, 2, 0, "out"); + if (isConnectedToBones) { + _weights = new Float32List(24); + } + } + + PathPoint transformed(Mat2D transform) { + CubicPathPoint result = super.transformed(transform) as CubicPathPoint; + Vec2D.transformMat2D(result.inPoint, result.inPoint, transform); + Vec2D.transformMat2D(result.outPoint, result.outPoint, transform); + return result; + } + + @override + PathPoint skin(Mat2D world, Float32List bones) { + CubicPathPoint point = new CubicPathPoint(pointType); + + double px = world[0] * translation[0] + world[2] * translation[1] + + world[4]; + double py = world[1] * translation[0] + world[3] * translation[1] + + world[5]; - StraightPathPoint() : super(PointType.Straight); - - StraightPathPoint.fromTranslation(Vec2D translation) : super(PointType.Straight) { - this._translation = translation; + double a = 0.0, + b = 0.0, + c = 0.0, + d = 0.0, + e = 0.0, + f = 0.0; + + for (int i = 0; i < 4; i++) { + int boneIndex = _weights[i].floor(); + double weight = _weights[i + 4]; + if (weight > 0) { + int bb = boneIndex * 6; + + a += bones[bb] * weight; + b += bones[bb + 1] * weight; + c += bones[bb + 2] * weight; + d += bones[bb + 3] * weight; + e += bones[bb + 4] * weight; + f += bones[bb + 5] * weight; + } + } + + Vec2D pos = point.translation; + pos[0] = a * px + c * py + e; + pos[1] = b * px + d * py + f; } - StraightPathPoint.fromValues(Vec2D translation, double r) : super(PointType.Straight) { - _translation = translation; - radius = r; + double a = 0.0, + b = 0.0, + c = 0.0, + d = 0.0, + e = 0.0, + f = 0.0; + px = world[0] * _in[0] + world[2] * _in[1] + world[4]; + py = world[1] * _in[0] + world[3] * _in[1] + world[5]; + + for (int i = 8; i < 12; i++) { + int boneIndex = _weights[i].floor(); + double weight = _weights[i + 4]; + if (weight > 0) { + int bb = boneIndex * 6; + + a += bones[bb] * weight; + b += bones[bb + 1] * weight; + c += bones[bb + 2] * weight; + d += bones[bb + 3] * weight; + e += bones[bb + 4] * weight; + f += bones[bb + 5] * weight; + } + } + + Vec2D pos = point.inPoint; + pos[0] = a * px + c * py + e; + pos[1] = b * px + d * py + f; + } + + { + double a = 0.0, + b = 0.0, + c = 0.0, + d = 0.0, + e = 0.0, + f = 0.0; + px = world[0] * _out[0] + world[2] * _out[1] + world[4]; + py = world[1] * _out[0] + world[3] * _out[1] + world[5]; + + for (int i = 16; i < 20; i++) { + int boneIndex = _weights[i].floor(); + double weight = _weights[i + 4]; + if (weight > 0) { + int bb = boneIndex * 6; + + a += bones[bb] * weight; + b += bones[bb + 1] * weight; + c += bones[bb + 2] * weight; + d += bones[bb + 3] * weight; + e += bones[bb + 4] * weight; + f += bones[bb + 5] * weight; + } + } + + Vec2D pos = point.outPoint; + pos[0] = a * px + c * py + e; + pos[1] = b * px + d * py + f; } - - PathPoint makeInstance() - { - StraightPathPoint node = new StraightPathPoint(); - node.copyStraight(this); - return node; - } - - copyStraight(StraightPathPoint from) - { - super.copy(from); - radius = from.radius; - } - - void readPoint(StreamReader reader, bool isConnectedToBones) - { - radius = reader.readFloat32("radius"); - if(isConnectedToBones) - { - _weights = new Float32List(8); - } - } - - @override - PathPoint skin(Mat2D world, Float32List bones) - { - StraightPathPoint point = new StraightPathPoint()..radius = radius; - - double px = world[0] * translation[0] + world[2] * translation[1] + world[4]; - double py = world[1] * translation[0] + world[3] * translation[1] + world[5]; - - double a = 0.0, b = 0.0, c = 0.0, d = 0.0, e = 0.0, f = 0.0; - - for(int i = 0; i < 4; i++) - { - int boneIndex = _weights[i].floor(); - double weight = _weights[i+4]; - if(weight > 0) - { - int bb = boneIndex*6; - - a += bones[bb] * weight; - b += bones[bb+1] * weight; - c += bones[bb+2] * weight; - d += bones[bb+3] * weight; - e += bones[bb+4] * weight; - f += bones[bb+5] * weight; - } - } - - Vec2D pos = point.translation; - pos[0] = a * px + c * py + e; - pos[1] = b * px + d * py + f; - - return point; - } -} -class CubicPathPoint extends PathPoint -{ - Vec2D _in = new Vec2D(); - Vec2D _out = new Vec2D(); - - CubicPathPoint(PointType type) : super(type); - - Vec2D get inPoint - { - return _in; - } - - Vec2D get outPoint - { - return _out; - } - - CubicPathPoint.fromValues(Vec2D translation, Vec2D inPoint, Vec2D outPoint) : super(PointType.Disconnected) - { - _translation = translation; - _in = inPoint; - _out = outPoint; - } - - PathPoint makeInstance() - { - CubicPathPoint node = new CubicPathPoint(_type); - node.copyCubic(this); - return node; - } - - copyCubic(from) - { - super.copy(from); - Vec2D.copy(_in, from._in); - Vec2D.copy(_out, from._out); - } - - void readPoint(StreamReader reader, bool isConnectedToBones) - { - reader.readFloat32ArrayOffset(_in.values, 2, 0, "in"); - reader.readFloat32ArrayOffset(_out.values, 2, 0, "out"); - if(isConnectedToBones) - { - _weights = new Float32List(24); - } - } - - PathPoint transformed(Mat2D transform) - { - CubicPathPoint result = super.transformed(transform) as CubicPathPoint; - Vec2D.transformMat2D(result.inPoint, result.inPoint, transform); - Vec2D.transformMat2D(result.outPoint, result.outPoint, transform); - return result; - } - - @override - PathPoint skin(Mat2D world, Float32List bones) - { - CubicPathPoint point = new CubicPathPoint(pointType); - - double px = world[0] * translation[0] + world[2] * translation[1] + world[4]; - double py = world[1] * translation[0] + world[3] * translation[1] + world[5]; - - { - double a = 0.0, b = 0.0, c = 0.0, d = 0.0, e = 0.0, f = 0.0; - - for(int i = 0; i < 4; i++) - { - int boneIndex = _weights[i].floor(); - double weight = _weights[i+4]; - if(weight > 0) - { - int bb = boneIndex*6; - - a += bones[bb] * weight; - b += bones[bb+1] * weight; - c += bones[bb+2] * weight; - d += bones[bb+3] * weight; - e += bones[bb+4] * weight; - f += bones[bb+5] * weight; - } - } - - Vec2D pos = point.translation; - pos[0] = a * px + c * py + e; - pos[1] = b * px + d * py + f; - } - - { - double a = 0.0, b = 0.0, c = 0.0, d = 0.0, e = 0.0, f = 0.0; - px = world[0] * _in[0] + world[2] * _in[1] + world[4]; - py = world[1] * _in[0] + world[3] * _in[1] + world[5]; - - for(int i = 8; i < 12; i++) - { - int boneIndex = _weights[i].floor(); - double weight = _weights[i+4]; - if(weight > 0) - { - int bb = boneIndex*6; - - a += bones[bb] * weight; - b += bones[bb+1] * weight; - c += bones[bb+2] * weight; - d += bones[bb+3] * weight; - e += bones[bb+4] * weight; - f += bones[bb+5] * weight; - } - } - - Vec2D pos = point.inPoint; - pos[0] = a * px + c * py + e; - pos[1] = b * px + d * py + f; - } - - { - double a = 0.0, b = 0.0, c = 0.0, d = 0.0, e = 0.0, f = 0.0; - px = world[0] * _out[0] + world[2] * _out[1] + world[4]; - py = world[1] * _out[0] + world[3] * _out[1] + world[5]; - - for(int i = 16; i < 20; i++) - { - int boneIndex = _weights[i].floor(); - double weight = _weights[i+4]; - if(weight > 0) - { - int bb = boneIndex*6; - - a += bones[bb] * weight; - b += bones[bb+1] * weight; - c += bones[bb+2] * weight; - d += bones[bb+3] * weight; - e += bones[bb+4] * weight; - f += bones[bb+5] * weight; - } - } - - Vec2D pos = point.outPoint; - pos[0] = a * px + c * py + e; - pos[1] = b * px + d * py + f; - } - - return point; - } + return point; + } } \ No newline at end of file diff --git a/lib/flare/stream_reader.dart b/lib/flare/stream_reader.dart index b907dfb..204fe1d 100644 --- a/lib/flare/stream_reader.dart +++ b/lib/flare/stream_reader.dart @@ -3,63 +3,77 @@ import 'dart:typed_data'; import "block_reader.dart"; import "json_block_reader.dart"; -abstract class StreamReader -{ - int blockType = 0; - - // Instantiate the right type of Reader based on the input values - factory StreamReader(data) - { - var reader; - if(data is ByteData) - { - reader = new BlockReader(data); - // Move the readIndex forward for the binary reader. - reader.readUint8(); - reader.readUint8(); - reader.readUint8(); - reader.readUint8(); - reader.readUint8(); - } - else if(data is Map) - { - reader = new JSONBlockReader(data); - } - return reader; +abstract class StreamReader { + int blockType = 0; + + // Instantiate the right type of Reader based on the input values + factory StreamReader(data) + { + var reader; + if (data is ByteData) { + reader = new BlockReader(data); + // Move the readIndex forward for the binary reader. + reader.readUint8(); + reader.readUint8(); + reader.readUint8(); + reader.readUint8(); + reader.readUint8(); + } + else if (data is Map) { + reader = new JSONBlockReader(data); } + return reader; + } + + bool isEOF(); + + int readUint8Length(); + + int readUint16Length(); + + int readUint32Length(); + + int readUint8(String label); + + readUint8Array(Uint8List list, int length, int offset, String label); + + int readInt8(String label); + + int readUint16(String label); + + readUint16Array(Uint16List ar, int length, int offset, String label); + + int readInt16(String label); + + int readInt32(String label); + + int readUint32(String label); + + int readVersion(); + + double readFloat32(String label); + + readFloat32Array(Float32List ar, String label); + + readFloat32ArrayOffset(Float32List ar, int length, int offset, String label); + + double readFloat64(String label); + + String readString(String label); + + bool readBool(String label); + + int readId(String label); + + StreamReader readNextBlock(Map types); + + openArray(String label); + + closeArray(); + + openObject(String label); + + closeObject(); - bool isEOF(); - - int readUint8Length(); - int readUint16Length(); - int readUint32Length(); - - int readUint8(String label); - readUint8Array(Uint8List list, int length, int offset, String label); - int readInt8(String label); - int readUint16(String label); - readUint16Array(Uint16List ar, int length, int offset, String label); - int readInt16(String label); - int readInt32(String label); - int readUint32(String label); - int readVersion(); - double readFloat32(String label); - readFloat32Array(Float32List ar, String label); - readFloat32ArrayOffset(Float32List ar, int length, int offset, String label); - double readFloat64(String label); - - String readString(String label); - - bool readBool(String label); - - int readId(String label); - - StreamReader readNextBlock(Map types); - - openArray(String label); - closeArray(); - openObject(String label); - closeObject(); - - String get containerType; + String get containerType; } \ No newline at end of file diff --git a/lib/flare/transform_space.dart b/lib/flare/transform_space.dart index c00db6f..54a63fd 100644 --- a/lib/flare/transform_space.dart +++ b/lib/flare/transform_space.dart @@ -1,5 +1,4 @@ -class TransformSpace -{ - static const int Local = 0; - static const int World = 1; +class TransformSpace { + static const int Local = 0; + static const int World = 1; } \ No newline at end of file diff --git a/lib/flare_actor.dart b/lib/flare_actor.dart index fe88e82..bbbe02d 100644 --- a/lib/flare_actor.dart +++ b/lib/flare_actor.dart @@ -9,484 +9,443 @@ import "package:flutter/scheduler.dart"; typedef void FlareCompletedCallback(String name); -abstract class FlareController -{ - void initialize(FlutterActorArtboard artboard); - void setViewTransform(Mat2D viewTransform); - bool advance(FlutterActorArtboard artboard, double elapsed); -} +abstract class FlareController { + void initialize(FlutterActorArtboard artboard); -class FlareActor extends LeafRenderObjectWidget -{ - final String filename; - final String animation; - final BoxFit fit; - final Alignment alignment; - final bool isPaused; - final bool shouldClip; - final FlareController controller; - final FlareCompletedCallback callback; - final Color color; - final String boundsNode; - - FlareActor(this.filename, {this.boundsNode, this.animation, this.fit = BoxFit.contain, this.alignment = Alignment.center, this.isPaused = false, this.controller, this.callback, this.color, this.shouldClip = true}); - - @override - RenderObject createRenderObject(BuildContext context) - { - return new FlareActorRenderObject() - ..filename = filename - ..fit = fit - ..alignment = alignment - ..animationName = animation - ..isPlaying = (!isPaused && animation != null) || controller != null - ..controller = controller - ..completed = callback - ..color = color - ..shouldClip = shouldClip - ..boundsNodeName = boundsNode; - } + void setViewTransform(Mat2D viewTransform); - @override - void updateRenderObject(BuildContext context, covariant FlareActorRenderObject renderObject) - { - renderObject - ..filename = filename - ..fit = fit - ..alignment = alignment - ..animationName = animation - ..isPlaying = (!isPaused && animation != null) || controller != null - .. color = color - ..shouldClip = shouldClip - ..boundsNodeName = boundsNode; - } + bool advance(FlutterActorArtboard artboard, double elapsed); +} - didUnmountRenderObject(covariant FlareActorRenderObject renderObject) - { - renderObject.dispose(); - } +class FlareActor extends LeafRenderObjectWidget { + final String filename; + final String animation; + final BoxFit fit; + final Alignment alignment; + final bool isPaused; + final bool shouldClip; + final FlareController controller; + final FlareCompletedCallback callback; + final Color color; + final String boundsNode; + + FlareActor(this.filename, {this.boundsNode, this.animation, this.fit = BoxFit + .contain, this.alignment = Alignment + .center, this.isPaused = false, this.controller, this.callback, this.color, this.shouldClip = true}); + + @override + RenderObject createRenderObject(BuildContext context) { + return new FlareActorRenderObject() + ..filename = filename + ..fit = fit + ..alignment = alignment + ..animationName = animation + ..isPlaying = (!isPaused && animation != null) || controller != null + ..controller = controller + ..completed = callback + ..color = color + ..shouldClip = shouldClip + ..boundsNodeName = boundsNode; + } + + @override + void updateRenderObject(BuildContext context, + covariant FlareActorRenderObject renderObject) { + renderObject + ..filename = filename + ..fit = fit + ..alignment = alignment + ..animationName = animation + ..isPlaying = (!isPaused && animation != null) || controller != null + .. color = color + ..shouldClip = shouldClip + ..boundsNodeName = boundsNode; + } + + didUnmountRenderObject(covariant FlareActorRenderObject renderObject) { + renderObject.dispose(); + } } -class FlareAnimationLayer -{ - String name; - ActorAnimation animation; - double time = 0.0, mix = 0.0; +class FlareAnimationLayer { + String name; + ActorAnimation animation; + double time = 0.0, + mix = 0.0; } -class FlareActorRenderObject extends RenderBox -{ - String _filename; - BoxFit _fit; - Alignment _alignment; - String _animationName; - String _boundsNodeName; - FlareController _controller; - FlareCompletedCallback _completedCallback; - double _lastFrameTime = 0.0; - double _mixSeconds = 0.2; - - List _animationLayers = []; - bool _isPlaying; - bool shouldClip; - - FlutterActor _actor; - FlutterActorArtboard _artboard; - AABB _setupAABB; - int _frameCallbackID; - - Color _color; - - Color get color => _color; - set color(Color value) - { - if(value != _color) - { - _color = value; - markNeedsPaint(); - } +class FlareActorRenderObject extends RenderBox { + String _filename; + BoxFit _fit; + Alignment _alignment; + String _animationName; + String _boundsNodeName; + FlareController _controller; + FlareCompletedCallback _completedCallback; + double _lastFrameTime = 0.0; + double _mixSeconds = 0.2; + + List _animationLayers = []; + bool _isPlaying; + bool shouldClip; + + FlutterActor _actor; + FlutterActorArtboard _artboard; + AABB _setupAABB; + int _frameCallbackID; + + Color _color; + + Color get color => _color; + + set color(Color value) { + if (value != _color) { + _color = value; + markNeedsPaint(); } + } - String get boundsNodeName => _boundsNodeName; - set boundsNodeName(String value) - { - if(_boundsNodeName == value) - { - return; - } - _boundsNodeName = value; - if(_artboard != null) - { - ActorNode node = _artboard.getNode(_boundsNodeName); - if(node is ActorDrawable) - { - _setupAABB = (node as ActorDrawable).computeAABB(); - } - } - } - - void dispose() - { - _isPlaying = false; - updatePlayState(); - _actor = null; - _controller = null; - } - - void updateBounds() - { - if(_actor != null) - { - ActorNode node; - if(_boundsNodeName != null && (node = _artboard.getNode(_boundsNodeName)) is ActorDrawable) - { - _setupAABB = (node as ActorDrawable).computeAABB(); - } - else - { - _setupAABB = _artboard.artboardAABB(); - //_setupAABB = _artboard.computeAABB(); - } - } - } - - BoxFit get fit => _fit; - set fit(BoxFit value) - { - if(value != _fit) - { - _fit = value; - markNeedsPaint(); - } - } + String get boundsNodeName => _boundsNodeName; - bool get isPlaying => _isPlaying; - set isPlaying(bool value) - { - if(value != _isPlaying) - { - _isPlaying = value; - updatePlayState(); - } + set boundsNodeName(String value) { + if (_boundsNodeName == value) { + return; } - - updatePlayState() - { - if(_isPlaying) - { - if(_frameCallbackID == null) - { - _frameCallbackID = SchedulerBinding.instance.scheduleFrameCallback(beginFrame); - } - } - else - { - if(_frameCallbackID != null) - { - SchedulerBinding.instance.cancelFrameCallbackWithId(_frameCallbackID); - } - _lastFrameTime = 0; - } - } - - String get animationName => _animationName; - set animationName(String value) - { - if(value != _animationName) - { - _animationName = value; - _updateAnimation(); - } + _boundsNodeName = value; + if (_artboard != null) { + ActorNode node = _artboard.getNode(_boundsNodeName); + if (node is ActorDrawable) { + _setupAABB = (node as ActorDrawable).computeAABB(); + } } - - FlareController get controller => _controller; - set controller(FlareController c) - { - if(_controller != c) - { - _controller = c; - if(_controller != null && _artboard != null) - { - _controller.initialize(_artboard); - } - } + } + + void dispose() { + _isPlaying = false; + updatePlayState(); + _actor = null; + _controller = null; + } + + void updateBounds() { + if (_actor != null) { + ActorNode node; + if (_boundsNodeName != null && + (node = _artboard.getNode(_boundsNodeName)) is ActorDrawable) { + _setupAABB = (node as ActorDrawable).computeAABB(); + } + else { + _setupAABB = _artboard.artboardAABB(); + //_setupAABB = _artboard.computeAABB(); + } } + } - String get filename => _filename; - set filename(String value) - { - if(value != _filename) - { - _filename = value; - if(_actor != null) - { - _actor.dispose(); - _actor = null; - _artboard = null; - } - if(_filename == null) - { - markNeedsPaint(); - return; - } + BoxFit get fit => _fit; - FlutterActor actor = new FlutterActor(); - actor.loadFromBundle(_filename).then( - (bool success) { - if(success) - { - _actor = actor; - _artboard = _actor?.artboard;//?.makeInstance(); - if(_artboard != null) - { - _artboard.advance(0.0); - updateBounds(); - // _setupAABB[0] -= 5000.0; - // _setupAABB[1] -= 5000.0; - // _setupAABB[2] += 5000.0; - // _setupAABB[3] += 5000.0; - - //print("SETUP AABB $_setupAABB"); - // _setupAABB[0] = -261.97979736328125; - // _setupAABB[1] = -1001.48486328125; - // _setupAABB[2] = 248.85952758789062; - // _setupAABB[3] = -33.52388381958008; - } - if(_controller != null) - { - _controller.initialize(_artboard); - } - _updateAnimation(onlyWhenMissing: true); - markNeedsPaint(); - updatePlayState(); - } - } - ); - } + set fit(BoxFit value) { + if (value != _fit) { + _fit = value; + markNeedsPaint(); } + } + + bool get isPlaying => _isPlaying; - Alignment get alignment => _alignment; - set alignment(Alignment value) - { - if(value != _alignment) - { - _alignment = value; - markNeedsPaint(); - } + set isPlaying(bool value) { + if (value != _isPlaying) { + _isPlaying = value; + updatePlayState(); + } + } + + updatePlayState() { + if (_isPlaying) { + if (_frameCallbackID == null) { + _frameCallbackID = + SchedulerBinding.instance.scheduleFrameCallback(beginFrame); + } } + else { + if (_frameCallbackID != null) { + SchedulerBinding.instance.cancelFrameCallbackWithId(_frameCallbackID); + } + _lastFrameTime = 0; + } + } + + String get animationName => _animationName; - FlareCompletedCallback get completed => _completedCallback; - set completed(FlareCompletedCallback value) - { - if(_completedCallback != value) - { - _completedCallback = value; - } + set animationName(String value) { + if (value != _animationName) { + _animationName = value; + _updateAnimation(); } + } - @override - bool get sizedByParent => true; + FlareController get controller => _controller; + + set controller(FlareController c) { + if (_controller != c) { + _controller = c; + if (_controller != null && _artboard != null) { + _controller.initialize(_artboard); + } + } + } + + String get filename => _filename; + + set filename(String value) { + if (value != _filename) { + _filename = value; + if (_actor != null) { + _actor.dispose(); + _actor = null; + _artboard = null; + } + if (_filename == null) { + markNeedsPaint(); + return; + } + + FlutterActor actor = new FlutterActor(); + actor.loadFromBundle(_filename).then( + (bool success) { + if (success) { + _actor = actor; + _artboard = _actor?.artboard; //?.makeInstance(); + if (_artboard != null) { + _artboard.advance(0.0); + updateBounds(); + // _setupAABB[0] -= 5000.0; + // _setupAABB[1] -= 5000.0; + // _setupAABB[2] += 5000.0; + // _setupAABB[3] += 5000.0; + + //print("SETUP AABB $_setupAABB"); + // _setupAABB[0] = -261.97979736328125; + // _setupAABB[1] = -1001.48486328125; + // _setupAABB[2] = 248.85952758789062; + // _setupAABB[3] = -33.52388381958008; + } + if (_controller != null) { + _controller.initialize(_artboard); + } + _updateAnimation(onlyWhenMissing: true); + markNeedsPaint(); + updatePlayState(); + } + } + ); + } + } - @override - bool hitTestSelf(Offset screenOffset) => true; + Alignment get alignment => _alignment; - @override - performResize() - { - size = constraints.biggest; + set alignment(Alignment value) { + if (value != _alignment) { + _alignment = value; + markNeedsPaint(); } + } + + FlareCompletedCallback get completed => _completedCallback; - @override - void performLayout() - { - super.performLayout(); + set completed(FlareCompletedCallback value) { + if (_completedCallback != value) { + _completedCallback = value; } + } - void beginFrame(Duration timestamp) - { - _frameCallbackID = null; - if(_actor == null) - { - return; - } - final double t = timestamp.inMicroseconds / Duration.microsecondsPerMillisecond / 1000.0; - if(_lastFrameTime == 0 || _actor == null) - { - _lastFrameTime = t; - updatePlayState(); - return; - } - - double elapsedSeconds = t - _lastFrameTime; - _lastFrameTime = t; - - int lastFullyMixed = -1; - double lastMix = 0.0; - - List completed = []; - - for(int i = 0; i < _animationLayers.length; i++) - { - FlareAnimationLayer layer = _animationLayers[i]; - layer.mix += elapsedSeconds; - layer.time += elapsedSeconds; - - lastMix = (_mixSeconds == null || _mixSeconds == 0.0) ? 1.0 : min(1.0, layer.mix/_mixSeconds); - if(layer.animation.isLooping) - { - layer.time %= layer.animation.end; - } - layer.animation.apply(layer.time, _artboard, lastMix); - if(lastMix == 1.0) - { - lastFullyMixed = i; - } - if(layer.time > layer.animation.end) - { - completed.add(layer); - } - } - - if(lastFullyMixed != -1) - { - _animationLayers.removeRange(0, lastFullyMixed); - } - if(animationName == null && _animationLayers.length == 1 && lastMix == 1.0) - { - // Remove remaining animations. - _animationLayers.removeAt(0); - } - for(FlareAnimationLayer animation in completed) - { - _animationLayers.remove(animation); - if(_completedCallback != null) - { - _completedCallback(animation.name); - } - } + @override + bool get sizedByParent => true; - bool stopPlaying = true; - if(_animationLayers.length > 0) - { - stopPlaying = false; - } + @override + bool hitTestSelf(Offset screenOffset) => true; - if(_controller != null) - { - if(_controller.advance(_artboard, elapsedSeconds)) - { - stopPlaying = false; - } - } + @override + performResize() { + size = constraints.biggest; + } - isPlaying = !stopPlaying; + @override + void performLayout() { + super.performLayout(); + } - updatePlayState(); + void beginFrame(Duration timestamp) { + _frameCallbackID = null; + if (_actor == null) { + return; + } + final double t = timestamp.inMicroseconds / + Duration.microsecondsPerMillisecond / 1000.0; + if (_lastFrameTime == 0 || _actor == null) { + _lastFrameTime = t; + updatePlayState(); + return; + } - if(_artboard != null) - { - _artboard.advance(elapsedSeconds); - } + double elapsedSeconds = t - _lastFrameTime; + _lastFrameTime = t; + + int lastFullyMixed = -1; + double lastMix = 0.0; + + List completed = []; + + for (int i = 0; i < _animationLayers.length; i++) { + FlareAnimationLayer layer = _animationLayers[i]; + layer.mix += elapsedSeconds; + layer.time += elapsedSeconds; + + lastMix = (_mixSeconds == null || _mixSeconds == 0.0) ? 1.0 : min( + 1.0, layer.mix / _mixSeconds); + if (layer.animation.isLooping) { + layer.time %= layer.animation.end; + } + layer.animation.apply(layer.time, _artboard, lastMix); + if (lastMix == 1.0) { + lastFullyMixed = i; + } + if (layer.time > layer.animation.end) { + completed.add(layer); + } + } - markNeedsPaint(); + if (lastFullyMixed != -1) { + _animationLayers.removeRange(0, lastFullyMixed); + } + if (animationName == null && _animationLayers.length == 1 && + lastMix == 1.0) { + // Remove remaining animations. + _animationLayers.removeAt(0); + } + for (FlareAnimationLayer animation in completed) { + _animationLayers.remove(animation); + if (_completedCallback != null) { + _completedCallback(animation.name); + } } - @override - void paint(PaintingContext context, Offset offset) - { - final Canvas canvas = context.canvas; - - if(_artboard != null) - { - AABB bounds = _setupAABB; - double contentWidth = bounds[2] - bounds[0]; - double contentHeight = bounds[3] - bounds[1]; - double x = -bounds[0] - contentWidth/2.0 - (_alignment.x * contentWidth/2.0); - double y = -bounds[1] - contentHeight/2.0 - (_alignment.y * contentHeight/2.0); - - double scaleX = 1.0, scaleY = 1.0; - - canvas.save(); - if(this.shouldClip) - { - canvas.clipRect(offset & size); - } + bool stopPlaying = true; + if (_animationLayers.length > 0) { + stopPlaying = false; + } - switch(_fit) - { - case BoxFit.fill: - scaleX = size.width / contentWidth; - scaleY = size.height / contentHeight; - break; - case BoxFit.contain: - double minScale = min(size.width/contentWidth, size.height/contentHeight); - scaleX = scaleY = minScale; - break; - case BoxFit.cover: - double maxScale = max(size.width/contentWidth, size.height/contentHeight); - scaleX = scaleY = maxScale; - break; - case BoxFit.fitHeight: - double minScale = size.height/contentHeight; - scaleX = scaleY = minScale; - break; - case BoxFit.fitWidth: - double minScale = size.width/contentWidth; - scaleX = scaleY = minScale; - break; - case BoxFit.none: - scaleX = scaleY = 1.0; - break; - case BoxFit.scaleDown: - double minScale = min(size.width/contentWidth, size.height/contentHeight); - scaleX = scaleY = minScale < 1.0 ? minScale : 1.0; - break; - } + if (_controller != null) { + if (_controller.advance(_artboard, elapsedSeconds)) { + stopPlaying = false; + } + } - if(_controller != null) - { - Mat2D transform = new Mat2D(); - transform[4] = offset.dx + size.width/2.0 + (_alignment.x * size.width/2.0); - transform[5] = offset.dy + size.height/2.0 + (_alignment.y * size.height/2.0); - Mat2D.scale(transform, transform, new Vec2D.fromValues(scaleX, scaleY)); - Mat2D center = new Mat2D(); - center[4] = x; - center[5] = y; - Mat2D.multiply(transform, transform, center); - _controller.setViewTransform(transform); - } + isPlaying = !stopPlaying; - canvas.translate( - offset.dx + size.width/2.0 + (_alignment.x * size.width/2.0), - offset.dy + size.height/2.0 + (_alignment.y * size.height/2.0), - ); + updatePlayState(); - canvas.scale(scaleX, scaleY); - canvas.translate(x,y); - _artboard.draw(canvas, overrideColor : _color); - canvas.restore(); - } + if (_artboard != null) { + _artboard.advance(elapsedSeconds); } - _updateAnimation({bool onlyWhenMissing = false}) - { - if(onlyWhenMissing && _animationLayers.isNotEmpty) - { - return; - } - if(_animationName != null && _artboard != null) - { - ActorAnimation animation = _artboard.getAnimation(_animationName); - if(animation != null) - { - _animationLayers.add(new FlareAnimationLayer() - ..name = _animationName - ..animation = animation - ..mix = 1.0); - animation.apply(0.0, _artboard, 1.0); - _artboard.advance(0.0); - } - updatePlayState(); - } + markNeedsPaint(); + } + + @override + void paint(PaintingContext context, Offset offset) { + final Canvas canvas = context.canvas; + + if (_artboard != null) { + AABB bounds = _setupAABB; + double contentWidth = bounds[2] - bounds[0]; + double contentHeight = bounds[3] - bounds[1]; + double x = -bounds[0] - contentWidth / 2.0 - + (_alignment.x * contentWidth / 2.0); + double y = -bounds[1] - contentHeight / 2.0 - + (_alignment.y * contentHeight / 2.0); + + double scaleX = 1.0, + scaleY = 1.0; + + canvas.save(); + if (this.shouldClip) { + canvas.clipRect(offset & size); + } + + switch (_fit) { + case BoxFit.fill: + scaleX = size.width / contentWidth; + scaleY = size.height / contentHeight; + break; + case BoxFit.contain: + double minScale = min( + size.width / contentWidth, size.height / contentHeight); + scaleX = scaleY = minScale; + break; + case BoxFit.cover: + double maxScale = max( + size.width / contentWidth, size.height / contentHeight); + scaleX = scaleY = maxScale; + break; + case BoxFit.fitHeight: + double minScale = size.height / contentHeight; + scaleX = scaleY = minScale; + break; + case BoxFit.fitWidth: + double minScale = size.width / contentWidth; + scaleX = scaleY = minScale; + break; + case BoxFit.none: + scaleX = scaleY = 1.0; + break; + case BoxFit.scaleDown: + double minScale = min( + size.width / contentWidth, size.height / contentHeight); + scaleX = scaleY = minScale < 1.0 ? minScale : 1.0; + break; + } + + if (_controller != null) { + Mat2D transform = new Mat2D(); + transform[4] = + offset.dx + size.width / 2.0 + (_alignment.x * size.width / 2.0); + transform[5] = + offset.dy + size.height / 2.0 + (_alignment.y * size.height / 2.0); + Mat2D.scale(transform, transform, new Vec2D.fromValues(scaleX, scaleY)); + Mat2D center = new Mat2D(); + center[4] = x; + center[5] = y; + Mat2D.multiply(transform, transform, center); + _controller.setViewTransform(transform); + } + + canvas.translate( + offset.dx + size.width / 2.0 + (_alignment.x * size.width / 2.0), + offset.dy + size.height / 2.0 + (_alignment.y * size.height / 2.0), + ); + + canvas.scale(scaleX, scaleY); + canvas.translate(x, y); + _artboard.draw(canvas, overrideColor: _color); + canvas.restore(); + } + } + + _updateAnimation({bool onlyWhenMissing = false}) { + if (onlyWhenMissing && _animationLayers.isNotEmpty) { + return; + } + if (_animationName != null && _artboard != null) { + ActorAnimation animation = _artboard.getAnimation(_animationName); + if (animation != null) { + _animationLayers.add(new FlareAnimationLayer() + ..name = _animationName + ..animation = animation + ..mix = 1.0); + animation.apply(0.0, _artboard, 1.0); + _artboard.advance(0.0); + } + updatePlayState(); } + } } \ No newline at end of file