UNPKG

mylingo3d

Version:

Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor

313 lines (273 loc) 8.71 kB
import { Group, Material, Mesh, Object3D } from "three" import { boxGeometry } from "../primitives/Cube" import { wireframeMaterial } from "../utils/reusables" import ObjectManager from "./ObjectManager" import ILoaded from "../../interface/ILoaded" import { addOutline, deleteOutline } from "../../engine/renderLoop/effectComposer/outlinePass" import { addBloom, deleteBloom } from "../../engine/renderLoop/effectComposer/selectiveBloomPass/renderSelectiveBloom" import Reresolvable from "./utils/Reresolvable" import { Cancellable } from "@lincode/promiselikes" import toResolvable from "../utils/toResolvable" import MeshItem from "./MeshItem" import { Point3d } from "@lincode/math" export default abstract class Loaded<T = Object3D> extends ObjectManager<Mesh> implements ILoaded { public loadedGroup = new Group() public constructor(unmounted?: boolean) { super(new Mesh(boxGeometry, wireframeMaterial), unmounted) this.outerObject3d.add(this.loadedGroup) } public loaded = new Reresolvable<Object3D>() protected abstract load(src: string): Promise<T> protected abstract resolveLoaded(data: T, src: string): Group protected _src?: string public get src() { return this._src } public set src(val) { this._src = val this.loaded.done && this.loadedGroup.clear() this.cancelHandle( "src", val && (() => toResolvable(this.load(val)).then((loaded) => { const loadedObject3d = this.resolveLoaded(loaded, val) this.loadedGroup.add(loadedObject3d) this.loaded.resolve(loadedObject3d) this.object3d.visible = !!this._boxVisible })) ) } private _onLoad?: () => void public get onLoad() { return this._onLoad } public set onLoad(cb) { this._onLoad = cb this.cancelHandle( "onLoad", cb && (() => this.loaded.then(() => void cb())) ) } protected widthSet?: boolean public override get width() { return super.width } public override set width(val) { super.width = val this.widthSet = true } protected heightSet?: boolean public override get height() { return super.height } public override set height(val) { super.height = val this.heightSet = true } protected depthSet?: boolean public override get depth() { return super.depth } public override set depth(val) { super.depth = val this.depthSet = true } public override get innerRotationX() { return super.innerRotationX } public override set innerRotationX(val) { super.innerRotationX = val this.loadedGroup.rotation.x = this.object3d.rotation.x } public override get innerRotationY() { return super.innerRotationY } public override set innerRotationY(val) { super.innerRotationY = val this.loadedGroup.rotation.y = this.object3d.rotation.y } public override get innerRotationZ() { return super.innerRotationZ } public override set innerRotationZ(val) { super.innerRotationZ = val this.loadedGroup.rotation.z = this.object3d.rotation.z } public override get innerX() { return super.innerX } public override set innerX(val) { super.innerX = val this.loadedGroup.position.x = this.object3d.position.x } public override get innerY() { return super.innerY } public override set innerY(val) { super.innerY = val this.loadedGroup.position.y = this.object3d.position.y } public override get innerZ() { return super.innerZ } public override set innerZ(val) { super.innerZ = val this.loadedGroup.position.z = this.object3d.position.z } public override get innerVisible() { return this.loadedGroup.visible } public override set innerVisible(val) { this.loadedGroup.visible = val } public override get frustumCulled() { return super.frustumCulled } public override set frustumCulled(val) { this.outerObject3d.frustumCulled = val this.cancelHandle("frustumCulled", () => this.loaded.then(() => { super.frustumCulled = val }) ) } public override get castShadow() { return super.castShadow } public override set castShadow(val) { this._castShadow = val this.cancelHandle("castShadow", () => this.loaded.then(() => { super.castShadow = val }) ) } public override get receiveShadow() { return super.receiveShadow } public override set receiveShadow(val) { this._receiveShadow = val this.cancelHandle("receiveShadow", () => this.loaded.then(() => { super.receiveShadow = val }) ) } public override get physics() { return super.physics } public override set physics(val) { this._physics = val const handle = this.cancelHandle("physics", () => this.loaded.then(() => { this.initPhysics(val, handle!) }) ) } private _boxVisible?: boolean public get boxVisible() { return this._boxVisible ?? this.object3d.visible } public set boxVisible(val) { this._boxVisible = val this.object3d.visible = val } private _outline?: boolean public override get outline() { return !!this._outline } public override set outline(val) { this._outline = val this.cancelHandle("outline", () => this.loaded.then((loaded) => { if (!val) return addOutline(loaded) return () => { deleteOutline(loaded) } }) ) } private _bloom?: boolean public override get bloom() { return !!this._bloom } public override set bloom(val) { this._bloom = val this.cancelHandle("bloom", () => this.loaded.then((loaded) => { if (!val) return addBloom(loaded) return () => { deleteBloom(loaded) } }) ) } private managerSet?: boolean protected override addToRaycastSet(set: Set<Object3D>) { const handle = new Cancellable() queueMicrotask(() => { if (handle.done) return if (this._physics === "map" || this._physics === "map-debug") handle.watch( this.loaded.then((loaded) => { if (!this.managerSet) { this.managerSet = true loaded.traverse( (child) => (child.userData.manager ??= this) ) } set.add(loaded) return () => { set.delete(loaded) } }) ) else handle.watch(super.addToRaycastSet(set)) }) return handle } protected override refreshFactors() { this.cancelHandle("refreshFactorsLoaded", () => this.loaded.then(() => void super.refreshFactors()) ) } protected materialCloned?: boolean protected tryCloneMaterial() { if (this.materialCloned) return this.materialCloned = true this.watch( this.loaded.then((loaded) => { const cloned: Array<Material> = [] loaded.traverse((child: any) => { if (!child.material) return cloned.push((child.material = child.material.clone())) }) return () => { for (const material of cloned) material.dispose() } }) ) } public override placeAt(object: MeshItem | Point3d | string) { this.cancelHandle("placeAt", () => this.loaded.then(() => void super.placeAt(object)) ) } } export const getLoadedObject = (item: Loaded | MeshItem) => { if ("loadedGroup" in item) return item.loadedGroup if ("object3d" in item) return item.object3d return item.outerObject3d }