summaryrefslogtreecommitdiffstats
path: root/src/net/java/joglutils/model/loader/WaveFrontLoader.java
blob: 2f9c1b13f8b44223f17168dd75e2dded97743c3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/*
 * myWaveFrontLoader.java
 *
 * Created on March 16, 2008, 8:57 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package net.java.joglutils.model.loader;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import net.java.joglutils.model.ModelLoadException;
import net.java.joglutils.model.ResourceRetriever;
import net.java.joglutils.model.geometry.Bounds;
import net.java.joglutils.model.geometry.Face;
import net.java.joglutils.model.geometry.Material;
import net.java.joglutils.model.geometry.Mesh;
import net.java.joglutils.model.geometry.Model;
import net.java.joglutils.model.geometry.TexCoord;
import net.java.joglutils.model.geometry.Vec4;

/**
 *
 * @author RodgersGB
 */
public class WaveFrontLoader implements iLoader {
    public static final String VERTEX_DATA = "v ";
    public static final String NORMAL_DATA = "vn ";
    public static final String TEXTURE_DATA = "vt ";
    public static final String FACE_DATA = "f ";
    public static final String SMOOTHING_GROUP = "s ";
    public static final String GROUP = "g ";
    public static final String OBJECT = "o ";
    public static final String COMMENT = "#";
    public static final String EMPTY = "";
    
    int vertexTotal = 0;
    int textureTotal = 0;
    int normalTotal = 0;
    
    private DataInputStream dataInputStream;
    // the model
    private Model model = null;
    /** Bounds of the model */
    private Bounds bounds = new Bounds();
    /** Center of the model */
    private Vec4 center = new Vec4(0.0f, 0.0f, 0.0f);
    private String baseDir = null;
    
    /** Creates a new instance of myWaveFrontLoader */
    public WaveFrontLoader() {
    }

    int numComments = 0;
    public Model load(String path) throws ModelLoadException {
        model = new Model(path);
        Mesh mesh = null;
        
        baseDir = "";
        String tokens[] = path.split("/");
        for(int i = 0; i < tokens.length - 1; i++) {
            baseDir += tokens[i] + "/";
        }
        
        InputStream stream = null;
        try {
            stream = ResourceRetriever.getResourceAsInputStream(model.getSource());
            if (stream == null) {
                throw new ModelLoadException("Stream is null");
            }
        } catch(IOException e) {
            throw new ModelLoadException("Caught IO exception: " + e);
        }
        
        try {
            // Open a file handle and read the models data
            BufferedReader br = new BufferedReader(new InputStreamReader(stream));
            String  line = null;
            while((line = br.readLine()) != null) {
                if (lineIs(COMMENT, line)) {
                    // ignore comments
                    numComments++;
                    continue;
                }
                
                if (line.length() == 0) {
                    // igonore empty lines
                    continue;
                }
                
                if (lineIs(GROUP, line)) {
                    if (mesh == null) {
                        mesh = new Mesh();
                    }
                    
                    mesh.name = parseName(line);
                }
                
                if (lineIs(OBJECT, line)) {
                    
                }
                
                if (lineIs(VERTEX_DATA, line)) {
                    if (mesh == null)
                        mesh = new Mesh();
                    
                    mesh.vertices = getPoints(VERTEX_DATA, line, br);
                    mesh.numOfVerts = mesh.vertices.length;
                }
                
                if (lineIs(TEXTURE_DATA, line)) {
                    if (mesh == null)
                        mesh = new Mesh();
                    
                    mesh.texCoords = getTexCoords(TEXTURE_DATA, line, br);
                    mesh.hasTexture = true;
                    mesh.numTexCoords = mesh.texCoords.length;
                }
                
                if (lineIs(NORMAL_DATA, line)) {
                    if (mesh == null)
                        mesh = new Mesh();
                    
                    mesh.normals = getPoints(NORMAL_DATA, line, br);
                }
                
                if (lineIs(FACE_DATA, line)) {
                    if (mesh == null)
                        mesh = new Mesh();
                    
                    mesh.faces = getFaces(line, mesh, br);
                    mesh.numOfFaces = mesh.faces.length;
                    
                    model.addMesh(mesh);
                    mesh = new Mesh();
                }
                
                if (lineIs("mtllib ", line)){
                    processMaterialLib(line);
                }
                
                if (lineIs("usemtl ", line)) {
                    processMaterialType(line, mesh);
                }
            }
        }
        catch (IOException e) {
            throw new ModelLoadException("Failed to find or read OBJ: " + stream);
        }
        model.addMesh(mesh);
        mesh = null;
        
        System.out.println(this.bounds.toString());
        model.setBounds(this.bounds);
        model.setCenterPoint(this.center);
        
        return model;
    }
    
    private boolean lineIs(String type, String line) {
        return line.startsWith(type);
    }
    
    private Vec4[] getPoints(String prefix, String currLine, BufferedReader br) throws IOException {
        Vector<Vec4> points = new Vector<Vec4>();
        boolean isVertices = prefix.equals(VERTEX_DATA);
        
        // we've already read in the first line (currLine)
        // so go ahead and parse it
        points.add(parsePoint(currLine));
        
        // parse through the rest of the points
        String line = null;
        while((line = br.readLine()) != null) {
            if (!lineIs(prefix, line))
                break;
            
            Vec4 point = parsePoint(line);
            if (isVertices) {
                // Calculate the bounds for the entire model
                bounds.calc(point);
            }
            points.add(point);
        }
        
        if (isVertices) {
            // Calculate the center of the model
            center.x = 0.5f * (bounds.max.x + bounds.min.x);
            center.y = 0.5f * (bounds.max.y + bounds.min.y);
            center.z = 0.5f * (bounds.max.z + bounds.min.z);
        }
        
        // return the points
        Vec4 values[] = new Vec4[points.size()];
        return points.toArray(values);
    }
    
    private TexCoord[] getTexCoords(String prefix, String currLine, BufferedReader br) throws IOException {
        Vector<TexCoord> texCoords = new Vector<TexCoord>();
        
        String s[] = currLine.split("\\s+");
        TexCoord texCoord = new TexCoord();
        texCoord.u = Float.parseFloat(s[1]);
        texCoord.v = Float.parseFloat(s[2]);
            
        texCoords.add(texCoord);
        
        // parse through the rest of the points
        String line = null;
        while((line = br.readLine()) != null) {
            if (!lineIs(prefix, line))
                break;
            
            s = line.split("\\s+");
        
            texCoord = new TexCoord();
            texCoord.u = Float.parseFloat(s[1]);
            texCoord.v = Float.parseFloat(s[2]);
            
            texCoords.add(texCoord);
        }
        
        // return the texture coordinates
        TexCoord values[] = new TexCoord[texCoords.size()];
        return texCoords.toArray(values);
    }
    
    private Face[] getFaces(String currLine, Mesh mesh, BufferedReader br) throws IOException {
        Vector<Face> faces = new Vector<Face>();
        
        faces.add(parseFace(currLine));
        
        // parse through the rest of the faces
        String line = null;
        while((line = br.readLine()) != null) {
            if (lineIs(SMOOTHING_GROUP, line)) {
                continue;
            }
            else if (lineIs("usemtl ", line)) {
                processMaterialType(line, mesh);
            }
            
            else if (lineIs(FACE_DATA, line)) {
                faces.add(parseFace(line));
            }
            
            else
                break;
        }        
        
        // return the faces
        Face values[] = new Face[faces.size()];
        return faces.toArray(values);
    }
    
    private Face parseFace(String line) {
        String s[] = line.split("\\s+");
        if (line.contains("//")) { // Pattern is present if obj has no texture
            for (int loop=1; loop < s.length; loop++) {
                s[loop] = s[loop].replaceAll("//","/-1/"); //insert -1 for missing vt data
            }
        }
        
        int vdata[] = new int[s.length-1];
        int vtdata[] = new int[s.length-1];
        int vndata[] = new int[s.length-1];
        Face face = new Face(s.length - 1);
        
        for (int loop = 1; loop < s.length; loop++) {
            String s1 = s[loop];
            String[] temp = s1.split("/");
            
            if (temp.length > 0) { // we have vertex data
                if (Integer.valueOf(temp[0]) < 0) {
                    //TODO handle relative vertex data
                }
                else {
                    face.vertIndex[loop-1] = Integer.valueOf(temp[0]) - 1 - this.vertexTotal;
                    //System.out.println("found vertex index: " + face.vertIndex[loop-1]);
                }
            }
            
            if (temp.length > 1) { // we have texture data
                if(Integer.valueOf(temp[1]) < 0) {
                    face.coordIndex[loop - 1] = 0;
                }
                else {
                    face.coordIndex[loop - 1] = Integer.valueOf(temp[1]) - 1 - this.textureTotal;
                    //System.out.println("found texture index: " + face.coordIndex[loop-1]);
                }
            }
            
            if (temp.length > 2) { // we have normal data
                face.normalIndex[loop-1] = Integer.valueOf(temp[2]) - 1 - this.normalTotal;
                //System.out.println("found normal index: " + face.normalIndex[loop-1]);
            }
        }
        
        return face;
    }
    
    private Vec4 parsePoint(String line) {
        Vec4 point = new Vec4();
        
        final String s[] = line.split("\\s+");
        
        point.x = Float.parseFloat(s[1]);
        point.y = Float.parseFloat(s[2]);
        point.z = Float.parseFloat(s[3]);
        
        return point;
    }
    
    private String parseName(String line) {
        String name;
        
        final String s[] = line.split("\\s+");
        
        name = s[1];
        
        return name;
    }
    
    private void processMaterialLib(String mtlData) {
        String s[] = mtlData.split("\\s+");
        
        Material mat = new Material();
        InputStream stream = null;
        try {
            stream = ResourceRetriever.getResourceAsInputStream(baseDir + s[1]);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        if(stream == null) {
            try {
                stream = new FileInputStream(baseDir + s[1]);
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
                return;
            }
        }
        loadMaterialFile(stream);
    }
    
    private void processMaterialType(String line, Mesh mesh) {
        String s[] = line.split("\\s+");
        
        int materialID = -1;
        boolean hasTexture = false;
        
        for(int i = 0; i < model.getNumberOfMaterials(); i++){
            Material mat = model.getMaterial(i);
            
            if(mat.strName.equals(s[1])){
                materialID = i;
                if(mat.strFile != null)
                    hasTexture = true;
                else
                    hasTexture = false;
                break;
            }
        }
        
        if(materialID != -1)
            mesh.materialID = materialID;
    }
    
    public Material loadMaterialFile(InputStream stream) {
        Material mat = null;
        int texId = 0;
        
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(stream));
            String line;
            
            while((line = br.readLine()) != null){
                
                String parts[] = line.trim().split("\\s+");
                
                if(parts[0].equals("newmtl")){
                    if(mat != null)
                        model.addMaterial(mat);
                    
                    mat = new Material();
                    mat.strName = parts[1];
                    mat.textureId = texId++;
                    
                } else if(parts[0].equals("Ks"))
                    mat.specularColor = parseColor(line);
                
                else if(parts[0].equals("Ns")) {
                    if (parts.length > 1)
                        mat.shininess = Float.valueOf(parts[1]);
                }
                else if(parts[0].equals("d"))
                    ;
                else if(parts[0].equals("illum"))
                    ;
                else if(parts[0].equals("Ka"))
                    mat.ambientColor = parseColor(line);
                else if(parts[0].equals("Kd"))
                    mat.diffuseColor = parseColor(line);
                else if(parts[0].equals("map_Kd")) {
                    if (parts.length > 1)
                        mat.strFile = /*baseDir + */parts[1];
                }
                
                else if(parts[0].equals("map_Ka")) {
                    if (parts.length > 1)
                        mat.strFile = /*baseDir + */parts[1];
                }
            }
            
            br.close();
            model.addMaterial(mat);
            
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return mat;
    }
    
    private Color parseColor(String line) {
        String parts[] = line.trim().split("\\s+");
        
        Color color = new Color(Float.valueOf(parts[1]),
                Float.valueOf(parts[2]),Float.valueOf(parts[3]));
        
        return color;
    }
    
    public static void main(String[] args) {
        WaveFrontLoader loader = new WaveFrontLoader();
        try {
            loader.load("C:\\Documents and Settings\\RodgersGB\\My Documents\\Projects\\JOGLUTILS\\src\\net\\java\\joglutils\\examples\\models\\obj\\penguin.obj");
        } catch (ModelLoadException ex) {
            ex.printStackTrace();
        }
    }
}