download \ examples \ tutorial \ advanced \ api summary \ api reference

Description

Processing Layers is a simple library for the Processing languange. The concept of layering is very familiar to anyone who uses drawing tools like Photoshop or Gimp. This library allows Processing developers to create sketches with multiple layers that are drawn independently of one another. Each layer has its own draw() method. This indepedence between layers allows some layers to change without affecting others. For example, you can use a layer to animate some thing without having to redraw everything that is "behind" it. Layers can be added and removed from a sketch dynamically.

Last Updated: Version 1.2 released on April 22, 2011
Tested On: Mac OS X, Windows XP, Windows Vista with Processing 1.5
Keywords: layers, layering, animation


Changelog

Version 1.2:
  • Updated for Processing 1.5. Sketches written for earlier versions of Processing will need to modify their paint method to take an argument java.awt.Graphics.
  • Added loadPixels() method so that this library can be used with MovieMaker.
Version 1.1:
  • The core classes were renamed from PAppletLayers to AppletLayers and PLayer to Layer.
  • Event propagation to Layer objects is now automatic and the event methods of AppletLayers have been removed.


Download

The Processing Layers library can be downloaded from here. Unzip the file in your sketchbook libraries folder.

The source code for the Processing Layers library is included in the distribution and can also be found at the SourceForge Project.

Forum

For discussion/questions/bugs see the Processing Layers forum.

Examples

A very simple sketch demonstrating animation of using layers.
Flying paintballs are drawn on a separate layer so the background splatters never need to be redrawn.
A more complex sketch with many layers.

Quick Tutorial

There are several steps necessary to create a layered Processing sketch. First import the layers library using the Sketch -> Import Library... menu item.

Next, your sketch -- which is a PApplet object -- needs to create an instance of a AppletLayers object. The AppletLayers object is a container for all the layers in the sketch and it arranges for all the layers to be rendered on top of the normal drawing surface. You must pass an instance of the PApplet to the AppletLayers constructor. You can do this in the setup() method:

AppletLayers layers;

void setup() {
  size(200, 200);
  layers = new AppletLayers(this);
...

Now you need to implement some layers. Each layer is a subclass of the class Layer. Just like an ordinary sketch, a layer has a draw() method which performs the drawing for that layer. Remember to set the alpha channel to 0 when calling background() so that you can see "through" the layer. A layer can optionally have a setup() method for setup specific to that layer. Since layers are separate Java classes in a sketch, you'll need to add tabs to the sketch with the arrow button in the upper right of the Processing IDE. If you are unfamiliar with using multiple tabs and classes in Processing, see the Processing IDE documentation here. Layers need to have a constructor that takes the main PApplet as an argument and passes it to the Layer constructor as in this example fragment:

class MyLayer extends Layer {

  MyLayer(PApplet parent) {
    super(parent); // This is necessary!
  }

  void draw() {
    background(0, 0); // clear the background every time, but be transparent
    // now draw something
    ...
  }
...
}

Now that we've created at least one Layer class, we need to instantiate them and add it to our sketch so that it gets rendered. This is done simply by adding them to the AppletLayers object we created before. All the layers will automatically be drawn on top of the sketch's main drawing surface. The order of layering depends on the order the layers are added to the AppletLayers object (last is on top). The code below shows how to create an instance of a MyLayer object and add it to our sketch:

AppletLayers layers;

void setup() {
  size(200, 200);
  layers = new AppletLayers(this);
  MyLayer m = new MyLayer(this);
  layers.addLayer(m);
}

void draw() {
  // Draw whatever we want on the main drawing surface.
  // The layers will automatically be drawn "on top" of what is drawn here.
}

A few more very important things: in order for layering to work, you must include a paint method like this in your sketch. Make sure to use the one below that is appropriate for the version of Processing that you are running (the API changed in 1.5).

Also, even if your sketch doesn't need to draw anything itself (the layers are doing all the drawing), you need to have at least an empty draw() method:

// paint method for Processing 1.5 or higher:
void paint(java.awt.Graphics g) {
  // This method MUST be present in your sketch for layers to be rendered!
  if (layers != null) {
    layers.paint(this);
  } else {
    super.paint(g);
  }
}

// paint method for Processing versions prior to 1.5
void paint() {
  // This method MUST be present in your sketch for layers to be rendered!
  if (layers != null) {
    layers.paint(this);
  } else {
    super.paint();
  }
}

void draw() {
  // Even if there's nothing to do, an empty draw method must be present in the sketch!
}

That's basically it -- look at the code in the demos below for concrete examples of using this library.

Advanced Features

Renderers

Each layer can use a different renderer than the main drawing surface if desired. For example, the sketch can use the P3D renderer, while one layer uses JAVA2D, and yet another layer uses P3D. The default renderer is JAVA2D, but a different renderer can be specified when calling the Layer constructor in your layer's constructor. For example, the ProjectileLayer in the Paintball example uses the P3D renderer:
ProjectileLayer(PApplet parent) {
  super(parent, P3D);
}
There are several constraints to be considered when using renderers other than JAVA2D. These constraints are documented in a section below.

Clipping

To improve performance, it's possible to specify a clipping rectangle in a layer so that only a portion of the entire layer is rendered. This is useful if only a small portion of a layer has anything drawn on it. The clipping rectangle is specified simply by setting the Layer variables clipX, clipY, clipWidth, and clipHeight.

Event Propagation

Keyboard and mouse events that occur in a sketch are automatically propagated to the sketch's layers in order for the layers to process them. For example, any layer interested in a mousePressed event can then simply implement a mousePressed() method to process the event.

Layer Visibility

Layers can be set to be visible or invisible by calling the setVisible(boolean) method. If set to false, the layer's draw() method will still be called, but the layer will not be rendered to the screen.

Dynamically Adding, Removing, or Reordering Layers

It is possible to dynamically add, remove, or reorder layers during a sketch's execution, but great care should be taken when doing so. The list of layers managed by the AppletLayers object can be manipulated by obtaining a ListIterator object. The semantics of how a list can be manipulated via an iterator should be studied carefully by reading the Javadoc for java.util.ListIterator. The reason it is difficult to manipulate a list during sketch execution is because the list of layers is being iterated through in order to render them. The best place to manipulate the list of layers is in the main sketch's draw() method and not in a layer's draw() method or in mouse or keyboard event processing.

Making Layered Movies

The Processing Video library allows developers to create Quicktime movies from their Processing sketches using the MovieMaker class. It is possible to make layered movies with Processing Layers. In order for the content of all layers to be included in the movie, you need to add frames to the MovieMaker movie in a different way. If you try to add a frame using the usual way addFrame(), only the main drawing surface will be included in the movie. To ensure all layers are included, you must create a post() method in your sketch and add the pixels from the AppletLayers object to the movie:
AppletLayers layers;
MovieMaker mm;

setup() {
  ...
  layers = new AppletLayers(this);
  mm = new MovieMaker(this, width, height, "layeredMovie.mov");
  registerPost(this);
  ...
}

void post() {
  layers.loadPixels();
  mm.addFrame(layers.pixels, width, height);
}

...



API Summary

AppletLayers

AppletLayers(PApplet) : Constructor. Pass the sketch PApplet as an argument, e.g. layers = new AppletLayers(this);

void addLayer(Layer) : add a layer

int numLayers() : returns number of layers

Layer getLayer(int) : returns Layer object at specified index

ListIterator getListIterator() : returns java.util.ListIterator for the list of layers

Layer

Layer(PApplet) : Constructor. Pass the sketch PApplet as an argument from your layer's constructor, e.g. super(parent);

Layer(PApplet, String) : Constructor with specified renderer. Pass the sketch PApplet as an argument from your layer's constructor, e.g. super(parent, P3D);

void setup() : optionally perform setup for the layer. Do not call size() as you would in a normal sketch. The setup() method will be invoked when a layer is added to a AppletLayers object.

void draw() : layers must implement draw() to render themselves. The usual Processing drawing primitives are available to layers.

AppletLayers getContainer() : return the AppletLayers object that this layer is managed by

boolean isVisible() : return the layer's visibility

void setVisible(boolean) : set layer's visibility. If set to false, its draw() method will still be called, but the layer will not be rendered to the screen.

Renderer Constraints

  • OPENGL is not yet supported.
  • When P3D is used in a layer (not on the main drawing surface), rendering is very slow.
  • When P2D or P3D are used in a layer, the alpha channel of colors specified with stroke() or fill() will have no effect; the colors will be opaque. An alpha channel passed to background() will still work so that they layer is transparent. This means that only layers using the default renderer JAVA2D may draw shapes to the layer that have transparency.


Performance Considerations

Layering is accomplished by rendering the main drawing surface and all layers onto an off-screen PGraphics object and then rendering the result into the applet. This means lots of data copying. Layered sketches may run very slowly if there are a large number of layers or if the dimensions of sketch is large in size. Generally speaking, the dimensions of a sketch has the most effect on performance. Large == slow. A very small sketch with many layers may perform very well.

You can optimize performance of a layered sketch in a couple of ways:

  • If only a small area of a layer needs to be rendered, a clipping rectangle will limit the data copying to that area and the rest of the layer will not be rendered at all.
  • If there is nothing to render, then setVisible(false) can be called.


Troubleshooting FAQ

Why is my layered sketch running so slow?

Each layer must be rendered and copied over the main drawing surface, which can result in slowness. This seems to depend more on the size of the sketch rather than the number of layers. Try using clipping rectangles in your layers if you can.

Why don't my layers render?

Don't forget to:
  • add your Layer objects to the AppletLayers object
  • call the Layer superclass constructor from your layer's constructor
  • implement a paint() method that calls the paint method of the AppletLayers object.
  • implement a draw() method in your sketch even if it doesn't need to do anything

Why do I only see my "top" layer?

Layers must be drawn with a transparent background in order to be able to see "through" them to layers below them or to see the main drawing surface. Pass a value of 0 as the alpha channel parameter if your layer clears itself by calling background(). For example:
// clear the layer.  The color does not matter since it is completely transparent.
background(0, 0);

Where can I get more help?

Try the Processing Layers forum for discussion with other users.

License

CC-GNU LGPL
This software is licensed under the CC-GNU LGPL.