/* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import * as BABYLON from '@babylonjs/core'; import { defineObject, WORLD_SCALE } from '../engine.js'; import { createPlaneUvMapper } from '../utility.js'; export const allInOnePc = defineObject({ id: 'allInOnePc', name: 'All-in-One 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: async ({ room, scene, options, model }) => { const light = new BABYLON.SpotLight('', new BABYLON.Vector3(0/*cm*/, 30/*cm*/ / WORLD_SCALE, 0), new BABYLON.Vector3(0, 0, 1), Math.PI / 1, 2, scene, room?.lightContainer != null); light.parent = model.root; light.diffuse = new BABYLON.Color3(1.0, 1.0, 1.0); light.range = 999/*cm*/; if (room?.lightContainer != null) room.lightContainer.addLight(light); const screenMesh = model.findMesh('__X_SCREEN__'); const bodyMaterial = model.findMaterial('__X_BODY__'); const bezelMaterial = model.findMaterial('__X_BEZEL__'); const screenMaterial = model.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 = 50 / 27.5; updateUv(srcAspect, targetAspect, 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; tex.level = 0.5; screenMaterial.emissiveTexture = tex; tex.onLoadObservable.addOnce(() => { applyFit(); resolve(); }); } else { screenMaterial.emissiveTexture = null; resolve(); } }); await applyCustomPicture(); const applyScreenBrightness = () => { const b = options.screenBrightness; screenMaterial.emissiveColor = new BABYLON.Color3(b, b, b); light.intensity = 50000 * 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: {}, }; }, });