loadShape properly implemented across renderers

This commit is contained in:
codeanticode
2012-05-23 23:31:25 +00:00
parent a9c69166f0
commit c63a06a8f0
10 changed files with 618 additions and 381 deletions
@@ -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;
}
//////////////////////////////////////////////////////////////
@@ -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<PVector> vertices = new ArrayList<PVector>();
ArrayList<PVector> normals = new ArrayList<PVector>();
ArrayList<PVector> textures = new ArrayList<PVector>();
ArrayList<OBJFace> faces = new ArrayList<OBJFace>();
ArrayList<OBJMaterial> materials = new ArrayList<OBJMaterial>();
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<PVector> vertices = new ArrayList<PVector>();
ArrayList<PVector> normals = new ArrayList<PVector>();
ArrayList<PVector> textures = new ArrayList<PVector>();
ArrayList<OBJFace> faces = new ArrayList<OBJFace>();
ArrayList<OBJMaterial> materials = new ArrayList<OBJMaterial>();
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<PVector> vertices,
ArrayList<PVector> normals,
ArrayList<PVector> textures,
ArrayList<OBJFace> faces,
ArrayList<OBJMaterial> materials) {
static protected void parseOBJ(PApplet parent,
BufferedReader reader, ArrayList<PVector> vertices,
ArrayList<PVector> normals,
ArrayList<PVector> textures,
ArrayList<OBJFace> faces,
ArrayList<OBJMaterial> materials) {
Hashtable<String, Integer> mtlTable = new Hashtable<String, Integer>();
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<OBJMaterial> materials, Hashtable<String, Integer> materialsHash) {
static protected void parseMTL(PApplet parent,
BufferedReader reader, ArrayList<OBJMaterial> materials,
Hashtable<String, Integer> 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<Integer> vertIdx;
ArrayList<Integer> texIdx;
ArrayList<Integer> 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;
@@ -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();
@@ -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);
}
}
///////////////////////////////////////////////////////////
@@ -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);
}
}
}
@@ -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);