mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-20 04:45:31 +02:00
wip
This commit is contained in:
@@ -255,11 +255,11 @@ export class RoomController {
|
||||
}
|
||||
}
|
||||
|
||||
public addObject(type: string) {
|
||||
public addObject(type: string, options: any) {
|
||||
if (this.worker != null) {
|
||||
this.worker.postMessage({ type: 'addObject', objectType: type });
|
||||
this.worker.postMessage({ type: 'addObject', objectType: type, objectOptions: options });
|
||||
} else if (this.engine != null) {
|
||||
this.engine.addObject(type);
|
||||
this.engine.addObject(type, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
||||
public camera: BABYLON.UniversalCamera;
|
||||
public objectEntities: Map<string, {
|
||||
rootMesh: BABYLON.Mesh;
|
||||
instance: RoomObjectInstance<any>;
|
||||
instance: RoomObjectInstance;
|
||||
model: ModelManager;
|
||||
}> = new Map();
|
||||
private heyaManager: HeyaManager | null = null;
|
||||
@@ -1433,7 +1433,7 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
||||
return ghost;
|
||||
}
|
||||
|
||||
public async addObject(type: string) {
|
||||
public async addObject(type: string, _options?: any) {
|
||||
if (!this.isEditMode) return;
|
||||
if (this.grabbingCtx != null) return;
|
||||
this.selectObject(null);
|
||||
@@ -1445,7 +1445,7 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
|
||||
|
||||
const def = getObjectDef(type);
|
||||
|
||||
const options = deepClone(def.options.default);
|
||||
const options = _options != null ? deepClone(_options) : deepClone(def.options.default);
|
||||
|
||||
const { root } = await this.loadObject({
|
||||
id: id,
|
||||
|
||||
@@ -22,7 +22,7 @@ export type RoomStateObject<Options = any> = {
|
||||
sticky?: string | null;
|
||||
};
|
||||
|
||||
export type RoomObjectInstance<Options> = {
|
||||
export type RoomObjectInstance<Options = any> = {
|
||||
onInited?: () => void;
|
||||
onOptionsUpdated?: <K extends keyof Options, V extends Options[K]>(kv: [K, V]) => void;
|
||||
interactions: Record<string, {
|
||||
@@ -71,7 +71,12 @@ type ImageOptionSchema = {
|
||||
label: string;
|
||||
};
|
||||
|
||||
type OptionsSchema = Record<string, NumberOptionSchema | BooleanOptionSchema | ColorOptionSchema | EnumOptionSchema | RangeOptionSchema | ImageOptionSchema>;
|
||||
type SeedOptionSchema = {
|
||||
type: 'seed';
|
||||
label: string;
|
||||
};
|
||||
|
||||
type OptionsSchema = Record<string, NumberOptionSchema | BooleanOptionSchema | ColorOptionSchema | EnumOptionSchema | RangeOptionSchema | ImageOptionSchema | SeedOptionSchema>;
|
||||
|
||||
type GetOptionsSchemaValues<T extends OptionsSchema> = {
|
||||
[K in keyof T]:
|
||||
@@ -81,6 +86,7 @@ type GetOptionsSchemaValues<T extends OptionsSchema> = {
|
||||
T[K] extends EnumOptionSchema ? T[K]['enum'][number] :
|
||||
T[K] extends RangeOptionSchema ? number :
|
||||
T[K] extends ImageOptionSchema ? string | null :
|
||||
T[K] extends SeedOptionSchema ? number :
|
||||
never;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,11 +33,8 @@ export const randomBooks = defineObject({
|
||||
label: 'Stack vertically',
|
||||
},
|
||||
seed: {
|
||||
type: 'range',
|
||||
type: 'seed',
|
||||
label: 'Seed',
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 1,
|
||||
},
|
||||
},
|
||||
default: {
|
||||
@@ -51,7 +48,7 @@ export const randomBooks = defineObject({
|
||||
hasCollisions: false,
|
||||
hasTexture: true,
|
||||
canPreMeshesMerging: false,
|
||||
createInstance: ({ options, model, scene, id }) => {
|
||||
createInstance: ({ options, model, scene }) => {
|
||||
const bodyMesh = model.findMesh('__X_BODY__');
|
||||
const tex = new BABYLON.Texture('/client-assets/room/objects/random-books/texture.png', scene, {
|
||||
invertY: false,
|
||||
@@ -69,7 +66,7 @@ export const randomBooks = defineObject({
|
||||
}
|
||||
bookMeshes = [];
|
||||
|
||||
const rng = seedrandom(options.seed === 0 ? id : options.seed.toString());
|
||||
const rng = seedrandom(options.seed.toString());
|
||||
const randomRange = (min: number, max: number) => rng() * (max - min) + min;
|
||||
|
||||
let accumulatedPos = 0;
|
||||
|
||||
@@ -28,7 +28,8 @@ export class RoomObjectPreviewEngine {
|
||||
private shadowGenerator: BABYLON.ShadowGenerator;
|
||||
private camera: BABYLON.ArcRotateCamera;
|
||||
private objectMesh: BABYLON.Mesh | null = null;
|
||||
private objectInstance: RoomObjectInstance<any> | null = null;
|
||||
private objectInstance: RoomObjectInstance | null = null;
|
||||
private objectOptions: any = null;
|
||||
private objectType: string | null = null;
|
||||
private envMapIndoor: BABYLON.CubeTexture;
|
||||
private roomLight: BABYLON.SpotLight;
|
||||
@@ -152,21 +153,20 @@ export class RoomObjectPreviewEngine {
|
||||
}
|
||||
|
||||
public async load(type: string) {
|
||||
if (this.objectInstance != null) {
|
||||
this.objectInstance.dispose?.();
|
||||
this.objectInstance = null;
|
||||
this.objectMesh!.dispose();
|
||||
}
|
||||
|
||||
const def = getObjectDef(type);
|
||||
|
||||
const options = deepClone(def.options.default);
|
||||
this.clear();
|
||||
|
||||
const id = genId();
|
||||
const def = getObjectDef(type);
|
||||
this.objectOptions = deepClone(def.options.default);
|
||||
for (const [key, value] of Object.entries(def.options.schema)) {
|
||||
if (value.type === 'seed') {
|
||||
this.objectOptions[key] = Math.floor(Math.random() * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
await this.loadObject({
|
||||
type,
|
||||
options,
|
||||
options: this.objectOptions,
|
||||
id,
|
||||
});
|
||||
|
||||
@@ -214,6 +214,12 @@ export class RoomObjectPreviewEngine {
|
||||
//this.camera.orthoTop = distance;
|
||||
//this.camera.orthoBottom = -distance;
|
||||
}, 10);
|
||||
|
||||
return {
|
||||
id,
|
||||
objectInstance: this.objectInstance,
|
||||
options: this.objectOptions,
|
||||
};
|
||||
}
|
||||
|
||||
private async loadObject(args: {
|
||||
@@ -236,10 +242,8 @@ export class RoomObjectPreviewEngine {
|
||||
|
||||
root.addChild(subRoot);
|
||||
|
||||
const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m !== subRoot), def.hasTexture, (meshes) => {
|
||||
for (const m of meshes) {
|
||||
const mesh = m;
|
||||
|
||||
const updateMeshes = (meshes: BABYLON.AbstractMesh[]) => {
|
||||
for (const mesh of meshes) {
|
||||
// シェイプキー(morph)を考慮してbounding boxを更新するために必要
|
||||
mesh.refreshBoundingInfo({ applyMorph: true });
|
||||
|
||||
@@ -269,11 +273,14 @@ export class RoomObjectPreviewEngine {
|
||||
|
||||
if (!this.scene.meshes.includes(mesh)) this.scene.addMesh(mesh);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m !== subRoot), def.hasTexture, (meshes) => {
|
||||
updateMeshes(meshes);
|
||||
});
|
||||
|
||||
if (this.timerForEachObject != null) {
|
||||
this.timerForEachObject.dispose();
|
||||
}
|
||||
updateMeshes(subRoot.getChildMeshes());
|
||||
|
||||
this.timerForEachObject = new Timer();
|
||||
|
||||
const objectInstance = await def.createInstance({
|
||||
@@ -288,17 +295,31 @@ export class RoomObjectPreviewEngine {
|
||||
|
||||
objectInstance.onInited?.();
|
||||
|
||||
model.bakeMesh();
|
||||
|
||||
this.objectType = args.type;
|
||||
this.objectInstance = objectInstance;
|
||||
this.objectMesh = root;
|
||||
}
|
||||
|
||||
public updateObjectOption(key: string, value: any) {
|
||||
this.objectOptions[key] = value;
|
||||
this.objectInstance?.onOptionsUpdated?.([key, value]);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
if (this.timerForEachObject != null) {
|
||||
this.timerForEachObject.dispose();
|
||||
this.timerForEachObject = null;
|
||||
}
|
||||
if (this.objectInstance != null) {
|
||||
this.objectInstance.dispose?.();
|
||||
this.objectInstance = null;
|
||||
this.objectOptions = null;
|
||||
this.objectMesh!.dispose();
|
||||
this.objectMesh = null;
|
||||
this.objectType = null;
|
||||
}
|
||||
}
|
||||
|
||||
public resize() {
|
||||
this.engine.resize();
|
||||
}
|
||||
|
||||
@@ -589,3 +589,21 @@ export function getYRotationDirection(rotationY: number): '+x' | '+z' | '-x' | '
|
||||
return '+x';
|
||||
}
|
||||
}
|
||||
|
||||
export function getHex(c: [number, number, number]) {
|
||||
return `#${c.map(x => Math.round(x * 255).toString(16).padStart(2, '0')).join('')}`;
|
||||
}
|
||||
|
||||
export function getRgb(hex: string | number): [number, number, number] | null {
|
||||
if (
|
||||
typeof hex === 'number' ||
|
||||
typeof hex !== 'string' ||
|
||||
!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const m = hex.slice(1).match(/[0-9a-fA-F]{2}/g);
|
||||
if (m == null) return [0, 0, 0];
|
||||
return m.map(x => parseInt(x, 16) / 255) as [number, number, number];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user