From 543fe00b74e6324201d05b748a013c5a4fd127c6 Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Mon, 29 Aug 2022 01:36:04 +0200 Subject: [PATCH] `SvelthreeGLTF.ts` improve dx and refactor (add new) types (see #136) - rename interface `ITreeMember` to `ISvelthreeGLTFTreeMapMember` - `GLTF` is now passed via constructor, e.g. `const foo: SvelthreeGLTF = new SvelthreeGLTF(loaded_gltf_file: GLTF)` - `apply(...)` now uses a `Canvas` component reference instead of a `Canvas` DOM Element. - various `strict: true` related changes (due to `strict: true` in the SvelteKit tests project, see also #153 ) --- src/types-extra.d.ts | 14 +++++ src/utils/SvelthreeGLTF.ts | 109 +++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/types-extra.d.ts b/src/types-extra.d.ts index 413b3fc..a621747 100644 --- a/src/types-extra.d.ts +++ b/src/types-extra.d.ts @@ -213,6 +213,20 @@ export type GLTFSupportedSvelthreeComponents = Mesh | Group | Object3D | Sc /** currently unused -> check possible usage or delete */ //export type RaycastableSvelthreeComponents = Mesh | Group | Object3D +export interface ISvelthreeGLTFTreeMapMember { + obj: THREE.Object3D + parent_uuid?: string | null + name?: string | null + obj_type?: string + mesh?: { + geometry: THREE.BufferGeometry + material: THREE.Material | THREE.Material[] + } | null + svelthree_comp?: GLTFSupportedSvelthreeComponents +} + +export type SvelthreeGLTFTreeMap = Map + export interface PointerState { pos: THREE.Vector2 event: PointerEvent diff --git a/src/utils/SvelthreeGLTF.ts b/src/utils/SvelthreeGLTF.ts index 7f18ae5..708b37d 100644 --- a/src/utils/SvelthreeGLTF.ts +++ b/src/utils/SvelthreeGLTF.ts @@ -1,39 +1,30 @@ -import type { BufferGeometry, Material } from "three" import { Euler, Vector3 } from "three" import type { GLTF } from "three/examples/jsm/loaders/GLTFLoader" // import currently supported components only import { Mesh } from "../components" import { Group, Object3D } from "../components" +import type { Canvas } from "../components" -import type { GLTFSupportedSvelthreeComponents } from "../types-extra" - -interface ITreeMember { - obj: THREE.Object3D - parent_uuid?: string - name?: string - obj_type?: string - mesh?: { - geometry: BufferGeometry - material: Material | Material[] - } - svelthree_comp?: any -} +import type { + GLTFSupportedSvelthreeComponents, + SvelthreeGLTFTreeMap, + ISvelthreeGLTFTreeMapMember +} from "../types-extra" export default class SvelthreeGLTF { - public tree: Map + public tree: SvelthreeGLTFTreeMap = new Map() - constructor() { - this.tree = new Map() - } + constructor(public content: GLTF) {} - public async parse(content: GLTF): Promise> { - if (content.scenes?.length > 1) { - for (let i = 0; i < content.scenes.length; i++) { - await this.build_tree(content.scenes[i]) + /** */ + public async parse(): Promise { + if (this.content.scenes?.length > 1) { + for (let i = 0; i < this.content.scenes.length; i++) { + await this.build_tree(this.content.scenes[i]) } } else { - await this.build_tree(content.scene) + await this.build_tree(this.content.scene) } return this.tree @@ -45,7 +36,7 @@ export default class SvelthreeGLTF { const fns: (() => Promise)[] = [] const make_three_member = - (obj: THREE.Object3D, parent: THREE.Object3D | undefined, tree_map: Map) => + (obj: THREE.Object3D, parent: THREE.Object3D | undefined, tree_map: SvelthreeGLTFTreeMap) => async (): Promise => { tree_map.set(obj.uuid, { obj: obj, @@ -56,11 +47,11 @@ export default class SvelthreeGLTF { obj.type === "Mesh" ? { geometry: (obj as THREE.Mesh).geometry, material: (obj as THREE.Mesh).material } : null, - svelthree_comp: null + svelthree_comp: undefined }) } - function traverse(child: THREE.Object3D, tree_map: Map, parent?: THREE.Object3D) { + function traverse(child: THREE.Object3D, tree_map: SvelthreeGLTFTreeMap, parent?: THREE.Object3D) { fns.push(make_three_member(child, parent, tree_map)) const children = child.children @@ -78,26 +69,43 @@ export default class SvelthreeGLTF { //console.log("SvelthreeGLTF parsing FINISHED!") } - async get_parent_component(parent_uuid: string): Promise { - return this.tree.get(parent_uuid).svelthree_comp + async get_parent_component(parent_uuid: string): Promise { + const tree_member: ISvelthreeGLTFTreeMapMember | undefined = this.tree.get(parent_uuid) + + if (tree_member?.svelthree_comp) { + return tree_member?.svelthree_comp + } else { + return undefined + } } async get_parent_context(parent_component: GLTFSupportedSvelthreeComponents): Promise> { return parent_component["$$"].context } - public async apply(dom_target: HTMLElement, root_component: GLTFSupportedSvelthreeComponents): Promise { + public async apply(canvas_component: Canvas, root_component: GLTFSupportedSvelthreeComponents): Promise { //console.log("SvelthreeGLTF apply started!") const fns: (() => Promise)[] = [] const create_component = - (item: ITreeMember, dom_target: HTMLElement, root_component: GLTFSupportedSvelthreeComponents) => + ( + item: ISvelthreeGLTFTreeMapMember, + canvas_component: Canvas, + root_component: GLTFSupportedSvelthreeComponents + ) => async (): Promise => { - let context: Map = null + let context: Map if (item.parent_uuid) { const parent_component = await this.get_parent_component(item.parent_uuid) - context = await this.get_parent_context(parent_component) + if (parent_component) { + context = await this.get_parent_context(parent_component) + } else { + console.error( + `SVELTHREE > utils > SvelthreeGLTF > create_component : invalid 'parent_component' value!`, + parent_component + ) + } } else { context = root_component["$$"].context } @@ -105,16 +113,24 @@ export default class SvelthreeGLTF { switch (item.obj_type) { case "Mesh": item.svelthree_comp = new Mesh({ - target: dom_target, + target: canvas_component.getDomElement(), props: { geometry: item.mesh.geometry, material: item.mesh.material, name: item.name }, context }) break case "Object3D": - item.svelthree_comp = new Object3D({ target: dom_target, props: { name: item.name }, context }) + item.svelthree_comp = new Object3D({ + target: canvas_component.getDomElement(), + props: { name: item.name }, + context + }) break case "Group": - item.svelthree_comp = new Group({ target: dom_target, props: { name: item.name }, context }) + item.svelthree_comp = new Group({ + target: canvas_component.getDomElement(), + props: { name: item.name }, + context + }) break default: console.error( @@ -127,7 +143,11 @@ export default class SvelthreeGLTF { // const [uuid, item] -> uuid not needed -> [,item] for (const [, item] of this.tree.entries()) { - fns.push(create_component(item, dom_target, root_component)) + if (item) { + fns.push(create_component(item, canvas_component, root_component)) + } else { + console.error(`SVELTHREE > utils > SvelthreeGLTF > create_component : invalid 'item' value!`, item) + } } for (const fn of fns) { @@ -139,11 +159,18 @@ export default class SvelthreeGLTF { for (const [, item] of this.tree.entries()) { const comp = item.svelthree_comp - comp.scale = new Vector3().copy(item.obj.scale) - comp.pos = new Vector3().copy(item.obj.position) - comp.rot = new Euler().copy(item.obj.rotation) - comp.castShadow = item.obj.castShadow - comp.receiveShadow = item.obj.receiveShadow + if (comp) { + comp.scale = new Vector3().copy(item.obj.scale) + comp.pos = new Vector3().copy(item.obj.position) + comp.rot = new Euler().copy(item.obj.rotation) + comp.castShadow = item.obj.castShadow + comp.receiveShadow = item.obj.receiveShadow + } else { + console.error( + `SVELTHREE > utils > SvelthreeGLTF > create_component : invalid 'item.svelthree_comp' (comp) value!`, + comp + ) + } } //console.log("SvelthreeGLTF apply FINISHED!")