xonotic/misc/tools/ObjToMap/objtomap/ObjToMap.java
2010-03-18 14:22:15 +01:00

319 lines
10 KiB
Java

/* This code is *ugly*. It may blind you.
*
* I hereby pollute the software world by putting this into public domain.
*
* SavageX
*/
package objtomap;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Vector;
public class ObjToMap {
private Vector points, faces;
private Configuration config;
public ObjToMap(Configuration c) {
config = c;
}
public void parseOBJ() throws IOException {
points = new Vector();
faces = new Vector();
double scale = config.scale;
config.simpleterrain = true;
config.minz = Double.MAX_VALUE;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(config.objfile));
} catch(Exception e) {
System.err.println("Input file not found!");
return;
}
String currentmat = "common/caulk";
while(in.ready()) {
String line = in.readLine();
line.trim();
line = line.replaceAll(" ", " ");
String[] tokens = line.split(" ");
if(tokens.length > 1) {
if(tokens[0].equals("v")) {
// vertices
Vector3D p = new Vector3D();
p.x = Double.parseDouble(tokens[3]) * scale;
p.y = Double.parseDouble(tokens[1]) * scale;
p.z = Double.parseDouble(tokens[2]) * scale;
points.add(p);
if(p.z < config.minz)
config.minz = p.z;
} else if(tokens[0].equals("f")) {
// faces
if(tokens.length == 4) {
// TriFace
String[] facetokens1 = tokens[1].split("/");
String[] facetokens2 = tokens[2].split("/");
String[] facetokens3 = tokens[3].split("/");
Face f = new Face();
f.material = currentmat;
Vector3D p1, p2, p3;
p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
f.setPoints(p1, p2, p3);
if(f.getXYangle() >= 90.0)
config.simpleterrain = false;
faces.add(f);
} else if(tokens.length == 5) {
// QuadFace
String[] facetokens1 = tokens[1].split("/");
String[] facetokens2 = tokens[2].split("/");
String[] facetokens3 = tokens[3].split("/");
String[] facetokens4 = tokens[4].split("/");
Vector3D p1, p2, p3;
Face f1 = new Face();
f1.material = currentmat;
p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
f1.setPoints(p1, p2, p3);
if(f1.getXYangle() >= 90.0)
config.simpleterrain = false;
faces.add(f1);
Face f2 = new Face();
f2.material = currentmat;
p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
p2 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
p3 = (Vector3D)points.get(Integer.parseInt(facetokens4[0]) - 1);
f2.setPoints(p1, p2, p3);
if(f2.getXYangle() >= 90.0)
config.simpleterrain = false;
faces.add(f2);
}
} else if(tokens[0].equals("usemtl")) {
//change material
currentmat = tokens[1];
}
}
}
System.out.println("Read points: " + points.size() + " Read faces: " + faces.size());
}
public void writeMap() {
if(faces == null) return;
PrintWriter out = null;
try {
out = new PrintWriter(new FileWriter(config.mapfile));
} catch(Exception e) {
System.err.println("Can't open output file?!");
return;
}
out.print("{\n\"classname\" \"worldspawn\"\n");
for(int i = 0; i < faces.size(); i++) {
Face f = (Face)faces.get(i);
out.print(f.generateBrush());
}
out.print("}\n");
out.flush();
out.close();
}
private class Vector3D {
public double x, y, z;
public Vector3D() {
this(0.0, 0.0, 0.0);
}
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3D crossproduct(Vector3D p1) {
Vector3D result = new Vector3D();
result.x = this.y * p1.z - this.z * p1.y;
result.y = this.z * p1.x - this.x * p1.z;
result.z = this.x * p1.y - this.y * p1.x;
return result;
}
public double dotproduct(Vector3D p1) {
return this.x * p1.x + this.y * p1.y + this.z * p1.z;
}
public Vector3D substract(Vector3D p1) {
Vector3D result = new Vector3D();
result.x = this.x - p1.x;
result.y = this.y - p1.y;
result.z = this.z - p1.z;
return result;
}
public void scale(double factor) {
x *= factor;
y *= factor;
z *= factor;
}
public double length() {
return Math.sqrt((x*x) + (y*y) + (z*z));
}
public void normalize() {
double l = length();
x /= l;
y /= l;
z /= l;
}
}
private class Face {
private Vector3D p1, p2, p3, normal;
private double angle_xy = 0.0;
public String material;
public void setPoints(Vector3D p1, Vector3D p2, Vector3D p3) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
computeNormal();
computeXYangle();
}
public double getXYangle() {
return angle_xy;
}
private void computeNormal() {
Vector3D vector1 = p1.substract(p2);
Vector3D vector2 = p1.substract(p3);
normal = vector1.crossproduct(vector2);
normal.normalize();
}
private void computeXYangle() {
Vector3D normal_xy = new Vector3D(0.0, 0.0, 1.0);
angle_xy = Math.acos(normal.dotproduct(normal_xy)) / (2 * Math.PI) * 360.0;
}
public String generateBrush() {
String result = "{\n";
// this looks like a floor, extrude along the z-axis
if(angle_xy < 70.0) {
normal.x = 0.0;
normal.y = 0.0;
normal.z = 1.0;
}
normal.scale(config.brush_thickness);
Vector3D p1_, p2_, p3_;
if(!config.simpleterrain) {
p1_ = p1.substract(normal);
p2_ = p2.substract(normal);
p3_ = p3.substract(normal);
} else {
double min = config.minz;
min -= 16.0;
p1_ = new Vector3D(p1.x, p1.y, min);
p2_ = new Vector3D(p2.x, p2.y, min);
p3_ = new Vector3D(p3.x, p3.y, min);
}
String mat = material;
if(config.autotexturing.size() > 0) {
double maxangle = -1.0;
for(int i = 0; i < config.autotexturing.size(); i++) {
AutoTexturingEntry e = (AutoTexturingEntry)config.autotexturing.get(i);
if(angle_xy >= e.angle && e.angle > maxangle) {
mat = e.texturename;
maxangle = e.angle;
}
}
}
// top face, apply texture here
result += getMapPlaneString(p3, p2, p1, mat);
// bottom face
result += getMapPlaneString(p1_, p2_, p3_, "common/caulk");
// extruded side 1
result += getMapPlaneString(p1, p1_, p3_, "common/caulk");
// extruded side 2
result += getMapPlaneString(p2, p3, p3_, "common/caulk");
// extruded side 3
result += getMapPlaneString(p1, p2, p2_, "common/caulk");
result += "}\n";
return result;
}
private String getMapPlaneString(Vector3D p1, Vector3D p2, Vector3D p3, String material) {
int flag;
if(config.detail)
flag = 134217728;
else
flag = 0;
return "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p3.x + " " + p3.y + " " + p3.z + " ) " + material + " 0 0 0 " + config.texture_scale + " " + config.texture_scale + " " + flag + " 0 0\n";
}
}
}