Amino 2: Overall Design
When redesigning Amino I had a few core goals. These goals are in place to guide the product and ensure we created something genuinely useful, and not become "yet another gfx lib".
Amino 2 must be:
- Simple: the api must be simple and easy to understand
- Responsive: the goal is to hit a consistent fps for all graphics on screen. 60fps on desktop and 30fps on mobile. This should be very doable with modern devices. The UI must always be responsive, even at the cost of accuracy or graphics complexity.
- Rich: complex effects and animation should be possible(shadows, gradients, real world textures, animation) while still hitting a consistent FPS.
- Speedable: we should be able to add speed improvements, including hardware acceleration, purely in the implementation. Speedups shouldn't affect the API. Existing apps just get faster over time.
- Subsettable: You should be able to use just the parts you need.
- Portable: Nothing of the underlying graphics implementation should be exposed. (we aren't there yet).
- Flexible: for lots of tasks you can just compose nodes together, but sometimes you may want to dig down to the lower levels. This should be possible, as long as you realize your code might not be as portable anymore.
With these goals in mind, here is the basic structure:
A Node is an object in the tree with a draw function. Anything which draws or affects drawing is a subclass of Node. This means all shapes, groups, transforms, imageviews, etc. Nodes also track their dirty state, and if they contain a given point (used for input processing). All nodes have parents (except the top most node)
A Parent is simple a node that implements the Parent interface. Currently only Group and Transform are parents.
A Scene is a tree of Nodes (a non-cyclical directed graph).
Everything is done on a single GUI thread. Touching nodes or trying to draw off the GUI thread is an error.
Resources (images, gradients, colors, textures) are immutable, to enable transparent caching.
Amino's internal system handles repaints, animation, and input events for you. you just create the tree of nodes and you are off to the races. By letting Amino handle these things we can ensure a consistent framerate and the best performance possible.
All events are generated by the system (usually by wrapping native events) and passed to your handlers through the event bus. You can listen to either a particular kind of event on a particular object, or all of that kind of event throughout the system. For example: Give me all mouse press events or Tell me when this node is clicked. Events will be automatically transformed into local coordinates when you click on transformed objects, and they are passed along with the target node of the event.
var runner = new Runner(); runner.setCanvas(document.getElementById("canvas")); var g = new Group(); g.add(new Rect().setWidth(100).setHeight(50).setFill("green")) .add(new Rect().setWidth(50).setHeight(50).setY(100).setFill("yellow")) ; var r = new Rect().set(-25,-25,50,50).setFill("white"); var t = new Transform(r).setTranslateX(100).setTranslateY(100); g.add(t); runner.addAnim(new Anim(t,"rotation",0,90,1).setLoop(true).setAutoReverse(false)); runner.addAnim(new Anim(t,"translateX",100,500,4).setLoop(true).setAutoReverse(true)); runner.addAnim(new Anim(t,"translateY",100,150,0.5).setLoop(true).setAutoReverse(true)); runner.root = g; runner.start();
final Core runner = new Core(); runner.setSize(600,400); runner.setBackground(Color.BLACK); Group g = new Group(); g.add(new Rect().setWidth(100).setHeight(50).setFill(Color.GREEN)) .add(new Rect().setWidth(50).setHeight(50).setFill(Color.YELLOW).setY(100)) ; Rect r = new Rect().set(-25, -25, 50, 50); r.setFill(Color.WHITE); Transform t = new Transform(r).setTranslateX(100).setTranslateY(100); g.add(t); runner.addAnim(new PropAnim(t,"rotation",0,90,1).setLoop(true).setAutoReverse(false)); runner.addAnim(new PropAnim(t,"translateX",100,500,4).setLoop(true).setAutoReverse(true)); runner.addAnim(new PropAnim(t,"translateY",100,150,0.5).setLoop(true).setAutoReverse(true)); runner.root = g; runner.start();
Amino 2 is still very much a work in progress, but so far I'm happy with the design. I've made several TouchPad apps already with decent performance, and the API really simplifies Java2D coding. Next I'm working on more graphics primitives, buffered effects, and a simple path API.
Posted March 14th, 2011