/* * OBJExport - Exports obj files from processing with beginRecord and endRecord * by Jesse Louis-Rosenberg * http://n-e-r-v-o-u-s.com * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * <p/> * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * <p/> * You should have received a copy of the GNU Lesser General * Public License along with the Processing project; if not, * write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ import java.io.*; import java.util.HashMap; import processing.core.*; public class OBJExport extends PGraphics3D { File file; PrintWriter writer; PVector[] pts; int[][] lines; int[][] faces; int lineCount; int faceCount; int objectMode = 0; HashMap<String,String> ptMap; public OBJExport() { } public void setPath(String path) { this.path = path; if (path != null) { file = new File(path); if (!file.isAbsolute()) file = null; } if (file == null) { throw new RuntimeException("OBJExport requires an absolute path " + "for the location of the output file."); } } protected void allocate() { } public void dispose() { writer.flush(); writer.close(); writer = null; } public boolean displayable() { return false; // just in case someone wants to use this on its own } public void beginDraw() { // have to create file object here, because the name isn't yet // available in allocate() if (writer == null) { try { writer = new PrintWriter(new FileWriter(file)); } catch (IOException e) { throw new RuntimeException(e); } pts = new PVector[1024]; lines = new int[1024][]; faces = new int[1024][]; lineCount = 0; faceCount = 0; ptMap = new HashMap<String,String>(); } } public void endDraw() { //write vertices and initialize ptMap writeVertices(); writeLines(); writeFaces(); } private void writeVertices() { for(int i=0;i<ptMap.size();++i) { PVector v = pts[i]; writer.println("v " + v.x + " " + v.y + " " + v.z); } } private void writeLines() { for(int i=0;i<lineCount;++i) { int[] l = lines[i]; String output = "l"; for(int j=0;j<l.length;++j) { output += " " + l[j]; } writer.println(output); } } private void writeFaces() { for(int i=0;i<faceCount;++i) { int[] f = faces[i]; String output = "f"; for(int j=0;j<f.length;++j) { output += " " + f[j]; } writer.println(output); } } public void beginShape(int kind) { shape = kind; vertexCount = 0; } public void vertex(float x, float y) { vertex(x,y,0); } public void vertex(float x, float y,float z) { PMatrix3D m = getMatrix((PMatrix3D)null); PVector v1 = new PVector(x, y, z); v1 = m.mult(v1, null); x = v1.x; y = v1.y; z = v1.z; System.out.println(vertexCount); float vertex[] = vertices[vertexCount]; if(!ptMap.containsKey(x+"_"+y+"_"+z)) { if(ptMap.size() >= pts.length) { PVector newPts[] = new PVector[pts.length*2]; System.arraycopy(pts,0,newPts,0,pts.length); pts = newPts; } pts[ptMap.size()] = new PVector(x,y,z); ptMap.put(x+"_"+y+"_"+z,""+(ptMap.size()+1)); } vertex[X] = x; // note: not mx, my, mz like PGraphics3 vertex[Y] = y; vertex[Z] = z; if (fill) { vertex[R] = fillR; vertex[G] = fillG; vertex[B] = fillB; vertex[A] = fillA; } if (stroke) { vertex[SR] = strokeR; vertex[SG] = strokeG; vertex[SB] = strokeB; vertex[SA] = strokeA; vertex[SW] = strokeWeight; } if (textureImage != null) { // for the future? vertex[U] = textureU; vertex[V] = textureV; } vertexCount++; } public void endShape(int mode) { //if(stroke) endShapeStroke(mode); //if(fill) endShapeFill(mode); endShapeFill(mode); } public void endShapeFill(int mode) { switch(shape) { case TRIANGLES: { int stop = vertexCount-2; for (int i = 0; i < stop; i += 3) { int[] f = new int[3]; f[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); addFace(f); } } break; case TRIANGLE_STRIP: { int stop = vertexCount - 2; for (int i = 0; i < stop; i++) { // have to switch between clockwise/counter-clockwise // otherwise the feller is backwards and renderer won't draw if ((i % 2) == 0) { int[] f = new int[3]; f[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); addFace(f); } else { int[] f = new int[3]; f[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); addFace(f); } } } break; case POLYGON: { int[] f; boolean closed = vertices[0][X]!=vertices[vertexCount-1][X] || vertices[0][Y]!=vertices[vertexCount-1][Y] || vertices[0][Z]!=vertices[vertexCount-1][Z]; if(closed) { f = new int[vertexCount]; } else { f = new int[vertexCount-1]; } int end = vertexCount; if(!closed) end--; for(int i=0;i<end;++i) { f[i] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); } addFace(f); } break; case QUADS: { int stop = vertexCount-3; for (int i = 0; i < stop; i += 4) { int[] f = new int[4]; f[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); f[3] = PApplet.parseInt(ptMap.get(vertices[i+3][X]+"_"+vertices[i+3][Y]+"_"+vertices[i+3][Z])); addFace(f); } } break; case QUAD_STRIP: { int stop = vertexCount-3; for (int i = 0; i < stop; i += 2) { int[] f = new int[4]; f[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); f[3] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+3][X]+"_"+vertices[i+3][Y]+"_"+vertices[i+3][Z])); addFace(f); } } break; case TRIANGLE_FAN: { int stop = vertexCount - 1; for (int i = 1; i < stop; i++) { int f[] = new int[3]; f[0] = PApplet.parseInt(ptMap.get(vertices[0][X]+"_"+vertices[0][Y]+"_"+vertices[0][Z])); f[1] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); f[2] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); addFace(f); } } break; } } //unused as of now public void endShapeStroke(int mode) { switch(shape) { case LINES: { int stop = vertexCount-1; for (int i = 0; i < stop; i += 2) { int[] l = new int[2]; l[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); l[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); addLine(l);; } } break; case TRIANGLES: { int stop = vertexCount-2; for (int i = 0; i < stop; i += 3) { int[] l = new int[4]; l[0] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); l[1] = PApplet.parseInt(ptMap.get(vertices[i+1][X]+"_"+vertices[i+1][Y]+"_"+vertices[i+1][Z])); l[2] = PApplet.parseInt(ptMap.get(vertices[i+2][X]+"_"+vertices[i+2][Y]+"_"+vertices[i+2][Z])); l[3] = l[0]; addLine(l);; } } break; case POLYGON: { int[] l; boolean closed = mode == CLOSE && (vertices[0][X]!=vertices[vertexCount-1][X] || vertices[0][Y]!=vertices[vertexCount-1][Y] || vertices[0][Z]!=vertices[vertexCount-1][Z]); if(closed) { l = new int[vertexCount+1]; } else { l = new int[vertexCount]; } for(int i=0;i<vertexCount;++i) { l[i] = PApplet.parseInt(ptMap.get(vertices[i][X]+"_"+vertices[i][Y]+"_"+vertices[i][Z])); } if(closed) l[vertexCount] = l[0]; addLine(l);; } break; } } private void addFace(int[] f) { if(faceCount >= faces.length) { int newfaces[][] = new int[faces.length*2][]; System.arraycopy(faces,0,newfaces,0,faces.length); faces = newfaces; } faces[faceCount++] = f; } private void addLine(int[] l) { if(lineCount >= lines.length) { int newLines[][] = new int[lines.length*2][]; System.arraycopy(lines,0,newLines,0,lines.length); lines = newLines; } lines[lineCount++] = l; } }