From e43f6c6bc2774de5ddfa84edcdacbb2beaab3805 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Thu, 30 Dec 2021 22:59:46 -0500 Subject: [PATCH] add model groups --- app.js | 11 +++++++-- src/main/mesh.js | 2 +- src/mesh/api.js | 57 ++++++++++++++++++++++++----------------------- src/mesh/group.js | 53 +++++++++++++++++++++++++++++++++++++++++++ src/mesh/model.js | 13 +++++++++-- 5 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 src/mesh/group.js diff --git a/app.js b/app.js index e7c2c92b..3b094f6a 100644 --- a/app.js +++ b/app.js @@ -47,11 +47,18 @@ function init(mod) { let depcache = {}; - function find_deps(path) { + function find_deps(path, seen = []) { let cached = depcache[path]; if (cached) { return cached; } + if (seen.indexOf(path) >= 0) { + if (debug) { + console.log(`circular dependency at ${path}`, seen); + } + return []; + } + seen.push(path); let deps = [ "main/gapp" ]; let lines = fs.readFileSync(`${dir}/src/${path}.js`) .toString() @@ -63,7 +70,7 @@ function init(mod) { if (deps.indexOf(dep) < 0) { deps.push(dep); } - let deep = find_deps(dep); + let deep = find_deps(dep, seen); deps = deps.filter(p => deep.indexOf(p) < 0); // deeper dependencies go first deps = [...deep, ...deps]; diff --git a/src/main/mesh.js b/src/main/mesh.js index 34a7bcd2..809c7f0d 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -84,7 +84,7 @@ broker.subscribe('space_init', data => { // add object loader broker.subscribe('space_load', data => { - mesh.api.models.add(data.flat().map(el => new mesh.model(el))); + mesh.api.group.new(data.flat().map(el => new mesh.model(el))); }); // remove version cache bust from url diff --git a/src/mesh/api.js b/src/mesh/api.js index cbbde581..f9ca3899 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -18,41 +18,42 @@ let mesh = self.mesh = self.mesh || {}; if (mesh.api) return; let space = moto.Space; -let models = []; +let groups = []; let api = mesh.api = { - models: { - get all() { - return models.slice(); + group: { + list() { + return groups.slice(); }, - add: (list, group = new THREE.Group()) => { - if (!Array.isArray(list)) { - list = [ list ]; - } - for (let model of list) { - models.addOnce(model); - model.group = group; - group.add(model.mesh); - } - space.world.add(group); - space.refresh(); + // @param group {MeshModel[]} + new: (models) => { + api.group.add(new mesh.group(models)); }, - remove: list => { - if (!Array.isArray(list)) { - list = [ list ]; - } - for (let model of list) { - if (models.remove(model)) { - model.group.remove(model.mesh); - if (model.group.children.length === 0) { - space.world.remove(model.group); - } - space.refresh(); - } - } + // @param group {MeshGroup} + add: (group) => { + groups.addOnce(group); + space.world.add(group.group); + space.update(); + }, + + // @param group {MeshGroup} + remove: (group) => { + groups.remove(group); + space.world.remove(group.group); + space.update(); + } + }, + + model: { + list() { + return groups.map(g => g.models).flat(); + }, + + remove: (model) => { + model.group.remove(model); } } }; diff --git a/src/mesh/group.js b/src/mesh/group.js new file mode 100644 index 00000000..33d627f4 --- /dev/null +++ b/src/mesh/group.js @@ -0,0 +1,53 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +"use strict"; + +(function() { + +gapp.register("mesh.group", [ + "add.array", // dep: add.array + "add.three", // dep: add.three + "moto.license", // dep: moto.license + "mesh.model", // dep: mesh.model +]); + +let mesh = self.mesh = self.mesh || {}; +if (mesh.group) return; + +mesh.group = class MeshGroup { + + // @param group {THREE.Group} + constructor(models) { + this.group = new THREE.Group(); + this.models = []; + for (let model of (models || [])) { + this.add(model); + } + } + + bounds() { + return new THREE.Box3().setFromObject(this.group); + } + + // @param model {MeshModel} + add(model) { + model.group = this; + this.models.addOnce(model); + this.group.add(model.mesh); + moto.Space.update(); + } + + // @param model {MeshModel} + remove(model) { + model.group = undefined; + this.models.remove(model); + this.group.remove(model.mesh); + // auto-remove group when empty + if (this.group.children.length === 0) { + mesh.api.group.remove(this); + } + moto.Space.update(); + } +}; + +})(); diff --git a/src/mesh/model.js b/src/mesh/model.js index 6caa46b8..db990dc6 100644 --- a/src/mesh/model.js +++ b/src/mesh/model.js @@ -7,6 +7,7 @@ gapp.register("mesh.model", [ "add.three", // dep: add.three "moto.license", // dep: moto.license + "mesh.group", // dep: mesh.group ]); let mesh = self.mesh = self.mesh || {}; @@ -37,6 +38,10 @@ mesh.model = class MeshModel { this.mesh = this.load(mesh); } + bounds() { + return new THREE.Box3().setFromObject(this.mesh); + } + load(vertices, indices) { let geo = new THREE.BufferGeometry(); if (indices) geo.setIndex(new THREE.BufferAttribute(indices, 1)); @@ -57,11 +62,15 @@ mesh.model = class MeshModel { } set group(gv) { - if (this._group && this._group !== gv) { - throw "model cannot change groups"; + if (gv && this._group && this._group !== gv) { + throw "models can only belong to one group"; } this._group = gv; } + + remove() { + mesh.api.model.remove(this); + } }; })();