Skip to content

Commit

Permalink
refactored face line parsing to support multiline faces
Browse files Browse the repository at this point in the history
  • Loading branch information
rahwang committed Jun 16, 2017
1 parent 7e82e90 commit 2396899
Showing 1 changed file with 111 additions and 42 deletions.
153 changes: 111 additions & 42 deletions lib/loadObj.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,15 @@ var facePattern2 = /f(\s+-?\d+\/-?\d+){3,}/;
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 faceSpacePattern = /f?\s+/;
var faceSpaceOrSlashPattern = /(f?\s+)|(\/+\s*)/g;
// Just for line continuations
var facePattern5 = /((\s|^)+-?\d+\/?(\s|$)){1,}/; // f vertex vertex vertex ...
var facePattern6 = /((\s|^)+-?\d+\/-?\d+(\s|$)){1,}/; // f vertex/uv vertex/uv vertex/uv ...
var facePattern7 = /((\s|^)+-?\d+\/-?\d+\/-?\d+(\s|$)+){1,}/; // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var facePattern8 = /((\s|^)+-?\d+\/\/-?\d+(\s|$)){1,}/; // f vertex//normal vertex//normal vertex//normal ...


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

/**
Expand Down Expand Up @@ -101,6 +108,12 @@ function loadObj(objPath, options) {
// All mtl paths seen in the obj
var mtlPaths = [];

// Buffers for face data that spans multiple lines
var faceVertices = [];
var facePositions = [];
var faceUvs = [];
var faceNormals = [];

function getName(name) {
return (name === '' ? undefined : name);
}
Expand Down Expand Up @@ -166,6 +179,20 @@ function loadObj(objPath, options) {
var zMag = Cartesian3.magnitude(zAxis);
var min = Math.min(xMag, yMag, zMag);

// If all the points are on a line, just remove one of the zero dimensions
if (xMag === 0 && (yMag === 0 || zMag === 0)) {
var i;
for (i = 0; i < positions.length; i++) {
positions2D[i] = new Cartesian2(positions[i].y, positions[i].z);
}
return positions2D;
} else if (yMag === 0 && zMag === 0) {
for (i = 0; i < positions.length; i++) {
positions2D[i] = new Cartesian2(positions[i].x, positions[i].y);
}
return positions2D;
}

var center = obb.center;
var planeXAxis;
var planeYAxis;
Expand Down Expand Up @@ -200,7 +227,7 @@ function loadObj(objPath, options) {
Plane.fromPointNormal(origin, normal, plane);
ray.direction = normal;

for (var i = 0; i < positions.length; i++) {
for (i = 0; i < positions.length; i++) {
ray.origin = positions[i];

var intersectionPoint = IntersectionTests.rayPlane(ray, plane, intPoint);
Expand Down Expand Up @@ -279,6 +306,14 @@ function loadObj(objPath, options) {
return index;
}

function get3DPoint(index, result) {
var pi = getOffset(index, positions, 3);
var px = positions.get(pi + 0);
var py = positions.get(pi + 1);
var pz = positions.get(pi + 2);
return Cartesian3.fromElements(px, py, pz, result);
}

// Given a sequence of three points A B C, determine whether vector BC
// "turns" clockwise (positive) or counter-clockwise (negative) from vector AB
var scratch1 = new Cartesian3();
Expand Down Expand Up @@ -333,31 +368,26 @@ function loadObj(objPath, options) {

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);
vertexIndices.push(index);

// Collect the vertex positions as 3D points
var pi = getOffset(index + 1, positions, 3);
var px = mesh.positions.get(pi + 0);
var py = mesh.positions.get(pi + 1);
var pz = mesh.positions.get(pi + 2);
positions3D.push(new Cartesian3(px, py, pz));
positions3D.push(get3DPoint(positions[i], new Cartesian3()));
}

var positions2D = projectTo2D(positions3D);

if (isConvex(positions2D)) {
// Use the fan method to triangulate
for (i=1; i < vertices.length-1; ++i) {
primitive.indices.push(vertexIndices[0]);
primitive.indices.push(vertexIndices[i]);
primitive.indices.push(vertexIndices[i+1]);
}
} else {

// Since the projection doesn't respect winding order, reverse the order of
// the vertices before triangulating to enforce counter clockwise.
var windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D);
Expand All @@ -372,7 +402,66 @@ 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)
faceVertices = faceVertices.concat(line.replace(faceSpacePattern, ' ').split(' ').filter(trimEmpty));
// get all vertex attributes for this line
var faceAttributes = line.replace(faceSpaceOrSlashPattern, ' ').split(' ').filter(trimEmpty);

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;
}

// If there's a line continuation, buffer the results and don't create face yet
if (line.slice(-1) === '\\') {
return;
}

addFace(faceVertices, facePositions, faceUvs, faceNormals);

// Clear buffered data once face has been added.
faceVertices = [];
facePositions = [];
faceUvs = [];
faceNormals = [];
}

function parseLine(line) {
Expand Down Expand Up @@ -418,38 +507,18 @@ function loadObj(objPath, options) {
} else if ((result = uvPattern.exec(line)) !== null) {
uvs.push(parseFloat(result[1]));
uvs.push(1.0 - parseFloat(result[2])); // Flip y so 0.0 is the bottom of the image
} else {
var faceVertices = line.replace(faceSpacePattern, ' ').substring(1).split(' '); // get vertex data (attributes '/' separated)
var faceAttributes = line.replace(faceSpaceOrSlashPattern, ' ').substring(1).split(' '); // get vertex attributes
var facePositions = [];
var faceUvs = [];
var faceNormals = [];

if (facePattern1.test(line)) { // format "f v v v ..."
addFace(faceVertices, faceAttributes, undefined, undefined);
} else if (facePattern2.test(line)) { // format "f v/uv v/uv v/uv ..."
var i;
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
}
addFace(faceVertices, facePositions, faceUvs, undefined);
} else if (facePattern3.test(line)) { // format "v/uv/n v/uv/n v/uv/n ..."
for (i=0; i <= faceAttributes.length - 3; i += 3)
{
facePositions.push(faceAttributes[i]);
faceUvs.push(faceAttributes[i+1]);
faceNormals.push(faceAttributes[i+2]);
}
addFace(faceVertices, facePositions, faceUvs, faceNormals);
} else if (facePattern4.test(line)) { // format "v//n v//n v//n ..."
for (i=0; i <= faceAttributes.length - 2; i += 2)
{
facePositions.push(faceAttributes[i]);
faceNormals.push(faceAttributes[i+1]);
}
addFace(faceVertices, facePositions, undefined, faceNormals);
} else { // face line or invalid line
// If we already have buffered data, this is a continued line
var continuedLine = faceVertices.length > 0;

if (facePattern1.test(line) || (continuedLine && facePattern5.test(line))) { // format "f v v v ..."
parseFaceLine(line, false, false);
} else if (facePattern2.test(line) || (continuedLine && facePattern6.test(line))) { // format "f v/uv v/uv v/uv ..."
parseFaceLine(line, true, false);
} else if (facePattern3.test(line) || (continuedLine && facePattern7.test(line))) { // format "v/uv/n v/uv/n v/uv/n ..."
parseFaceLine(line, true, true);
} else if (facePattern4.test(line) || (continuedLine && facePattern8.test(line))) { // format "v//n v//n v//n ..."
parseFaceLine(line, false, true);
}
}
}
Expand Down

0 comments on commit 2396899

Please sign in to comment.