deepmatrixstack

versions0095+,1.0.3
contributorsdavebollinger,steve
started on2007-08-31 13:19

The default matrix stack depth of 32 is adequate for most uses, but may not be adequate for deeply nested or recursive transforms. You'll know you've reached the limit when the “Too many calls to pushMatrix()” exception occurs.

Version 1.0.3

Fortunately you can override the built in 'pushMatrix()' and 'popMatrix()' functions quite easy. To override just copy the code example from below. Unfortunately this technique wont work for the P3D and OPENGL renderes (at least i wasn't able to get it working).

// simple example sketch
void setup(){
  size(512, 512);
  noStroke();
}
 
void draw(){
  background(0);
  recursiveFunction(0);
}
 
void recursiveFunction(int fn){
  pushMatrix();
    translate(1,1);
    fill(255-fn*1,255-0.5*fn,fn*0.5,fn*1);
    rect(0,0,10,10);
    fn++;
    if(fn < 512){
      recursiveFunction(fn); 
    }
  popMatrix();
}
/**
deepmatrixstack taken from http://processinghacks.com/hacks:deepmatrixstack
to override the default stack just copy & paste the following code
   to your sketch
@author steve
*/
 
// adjust this value to whatever depth is actually necessary
public final int STACK_DEPTH = 512;
public float[][] matrixStack = new float[STACK_DEPTH][6];
public int matrixStackDepth;
 
// this version will override the built-in version pushMatrix function
public void pushMatrix() {
  if (matrixStackDepth == 512) {
    throw new RuntimeException("too many calls to pushMatrix()");
  }
  this.g.getMatrix().get(matrixStack[matrixStackDepth]);
  matrixStackDepth++;
}
 
// this version will override the built-in version popMatrix function
public void popMatrix() {
  if (matrixStackDepth == 0) {
    throw new RuntimeException("too many calls to popMatrix()" +
                               "(or too few to pushMatrix)");
  }
  matrixStackDepth--;
  PMatrix2D m = new PMatrix2D();
  m.set(matrixStack[matrixStackDepth]);
  this.g.setMatrix(m);
}

Version 0095+

Unfortunately, there is no easy way to specify a different stack depth (short of recompiling the core), and recreating the internal g.modelview as a new PMatrix(n) after it's already created is a bit “slimy” even for a “hack”. But there is an easy and nearly transparent workaround possible by overriding the built-in pushMatrix() and popMatrix() methods.

The technique involves creating a new instance of a PMatrix and using it as the storage mechanism for a deeper stack. This technique will work with both the P3D and OPENGL renderers.

/**
deepmatrixstack taken from http://processinghacks.com/hacks:deepmatrixstack
@author David Bollinger
*/
 
// to use:  simply include this code somewhere within your sketch
 
// adjust this value to whatever depth is actually necessary
int DEEP_STACK_DEPTH = 512;
PMatrix _deepstack;
PMatrix _deepstackInv;
 
// this version will override and obscure the built-in version
void pushMatrix() {
  if (_deepstack==null) {
    _deepstack = new PMatrix(DEEP_STACK_DEPTH);
  }
  if (_deepstackInv==null) {
    _deepstackInv = new PMatrix(DEEP_STACK_DEPTH);
  }
  // load the current modelview matrix into the stack matrix
  _deepstack.set(g.modelview);
  // push the stack matrix
  if (!_deepstack.push()) {
    throw new RuntimeException("Too many calls to pushMatrix()");
  }
  // same for the inverse, to keep them in sync
  _deepstackInv.set(g.modelviewInv);
  _deepstackInv.push();
}
 
// this version will override and obscure the built-in version
void popMatrix() {
  // pop the stack matrix
  // (allow this to blow up if _deepstack is null,
  //  when pop called before push, stack underflow)
  if (!_deepstack.pop()) {
    throw new RuntimeException("Too many calls to popMatrix() " +
                                 "(and not enough to pushMatrix)");
  }
  // set the current modelview matrix to the stack matrix
  g.modelview.set(_deepstack);
  // same for the inverse, to keep them in sync
  _deepstackInv.pop();
  g.modelviewInv.set(_deepstackInv);
}
hacks/deepmatrixstack.txt · Last modified: 2009-04-19 15:41 by steve