CAD/client/src/layers/sceneSync.ts

109 lines
3.0 KiB
TypeScript

import * as THREE from 'three';
import type { GeometryCache } from './geometryCache';
import { meshToDto, type MeshDto } from '../backend/dto/mesh';
import { model } from '../model/model';
import { Geometry } from '../backend/geometry/geometry';
import type { Id } from '../types';
export class SceneSync {
private scene: THREE.Scene;
private meshByFace: Record<Id, THREE.Mesh> = {}; // faceId → THREE.Mesh
private cache: GeometryCache;
private _selectedFaceIds: Id[] = [];
private readonly baseMaterial = new THREE.MeshPhongMaterial({
color: 0x4a7fc8, shininess: 40, specular: 0x223344, wireframe: false,
});
constructor(scene: THREE.Scene, cache: GeometryCache) {
this.scene = scene;
this.cache = cache;
}
public get selectedFaceIds() {
return this._selectedFaceIds;
}
public get meshes(): THREE.Mesh[] {
return Object.values(this.meshByFace);
}
public get items(): Record<Id, THREE.Mesh> {
return this.meshByFace;
}
addWholeModel() {
for (const id of Object.keys(model.solids)) {
const meshes = Geometry
.tessellateSolid(id)
.map(meshToDto);
this.addSolid(meshes[0]); // bottom
this.addSolid(meshes[3]); // front
// for (const mesh of meshes)
// this.addSolid(mesh);
}
}
// Called when FE scene graph syncs from BE
addSolid(dto: MeshDto) {
const faceId = dto.faceId;
if (this.meshByFace[faceId])
return;
const geo = this.cache.getOrCreate(faceId, 0, dto);
const mesh = new THREE.Mesh(geo, this.baseMaterial.clone());
mesh.userData.faceId = faceId;
mesh.userData.vertexIds = dto.vertexIds;
mesh.userData.surfaceId = dto.surfaceId;
mesh.userData.solidId = dto.solidId;
this.scene.add(mesh);
this.meshByFace[faceId] = mesh;
}
setSelected(faceIds: Id[]) {
this._selectedFaceIds = faceIds;
for (const [sid, mesh] of Object.entries(this.meshByFace)) {
const mat = mesh.material as THREE.MeshPhongMaterial;
if (faceIds.includes(sid)) {
mat.color.setHex(0xf0a040);
mat.emissive.setHex(0x221100);
}
else {
mat.color.setHex(0x4a7fc8);
mat.emissive.setHex(0x000000);
}
}
}
public disposeMesh(faceId: Id) {
const mesh = this.meshByFace[faceId];
if (!mesh)
return;
this.scene.remove(mesh);
mesh.geometry.dispose();
if (Array.isArray(mesh.material)) {
for (const mat of mesh.material)
mat.dispose();
}
else
mesh.material.dispose();
this.cache.unset(faceId, 0);
delete (this.meshByFace[faceId]);
}
public dispose() {
for (const faceId of Object.keys(this.meshByFace))
this.disposeMesh(faceId);
this.baseMaterial.dispose();
}
}