Wednesday Jun 10, 2009

JavaFX Design Tool

Although you probably didn't see me, I was at JavaOne, where they unveiled the JavaFX design tool. Although the demos were fairly minimal, the elegance, beauty, and genius of Anthony's design showed through to me.

TIMELINE DESIGN

Tuesday Jan 13, 2009

Collada MoonBuggy in JavaFX

Collada MoonBuggy with skin animation in JavaFX.

In the scripting API for this scene graph, animated Collada models are Nodes which are also polymorphic with Timelines. You can "play" them. Relevant code:


var model = Model {
    url: "lunar_lander_tris.dae"
    repeatCount: Timeline.INDEFINITE
}

model.play();

var zoom = 0.0;

var scene = Scene {
   background: BLACK;
   camera: PerspectiveCamera {
       heightAngle: 15
       nearDistance: 1
       farDistance: 1000
       position: bind Transform.translate(0, 0, 30+zoom);
   }
   lights: [...]
   content: model

}

...

Thursday Jan 08, 2009

Simple yet elegant vector user interfaces in JavaFX 1.0

It's very easy to create simple yet elegant custom vector user interface elements in JavaFX 1.0 by means of simple compositions of basic shapes. The above example consists entirely of compositions of simple triangles and (rounded) rectangles, together with some text.

The outer shell is a round rectangle from which two other round rectangles have been "subtracted", one for the control area, and one for the track of the slider. Behind this shape is a semi-transparent round rectangle of the same size. Due to the background color of the scene in the screenshot, you can't really tell, but the result is that you can partially "see through" these areas.

The "play", "back", and "forward", buttons are composed of a single triangle or two "added" together. The "pause" button consists of two rectangles "added" together. Finally, the thumb on the slider is simply a rectangle that's been rotated.

In JavaFX 1.0, you can declaratively compose vector shapes by means of the ShapeSubtract node. Although it's my personal opinion that this API element is poorly named and its member variables (a and b) overly obscure, nevertheless it's good enough to get the job done for now.

The a instance variable of ShapeSubtract takes a list of shapes which will be added together. Its b instance variable takes a list of shapes which will then be subtracted from that. ShapeSubtract is itself a shape and may be used in a larger composition.

Using JavaFX script, it's then very easy to factor such into reusable custom scene graph elements, and to make them interactive and/or animated.

Below is the full source code for the example.

/\*
 \* Main.fx
 \*
 \*/

package moviecontrol;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.\*;
import javafx.scene.\*;
import javafx.scene.shape.\*;
import javafx.scene.transform.\*;
import javafx.scene.paint.\*;
import javafx.scene.paint.Color.\*;
import javafx.scene.input.\*;
import java.lang.Math;
import java.lang.System;
import javafx.animation.\*;

def defaultFillColor = Color.color(.8, .8, .8, 1);
def selectedFillColor = WHITE;

class MovieButton extends CustomNode {

    // interface
    public var action: function():Void;
    public var icon: Shape;
    public var selectedIcon: Shape;
    public var selected: Boolean;


    // implementation
   
    var mouseOver: Boolean = bind hover;
    var mousePress: Boolean = false;
    var fillColor = bind if (mouseOver and mousePress) selectedFillColor else defaultFillColor;
    var path = bind
        if (selected and selectedIcon != null)
        ShapeSubtract { fill: bind fillColor, a: selectedIcon }
        else
        ShapeSubtract { fill: bind fillColor, a: icon };
    
   
    override protected function create():Node {
        Group {
            // center it 
            translateX: bind -path.boundsInLocal.width / 2;
            translateY: bind -path.boundsInLocal.height / 2;
            // mouse behavior
            onMouseReleased: function(e) {
                if (mouseOver) {
                    if (action != null) action();
                    selected = not selected;
                }
                mousePress = false;
            }
            onMousePressed: function(e) {
                mousePress = true;
            }
            // make an internal scene consisting of the icon shape
            // and an invisiable rectangle bounding it (so mouse
            // events anywhere within its bounding box are
            // accepted
            content:
            [Rectangle { 
                height: bind path.boundsInLocal.height;
                width: bind path.boundsInLocal.width;
                opacity: 0;
                fill: Color.BLACK;
            },
            Group {
                content: bind path;
            }];
        }
    }
}


class MovieControl extends CustomNode {

    public var back: function():Void;
    public var fwd: function():Void;
    public var paused: Boolean;
    public var loaded: Duration;
    public var setPosition: function(pos:Duration):Void;

    public var duration: Duration = 0s on replace {
        updateAlpha();
    }

    public var position: Duration  = 0s on replace {
        updateAlpha();
    }

    function updateAlpha():Void {
        if (duration != null and position != null and duration != 0s) {
            positionAlpha = position.toMillis() / duration.toMillis();
        }
    }

    var positionAlpha: Number;

    override protected function create():Node {
        Group {
            translateX: -150;
            translateY: -32;
            var bg:Rectangle;
            content:
            [bg = Rectangle { // semi-transparent background
                height: 64;
                width: 300;
                arcHeight: 20;
                arcWidth: 20;
                fill: Color.color(0, 0, 0, 0.2);
            },
            ShapeSubtract { // subtract the control area and slider track from the main body
                fill: defaultFillColor;
                a: Rectangle {
                    height: 64;
                    width: 300;
                    arcHeight: 20;
                    arcWidth: 20;
                }
                b:
                [Rectangle {
                   x: 1;
                   y: 1;
                   arcHeight: 20;
                   arcWidth: 20;
                   width: 298;
                   height: 48;
                },
                Rectangle {
                    x: 50;
                    y: 50;
                    height: 13;
                    width: 200;
                    arcHeight: 13;
                    arcWidth: 13;
                }]
             },
             Group { // place the text for the elapsed time and duration
                translateY: 52;
                var font = Font {size: 11};
                content:
                [Text {
                   x: 10;
                   y: 0;
                   textOrigin: TextOrigin.TOP
                   font: font;
                   fill: BLACK;
                   content: bind "{%tM position}:{%tS position}";
               },
               Text {
                  x: 254;
                  y: 0;
                  textOrigin: TextOrigin.TOP
                  font: font;
                  fill: BLACK;
                  content: bind if (duration == null or position == null) "" else "-{%tM duration.sub(position)}:{%tS duration.sub(position)}";
               }]
             },
             Group { // handle the slider thumb
                 var thumbX: Number = bind positionAlpha \* 190;
                 translateX: bind 51 + thumbX;
                 translateY: 52.5;
                 var thumb: Rectangle;
                 var startX = 0.0;
                 onMousePressed: function(e) {
                     startX = thumbX;
                 }
                 onMouseDragged: function(e) {
                     var x = startX + e.dragX;
                     x = Math.max(Math.min(x, 190), 0);
                     positionAlpha = x / 190;
                     if (setPosition != null) { setPosition(position); };
                 }
                 content: thumb = Rectangle {
                     var c = 8.0;
                     transforms: Transform.rotate(45, c/2, c/2);
                     height: c;
                     width: c;
                     var thumbMousePress = false;
                     onMousePressed: function(e) {
                         thumbMousePress = true;
                     }
                     onMouseReleased: function(e) {
                         thumbMousePress = false;
                     }
                     fill: bind if (thumbMousePress) selectedFillColor else defaultFillColor;
                 }
             },
             Group { // construct the various buttons
                 translateX: 100;
                 translateY: 24;
                 // functions for basic shape elements that
                 // are composed below
                 var u = 16.0;
                 var bar = function() {
                     Rectangle {
                        height: u;
                        width: u/3
                     }
                 };
                 var leftArrow = function() {
                     Polygon {
                        points: [0, u/2, u, 0, u, u];
                     }
                 };
                 var rightArrow = function() {
                     Polygon {
                         points: [0, 0, u, u/2, 0, u];
                     }
                 }
                 var backIcon = function() {
                     ShapeSubtract {
                         a:
                         [leftArrow(),
                          ShapeSubtract {
                             translateX: u;
                             a: leftArrow()
                         }]

                     }
                 };
                 var fwdIcon = function() {
                     ShapeSubtract {
                         a: [rightArrow(),
                             ShapeSubtract {
                                   translateX: u;
                                   a: rightArrow()
                             }];

                    }
                 };
                 var playIcon = function() {
                     ShapeSubtract {
                         transforms:
                         [Transform.scale(1.5, 1.5)];
                         a: rightArrow();
                     }
                 };
                 var pauseIcon = function() {
                     ShapeSubtract {
                         transforms:
                         [Transform.scale(1.5, 1.5)];
                         a:
                         [bar(), ShapeSubtract { translateX: u/2; a: bar()}];
                     }
                 };
                 content:
                 Group {
                     var buttons = 
                     [MovieButton {
                         icon: backIcon();
                         action: bind back;
                     },
                     MovieButton {
                         icon: pauseIcon();
                         selected: bind paused with inverse;
                         selectedIcon: playIcon()
                     },
                     MovieButton {
                         icon: fwdIcon();
                         action: bind fwd;
                     }];
                     content: for (i in buttons)
                     Group {
                         translateX: indexof i \* 42;
                         content: i;
                     }
                 }
             }]
         }
    }
}




/\*\*
 \* @author coliver
 \*/

// As a test simulate playing movies with a timeline


var duration = 5m;

function reset():Void {
    simulator.stop();
    paused = true;
}

var simulator = Timeline {
    keyFrames:
    KeyFrame {
        time: duration
    }
    repeatCount: Timeline.INDEFINITE;
};

var paused = true on replace {
    if (paused) { simulator.pause() } else { simulator.play() }
}


Stage{
    title: "Movie Control"
    width: 500
    height: 400

    scene: Scene{
         fill: BLACK;
         content: MovieControl {
             translateX: 250
             translateY: 180
             setPosition: function(pos:Duration) {               
                 simulator.time = pos;
             }
             fwd: reset
             back: reset
             paused: bind paused with inverse;
             duration: bind duration;
             position: bind simulator.time with inverse;
         }
    }
}

Wednesday Jan 07, 2009

JavaFX Script Keywords and Java Interoperability

In JavaFX script any sequence of characters enclosed in "french quotes" is treated as a lexical identifier, and thus may be used as a valid name of a variable, function, or class.
  var <<this is a variable>> = "Hello World";
  <<this is a variable>>.toUpperCase();

This mechanism may be used to access Java methods which conflict with JavaFX keywords, for example:

  var textArea = new javax.swing.JTextArea();
  textArea.<<insert>>("Hello World", 0);

This mechanism is also useful for code generators in translating symbols from other languages having incompatible lexical rules to JavaFX script.

Sunday Jan 04, 2009

From F3 to JavaFX 1.0 - Effects

An important and impressive innovation between F3 and JavaFX is the Effects framework created by Chris Campbell.

F3 had a simple system of software pixel filters, which could be applied to any Node or group of Nodes in a scene. However, thanks to Chris, JavaFX 1.0 includes a much more complete set of effects, and a sophisticated framework that enables GPU hardware acceleration where available.

Underlying the simple declarative expression of effects at the JavaFX script level, effect implementations are described in a GPU-shader-like procedural language, which Chris created, called JSL. Chris's JSL compiler then compiles to various targets, either GPU-based (GLSL/HLSL), or CPU-based (Java/Native).

Friday Jan 02, 2009

Performance matters - 25x for JavaFX script over Groovy and JRuby

JavaFX script

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

for (i in [1..1000]) {
    tak(24, 16, 8);
}
time javafx -server -cp . Tak

real    0m10.724s
user    0m10.105s
sys     0m0.173s
Groovy
def 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));
}


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

time java -Djava.ext.dirs=./groovy-1.6-RC-1/lib -server groovy.lang.GroovyShell tak.groovy

real    4m36.674s
user    4m29.272s
sys     0m3.842s

JRuby


def tak x, y, z
  unless y < x
    z
  else
    tak( tak(x-1, y, z),
         tak(y-1, z, x),
         tak(z-1, x, y))
  end
end

i = 0
while i<1000
        tak(24, 16, 8)
        i+=1
end

time ./jruby-1.1.6RC1/bin/jruby -J-server tak.rb

real    4m24.735s
user    4m22.203s
sys     0m1.069s

Summary

For this benchmark, as you can see both JRuby and Groovy are around 25x slower than JavaFX script.

Sunday Dec 28, 2008

Data binding in Silverlight and Flex compared to JavaFX 1.0...

Silverlight

Flex

Don't be fooled by the naysayers and the hype.

Although JavaFX 1.0 is only a few days old, when it comes to data binding: functionality-wise, usability-wise, and performance-wise it appears to me it's already "no contest".

I invite you to judge for yourselves.

For those who've never actually tried JavaFX script, let me just say this: any JavaFX script variable may be bound to any expression of any complexity (including function calls, Java method calls, loops, conditional expressions, block expressions, etc).

In case you haven't seen one, below is a very simple JavaFX 1.0 example. Here, the degrees variable is (bidirectionally) bound to a slider and simultaneously to the content of a text node. Meanwhile, the x and y variables are bound to expressions that compute the coordinates of the point corresponding to such an angle on a circle of the given radius. Besides the slider and the text, the stage contains two circles, a red one with the given radius, and a small blue one whose center is bound to the above point. As a result, moving the slider animates the blue circle around the red one.

import javafx.stage.\*;
import javafx.scene.\*;
import javafx.scene.shape.\*;
import javafx.scene.text.\*;
import javafx.scene.text.TextOrigin.\*;
import javafx.scene.paint.Color.\*;
import javafx.scene.layout.\*;
import javafx.ext.swing.\*;
import java.lang.Math.\*;

def radius = 50.0;
var degrees = 0;
var radians = bind toRadians(degrees);
var x = bind cos(radians) \* radius;
var y = bind sin(radians) \* radius;

Stage {
    title: "Binding"
    scene : Scene {
        width: 400 
        height: 260
        content: 
        VBox {
             translateX: 100
             translateY: 80
             spacing: 10
             content: 
             [SwingSlider {
                  minimum: 0
                  maximum: 360
                  value: bind degrees with inverse
             },
             Text {
                  textOrigin: TOP
                  content: bind "{degrees} degrees"
             },
             Group {
                 translateX: radius
                 translateY: radius
                 content: 
                 [Circle {
                     fill: RED
                     radius: radius
                 },
                 Circle {
                    radius: 10
                    fill: BLUE
                    centerX: bind x 
                    centerY: bind y
                }]
             }]
        }
    }
}

Saturday Dec 27, 2008

Performance matters, but for whom?

Alexander A. Stepanov (inventor of C++ STL):
Computers that were able to deal just with numbers evolved into computers with byte-addressable memory, flat address spaces, and pointers. This was a natural evolution reflecting the growing set of problems that people were solving. C, reflecting the genius of Dennis Ritchie, provided a minimal model of the computer that had evolved over 30 years. C was not a quick hack. As computers evolved to handle all kinds of problems, C, being the minimal model of such a computer, became a very powerful language to solve all kinds of problems in different domains very effectively. This is the secret of C's portability: it is the best representation of an abstract computer that we have. Of course, the abstraction is done over the set of real computers, not some imaginary computational devices. Moreover, people could understand the machine model behind C. It is much easier for an average engineer to understand the machine model behind C than the machine model behind Ada or even Scheme. C succeeded because it was doing the right thing, not because of AT&T promoting it or Unix being written with it.

Yukihiro Matsumoto (inventor of Ruby):

In my point of view, efficiency and productivity are the same thing, because we focus on programming efficiency, not runtime efficiency. I don't care about runtime efficiency. The computer goes faster and faster every year, so I don't really care about performance. Actually, I care about performance when I'm implementing the Ruby interpreter, but not when I'm designing Ruby. The implementer should care about performance, but the designer shouldn't. If you care about performance, you will focus on machines in design instead of on humans. So you shouldn't focus on performance in design.

Stepanov definitely influenced me at the time (early/mid nineties) and I got plenty of mileage out of STL (in spite of c++ compiler limitations) and I found (and still find) STL amazing. I actually never used Java professionally until 2000, tbh - like Stepanov I felt it was unusably slow for my purposes (and it was). However, by 2000 Hotspot had achieved a very impressive level of performance.

Although I can't say the same for Matz and Ruby, I think it's interesting to juxtapose their points of view.

Although I've never actually written a Ruby program, the processing requirements for such must be quite low - since Ruby's runtime performance is unconscionably poor by Stepanov's standards. I guess I can imagine a web server application which is supported by mostly static cached documents and dominated by the file system synchronization of a transactional database could be such a low-performance use case, and that is where Ruby seems to have found a niche.

Programming language compilers are "translators", which we require to translate from human expression to that of the machine.

In my opinion, designing a programming language is always a "mediation" between the needs of the human programmer and those of the machine - contrary to Matz.

Now, given the fact that runtime performance is a factor to the end user (i.e the customer - and the customer always comes first), it cannot simply be sacrificed when required to make the programmer's job easier.

OTOH, if the programmer's burden is too high, runtime performance may never come into question, since you'll fail to even deliver a product.

The design of F3 (now JavaFX script) was largely based on the concept that many perceived programmer ease-of-use features are not primarily related to the typical implementation techniques of so-called scripting languages, but rather to their purely linguistic characteristics - i.e. their correspondence to the language of the mind, rather than that of the machine - and that such features could be provided thanks to the Java platform without severely compromising runtime performance.

Object-orientation is one such feature - it corresponds to the way we conceptualize the world around us and allows us to navigate such concepts in a way that is natural to us.

Interestingly, Stepanov completely rejects this, focusing instead completely on the "generic" processing that applies across collections of objects at very high levels of abstraction.

Admirably in my opinion, Stepanov steadfastly refused to sacrifice the needs of the machine, yet nevertheless produced with STL a level of programming expression which was quite lovely to the human programmer (given that former constraint and those of the C++ language).

The beauty of the Java platform in my opinion has been that it does the best job of mediating these needs, overall, and that largely explains its success.

Java has many detractors on both sides - the C/C++ world thinks it's too slow, the Ruby-and-various-other-scripting-languages world that it's too hard to use. And everybody knows it's long been too big and monolithic.

Now, no one language or platform can be all things to all people. However, it's my belief that the Java platform - in spite of its wide use - is actually still under-utilized for many important use-cases - given current available alternatives.

Obviously, it's clear that I think one of those is the world of high-performance graphics and multimedia, which is currently still dominated by C and C++.

Surprisingly (or maybe not?) a similar tension exists among my colleagues here at Sun with respect to JavaFX script. There are those who actually think they're designing a language to serve (from their point of view) some lesser form of "web scripter" for whom they (incorrectly) perceive performance doesn't matter. Conversely, there are those who are acutely aware of the performance requirements of graphics and multimedia, who are dubious of the necessity and viability of JavaFX script (although they tend not to be forthcoming with any credible alternative, other than "just use Java" - but the fact is that's been done, and the barrier to entry is still too high).

Since I happen to think both points of view are wrong, it's my job to prove that, and to bring us together, and that's what I'm currently working on.

Although its scope is limited, in terms of finding something closer to the right level of "mediation" of performance/programmer-ease-of-use/functionality for this problem domain (and based on the Java platform), a good place to start is here.

Tuesday Dec 23, 2008

Media

For the observant who are in the "know" about making real media, there are a few glimpses (here, and here, and here, and here), and also the fact that the individuals who through self-motivation decided to revamp the Java browser plugin are actually 3d graphics experts, that we're not completely oblivious.

There's a broad cultural divide between the real media world, and the world of current 2d graphics toolkits, such as web browsers, Flash, JavaFX 1.0, Java Swing, Silverlight, QT, Cocoa, etc, etc.

An important thing to note is that this, and this (meaning the flash content on this web site), and this (meaning the actual product - not the web site), all run on the same consumer hardware. What differentiates them is the skill of the artists/designers involved, and the performance and capability of the software systems that enable such artists.

In spite of being composed of the very most simplistic graphics imaginable, the AJAX site above delivers unconscionably poor, stuttering, animation performance. In spite of being a premier 3d game engine provider, the Flash content on Crytek's web site is very poor animation-performance-wise (although a lot better than the web browser's) - and still remarkably simplistic (compared to Crytek's real product) - and obviously lack of availability of artists is not part of the equation in their case. Meanwhile EVE online brings you amazing graphics, sound, animation and interactivity with silky smooth performance.

At the end of the day, however, these discrepancies clearly are about hardware. It's impossible to get a sufficient frame-rate for smooth animation of non-trivial graphics without hardware acceleration (GPU + CPU SIMD) - even for 2d. This is the very reason for the existence of GPU hardware. By contrast, the web browser, Flash, Java2D, & etc have a software architecture which is not designed around leveraging such hardware, and such is the result you get.

The state of the art in real media is created and advanced in the world of movies, TV, and video games, not that of the PC desktop and web browser. Nevertheless, modern video game engines demonstrate that interactive, real-time, very high production quality, high-performance multimedia (2d and 3d animation and graphics, audio, and video), is possible on today's desktops and on the web, not to mention devices with multimedia hardware acceleration.

Monday Dec 22, 2008

Experiments with JavaFX script

A nice introduction to JavaFX script by Weiqi Gao.

Thursday Dec 11, 2008

JavaFX script - functional and procedural programming, and animation

Functional programming and procedural programming often provide different views of the same thing. When I declare a mathematical function, such as

   y = 2x

I may think of this as a procedure (sequential process): "Give me something, I'll double it, and then I'll give it back to you". However, I may also think of it as simply an expression of unchanging state: for example as an infinite line on a graph, without regard to any real process that may produce it.

In natural language, and in the language of the mind it's clear that both conceptualizations are useful and constantly used.

In JavaFX script, functional relationships may be expressed using the bind operator. Meanwhile, procedural code may sequentially change the values of the independent variables of such expressions over time and the system will automatically maintain those relationships.

Both procedural state changes and functional relationships derived from them are conceptually "instantaneous".

By contrast, "animation" describes what we perceive to be continuous state changes over time.

Any JavaFX script variable may be "animated" - not just those that represent properties of actual visual elements. Animating a variable amounts to assigning a new value to it "often enough" to create the perception of continuous change. For smooth animation of graphics "often enough" means at the refresh rate of your display (60 times per second for a typical LCD display).

Although possible, it would be quite onerous to specify each discrete change for each variable procedurally at each time step, and equally onerous to attempt to specify every variable as a function of time.

Fortunately, traditional animators invented an easier system, which has been adopted in computer animation. The animator (or programmer in the case of JavaFX script) specifies only the "key" states of a variable at various points along the time dimension, and provides an interpolation function to automatically compute the "in-between" states.

Although an animation can target any JavaFX script variable, it isn't necessary for the animation itself to directly modify all the variables it may affect. Instead, the programmer can place bindings and triggers on the variables targeted by the animation, which express additional effects.

So, for example, if I wanted to have a rectangle whose height was twice its width and whose size was animated over one second I could write something like this:

    var width: Number;  // animation target
    var height = bind width \* 2; // height has functional dependency on width

    var t = Timeline {
        keyFrames:   // list of key states
        [KeyFrame {
            time: 0s
            values: width => 100 // width is 100 at zero seconds
        },
        KeyFrame {
            time: 1s
            values: width => 200 tween LINEAR  // width is 200 at one second (and linearly interpolated in between)
        }]
    }

    t.play(); // procedurally start the animation
Although the code only animates the width variable, the height variable is also animated as a side effect of its functional dependency.

You've probably noticed there's no actual rectangle here. That's intentional. I can connect a visual rectangle to this logic separately in a decoupled way using additional functional dependencies:


   Rectangle {
       height: bind height
       width: bind width
       fill: BLUE
   }

Throwing that onto a Stage/Scene would give me graphical animation of a blue rectangle.

Monday Dec 08, 2008

JavaFX 1.0 on Mac - Don't jump to conclusions

Although JavaFX 1.0 runs on the Mac, keep in mind that the browser plugin on this platform is not new, but rather is the same problematic plugin that has been around for years - it has repainting bugs, memory leaks, thread leaks, the security dialog handling is broken, it blocks the browser during application loading, etc.

These are the very problems that motivated the new browser plugin, mentioned in my previous post.

The new browser plugin is in the pipeline for delivery on Mac, and it's only a matter of time until you'll see it in an Apple software update. Until then, however, please reserve your final judgments.

There's no magic. Until the new software is installed on your system, it's not reasonable to expect corrections to the user-experience.

Friday Nov 28, 2008

JavaFX 1.0 - Now you can judge for yourself

In a few more days the official release of JavaFX 1.0 will be made.

It's been almost exactly 2 years since my first entry on this blog, which introduced the F3 language that has since come to be known as JavaFX script.

Although F3 was almost entirely a one-man project, JavaFX 1.0 is the product of many, many contributors.

Along the way there have been many supporters, and quite a few detractors and nay-sayers, both inside and outside of Sun.

I believe what you'll see in December does indeed reflect much of the vision I've expressed on this blog over the past 2 years.

Nevertheless, the vision now embodied in JavaFX 1.0 is not a direct reflection of my personal vision but rather of the collective vision of its contributors.

These include the JavaFX compiler team, JavaFX Runtime team, Swing team, Java2D team, Java Media Components team, Java Plugin team, JavaME team, Netbeans team, Java-organization technical leadership, marketing, and management, as well as Sun executive technical leadership, marketing, and management.

Over the past two years, I've personally heard and/or read literally many thousands of opinions about JavaFX and the validity and potential of the Java platform for client side applications.

My view remains that many of the fundamental elements of the Java platform are still far superior to current alternatives and that it is our obligation and duty to make those benefits available to client developers by correcting orthogonal shortcomings and mistakes.

For example, it's unconscionable in my opinion that we allowed a dysfunctional browser plugin to exist for many years, steadily eroding Java's reputation and viability on the Internet. Thanks to others at Sun feeling the same way, that's been corrected.

I believe JavaFX 1.0 is a good, incremental step in overcoming some of our past mistakes, while preserving continuity with both standard JavaSE and JavaME.

But you don't have to take my word for it, now you'll be able to try it yourself.

Saturday Aug 23, 2008

JavaFX script vs ActionScript Performance

In a previous post I compared Java performance to that of ActionScript,

Thanks to the efforts of our JavaFX script compiler team (Robert Field, Per Bothner, Brian Goetz) the performance of JavaFX script is now on par with Java in many cases.

Repeating the same Takeuchi benchmark (but with 1000 iterations this time) with JavaFX script vs ActionScript yields the following results:

Here's the FX script:


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

for (i in [1..1000]) {
    tak(24, 16, 8);
}

javafxc Tak.fx

With the hotspot server vm:

time javafx -server -cp . Tak

real    0m10.432s
user    0m10.273s
sys     0m0.101s

With the client vm:

time javafx  -cp . Tak

real    0m23.763s
user    0m23.449s
sys     0m0.146s

And here's the ActionScript (statically typed):
package {
    function tak(x:Number, y:Number , z:Number):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 < 1000) {
        tak(24, 16, 8);
        i++;
    }

}

java -jar asc.jar -import builtin.abc tak.as

tak.abc, 205 bytes written
time ./avmplus tak.abc 

real    2m1.013s
user    1m59.350s
sys     0m0.642s
But, removing the package declaration, yields the following result:
java -jar asc.jar -import builtin.abc tak2.as
tak2.abc, 208 bytes written

time ./avmplus tak2.abc 

real    10m50.701s
user    10m40.793s
sys     0m3.318s

In summary, for this benchmark, with the hotspot server vm, JavaFX script outperforms statically typed ActionScript by a factor of 12, dynamically typed ActionScript by a factor of 65.

Tuesday May 13, 2008

Why JavaFX?

Our goal with JavaFX is to deliver a "media" stack for the Java platform. What does that mean? Well, in simple terms, 5 things:
  • Audio
  • Video
  • 2D Graphics
  • 3D Graphics
  • Animation

We've been working on a new graphics stack for JavaFX, consisting of an integrated 2D+3D JavaFX script scene graph based on a hardware accelerated shader-based immediate mode Java API which fits seamlessly into the OpenKode platform mentioned in my previous post. Of course, this same Java/JavaFX API can also sit on top of OS-specific, proprietary frameworks, such as CoreVideo+CoreAudio on MacOS. Several of our J1 keynote demos actually demonstrated this, namely the two video demos shown here.

This stack is gpu-accelerated 3D "all the way down". 2D vector paths are tessellated and fed directly to the 3D graphics driver and rendered via fragment shaders. For example, the movies in the second demo can be replaced with any arbitrary 2d rendering:

About

user12610627

Search

Archives
« April 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
   
       
Today