Copying a PShape?

If I want to have several of the same 3D model (.obj file loaded), is there a way to to load it once and then copy that PShape. I want to avoid several calls to loadFile.

-Carmine

2 Likes
PShape shape;
PShape shape1;
PShape shape2;

void setup() {

// load once
shape = loadShape("path/to/shape.obj");

// Same shape now in 3 PShapes
// Note that if you modify any of shape, shape1 and shape2 they will all be modified
shape1 = shape;
shape2 = shape;

// To avoid to have same instance in 3 variables, use this 'copy' trick
// Put shape as a child in a GROUP shape
shape1 = createShape(GROUP);
shape1.addChild(shape);

shape2 = createShape(GROUP);
shape2.addChild(shape);

}

void draw() {

//If you only need to show 3 of the same shape just call shape multiple times with the same shape
pushMatrix();
translate(0, 0, 0);
shape(shape);
translate(100, 0, 0);
shape(shape);
translate(100, 0, 0);
popMatrix();

}

There is no function like shape.copy() for the moment so you can’t entirely copy a PShape.
If you really want a complete copy, this is the way, but it is slow because we rebuild the shape :

PShape clone(PShape obj) {
  PShape shape = createShape();
  shape.beginShape();
  
  for(int i=0; i<obj.getVertexCount(); i++) {
    PVector vertex = obj.getVertex(i);

    obj.vertex(vertex.x, vertex.y, vertex.z);
  }

  shape.endShape();

  return shape;
}

You will need to iterate obj.getChildCount() and obj.getChild(i).getVertexCount() if your shape contains child PShape

1 Like

If you modify shape, will that be reflected when you draw shape1?

I’m not sure any of the available solutions are better than just loading the file multiple times.

Well a PShape.copy() would be the best solution here but it does not exist yet. It really depends on what you want to do, by putting the shape in a GROUP shape you now have acess to shape.translate(), shape.rotate() and shape.scale() whitout affecting the other shapes so it can help in some cases. But I think if you really want to modify a shape reconstruct it is faster than loading it i think.

It looks like there is currently draft code in PShape for using createShape as a copy command, like this:

PShape newShape = createShape(oldShape);    
1 Like

static protected PShape createShape(PApplet parent, PShape src) {

But they should stop limiting useful methods w/ private & protected! :japanese_ogre:

I believe (?) the dev team philosophy is to only make public those methods that they intend to support – in general they don’t make public interface that they can’t (or can’t yet) commit to ongoing support for, so that changing things won’t break stuff in ways that makes development harder and generates support tickets about internals.

For those planning to fork Processing and make custom changes who still want to use the full PDE app, the build instructions are on the wiki, here:

I did a full custom build once when I really really wanted a custom PGraphics methods for a project and couldn’t get an extended class to integrate due to createGraphics().

Note that for Mac you need to do the building on a Mac.

If you are on Linux, you can even build in a Docker container if you want, like this:

# Dockerfile for building Processing PDE on Linux using ant/jdk8
FROM frekele/ant:1.10.3-jdk8
WORKDIR /root
RUN apt-get -y install git
# point at your altered fork here:
RUN git clone https://github.com/processing/processing.git --depth 1
WORKDIR /root/processing/build/
RUN ant clean
RUN ant build

Here is a hack to access protected functions in classes :slight_smile:

public static class PShapeAcess extends PShape {
  
  public static PShape copyShape(PApplet parent, PShape shape) {
    return createShape(parent, shape);
  }
  
}

PShape shape;
PShape shapeCopy;

public void setup() {
  
  // Copy the shape
  shapeCopy = PShapeAcess.copyShape(this, shape);
}
4 Likes

Interesting static copy class hack! The key problem I recall having with trying to extend PGraphics in a non-static way was that createGraphics() returned PGraphics – so extending PGraphics with new methods did me no good without also writing my own create method. In this case, however, all we want are PShapes, so the hack fits the bill even though createShape() and loadShape() would present similar problems if we were trying to add non-static methods.

Here is a full demo sketch of Stephcraft’s PShape copy hack. Keep in mind – protected, not supported, not documented = could break anytime!

PShape mySquare;
PShape mySquareCopy;

void setup() {
  mySquare = createShape(RECT, 0, 0, 50, 50);
  mySquareCopy = PShapeAccess.copyShape(this, mySquare);
  mySquareCopy.setFill(0);
  shape(mySquare, 10, 10);
  shape(mySquareCopy, 40, 40);
}

static class PShapeAccess extends PShape {
  static PShape copyShape(PApplet parent, PShape src) {
    return createShape(parent, src);
  }
}
3 Likes

Is there any new to this topic yet?

unfortunately, the Hack is nice but not copy things like .setEmissive()

This was the original question. There were a number of replies providing hacks into the Processing source code to overcome the protected, private access modifiers they were not completely successful.

A good question but unfortunately the answer is no, despite this discussion being over 7½ years old the shape copy code is still marked as unapproved.

BUT there is good news I have a non-hackish and simple solution to the original question. To see it in action select the File | Examples menu option in the PDE and in the dialog box select the example Basics | Shape | LoadDisplayOBJ then File | SaveAs so you end up with an editable copy of the example with the OBJ file.

Now replace the entire example code with the sketch code below. and bingo the rocket.obj file is only loaded once no matter how many rocket shape you want to create. :grinning_face: :+1:

/**
 * Load and Display an OBJ Shape.
 *
 * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
 * files and OBJ (Object) files into a Processing sketch. This example loads an
 * OBJ file of a rocket and displays it to the screen.
 */

PShape rocket, rocket2;
float ry;

public void setup() {
  size(640, 360, P3D);
  rocket  = loadOBJ(this, "rocket.obj");
  rocket2 = loadOBJ(this, "rocket.obj");
}

public void draw() {
  background(0);
  lights();
  push();
  translate(width/6, height/2 + 100, -200);
  rotateZ(PI);
  rotateY(ry);
  shape(rocket);
  pop();
  push();
  translate(width*5/6, height/2 + 100, -200);
  rotateZ(PI);
  rotateY(ry*3);
  shape(rocket2);
  pop();
  ry += 0.02;
}


// ###########################################################################
// Load a 3D object from  a '.obj' file. If a file is used multiple times it
// only loaded once.
// ###########################################################################

final HashMap<String, PShapeOBJ> OBJMAP = new HashMap<String, PShapeOBJ>();

public PShape loadOBJ(PApplet parent, String filename) {
  PGraphics pg = parent.getGraphics();
  PShapeOBJ obj = OBJMAP.get(filename);
  if (obj == null) { // File has not been previously loaded
    // load the object file
    int dot = filename.lastIndexOf(".");
    String ext = filename.substring(dot+1);
    if (ext.equalsIgnoreCase("obj")) {
      obj = new PShapeOBJ(parent, filename);
      OBJMAP.put(filename, obj);
    }
  }
  if (obj != null) {
    int prevTextureMode = pg.textureMode;
    pg.textureMode = NORMAL;
    PShapeOpenGL p3d = PShapeOpenGL.createShape((PGraphicsOpenGL)pg, obj);
    pg.textureMode = prevTextureMode;
    return p3d;
  }
  return null;
}
3 Likes

Hey! I don’t even remember what I was working on at the time. But I wanted to say thank you for taking the time to reply to this :slight_smile:

4 Likes

This wasn’t meant to be a criticism of the development team. I think that @jeremydouglass had it right with -

It can always be added to github as a feature request :innocent:

2 Likes

I did a quick search and there are a couple of issues in the old repository:

I did not find them in the new Processing 4 repository:

GitHub - processing/processing4: Source code for Processing, the software sketchbook and Java-based programming language for students, artists, designers, educators, hobbyists, and creative coders. Includes the core library, and editor (PDE)

I may certainly have missed something in my search.

Active participation from members is the foundation of this community.
Let’s help the Processing Foundation and this community by submitting an issue (enhancement).

:-)

1 Like