Before you read this tutorial, you might want to read “How this works”. Also, the tutorial on Processing and Eclipse.

To get the examples described below, grab the source from google code hosting:

http://code.google.com/p/mostpixelsever/

To develop a project using MPE, it’s recommended that you start by running the server and your client application locally. Before you can test the client, you’ll need to run the server.

Step 1. Run the server.

You have two options for running the server app. Option number one is to grab the source via subversion and compile and run UDPServer.java.

The second option is to download and extract the server (see Downloads at google code hosting: http://code.google.com/p/mostpixelsever/). The file contains the server application in a jar. Run the server via the command line like so: 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 frame rate 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 the MPE library

Again, you have two options. You can grab the source as an Eclipse project and include it in the build path of your project.

Or you can download mpe.zip (http://code.google.com/p/mostpixelsever/) and include mpe.jar in your build path.

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

Let’s assume you a simple ball bouncing application 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
public 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.

public 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:

public 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.)

public void frameEvent(Client c){
  if (c.messageAvailable()) {
    String[] msg = c.getDataMessage();
    String[] xy = msg[0].split(",");
    int x = Integer.parseInt(xy[0]);
    int y = Integer.parseInt(xy[1]);
    balls.add(new Ball(this,x,y));
  }
  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
public 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.

The nice thing about Eclipse is that you can run the same application multiple times fairly easily. You can create two ini files: mpe0.ini and mpe1.ini. The whole project would then look something like:

One INI file (mpe0.ini) would look like this:

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

And the other (mpe1.ini) like this:

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

Then add a global variable to your application to keep track of the client ID number:

final int ID = 0;

Use that ID number to load the correct INI file:

client = new Client(sketchPath("mpe"+ID+".ini"),this);

Execute the application once, then switch ID = 0 to ID = 1 and execute again!

The examples are available for download via subversion or as a zip of all project files.

Quick links to code:

BouncingBalls.java
Ball.java