From 78c5c43e16100dd4b841ebcfaaa67783b16680a6 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sat, 28 Aug 2021 15:29:33 -0400 Subject: [PATCH] add preliminary obj file import support --- app.js | 3 + src/kiri/main.js | 13 ++- src/moto/load-obj.js | 238 ++++--------------------------------------- 3 files changed, 34 insertions(+), 220 deletions(-) diff --git a/app.js b/app.js index 2285ec80..f3c8b131 100644 --- a/app.js +++ b/app.js @@ -244,6 +244,7 @@ const script = { "moto/ctrl", "moto/pack", "moto/space", + "moto/load-obj", "moto/load-stl", "moto/db", "kiri/ui", @@ -367,6 +368,7 @@ const script = { "geo/polygon", "geo/polygons", "moto/kv", + "moto/load-obj", "moto/load-stl", "kiri/conf", "kiri/client", @@ -400,6 +402,7 @@ const script = { "moto/ajax", "moto/ctrl", "moto/space", + "moto/load-obj", "moto/load-stl", "moto/db", "moto/ui", diff --git a/src/kiri/main.js b/src/kiri/main.js index 02a0b983..a2674cfe 100644 --- a/src/kiri/main.js +++ b/src/kiri/main.js @@ -2432,6 +2432,7 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ lower = files[i].name.toLowerCase(), israw = lower.indexOf(".raw") > 0 || lower.indexOf('.') < 0, isstl = lower.indexOf(".stl") > 0, + isobj = lower.indexOf(".obj") > 0, issvg = lower.indexOf(".svg") > 0, ispng = lower.indexOf(".png") > 0, isjpg = lower.indexOf(".jpg") > 0, @@ -2447,10 +2448,18 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ if (API.feature.on_add_stl) { API.feature.on_add_stl(e.target.result, file); } else { - let scale = unitScale(); platform.add( newWidget(undefined,group) - .loadVertices(new MOTO.STL().parse(e.target.result,scale)) + .loadVertices(new MOTO.STL().parse(e.target.result,unitScale())) + .saveToCatalog(e.target.file.name) + ); + } + } else if (isobj) { + let objs = MOTO.OBJ.parse(e.target.result); + for (let obj of objs) { + platform.add( + newWidget(undefined,group) + .loadVertices(obj.toFloat32(),unitScale()) .saveToCatalog(e.target.file.name) ); } diff --git a/src/moto/load-obj.js b/src/moto/load-obj.js index 1e8f508c..19cf0e89 100644 --- a/src/moto/load-obj.js +++ b/src/moto/load-obj.js @@ -1,9 +1,3 @@ -/** - * adapted from THREE.OBJLoader example - * - * https://en.wikipedia.org/wiki/Wavefront_.obj_file - */ - 'use strict'; (function() { @@ -17,225 +11,33 @@ /** * @param {String} text - * @returns {Array} + * @returns {Array} vertex face array */ function parse(text) { - let object, - objects = [], - geometry, - material; + let lines = text.split('\n').map(l => l.trim()); + let verts = []; + let faces = []; - function parseVertexIndex(value) { - let index = parseInt(value); - return (index >= 0 ? index - 1 : index + vertices.length / 3) * 3; - } - - function parseNormalIndex(value) { - let index = parseInt(value); - return (index >= 0 ? index - 1 : index + normals.length / 3) * 3; - } - - function parseUVIndex(value) { - let index = parseInt(value); - return (index >= 0 ? index - 1 : index + uvs.length / 2) * 2; - } - - function addVertex(a, b, c) { - geometry.vertices.push( - vertices[a], vertices[a + 1], vertices[a + 2], - vertices[b], vertices[b + 1], vertices[b + 2], - vertices[c], vertices[c + 1], vertices[c + 2] - ); - } - - function addNormal(a, b, c) { - geometry.normals.push( - normals[a], normals[a + 1], normals[a + 2], - normals[b], normals[b + 1], normals[b + 2], - normals[c], normals[c + 1], normals[c + 2] - ); - } - - function addUV(a, b, c) { - geometry.uvs.push( - uvs[a], uvs[a + 1], - uvs[b], uvs[b + 1], - uvs[c], uvs[c + 1] - ); - } - - function addFace(a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) { - - let ia = parseVertexIndex(a); - let ib = parseVertexIndex(b); - let ic = parseVertexIndex(c); - let id; - - if (d === undefined) { - addVertex(ia, ib, ic); - } else { - id = parseVertexIndex(d); - addVertex(ia, ib, id); - addVertex(ib, ic, id); - } - - if (ua !== undefined) { - ia = parseUVIndex(ua); - ib = parseUVIndex(ub); - ic = parseUVIndex(uc); - - if (d === undefined) { - addUV(ia, ib, ic); - } else { - id = parseUVIndex(ud); - addUV(ia, ib, id); - addUV(ib, ic, id); - } - } - - if (na !== undefined) { - ia = parseNormalIndex(na); - ib = parseNormalIndex(nb); - ic = parseNormalIndex(nc); - - if (d === undefined) { - addNormal(ia, ib, ic); - } else { - id = parseNormalIndex(nd); - addNormal(ia, ib, id); - addNormal(ib, ic, id); - } + for (let line of lines) { + let toks = line.split(' '); + switch (toks.shift()) { + case 'v': + verts.push(toks.map(v => parseFloat(v))); + break; + case 'f': + let tok = toks.map(f => parseInt(f.split('/')[0])); + faces.appendAll(verts[tok[0]-1]); + faces.appendAll(verts[tok[1]-1]); + faces.appendAll(verts[tok[2]-1]); + break; + case 'g': + case 'o': + break; } } - // create mesh if no objects in text - - if (/^o /gm.test(text) === false) { - geometry = { - vertices: [], - normals: [], - uvs: [] - }; - - object = { - name: '', - geometry: geometry - }; - - objects.push(object); - } - - let vertices = [], - normals = [], - uvs = [], - // v float float float - vertex_pattern = /v(+[\d|\.|\+|\-|e|E]+)(+[\d|\.|\+|\-|e|E]+)(+[\d|\.|\+|\-|e|E]+)/, - // vn float float float - normal_pattern = /vn(+[\d|\.|\+|\-|e|E]+)(+[\d|\.|\+|\-|e|E]+)(+[\d|\.|\+|\-|e|E]+)/, - // vt float float - uv_pattern = /vt(+[\d|\.|\+|\-|e|E]+)(+[\d|\.|\+|\-|e|E]+)/, - // f vertex vertex vertex ... - face_pattern1 = /f(+-?\d+)(+-?\d+)(+-?\d+)(+-?\d+)?/, - // f vertex/uv vertex/uv vertex/uv ... - face_pattern2 = /f(+(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+))?/, - // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... - face_pattern3 = /f(+(-?\d+)\/(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+)\/(-?\d+))(+(-?\d+)\/(-?\d+)\/(-?\d+))?/, - // f vertex//normal vertex//normal vertex//normal ... - face_pattern4 = /f(+(-?\d+)\/\/(-?\d+))(+(-?\d+)\/\/(-?\d+))(+(-?\d+)\/\/(-?\d+))(+(-?\d+)\/\/(-?\d+))?/, - // split text into lines - lines = text.split('\n'); - - for (let i = 0; i < lines.length; i++) { - - let line = lines[i]; - line = line.trim(); - - let result; - - if (line.length === 0 || line.charAt(0) === '#') { - continue; - } else if ((result = vertex_pattern.exec(line)) !== null) { - // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] - vertices.push( - parseFloat(result[1]), - parseFloat(result[2]), - parseFloat(result[3]) - ); - } else if ((result = normal_pattern.exec(line)) !== null) { - // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] - normals.push( - parseFloat(result[1]), - parseFloat(result[2]), - parseFloat(result[3]) - ); - } else if ((result = uv_pattern.exec(line)) !== null) { - // ["vt 0.1 0.2", "0.1", "0.2"] - uvs.push( - parseFloat(result[1]), - parseFloat(result[2]) - ); - } else if ((result = face_pattern1.exec(line)) !== null) { - // ["f 1 2 3", "1", "2", "3", undefined] - addFace( - result[1], result[2], result[3], result[4] - ); - } else if ((result = face_pattern2.exec(line)) !== null) { - // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] - addFace( - result[2], result[5], result[8], result[11], - result[3], result[6], result[9], result[12] - ); - } else if ((result = face_pattern3.exec(line)) !== null) { - // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] - addFace( - result[2], result[6], result[10], result[14], - result[3], result[7], result[11], result[15], - result[4], result[8], result[12], result[16] - ); - } else if ((result = face_pattern4.exec(line)) !== null) { - // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] - addFace( - result[2], result[5], result[8], result[11], - undefined, undefined, undefined, undefined, - result[3], result[6], result[9], result[12] - ); - } else if (/^o /.test(line)) { - - geometry = { - vertices: [], - normals: [], - uvs: [] - }; - - object = { - name: line.substring(2).trim(), - geometry: geometry - }; - - objects.push(object) - - } else if (/^g /.test(line)) { - // group - } else if (/^usemtl /.test(line)) { - // material - material.name = line.substring(7).trim(); - } else if (/^mtllib /.test(line)) { - // mtl file - } else if (/^s /.test(line)) { - // smooth shading - } else { - // unhandled - } - } - - objects.forEach(function(object) { - object.geometry.vertices = new Float32Array(object.geometry.vertices); - object.geometry.normals = new Float32Array(object.geometry.normals); - object.geometry.uvs = new Float32Array(object.geometry.uvs); - }); - - return objects; + return [ faces ]; } })();