No matter how you look at it, an hourglass is a pretty weird polygon -- much too weird to take it as is for a 3D surface. :D
You seem to be worried about the speed of beginShape(),vertex(),endShape(), but unfortunately you can't have it both ways -- if you make degenerate polys then *something* has to fix it for you, which takes time. The fastest method of drawing 3d surfaces is to just draw valid triangles directly. (ignoring display lists and other advanced stuff) For simple polygons the built-in triangulator is pretty fast, but as you've seen will fail on degenerate polys.
Here's what's necessary to draw that hourglass with OpenGL, adapt and reuse for your own sketch, though it's not likely to be fast:
Quote:
import processing.opengl.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
GL gl;
GLU glu;
GLUtessellator tess;
TessCallback tessCallback;
void setup() {
size(400,400,OPENGL);
// setup the tesselator
gl = ((PGraphicsOpenGL)g).gl;
glu = ((PGraphicsOpenGL)g).glu;
tess = glu.gluNewTess();
tessCallback = new TessCallback();
glu.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, tessCallback);
glu.gluTessCallback(tess, GLU.GLU_TESS_END, tessCallback);
glu.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, tessCallback);
glu.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, tessCallback);
glu.gluTessCallback(tess, GLU.GLU_TESS_ERROR, tessCallback);
}
void draw() {
background(255);
stroke(0);
fill(128);
/*
// this degenerate "hourglass" poly won't triangulate properly:
beginShape();
vertex(100,100);
vertex(300,300);
vertex(100,300);
vertex(300,100);
endShape(CLOSE);
*/
// so have to do it the hard way:
glu.gluTessBeginPolygon(tess, null);
glu.gluTessBeginContour(tess);
double [] vertex1 = { 100, 100, 0 };
glu.gluTessVertex(tess, vertex1, 0, vertex1);
double [] vertex2 = { 300, 300, 0 };
glu.gluTessVertex(tess, vertex2, 0, vertex2);
double [] vertex3 = { 100, 300, 0 };
glu.gluTessVertex(tess, vertex3, 0, vertex3);
double [] vertex4 = { 300, 100, 0 };
glu.gluTessVertex(tess, vertex4, 0, vertex4);
glu.gluTessEndContour(tess);
glu.gluTessEndPolygon(tess);
}
class TessCallback extends GLUtessellatorCallbackAdapter {
public void begin(int type) {
switch (type) {
case GL.GL_TRIANGLE_FAN: beginShape(TRIANGLE_FAN); break;
case GL.GL_TRIANGLE_STRIP: beginShape(TRIANGLE_STRIP); break;
case GL.GL_TRIANGLES: beginShape(TRIANGLES); break;
}
}
public void end() {
endShape();
}
public void vertex(Object data) {
if (data instanceof double[]) {
double[] d = (double[]) data;
if (d.length != 3) {
throw new RuntimeException("TessCallback vertex() data isn't length 3");
}
g.vertex((float) d[0], (float) d[1], (float) d[2]);
} else {
throw new RuntimeException("TessCallback vertex() data not understood");
}
}
public void error(int errnum) {
String estring = glu.gluErrorString(errnum);
throw new RuntimeException("Tessellation Error: " + estring);
}
public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) {
double[] vert = new double[coords.length];
vert[0] = coords[0];
vert[1] = coords[1];
vert[2] = coords[2];
outData[0] = vert;
}
}