Friday, September 18, 2009

Wish list for converting Adobe Illustrator Files to JavaFX

When developing JavaFX applications, much of the graphics work can be done in Adobe Illustrator and exported to a format friendly to JavaFX. This is done by using the JavaFX 1.2 Production Suite. Recently a friend at Sun pointed me to a link which shows which features in Adobe's tools are supported.

It is nice to have some clarification about which features are supported and which are not, until I looked at this document I was pretty frustrated with the guess work involved in getting content to export in a reasonable way. But now I can just look up what works, excellent.

Naming Nodes

This brings me to another struggle I have with the production suite, which involves how nodes are named. Currently you can name a node, say "jfx:ball" and when you export your file for JavaFX, one of the nodes that gets exported has its Id set to "ball", this allows you to pull out particular nodes in the scene. This works great for a lot of use cases, it allows your application set up code to find nodes and perform operations on them, like animate them or make them a button.

The trouble comes when you start to use Illustrator or Photoshop to create more complex scenes, with more complex interactions between the nodes. For example, lets say you are implementing a game like Super Mario Brothers. It makes a lot of sense to use illustrator to put each level together, it allows rapid placement of content and lots of fine tuning. The trouble, is how to identify which layers in the adobe file should be bricks, or coin bricks, or even goombas.

Right now you could go through and name each brick, but you have to give them all unique names, you have to say "jfx:brick1", "jfx:brick2", etc. This is error prone and a lot of work. Ideally you would want to be able to just create a brick layer, and then just copy it and place it without thinking about it.

So if we consider a developer/designer work flow, I the developer, would create a file containing one of each actor in the scene. An actor is something my code has to know about. The designer can then create a new scene by copying the basic building blocks I provided. They can also add other content, which are not actors, this would be backgrounds and other decorations. Interested designer could also look at my example content and create their own. Maybe on level 6 the coin bricks have a different look, they would be able to adapt the naming system to create the actors they require.

In this way, there is a streamlined designer/developer work flow. This is really important to creating excellent applications, because the less time spent making it just work and the more time spent on making it cool, hence cooler applications :)

Extensi0n To Naming System
To enable this work flow I suggest changing how the name system works for the production suite. We should be able to specify a class for a given node. I think it could work like this, first start with how it works now:


This just simply says, set this nodes id to NODE_ID. This is perfect for singletons in the scene. But, now if you want to specify a node to be a particular class you would say:


Where Brick is a mixin class defined someplace else in your project. The production tool would then create a new class, which would look something like:

class Group_Brick extends Group, Brick{
//no additional implementation.

Then each time the export tool finds a layer which should be node of type brick, it uses the class Group_Brick instead of Group to represent that node. If the node which is to be a brick would normally be of a type type other then Group, say SVGPath, then another class like the following could be created.

class SVGPath_Brick extends SVGPath, Brick{
//no additional implementation.

In this case, maybe some Bricks are SVGPaths and some are Groups. But your code might not care, since bot SVGPath and Group are nodes.

If you wanted a node to be of two classes, you would name the layer:


this would cause the production suite to produce a class like the following:

class Group_Brick_HasCoin extends Group, Brick, HasCoin {
//no additional implementation.

In this way the node can be two things. Lastly, suppose you wanted a node to have its id set and be of a particular class, you would then name the node like this:


This would create a node which was whatever type the layer should be (Group, SVGPath, Circle, etc) and also of type Brick, and have the id property set to 'startspot'.

Of course some tools on the javafx side must be created, it would be nice to say 'give me all nodes in this tree which are of a particular type', something like the following.

function getAll(clazz:Class, group:Group):Node[];

I am sure the above method can be implemented with little trouble.

One drawback to this approach is that the exported fxz files would not be self sufficient, they could not be rendered unless the classes like Brick and HasCoin are present. But, this is an extension to the current system, so people would not be required to use it. The preview tool in illustrator could also just provide empty implementations for all unknown classes, which would allow it to at least draw the content in a static way.
Another drawback is that there might be some complexity when creating nodes with multiple classes, naming conflicts and that sort of thing. But even if only one class could be specified, inheritance would take care of most of the use cases. In the above example, Brick and HasCoin are separate classes. It might be possible to simply create the class Brick and the class CoinBrick, and have CoinBrick extend Brick. That being said, I think it best to allow nodes to have many, many classes, as it cuts down on the complexity of the inheritance model.

In short, this modification would allow us to specify that a layer in an adobe file is of a particular type as well as have a name. This would turn illustrator and photoshop into very powerful tools for creating complex content in a JavaFX application.