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