11 – Keystone example

Example of using the keystone library with the ball class.

There is a simpler example in the library folders too.

This library means that we are drawing our processing elements to an offscreen buffer. That means a version a screen that is off out of view. This buffer is then reprojected and mapped onto the surface that you set.

Import the library and set up the classes and their instances as shown below. You then have to go through and replace all of the x, y, width, height coordinates with offscreen.x, offscreen.y, offscreen.width, offscreen.height.

Also all of your drawing functions like ellipse, line, point, rect, etc.
They should all be offscreen.ellipse, offscreen.line, offscreen.point, offscreen.rect

You do this because you are drawing these shapes to the buffer which is then reinterpreted and skewed based on your surface settings.

Remember, PRESS C to set control points, PRESS S to save your control points to the XML file, PRESS U, to update the control points from the XML files.

/**
 * This is a simple example of how to use the Keystone library.
 *
 * To use this example in the real world, you need a projector
 * and a surface you want to project your Processing sketch onto.
 *
 * Simply drag the corners of the CornerPinSurface so that they
 * match the physical surface's corners. The result will be an
 * undistorted projection, regardless of projector position or 
 * orientation.
 *
 * You can also create more than one Surface object, and project
 * onto multiple flat surfaces using a single projector.
 *
 * This extra flexbility can comes at the sacrifice of more or 
 * less pixel resolution, depending on your projector and how
 * many surfaces you want to map. 
 */
 
import deadpixel.keystone.*;
 
Keystone ks;
CornerPinSurface surface;
 
int offscreenW = 480; 
int offscreenH = 360; 
 
PGraphics offscreen;
 
 
Ball ball1;
Ball ball2;
ArrayList<Ball> balls;
 
 
 
void setup() {
  // Keystone will only work with P3D or OPENGL renderers, 
  // since it relies on texture mapping to deform
  size(800, 600, P3D);
 
  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(400, 300, 20);
 
  // We need an offscreen buffer to draw the surface we
  // want projected
  // note that we're matching the resolution of the
  // CornerPinSurface.
  // (The offscreen buffer can be P2D or P3D)
  offscreen = createGraphics(400, 300, P3D);
  smooth();
 
  ball1 = new Ball(40);
  ball2 = new Ball(30);
  balls = new ArrayList<Ball>();
}
 
void draw() {
  // Convert the mouse coordinate into surface coordinates
  // this will allow you to use mouse events inside the 
  // surface from your screen. 
  //PVector surfaceMouse = surface.getTransformedMouse();
  ball1.move();
  ball2.move();
  ball1.bounce();
  ball2.bounce();
 
 
 
  if (ball1.intersect(ball2)) {
    ball1.highlight();
    ball2.highlight();
  }
  // Draw the scene, offscreen
  offscreen.beginDraw();
  offscreen.background(255);
  ball1.display();
  ball2.display();
 
  offscreen.endDraw();
 
  // most likely, you'll want a black background to minimize
  // bleeding around your projection area
  background(0);
  surface.render(offscreen);
}
 
void keyPressed() {
  switch(key) {
  case 'c':
    // enter/leave calibration mode, where surfaces can be warped 
    // and moved
    ks.toggleCalibration();
    break;
 
  case 'l':
    // loads the saved layout
    ks.load();
    break;
 
  case 's':
    // saves the layout
    ks.save();
    break;
  }
}

And the ball class is:

 
class Ball {
  float r; // radius
  float x, y; // location 
  float xspeed, yspeed; // speed
  color c;
 
  // Constructor
  Ball(float tempR) {
    r = tempR;
    x = random(offscreen.width);
    y = random(offscreen.height);
    xspeed = random(-5, 5);
    yspeed = random(-5, 5);
    c = color(50, 50, 50);
  }
 
 
  void move() {
    x += xspeed; // Increment x 
    y += yspeed; // Increment y
    // Check horizontal edges
  }
  void bounce() {
    if (x > offscreen.width || x < 0) {
      xspeed = xspeed -1;
    }
    //Check vertical edges
    if (y > offscreen.width || y < 0) {
     yspeed = yspeed -1;
    }
  }
 
  // Draw the ball
  void display() {
   stroke(255);
    offscreen.fill(c);
    offscreen.ellipse(x, y, r*2, r*2);
    c = color(50, 50, 50);
  }
 
  //pass in a second ball to see if they are intersecting.
  boolean intersect(Ball b) {
    float distance = dist(x, y, b.x, b.y);
    if (distance < r + b.r) {
      return true;
    } else {
      return false;
    }
  }
 
  void highlight() {
    c = color(255, 0, 0);
  }
}
'+
1
'+
2 - 3
4 - 5
6 - 7
8 - 9
10 - 11
12 - 13
13 - 14
[x]