From 81b8512b4171f736c36a8ab3ca5475d6ddcbc05f Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Wed, 3 Jun 2015 10:20:33 -0700 Subject: [PATCH] Add support for transforms to container These transforms are currently very basic but they seem to mostly work. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/1152273004 --- examples/fn2/container.dart | 2 - examples/raw/transform.dart | 27 +++++++++++ sdk/lib/framework/fn2.dart | 23 ++++++++- sdk/lib/framework/rendering/box.dart | 72 +++++++++++++++++++++++++++- sdk/pubspec.yaml | 1 + 5 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 examples/raw/transform.dart diff --git a/examples/fn2/container.dart b/examples/fn2/container.dart index a3509c455f3..a236a42e271 100644 --- a/examples/fn2/container.dart +++ b/examples/fn2/container.dart @@ -10,7 +10,6 @@ class ContainerApp extends App { UINode build() { return new EventListenerNode( new BlockContainer(children: [ - new Rectangle(0xFF00FFFF, key: 1), new Container( padding: new EdgeDims.all(10.0), margin: new EdgeDims.all(10.0), @@ -23,7 +22,6 @@ class ContainerApp extends App { desiredSize: new sky.Size(double.INFINITY, 20.0) ) ])), - new Rectangle(0xFF0000FF, key: 3) ]), onPointerDown: _handlePointerDown); } diff --git a/examples/raw/transform.dart b/examples/raw/transform.dart new file mode 100644 index 00000000000..b5c04a58daf --- /dev/null +++ b/examples/raw/transform.dart @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:sky' as sky; +import 'package:sky/framework/app.dart'; +import 'package:sky/framework/rendering/flex.dart'; +import 'package:sky/framework/rendering/box.dart'; +import 'package:vector_math/vector_math.dart'; + +AppView app; + +void main() { + RenderDecoratedBox green = new RenderDecoratedBox( + decoration: new BoxDecoration(backgroundColor: 0xFF00FF00)); + RenderSizedBox box = new RenderSizedBox( + desiredSize: new sky.Size(200.0, 200.0), child: green); + + Matrix4 transform = new Matrix4.identity(); + RenderTransform spin = new RenderTransform( + transform: transform, child: box); + spin.rotateZ(1.0); + + RenderFlex flex = new RenderFlex(); + flex.add(spin); + app = new AppView(flex); +} diff --git a/sdk/lib/framework/fn2.dart b/sdk/lib/framework/fn2.dart index 427f58b47c8..10b93c563bb 100644 --- a/sdk/lib/framework/fn2.dart +++ b/sdk/lib/framework/fn2.dart @@ -4,12 +4,13 @@ library fn; +import 'app.dart'; import 'dart:async'; import 'dart:collection'; import 'dart:mirrors'; import 'dart:sky' as sky; +import 'package:vector_math/vector_math.dart'; import 'reflect.dart' as reflect; -import 'app.dart'; import 'rendering/block.dart'; import 'rendering/box.dart'; import 'rendering/flex.dart'; @@ -395,6 +396,21 @@ class SizedBox extends OneChildRenderNodeWrapper { } } +class Transform extends OneChildRenderNodeWrapper { + RenderTransform root; + final Matrix4 transform; + + Transform({ this.transform, UINode child, Object key }) + : super(child: child, key: key); + + RenderTransform createNode() => new RenderTransform(transform: transform); + + void syncRenderNode(Transform old) { + super.syncRenderNode(old); + root.transform = transform; + } +} + final List _emptyList = new List(); abstract class OneChildListRenderNodeWrapper extends RenderNodeWrapper { @@ -850,6 +866,7 @@ abstract class Component extends UINode { class Container extends Component { final UINode child; + final Matrix4 transform; final EdgeDims margin; final BoxDecoration decoration; final sky.Size desiredSize; @@ -858,6 +875,7 @@ class Container extends Component { Container({ Object key, this.child, + this.transform, this.margin, this.decoration, this.desiredSize, @@ -867,6 +885,9 @@ class Container extends Component { UINode build() { UINode current = child; + if (transform != null) + current = new Transform(transform: transform, child: current); + if (padding != null) current = new Padding(padding: padding, child: current); diff --git a/sdk/lib/framework/rendering/box.dart b/sdk/lib/framework/rendering/box.dart index 803c85b2b88..76002fc56fa 100644 --- a/sdk/lib/framework/rendering/box.dart +++ b/sdk/lib/framework/rendering/box.dart @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'node.dart'; import 'dart:sky' as sky; +import 'dart:typed_data'; +import 'node.dart'; +import 'package:vector_math/vector_math.dart'; // GENERIC BOX RENDERING // Anything that has a concept of x, y, width, height is going to derive from this @@ -283,7 +285,75 @@ class RenderDecoratedBox extends RenderProxyBox { } super.paint(canvas); } +} +class RenderTransform extends RenderProxyBox { + RenderTransform({ + Matrix4 transform, + RenderBox child + }) : super(child) { + assert(transform != null); + this.transform = transform; + } + + Matrix4 _transform; + + void set transform (Matrix4 value) { + assert(value != null); + if (_transform == value) + return; + _transform = new Matrix4.copy(value); + markNeedsPaint(); + } + + void rotateX(double radians) { + _transform.rotateX(radians); + markNeedsPaint(); + } + + void rotateY(double radians) { + _transform.rotateY(radians); + markNeedsPaint(); + } + + void rotateZ(double radians) { + _transform.rotateZ(radians); + markNeedsPaint(); + } + + void translate(x, [double y = 0.0, double z = 0.0]) { + _transform.translate(x, y, z); + markNeedsPaint(); + } + + void scale(x, [double y, double z]) { + _transform.scale(x, y, z); + markNeedsPaint(); + } + + void hitTestChildren(HitTestResult result, { sky.Point position }) { + Matrix4 inverse = new Matrix4.zero(); + double det = inverse.copyInverse(_transform); + // TODO(abarth): Check the determinant for degeneracy. + + Vector3 position3 = new Vector3(position.x, position.y, 0.0); + Vector3 transformed3 = inverse.transform3(position3); + sky.Point transformed = new sky.Point(transformed3.x, transformed3.y); + super.hitTestChildren(result, position: transformed); + } + + void paint(RenderNodeDisplayList canvas) { + Float32List storage = _transform.storage; + + canvas.save(); + canvas.concat([ + storage[ 0], storage[ 1], storage[ 3], + storage[ 4], storage[ 5], storage[ 7], + storage[12], storage[13], storage[15], + ]); + super.paint(canvas); + canvas.restore(); + } } diff --git a/sdk/pubspec.yaml b/sdk/pubspec.yaml index 23e101f514a..2393b0fb8c9 100644 --- a/sdk/pubspec.yaml +++ b/sdk/pubspec.yaml @@ -6,3 +6,4 @@ version: 0.0.5 dependencies: mojo: '>=0.0.1 <1.0.0' mojom: '>=0.0.4 <1.0.0' + vector_math: '>=1.4.3 <2.0.0'