refactor worker with cleaner object function bindings
This commit is contained in:
parent
b4966bbb6f
commit
eb2fbf2a09
8 changed files with 168 additions and 59 deletions
|
|
@ -83,7 +83,8 @@ broker.subscribe('space_init', data => {
|
|||
platform.setColor(platcolor);
|
||||
},
|
||||
'keypress', evt => {
|
||||
switch (evt.code) {
|
||||
let { shiftKey, metaKey, ctrlKey, code } = evt;
|
||||
switch (code) {
|
||||
case 'KeyC':
|
||||
selection.centerXY().focus();
|
||||
break;
|
||||
|
|
@ -96,11 +97,6 @@ broker.subscribe('space_init', data => {
|
|||
case 'KeyB':
|
||||
selection.boundsBox({toggle:true});
|
||||
break;
|
||||
case 'KeyS':
|
||||
for (let m of selection.models()) {
|
||||
m.sync();
|
||||
}
|
||||
break;
|
||||
case 'KeyH':
|
||||
space.view.home();
|
||||
break;
|
||||
|
|
@ -126,7 +122,13 @@ broker.subscribe('space_init', data => {
|
|||
}
|
||||
break;
|
||||
case 'KeyD':
|
||||
broker.send.space_debug();
|
||||
if (shiftKey) {
|
||||
for (let m of selection.models()) {
|
||||
m.debug();
|
||||
}
|
||||
} else {
|
||||
broker.send.space_debug();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
selection.clear();
|
||||
|
|
@ -213,19 +215,21 @@ broker.subscribe('space_load', data => {
|
|||
broker.subscribe('space_debug', () => {
|
||||
for (let g of mesh.api.group.list()) {
|
||||
let { center, size } = g.bounds();
|
||||
console.group('group', {
|
||||
console.group(g.id);
|
||||
console.log({
|
||||
center,
|
||||
size,
|
||||
pos: g.group.position
|
||||
});
|
||||
for (let m of g.models) {
|
||||
console.log('model', {
|
||||
console.log(m.id, {
|
||||
box: m.mesh.getBoundingBox(),
|
||||
pos: m.mesh.position
|
||||
});
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
moto.client.fn.debug();
|
||||
});
|
||||
|
||||
// remove version cache bust from url
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ let api = mesh.api = {
|
|||
model,
|
||||
|
||||
objects() {
|
||||
// return models, not groups
|
||||
// return model objects suitable for finding ray intersections
|
||||
return group.list().map(o => o.models).flat().map(o => o.object());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ gapp.register("mesh.group", [
|
|||
let mesh = self.mesh = self.mesh || {};
|
||||
if (mesh.group) return;
|
||||
|
||||
let space = moto.Space;
|
||||
let worker = moto.client.fn;
|
||||
|
||||
mesh.group = class MeshGroup extends mesh.object {
|
||||
|
||||
// @param group {mesh.model[]}
|
||||
|
|
@ -28,6 +31,10 @@ mesh.group = class MeshGroup extends mesh.object {
|
|||
}
|
||||
}
|
||||
|
||||
type() {
|
||||
return "group";
|
||||
}
|
||||
|
||||
object() {
|
||||
return this.group;
|
||||
}
|
||||
|
|
@ -37,7 +44,8 @@ mesh.group = class MeshGroup extends mesh.object {
|
|||
model.group = this;
|
||||
this.models.addOnce(model);
|
||||
this.group.add(model.mesh);
|
||||
moto.Space.update();
|
||||
space.update();
|
||||
worker.group_add({id: this.id, model:model.id});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -54,12 +62,14 @@ mesh.group = class MeshGroup extends mesh.object {
|
|||
this.models.remove(model);
|
||||
this.group.remove(model.mesh);
|
||||
// trigger sync with worker
|
||||
worker.group_remove({id: this.id, model:model.id});
|
||||
model.remove(true);
|
||||
// auto-remove group when empty
|
||||
if (this.group.children.length === 0) {
|
||||
mesh.api.group.remove(this);
|
||||
worker.object_destroy({id: this.id});
|
||||
}
|
||||
moto.Space.update();
|
||||
space.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ gapp.register("mesh.model", [
|
|||
let mesh = self.mesh = self.mesh || {};
|
||||
if (mesh.model) return;
|
||||
|
||||
let space = moto.Space;
|
||||
let worker = moto.client.fn;
|
||||
|
||||
/** default materials **/
|
||||
let materials = mesh.material = {
|
||||
unselected: new THREE.MeshPhongMaterial({
|
||||
|
|
@ -49,16 +52,19 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
this.mesh = this.load(mesh);
|
||||
}
|
||||
|
||||
type() {
|
||||
return "model";
|
||||
}
|
||||
|
||||
object() {
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
sync() {
|
||||
moto.client.fn.model_sync({
|
||||
debug() {
|
||||
worker.model_debug({
|
||||
matrix: this.mesh.matrixWorld.elements,
|
||||
id: this.id
|
||||
}).then(data => {
|
||||
if (data && data.length)
|
||||
// for debugging matrix ops
|
||||
return mesh.api.group.new([new mesh.model({
|
||||
file: `synth-${this.name}`,
|
||||
|
|
@ -80,7 +86,7 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
// this ref allows clicks to be traced to models and groups
|
||||
meh.model = this;
|
||||
// sync data to worker
|
||||
moto.client.fn.model_load({id: this.id, name: this.name, vertices, indices});
|
||||
worker.model_load({id: this.id, name: this.file, vertices, indices});
|
||||
return meh;
|
||||
}
|
||||
|
||||
|
|
@ -93,8 +99,8 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
geo.attributes.index.needsUpdate = true;
|
||||
}
|
||||
geo.attributes.position.needsUpdate = true;
|
||||
geo.computeFaceNormals();
|
||||
geo.computeVertexNormals();
|
||||
worker.model_load({id: this.id, name: this.name, vertices, indices});
|
||||
}
|
||||
|
||||
get group() {
|
||||
|
|
@ -122,7 +128,7 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
mat.opacity = ov;
|
||||
mat.visible = true;
|
||||
}
|
||||
moto.Space.update();
|
||||
space.update();
|
||||
}
|
||||
|
||||
wireframe(bool, opt = {}) {
|
||||
|
|
@ -151,7 +157,7 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
this.mesh.add(this._wire);
|
||||
this.opacity(opt.opacity || 0);
|
||||
}
|
||||
moto.Space.update();
|
||||
space.update();
|
||||
}
|
||||
|
||||
material(mat) {
|
||||
|
|
@ -163,7 +169,7 @@ mesh.model = class MeshModel extends mesh.object {
|
|||
// direct call requires pass through group
|
||||
} else {
|
||||
// called from group
|
||||
moto.client.fn.model_remove({id: this.id});
|
||||
worker.object_destroy({id: this.id});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,10 +13,18 @@ gapp.register("mesh.object", [
|
|||
let mesh = self.mesh = self.mesh || {};
|
||||
if (mesh.object) return;
|
||||
|
||||
let space = moto.Space;
|
||||
let worker = moto.client.fn;
|
||||
|
||||
mesh.object = class MeshObject {
|
||||
|
||||
constructor() {
|
||||
this.id = mesh.util.uuid();
|
||||
worker.object_create({id: this.id, type: this.type()});
|
||||
}
|
||||
|
||||
type() {
|
||||
throw "type() requires implementation";
|
||||
}
|
||||
|
||||
// @returns {THREE.Object3D}
|
||||
|
|
@ -54,7 +62,8 @@ mesh.object = class MeshObject {
|
|||
let pos = this.position();
|
||||
pos.set(pos.x + x, pos.y + y, pos.z + z);
|
||||
this.updateBoundsBox();
|
||||
moto.Space.update();
|
||||
space.update();
|
||||
moto.client.fn.object_move({id: this.id, x, y, z});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +74,9 @@ mesh.object = class MeshObject {
|
|||
}
|
||||
scale.set(...arguments);
|
||||
this.updateBoundsBox();
|
||||
moto.Space.update();
|
||||
let [ x, y, z ] = arguments;
|
||||
moto.client.fn.object_scale({id: this.id, x, y, z});
|
||||
space.update();
|
||||
}
|
||||
|
||||
rotate(x = 0, y = 0, z = 0) {
|
||||
|
|
@ -73,25 +84,30 @@ mesh.object = class MeshObject {
|
|||
if (y) this.object().rotateOnWorldAxis(new THREE.Vector3(0,1,0), y);
|
||||
if (z) this.object().rotateOnWorldAxis(new THREE.Vector3(0,0,1), z);
|
||||
this.updateBoundsBox();
|
||||
moto.Space.update();
|
||||
worker.object_rotate({id: this.id, x, y, z});
|
||||
space.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
rotation() {
|
||||
let rot = this.object().rotation;
|
||||
let rotation = this.object().rotation;
|
||||
if (arguments.length === 0) {
|
||||
return rot;
|
||||
return rotation;
|
||||
}
|
||||
rot.set(...arguments);
|
||||
rotation.set(...arguments);
|
||||
this.updateBoundsBox();
|
||||
moto.Space.update();
|
||||
let { x, y, z } = rotation;
|
||||
worker.object_rotation({id: this.id, x, y, z});
|
||||
space.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
qrotation(quaternion) {
|
||||
this.object().setRotationFromQuaternion(quaternion);
|
||||
this.updateBoundsBox();
|
||||
moto.Space.update();
|
||||
let { w, x, y, z } = quaternion;
|
||||
worker.object_qrotation({id: this.id, w, x, y, z});
|
||||
space.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +117,9 @@ mesh.object = class MeshObject {
|
|||
return pos;
|
||||
}
|
||||
pos.set(...arguments);
|
||||
moto.Space.update();
|
||||
let [ x, y, z ] = arguments;
|
||||
worker.object_position({id: this.id, x, y, z});
|
||||
space.update();
|
||||
}
|
||||
|
||||
showBounds(bool) {
|
||||
|
|
@ -114,7 +132,7 @@ mesh.object = class MeshObject {
|
|||
|
||||
updateBoundsBox() {
|
||||
let helper = this._boundsBox;
|
||||
let world = moto.Space.world;
|
||||
let world = space.world;
|
||||
if (helper) {
|
||||
world.remove(helper);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,33 +23,85 @@ let space_rotation = new THREE.Matrix4().makeRotationX(Math.PI / 2);
|
|||
let { client, worker } = moto;
|
||||
let cache = {};
|
||||
|
||||
function cacheUpdate(id, data) {
|
||||
Object.assign(cache[id], data);
|
||||
}
|
||||
|
||||
worker.bind("debug", (data, send) => {
|
||||
console.log({cache});
|
||||
console.log({work_cache: cache});
|
||||
send.done();
|
||||
});
|
||||
|
||||
worker.bind("model_load", (data, send) => {
|
||||
let { vertices, name, id } = data;
|
||||
let geo = new THREE.BufferGeometry();
|
||||
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
|
||||
geo.computeVertexNormals();
|
||||
cache[id] = { id, name, geo };
|
||||
send.done();
|
||||
});
|
||||
let model = {
|
||||
load(data) {
|
||||
let { vertices, name, id } = data;
|
||||
let geo = new THREE.BufferGeometry();
|
||||
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
|
||||
geo.computeVertexNormals();
|
||||
cacheUpdate(id, { name, geo });
|
||||
},
|
||||
|
||||
worker.bind("model_remove", (data, send) => {
|
||||
delete cache[data.id];
|
||||
send.done();
|
||||
});
|
||||
debug(data) {
|
||||
let { matrix, id } = data;
|
||||
let rec = cache[id];
|
||||
let geo = rec.geo.clone();
|
||||
let m4 = space_rotation.clone().multiply( new THREE.Matrix4().fromArray(matrix) );
|
||||
geo.applyMatrix4(m4);
|
||||
// for debugging state / matrix ops
|
||||
return geo.attributes.position.array;
|
||||
}
|
||||
};
|
||||
|
||||
worker.bind("model_sync", (data, send) => {
|
||||
let { matrix, id } = data;
|
||||
let rec = cache[id];
|
||||
let geo = rec.geo.clone();
|
||||
let m4 = space_rotation.clone().multiply( new THREE.Matrix4().fromArray(matrix) );
|
||||
geo.applyMatrix4(m4);
|
||||
// for debugging matrix ops
|
||||
send.done(geo.attributes.position.array);
|
||||
let group = {
|
||||
add(data) {
|
||||
let { id, model } = data;
|
||||
},
|
||||
|
||||
remove(data) {
|
||||
let { id, model } = data;
|
||||
},
|
||||
|
||||
create(data) {
|
||||
let { id, type } = data;
|
||||
cache[id] = { id, type };
|
||||
}
|
||||
};
|
||||
|
||||
let object = {
|
||||
create(data) {
|
||||
let { id, type } = data;
|
||||
cache[id] = { id, type };
|
||||
},
|
||||
|
||||
destroy(data) {
|
||||
delete cache[data.id];
|
||||
},
|
||||
|
||||
move(data) {
|
||||
let { id, type, x, y, z } = data;
|
||||
},
|
||||
|
||||
position(data) {
|
||||
let { id, type, x, y, z } = data;
|
||||
},
|
||||
|
||||
rotate(data) {
|
||||
let { id, type, x, y, z } = data;
|
||||
},
|
||||
|
||||
rotation(data) {
|
||||
let { id, type, x, y, z } = data;
|
||||
},
|
||||
|
||||
qrotation(data) {
|
||||
let { id, type, w, x, y, z } = data;
|
||||
}
|
||||
};
|
||||
|
||||
worker.bindObject({
|
||||
model,
|
||||
group,
|
||||
object
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ let client = moto.client = {
|
|||
data,
|
||||
stream: ondata ? true : false
|
||||
};
|
||||
|
||||
try {
|
||||
worker.postMessage(msg, direct);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -15,32 +15,52 @@ let endpoints = {};
|
|||
// code is running in the worker / server context
|
||||
const dispatch = moto.worker = {
|
||||
|
||||
bind: (name, fn) => {
|
||||
// bind an endpoint name to a function
|
||||
bind(name, fn) {
|
||||
endpoints[name] = fn;
|
||||
dispatch.send({bind: name});
|
||||
},
|
||||
|
||||
send: (msg) => {
|
||||
// bind all functions in an object
|
||||
bindObject(object, root, recurse) {
|
||||
recurse = recurse || root === undefined;
|
||||
for (let [key, fn] of Object.entries(object)) {
|
||||
key = root ? `${root}_${key}` : key;
|
||||
if (typeof fn === 'function') {
|
||||
dispatch.bind(key, fn);
|
||||
} else if (recurse) {
|
||||
dispatch.bindObject(fn, key, recurse);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
send(msg) {
|
||||
self.postMessage(msg);
|
||||
},
|
||||
|
||||
onmessage: (e) => {
|
||||
onmessage(e) {
|
||||
let msg = e.data,
|
||||
run = endpoints[msg.task],
|
||||
async = false,
|
||||
done = false,
|
||||
send = {
|
||||
data: (data, direct) => {
|
||||
// puts function in async mode
|
||||
// prevents auto send.done() on function return
|
||||
async() {
|
||||
async = true;
|
||||
},
|
||||
data(data, direct) {
|
||||
if (canSend(data)) {
|
||||
dispatch.send({ done: false, data: data }, direct);
|
||||
}
|
||||
},
|
||||
done: (data, direct) => {
|
||||
done(data, direct) {
|
||||
if (canSend(data)) {
|
||||
dispatch.send({ done: true, data: data }, direct);
|
||||
done = true;
|
||||
}
|
||||
},
|
||||
error: (data) => {
|
||||
error(data) {
|
||||
if (canSend(data)) {
|
||||
done = true;
|
||||
dispatch.send({ error: data });
|
||||
|
|
@ -57,7 +77,7 @@ const dispatch = moto.worker = {
|
|||
if (run) {
|
||||
try {
|
||||
let data = run(msg.data, send);
|
||||
if (data) {
|
||||
if (data || async === false) {
|
||||
send.done(data);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue