diff --git a/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.blend b/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.blend new file mode 100644 index 0000000000..160e1d3223 Binary files /dev/null and b/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.blend differ diff --git a/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.glb b/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.glb new file mode 100644 index 0000000000..1c8cfaf9ef Binary files /dev/null and b/packages/frontend/assets/room/objects/tabletop-flag/tabletop-flag.glb differ diff --git a/packages/frontend/src/utility/room/object-defs.ts b/packages/frontend/src/utility/room/object-defs.ts index 6d0c988a50..b7809f9af0 100644 --- a/packages/frontend/src/utility/room/object-defs.ts +++ b/packages/frontend/src/utility/room/object-defs.ts @@ -35,6 +35,8 @@ import { laptopPc } from './objects/laptopPc.js'; import { lavaLamp } from './objects/lavaLamp.js'; import { letterCase } from './objects/letterCase.js'; import { milk } from './objects/milk.js'; +import { miPlate } from './objects/miPlate.js'; +import { miPlateDisplayed } from './objects/miPlateDisplayed.js'; import { mixer } from './objects/mixer.js'; import { monitor } from './objects/monitor.js'; import { monitorSpeaker } from './objects/monitorSpeaker.js'; @@ -58,6 +60,7 @@ import { speaker } from './objects/speaker.js'; import { steelRack } from './objects/steelRack.js'; import { tabletopCalendar } from './objects/tabletopCalendar.js'; import { tabletopDigitalClock } from './objects/tabletopDigitalClock.js'; +import { tabletopFlag } from './objects/tabletopFlag.js'; import { tabletopPictureFrame } from './objects/tabletopPictureFrame.js'; import { tapestry } from './objects/tapestry.js'; import { tetrapod } from './objects/tetrapod.js'; @@ -99,6 +102,8 @@ export const OBJECT_DEFS = [ lavaLamp, letterCase, milk, + miPlate, + miPlateDisplayed, mixer, monitor, monitorSpeaker, @@ -122,6 +127,7 @@ export const OBJECT_DEFS = [ steelRack, tabletopCalendar, tabletopDigitalClock, + tabletopFlag, tabletopPictureFrame, tapestry, tetrapod, diff --git a/packages/frontend/src/utility/room/objects/allInOnePc.ts b/packages/frontend/src/utility/room/objects/allInOnePc.ts index 9c2f24fdb8..1f63f4e20f 100644 --- a/packages/frontend/src/utility/room/objects/allInOnePc.ts +++ b/packages/frontend/src/utility/room/objects/allInOnePc.ts @@ -89,6 +89,7 @@ export const allInOnePc = defineObject({ tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.level = 0.5; + screenMaterial.unfreeze(); screenMaterial.emissiveTexture = tex; tex.onLoadObservable.addOnce(() => { diff --git a/packages/frontend/src/utility/room/objects/laptopPc.ts b/packages/frontend/src/utility/room/objects/laptopPc.ts index db05885028..bc723160f9 100644 --- a/packages/frontend/src/utility/room/objects/laptopPc.ts +++ b/packages/frontend/src/utility/room/objects/laptopPc.ts @@ -98,6 +98,7 @@ export const laptopPc = defineObject({ tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.level = 0.5; + screenMaterial.unfreeze(); screenMaterial.emissiveTexture = tex; tex.onLoadObservable.addOnce(() => { diff --git a/packages/frontend/src/utility/room/objects/pictureFrame.ts b/packages/frontend/src/utility/room/objects/pictureFrame.ts index 6403974217..63f48d35f6 100644 --- a/packages/frontend/src/utility/room/objects/pictureFrame.ts +++ b/packages/frontend/src/utility/room/objects/pictureFrame.ts @@ -164,6 +164,7 @@ export const pictureFrame = defineObject({ tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + pictureMaterial.unfreeze(); pictureMaterial.albedoColor = new BABYLON.Color3(1, 1, 1); pictureMaterial.albedoTexture = tex; diff --git a/packages/frontend/src/utility/room/objects/poster.ts b/packages/frontend/src/utility/room/objects/poster.ts index 3fa42b7b0f..f880cdfb25 100644 --- a/packages/frontend/src/utility/room/objects/poster.ts +++ b/packages/frontend/src/utility/room/objects/poster.ts @@ -92,6 +92,7 @@ export const poster = defineObject({ tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + pictureMaterial.unfreeze(); pictureMaterial.albedoColor = new BABYLON.Color3(1, 1, 1); pictureMaterial.albedoTexture = tex; diff --git a/packages/frontend/src/utility/room/objects/tabletopFlag.ts b/packages/frontend/src/utility/room/objects/tabletopFlag.ts new file mode 100644 index 0000000000..27c4f2342f --- /dev/null +++ b/packages/frontend/src/utility/room/objects/tabletopFlag.ts @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as BABYLON from '@babylonjs/core'; +import { defineObject } from '../engine.js'; +import { createPlaneUvMapper } from '../utility.js'; + +export const tabletopFlag = defineObject({ + id: 'tabletopFlag', + name: 'Tabletop flag', + options: { + schema: { + customPicture: { + type: 'image', + label: 'Custom picture', + }, + fit: { + type: 'enum', + label: 'Custom picture fit', + enum: ['cover', 'contain', 'stretch'], + }, + }, + default: { + customPicture: null, + fit: 'cover', + }, + }, + placement: 'top', + createInstance: async ({ model, options, scene }) => { + const flagMesh = model.findMesh('__X_FLAG__'); + const flagMaterial = model.findMaterial('__X_FLAG__'); + + const updateUv = createPlaneUvMapper(flagMesh); + + const applyFit = () => { + const tex = flagMaterial.albedoTexture; + if (tex == null) return; + + const srcWidth = tex.getSize().width; + const srcHeight = tex.getSize().height; + const srcAspect = srcWidth / srcHeight; + + updateUv(srcAspect, 24 / 16, options.fit); + + model.updated(); + }; + + applyFit(); + + const applyCustomPicture = () => new Promise((resolve) => { + if (options.customPicture != null) { + const tex = new BABYLON.Texture(options.customPicture, scene, false, false); + tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; + tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + + flagMaterial.unfreeze(); + flagMaterial.albedoColor = new BABYLON.Color3(1, 1, 1); + flagMaterial.albedoTexture = tex; + + tex.onLoadObservable.addOnce(() => { + applyFit(); + resolve(); + }); + } else { + flagMaterial.albedoColor = new BABYLON.Color3(0.5, 0.5, 0.5); + flagMaterial.albedoTexture = null; + resolve(); + } + }); + + await applyCustomPicture(); + + return { + onOptionsUpdated: ([k, v]) => { + switch (k) { + case 'customPicture': applyCustomPicture(); break; + case 'fit': applyFit(); break; + } + }, + interactions: {}, + }; + }, +}); diff --git a/packages/frontend/src/utility/room/objects/tabletopPictureFrame.ts b/packages/frontend/src/utility/room/objects/tabletopPictureFrame.ts index 4163812769..b09e04dfdd 100644 --- a/packages/frontend/src/utility/room/objects/tabletopPictureFrame.ts +++ b/packages/frontend/src/utility/room/objects/tabletopPictureFrame.ts @@ -169,6 +169,7 @@ export const tabletopPictureFrame = defineObject({ tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + pictureMaterial.unfreeze(); pictureMaterial.albedoColor = new BABYLON.Color3(1, 1, 1); pictureMaterial.albedoTexture = tex; diff --git a/packages/frontend/src/utility/room/objects/tapestry.ts b/packages/frontend/src/utility/room/objects/tapestry.ts index 25b9918b73..fe9e47e94f 100644 --- a/packages/frontend/src/utility/room/objects/tapestry.ts +++ b/packages/frontend/src/utility/room/objects/tapestry.ts @@ -96,6 +96,7 @@ export const tapestry = defineObject({ tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + pictureMaterial.unfreeze(); pictureMaterial.albedoColor = new BABYLON.Color3(1, 1, 1); pictureMaterial.albedoTexture = tex;