/**
* Copyright 2014
* SMEdit https://github.com/StarMade/SMEdit
* SMTools https://github.com/StarMade/SMTools
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
**/
package jo.sm.plugins.ship.imp;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import jo.sm.logic.utils.FloatUtils;
import jo.vecmath.Point2f;
import jo.vecmath.Point3f;
import jo.vecmath.ext.Hull3f;
import jo.vecmath.ext.Triangle3f;
import jo.vecmath.logic.Point3fLogic;
import jo.vecmath.logic.ext.Triangle3fLogic;
public class OBJLogic {
private static final Logger log = Logger.getLogger(OBJLogic.class.getName());
public static Hull3f readFile(String objFileName) throws IOException {
File objFile;
objFile = new File(objFileName);
Hull3f hull;
try (BufferedReader rdr = new BufferedReader(new FileReader(objFile))) {
hull = new Hull3f();
List<Point3f> verts;
verts = new ArrayList<>();
List<Point2f> textures;
textures = new ArrayList<>();
Map<String, OBJMaterial> materials;
materials = new HashMap<>();
OBJMaterial material;
material = null;
for (;;) {
String inbuf;
inbuf = rdr.readLine();
if (inbuf == null) {
break;
}
if (inbuf.startsWith("v ")) { // vertex
StringTokenizer st;
st = new StringTokenizer(inbuf, " ");
if (st.countTokens() != 4) {
log.log(Level.WARNING, "Unrecognized vertex line '" + inbuf + "'");
break;
}
st.nextToken(); // skip label
Point3f v;
v = new Point3f();
v.x = Float.parseFloat(st.nextToken());
v.y = Float.parseFloat(st.nextToken());
v.z = Float.parseFloat(st.nextToken());
verts.add(v);
} else if (inbuf.startsWith("vt ")) { // vertex texture
StringTokenizer st;
st = new StringTokenizer(inbuf, " ");
if (st.countTokens() != 3) {
log.log(Level.WARNING, "Unrecognized vertex texture line '" + inbuf + "'");
break;
}
st.nextToken(); // skip label
Point2f v;
v = new Point2f();
v.x = Float.parseFloat(st.nextToken());
v.y = Float.parseFloat(st.nextToken());
textures.add(v);
} else if (inbuf.startsWith("f ")) { // poly
List<Point3f> points;
points = new ArrayList<>();
List<Point2f> uvs;
uvs = new ArrayList<>();
StringTokenizer st;
st = new StringTokenizer(inbuf, " ");
st.nextToken(); // skip label
while (st.hasMoreTokens()) {
String v;
v = st.nextToken();
StringTokenizer st2;
st2 = new StringTokenizer(v, "/");
if (st2.hasMoreTokens()) {
int idx;
idx = Integer.parseInt(st2.nextToken());
points.add(verts.get(idx - 1));
if (st2.hasMoreTokens()) {
idx = Integer.parseInt(st2.nextToken());
uvs.add(textures.get(idx - 1));
}
}
}
for (int third = 2; third < points.size(); third++) {
Triangle3f tri;
tri = new Triangle3f();
tri.setA(points.get(0));
tri.setB(points.get(third - 1));
tri.setC(points.get(third));
if ((uvs.size() > 0) && (material != null)) {
tri.setAUV(uvs.get(0));
tri.setBUV(uvs.get(third - 1));
tri.setCUV(uvs.get(third));
ensureImage(material);
tri.setTexture(material.getMapKDImage());
}
if (!Triangle3fLogic.isDegenerate(tri)) {
hull.getTriangles().add(tri);
}
}
} else if (inbuf.startsWith("mtllib ")) {
File mtlFile;
mtlFile = new File(objFile.getParentFile(), inbuf.substring(7).trim());
readMTLFile(mtlFile, materials);
} else if (inbuf.startsWith("usemtl ")) {
material = materials.get(inbuf.substring(7).trim());
}
}
}
return hull;
}
private static void ensureImage(OBJMaterial material) {
if (material.getMapKDImage() != null) {
return;
}
if (material.getMapKD() == null) {
return;
}
try {
BufferedImage img;
img = ImageIO.read(material.getMapKD());
material.setMapKDImage(img);
} catch (IOException e) {
log.log(Level.WARNING, "Image IO failed!", e);
material.setMapKD(null); // null out so we don't retry
}
}
private static void readMTLFile(File mtlFile, Map<String, OBJMaterial> materials) {
if (!mtlFile.exists()) {
return; // gracefully degrade
}
try {
OBJMaterial mtl = null;
try (BufferedReader rdr = new BufferedReader(new FileReader(mtlFile))) {
for (;;) {
String inbuf = rdr.readLine();
if (inbuf == null) {
break;
}
if (inbuf.startsWith("newmtl ")) {
mtl = new OBJMaterial();
mtl.setName(inbuf.substring(7).trim());
materials.put(mtl.getName(), mtl);
} else if (inbuf.startsWith("Ns ")) {
if (mtl != null) {
mtl.setNS(FloatUtils.parseFloat(inbuf.substring(3).trim()));
}
} else if (inbuf.startsWith("Ni ")) {
if (mtl != null) {
mtl.setNi(FloatUtils.parseFloat(inbuf.substring(3).trim()));
}
} else if (inbuf.startsWith("D ")) {
if (mtl != null) {
mtl.setD(FloatUtils.parseFloat(inbuf.substring(2).trim()));
}
} else if (inbuf.startsWith("illum ")) {
if (mtl != null) {
mtl.setIllum(FloatUtils.parseFloat(inbuf.substring(6).trim()));
}
} else if (inbuf.startsWith("Ka ")) {
if (mtl != null) {
mtl.setKA(Point3fLogic.fromString(inbuf.substring(3).trim()));
}
} else if (inbuf.startsWith("Kd ")) {
if (mtl != null) {
mtl.setKD(Point3fLogic.fromString(inbuf.substring(3).trim()));
}
} else if (inbuf.startsWith("Ks ")) {
if (mtl != null) {
mtl.setKS(Point3fLogic.fromString(inbuf.substring(3).trim()));
}
} else if (inbuf.startsWith("map_Kd ")) {
if (mtl != null) {
File mapFile = new File(mtlFile.getParentFile(), inbuf.substring(7).trim());
if (mapFile.exists()) {
mtl.setMapKD(mapFile);
}
}
}
}
}
} catch (IOException e) {
log.log(Level.WARNING, "Buffered Reader failed!", e);
}
}
}