add preliminary obj file import support
This commit is contained in:
parent
b17c09cb9a
commit
78c5c43e16
3 changed files with 35 additions and 221 deletions
3
app.js
3
app.js
|
|
@ -244,6 +244,7 @@ const script = {
|
||||||
"moto/ctrl",
|
"moto/ctrl",
|
||||||
"moto/pack",
|
"moto/pack",
|
||||||
"moto/space",
|
"moto/space",
|
||||||
|
"moto/load-obj",
|
||||||
"moto/load-stl",
|
"moto/load-stl",
|
||||||
"moto/db",
|
"moto/db",
|
||||||
"kiri/ui",
|
"kiri/ui",
|
||||||
|
|
@ -367,6 +368,7 @@ const script = {
|
||||||
"geo/polygon",
|
"geo/polygon",
|
||||||
"geo/polygons",
|
"geo/polygons",
|
||||||
"moto/kv",
|
"moto/kv",
|
||||||
|
"moto/load-obj",
|
||||||
"moto/load-stl",
|
"moto/load-stl",
|
||||||
"kiri/conf",
|
"kiri/conf",
|
||||||
"kiri/client",
|
"kiri/client",
|
||||||
|
|
@ -400,6 +402,7 @@ const script = {
|
||||||
"moto/ajax",
|
"moto/ajax",
|
||||||
"moto/ctrl",
|
"moto/ctrl",
|
||||||
"moto/space",
|
"moto/space",
|
||||||
|
"moto/load-obj",
|
||||||
"moto/load-stl",
|
"moto/load-stl",
|
||||||
"moto/db",
|
"moto/db",
|
||||||
"moto/ui",
|
"moto/ui",
|
||||||
|
|
|
||||||
|
|
@ -2432,6 +2432,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
lower = files[i].name.toLowerCase(),
|
lower = files[i].name.toLowerCase(),
|
||||||
israw = lower.indexOf(".raw") > 0 || lower.indexOf('.') < 0,
|
israw = lower.indexOf(".raw") > 0 || lower.indexOf('.') < 0,
|
||||||
isstl = lower.indexOf(".stl") > 0,
|
isstl = lower.indexOf(".stl") > 0,
|
||||||
|
isobj = lower.indexOf(".obj") > 0,
|
||||||
issvg = lower.indexOf(".svg") > 0,
|
issvg = lower.indexOf(".svg") > 0,
|
||||||
ispng = lower.indexOf(".png") > 0,
|
ispng = lower.indexOf(".png") > 0,
|
||||||
isjpg = lower.indexOf(".jpg") > 0,
|
isjpg = lower.indexOf(".jpg") > 0,
|
||||||
|
|
@ -2447,10 +2448,18 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
if (API.feature.on_add_stl) {
|
if (API.feature.on_add_stl) {
|
||||||
API.feature.on_add_stl(e.target.result, file);
|
API.feature.on_add_stl(e.target.result, file);
|
||||||
} else {
|
} else {
|
||||||
let scale = unitScale();
|
|
||||||
platform.add(
|
platform.add(
|
||||||
newWidget(undefined,group)
|
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)
|
.saveToCatalog(e.target.file.name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* adapted from THREE.OBJLoader example
|
|
||||||
*
|
|
||||||
* https://en.wikipedia.org/wiki/Wavefront_.obj_file
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
@ -17,225 +11,33 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} text
|
* @param {String} text
|
||||||
* @returns {Array}
|
* @returns {Array} vertex face array
|
||||||
*/
|
*/
|
||||||
function parse(text) {
|
function parse(text) {
|
||||||
|
|
||||||
let object,
|
let lines = text.split('\n').map(l => l.trim());
|
||||||
objects = [],
|
let verts = [];
|
||||||
geometry,
|
let faces = [];
|
||||||
material;
|
|
||||||
|
|
||||||
function parseVertexIndex(value) {
|
for (let line of lines) {
|
||||||
let index = parseInt(value);
|
let toks = line.split(' ');
|
||||||
return (index >= 0 ? index - 1 : index + vertices.length / 3) * 3;
|
switch (toks.shift()) {
|
||||||
}
|
case 'v':
|
||||||
|
verts.push(toks.map(v => parseFloat(v)));
|
||||||
function parseNormalIndex(value) {
|
break;
|
||||||
let index = parseInt(value);
|
case 'f':
|
||||||
return (index >= 0 ? index - 1 : index + normals.length / 3) * 3;
|
let tok = toks.map(f => parseInt(f.split('/')[0]));
|
||||||
}
|
faces.appendAll(verts[tok[0]-1]);
|
||||||
|
faces.appendAll(verts[tok[1]-1]);
|
||||||
function parseUVIndex(value) {
|
faces.appendAll(verts[tok[2]-1]);
|
||||||
let index = parseInt(value);
|
break;
|
||||||
return (index >= 0 ? index - 1 : index + uvs.length / 2) * 2;
|
case 'g':
|
||||||
}
|
case 'o':
|
||||||
|
break;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create mesh if no objects in text
|
return [ faces ];
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue