/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; (function() { // start worker pool (disabled for now with *0) moto.client.start(`/code/mesh_pool?${gapp.version}`, moto.client.max() * 0); // dep: ext.three // dep: ext.three-bgu gapp.finalize("mesh.work", [ "moto.license", // dep: moto.license "moto.client", // dep: moto.client "moto.worker", // dep: moto.worker "mesh.tool", // dep: mesh.tool "add.three", // dep: add.three ]); let { Matrix4, Vector3, BufferGeometry, BufferAttribute, computeFaceNormal } = THREE; // compensation for space/world/platform rotation let core_matrix = new Matrix4().makeRotationX(Math.PI / 2); let { client, worker } = moto; let cache = {}; function log(msg) { return worker.publish("mesh.log", msg); } function cacheUpdate(id, data) { Object.assign(cache[id], data); } // translate original mesh vertices into UI world view (PI/2 rotation on X) function translate_encode(id, matrix) { let rec = cache[id]; let mkey = matrix.map(v => v.round(6)).join('-'); if (!rec || !rec.trans || rec.mkey !== mkey) { let geo = rec.geo.clone(); let mat = core_matrix.clone().multiply(new Matrix4().fromArray(matrix)); geo.applyMatrix4(mat); rec.mkey = mkey; rec.trans = geo.attributes.position.array } return rec.trans; } function analyze(id, opt = {}) { log(`${id} | indexing...`); let geo = cache[id].geo; let tool = new mesh.tool({ vertices: geo.attributes.position.array, faces: geo.index ? geo.index.array : undefined, debug: false }); log(`${id} | analyzing...`); tool.heal(opt); dbug.log(tool); return tool; } let model = { load(data) { let { vertices, indices, name, id } = data; let geo = new BufferGeometry(); geo.setAttribute('position', new BufferAttribute(vertices, 3)); if (indices) geo.setIndex(new BufferAttribute(indices, 1)); cacheUpdate(id, { name, geo, xmatrix: core_matrix.clone(), trans: undefined }); }, // return new vertices in world coordinates duplicate(data) { let { id, matrix } = data; return translate_encode(id, matrix); }, // merge several model vertices into a single array merge(recs) { let arrays = recs.map(rec => translate_encode(rec.id, rec.matrix)); let length = arrays.map(a => a.length).reduce((v,a) => v + a); let data = new Float32Array(length); for (let i=0, l=arrays.length, p=0; i parseFloat(v)); }, // split a model along an axis at a given point // return two arrays of vertices for each resulting object split(data) { let { id, matrix, z } = data; let o1 = []; let o2 = []; let pos = translate_encode(id, matrix); let split = []; let on = []; let over = []; let under = []; function sort(v) { if (v.z < z) return under.push(v); if (v.z > z) return over.push(v); on.push(v); } function lerp(v1, v2) { let zd = Math.abs(v1.z - v2.z); let z1 = Math.abs(v1.z - z); return v1.clone().lerp(v2, z1/zd); } for (let i=0, l=pos.length; i v.round(5)); vtot += (vs.length / 3); } switch (format) { case "obj": let p = 1; let obj = [header]; for (let rec of recs) { let { id, matrix, file, varr } = rec; obj.push(`g ${file}`); for (let i=0; i { dat.setUint8(i, c.charCodeAt(0)); }); // todo put Kiri:Moto info in header dat.setInt32(80, vtot/3, true); for (let rec of recs) { let { id, matrix, file, varr } = rec; for (let i=0, l=varr.length; i