Skip to content

Writing Your First MPE Program

bmwesting edited this page Dec 14, 2012 · 7 revisions

Our first MPE program will be the simple 3D PeasyCam example working across multiple displays. You can find this example in the source repository of this library. You will need the PeasyCam and the MPE Cluster libraries installed for this to work.

HelloPeasy Original

Importing the Libraries

import processing.opengl.*;

import peasy.*;
PeasyCam cam;

// MPE includes
import mpe.Process;
import mpe.Configuration;

// MPE Process thread
Process process;

// MPE Configuration object
Configuration tileConfig;

Peasy and opengl are self explanatory. Peasy will create an easy to use camera for interaction, and opengl is needed for fast 3D hardware acceleration.

The MPE includes are for the process and configuration objects, process and tileConfig. The tileConfig object will read in the configuration file we created in the previous step. The process object will create a thread that will run in the background receiving communication from the master process on how to synchronize with the rest of the display.

The Setup Method

void setup() {
  
  // create a new configuration object and specify the path to the configuration file
  tileConfig = new Configuration("data/configuration.xml", this);
  
  // set the size of the sketch based on the configuration file
  size(tileConfig.getLWidth(), tileConfig.getLHeight(), OPENGL);
  
  // create a new process
  process = new Process(tileConfig);
  
  // disable camera placement by MPE, because it interferes with PeasyCam
  process.disableCameraReset();
 
  // initialize the peasy cam
  cam = new PeasyCam(this, 3000);
  cam.setMinimumDistance(0);
  cam.setMaximumDistance(5000);
  
  // start the MPE process
  process.start();
}

In the setup method, we point our tileConfig object at the configuration file we created. Then we call the Processing size() function, with the size of the local display of the process, and the 3D acceleration method. Because there will be 4 processes running on our display in the end, each process with have its own tileConfig.getLWidth() and tileConfig.getLHeight(), which will be 400. The functions grab the local width and height of the display. The corresponding getMWidth() will grab the pixel size of the entire display in width, including all displays in the configuration.

We run process.disableCameraReset(); specifically for peasycam, so peasycam doesn't interfere with MPE's functionality. This step is not necessary if not using a camera library.

Finally, we call process.start(), which will start the MPE communication thread in the background.

Mouse Events

// when the master process receives a mouse event, broadcast the update camera state to the other processes
void mouseDragged()
{
  process.broadcast(cam.getState());
}

Because mouse events only occur on the head process, we want to capture them and send them to the other processes. This is done by the process.broadcast() call. The arguments of this call can be any object, or event a vector of objects. Here, we send the camera state over to all the processes.

This will be received in the Processing draw() method, next.

The Draw Method

Lastly, we draw a couple of boxes:

void draw() {
  
  // synchronize this process' camera with the headnode
  if(process.messageReceived())
  {
    // set the animation time to 0, otherwise we get weird behavior
    cam.setState((CameraState) process.getMessage(), 0);
  }
  
  // draw a couple boxes
  scale(5);
  rotateX(-.5);
  rotateY(-.5);
  background(0);
  fill(255,0,0);
  box(200);
  pushMatrix();
  translate(0,0,200);
  fill(0,0,255);
  box(50);
  popMatrix();
}

The only special thing here is that we need to check and see if we have received any messages from the master process. When the master process broadcasts the camera state, the followers processes will receive a new camera state here. They simply set their camera state to the received state, with an animation time of 0.

End Result

import processing.opengl.*;

import peasy.*;
PeasyCam cam;

// MPE includes
import mpe.Process;
import mpe.Configuration;

// MPE Process thread
Process process;

// MPE Configuration object
Configuration tileConfig;

void setup() {
  
  // create a new configuration object and specify the path to the configuration file
  tileConfig = new Configuration("data/configuration.xml", this);
  
  // set the size of the sketch based on the configuration file
  size(tileConfig.getLWidth(), tileConfig.getLHeight(), OPENGL);
  
  // create a new process
  process = new Process(tileConfig);
  
  // disable camera placement by MPE, because it interferes with PeasyCam
  process.disableCameraReset();
 
  // initialize the peasy cam
  cam = new PeasyCam(this, 3000);
  cam.setMinimumDistance(0);
  cam.setMaximumDistance(5000);
  
  // start the MPE process
  process.start();
}
void draw() {
  
  // synchronize this process' camera with the headnode
  if(process.messageReceived())
  {
    // set the animation time to 0, otherwise we get weird behavior
    cam.setState((CameraState) process.getMessage(), 0);
  }
  
  // draw a couple boxes
  scale(5);
  rotateX(-.5);
  rotateY(-.5);
  background(0);
  fill(255,0,0);
  box(200);
  pushMatrix();
  translate(0,0,200);
  fill(0,0,255);
  box(50);
  popMatrix();
}

// when the master process receives a mouse event, broadcast the update camera state to the other processes
void mouseDragged()
{
  process.broadcast(cam.getState());
}

Next: How to run your program