Urgent help using Keystone Library

Hello, I’m trying to implement the Keystone library into a sketch I am using to do visuals at a show tonight.

The sketch is somewhat complex, and involves control with monome hardware, but I think I can boil down the essence of the problem. The full code is here: https://github.com/Upow1234/Processing-Sketches/tree/master/shapes_feedback
The shapes_feedback file is the one containing setup() and draw().

I have a global PGraphics context ‘pg’ that I am passing into a class ‘Five_Circles’ where the drawing is done to ‘pg’.

When I try to add the keystone library, everything seems to work ok, except that the output image will only display in the keystone editing mode and not in the non-edting mode. The editing mode is toggled with the ‘c’ keyboard key.

Below is essentially what I’ve done. I updated all the renderers from P2D to P3D. I tried all kinds of things changing around how ‘pg’ is passed into the class, even hard coding it in, and also trying to return a PGraphics from the class and assigning it to pg. All to no avail.

import deadpixel.keystone.*;

Keystone ks;
CornerPinSurface surface;

import org.monome.Monome;
import oscP5.*;

Monome grid;
Monome arc;

Monome_Parameters mp;

PGraphics pg;
int pgWidth = 1280;
int pgHeight = 1024;

Five_Circles fiveCircles;
//Expanding_Square exsqua;
Feedback feedback;

void setup() { 
  fullScreen(P3D, 2);
  //size(320, 240, P2D);
  pg = createGraphics(pgWidth, pgHeight, P3D);

  feedback = new Feedback(200);

  arc = new Monome(this, "m1100144");
  grid = new Monome(this, "m1000370");

  fiveCircles = new Five_Circles(pg, pgWidth, pgHeight);
  //exsqua = new Expanding_Square(pg, pgWidth, pgHeight);

  mp = new Monome_Parameters(grid, arc, fiveCircles);
  //mp = new Monome_Parameters(grid, arc, exsqua);

  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(width, height, 20);
}

void draw() {
  pg.beginDraw();
  pg.background(0);

  feedback.feedbackDisplay(pg);
  feedback.parameters(fiveCircles);
  //feedback.parameters(exsqua);

  fiveCircles.render();
  //exsqua.render();

  //println("frame rate = " + frameRate);

  pg.endDraw();
  //fiveCircles.display();
  //exsqua.display();

  feedback.feedbackCapture(pg);
  feedback.count();
  
  surface.render(pg);
}

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;
  }
}

I hope someone can help! Thank you very much!!!

I can’t find where to download the org.monome.Monome library.
It would be much better if you could isolate the problem in a sketch that actually runs and only requires the keystone library.

Anyway, looking at draw its either:

fiveCircles.render();

Cause in there you never use the pg that you keystone.

But more likely it is the fiveCircles.display();.

You want something like fiveCircles.display(pg); and call that before pg.endDraw();.

Thanks for the ideas.

The monome library can be found here:

Sorry about that.

Also, as far as the fiveCircles.redner() and fiveCircles.display() functions, I believe that they are already aware of ‘pg’ since I passed it into their constructors, and have a local variable ‘masterContext’ in the Five_Circles class that has taken the reference from ‘pg’. Would that not work essentially the same?

Here is a sketch that I believe functions the same as mine, without all of the additional complexity. It’s a modification of the CornerPin example that comes with the Keystone library. Of course, this one work though. So I’m still not sure where I’m going wrong.


import deadpixel.keystone.*;

Keystone ks;
CornerPinSurface surface;

PGraphics offscreen;

Draw_Circle drawCircle;

void setup() {
  size(800, 600, P3D);

  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(400, 300, 20);

  offscreen = createGraphics(400, 300, P3D);
  drawCircle = new Draw_Circle(offscreen);
}

void draw() {
  background(0);
  
  offscreen.beginDraw();
  drawCircle.drawCir();
  offscreen.endDraw();

  drawCircle.displayCir(surface);
}

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;
  }
}

class Draw_Circle {
  
  PGraphics masterContext;

  Draw_Circle(PGraphics inputContext) {
    masterContext = inputContext;
  }

  void drawCir() {
    masterContext.background(255);
    masterContext.fill(0, 255, 0);
    masterContext.ellipse(mouseX, mouseY, 75, 75);
  }

  void displayCir(CornerPinSurface cpsTemp) {
      cpsTemp.render(masterContext);
  }
}

You should not modify the CornerPin example but you should modify the sketch where you have the problem.
Throw everything out peace by peace until you are left with the most basic sketch that still has the problem.

Also I really advice agains this heavy object oriented programming, it’s harder to write, to read and to debug.

Anyway, in the GitHub version you never do a call to surface.render(offscreen);
What you do in the fiveCircles.display(); is image(masterContext, 0, 0, width, height);.
You wan’t that masterContext to be rendered by surface.render.

And do that in your Five_Circles class, cause that will give that class a dependency to the keystone library which increases the complexity.

just use surface.render(pg); close after the pg.endDraw().

Here is another that seems to work fine, it is essentially my sketch watered down to the essential parts. So now I’m really not sure where I’m going wrong.

And sorry the github one doesn’t match my current intentions, I only have been trying to add the keystone this morning. I uploaded to github last night as a backup.

And sorry I’m all over the place with the code snippets, I’m trying a lot of different things to try to get something working.

import deadpixel.keystone.*;

Keystone ks;
CornerPinSurface surface;

PGraphics pg;
//int pgWidth = 1280;
//int pgHeight = 1024;
int pgWidth = 320;
int pgHeight = 240;

Five_Circles fiveCircles;

void setup() { 
  //fullScreen(P3D, 2);
  size(320, 240, P3D);
  pg = createGraphics(pgWidth, pgHeight, P3D);

  fiveCircles = new Five_Circles(pg, pgWidth, pgHeight);

  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(pgWidth, pgHeight, 20);
}

void draw() {
  background(0);
  
  pg.beginDraw();
  //pg.background(0);

  fiveCircles.render();

  pg.endDraw();
  
  //fiveCircles.display();
  surface.render(pg);
}

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;
  }
}

class Five_Circles { 

  PGraphics masterContext;
  int masterContextWidth;
  int masterContextHeight;

  PShape ellipse;

  float scale;


  Five_Circles(PGraphics masterContextTemp, int masterContextWidthTemp, int masterContextHeightTemp) {
    masterContext = masterContextTemp;
    masterContextWidth = masterContextWidthTemp;
    masterContextHeight = masterContextHeightTemp;
    
    scale = 1;
  }

  void render() { 
    float ellipseWidth = 1;
    float ellipseHeight = 1;
    float xOffset = 0.5;
    float yOffset = 0.5;

    float redStroke = 255;
    float greenStroke = 0;
    float blueStroke = 0;
    float alphaStroke = 255;

    float redFill = 0;
    float greenFill = 0;
    float blueFill = 0;
    float alphaFill = 0;


    ellipse = createShape(ELLIPSE, 0, 0, 100, 100);

    ellipse.setStroke(color(redStroke, greenStroke, 
      blueStroke, alphaStroke));

    ellipse.setFill(color(redFill, greenFill, blueFill, alphaFill));
    ellipse.scale(scale);

    masterContext.shape(ellipse, (pgWidth/2) + (xOffset), (pgHeight/2) + (yOffset));
    masterContext.shape(ellipse, 0 + (xOffset), 0 + (yOffset));
    masterContext.shape(ellipse, pgWidth + (xOffset), 0 + (yOffset));
    masterContext.shape(ellipse, 0 + (xOffset), pgHeight + (yOffset));
    masterContext.shape(ellipse, pgWidth + (xOffset), pgHeight + (yOffset));
  }

  void display() {
    image(masterContext, 0, 0, width, height);
  }
}

There seems to be some kind of conflict while combining the PGraphics and a PShape. The normal shape functions work fine but as soon as you try to use a PShape, the PGraphics.background functions covers the drawing, even when placed before the shape is drawn. I think it’s a bug.

This is my same sketch from my last post, if you uncomment ‘pg.background’ it no longer works.

import deadpixel.keystone.*;

Keystone ks;
CornerPinSurface surface;

PGraphics pg;
//int pgWidth = 1280;
//int pgHeight = 1024;
int pgWidth = 320;
int pgHeight = 240;

Five_Circles fiveCircles;

void setup() { 
  //fullScreen(P3D, 2);
  size(320, 240, P3D);
  pg = createGraphics(pgWidth, pgHeight, P3D);

  fiveCircles = new Five_Circles(pg, pgWidth, pgHeight);

  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(pgWidth, pgHeight, 20);
}

void draw() {
  background(0);
  
  pg.beginDraw();
  pg.background(0);

  fiveCircles.render();

  pg.endDraw();
  
  //fiveCircles.display();
  surface.render(pg);
}

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;
  }
}

class Five_Circles { 

  PGraphics masterContext;
  int masterContextWidth;
  int masterContextHeight;

  PShape ellipse;

  float scale;


  Five_Circles(PGraphics masterContextTemp, int masterContextWidthTemp, int masterContextHeightTemp) {
    masterContext = masterContextTemp;
    masterContextWidth = masterContextWidthTemp;
    masterContextHeight = masterContextHeightTemp;
    
    scale = 1;
  }

  void render() { 
    float ellipseWidth = 1;
    float ellipseHeight = 1;
    float xOffset = 0.5;
    float yOffset = 0.5;

    float redStroke = 255;
    float greenStroke = 0;
    float blueStroke = 0;
    float alphaStroke = 255;

    float redFill = 0;
    float greenFill = 0;
    float blueFill = 0;
    float alphaFill = 0;


    ellipse = createShape(ELLIPSE, 0, 0, 100, 100);

    ellipse.setStroke(color(redStroke, greenStroke, 
      blueStroke, alphaStroke));

    ellipse.setFill(color(redFill, greenFill, blueFill, alphaFill));
    ellipse.scale(scale);

    masterContext.shape(ellipse, (pgWidth/2) + (xOffset), (pgHeight/2) + (yOffset));
    masterContext.shape(ellipse, 0 + (xOffset), 0 + (yOffset));
    masterContext.shape(ellipse, pgWidth + (xOffset), 0 + (yOffset));
    masterContext.shape(ellipse, 0 + (xOffset), pgHeight + (yOffset));
    masterContext.shape(ellipse, pgWidth + (xOffset), pgHeight + (yOffset));
  }

  void display() {
    image(masterContext, 0, 0, width, height);
  }
}