This commit is contained in:
syuilo
2026-02-20 11:39:42 +09:00
parent 41d40f53cf
commit cdc9b47b78
8 changed files with 94 additions and 7 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -33,6 +33,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="s.type === 'color'">
<MkInput :modelValue="getHex(engine.selected.value.objectState.options[k])" type="color" @update:modelValue="v => { const c = getRgb(v); if (c != null) engine.updateObjectOption(engine.selected.value.objectId, k, c); }"></MkInput>
</div>
<div v-else-if="s.type === 'enum'">
<MkSelect :items="s.enum.map(e => ({ label: e, value: e }))" :modelValue="engine.selected.value.objectState.options[k]" @update:modelValue="v => engine.updateObjectOption(engine.selected.value.objectId, k, v)"></MkSelect>
</div>
</div>
</div>
</template>
@@ -602,5 +605,7 @@ definePage(() => ({
right: 16px;
z-index: 1;
padding: 16px;
box-sizing: border-box;
width: 300px;
}
</style>

View File

@@ -25,7 +25,7 @@ import { registerBuiltInLoaders } from '@babylonjs/loaders/dynamic';
import { BoundingBoxRenderer } from '@babylonjs/core/Rendering/boundingBoxRenderer';
import { GridMaterial } from '@babylonjs/materials';
import { ShowInspector } from '@babylonjs/inspector';
import { reactive, ref, shallowRef, watch } from 'vue';
import { reactive, ref, shallowRef, triggerRef, watch } from 'vue';
import { genId } from '../id.js';
import { getObjectDef } from './object-defs.js';
import { HorizontalCameraKeyboardMoveInput } from './utility.js';
@@ -78,16 +78,16 @@ type ColorOptionSchema = {
label: string;
};
type SelectOptionSchema = {
type: 'select';
type EnumOptionSchema = {
type: 'enum';
label: string;
enum: string[];
};
type OptionsSchema = Record<string, NumberOptionSchema | ColorOptionSchema | SelectOptionSchema>;
type OptionsSchema = Record<string, NumberOptionSchema | ColorOptionSchema | EnumOptionSchema>;
type GetOptionsSchemaValues<T extends OptionsSchema> = {
[K in keyof T]: T[K] extends NumberOptionSchema ? number : T[K] extends ColorOptionSchema ? [number, number, number] : T[K] extends SelectOptionSchema ? T[K]['enum'][number] : never;
[K in keyof T]: T[K] extends NumberOptionSchema ? number : T[K] extends ColorOptionSchema ? [number, number, number] : T[K] extends EnumOptionSchema ? T[K]['enum'][number] : never;
};
type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
@@ -1213,6 +1213,10 @@ export class RoomEngine {
const obji = this.objectInstances.get(objectId);
if (obji == null) return;
obji.onOptionsUpdated?.([key, value]);
if (this.selected.value?.objectId === objectId) {
triggerRef(this.selected);
}
}
public resize() {

View File

@@ -39,6 +39,7 @@ import { tabletopCalendar } from './objects/tabletopCalendar.js';
import { tabletopDigitalClock } from './objects/tabletopDigitalClock.js';
import { tv } from './objects/tv.js';
import { wallClock } from './objects/wallClock.js';
import { wallShelf } from './objects/wallShelf.js';
import { woodSoundAbsorbingPanel } from './objects/woodSoundAbsorbingPanel.js';
export const OBJECT_DEFS = [
@@ -78,6 +79,7 @@ export const OBJECT_DEFS = [
tabletopDigitalClock,
tv,
wallClock,
wallShelf,
woodSoundAbsorbingPanel,
];

View File

@@ -13,7 +13,7 @@ export const tabletopDigitalClock = defineObject({
options: {
schema: {
bodyStyle: {
type: 'select',
type: 'enum',
label: 'Body Style',
enum: ['color', 'wood'],
},
@@ -37,7 +37,7 @@ export const tabletopDigitalClock = defineObject({
const [r, g, b] = options.bodyColor;
bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
} else {
bodyMaterial.albedoTexture = room.scene.getTextureByName('tabletop_digital_clock_wood');
}
};

View File

@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import * as BABYLON from '@babylonjs/core';
import { defineObject } from '../engine.js';
export const wallShelf = defineObject({
id: 'wallShelf',
name: 'Wall Shelf',
options: {
schema: {
style: {
type: 'enum',
label: 'Style',
enum: ['A', 'B'],
},
boardStyle: {
type: 'enum',
label: 'Board style',
enum: ['color', 'wood'],
},
boardColor: {
type: 'color',
label: 'Board color',
},
},
default: {
style: 'A',
boardStyle: 'wood',
boardColor: [1, 1, 1],
},
},
placement: 'side',
createInstance: ({ room, options, root }) => {
const applyStyle = () => {
const aMeshes = root.getChildMeshes().filter(m => m.name.includes('__X_VARIATION_A__'));
const bMeshes = root.getChildMeshes().filter(m => m.name.includes('__X_VARIATION_B__'));
for (const m of aMeshes) {
(m as BABYLON.Mesh).setEnabled(options.style === 'A');
}
for (const m of bMeshes) {
(m as BABYLON.Mesh).setEnabled(options.style === 'B');
}
};
applyStyle();
const bodyMesh = root.getChildMeshes().find(m => m.name.includes('__X_BOARD__')) as BABYLON.Mesh;
const bodyMaterial = bodyMesh.material as BABYLON.PBRMaterial;
const bodyTexture = bodyMaterial.albedoTexture as BABYLON.Texture;
const applyBoardColor = () => {
const [r, g, b] = options.boardColor;
bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
if (options.boardStyle === 'color') {
bodyMaterial.albedoTexture = null;
} else {
bodyMaterial.albedoTexture = bodyTexture;
}
};
applyBoardColor();
return {
onOptionsUpdated: ([k, v]) => {
applyStyle();
applyBoardColor();
},
interactions: {},
};
},
});