Home Reference Source

src/loaders/obj.js

import File from './file';

class ObjLoader {
    static load(url, callback) {
        File.load(url).then((raw) => {
            callback(ObjLoader.parse(raw));
        });
    }

    static parse(raw) {
        // credits: https://raw.githubusercontent.com/frenchtoast747/webgl-obj-loader/master/webgl-obj-loader.js
        const verts = [];
        const vertNormals = [];
        const textures = [];
        const unpacked = {};

        unpacked.verts = [];
        unpacked.norms = [];
        unpacked.textures = [];
        unpacked.hashindices = {};
        unpacked.indices = [];
        unpacked.index = 0;

        const lines = raw.split('\n');

        const VERTEX_RE = /^v\s/;
        const NORMAL_RE = /^vn\s/;
        const TEXTURE_RE = /^vt\s/;
        const FACE_RE = /^f\s/;
        const WHITESPACE_RE = /\s+/;

        for (let i = 0; i < lines.length; i++) {
            const line = lines[i].trim();
            const elements = line.split(WHITESPACE_RE);
            elements.shift();

            if (VERTEX_RE.test(line)) {
                verts.push.apply(verts, elements); // eslint-disable-line
            } else if (NORMAL_RE.test(line)) {
                vertNormals.push.apply(vertNormals, elements); // eslint-disable-line
            } else if (TEXTURE_RE.test(line)) {
                textures.push.apply(textures, elements); // eslint-disable-line
            } else if (FACE_RE.test(line)) {
                let quad = false;
                for (let j = 0; j < elements.length; j++) {
                    if (j === 3 && !quad) {
                        j = 2;
                        quad = true;
                    }

                    if (elements[j] in unpacked.hashindices) {
                        unpacked.indices.push(unpacked.hashindices[elements[j]]);
                    } else {
                        const vertex = elements[j].split('/');

                        unpacked.verts.push(+verts[((vertex[0] - 1) * 3) + 0]);
                        unpacked.verts.push(+verts[((vertex[0] - 1) * 3) + 1]);
                        unpacked.verts.push(+verts[((vertex[0] - 1) * 3) + 2]);

                        if (textures.length) {
                            unpacked.textures.push(+textures[((vertex[1] - 1) * 2) + 0]);
                            unpacked.textures.push(+textures[((vertex[1] - 1) * 2) + 1]);
                        }

                        unpacked.norms.push(+vertNormals[((vertex[2] - 1) * 3) + 0]);
                        unpacked.norms.push(+vertNormals[((vertex[2] - 1) * 3) + 1]);
                        unpacked.norms.push(+vertNormals[((vertex[2] - 1) * 3) + 2]);

                        unpacked.hashindices[elements[j]] = unpacked.index;
                        unpacked.indices.push(unpacked.index);

                        unpacked.index++;
                    }
                    if (j === 3 && quad) {
                        unpacked.indices.push(unpacked.hashindices[elements[0]]);
                    }
                }
            }
        }

        return {
            positions: unpacked.verts,
            indices: unpacked.indices,
            normals: unpacked.norms,
            uvs: unpacked.textures,
        };
    }
}

export default ObjLoader;