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