Skip to content

Commit 3a10d8f

Browse files
committed
ported OBJ fixes from Java mode
1 parent 531425e commit 3a10d8f

File tree

1 file changed

+109
-80
lines changed

1 file changed

+109
-80
lines changed

core/src/processing/core/PShapeOBJ.java

Lines changed: 109 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,17 @@
1-
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2-
3-
/*
4-
Part of the Processing project - http://processing.org
5-
6-
Copyright (c) 2012-16 The Processing Foundation
7-
8-
This library is free software; you can redistribute it and/or
9-
modify it under the terms of the GNU Lesser General Public
10-
License version 2.1 as published by the Free Software Foundation.
11-
12-
This library is distributed in the hope that it will be useful,
13-
but WITHOUT ANY WARRANTY; without even the implied warranty of
14-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15-
Lesser General Public License for more details.
16-
17-
You should have received a copy of the GNU Lesser General
18-
Public License along with this library; if not, write to the
19-
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20-
Boston, MA 02111-1307 USA
21-
*/
22-
231
package processing.core;
242

253
import java.io.BufferedReader;
4+
import java.io.File;
265
import java.util.ArrayList;
27-
import java.util.Hashtable;
6+
import java.util.HashMap;
7+
import java.util.Map;
288

299
/**
10+
* This class is not part of the Processing API and should not be used
11+
* directly. Instead, use loadShape() and methods like it, which will make
12+
* use of this class. Using this class directly will cause your code to break
13+
* when combined with future versions of Processing.
14+
* <p>
3015
* OBJ loading implemented using code from Saito's OBJLoader library:
3116
* http://code.google.com/p/saitoobjloader/
3217
* and OBJReader from Ahmet Kizilay
@@ -39,17 +24,21 @@ public class PShapeOBJ extends PShape {
3924
* Initializes a new OBJ Object with the given filename.
4025
*/
4126
public PShapeOBJ(PApplet parent, String filename) {
42-
this(parent, parent.createReader(filename));
27+
this(parent, parent.createReader(filename), getBasePath(parent, filename));
4328
}
4429

45-
4630
public PShapeOBJ(PApplet parent, BufferedReader reader) {
31+
this(parent, reader, "");
32+
}
33+
34+
public PShapeOBJ(PApplet parent, BufferedReader reader, String basePath) {
4735
ArrayList<OBJFace> faces = new ArrayList<OBJFace>();
4836
ArrayList<OBJMaterial> materials = new ArrayList<OBJMaterial>();
4937
ArrayList<PVector> coords = new ArrayList<PVector>();
5038
ArrayList<PVector> normals = new ArrayList<PVector>();
5139
ArrayList<PVector> texcoords = new ArrayList<PVector>();
52-
parseOBJ(parent, reader, faces, materials, coords, normals, texcoords);
40+
parseOBJ(parent, basePath, reader,
41+
faces, materials, coords, normals, texcoords);
5342

5443
// The OBJ geometry is stored with each face in a separate child shape.
5544
parent = null;
@@ -88,10 +77,10 @@ protected PShapeOBJ(OBJFace face, OBJMaterial mtl,
8877
vertexCount = face.vertIdx.size();
8978
vertices = new float[vertexCount][12];
9079
for (int j = 0; j < face.vertIdx.size(); j++){
91-
int vertIdx, normIdx;
92-
PVector vert, norms;
80+
int vertIdx, normIdx, texIdx;
81+
PVector vert, norms, tex;
9382

94-
vert = norms = null;
83+
vert = norms = tex = null;
9584

9685
vertIdx = face.vertIdx.get(j).intValue() - 1;
9786
vert = coords.get(vertIdx);
@@ -103,6 +92,13 @@ protected PShapeOBJ(OBJFace face, OBJMaterial mtl,
10392
}
10493
}
10594

95+
if (j < face.texIdx.size()) {
96+
texIdx = face.texIdx.get(j).intValue() - 1;
97+
if (-1 < texIdx) {
98+
tex = texcoords.get(texIdx);
99+
}
100+
}
101+
106102
vertices[j][X] = vert.x;
107103
vertices[j][Y] = vert.y;
108104
vertices[j][Z] = vert.z;
@@ -118,23 +114,13 @@ protected PShapeOBJ(OBJFace face, OBJMaterial mtl,
118114
vertices[j][PGraphics.NZ] = norms.z;
119115
}
120116

121-
if (mtl != null && mtl.kdMap != null) {
122-
// This face is textured.
123-
int texIdx;
124-
PVector tex = null;
125-
126-
if (j < face.texIdx.size()) {
127-
texIdx = face.texIdx.get(j).intValue() - 1;
128-
if (-1 < texIdx) {
129-
tex = texcoords.get(texIdx);
130-
}
131-
}
117+
if (tex != null) {
118+
vertices[j][PGraphics.U] = tex.x;
119+
vertices[j][PGraphics.V] = tex.y;
120+
}
132121

122+
if (mtl != null && mtl.kdMap != null) {
133123
image = mtl.kdMap;
134-
if (tex != null) {
135-
vertices[j][PGraphics.U] = tex.x;
136-
vertices[j][PGraphics.V] = tex.y;
137-
}
138124
}
139125
}
140126
}
@@ -164,14 +150,14 @@ protected void addChildren(ArrayList<OBJFace> faces,
164150
}
165151

166152

167-
static protected void parseOBJ(PApplet parent,
153+
static protected void parseOBJ(PApplet parent, String path,
168154
BufferedReader reader,
169155
ArrayList<OBJFace> faces,
170156
ArrayList<OBJMaterial> materials,
171157
ArrayList<PVector> coords,
172158
ArrayList<PVector> normals,
173159
ArrayList<PVector> texcoords) {
174-
Hashtable<String, Integer> mtlTable = new Hashtable<String, Integer>();
160+
Map<String, Integer> mtlTable = new HashMap<String, Integer>();
175161
int mtlIdxCur = -1;
176162
boolean readv, readvn, readvt;
177163
try {
@@ -235,11 +221,16 @@ static protected void parseOBJ(PApplet parent,
235221
// Object name is ignored, for now.
236222
} else if (parts[0].equals("mtllib")) {
237223
if (parts[1] != null) {
238-
BufferedReader mreader = parent.createReader(parts[1]);
224+
String fn = parts[1];
225+
if (fn.indexOf(File.separator) == -1 && !path.equals("")) {
226+
// Relative file name, adding the base path.
227+
fn = path + File.separator + fn;
228+
}
229+
BufferedReader mreader = parent.createReader(fn);
239230
if (mreader != null) {
240-
parseMTL(parent, mreader, materials, mtlTable);
231+
parseMTL(parent, fn, path, mreader, materials, mtlTable);
232+
mreader.close();
241233
}
242-
mreader.close();
243234
}
244235
} else if (parts[0].equals("g")) {
245236
gname = 1 < parts.length ? parts[1] : "";
@@ -326,10 +317,10 @@ static protected void parseOBJ(PApplet parent,
326317
}
327318

328319

329-
static protected void parseMTL(PApplet parent,
320+
static protected void parseMTL(PApplet parent, String mtlfn, String path,
330321
BufferedReader reader,
331322
ArrayList<OBJMaterial> materials,
332-
Hashtable<String, Integer> materialsHash) {
323+
Map<String, Integer> materialsHash) {
333324
try {
334325
String line;
335326
OBJMaterial currentMtl = null;
@@ -342,35 +333,53 @@ static protected void parseMTL(PApplet parent,
342333
if (parts[0].equals("newmtl")) {
343334
// Starting new material.
344335
String mtlname = parts[1];
345-
currentMtl = new OBJMaterial(mtlname);
346-
materialsHash.put(mtlname, new Integer(materials.size()));
347-
materials.add(currentMtl);
348-
} else if (parts[0].equals("map_Kd") && parts.length > 1) {
349-
// Loading texture map.
350-
String texname = parts[1];
351-
currentMtl.kdMap = parent.loadImage(texname);
352-
} else if (parts[0].equals("Ka") && parts.length > 3) {
353-
// The ambient color of the material
354-
currentMtl.ka.x = Float.valueOf(parts[1]).floatValue();
355-
currentMtl.ka.y = Float.valueOf(parts[2]).floatValue();
356-
currentMtl.ka.z = Float.valueOf(parts[3]).floatValue();
357-
} else if (parts[0].equals("Kd") && parts.length > 3) {
358-
// The diffuse color of the material
359-
currentMtl.kd.x = Float.valueOf(parts[1]).floatValue();
360-
currentMtl.kd.y = Float.valueOf(parts[2]).floatValue();
361-
currentMtl.kd.z = Float.valueOf(parts[3]).floatValue();
362-
} else if (parts[0].equals("Ks") && parts.length > 3) {
363-
// The specular color weighted by the specular coefficient
364-
currentMtl.ks.x = Float.valueOf(parts[1]).floatValue();
365-
currentMtl.ks.y = Float.valueOf(parts[2]).floatValue();
366-
currentMtl.ks.z = Float.valueOf(parts[3]).floatValue();
367-
} else if ((parts[0].equals("d") ||
368-
parts[0].equals("Tr")) && parts.length > 1) {
369-
// Reading the alpha transparency.
370-
currentMtl.d = Float.valueOf(parts[1]).floatValue();
371-
} else if (parts[0].equals("Ns") && parts.length > 1) {
372-
// The specular component of the Phong shading model
373-
currentMtl.ns = Float.valueOf(parts[1]).floatValue();
336+
currentMtl = addMaterial(mtlname, materials, materialsHash);
337+
} else {
338+
if (currentMtl == null) {
339+
currentMtl = addMaterial("material" + materials.size(),
340+
materials, materialsHash);
341+
}
342+
if (parts[0].equals("map_Kd") && parts.length > 1) {
343+
// Loading texture map.
344+
String texname = parts[1];
345+
if (texname.indexOf(File.separator) == -1 && !path.equals("")) {
346+
// Relative file name, adding the base path.
347+
texname = path + File.separator + texname;
348+
}
349+
350+
File file = new File(parent.dataPath(texname));
351+
if (file.exists()) {
352+
currentMtl.kdMap = parent.loadImage(texname);
353+
} else {
354+
System.err.println("The texture map \"" + texname + "\" " +
355+
"in the materials definition file \"" + mtlfn + "\" " +
356+
"is missing or inaccessible, make sure " +
357+
"the URL is valid or that the file has been " +
358+
"added to your sketch and is readable.");
359+
}
360+
} else if (parts[0].equals("Ka") && parts.length > 3) {
361+
// The ambient color of the material
362+
currentMtl.ka.x = Float.valueOf(parts[1]).floatValue();
363+
currentMtl.ka.y = Float.valueOf(parts[2]).floatValue();
364+
currentMtl.ka.z = Float.valueOf(parts[3]).floatValue();
365+
} else if (parts[0].equals("Kd") && parts.length > 3) {
366+
// The diffuse color of the material
367+
currentMtl.kd.x = Float.valueOf(parts[1]).floatValue();
368+
currentMtl.kd.y = Float.valueOf(parts[2]).floatValue();
369+
currentMtl.kd.z = Float.valueOf(parts[3]).floatValue();
370+
} else if (parts[0].equals("Ks") && parts.length > 3) {
371+
// The specular color weighted by the specular coefficient
372+
currentMtl.ks.x = Float.valueOf(parts[1]).floatValue();
373+
currentMtl.ks.y = Float.valueOf(parts[2]).floatValue();
374+
currentMtl.ks.z = Float.valueOf(parts[3]).floatValue();
375+
} else if ((parts[0].equals("d") ||
376+
parts[0].equals("Tr")) && parts.length > 1) {
377+
// Reading the alpha transparency.
378+
currentMtl.d = Float.valueOf(parts[1]).floatValue();
379+
} else if (parts[0].equals("Ns") && parts.length > 1) {
380+
// The specular component of the Phong shading model
381+
currentMtl.ns = Float.valueOf(parts[1]).floatValue();
382+
}
374383
}
375384
}
376385
}
@@ -379,6 +388,14 @@ static protected void parseMTL(PApplet parent,
379388
}
380389
}
381390

391+
protected static OBJMaterial addMaterial(String mtlname,
392+
ArrayList<OBJMaterial> materials,
393+
Map<String, Integer> materialsHash) {
394+
OBJMaterial currentMtl = new OBJMaterial(mtlname);
395+
materialsHash.put(mtlname, Integer.valueOf(materials.size()));
396+
materials.add(currentMtl);
397+
return currentMtl;
398+
}
382399

383400
protected static int rgbaValue(PVector color) {
384401
return 0xFF000000 | ((int)(color.x * 255) << 16) |
@@ -413,6 +430,18 @@ static protected class OBJFace {
413430
}
414431

415432

433+
static protected String getBasePath(PApplet parent, String filename) {
434+
// Obtaining the path
435+
File file = new File(parent.dataPath(filename));
436+
if (!file.exists()) {
437+
file = parent.sketchFile(filename);
438+
}
439+
String absolutePath = file.getAbsolutePath();
440+
return absolutePath.substring(0,
441+
absolutePath.lastIndexOf(File.separator));
442+
}
443+
444+
416445
// Stores a material defined in an MTL file.
417446
static protected class OBJMaterial {
418447
String name;

0 commit comments

Comments
 (0)