Created
August 14, 2012 18:15
-
-
Save zao/3351414 to your computer and use it in GitHub Desktop.
OBJ loading
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* To change this template, choose Tools | Templates | |
* and open the template in the editor. | |
*/ | |
package se.zao.obj; | |
/** | |
* | |
* @author Lars | |
*/ | |
public class IndexedMesh { | |
public float[] positions; | |
public float[] texcoords; | |
public float[] normals; | |
public short[] indices; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* To change this template, choose Tools | Templates | |
* and open the template in the editor. | |
*/ | |
package se.zao.obj; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.StringReader; | |
import java.util.ArrayList; | |
import java.util.Dictionary; | |
import java.util.HashMap; | |
import java.util.Hashtable; | |
import java.util.List; | |
import java.util.Map; | |
import sun.rmi.runtime.Log; | |
/** | |
* | |
* @author Lars | |
*/ | |
public class ObjLoader { | |
static class Vec3 | |
{ | |
float x, y, z; | |
Vec3() | |
{ this(0.0f, 0.0f, 0.0f); } | |
Vec3(float x, float y, float z) | |
{ this.x = x; this.y = y; this.z = z; } | |
void addTo(List<Float> list) | |
{ | |
list.add(x); | |
list.add(y); | |
list.add(z); | |
} | |
} | |
static class Vec2 | |
{ | |
float x, y; | |
Vec2() | |
{ this(0.0f, 0.0f); } | |
Vec2(float x, float y) | |
{ this.x = x; this.y = y;} | |
void addTo(List<Float> list) | |
{ | |
list.add(x); | |
list.add(y); | |
} | |
} | |
static class Triad | |
{ | |
int positionIndex = 0, texcoordIndex = 0, normalIndex = 0; | |
boolean equals(Triad rhs) | |
{ | |
return positionIndex == rhs.positionIndex && | |
texcoordIndex == rhs.texcoordIndex && | |
normalIndex == rhs.normalIndex; | |
} | |
} | |
static class RawFace | |
{ | |
Triad[] vertices; | |
} | |
static class Triangle | |
{ | |
Triad a, b, c; | |
Triangle(Triad a, Triad b, Triad c) | |
{ this.a = a; this.b = b; this.c = c; } | |
} | |
static class GatherStage | |
{ | |
List<Vec3> positions = new ArrayList<>(); | |
List<Vec2> texcoords = new ArrayList<>(); | |
List<Vec3> normals = new ArrayList<>(); | |
List<Triangle> triangles = new ArrayList<>(); | |
} | |
static class IndexAssembleStage | |
{ | |
List<Float> positionBuffer = new ArrayList<>(); | |
List<Float> texcoordBuffer = new ArrayList<>(); | |
List<Float> normalBuffer = new ArrayList<>(); | |
List<Short> indexBuffer = new ArrayList<>(); | |
} | |
public static IndexedMesh loadIndexed(String objData, boolean deduplicate) | |
{ | |
GatherStage rawData = loadRaw(objData); | |
Map<Triad, Short> indexLookup = new HashMap<>(); | |
IndexAssembleStage bakedData = new IndexAssembleStage(); | |
for (Triangle tri : rawData.triangles) | |
{ | |
Triad[] triads = new Triad[]{tri.a, tri.b, tri.c}; | |
for (Triad t : triads) | |
{ | |
Short idx = null; | |
if (deduplicate) { | |
idx = indexLookup.get(t); | |
} | |
if (idx == null) { | |
idx = (short)bakedData.indexBuffer.size(); | |
Vec3 vp = rawData.positions.get(t.positionIndex-1); | |
Vec2 vt = rawData.texcoords.get(t.texcoordIndex-1); | |
Vec3 vn = rawData.normals.get(t.normalIndex-1); | |
vp.addTo(bakedData.positionBuffer); | |
vt.addTo(bakedData.texcoordBuffer); | |
vn.addTo(bakedData.normalBuffer); | |
if (deduplicate) { | |
indexLookup.put(t, idx); | |
} | |
} | |
bakedData.indexBuffer.add(idx); | |
} | |
} | |
IndexedMesh mesh = new IndexedMesh(); | |
mesh.positions = new float[bakedData.positionBuffer.size()]; | |
mesh.texcoords = new float[bakedData.texcoordBuffer.size()]; | |
mesh.normals = new float[bakedData.normalBuffer.size()]; | |
mesh.indices = new short[bakedData.indexBuffer.size()]; | |
for (int i = 0; i < bakedData.positionBuffer.size(); ++i) { | |
mesh.positions[i] = bakedData.positionBuffer.get(i); | |
} | |
for (int i = 0; i < bakedData.texcoordBuffer.size(); ++i) { | |
mesh.texcoords[i] = bakedData.texcoordBuffer.get(i); | |
} | |
for (int i = 0; i < bakedData.normalBuffer.size(); ++i) { | |
mesh.normals[i] = bakedData.normalBuffer.get(i); | |
} | |
for (int i = 0; i < bakedData.indexBuffer.size(); ++i) { | |
mesh.indices[i] = bakedData.indexBuffer.get(i); | |
} | |
return mesh; | |
} | |
static GatherStage loadRaw(String objData) | |
{ | |
GatherStage data = new GatherStage(); | |
BufferedReader r = new BufferedReader(new StringReader(objData)); | |
try | |
{ | |
for (String line = r.readLine(); line != null; line = r.readLine()) | |
{ | |
String[] tokens = line.split("[#]"); | |
if (tokens.length == 0) { | |
continue; | |
} | |
tokens = tokens[0].split("[ \t]+"); | |
if (tokens.length < 2) | |
{ | |
continue; | |
} | |
String cmd = tokens[0]; | |
switch (cmd) | |
{ | |
case "v": | |
{ | |
assert tokens.length == 4; | |
data.positions.add(new Vec3( | |
Float.parseFloat(tokens[1]), | |
Float.parseFloat(tokens[2]), | |
Float.parseFloat(tokens[3]))); | |
break; | |
} | |
case "vt": | |
{ | |
assert tokens.length >= 3; | |
data.texcoords.add(new Vec2( | |
Float.parseFloat(tokens[1]), | |
Float.parseFloat(tokens[2]))); | |
break; | |
} | |
case "vn": | |
{ | |
assert tokens.length == 4; | |
data.normals.add(new Vec3( | |
Float.parseFloat(tokens[1]), | |
Float.parseFloat(tokens[2]), | |
Float.parseFloat(tokens[3]))); | |
break; | |
} | |
case "f": | |
{ | |
assert tokens.length >= 4; | |
int numVertices = tokens.length - 1; | |
RawFace face = new RawFace(); | |
face.vertices = new Triad[numVertices]; | |
for (int i = 0; i < numVertices; ++i) | |
{ | |
String[] parts = tokens[i+1].split("[/]", -1); | |
Triad triad = new Triad(); | |
if (parts.length >= 1) { | |
triad.positionIndex = Short.parseShort(parts[0]); | |
} | |
if (parts.length >= 2) { | |
triad.texcoordIndex = Short.parseShort(parts[1]); | |
} | |
if (parts.length >= 3) { | |
triad.normalIndex = Short.parseShort(parts[2]); | |
} | |
if (triad.positionIndex <= 0 || triad.texcoordIndex <= 0 || triad.normalIndex <= 0) { | |
// not bothering to handle reverse indexing | |
return null; | |
} | |
face.vertices[i] = triad; | |
} | |
Triad v0 = face.vertices[0], vPrev = face.vertices[1]; | |
for (int i = 2; i < face.vertices.length; ++i) | |
{ | |
Triad vCurrent = face.vertices[i]; | |
Triangle tri = new Triangle(v0, vPrev, vCurrent); | |
vPrev = vCurrent; | |
data.triangles.add(tri); | |
} | |
break; | |
} | |
} | |
} | |
} | |
catch (IOException ex) | |
{ | |
System.err.println(ex); | |
} | |
return data; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment