diff --git a/packages/frontend/assets/room/objects/debug-hipoly/debug-hipoly.glb b/packages/frontend/assets/room/objects/debug-hipoly/debug-hipoly.glb new file mode 100644 index 0000000000..9ccfe560e0 Binary files /dev/null and b/packages/frontend/assets/room/objects/debug-hipoly/debug-hipoly.glb differ diff --git a/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.blend b/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.blend new file mode 100644 index 0000000000..312675f316 Binary files /dev/null and b/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.blend differ diff --git a/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.glb b/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.glb new file mode 100644 index 0000000000..6961f16130 Binary files /dev/null and b/packages/frontend/assets/room/objects/laptop-pc/laptop-pc.glb differ diff --git a/packages/frontend/assets/room/objects/laptop-pc/textures/keyboard.png b/packages/frontend/assets/room/objects/laptop-pc/textures/keyboard.png new file mode 100644 index 0000000000..8cee6c3087 Binary files /dev/null and b/packages/frontend/assets/room/objects/laptop-pc/textures/keyboard.png differ diff --git a/packages/frontend/src/utility/room/object-defs.ts b/packages/frontend/src/utility/room/object-defs.ts index de45460f2d..85be80d0d6 100644 --- a/packages/frontend/src/utility/room/object-defs.ts +++ b/packages/frontend/src/utility/room/object-defs.ts @@ -20,6 +20,7 @@ import { ceilingFanLight } from './objects/ceilingFanLight.js'; import { chair } from './objects/chair.js'; import { colorBox } from './objects/colorBox.js'; import { cupNoodle } from './objects/cupNoodle.js'; +import { debugHipoly } from './objects/debugHipoly.js'; import { desk } from './objects/desk.js'; import { ductTape } from './objects/ductTape.js'; import { emptyBento } from './objects/emptyBento.js'; @@ -28,6 +29,7 @@ import { envelope } from './objects/envelope.js'; import { facialTissue } from './objects/facialTissue.js'; import { hangingTShirt } from './objects/hangingTShirt.js'; import { keyboard } from './objects/keyboard.js'; +import { laptopPc } from './objects/laptopPc.js'; import { lavaLamp } from './objects/lavaLamp.js'; import { letterCase } from './objects/letterCase.js'; import { milk } from './objects/milk.js'; @@ -87,6 +89,7 @@ export const OBJECT_DEFS = [ facialTissue, hangingTShirt, keyboard, + laptopPc, lavaLamp, letterCase, milk, @@ -119,6 +122,7 @@ export const OBJECT_DEFS = [ wallClock, wallShelf, woodSoundAbsorbingPanel, + debugHipoly, ]; export function getObjectDef(type: string): typeof OBJECT_DEFS[number] { diff --git a/packages/frontend/src/utility/room/objects/debugHipoly.ts b/packages/frontend/src/utility/room/objects/debugHipoly.ts new file mode 100644 index 0000000000..2df52ba401 --- /dev/null +++ b/packages/frontend/src/utility/room/objects/debugHipoly.ts @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { defineObject } from '../engine.js'; + +export const debugHipoly = defineObject({ + id: 'debugHipoly', + name: 'debugHipoly', + options: { + schema: {}, + default: {}, + }, + placement: 'top', + createInstance: () => { + return { + interactions: {}, + }; + }, +}); diff --git a/packages/frontend/src/utility/room/objects/laptopPc.ts b/packages/frontend/src/utility/room/objects/laptopPc.ts new file mode 100644 index 0000000000..5f883e9212 --- /dev/null +++ b/packages/frontend/src/utility/room/objects/laptopPc.ts @@ -0,0 +1,127 @@ +/* + * 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 laptopPc = defineObject({ + id: 'laptopPc', + name: 'Laptop PC', + options: { + schema: { + bodyColor: { + type: 'color', + label: 'Body color', + }, + bezelColor: { + type: 'color', + label: 'Bezel color', + }, + screenBrightness: { + type: 'range', + label: 'Screen brightness', + min: 0, + max: 1, + step: 0.01, + }, + customPicture: { + type: 'image', + label: 'Custom picture', + }, + fit: { + type: 'enum', + label: 'Custom picture fit', + enum: ['cover', 'contain', 'stretch'], + }, + }, + default: { + bodyColor: [1, 1, 1], + bezelColor: [0, 0, 0], + screenBrightness: 0.35, + customPicture: null, + fit: 'cover', + }, + }, + placement: 'top', + createInstance: ({ room, options, findMesh, findMaterial }) => { + const screenMesh = findMesh('__X_SCREEN__'); + + const bodyMaterial = findMaterial('__X_BODY__'); + const bezelMaterial = findMaterial('__X_BEZEL__'); + const screenMaterial = findMaterial('__X_SCREEN__'); + + screenMaterial.ambientColor = new BABYLON.Color3(0, 0, 0); + screenMaterial.albedoColor = new BABYLON.Color3(0, 0, 0); + + const updateUv = createPlaneUvMapper(screenMesh); + + const applyFit = () => { + const tex = screenMaterial.emissiveTexture; + if (tex == null) return; + + const srcAspect = tex.getSize().width / tex.getSize().height; + const targetAspect = 31 / 19; + + updateUv(srcAspect, targetAspect, options.fit); + }; + + applyFit(); + + const applyCustomPicture = () => { + if (options.customPicture != null) { + const tex = new BABYLON.Texture(options.customPicture, room.scene, false, false); + tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; + tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; + tex.level = 0.5; + + screenMaterial.emissiveTexture = tex; + + applyFit(); + + tex.onLoadObservable.addOnce(() => { + applyFit(); + }); + } else { + screenMaterial.emissiveTexture = null; + } + }; + + applyCustomPicture(); + + const applyScreenBrightness = () => { + const b = options.screenBrightness; + screenMaterial.emissiveColor = new BABYLON.Color3(b, b, b); + }; + + applyScreenBrightness(); + + const applyBodyColor = () => { + const [r, g, b] = options.bodyColor; + bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b); + }; + + const applyBezelColor = () => { + const [r, g, b] = options.bezelColor; + bezelMaterial.albedoColor = new BABYLON.Color3(r, g, b); + }; + + applyBodyColor(); + applyBezelColor(); + + return { + onOptionsUpdated: ([k, v]) => { + switch (k) { + case 'bodyColor': applyBodyColor(); break; + case 'bezelColor': applyBezelColor(); break; + case 'screenBrightness': applyScreenBrightness(); break; + case 'customPicture': applyCustomPicture(); break; + case 'fit': applyFit(); break; + } + }, + interactions: {}, + }; + }, +});