diff --git a/packages/frontend/assets/room/objects/steel-rack/60-35.glb b/packages/frontend/assets/room/objects/steel-rack/60-35.glb new file mode 100644 index 0000000000..e40a1e3fa1 Binary files /dev/null and b/packages/frontend/assets/room/objects/steel-rack/60-35.glb differ diff --git a/packages/frontend/assets/room/objects/steel-rack/pole-normal.png b/packages/frontend/assets/room/objects/steel-rack/pole-normal.png new file mode 100644 index 0000000000..fe6d27a871 Binary files /dev/null and b/packages/frontend/assets/room/objects/steel-rack/pole-normal.png differ diff --git a/packages/frontend/assets/room/objects/steel-rack/steel-rack.blend b/packages/frontend/assets/room/objects/steel-rack/steel-rack.blend index 51b84a26bc..085f176533 100644 Binary files a/packages/frontend/assets/room/objects/steel-rack/steel-rack.blend and b/packages/frontend/assets/room/objects/steel-rack/steel-rack.blend differ diff --git a/packages/frontend/assets/room/objects/steel-rack/steel-rack.glb b/packages/frontend/assets/room/objects/steel-rack/steel-rack.glb deleted file mode 100644 index bf8fa809e8..0000000000 Binary files a/packages/frontend/assets/room/objects/steel-rack/steel-rack.glb and /dev/null differ diff --git a/packages/frontend/src/world/room/object-defs.ts b/packages/frontend/src/world/room/object-defs.ts index 1b1e965c83..d6bda2504a 100644 --- a/packages/frontend/src/world/room/object-defs.ts +++ b/packages/frontend/src/world/room/object-defs.ts @@ -88,7 +88,7 @@ import { speakerStand } from './objects/speakerStand.js'; import { spotLight } from './objects/spotLight.js'; import { sprayer } from './objects/sprayer.js'; import { stanchionPole } from './objects/stanchionPole.js'; -import { steelRack } from './objects/steelRack.js'; +import { steelRack60x35 } from './objects/steelRack.js'; import { stormGlass } from './objects/stormGlass.js'; import { tableSalt } from './objects/tableSalt.js'; import { tabletopCalendar } from './objects/tabletopCalendar.js'; @@ -193,7 +193,7 @@ export const OBJECT_DEFS = [ speaker, speakerStand, sprayer, - steelRack, + steelRack60x35, stormGlass, tableSalt, tabletopCalendar, diff --git a/packages/frontend/src/world/room/objects/steelRack.ts b/packages/frontend/src/world/room/objects/steelRack.ts index 0df243423a..32d9f3215e 100644 --- a/packages/frontend/src/world/room/objects/steelRack.ts +++ b/packages/frontend/src/world/room/objects/steelRack.ts @@ -3,20 +3,203 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { defineObject } from '../object.js'; +import * as BABYLON from '@babylonjs/core'; +import { defineObjectClass } from '../object.js'; +import { cm, remap } from '@/world/utility.js'; -export const steelRack = defineObject({ - id: 'steelRack', - name: 'Steel Rack', +const base = defineObjectClass({ options: { - schema: {}, - default: {}, + schema: { + height: { + type: 'range', + label: 'Height', + min: 1, + max: 7, + step: 1, + }, + numberOfShelfs: { + type: 'range', + label: '# of shelfs', + min: 2, + max: 10, + step: 1, + }, + shelf1Position: { + type: 'range', + label: 'Shelf1 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf2Position: { + type: 'range', + label: 'Shelf2 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf3Position: { + type: 'range', + label: 'Shelf3 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf4Position: { + type: 'range', + label: 'Shelf4 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf5Position: { + type: 'range', + label: 'Shelf5 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf6Position: { + type: 'range', + label: 'Shelf6 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf7Position: { + type: 'range', + label: 'Shelf7 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf8Position: { + type: 'range', + label: 'Shelf8 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf9Position: { + type: 'range', + label: 'Shelf9 position', + min: 0, + max: 1, + step: 0.01, + }, + shelf10Position: { + type: 'range', + label: 'Shelf10 position', + min: 0, + max: 1, + step: 0.01, + }, + }, + default: { + height: 3, + numberOfShelfs: 4, + shelf1Position: 0.1, + shelf2Position: 0.2, + shelf3Position: 0.3, + shelf4Position: 0.4, + shelf5Position: 0.5, + shelf6Position: 0.6, + shelf7Position: 0.7, + shelf8Position: 0.8, + shelf9Position: 0.9, + shelf10Position: 1, + }, }, placement: 'floor', hasCollisions: true, - createInstance: () => { + hasTexture: true, + createInstance: ({ options, model }) => { + const matrix = model.root.getWorldMatrix(true); + const scale = new BABYLON.Vector3(); + matrix.decompose(scale); + + const pole = model.findMesh('__X_POLE__'); + const shelf = model.findTransformNode('__X_SHELF__'); + + const clonedPoleMeshes = [] as BABYLON.Mesh[]; + const clonedShelfMeshes = [] as BABYLON.TransformNode[]; + + const applyShelfPositions = () => { + for (let i = 0; i < clonedShelfMeshes.length + 1; i++) { + const shelfMesh = i === 0 ? shelf : clonedShelfMeshes[i - 1]; + const pos = + i === 0 ? options.shelf1Position : + i === 1 ? options.shelf2Position : + i === 2 ? options.shelf3Position : + i === 3 ? options.shelf4Position : + i === 4 ? options.shelf5Position : + i === 5 ? options.shelf6Position : + i === 6 ? options.shelf7Position : + i === 7 ? options.shelf8Position : + i === 8 ? options.shelf9Position : + options.shelf10Position; + shelfMesh.position.y = remap(pos, 0, 1, cm(5), cm(30) * options.height) / Math.abs(scale.y); + } + }; + + const applyNumberOfShelfs = () => { + for (const mesh of clonedShelfMeshes) { + mesh.dispose(); + } + clonedShelfMeshes.length = 0; + + for (let i = 0; i < options.numberOfShelfs - 1; i++) { + const clonedShelf = shelf.clone(`__X_SHELF_CLONE_${i}__`, shelf.parent); + clonedShelf.isVisible = true; + clonedShelfMeshes.push(clonedShelf); + } + + applyShelfPositions(); + }; + + applyNumberOfShelfs(); + + const applyHeight = () => { + for (const mesh of clonedPoleMeshes) { + mesh.dispose(); + } + clonedPoleMeshes.length = 0; + + for (let i = 1; i < options.height; i++) { + const clonedPole = pole.clone(`__X_POLE_CLONE_${i}__`); + clonedPole.position.y = (i * cm(30)) / Math.abs(scale.y); + clonedPoleMeshes.push(clonedPole); + } + + applyShelfPositions(); + }; + + applyHeight(); + return { + onOptionsUpdated: ([k, v]) => { + switch (k) { + case 'height': applyHeight(); break; + case 'numberOfShelfs': applyNumberOfShelfs(); break; + case 'shelf1Position': + case 'shelf2Position': + case 'shelf3Position': + case 'shelf4Position': + case 'shelf5Position': + case 'shelf6Position': + case 'shelf7Position': + case 'shelf8Position': + case 'shelf9Position': + case 'shelf10Position': applyShelfPositions(); break; + } + }, interactions: {}, }; }, }); + +export const steelRack60x35 = base.extend({ + id: 'steelRack60x35', + name: 'steelRack60x35', + path: 'steel-rack/60-35', +});