diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3c0e80a7..79bdbe06 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,4 +1,4 @@ -name: 'coverage' +name: "coverage" on: pull_request: branches: diff --git a/examples/src/simulators/VolumeSimulator.ts b/examples/src/simulators/VolumeSimulator.ts index 0542f785..68ab51af 100644 --- a/examples/src/simulators/VolumeSimulator.ts +++ b/examples/src/simulators/VolumeSimulator.ts @@ -68,9 +68,8 @@ export default class VolumeSim implements IClientSimulatorImpl { [0]: { name: "volume", geometry: { - // TODO swap with volume display type when available - displayType: GeometryDisplayType.SPHERE, - url: "", + displayType: GeometryDisplayType.VOLUME, + url: "https://animatedcell-test-data.s3.us-west-2.amazonaws.com/variance/1.zarr", color: "ffff00", }, }, diff --git a/package-lock.json b/package-lock.json index ab901fb6..a2194896 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.8.4", "license": "MIT", "dependencies": { + "@aics/volume-viewer": "allen-cell-animated/volume-viewer#simularium-volumes", "@babel/plugin-transform-runtime": "^7.23.6", "@babel/runtime": "^7.23.6", "@fortawesome/fontawesome-free": "^5.15.2", @@ -85,6 +86,19 @@ "node": ">=0.10.0" } }, + "node_modules/@aics/volume-viewer": { + "version": "3.11.1", + "resolved": "git+ssh://git@github.com/allen-cell-animated/volume-viewer.git#a6efd4a7f2272a58ee4481a3f24be39bf626847c", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.6", + "geotiff": "^2.0.5", + "serialize-error": "^11.0.3", + "three": "^0.144.0", + "tweakpane": "^3.1.9", + "zarrita": "^0.3.2" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -1883,9 +1897,10 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3180,6 +3195,12 @@ "node": ">= 8" } }, + "node_modules/@petamoriken/float16": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.7.tgz", + "integrity": "sha512-/Ri4xDDpe12NT6Ex/DRgHzLlobiQXEW/hmG08w1wj/YU7hLemk97c+zHQFp0iZQ9r7YqgLEXZR2sls4HxBf9NA==", + "license": "MIT" + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -3871,6 +3892,40 @@ "dev": true, "peer": true }, + "node_modules/@zarrita/core": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@zarrita/core/-/core-0.0.3.tgz", + "integrity": "sha512-fWv51b+xbYnws1pkNDPwJQoDa76aojxplHyMup82u11UAiet3gURMsrrkhM6YbeTgSY1A8oGxDOrvar3SiZpLA==", + "dependencies": { + "@zarrita/storage": "^0.0.2", + "@zarrita/typedarray": "^0.0.1", + "numcodecs": "^0.2.2" + } + }, + "node_modules/@zarrita/indexing": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@zarrita/indexing/-/indexing-0.0.3.tgz", + "integrity": "sha512-Q61d9MYX6dsK1DLltEpwx4mJWCZHj0TXiaEN4QpxNDtToa/EoyytP/pYHPypO4GXBscZooJ6eZkKT5FMx9PVfg==", + "dependencies": { + "@zarrita/core": "^0.0.3", + "@zarrita/storage": "^0.0.2", + "@zarrita/typedarray": "^0.0.1" + } + }, + "node_modules/@zarrita/storage": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@zarrita/storage/-/storage-0.0.2.tgz", + "integrity": "sha512-uFt4abAoiOYLroalNDAnVaQxA17zGKrQ0waYKmTVm+bNonz8ggKZP+0FqMhgUZITGChqoANHuYTazbuU5AFXWA==", + "dependencies": { + "reference-spec-reader": "^0.2.0", + "unzipit": "^1.3.6" + } + }, + "node_modules/@zarrita/typedarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@zarrita/typedarray/-/typedarray-0.0.1.tgz", + "integrity": "sha512-ZdvNjYP1bEuQXoSTVkemV99w42jHYrJ3nh9golCLd4MVBlrVbfZo4wWgBslU4JZUaDikhFSH+GWMDgAq/rI32g==" + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -7711,6 +7766,25 @@ "node": ">=6.9.0" } }, + "node_modules/geotiff": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.1.3.tgz", + "integrity": "sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==", + "license": "MIT", + "dependencies": { + "@petamoriken/float16": "^3.4.7", + "lerc": "^3.0.0", + "pako": "^2.0.4", + "parse-headers": "^2.0.2", + "quick-lru": "^6.1.1", + "web-worker": "^1.2.0", + "xml-utils": "^1.0.2", + "zstddec": "^0.1.0" + }, + "engines": { + "node": ">=10.19" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -11821,6 +11895,12 @@ "node": ">=6" } }, + "node_modules/lerc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", + "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==", + "license": "Apache-2.0" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -12911,6 +12991,15 @@ "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", "dev": true }, + "node_modules/numcodecs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/numcodecs/-/numcodecs-0.2.2.tgz", + "integrity": "sha512-Y5K8mv80yb4MgVpcElBkUeMZqeE4TrovxRit/dTZvoRl6YkB6WEjY+fiUjGCblITnt3T3fmrDg8yRWu0gOLjhQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/nwsapi": { "version": "2.2.12", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", @@ -13423,6 +13512,12 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -13447,6 +13542,12 @@ "node": ">=0.10.0" } }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "license": "MIT" + }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -15173,6 +15274,18 @@ } ] }, + "node_modules/quick-lru": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", + "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -15278,6 +15391,12 @@ "node": ">=8.10.0" } }, + "node_modules/reference-spec-reader": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/reference-spec-reader/-/reference-spec-reader-0.2.0.tgz", + "integrity": "sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==", + "license": "MIT" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", @@ -16034,6 +16153,33 @@ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true }, + "node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "license": "MIT", + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -17656,6 +17802,18 @@ "node": ">=8" } }, + "node_modules/unzipit": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unzipit/-/unzipit-1.4.3.tgz", + "integrity": "sha512-gsq2PdJIWWGhx5kcdWStvNWit9FVdTewm4SEG7gFskWs+XCVaULt9+BwuoBtJiRE8eo3L1IPAOrbByNLtLtIlg==", + "license": "MIT", + "dependencies": { + "uzip-module": "^1.0.2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -17736,6 +17894,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uzip-module": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/uzip-module/-/uzip-module-1.0.3.tgz", + "integrity": "sha512-AMqwWZaknLM77G+VPYNZLEruMGWGzyigPK3/Whg99B3S6vGHuqsyl5ZrOv1UUF3paGK1U6PM0cnayioaryg/fA==", + "license": "MIT" + }, "node_modules/v8-compile-cache": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", @@ -17803,6 +17967,12 @@ "node": ">=10.13.0" } }, + "node_modules/web-worker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", + "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==", + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -18190,6 +18360,12 @@ "node": ">=12" } }, + "node_modules/xml-utils": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.1.tgz", + "integrity": "sha512-Dn6vJ1Z9v1tepSjvnCpwk5QqwIPcEFKdgnjqfYOABv1ngSofuAhtlugcUC3ehS1OHdgDWSG6C5mvj+Qm15udTQ==", + "license": "CC0-1.0" + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", @@ -18277,6 +18453,22 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zarrita": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/zarrita/-/zarrita-0.3.2.tgz", + "integrity": "sha512-Zx9nS28C2tXZhF1BmQkgQGi0M/Z5JiM/KCMa+fEYtr/MnIzyizR4sKRA/sXjDP1iuylILWTJAWWBJD//0ONXCA==", + "dependencies": { + "@zarrita/core": "^0.0.3", + "@zarrita/indexing": "^0.0.3", + "@zarrita/storage": "^0.0.2" + } + }, + "node_modules/zstddec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz", + "integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==", + "license": "MIT AND BSD-3-Clause" } } } diff --git a/package.json b/package.json index ca56a2be..2d50eca6 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "react-dom": "^18.2.0" }, "dependencies": { + "@aics/volume-viewer": "allen-cell-animated/volume-viewer#simularium-volumes", "@babel/plugin-transform-runtime": "^7.23.6", "@babel/runtime": "^7.23.6", "@fortawesome/fontawesome-free": "^5.15.2", diff --git a/src/visGeometry/GeometryStore.ts b/src/visGeometry/GeometryStore.ts index 2ec874e1..0a5d29e6 100644 --- a/src/visGeometry/GeometryStore.ts +++ b/src/visGeometry/GeometryStore.ts @@ -1,6 +1,7 @@ import { forEach } from "lodash"; import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader"; import jsLogger, { ILogger, ILogLevel } from "js-logger"; +import { createVolumeLoader, LoadSpec } from "@aics/volume-viewer"; import { BufferGeometry, Object3D, @@ -23,6 +24,7 @@ import { MeshLoadRequest, } from "./types"; import { MetaballMesh } from "./rendering/MetaballMesh"; +import VolumeModel from "./VolumeModel"; export const DEFAULT_MESH_NAME = "SPHERE"; @@ -67,7 +69,8 @@ class GeometryStore { } if ( displayType === GeometryDisplayType.PDB || - displayType === GeometryDisplayType.OBJ + displayType === GeometryDisplayType.OBJ || + displayType === GeometryDisplayType.VOLUME ) { return false; } @@ -123,7 +126,10 @@ class GeometryStore { // forEach method for manipulating ThreeJs Mesh objects this._registry.forEach((value) => { const { displayType } = value; - if (displayType !== GeometryDisplayType.PDB) { + if ( + displayType !== GeometryDisplayType.PDB && + displayType !== GeometryDisplayType.VOLUME + ) { const agentGeo = value as MeshGeometry; iteratee(agentGeo); } @@ -378,6 +384,18 @@ class GeometryStore { }); } + private async fetchVolume(url: string): Promise { + // TODO should this be in a worker? Are we already in a worker here? + // Should this class get a `VolumeLoaderContext` going? + const model = new VolumeModel(); + this.setGeometryInRegistry(url, model, GeometryDisplayType.VOLUME); + const loader = await createVolumeLoader(url); + // TODO onChannelLoaded callback? + const volume = await loader.createVolume(new LoadSpec()); + model.setImage(volume); + return model; + } + /** * Load new geometry if necessary, ie this geometry hasn't already * been loaded or attempted and failed to be loaded. @@ -392,7 +410,7 @@ class GeometryStore { private async attemptToLoadGeometry( urlOrPath: string, displayType: GeometryDisplayType - ): Promise { + ): Promise { if (this._cachedAssets.has(urlOrPath)) { // if it's in the cached assets, parse the data // store it in the registry, and return it @@ -431,6 +449,8 @@ class GeometryStore { return await this.fetchPdb(urlOrPath); case GeometryDisplayType.OBJ: return await this.fetchObj(urlOrPath); + case GeometryDisplayType.VOLUME: + return await this.fetchVolume(urlOrPath); default: // will replace geom in registry is sphere throw new Error( diff --git a/src/visGeometry/VolumeModel.ts b/src/visGeometry/VolumeModel.ts new file mode 100644 index 00000000..7d3a84a2 --- /dev/null +++ b/src/visGeometry/VolumeModel.ts @@ -0,0 +1,40 @@ +import { Box3Helper, Euler, Object3D, Vector3 } from "three"; + +import { Volume, VolumeDrawable } from "@aics/volume-viewer"; + +import { AgentData } from "../simularium/types"; + +// TEMPORARY HACK to make things typecheck. TODO remove! +import { VolumeRenderImpl } from "@aics/volume-viewer/es/types/VolumeRenderImpl"; +interface TempRayMarchedVolume extends VolumeRenderImpl { + boxHelper: Box3Helper; +} + +export default class VolumeModel { + // TODO what to do with this `cancelled` property? Type check fails without it. + // When should it be set, if ever; what should it be used for, if anything? + public cancelled = false; + private image?: VolumeDrawable; + + public setImage(volumeObject: Volume): void { + this.image = new VolumeDrawable(volumeObject, {}); + } + + public setAgentData(data: AgentData): void { + if (this.image) { + this.image.setTranslation(new Vector3(data.x, data.y, data.z)); + this.image.setRotation(new Euler(data.xrot, data.yrot, data.zrot)); + const r = data.cr * 2; + this.image.setScale(new Vector3(r, r, r)); + } + } + + public getObject3D(): Object3D | undefined { + return this.image?.sceneRoot; + } + + public tempGetBoundingBoxObject(): Box3Helper | undefined { + this.image?.setShowBoundingBox(true); + return (this.image?.volumeRendering as TempRayMarchedVolume)?.boxHelper; + } +} diff --git a/src/visGeometry/index.ts b/src/visGeometry/index.ts index ef655198..0b1c8e1f 100644 --- a/src/visGeometry/index.ts +++ b/src/visGeometry/index.ts @@ -35,6 +35,7 @@ import { cloneDeep, noop } from "lodash"; import VisAgent from "./VisAgent"; import VisTypes from "../simularium/VisTypes"; import PDBModel from "./PDBModel"; +import VolumeModel from "./VolumeModel"; import AgentPath from "./agentPath"; import { FrontEndError, ErrorLevel } from "../simularium/FrontEndError"; @@ -151,6 +152,7 @@ class VisGeometry { public lightsGroup: Group; public agentPathGroup: Group; public instancedMeshGroup: Group; + public tempVolumeGroup: Group; // TODO remove private supportsWebGL2Rendering: boolean; private lodBias: number; private lodDistanceStops: number[]; @@ -217,6 +219,9 @@ class VisGeometry { this.instancedMeshGroup = new Group(); this.instancedMeshGroup.name = "instanced meshes for agents"; this.scene.add(this.instancedMeshGroup); + this.tempVolumeGroup = new Group(); + this.tempVolumeGroup.name = "volumes"; + this.scene.add(this.tempVolumeGroup); this.resetBounds(DEFAULT_VOLUME_DIMENSIONS); @@ -716,7 +721,7 @@ class VisGeometry { public onNewRuntimeGeometryType( geoName: string, displayType: GeometryDisplayType, - data: PDBModel | MeshLoadRequest + data: PDBModel | MeshLoadRequest | VolumeModel ): void { // find all typeIds for this meshName const typeIds = this.getAllTypeIdsForGeometryName(geoName); @@ -990,6 +995,9 @@ class VisGeometry { for (let i = this.instancedMeshGroup.children.length - 1; i >= 0; i--) { this.instancedMeshGroup.remove(this.instancedMeshGroup.children[i]); } + for (let i = this.tempVolumeGroup.children.length - 1; i >= 0; i--) { + this.tempVolumeGroup.remove(this.tempVolumeGroup.children[i]); + } // re-add fibers immediately this.instancedMeshGroup.add(this.fibers.getGroup()); @@ -1007,15 +1015,7 @@ class VisGeometry { const meshTypes: GeometryInstanceContainer[] = []; for (const entry of this.geometryStore.registry.values()) { const { displayType } = entry; - if (displayType !== GeometryDisplayType.PDB) { - const meshEntry = entry as MeshGeometry; - if (meshEntry.geometry.instances.instanceCount() > 0) { - meshTypes.push(meshEntry.geometry.instances); - this.instancedMeshGroup.add( - meshEntry.geometry.instances.getMesh() - ); - } - } else { + if (displayType === GeometryDisplayType.PDB) { const pdbEntry = entry as PDBGeometry; for (let i = 0; i < pdbEntry.geometry.numLODs(); ++i) { const lod = pdbEntry.geometry.getLOD(i); @@ -1024,6 +1024,19 @@ class VisGeometry { this.instancedMeshGroup.add(lod.getMesh()); } } + } else if (displayType === GeometryDisplayType.VOLUME) { + const volObject = entry.geometry.tempGetBoundingBoxObject(); + if (volObject) { + this.tempVolumeGroup.add(volObject); + } + } else { + const meshEntry = entry as MeshGeometry; + if (meshEntry.geometry.instances.instanceCount() > 0) { + meshTypes.push(meshEntry.geometry.instances); + this.instancedMeshGroup.add( + meshEntry.geometry.instances.getMesh() + ); + } } } @@ -1047,6 +1060,7 @@ class VisGeometry { this.boundingBoxMesh.visible = false; this.tickMarksMesh.visible = false; this.agentPathGroup.visible = false; + this.tempVolumeGroup.visible = false; this.renderer.render( this.threejsrenderer, this.scene, @@ -1058,6 +1072,7 @@ class VisGeometry { this.boundingBoxMesh.visible = true; this.tickMarksMesh.visible = true; this.agentPathGroup.visible = true; + this.tempVolumeGroup.visible = true; this.threejsrenderer.autoClear = false; // hide everything except the wireframe and paths, and render with the standard renderer @@ -1613,14 +1628,15 @@ class VisGeometry { } const { geometry, displayType } = response; if (geometry && displayType === GeometryDisplayType.PDB) { - const pdbEntry = geometry as PDBModel; - this.addPdbToDrawList(typeId, visAgent, pdbEntry); + this.addPdbToDrawList(typeId, visAgent, geometry); + } else if (displayType === GeometryDisplayType.VOLUME) { + // Hmm... is anyone gonna want to instance a volume? + geometry.setAgentData(agentData); } else { - const meshEntry = geometry as MeshLoadRequest; this.addMeshToDrawList( typeId, visAgent, - meshEntry, + geometry as MeshLoadRequest, agentData ); } diff --git a/src/visGeometry/types.ts b/src/visGeometry/types.ts index 3eb61f68..29d3a93d 100644 --- a/src/visGeometry/types.ts +++ b/src/visGeometry/types.ts @@ -1,6 +1,7 @@ import { BufferGeometry, Color, Object3D } from "three"; import PDBModel from "./PDBModel"; import { MRTShaders } from "./rendering/MultipassMaterials"; +import VolumeModel from "./VolumeModel"; export interface GeometryInstanceContainer { replaceGeometry: (newGeometry: BufferGeometry, name: string) => void; @@ -35,6 +36,7 @@ export enum GeometryDisplayType { OBJ = "OBJ", SPHERE = "SPHERE", CUBE = "CUBE", + VOLUME = "VOLUME", GIZMO = "GIZMO", SPHERE_GROUP = "SPHERE_GROUP", } @@ -57,11 +59,16 @@ export interface MeshGeometry { | PrimitiveDisplayType; } -export type AgentGeometry = PDBGeometry | MeshGeometry; +export interface VolumeGeometry { + geometry: VolumeModel; + displayType: GeometryDisplayType.VOLUME; +} + +export type AgentGeometry = PDBGeometry | MeshGeometry | VolumeGeometry; export interface GeometryStoreLoadResponse { displayType?: GeometryDisplayType; - geometry: MeshLoadRequest | PDBModel; + geometry: MeshLoadRequest | PDBModel | VolumeModel; errorMessage?: string; }