1 /* This code is *ugly*. It may blind you.
3 * I hereby pollute the software world by putting this into public domain.
11 import java.io.BufferedReader;
12 import java.io.FileReader;
13 import java.io.FileWriter;
14 import java.io.IOException;
15 import java.io.PrintWriter;
16 import java.util.Vector;
18 public class ObjToMap {
20 private Vector points, faces;
21 private Configuration config;
23 public ObjToMap(Configuration c) {
27 public void parseOBJ() throws IOException {
29 points = new Vector();
31 double scale = config.scale;
32 config.simpleterrain = true;
33 config.minz = Double.MAX_VALUE;
36 BufferedReader in = null;
38 in = new BufferedReader(new FileReader(config.objfile));
39 } catch(Exception e) {
40 System.err.println("Input file not found!");
44 String currentmat = "common/caulk";
47 String line = in.readLine();
49 line = line.replaceAll(" ", " ");
50 String[] tokens = line.split(" ");
51 if(tokens.length > 1) {
53 if(tokens[0].equals("v")) {
55 Vector3D p = new Vector3D();
56 p.x = Double.parseDouble(tokens[3]) * scale;
57 p.y = Double.parseDouble(tokens[1]) * scale;
58 p.z = Double.parseDouble(tokens[2]) * scale;
64 } else if(tokens[0].equals("f")) {
67 if(tokens.length == 4) {
70 String[] facetokens1 = tokens[1].split("/");
71 String[] facetokens2 = tokens[2].split("/");
72 String[] facetokens3 = tokens[3].split("/");
75 f.material = currentmat;
77 p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
78 p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
79 p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
81 f.setPoints(p1, p2, p3);
82 if(f.getXYangle() >= 90.0)
83 config.simpleterrain = false;
87 } else if(tokens.length == 5) {
89 String[] facetokens1 = tokens[1].split("/");
90 String[] facetokens2 = tokens[2].split("/");
91 String[] facetokens3 = tokens[3].split("/");
92 String[] facetokens4 = tokens[4].split("/");
97 f1.material = currentmat;
98 p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
99 p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
100 p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
101 f1.setPoints(p1, p2, p3);
103 if(f1.getXYangle() >= 90.0)
104 config.simpleterrain = false;
108 Face f2 = new Face();
109 f2.material = currentmat;
110 p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
111 p2 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
112 p3 = (Vector3D)points.get(Integer.parseInt(facetokens4[0]) - 1);
113 f2.setPoints(p1, p2, p3);
115 if(f2.getXYangle() >= 90.0)
116 config.simpleterrain = false;
120 } else if(tokens[0].equals("usemtl")) {
123 currentmat = tokens[1];
129 System.out.println("Read points: " + points.size() + " Read faces: " + faces.size());
133 public void writeMap() {
134 if(faces == null) return;
136 PrintWriter out = null;
138 out = new PrintWriter(new FileWriter(config.mapfile));
139 } catch(Exception e) {
140 System.err.println("Can't open output file?!");
144 out.print("{\n\"classname\" \"worldspawn\"\n");
146 for(int i = 0; i < faces.size(); i++) {
147 Face f = (Face)faces.get(i);
148 out.print(f.generateBrush());
157 private class Vector3D {
158 public double x, y, z;
164 public Vector3D(double x, double y, double z) {
170 public Vector3D crossproduct(Vector3D p1) {
171 Vector3D result = new Vector3D();
173 result.x = this.y * p1.z - this.z * p1.y;
174 result.y = this.z * p1.x - this.x * p1.z;
175 result.z = this.x * p1.y - this.y * p1.x;
180 public double dotproduct(Vector3D p1) {
181 return this.x * p1.x + this.y * p1.y + this.z * p1.z;
184 public Vector3D substract(Vector3D p1) {
185 Vector3D result = new Vector3D();
187 result.x = this.x - p1.x;
188 result.y = this.y - p1.y;
189 result.z = this.z - p1.z;
194 public void scale(double factor) {
200 public double length() {
201 return Math.sqrt((x*x) + (y*y) + (z*z));
204 public void normalize() {
216 private Vector3D p1, p2, p3, normal;
217 private double angle_xy = 0.0;
218 public String material;
220 public void setPoints(Vector3D p1, Vector3D p2, Vector3D p3) {
229 public double getXYangle() {
233 private void computeNormal() {
234 Vector3D vector1 = p1.substract(p2);
235 Vector3D vector2 = p1.substract(p3);
237 normal = vector1.crossproduct(vector2);
241 private void computeXYangle() {
242 Vector3D normal_xy = new Vector3D(0.0, 0.0, 1.0);
243 angle_xy = Math.acos(normal.dotproduct(normal_xy)) / (2 * Math.PI) * 360.0;
246 public String generateBrush() {
247 String result = "{\n";
249 // this looks like a floor, extrude along the z-axis
250 if(angle_xy < 70.0) {
256 normal.scale(config.brush_thickness);
258 Vector3D p1_, p2_, p3_;
260 if(!config.simpleterrain) {
261 p1_ = p1.substract(normal);
262 p2_ = p2.substract(normal);
263 p3_ = p3.substract(normal);
265 double min = config.minz;
267 p1_ = new Vector3D(p1.x, p1.y, min);
268 p2_ = new Vector3D(p2.x, p2.y, min);
269 p3_ = new Vector3D(p3.x, p3.y, min);
272 String mat = material;
274 if(config.autotexturing.size() > 0) {
275 double maxangle = -1.0;
276 for(int i = 0; i < config.autotexturing.size(); i++) {
277 AutoTexturingEntry e = (AutoTexturingEntry)config.autotexturing.get(i);
278 if(angle_xy >= e.angle && e.angle > maxangle) {
285 // top face, apply texture here
286 result += getMapPlaneString(p3, p2, p1, mat);
289 result += getMapPlaneString(p1_, p2_, p3_, "common/caulk");
292 result += getMapPlaneString(p1, p1_, p3_, "common/caulk");
295 result += getMapPlaneString(p2, p3, p3_, "common/caulk");
298 result += getMapPlaneString(p1, p2, p2_, "common/caulk");
306 private String getMapPlaneString(Vector3D p1, Vector3D p2, Vector3D p3, String material) {
313 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";