From 86119d5a7bcbdcaca447c57e3c3795f7437e43d9 Mon Sep 17 00:00:00 2001 From: Georg Hackenberg Date: Sat, 2 Dec 2023 08:05:54 +0100 Subject: [PATCH] start working on custom ldraw loading mechanism --- packages/frontend/package.json | 1 + .../frontend/src/scripts/loaders/ldraw.ts | 73 +++++++++++++++++-- packages/ldraw/src/model.ts | 5 ++ packages/ldraw/src/parser.ts | 2 +- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index bc6ef45c..b3429f6f 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -47,6 +47,7 @@ "plausible-tracker": "^0.3.8", "process": "^0.11.10", "productboard-common": "^0.0.1", + "productboard-ldraw": "^0.0.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-helmet": "^6.1.0", diff --git a/packages/frontend/src/scripts/loaders/ldraw.ts b/packages/frontend/src/scripts/loaders/ldraw.ts index 91639b6d..4d695810 100644 --- a/packages/frontend/src/scripts/loaders/ldraw.ts +++ b/packages/frontend/src/scripts/loaders/ldraw.ts @@ -1,11 +1,14 @@ -import { Group, LoadingManager } from "three" +import axios from "axios" +import * as THREE from "three" import { LDrawLoader } from "three/examples/jsm/loaders/LDrawLoader" +import { Model, Parser, Reference } from "productboard-ldraw" + import { CacheAPI } from "../clients/cache" const TEXT_DECODER = new TextDecoder() -const LOADING_MANAGER = new LoadingManager().setURLModifier(url => { +const LOADING_MANAGER = new THREE.LoadingManager().setURLModifier(url => { if (url.indexOf('/') == -1) { return `/rest/parts/${url}` } else { @@ -15,27 +18,85 @@ const LOADING_MANAGER = new LoadingManager().setURLModifier(url => { const LDRAW_LOADER = new LDrawLoader(LOADING_MANAGER) -/* LDRAW_LOADER.preloadMaterials('/rest/parts/LDConfig.ldr').then(() => { // console.log('Materials loaded!') }).catch(error => { console.error(error) }) -*/ export async function loadLDrawModel(path: string) { const file = await CacheAPI.loadFile(path) return parseLDrawModel(TEXT_DECODER.decode(file)) } +export async function loadLDrawPath(path: string) { + const response = await axios.get(path) + return parseLDrawModel(response.data) +} + export async function parseLDrawModel(data: string) { - return new Promise(resolve => { + return new Promise(resolve => { // eslint-disable-next-line @typescript-eslint/no-explicit-any - (LDRAW_LOADER as any).parse(data, (group: Group) => { + (LDRAW_LOADER as any).parse(data, (group: THREE.Group) => { // Fix coordinates group.rotation.x = Math.PI // Resolve resolve(group) }) }) +} + +const PARSER = new Parser() + +export class LDrawModelHandle { + private active = true + + public readonly root = new THREE.Group() + + constructor(private path: string) { + CacheAPI.loadFile(path).then(data => this.parseData(data)) + } + + public stop() { + this.active = false + } + + private parseData(data: ArrayBuffer) { + if (this.active) { + this.parseText(TEXT_DECODER.decode(data)) + } + } + private parseText(text: string) { + if (this.active) { + this.processModel(new THREE.MeshBasicMaterial({ color: 0x00ff00 }), new THREE.LineBasicMaterial({ color: 0x0000ff }), this.root, PARSER.parse(text, this.path)) + } + } + + private processModel(face: THREE.Material, edge: THREE.Material, parent: THREE.Group, model: Model) { + for (const reference of model.references) { + this.processReference(face, edge, parent, model, reference) + } + } + private async processReference(face: THREE.Material, edge: THREE.Material, parent: THREE.Group, model: Model, reference: Reference) { + const position = reference.position + const orientation = reference.orientation + const child = new THREE.Group() + child.name = reference.file + child.matrix.set( + orientation.a, orientation.b, orientation.c, 0, + orientation.d, orientation.e, orientation.f, 0, + orientation.g, orientation.h, orientation.i, 0, + position.x, position.y, position.z, 1 + ) + parent.add(child) + if (model.fileIndex[reference.file]) { + this.processModel(face, edge, child, model.fileIndex[reference.file]) + } else { + if (reference.file.indexOf('/') == -1) { + parent.add(await loadLDrawPath(`/rest/parts/${reference.file}`)) + } else { + parent.add(await loadLDrawPath(`/rest/parts/${reference.file.substring(reference.file.lastIndexOf('/') + 1)}`)) + } + } + } } \ No newline at end of file diff --git a/packages/ldraw/src/model.ts b/packages/ldraw/src/model.ts index 7d6e27be..09f89d8a 100644 --- a/packages/ldraw/src/model.ts +++ b/packages/ldraw/src/model.ts @@ -81,6 +81,9 @@ export class Model { public colors: Color[] = [] public files: Model[] = [] + public colorIndex: {[code: number]: Color} = {} + public fileIndex: {[name: string]: Model} = {} + constructor(public url: string= undefined, public parent: Model = null) {} private addEntry(entry: Entry) { @@ -119,9 +122,11 @@ export class Model { addColor(color: Color) { this.colors.push(color) + this.colorIndex[color.code] = color } addFile(file: Model) { this.files.push(file) + this.fileIndex[file.url] = file } } \ No newline at end of file diff --git a/packages/ldraw/src/parser.ts b/packages/ldraw/src/parser.ts index a673fff2..367afa4d 100644 --- a/packages/ldraw/src/parser.ts +++ b/packages/ldraw/src/parser.ts @@ -20,7 +20,7 @@ export class Parser { const lines = text.split('\n') for (const line of lines) { - this.parseEntry(context, line) + this.parseEntry(context, line.trim()) } }