r2093 - / tools tools/ObjToMap tools/ObjToMap/objtomap
savagex at icculus.org
savagex at icculus.org
Tue Jan 9 11:27:27 EST 2007
Author: savagex
Date: 2007-01-09 11:27:27 -0500 (Tue, 09 Jan 2007)
New Revision: 2093
Added:
tools/
tools/ObjToMap/
tools/ObjToMap/objtomap/
tools/ObjToMap/objtomap/ObjToMap.java
Log:
commit a pile of ugly code to convert .obj models to .map files.
This is mostly interesting to create clip brushes for .obj models - q3map2 is too buggy to do this properly.
Added: tools/ObjToMap/objtomap/ObjToMap.java
===================================================================
--- tools/ObjToMap/objtomap/ObjToMap.java (rev 0)
+++ tools/ObjToMap/objtomap/ObjToMap.java 2007-01-09 16:27:27 UTC (rev 2093)
@@ -0,0 +1,318 @@
+/* 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 {
+
+ public static void main(String[] args) throws IOException {
+ if(args.length != 2 && args.length != 3) {
+ System.out.println("USAGE: infile.obj outfile.map [scale, default 128]");
+ System.exit(1);
+ }
+ ObjToMap m = new ObjToMap();
+
+ double scale;
+ if(args.length == 2)
+ scale = 128d;
+ else
+ scale = Double.parseDouble(args[2]);
+
+ String objfile = args[0];
+ String mapfile = args[1];
+
+ Vector points = new Vector();
+ Vector faces = new Vector();
+
+
+ m.parseOBJ(objfile, points, faces, scale);
+
+ System.out.println("Read points: " + points.size() + " Read faces: " + faces.size());
+
+ m.writeMap(mapfile, faces);
+
+ }
+
+ private void parseOBJ(String filename, Vector points, Vector faces, double scale) throws IOException {
+
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new FileReader(filename));
+ } catch(Exception e) {
+ System.err.println("Input file not found!");
+ System.exit(1);
+ }
+
+ String currentmat = "common/caulk";
+
+ while(in.ready()) {
+ String line = in.readLine();
+ line.trim();
+ 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);
+
+
+ } 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("/");
+
+ TriFace f = new TriFace();
+ f.material = currentmat;
+ f.p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
+ f.p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
+ f.p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
+
+ 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("/");
+
+ // In theory I should use a QuadFace here
+ // HOWEVER, thanks to precision issues it's better to break
+ // it down into two TriFaces.
+ // It seems the Blender .obj exporter doesn't have all 4 points
+ // lying on the same plane (precision issue).
+
+ //QuadFace f = new QuadFace();
+ /*f.p1 = points.get(Integer.parseInt(facetokens1[0]) - 1);
+ f.p2 = points.get(Integer.parseInt(facetokens2[0]) - 1);
+ f.p3 = points.get(Integer.parseInt(facetokens3[0]) - 1);
+ f.p4 = points.get(Integer.parseInt(facetokens4[0]) - 1);*/
+ //faces.add(f);
+
+ TriFace f1 = new TriFace();
+ f1.material = currentmat;
+ f1.p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
+ f1.p2 = (Vector3D)points.get(Integer.parseInt(facetokens2[0]) - 1);
+ f1.p3 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
+ faces.add(f1);
+
+ TriFace f2 = new TriFace();
+ f2.material = currentmat;
+ f2.p1 = (Vector3D)points.get(Integer.parseInt(facetokens1[0]) - 1);
+ f2.p2 = (Vector3D)points.get(Integer.parseInt(facetokens3[0]) - 1);
+ f2.p3 = (Vector3D)points.get(Integer.parseInt(facetokens4[0]) - 1);
+ faces.add(f2);
+ }
+ } else if(tokens[0].equals("usemtl")) {
+ //change material
+
+ currentmat = tokens[1];
+ }
+ }
+
+ }
+
+
+ }
+
+ private void writeMap(String filename, Vector faces) {
+ PrintWriter out = null;
+ try {
+ out = new PrintWriter(new FileWriter(filename));
+ } catch(Exception e) {
+ System.err.println("Can't open output file?!");
+ System.exit(1);
+ }
+
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("{\n\"classname\" \"worldspawn\"\n");
+
+ for(int i = 0; i < faces.size(); i++) {
+ Face f = (Face)faces.get(i);
+ String brush = f.generateBrush();
+ sb.append(brush);
+ }
+
+ sb.append("}\n");
+ out.print(sb.toString());
+ out.flush();
+ out.close();
+ }
+
+
+ private class Vector3D {
+ public double x, y, 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 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 interface Face {
+ public String generateBrush();
+
+ }
+
+ private class TriFace implements Face {
+ public Vector3D p1, p2, p3;
+ public String material;
+
+ public String generateBrush() {
+ String result = "{\n";
+
+ Vector3D vector1 = p1.substract(p2);
+ Vector3D vector2 = p1.substract(p3);
+
+ Vector3D normal = vector1.crossproduct(vector2);
+ normal.normalize();
+ normal.scale(4.0);
+
+ Vector3D p1_, p2_, p3_;
+
+ p1_ = p1.substract(normal);
+ p2_ = p2.substract(normal);
+ p3_ = p3.substract(normal);
+
+
+ // top face, apply texture here
+ result += "( " + p3.x + " " + p3.y + " " + p3.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p1.x + " " + p1.y + " " + p1.z + " ) ";
+ result += material + " 0 0 0 0.5 0.5 0 0 0\n";
+
+ // bottom face
+ result += "( " + p1_.x + " " + p1_.y + " " + p1_.z + " ) ( " + p2_.x + " " + p2_.y + " " + p2_.z + " ) ( " + p3_.x + " " + p3_.y + " " + p3_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 1
+ result += "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p1_.x + " " + p1_.y + " " + p1_.z + " ) ( " + p3_.x + " " + p3_.y + " " + p3_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 2
+ result += "( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p3.x + " " + p3.y + " " + p3.z + " ) ( " + p3_.x + " " + p3_.y + " " + p3_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 3
+ result += "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p2_.x + " " + p2_.y + " " + p2_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+
+ result += "}\n";
+
+ return result;
+ }
+
+ }
+
+ private class QuadFace implements Face {
+ public Vector3D p1, p2, p3, p4;
+ public String material;
+
+ public String generateBrush() {
+ String result = "{\n";
+
+ Vector3D vector1 = p1.substract(p2);
+ Vector3D vector2 = p1.substract(p4);
+
+ Vector3D normal = vector1.crossproduct(vector2);
+ normal.normalize();
+ normal.scale(4.0);
+
+ Vector3D p1_, p2_, p3_, p4_;
+
+ p1_ = p1.substract(normal);
+ p2_ = p2.substract(normal);
+ p3_ = p3.substract(normal);
+ p4_ = p4.substract(normal);
+
+
+ // top face, apply texture here
+ result += "( " + p3.x + " " + p3.y + " " + p3.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p1.x + " " + p1.y + " " + p1.z + " ) ";
+ result += material + " 0 0 0 0.5 0.5 0 0 0\n";
+
+ // bottom face
+ result += "( " + p1_.x + " " + p1_.y + " " + p1_.z + " ) ( " + p2_.x + " " + p2_.y + " " + p2_.z + " ) ( " + p3_.x + " " + p3_.y + " " + p3_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 1
+ result += "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p2_.x + " " + p2_.y + " " + p2_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 2
+ result += "( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p3.x + " " + p3.y + " " + p3.z + " ) ( " + p3_.x + " " + p3_.y + " " + p3_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 3
+ result += "( " + p3.x + " " + p3.y + " " + p3.z + " ) ( " + p4.x + " " + p4.y + " " + p4.z + " ) ( " + p4_.x + " " + p4_.y + " " + p4_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+ // extruded side 4
+ result += "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p1_.x + " " + p1_.y + " " + p1_.z + " ) ( " + p4_.x + " " + p4_.y + " " + p4_.z + " ) ";
+ result += "common/caulk 0 0 0 0.5 0.5 0 0 0\n";
+
+
+ result += "}\n";
+
+ return result;
+ }
+
+ }
+
+}
More information about the nexuiz-commits
mailing list