From c63a06a8f02600a1f1b1d037c6a8c57817114cff Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 23 May 2012 23:31:25 +0000 Subject: [PATCH] loadShape properly implemented across renderers --- core/src/processing/core/PApplet.java | 152 +++------ core/src/processing/core/PGraphics.java | 85 +++-- core/src/processing/core/PGraphicsJava2D.java | 32 ++ core/src/processing/core/PShape.java | 153 ++++----- .../src/processing/opengl/PGraphics2D.java | 125 ++++++-- .../src/processing/opengl/PGraphics3D.java | 300 ++++++++++-------- .../processing/opengl/PGraphicsOpenGL.java | 61 +++- .../src/processing/opengl/PShape2D.java | 39 +++ .../src/processing/opengl/PShape3D.java | 38 +++ .../src/processing/opengl/PShapeOpenGL.java | 14 +- 10 files changed, 618 insertions(+), 381 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 6f9733a7c..55c81423d 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -5277,86 +5277,6 @@ public class PApplet extends Applet } - - ////////////////////////////////////////////////////////////// - - // SHAPE I/O - - - /** - * ( begin auto-generated from loadShape.xml ) - * - * Loads vector shapes into a variable of type PShape. Currently, - * only SVG files may be loaded. To load correctly, the file must be - * located in the data directory of the current sketch. In most cases, - * loadShape() should be used inside setup() because loading - * shapes inside draw() will reduce the speed of a sketch.
- *
filename parameter can also be a URL to a file found - * online. For security reasons, a Processing sketch found online can only - * download files from the same server from which it came. Getting around - * this restriction requires a signed - * applet.
- *
a shape is not loaded successfully, the null value is - * returned and an error message will be printed to the console. The error - * message does not halt the program, however the null value may cause a - * NullPointerException if your code does not check whether the value - * returned from loadShape() is null. - * - * ( end auto-generated ) - * - * @webref shape:loading_displaying - * @param filename name of the file to load - * @see PShape#PShape - * @see PGraphics#shape(PShape, float, float, float, float) - * @see PGraphics#shapeMode(int) - */ - public PShape loadShape(String filename) { - String extension; - - String lower = filename.toLowerCase(); - int dot = filename.lastIndexOf('.'); - if (dot == -1) { - extension = "unknown"; // no extension found - } - extension = lower.substring(dot + 1); - - // check for, and strip any parameters on the url, i.e. - // filename.jpg?blah=blah&something=that - int question = extension.indexOf('?'); - if (question != -1) { - extension = extension.substring(0, question); - } - - if (extension.equals("svg")) { - return new PShapeSVG(this, filename); - - } else if (extension.equals("svgz")) { - try { - InputStream input = new GZIPInputStream(createInput(filename)); - XML xml = new XML(createReader(input)); - return new PShapeSVG(xml); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - // Loading the formats supported by the renderer. - - String[] loadShapeFormats = g.getSupportedShapeFormats(); - - if (loadShapeFormats != null) { - for (int i = 0; i < loadShapeFormats.length; i++) { - if (extension.equals(loadShapeFormats[i])) { - return g.loadShape(filename); - } - } - } - } - - return null; - } - - ////////////////////////////////////////////////////////////// // DATA I/O @@ -6741,6 +6661,26 @@ public class PApplet extends Applet } + static public String getExtension(String filename) { + String extension; + + String lower = filename.toLowerCase(); + int dot = filename.lastIndexOf('.'); + if (dot == -1) { + extension = "unknown"; // no extension found + } + extension = lower.substring(dot + 1); + + // check for, and strip any parameters on the url, i.e. + // filename.jpg?blah=blah&something=that + int question = extension.indexOf('?'); + if (question != -1) { + extension = extension.substring(0, question); + } + + return extension; + } + ////////////////////////////////////////////////////////////// @@ -10152,6 +10092,37 @@ public class PApplet extends Applet } + public void blendMode(int mode) { + if (recorder != null) recorder.blendMode(mode); + g.blendMode(mode); + } + + + public PShape loadShape(String filename) { + return g.loadShape(filename); + } + + + public PShape createShape(PShape source) { + return g.createShape(source); + } + + + public PShape createShape() { + return g.createShape(); + } + + + public PShape createShape(int type) { + return g.createShape(type); + } + + + public PShape createShape(int kind, float... p) { + return g.createShape(kind, p); + } + + public void bezierVertex(float x2, float y2, float x3, float y3, float x4, float y4) { @@ -13842,27 +13813,6 @@ public class PApplet extends Applet } - public PShape createShape() { - return g.createShape(); - } - - - public PShape createShape(int type) { - return g.createShape(type); - } - - - public PShape createShape(int kind, float... p) { - return g.createShape(kind, p); - } - - - public void blendMode(int mode) { - if (recorder != null) recorder.blendMode(mode); - g.blendMode(mode); - } - - public void delete() { if (recorder != null) recorder.delete(); g.delete(); diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 4d0249efd..402f46934 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -1435,10 +1435,62 @@ public class PGraphics extends PImage implements PConstants { showMissingWarning("clip"); } + public void noClip() { showMissingWarning("noClip"); } + + ////////////////////////////////////////////////////////////// + + // BLEND + + + public void blendMode(int mode) { + showMissingWarning("blendMode"); + } + + + ////////////////////////////////////////////////////////////// + + // SHAPE I/O + + + public PShape loadShape(String filename) { + showMissingWarning("loadShape"); + return null; + } + + + ////////////////////////////////////////////////////////////// + + // SHAPE CREATION + + + public PShape createShape(PShape source) { + showMissingWarning("createShape"); + return null; + } + + + public PShape createShape() { + showMissingWarning("createShape"); + return null; + } + + + public PShape createShape(int type) { + showMissingWarning("createShape"); + return null; + } + + + public PShape createShape(int kind, float... p) { + showMissingWarning("createShape"); + return null; + } + + ////////////////////////////////////////////////////////////// // CURVE/BEZIER VERTEX HANDLING @@ -7454,37 +7506,4 @@ public class PGraphics extends PImage implements PConstants { public boolean isGL() { return false; } - - ////////////////////////////////////////////////////////////// - - // New API: - - public PShape createShape() { - showMissingWarning("createShape"); - return null; - } - - public PShape createShape(int type) { - showMissingWarning("createShape"); - return null; - } - - public PShape createShape(int kind, float... p) { - showMissingWarning("createShape"); - return null; - } - - public PShape loadShape(String filename) { // ignore - showMissingWarning("loadShape"); - return null; - } - - protected String[] getSupportedShapeFormats() { - showMissingWarning("getSupportedShapeFormats"); - return null; - } - - public void blendMode(int mode) { - showMissingWarning("blendMode"); - } } diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index 53c7f0eb6..118d866ea 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -26,8 +26,12 @@ package processing.core; import java.awt.*; import java.awt.geom.*; import java.awt.image.*; +import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; +import java.util.zip.GZIPInputStream; +import processing.data.XML; /** * Subclass for PGraphics that implements the graphics API using Java2D. @@ -1103,7 +1107,35 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ { //public void shape(PShape shape, float x, float y, float c, float d) + + ////////////////////////////////////////////////////////////// + // SHAPE I/O + + + public PShape loadShape(String filename) { + String extension = PApplet.getExtension(filename); + + PShapeSVG svg = null; + + if (extension.equals("svg")) { + svg = new PShapeSVG(parent, filename); + + } else if (extension.equals("svgz")) { + try { + InputStream input = new GZIPInputStream(parent.createInput(filename)); + XML xml = new XML(PApplet.createReader(input)); + svg = new PShapeSVG(xml); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + PGraphics.showWarning("Unsupported format"); + } + + return svg; + } + ////////////////////////////////////////////////////////////// diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index b155ffb48..a211c8ae3 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -245,7 +245,8 @@ public class PShape implements PConstants { public PShape() { this.family = GROUP; } - + + /** * @nowebref */ @@ -747,122 +748,126 @@ public class PShape implements PConstants { g.popStyle(); } } - //////////////////////////////////////////////////////////////////////// // - // The new copy methods to put an SVG into a PShape3D, for example + // Shape copy - public PShape copy(PGraphics g) { - PShape res = null; - if (family == GROUP) { - res = g.createShape(GROUP); - copyGroup(g, res); - } else if (family == PRIMITIVE) { - res = g.createShape(kind, params); - copyPrimitive(res); - } else if (family == GEOMETRY) { - res = g.createShape(kind); - copyGeometry(res); - } else if (family == PATH) { - res = g.createShape(PATH); - copyPath(res); + + static public PShape createShape(PApplet parent, PShape src) { + PShape dest = null; + if (src.family == GROUP) { + dest = parent.createShape(GROUP); + PShape.copyGroup(parent, src, dest); + } else if (src.family == PRIMITIVE) { + dest = parent.createShape(src.kind, src.params); + PShape.copyPrimitive(src, dest); + } else if (src.family == GEOMETRY) { + dest = parent.createShape(src.kind); + PShape.copyGeometry(src, dest); + } else if (src.family == PATH) { + dest = parent.createShape(PATH); + PShape.copyPath(src, dest); } - res.setName(name); - return res; + dest.setName(src.name); + return dest; } - protected void copyGroup(PGraphics g, PShape s) { - if (matrix != null) { - s.applyMatrix(matrix); - } - copyStyles(s); - copyImage(s); - for (int i = 0; i < childCount; i++) { - PShape c = children[i].copy(g); - s.addChild(c); + static public void copyGroup(PApplet parent, PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); + for (int i = 0; i < src.childCount; i++) { + PShape c = PShape.createShape(parent, src.children[i]); + dest.addChild(c); } } - protected void copyPrimitive(PShape s) { - if (matrix != null) { - s.applyMatrix(matrix); - } - copyStyles(s); - copyImage(s); + static public void copyPrimitive(PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); } - protected void copyGeometry(PShape s) { - if (matrix != null) { - s.applyMatrix(matrix); - } - copyStyles(s); - copyImage(s); + + static public void copyGeometry(PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); - if (style) { - for (int i = 0; i < vertexCount; i++) { - float[] vert = vertices[i]; + if (src.style) { + for (int i = 0; i < src.vertexCount; i++) { + float[] vert = src.vertices[i]; + + // Do we need to copy these as well? // s.ambient(vert[AR] * 255, vert[AG] * 255, vert[AB] * 255); // s.specular(vert[SPR] * 255, vert[SPG] * 255, vert[SPB] * 255); // s.emissive(vert[ER] * 255, vert[EG] * 255, vert[EB] * 255); // s.shininess(vert[SHINE]); - s.normal(vert[NX], vert[NY], vert[NZ]); - s.vertex(vert[X], vert[Y], vert[Z], vert[U], vert[V]); + dest.normal(vert[NX], vert[NY], vert[NZ]); + dest.vertex(vert[X], vert[Y], vert[Z], vert[U], vert[V]); } } else { - for (int i = 0; i < vertexCount; i++) { - float[] vert = vertices[i]; + for (int i = 0; i < src.vertexCount; i++) { + float[] vert = src.vertices[i]; if (vert[PGraphics.Z] == 0) { - s.vertex(vert[X], vert[Y]); + dest.vertex(vert[X], vert[Y]); } else { - s.vertex(vert[X], vert[Y], vert[Z]); + dest.vertex(vert[X], vert[Y], vert[Z]); } } } - s.end(); + dest.end(); } - protected void copyPath(PShape s) { - if (matrix != null) { - s.applyMatrix(matrix); - } - copyStyles(s); - copyImage(s); - s.close = close; - s.setPath(vertexCount, vertices, vertexCodeCount, vertexCodes); - + + static public void copyPath(PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); + dest.close = src.close; + dest.setPath(src.vertexCount, src.vertices, src.vertexCodeCount, src.vertexCodes); } - protected void copyStyles(PShape s) { - if (stroke) { - s.stroke = true; - s.strokeColor = strokeColor; - s.strokeWeight = strokeWeight; - s.strokeCap = strokeCap; - s.strokeJoin = strokeJoin; + + static public void copyMatrix(PShape src, PShape dest) { + if (src.matrix != null) { + dest.applyMatrix(src.matrix); + } + } + + static public void copyStyles(PShape src, PShape dest) { + if (src.stroke) { + dest.stroke = true; + dest.strokeColor = src.strokeColor; + dest.strokeWeight = src.strokeWeight; + dest.strokeCap = src.strokeCap; + dest.strokeJoin = src.strokeJoin; } else { - s.stroke = false; + dest.stroke = false; } - if (fill) { - s.fill = true; - s.fillColor = fillColor; + if (src.fill) { + dest.fill = true; + dest.fillColor = src.fillColor; } else { - s.fill = false; + dest.fill = false; } } - protected void copyImage(PShape s) { - if (image != null) { - s.texture(image); + + static public void copyImage(PShape src, PShape dest) { + if (src.image != null) { + dest.texture(src.image); } } + //////////////////////////////////////////////////////////////////////// diff --git a/java/libraries/opengl/src/processing/opengl/PGraphics2D.java b/java/libraries/opengl/src/processing/opengl/PGraphics2D.java index f9891133f..88597541a 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphics2D.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphics2D.java @@ -22,8 +22,16 @@ package processing.opengl; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +import processing.core.PApplet; +import processing.core.PGraphics; import processing.core.PMatrix3D; import processing.core.PShape; +import processing.core.PShapeSVG; +import processing.data.XML; public class PGraphics2D extends PGraphicsOpenGL { @@ -44,17 +52,110 @@ public class PGraphics2D extends PGraphicsOpenGL { return false; } + ////////////////////////////////////////////////////////////// - // SHAPE CREATORS + // SHAPE + + + public void shape(PShape shape) { + if (shape.is2D()) { + super.shape(shape); + } else { + showWarning("The shape object is not 2D, cannot be displayed with this renderer"); + } + } + + + public void shape(PShape shape, float x, float y) { + if (shape.is2D()) { + super.shape(shape, x, y); + } else { + showWarning("The shape object is not 2D, cannot be displayed with this renderer"); + } + } + + + public void shape(PShape shape, float a, float b, float c, float d) { + if (shape.is2D()) { + super.shape(shape, a, b, c, d); + } else { + showWarning("The shape object is not 2D, cannot be displayed with this renderer"); + } + } + + + public void shape(PShape shape, float x, float y, float z) { + showDepthWarningXYZ("shape"); + } + + + public void shape(PShape shape, float x, float y, float z, float c, float d, float e) { + showDepthWarningXYZ("shape"); + } + + + ////////////////////////////////////////////////////////////// + + // SHAPE I/O + + + static protected boolean isSupportedExtension(String extension) { + return extension.equals("svg") || extension.equals("svgz"); + } + static protected PShape2D loadShapeImpl(PGraphics pg, String filename, String extension) { + PShapeSVG svg = null; + + if (extension.equals("svg")) { + svg = new PShapeSVG(pg.parent, filename); + + } else if (extension.equals("svgz")) { + try { + InputStream input = new GZIPInputStream(pg.parent.createInput(filename)); + XML xml = new XML(PApplet.createReader(input)); + svg = new PShapeSVG(xml); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (svg != null) { + PShape2D p2d = PShape2D.createShape(pg.parent, svg); + return p2d; + } else { + return null; + } + } + + + ////////////////////////////////////////////////////////////// + + // SHAPE CREATION + + + public PShape createShape(PShape source) { + return PShape2D.createShape(parent, source); + } + + public PShape createShape() { return createShape(POLYGON); } public PShape createShape(int type) { + return createShapeImpl(parent, type); + } + + + public PShape createShape(int kind, float... p) { + return createShapeImpl(parent, kind, p); + } + + + static protected PShape2D createShapeImpl(PApplet parent, int type) { PShape2D shape = null; if (type == PShape.GROUP) { shape = new PShape2D(parent, PShape.GROUP); @@ -89,7 +190,7 @@ public class PGraphics2D extends PGraphicsOpenGL { } - public PShape createShape(int kind, float... p) { + static protected PShape2D createShapeImpl(PApplet parent, int kind, float... p) { PShape2D shape = null; int len = p.length; @@ -156,27 +257,7 @@ public class PGraphics2D extends PGraphicsOpenGL { return shape; } - - ////////////////////////////////////////////////////////////// - - // SHAPE I/O - - protected String[] getSupportedShapeFormats() { - return new String[] { "svg" }; - } - - - public PShape loadShape(String filename) { - // TODO: loadShape in PApplet probably needs to be - // re-implemented. - PShape svg = parent.loadShape(filename); - // TODO: rework base API in PShape to do this... - PShape2D p2d = (PShape2D) svg.copy(this); - - return p2d; - } - ////////////////////////////////////////////////////////////// diff --git a/java/libraries/opengl/src/processing/opengl/PGraphics3D.java b/java/libraries/opengl/src/processing/opengl/PGraphics3D.java index a8c6d0a1a..81fb8f64e 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphics3D.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphics3D.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Hashtable; import processing.core.PApplet; +import processing.core.PGraphics; import processing.core.PImage; import processing.core.PShape; import processing.core.PVector; @@ -37,18 +38,151 @@ public class PGraphics3D extends PGraphicsOpenGL { // RENDERER SUPPORT QUERIES + public boolean is2D() { return false; } + public boolean is3D() { return true; } + ////////////////////////////////////////////////////////////// - // SHAPE CREATORS + // SHAPE I/O + + static protected boolean isSupportedExtension(String extension) { + return extension.equals("obj"); + } + + + static protected PShape loadShapeImpl(PGraphics pg, String filename, String ext) { + ArrayList vertices = new ArrayList(); + ArrayList normals = new ArrayList(); + ArrayList textures = new ArrayList(); + ArrayList faces = new ArrayList(); + ArrayList materials = new ArrayList(); + + BufferedReader reader = pg.parent.createReader(filename); + parseOBJ(pg.parent, reader, vertices, normals, textures, faces, materials); + + int prevColorMode = pg.colorMode; + float prevColorModeX = pg.colorModeX; + float prevColorModeY = pg.colorModeY; + float prevColorModeZ = pg.colorModeZ; + float prevColorModeA = pg.colorModeA; + boolean prevStroke = pg.stroke; + int prevTextureMode = pg.textureMode; + pg.colorMode(RGB, 1); + pg.stroke = false; + pg.textureMode = NORMAL; + + // The OBJ geometry is stored in a group shape, + // with each face in a separate child geometry + // shape. + PShape root = createShapeImpl(pg.parent, GROUP); + + int mtlIdxCur = -1; + OBJMaterial mtl = null; + for (int i = 0; i < faces.size(); i++) { + OBJFace face = faces.get(i); + + // Getting current material. + if (mtlIdxCur != face.matIdx) { + mtlIdxCur = PApplet.max(0, face.matIdx); // To make sure that at least we get the default material. + mtl = materials.get(mtlIdxCur); + } + + // Creating child shape for current face. + PShape child; + if (face.vertIdx.size() == 3) { + child = createShapeImpl(pg.parent, TRIANGLES); // Face is a triangle, so using appropriate shape kind. + } else if (face.vertIdx.size() == 4) { + child = createShapeImpl(pg.parent, QUADS); // Face is a quad, so using appropriate shape kind. + } else { + child = createShapeImpl(pg.parent, POLYGON); // Face is a general polygon + } + + // Setting material properties for the new face + child.fill(mtl.kd.x, mtl.kd.y, mtl.kd.z); + child.ambient(mtl.ka.x, mtl.ka.y, mtl.ka.z); + child.specular(mtl.ks.x, mtl.ks.y, mtl.ks.z); + child.shininess(mtl.ns); + if (mtl.kdMap != null) { + // If current material is textured, then tinting the texture using the diffuse color. + child.tint(mtl.kd.x, mtl.kd.y, mtl.kd.z, mtl.d); + } + + for (int j = 0; j < face.vertIdx.size(); j++){ + int vertIdx, normIdx; + PVector vert, norms; + + vert = norms = null; + + vertIdx = face.vertIdx.get(j).intValue() - 1; + vert = vertices.get(vertIdx); + + if (j < face.normIdx.size()) { + normIdx = face.normIdx.get(j).intValue() - 1; + if (-1 < normIdx) { + norms = normals.get(normIdx); + } + } + + if (mtl != null && mtl.kdMap != null) { + // This face is textured. + int texIdx; + PVector tex = null; + + if (j < face.texIdx.size()) { + texIdx = face.texIdx.get(j).intValue() - 1; + if (-1 < texIdx) { + tex = textures.get(texIdx); + } + } + + child.texture(mtl.kdMap); + if (norms != null) { + child.normal(norms.x, norms.y, norms.z); + } + if (tex != null) { + child.vertex(vert.x, vert.y, vert.z, tex.x, tex.y); + } else { + child.vertex(vert.x, vert.y, vert.z); + } + } else { + // This face is not textured. + if (norms != null) { + child.normal(norms.x, norms.y, norms.z); + } + child.vertex(vert.x, vert.y, vert.z); + } + } + + child.end(CLOSE); + root.addChild(child); + } + + pg.colorMode(prevColorMode, prevColorModeX, prevColorModeY, prevColorModeZ, prevColorModeA); + pg.stroke = prevStroke; + pg.textureMode = prevTextureMode; + + return root; + } + + + ////////////////////////////////////////////////////////////// + + // SHAPE CREATION + + + public PShape createShape(PShape source) { + return PShape3D.createShape(parent, source); + } + public PShape createShape() { return createShape(POLYGON); @@ -56,6 +190,16 @@ public class PGraphics3D extends PGraphicsOpenGL { public PShape createShape(int type) { + return createShapeImpl(parent, type); + } + + + public PShape createShape(int kind, float... p) { + return createShapeImpl(parent, kind, p); + } + + + static protected PShape3D createShapeImpl(PApplet parent, int type) { PShape3D shape = null; if (type == PShape.GROUP) { shape = new PShape3D(parent, PShape.GROUP); @@ -88,9 +232,9 @@ public class PGraphics3D extends PGraphicsOpenGL { } return shape; } - - - public PShape createShape(int kind, float... p) { + + + static protected PShape3D createShapeImpl(PApplet parent, int kind, float... p) { PShape3D shape = null; int len = p.length; @@ -171,135 +315,15 @@ public class PGraphics3D extends PGraphicsOpenGL { ////////////////////////////////////////////////////////////// - // SHAPE I/O + // OBJ LOADING + - - protected String[] getSupportedShapeFormats() { - return new String[] { "obj" }; - } - - - public PShape loadShape(String filename) { - ArrayList vertices = new ArrayList(); - ArrayList normals = new ArrayList(); - ArrayList textures = new ArrayList(); - ArrayList faces = new ArrayList(); - ArrayList materials = new ArrayList(); - - BufferedReader reader = parent.createReader(filename); - parseOBJ(reader, vertices, normals, textures, faces, materials); - - int prevColorMode = pg.colorMode; - float prevColorModeX = pg.colorModeX; - float prevColorModeY = pg.colorModeY; - float prevColorModeZ = pg.colorModeZ; - float prevColorModeA = pg.colorModeA; - boolean prevStroke = pg.stroke; - int prevTextureMode = pg.textureMode; - pg.colorMode(RGB, 1); - pg.stroke = false; - pg.textureMode = NORMAL; - - - // The OBJ geometry is stored in a group shape, - // with each face in a separate child geometry - // shape. - PShape root = createShape(GROUP); - - int mtlIdxCur = -1; - OBJMaterial mtl = null; - for (int i = 0; i < faces.size(); i++) { - OBJFace face = faces.get(i); - - // Getting current material. - if (mtlIdxCur != face.matIdx) { - mtlIdxCur = PApplet.max(0, face.matIdx); // To make sure that at least we get the default material. - mtl = materials.get(mtlIdxCur); - } - - // Creating child shape for current face. - PShape child; - if (face.vertIdx.size() == 3) { - child = createShape(TRIANGLES); // Face is a triangle, so using appropriate shape kind. - } else if (face.vertIdx.size() == 4) { - child = createShape(QUADS); // Face is a quad, so using appropriate shape kind. - } else { - child = createShape(POLYGON); // Face is a general polygon - } - - // Setting material properties for the new face - child.fill(mtl.kd.x, mtl.kd.y, mtl.kd.z); - child.ambient(mtl.ka.x, mtl.ka.y, mtl.ka.z); - child.specular(mtl.ks.x, mtl.ks.y, mtl.ks.z); - child.shininess(mtl.ns); - if (mtl.kdMap != null) { - // If current material is textured, then tinting the texture using the diffuse color. - child.tint(mtl.kd.x, mtl.kd.y, mtl.kd.z, mtl.d); - } - - for (int j = 0; j < face.vertIdx.size(); j++){ - int vertIdx, normIdx; - PVector vert, norms; - - vert = norms = null; - - vertIdx = face.vertIdx.get(j).intValue() - 1; - vert = vertices.get(vertIdx); - - if (j < face.normIdx.size()) { - normIdx = face.normIdx.get(j).intValue() - 1; - if (-1 < normIdx) { - norms = normals.get(normIdx); - } - } - - if (mtl != null && mtl.kdMap != null) { - // This face is textured. - int texIdx; - PVector tex = null; - - if (j < face.texIdx.size()) { - texIdx = face.texIdx.get(j).intValue() - 1; - if (-1 < texIdx) { - tex = textures.get(texIdx); - } - } - - child.texture(mtl.kdMap); - if (norms != null) { - child.normal(norms.x, norms.y, norms.z); - } - if (tex != null) { - child.vertex(vert.x, vert.y, vert.z, tex.x, tex.y); - } else { - child.vertex(vert.x, vert.y, vert.z); - } - } else { - // This face is not textured. - if (norms != null) { - child.normal(norms.x, norms.y, norms.z); - } - child.vertex(vert.x, vert.y, vert.z); - } - } - - child.end(CLOSE); - root.addChild(child); - } - - pg.colorMode(prevColorMode, prevColorModeX, prevColorModeY, prevColorModeZ, prevColorModeA); - pg.stroke = prevStroke; - pg.textureMode = prevTextureMode; - - return root; - } - - - protected void parseOBJ(BufferedReader reader, ArrayList vertices, - ArrayList normals, - ArrayList textures, - ArrayList faces, - ArrayList materials) { + static protected void parseOBJ(PApplet parent, + BufferedReader reader, ArrayList vertices, + ArrayList normals, + ArrayList textures, + ArrayList faces, + ArrayList materials) { Hashtable mtlTable = new Hashtable(); int mtlIdxCur = -1; boolean readv, readvn, readvt; @@ -360,7 +384,7 @@ public class PGraphics3D extends PGraphicsOpenGL { if (elements[1] != null) { BufferedReader mreader = parent.createReader(elements[1]); if (mreader != null) { - parseMTL(mreader, materials, mtlTable); + parseMTL(parent, mreader, materials, mtlTable); } } } else if (elements[0].equals("g")) { @@ -446,7 +470,10 @@ public class PGraphics3D extends PGraphicsOpenGL { } } - protected void parseMTL(BufferedReader reader, ArrayList materials, Hashtable materialsHash) { + + static protected void parseMTL(PApplet parent, + BufferedReader reader, ArrayList materials, + Hashtable materialsHash) { try { String line; OBJMaterial currentMtl = null; @@ -498,8 +525,9 @@ public class PGraphics3D extends PGraphicsOpenGL { } } + // Stores a face from an OBJ file - protected class OBJFace { + static protected class OBJFace { ArrayList vertIdx; ArrayList texIdx; ArrayList normIdx; @@ -517,7 +545,7 @@ public class PGraphics3D extends PGraphicsOpenGL { // Stores a material defined in an MTL file. - protected class OBJMaterial { + static protected class OBJMaterial { String name; PVector ka; PVector kd; diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 787d08baf..865732c4d 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -2177,6 +2177,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void tessellate(int mode) { + tessellator.set3D(is3D()); tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); tessellator.setFill(fill || textureImage != null); @@ -2186,7 +2187,7 @@ public class PGraphicsOpenGL extends PGraphics { tessellator.setStrokeCap(strokeCap); tessellator.setStrokeJoin(strokeJoin); tessellator.setTexCache(texCache, textureImage0, textureImage); - + if (shape == POINTS) { tessellator.tessellatePoints(); } else if (shape == LINES) { @@ -2231,6 +2232,7 @@ public class PGraphicsOpenGL extends PGraphics { } } + tessellator.set3D(is3D()); tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); tessellator.setFill(fill || textureImage != null); @@ -2239,7 +2241,7 @@ public class PGraphicsOpenGL extends PGraphics { tessellator.setStrokeWeight(strokeWeight); tessellator.setStrokeCap(strokeCap); tessellator.setStrokeJoin(strokeJoin); - tessellator.setTexCache(texCache, textureImage0, textureImage); + tessellator.setTexCache(texCache, textureImage0, textureImage); if (stroke && defaultEdges && edges == null) inGeo.addTrianglesEdges(); if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTrianglesNormals(); @@ -3073,6 +3075,24 @@ public class PGraphicsOpenGL extends PGraphics { popMatrix(); } } + + + ////////////////////////////////////////////////////////////// + + // SHAPE I/O + + + public PShape loadShape(String filename) { + String ext = PApplet.getExtension(filename); + if (PGraphics2D.isSupportedExtension(ext)) { + return PGraphics2D.loadShapeImpl(this, filename, ext); + } if (PGraphics3D.isSupportedExtension(ext)) { + return PGraphics3D.loadShapeImpl(this, filename, ext); + } else { + PGraphics.showWarning("Unsupported format"); + return null; + } + } ////////////////////////////////////////////////////////////// @@ -9101,6 +9121,7 @@ public class PGraphicsOpenGL extends PGraphics { PGL.Tessellator gluTess; TessellatorCallback callback; + boolean is2D, is3D; boolean fill; boolean stroke; int strokeColor; @@ -9122,6 +9143,8 @@ public class PGraphicsOpenGL extends PGraphics { callback = new TessellatorCallback(); gluTess = pgl.createTessellator(callback); rawIndices = new int[512]; + is2D = false; + is3D = true; } void setInGeometry(InGeometry in) { @@ -9169,6 +9192,16 @@ public class PGraphicsOpenGL extends PGraphics { this.newTexImage = newTexImage; } + void set3D(boolean value) { + if (value) { + is2D = false; + is3D = true; + } else { + is2D = true; + is3D = false; + } + } + // ----------------------------------------------------------------- // // Point tessellation @@ -9193,9 +9226,9 @@ public class PGraphicsOpenGL extends PGraphics { } int nvertTot = nPtVert * nInVert; int nindTot = 3 * (nPtVert - 1) * nInVert; - if (is3D()) { + if (is3D) { tessellateRoundPoints3D(nvertTot, nindTot, nPtVert); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateRoundPoints2D(nvertTot, nindTot, nPtVert); endNoTex(); @@ -9334,9 +9367,9 @@ public class PGraphicsOpenGL extends PGraphics { // So the quad is formed by 4 triangles, each requires // 3 indices. int nindTot = 12 * quadCount; - if (is3D()) { + if (is3D) { tessellateSquarePoints3D(nvertTot, nindTot); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateSquarePoints2D(nvertTot, nindTot); endNoTex(); @@ -9467,9 +9500,9 @@ public class PGraphicsOpenGL extends PGraphics { // Each stroke line has 4 vertices, defining 2 triangles, which // require 3 indices to specify their connectivities. int nind = lineCount * 2 * 3; - if (is3D()) { + if (is3D) { tessellateLines3D(nvert, nind, lineCount); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateLines2D(nvert, nind, lineCount); endNoTex(); @@ -9536,9 +9569,9 @@ public class PGraphicsOpenGL extends PGraphics { int lineCount = nInVert - 1; int nvert = lineCount * 4; int nind = lineCount * 2 * 3; - if (is3D()) { + if (is3D) { tessellateLineStrip3D(nvert, nind, lineCount); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateLineStrip2D(nvert, nind, lineCount); endNoTex(); @@ -9606,9 +9639,9 @@ public class PGraphicsOpenGL extends PGraphics { int lineCount = nInVert; int nvert = lineCount * 4; int nind = lineCount * 2 * 3; - if (is3D()) { + if (is3D) { tessellateLineLoop3D(nvert, nind, lineCount); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateLineLoop2D(nvert, nind, lineCount); endNoTex(); @@ -9676,9 +9709,9 @@ public class PGraphicsOpenGL extends PGraphics { if (stroke) { int nInVert = in.getNumLineVertices(); int nInInd = in.getNumLineIndices(); - if (is3D()) { + if (is3D) { tessellateEdges3D(nInVert, nInInd); - } else if (is2D()) { + } else if (is2D) { beginNoTex(); tessellateEdges2D(nInVert, nInInd); endNoTex(); diff --git a/java/libraries/opengl/src/processing/opengl/PShape2D.java b/java/libraries/opengl/src/processing/opengl/PShape2D.java index 7e2bddce3..2d32cb2ec 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape2D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape2D.java @@ -24,6 +24,7 @@ package processing.opengl; import processing.core.PApplet; import processing.core.PGraphics; +import processing.core.PShape; public class PShape2D extends PShapeOpenGL { @@ -38,6 +39,44 @@ public class PShape2D extends PShapeOpenGL { public boolean is3D() { return false; } + + + //////////////////////////////////////////////////////////////////////// + // + // Shape copy + + + static public PShape2D createShape(PApplet parent, PShape src) { + PShape2D dest = null; + if (src.getFamily() == GROUP) { + dest = PGraphics2D.createShapeImpl(parent, GROUP); + PShape2D.copyGroup(parent, src, dest); + } else if (src.getFamily() == PRIMITIVE) { + dest = PGraphics2D.createShapeImpl(parent, src.getKind(), src.getParams()); + PShape.copyPrimitive(src, dest); + } else if (src.getFamily() == GEOMETRY) { + dest = PGraphics2D.createShapeImpl(parent, src.getKind()); + PShape.copyGeometry(src, dest); + } else if (src.getFamily() == PATH) { + dest = PGraphics2D.createShapeImpl(parent, PATH); + PShape.copyPath(src, dest); + } + dest.setName(src.getName()); + return dest; + } + + + static public void copyGroup(PApplet parent, PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); + + for (int i = 0; i < src.getChildCount(); i++) { + PShape c = PShape2D.createShape(parent, src.getChild(i)); + dest.addChild(c); + } + } + /////////////////////////////////////////////////////////// diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index 0b3df34cc..e46f23ed0 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -23,6 +23,7 @@ package processing.opengl; import processing.core.PApplet; +import processing.core.PShape; public class PShape3D extends PShapeOpenGL { @@ -37,5 +38,42 @@ public class PShape3D extends PShapeOpenGL { public boolean is3D() { return true; } + + + //////////////////////////////////////////////////////////////////////// + // + // Shape copy + + + static public PShape3D createShape(PApplet parent, PShape src) { + PShape3D dest = null; + if (src.getFamily() == GROUP) { + dest = PGraphics3D.createShapeImpl(parent, GROUP); + PShape3D.copyGroup(parent, src, dest); + } else if (src.getFamily() == PRIMITIVE) { + dest = PGraphics3D.createShapeImpl(parent, src.getKind(), src.getParams()); + PShape.copyPrimitive(src, dest); + } else if (src.getFamily() == GEOMETRY) { + dest = PGraphics3D.createShapeImpl(parent, src.getKind()); + PShape.copyGeometry(src, dest); + } else if (src.getFamily() == PATH) { + dest = PGraphics3D.createShapeImpl(parent, PATH); + PShape.copyPath(src, dest); + } + dest.setName(src.getName()); + return dest; + } + + + static public void copyGroup(PApplet parent, PShape src, PShape dest) { + copyMatrix(src, dest); + copyStyles(src, dest); + copyImage(src, dest); + + for (int i = 0; i < src.getChildCount(); i++) { + PShape c = PShape3D.createShape(parent, src.getChild(i)); + dest.addChild(c); + } + } } diff --git a/java/libraries/opengl/src/processing/opengl/PShapeOpenGL.java b/java/libraries/opengl/src/processing/opengl/PShapeOpenGL.java index 944d49418..009aea3ed 100644 --- a/java/libraries/opengl/src/processing/opengl/PShapeOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PShapeOpenGL.java @@ -272,9 +272,11 @@ public class PShapeOpenGL extends PShape { protected int firstModifiedPointAttribute; protected int lastModifiedPointAttribute; + PShapeOpenGL() { } + public PShapeOpenGL(PApplet parent, int family) { pg = (PGraphicsOpenGL)parent.g; pgl = pg.pgl; @@ -2558,8 +2560,17 @@ public class PShapeOpenGL extends PShape { int[] color = tessGeo.polyColors; float[] uv = tessGeo.polyTexcoords; short[] indices = tessGeo.polyIndices; + + PShape tess; + if (is3D()) { + tess = PGraphics3D.createShapeImpl(pg.parent, TRIANGLES); + } else if (is2D()) { + tess = PGraphics2D.createShapeImpl(pg.parent, TRIANGLES); + } else { + PGraphics.showWarning("This shape is not either 2D or 3D!"); + return null; + } - PShape tess = pg.createShape(TRIANGLES); tess.noStroke(); IndexCache cache = tessGeo.polyIndexCache; @@ -2721,6 +2732,7 @@ public class PShapeOpenGL extends PShape { // duplication. inGeo.clearEdges(); + tessellator.set3D(is3D()); tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); tessellator.setFill(fill || texture != null);