/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.graphics.export; import static jpcsp.graphics.GeCommands.PRIM_TRIANGLE; import static jpcsp.graphics.GeCommands.PRIM_TRIANGLE_STRIPS; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Locale; import org.apache.log4j.Logger; import jpcsp.graphics.GeContext; import jpcsp.graphics.VertexState; import jpcsp.graphics.VideoEngine; /** * @author gid15 * */ public class WavefrontExporter implements IGraphicsExporter { private static Logger log = VideoEngine.log; // Use "." as decimal separator for floating point values private static Locale l = Locale.ENGLISH; private GeContext context; private BufferedWriter exportObj; private BufferedWriter exportMtl; private int exportVertexCount; private int exportTextureCount; private int exportNormalCount; private int exportModelCount; private int exportMaterialCount; // Blender does not import normals (as of blender 2.63) private static final boolean exportNormal = false; protected void exportObjLine(String line) { if (exportObj != null) { try { exportObj.write(line); exportObj.newLine(); } catch (IOException e) { log.error("Error writing export.obj file", e); } } } protected void exportMtlLine(String line) { if (exportMtl != null) { try { exportMtl.write(line); exportMtl.newLine(); } catch (IOException e) { log.error("Error writing export.mtl file", e); } } } public static String getExportDirectory() { for (int i = 1; true; i++) { String directory = String.format("%sExport-%d%c", IGraphicsExporter.exportDirectory, i, File.separatorChar); if (!new File(directory).exists()) { return directory; } } } @Override public void startExport(GeContext context, String directory) { this.context = context; try { // Prepare the export writers exportObj = new BufferedWriter(new FileWriter(String.format("%sexport.obj", directory))); exportMtl = new BufferedWriter(new FileWriter(String.format("%sexport.mtl", directory))); } catch (IOException e) { log.error("Error creating the export files", e); } exportVertexCount = 1; exportModelCount = 1; exportTextureCount = 1; exportMaterialCount = 1; exportObjLine(String.format("mtllib export.mtl")); } @Override public void endExport() { if (exportObj != null) { try { exportObj.close(); } catch (IOException e) { // Ignore error } exportObj = null; } if (exportMtl != null) { try { exportMtl.close(); } catch (IOException e) { // Ignore error } exportMtl = null; } } @Override public void startPrimitive(int numberOfVertex, int primitiveType) { if (log.isTraceEnabled()) { log.trace(String.format("Exporting Object model%d", exportModelCount)); } exportObjLine(String.format("# modelCount=%d, vertexCount=%d, textureCount=%d, normalCount=%d", exportModelCount, exportVertexCount, exportTextureCount, exportNormalCount)); } @Override public void exportVertex(VertexState originalV, VertexState transformedV) { exportObjLine(String.format(l, "v %f %f %f", transformedV.p[0], transformedV.p[1], transformedV.p[2])); if (context.vinfo.texture != 0) { exportObjLine(String.format(l, "vt %f %f", transformedV.t[0], transformedV.t[1])); } if (exportNormal && context.vinfo.normal != 0) { exportObjLine(String.format(l, "vn %f %f %f", transformedV.n[0], transformedV.n[1], transformedV.n[2])); } } @Override public void endVertex(int numberOfVertex, int primitiveType) { // Export object material exportObjLine(String.format("g model%d", exportModelCount)); exportObjLine(String.format("usemtl material%d", exportMaterialCount)); // Export faces exportObjLine(""); switch (primitiveType) { case PRIM_TRIANGLE: { boolean clockwise = context.frontFaceCw; for (int i = 0; i < numberOfVertex; i += 3) { if (clockwise) { exportFace(i + 1, i, i + 2); } else { exportFace(i, i + 1, i + 2); } } break; } case PRIM_TRIANGLE_STRIPS: { for (int i = 0; i < numberOfVertex - 2; i++) { // Front face is alternating every 2 triangle strips boolean clockwise = (i % 2) == 0; if (!context.frontFaceCw) { clockwise = !clockwise; } if (clockwise) { exportFace(i + 1, i, i + 2); } else { exportFace(i, i + 1, i + 2); } } break; } } } @Override public void endPrimitive(int numberOfVertex, int primitiveType) { exportVertexCount += numberOfVertex; if (context.vinfo.texture != 0) { exportTextureCount += numberOfVertex; } if (exportNormal && context.vinfo.normal != 0) { exportNormalCount += numberOfVertex; } exportModelCount++; exportMaterialCount++; } @Override public void exportTexture(String fileName) { // Export material definition int illum = 1; exportMtlLine(String.format("newmtl material%d", exportMaterialCount)); exportMtlLine(String.format("illum %d", illum)); exportColor(l, "Ka", context.mat_ambient); exportColor(l, "Kd", context.mat_diffuse); exportColor(l, "Ks", context.mat_specular); if (fileName != null) { exportMtlLine(String.format("map_Kd %s", fileName)); } } private void exportFace(int i1, int i2, int i3) { int p1 = i1 + exportVertexCount; int p2 = i2 + exportVertexCount; int p3 = i3 + exportVertexCount; if (exportNormal && context.vinfo.normal != 0) { int n1 = i1 + exportNormalCount; int n2 = i2 + exportNormalCount; int n3 = i3 + exportNormalCount; if (context.vinfo.texture != 0) { int t1 = i1 + exportTextureCount; int t2 = i2 + exportTextureCount; int t3 = i3 + exportTextureCount; exportObjLine(String.format("f %d/%d/%d %d/%d/%d %d/%d/%d", p1, t1, n1, p2, t2, n2, p3, t3, n3)); } else { exportObjLine(String.format("f %d//%d %d//%d %d//%d", p1, n1, p2, n2, p3, n3)); } } else { if (context.vinfo.texture != 0) { int t1 = i1 + exportTextureCount; int t2 = i2 + exportTextureCount; int t3 = i3 + exportTextureCount; exportObjLine(String.format("f %d/%d %d/%d %d/%d", p1, t1, p2, t2, p3, t3)); } else { exportObjLine(String.format("f %d %d %d", p1, p2, p3)); } } } private void exportColor(Locale l, String name, float[] color) { exportMtlLine(String.format(l, "%s %f %f %f", name, color[0], color[1], color[2])); } }