Skip to content

Commit

Permalink
refactor regexes and correct line buffering bug
Browse files Browse the repository at this point in the history
  • Loading branch information
rahwang committed Jun 28, 2017
1 parent 2706b95 commit f526e9b
Showing 1 changed file with 36 additions and 101 deletions.
137 changes: 36 additions & 101 deletions lib/loadObj.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,8 @@ function Primitive() {
var vertexPattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // v float float float
var normalPattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vn float float float
var uvPattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/; // vt float float
var facePattern1 = /f(\s+-?\d+\/?\/?){3,}/; // f vertex vertex vertex ...
var facePattern2 = /f(\s+-?\d+\/-?\d+){3,}/; // f vertex/uv vertex/uv vertex/uv ...
var facePattern3 = /f(\s+-?\d+\/-?\d+\/-?\d+){3,}/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var facePattern4 = /f(\s+-?\d+\/\/-?\d+){3,}/; // f vertex//normal vertex//normal vertex//normal ...
var facePattern = /(-?\d+)\/?(-?\d*)\/?(-?\d*)/g; // for any face format "f v", "f v/v", "f v//v", "f v/v/v"

var faceSpacePattern = /(f?\s+)|(\s+\/)|(\s*\\)/g;
var faceSpaceOrSlashPattern = /(f?\s+)|(\/+\s*)|(\s+\/)|(\s*\\)/g;
var scratchCartesian = new Cartesian3();

/**
Expand Down Expand Up @@ -102,7 +97,16 @@ function loadObj(objPath, options) {
var mtlPaths = [];

// Buffers for face data that spans multiple lines
var lineBuffer = "";
var lineBuffer = '';

// Used for parsing face data
var faceVertices = []; // names of vertices for caching
var facePositions = []; // indices into position array
var faceUvs = []; // indices into uv array
var faceNormals = []; // indices into normal array

var positions3D = [];
var vertexIndices = [];

function getName(name) {
return (name === '' ? undefined : name);
Expand Down Expand Up @@ -247,7 +251,7 @@ function loadObj(objPath, options) {

function createVertex(p, u, n) {
// Positions
if (defined(p)) {
if (p.length > 0) {
var pi = getOffset(p, positions, 3);
var px = positions.get(pi + 0);
var py = positions.get(pi + 1);
Expand All @@ -258,7 +262,7 @@ function loadObj(objPath, options) {
}

// Normals
if (defined(n)) {
if (n.length > 0) {
var ni = getOffset(n, normals, 3);
var nx = normals.get(ni + 0);
var ny = normals.get(ni + 1);
Expand All @@ -269,7 +273,7 @@ function loadObj(objPath, options) {
}

// UVs
if (defined(u)) {
if (u.length > 0) {
var ui = getOffset(u, uvs, 2);
var ux = uvs.get(ui + 0);
var uy = uvs.get(ui + 1);
Expand Down Expand Up @@ -363,48 +367,28 @@ function loadObj(objPath, options) {

var scratchNormal = new Cartesian3();
function addFace(vertices, positions, uvs, normals) {

var u1, u2, u3, n1, n2, n3;
var isWindingCorrect = true;
var faceNormal;

// If normals are defined, find a face normal to use in winding order sanitization.
// If no face normal, we have to assume the winding is correct.
if (normals) {
if (normals[0].length > 0) {
faceNormal = get3DNormal(normals[0], scratchNormal);
isWindingCorrect = checkWindingCorrect(positions[0], positions[1], positions[2], faceNormal);
}

if (vertices.length === 3) {

if (uvs) {
u1 = uvs[0];
u2 = uvs[1];
u3 = uvs[2];
}

if (normals) {
n1 = normals[0];
n2 = normals[1];
n3 = normals[2];
}

var index1 = addVertex(vertices[0], positions[0], u1, n1);
var index2 = addVertex(vertices[1], positions[1], u2, n2);
var index3 = addVertex(vertices[2], positions[2], u3, n3);

var index1 = addVertex(vertices[0], positions[0], uvs[0], normals[0]);
var index2 = addVertex(vertices[1], positions[1], uvs[1], normals[1]);
var index3 = addVertex(vertices[2], positions[2], uvs[2], normals[2]);
addTriangle(index1, index2, index3, isWindingCorrect);
} else { // Triangulate if the face is not a triangle
var positions3D = [];
var vertexIndices = [];
positions3D.length = 0;
vertexIndices.length = 0;

var i;
for (i = 0; i < vertices.length; ++i) {

var u = (defined(uvs)) ? uvs[i] : undefined;
var n = (defined(normals)) ? normals[i] : undefined;

var index = addVertex(vertices[i], positions[i], u, n);
var index = addVertex(vertices[i], positions[i], uvs[i], normals[i]);
vertexIndices.push(index);

// Collect the vertex positions as 3D points
Expand Down Expand Up @@ -434,58 +418,6 @@ function loadObj(objPath, options) {
}
}

function trimEmpty(entry) { return entry.trim() !== ''; }

// Parse a line of face data.
// Because face data can span multiple lines, attribute data is buffered in parallel lists
// faceVertices : names of a vertices for caching
// facePosition : indices into position array
// faceUvs : indices into uv array
// faceNormals : indices into normal array
function parseFaceLine(line, hasUvs, hasNormals) {

// get vertex data (attributes '/' separated)
var faceVertices = line.replace(faceSpacePattern, ' ').split(' ').filter(trimEmpty);
// get all vertex attributes for this line
var faceAttributes = line.replace(faceSpaceOrSlashPattern, ' ').split(' ').filter(trimEmpty);

var facePositions = [];
var faceUvs = [];
var faceNormals = [];

var i;
if (hasUvs && hasNormals) {
for (i=0; i <= faceAttributes.length - 3; i += 3)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
faceNormals.push(faceAttributes[i+2]);
}
} else if (hasUvs) {
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
}
faceNormals = undefined;
} else if (hasNormals) {
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceNormals.push(faceAttributes[i+1]);
}
faceUvs = undefined;
} else {
for (i=0; i < faceAttributes.length; ++i)
{
facePositions.push(faceAttributes[i]);
}
faceUvs = undefined;
faceNormals = undefined;
}
addFace(faceVertices, facePositions, faceUvs, faceNormals);
}

function parseLine(line) {
line = line.trim();
var result;
Expand Down Expand Up @@ -530,25 +462,28 @@ function loadObj(objPath, options) {
uvs.push(parseFloat(result[1]));
uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
} else { // face line or invalid line

// Because face lines can contain n vertices, we use a line buffer in case the face data spans multiple lines.
// If there's a line continuation don't create face yet
if (line.slice(-1) === '\\') {
lineBuffer += line.substring(0, -1);
lineBuffer += line.substring(0, line.length-1);
return;
}

lineBuffer += line;
if (facePattern1.test(lineBuffer)) { // format "f v v v ..."
parseFaceLine(line, false, false);
} else if (facePattern2.test(lineBuffer)) { // format "f v/uv v/uv v/uv ..."
parseFaceLine(line, true, false);
} else if (facePattern3.test(lineBuffer)) { // format "v/uv/n v/uv/n v/uv/n ..."
parseFaceLine(line, true, true);
} else if (facePattern4.test(lineBuffer)) { // format "v//n v//n v//n ..."
parseFaceLine(line, false, true);
if (lineBuffer.substring(0, 2) === 'f ') {
while ( (result = facePattern.exec(lineBuffer)) !== null ) {
faceVertices.push(result[0]);
facePositions.push(result[1]);
faceUvs.push(result[2]);
faceNormals.push(result[3]);
}
addFace(faceVertices, facePositions, faceUvs, faceNormals);

faceVertices.length = 0;
facePositions.length = 0;
faceNormals.length = 0;
faceUvs.length = 0;
}
lineBuffer = "";
lineBuffer = '';
}
}

Expand Down

0 comments on commit f526e9b

Please sign in to comment.