Step 1. Run the server.

Download and extract mpeServer.zip. Run the server via the command line. java -jar mpeServer.jar

runserver

The server can be configured by editing the mpeServer.ini file. Comments are made with “#”. Parameters are set like so: “name=value;” No spaces! End with a semi-colon!

#"screens" variable contains the total number of screens
screens=2;
#
#"framerate" variable contains the global framerate of the screens
framerate=30;
#
#"masterDimensions" is the total pixel dimensions of all the screens.
masterDimensions=640,240;
#
#"listener" opens up a port listener so that other apps can sends data to the screens.
#0=don't listen (default). 1=listen
listener=0;
#
#"listenerPort" defines the listening port.  It defaults to 9003.
listenerPort=9003;

Step 2. Download and install the MPE library

Here it is! mpe.zip

Step 3. Convert a single-screen applet to a multi-screen one!

Let’s say you a simple ball bouncing applet that runs at 320×240. We now want to make it run at 640×240 across two windows. (For testing, it’s easiest to run two windows on one machine.)

First, import the libraries:

import mpe.client.*;
import mpe.config.*;

Then create a client object:

// A client object
Client client;

In setup(), initialize the Client object. Just as with the server, a settings INI file is required. This file tells the client what its local dimensions are, as well as its location within the master dimensions. Here is an example file: mpe.ini

// Make a new Client with an INI file.
// sketchPath() is used so that the INI file is local to the sketch
client = new Client(sketchPath("mpe.ini"),this);

Once you’ve made the Client object, you should ask it for the size of your applet.

// The size is determined by the client's local width and height
size(client.getLWidth(), client.getLHeight());

Finally, in setup(), you must make sure to disable Processing’s draw() loop by calling noLoop(), as well as tell the client to start().

// Important, must start the client!
client.start();
// Crucial, must stop the automatic looping of Processing!
noLoop();

Processing’s draw() loop is replaced by the the frameEvent() callback. This function is triggered by the Client object whenever the server alerts the client that a new frame should be rendered. You must implement this function for the applet to work.

// This is triggered by the client whenever a new frame should be rendered
void frameEvent(Client c){
  redraw();
}

Ok, almost there! Now, whenever you display something, you must first ask the client to place itself within the larger display. And when you are finished drawing, call client.done() to tell the server you’ve finished.

void draw() {
  // Before we do anything, the client must place itself within the larger display
  // (This is done with translate, so use push/pop if you want to overlay any info on all screens)
  client.placeScreen();
  // Do whatever it is you would normally do
  background(0);
  ball.calc();
  ball.draw();
  // Alert the server that you've finished drawing a frame
  client.done();
}

Note that if you are using the variables width or height in your applet, you may need to change these to client.getMWidth();

if (x < 0 || x > client.getMWidth()) xdir *= -1;  // Note the use of the master width!

In addition, if you are using any random numbers or Perlin noise, you must make sure to seed them with a constant so that all client screens will pick the same sequence of randoms.

randomSeed(1); // Seed random so all clients pick same sequence
noiseSeed(1);

Broadcasting Messages

You can also broadcast a message from one client to all clients. For example, if you want a mouse connected to one client to act as a mouse for the entire system, you will need to broadcast a message when the mouse is clicked. For example:

void mousePressed() {
  // How to broadcast a message
  // Do not include a ":" in your message
  int x = mouseX + client.getXoffset();
  int y = mouseY + client.getYoffset();
  client.broadcast(x + "," + y);
}

Note the use of getXoffset() and getYoffset() to account for the mouse’s position within the master dimensions.

The message is then received during a frameEvent(). Note that the message comes in as an array of Strings (the server accumulates these messages into an array.)

void frameEvent(Client c){
  if (c.messageAvailable()) {
    String[] msg = c.getDataMessage();
    // Only using the first message in the array
    // We could loop through them all here just in case
    int[] xy = int(msg[0].split(","));
    balls.add(new Ball(xy[0],xy[1]));
  }
  redraw();
}

You can also broadcast arrays of integers or bytes. For example (assuming a Capture object named “video”):

// A function to broadcast the video's pixel array
public void sendImage() {
  client.broadcastIntArray(video.pixels);
}

The array is then read in frameEvent(), in the same way as with Strings above (assumes a PImage object of the same size named “img”):

// Called by library whenever a new frame should be rendered
void frameEvent(Client c){
  // If there is an integer array go and get it!
  if (c.intsAvailable()) {
    int[] pix = c.getInts();
    img.pixels = pix;
    img.updatePixels();
  }
  redraw();
}

Step 4. Ok, how the heck do I run this thing?

Going back to the bouncing ball example, we want to have two windows 320×240 each, together making a bigger window 640×480. The server should have masterDimensions=640×240 and each client will have local dimensions of 320×240.

You should now go ahead and export your sketch to application, and make a copy of that application. You should then have two applications and two INI files. These would ultimately live on separate computers, but for now you can place them in separate folders. Note the application is identical, only the INI file is different!

One INI file would look like this:

id=0;
localLocation=0,0;
server=localhost;
port=9002;
localScreenSize=320,240;
masterDimensions=640,240;

And the other like this:

id=1;
localLocation=320,0;
server=localhost;
port=9002;
localScreenSize=320,240;
masterDimensions=640,240;

Download the example sketch: mpeTest.zip

And this example sketch with video: mpeVideoTest.zip