Tuesday May 13, 2008

Java on the NVidia APX 2500

Ken Russell describes the experience. This device kicks the IPhone's butt all over the place.

NVidia has created a beautiful platform, supporting a full media stack - OpenGL ES-2.0, OpenMAX-IL, OpenVG. In addition, they've created their own 3D compositing window manager, which they're contributing to Khronos as part of OpenKode.

One thing that I find interesting is how easily the CDC/FP JRE + JOGL ported (note this does not include the AWT, Java2D, Swing etc - which is no coincidence).

Wednesday May 07, 2008

JavaOne 2008

We presented our JavaFX keynote demos yesterday, including Moontank
A true 3D, multiplayer game written in JavaFX script, which includes spatialized audio via OpenAL. Moontank was designed by Anthony Rogers of Tomato design fame. The 3D models, textures, and audio assets were created by Anthony. The JavaFX application itself was written by Gerard Ziemski, and the OpenAL support thanks to Ken Russell. The actual moon images (provided by NASA) are also thanks to Ken.

Those at JavaOne can come by the JavaFX Pod and play it yourself.

Thursday Dec 20, 2007

Key-Frame Animation

It's unfortunate that OpenJFX currently isn't a real open-source project. As such, it gives the appearance that progress isn't being made with JavaFX Script. Nevertheless, evolution has occurred, albeit internally.

I've worked on replacing the animation framework in JavaFX with something more complete and consistent. This was always intended to happen. The presently available animation mechanism (the "dur" operator) was a temporary solution added to F3 more than a year ago, was never thought to be an adequate solution, and clearly isn't to anyone who has ever actually tried to use it.

The supported animation idiom is now that of "Key Frame" animation, as in traditional animation and visual design tools. My view (after significant research) is that this same idiom is also the most effective technique for describing animations programmatically. The concept is that you describe the animated state transitions of your "scene" by declaring start and end "snapshots" of state at certain points in time, and declare interpolation functions to calculate the in-between states.

Given this input the system can automatically perform the animation, stop it, pause it, resume it, reverse it, or repeat it when requested. Thus it is a "declarative" animation technique.

Programmatically such "snapshots" consist of specifying the values for JavaFX variables - local variables and instance variables.

Here are some examples:

  1. Simple A very simple example, which demonstrates simultaneous animation of the rotation, scale, and fill color of a rectangle.
  2. Ball Consists of three concurrent repeating animations: one for the x coordinate of the ball, one which animates the y coordinate, and the one which animates the scale to create a "bounce" effect. See line 65 for the animations.
  3. Motomaxxve Consists of only one keyframe animation whose "position" is bound to a Slider, such that you can manually "play" it by moving the slider. Left-click on the content will play it forward, Right-click will reverse it. One interesting point is that the text animations are dynamically generated.
  4. EG Consists of several animations (fade, slide): one of which is a kind of ticker-tape view of the presenters at the 2007 "Entertainment Gathering" at the Getty Museum. The others support a slide show view.
  5. Poker Video poker game. Consists of two animations: 1 for the deal, and 1 for the draw, each of which animates the bet, turning over the cards, and scoring (if you have a winning hand).

You'll want to take a look at the examples for reference as you read the below, I think.

Time Literals

Since time is fundamental to animation, I've added time "literals" to the language. These are instances of the following primitive class:

public class Time extends java.lang.Comparable {

    public attribute millis: Integer;
    public attribute seconds: Number;
    public attribute minutes: Number;
    public attribute hours: Number;

    public operation toMillis():Integer;
    public operation add(other:Time):Time;
    public operation subtract(other:Time):Time;
    public operation multiplyBy(n:Number):Time;
    public operation divideBy(n:Number):Time;
    public operation equals(other): Boolean;
}

Numeric Literals with one of the suffixes (h, m, s, ms) are interpreted as Time literals, e.g:

    2s == Time {seconds: 2};  // true
Relational operators and arithmetic operators other than % are overloaded for Time types:

    2.5s < 5000ms;   // true

    2.5s \* 3  == 7.5s; // true

Timelines

A KeyFrame describes a set of end states of various properties of objects at a certain time instant relative to the start of the animation, together with interpolation specifications to calculate the in-between values relative to the previous frame. Lack of an interpolation specification indicates a "discrete" animation, meaning the value of the property instantaneously transitions to the value given in the key frame at the time instant of the key frame. A Timeline is an object that contains a list of key frames, together with operations to control the overall animation, to start it, stop it. repeat it, etc.

Timelines are instances of the following class:

public class Timeline {
    public attribute keyFrames: KeyFrame\*;
    public attribute repeatCount: Number;
    public attribute autoReverse: Boolean;
    public operation start();
    public operation stop();
    public operation pause();
    public operation resume();
    public operation reverseNow();
    public attribute position: Number?; // unit time interval	
}

where KeyFrame is:

public class KeyFrame {
    public attribute time: Time;
    public attribute keyValues: InterpolatedLValue\*;
    public attribute action: function()?;
    public attribute timelines: TimeLine\*; // included timelines
}

InterpolatedLValue has the following definition:

public class InterpolatedValue {
    public attribute value: Object;
    public attribute interpolate: function(values:Object\*, unitTimeInterval:Number):Object?;
}

public class InterpolatedLValue extends InterpolatedValue {
    public attribute target: &Object;
}

InterpolatedValue describes a pair (<value>, <interpolation_function>).

InterpolatedLValue describes a triple (<target property>, <value>, <interpolation function>).

Properties

Specification of the target property required adding "pointers" to the JavaFX script language. Pointer types are declared with the "&" symbol (as in the target attribute above), and pointer instances are obtained with the unary "&" operator and dereferenced with the unary "\*" operator, as in C, e.g:

    var x = 2;
    var px = &x;
    \*px == 2; // true
    \*px = 3;
    x == 3; // true
Properties in JavaFX are pointers to local variables or object attributes. In cases where these are "sequences" a pointer to an element of such a sequence is also a valid property.

Syntax

Although KeyFrame animations are normal JavaFX objects, special syntax is provided to make it easier to express than is possible with the standard object-literal syntax.

The "tween" operator is a a literal constructor for InterpolatedValue.

    100 tween LINEAR;
is equivalent to
    InterpolatedValue { value: 100, interpolate: LINEAR:Number }
The "=>" operator provides a literal constructor for a list of InterpolatedLValues:
    var x = 2;

    x => 100 tween LINEAR;
is equivalent to the following
    var x = 2;

    InterpolatedLValue {target: &x, value: 100, interpolate: LINEAR:Number};
However, you can also apply "=>" to a whole set of object properties using an object-literal like notation rather than just single property or variable, for example like this:
     var rect = Rect {};

     rect => {height: 400 tween EASEBOTH, width: 500, fill: blue tween LINEAR, clip: { shape: Rect => {height: 500, width: 600} };
The second line above is equivalent to this:
[InterpolatedLValue {
     target: &rect.height
     value: 500
     interpolate: EASEBOTH:Number
},
InterpolatedLValue {
     target: &rect.width
     value: 500
      interpolate: null
},
InterpolatedLValue {
      target &rect.fill
      value: blue:Color
      interpolate: LINEAR:Color
},
InterpolatedLValue {
      target: &((Rect)rect.clip.shape).height
       value: 500
       interpolate: null
},
InterpolatedLValue {
      target: &((Rect)rect.clip.shape).width
      value: 600
      interpolate: null
}]
Finally, the "at" and "after" operators are literal constructors of KeyFrame objects:
    var x = 2;
    var rect = Rect {...};

    at (2s) {
        x => 2 tween LINEAR;
        rect => {width: 400 tween EASEBOTH, fill: red tween EASEBOTH};
        trigger {
           println("at 2 seconds...");
        }
    }

    after (5s) {
        x => 100 tween EASEBOTH;
    }
The "trigger" clause allows you to associate an arbitrary callback with the key frame.

The time specified by "at" is relative to the start of the Timeline. The time specified by "after" is relative to the previous key frame.

The first example above is equivalent to:

    KeyFrame {
        time: 2s
        action: operation() { println("at 2 seconds..."); }
        keyValues:
        [InterpolatedLValue {
           target &x
           value: 2
           interpolate: LINEAR:Number
        },
        InterpolatedLValue {
           target: &rect.width
           value: 400
           interpolate: EASEBOTH:Number
        },
        InterpolatedLValue {
           target: &rect.fill
           value: red:Color
           interpolate: EASEBOTH:Color
        }]
    }
Timelines and KeyFrames may be composed hierarchically - a KeyFrame may use the "include" operator to include any number of Timelines, in which case the key frames that make up the included timelines are merged into the containing timeline at the time instant of the key frame. The above "Ball" example demonstrates this, reproduced here:
    var ax = Timeline {
        // x
        keyFrames:
        [at (0s) {
            x => 0;
        },
        at (10s) {
            x => 700 tween LINEAR;
        }]
        autoReverse: true
        repeatCount: INFINITY
    }
    
    var ay = Timeline {
        // y
        repeatCount: INFINITY
        keyFrames:
        [at (0s) {
            y => 0;
        },
        at (2.2s) {
            y => 375 tween SPLINE(0, 0, .5, 0);
        },
        at (2.25s) {
            y => 375;
        },
        at (4.5s) {
            y => 0 tween SPLINE(0, 0, 0, 0.5);
        }]
    }
    
    var sxy =  Timeline {
        // scale x y
        repeatCount: INFINITY
        
        keyFrames:
        [at (2.15s) {
            sx => 1;
            sy => 1;
        },
        at (2.25s) {
            sx => 1.2 tween LINEAR;
            sy => .7 tween LINEAR;
        },
        at (2.5s) {
            sy => 1 tween LINEAR;
            sx => 1 tween LINEAR;
        },
        at (4.5s) {
            sx => 1;
            sy => 1;
        }]
    }
    
    var clip = Timeline {
        repeatCount: INFINITY
        keyFrames: 
        at (0s) { 
           include ax, ay, sxy;
        }
    }
In the above example, the "clip" timeline combines the other three animations. Playing "clip" will play all the animations simultaneously (yet still taking into account each ones individual repeat behavior).

Thursday Nov 15, 2007

Compiled JavaFX Script

The JavaFX script compiler is still a work in progress, but here's an very basic implementation of the Bubblemark application using it.

We're still working on implementing the full JavaFX script runtime with the compiler. The above version is just using a provisional runtime and is just animating an image and doesn't implement the "bubbles" with vector graphics.

However, even so, the footprint and performance is now on par with what you should expect from the eventual production quality JavaFX script implementation.

Note: on some systems OS-level timer-resolution will limit your fps. E.g. you'll see a max of 64 fps for any of the bubblemark examples.

Saturday Aug 25, 2007

Bubblemark

This posting says some nice things about JavaFX, but also points out that in its current incarnation its performance is lacking:

The first thing you’ll notice is that it’s very slow. The demo takes a very long time to load and start, and real time performance is disappointing. Here is how it compares:

JavaFX — 14 fps
Firefox + Silverlight (JavaScript) — 56 fps
Firefox + Flex — 62 fps
Adobe AIR — 62 fps
Firefox + Silverlight (CLR) — 99 202 fps (update: 202 fps after fixing main timer’s latency)

(All tests were performed on Pentium M 1.7 machine under Windows XP SP2)

It is 4.4x slower than Flash and 7x 14x slower than Silverlight (CLR-based variant).

On a positive side, development with JavaFX is fun, the language is very compact and efficient for building complex dynamic layouts. There is a great converter to JavaFX from SVG format and JavaFXPad is done nicely too.

If only it were 5x faster!

Of course, our intention is to provide hardware-accelerated vector graphics and compile JavaFX script to JVM bytecode getting the full benefits of the hotspot virtual machine, and to provide an improved deployment system, and we're working on that.

The Bubblemark performance described above is caused by

  • Download time - size of the deployment unit - The bubblemark JNLP doesn't use pack200 compression so the download of the JavaFX runtime + the app is ~2.1 MB
  • Performance of the JavaFX interpreter in doing the collision detection - which is currently probably 50-100 times slower than doing it in Java
  • Lack of caching or hardware acceleration of the vector graphics and gradients that make up the ball
Eventually, a production-quality JavaFX will automatically provide these benefits but in the meantime because JavaFX builds on Java, it's possible to get respectable performance for Bubblemark by making a few minor changes:
  1. Use pack200 compression for the Jar files
  2. Do the collision detection in Java code
  3. Cache the vector graphic at the application level - since once created it's static in this application

Below's a version of Bubblemark in JavaFX that does that.

Here's a link to the source code

Thursday Aug 09, 2007

Programming Animations in FX

I've been trying to refactor the animation support in FX lately and discussed it with Brian Goetz while he was here, and here's the current state. These changes will be checked in to the OpenJFX repository shortly. Note: this about programming animations, not tool-support. I assume a tool will produce data structures that describe canned animations, not code like this.

My goal is to make it possible for the programmer to specify the required behavior and still be able to actually understand what his code is doing.

Animations are fundamentally updates. They assign values to properties (or invoke processes that do such) at certain time instants.

The traditional animation loop

while (animationIsRunning) {
    // update stuff
    wait(interval);
}

is easy to understand, but it has several drawbacks:

  1. It requires a dedicated thread - introducing data synchronization issues
  2. It doesn't handle jitter - "update stuff" can take variable amounts of time at each iteration, making the animation look choppy.
  3. Since the time consumed by "update stuff" is included in the loop, the animation will exhibit different behavior based on the speed of the processor.

FX provides a time iterated for loop which (I think) is as easy to understand but overcomes these limitations:

println("before the animation");

for (i in [1..10] dur 10000) {
     // update stuff
}

println("after the animation");

The above loop describes a discrete animation which executes every second for 10 seconds. In addition, the loop body is always executed in the current thread. However the loop still blocks until all 10 iterations are complete. Currently, this is implemented with the Event Queue Hack, but proper support for continuations could be provided via code generation by the FX compiler. Since the loop blocks, it can be intuitively incorporated into a larger sequential process, e.g;

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          for (i in [0..100] dur 1000) {
               x = i;
          }
          for (i in [0..100] dur 1000 {
               y = i;
          }
     }
}

The above moves the rectangle from (0, 0) to (100, 0) over 1 second, and then moves it from (100, 0) to (100, 100) over 1 second, when you click the mouse on the rectangle.

Now, sometimes we want animations to run in parallel. For this case, a nearly identical construct is provided, namely the update trigger:

trigger on (i = [1..10] dur 10000) {
      // update stuff
}

println("after the trigger, but the animation is still running");

In this case the body of the trigger is executed 10 times, once per second. However, unlike the for loop, the code after the trigger executes in parallel with the trigger's body. The body of the trigger is still executed in the same thread, however, when the timer triggers it:

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          trigger on (i = [0..100] dur 1000) {
               x = i;
          }
          trigger on (i = [0..100] dur 1000) {
               y = i;
          }
     }
}

In this example, the animations of x and y occur in parallel and the the rectangle moves diagonally from (0, 0) to (100, 100) over 1 second.

In the case of discrete animations such as these the "frame rate" for the loop body is duration/(sizeof input-1). For cases where an animation is conceptually continuous, a better approach is often to use a predefined (high) frame rate and interpolate between the values for each frame using some interpolation function. The syntax is open to discussion but here's how that works right now:

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          trigger on (i = [0, 100] dur 1000 motion LINEAR) {
               x = i;
          }
          trigger on (i = [0, 100] dur 1000 motion LINEAR) {
               y = i;
          }
     }
}

LINEAR is a predefined function that performs linear interpolation (you can plug in your own instead). The interpolation function is of the form

function<T> (inputValues:T\*, elapsedTimeAsUnitInterval: Number): T

As a shorthand for animating individual properties a form of the the assignment statement is also provided:

x = [0, 100] dur 1000 motion LINEAR;
y = [0, 100] dur 1000 motion LINEAR;

which is equivalent to the two triggers above in onMouseClicked().

Finally, for the case where the for loop actually doesn't do anything:

for (i in [0, 1] dur 1000) {
     // don't do anything
}

we have a shorthand called "wait"

wait(1000);

Below are a few test cases for these constructs:

  1. Video Poker
    Standalone
    FXPad
  2. Motorola Intro
    Standalone
    FXPad
  3. Simple Path Animation
    FXPad

Thursday Jul 26, 2007

Hotspot vs Adobe Tamarin VM? No contest.

Several people have told me of Adobe boasting about their Tamarin JavaScript VM, so I decided to look into it myself. I ran 100 iterations of the same Takeuchi Benchmark from my previous post with both Tamarin and Java SE 1.6 Hotspot VM and for this case I found Hotspot more than 25 times faster (see below).

Surprisingly (or maybe not) Adobe's ActionScript compiler (which generates the byte-code for Tamarin) itself is actually a Java application.

Here's Tamarin:


function tak(x:Number, y:Number , z:Number) {
    return y >= x ? z : tak(tak(x-1, y, z),
                            tak(y-1, z, x),
                            tak(z-1, x, y));
}

var i = 0;
while (i < 100) {
  tak(24, 16, 8);
  i++;
}

$ java -jar asc.jar -import builtin.abc tak.as
$ time ./avmplus tak.abc

real    0m58.587s
user    0m57.900s
sys     0m0.130s

And here's Java:

public class Tak {
    public static double tak(double x, double y, double z) {
        return y >= x ? z : tak(tak(x-1, y, z),
                                tak(y-1, z, x),
                                tak(z-1, x, y));
    }
    public static void main(String argv[]) {
        for (int i = 0; i < 100; i++) {
            tak(24, 16, 8);
        }
    }
}


$ time java -cp . Tak

real    0m2.231s
user    0m2.143s
sys     0m0.061s

Interestingly, I also tried the Mozilla Rhino JavaScript engine (which I contributed to years ago), which is a pure Java implementation of JavaScript with this result:
$ time java -jar js.jar -opt 9 tak.js

real    0m31.944s
user    0m31.718s
sys     0m0.181s

Saturday Jul 14, 2007

First steps with the JavaFX Compiler

Thanks to the efforts of Robert Field, Lubo Litchev, and Jonathan Gibbons of the Javac team, as well as Per Bothner and Brian Goetz (and also thanks to the organizational efforts of Bob Brewin, James Gosling, and Tom Ball) we have the beginnings of a JavaFX to JVM-byte-code compiler built on the same infrastructure as Javac.

Of course, the compiler is still incomplete, but it turns out to be far enough along to try a first performance benchmark (Takeuchi function):

import java.lang.System;

public class Tak {
  operation tak(x:Number, y: Number, z:Number):Number;
}

operation Tak.tak(x, y, z) {
   return if (y >= x)
       then z
       else tak(tak(x-1, y, z),
                tak(y-1, z, x),
                tak(z-1, x, y));
}

var tak = new Tak();
System.out.println("tak(24,16,8)={tak.tak(24, 16, 8)}");

$ time java -cp ".;dist/JavaFX.jar" TakMod
tak(24,16,8)=9.0

real    0m1.333s
user    0m0.010s
sys     0m0.020s

Here's the interpreter:

$ time bin/javafx.sh TakMod.fx
compile thread: Thread[main,5,main]
compile 0.04
tak(24,16,8)=9.0
init: 69.48

real    1m10.422s
user    0m0.190s
sys     0m0.130s
Speed improvement for this particular example is a pretty awesome 54x.

Tuesday Jul 10, 2007

Bidirectional binding

In addition to corrections to local variable binding the next update of the JavaFX interpreter will include extended bidirectional binding, including of logical negation, unary minus, arithmetic, and sequence indexing. Here's a JavaFXPad example you can try out:


// logical negation
var a = true;
var b = bind not a;
assert b == false;
b = true;
assert a == false; // passes

// arithmetic
var x = 10;
var y = bind -x + 100;
assert y == 90;
y = 40;
assert x == 60; // passes

// sequence elements
var seq = [1, 2, 3];
var elem1 = bind seq[1];
elem1 = 500;
assert seq == [1, 500, 3]; // passes
delete seq[1];
assert elem1 == 3; // passes
insert 0 as first into seq;
assert elem1 == 1; // passes
var value = bind elem1;
value = 999;
assert seq == [0, 999, 3]; // passes

Tuesday Jun 26, 2007

Preview of JavaFX Interpreter

As I mentioned we will be posting an update to OpenJFX shortly.

The interpreter now has proper support for binding local variables and partially enforces cardinality constraints.

Here's the latest JavaFXPad for you to try it out.

JavaFXPad also has some improvements:

  • You can have multiple statements and the value of the last statement will be displayed - without having to specify return.
  • Non-visual output is displayed - if the result isn't a Widget, Frame, or Node, the value of the result converted to a string will be displayed in a text area. Thus you can use JavaFXPad like a REPL for experimenting with the JavaFX language.

Sunday Jun 24, 2007

JavaFX SVG Translator Preview

It'll take a few more days before we post the code to OpenJFX, but in the meantime here's a preview of the latest version of our SVG to FX translator. The translator converts an SVG document into a single JavaFX class. Each definition id in the SVG is converted into a method of the class that returns the JavaFX equivalent of that element. The generated class itself is an instance of the JavaFX class Node, which means it can be used anywhere in a JavaFX Canvas.

Having this translator makes it straightforward to incorporate graphics created in vector drawing tools into JavaFX programs.

The below demo program consists of an SVG browser that uses the translator to convert SVG into JavaFX source code and then compiles and executes the result. In addition, the browser lets you view the original SVG source as well as the translated JavaFX source.

You can drag URL's that point at SVG files from web pages into the SVG Browser's canvas. It's pretty sad to see how little quality vector artwork is available on the public internet. Anyway, below are a few examples for you to try:

Saturday May 26, 2007

A Real DryerFox

When I ran across this Apollo example it occurred to me that I could pretty easily create a close Java equivalent of Apollo by combining JavaFX with WebRenderer.

WebRenderer provides a Java Swing component that encapsulates the Firefox browser. In addition, it provides an extensive Java API to interact with the browser including the full DOM. However, WebRenderer isn't free software.

Anyway, below's a screenshot of the JFX version. The dryer turns while a page is loading, but it doesn't have the sound effects (at least, not yet).

Unlike the above cited example (Apollo apparently uses WebKit) that really is a fully functioning Firefox inside the dryer, which is still interactive even while it turns.

Sunday May 13, 2007

JavaFX

As you probably heard at JavaOne, F3 is now called JavaFX. The initial public release is available here: http://openjfx.org. Please join me there for discussion and further development.

Tuesday Mar 20, 2007

JavaOne 2007

I'll be presenting a technical session on F3 at JavaOne this year on Wednesday, May 9.

This F3 example won't make it into my session, so I'll just post it here.

Source:

Game.f3

Ship.f3

Alien.f3

Missle.f3

Friday Feb 23, 2007

MacOS Dashboard Widgets

I recently got a Mac and took a look at their dashboard widgets. Such widgets consist of several files:
  • An HTML file
  • A CSS file
  • A JavaScript file
  • Image files

Of course, I had to try to see how hard it would be to do the same thing in F3. Here's the F3 version of the Calculator widget:

Unfortunately, it's currently impossible to create transparent windows in Java on non-MacOS platforms, so in those cases you won't see the dropshadow and rounded corners.

It only took a few minutes to write the visual elements in F3 (I just used F3Pad). And about another hour to add the behavior (I borrowed the design of the non-visual part of the calculator from an ancient Java applet I found on the net).

F3 Source:

Calculator.f3

Original Source:

Calculator.html
Calculator.css
Calculator.js
About

user12610627

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today