UNPKG

mylingo3d

Version:

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

204 lines (176 loc) 5.99 kB
import { Color, MeshStandardMaterial, RepeatWrapping, SpriteMaterial, Texture, Vector2, VideoTexture } from "three" import loadTexture from "../../utils/loaders/loadTexture" import ITexturedBasic from "../../../interface/ITexturedBasic" import { Reactive } from "@lincode/reactivity" import queueDebounce from "../../../utils/queueDebounce" import { deg2Rad } from "@lincode/math" const mapNames = ["map", "alphaMap"] const queueTextureRepeat = queueDebounce() export default abstract class TexturedBasicMixin implements ITexturedBasic { protected abstract material: MeshStandardMaterial | SpriteMaterial protected materialCloned?: boolean protected tryCloneMaterial() { if (this.materialCloned) return this.materialCloned = true //@ts-ignore this.material = this.nativeObject3d.material = this.material.clone() //@ts-ignore this.then(() => this.material.dispose()) } public get color() { return "#" + this.material.color.getHexString() } public set color(val) { this.tryCloneMaterial() this.material.color = new Color(val) } public get fog() { return this.material.fog } public set fog(val) { this.tryCloneMaterial() this.material.fog = val } private _opacity?: number public get opacity() { return (this._opacity ??= 1) } public set opacity(val) { this.tryCloneMaterial() this._opacity = val this.material.opacity = val this.material.transparent = val <= 1 //@ts-ignore this.nativeObject3d.visible = !!val } protected applyTexture(mapNames: Array<string>) { const repeat = this._textureRepeat const flipY = this._textureFlipY const rotation = this._textureRotation queueTextureRepeat(this, () => { this.tryCloneMaterial() for (const name of mapNames) { //@ts-ignore const map: Texture = this.material[name] if (!map) return repeat !== undefined && (map.repeat = repeat) flipY !== undefined && (map.flipY = flipY) rotation !== undefined && (map.rotation = rotation * deg2Rad) map.needsUpdate = true } }) } private videoTextureState?: Reactive<string | HTMLVideoElement | undefined> private textureState?: Reactive<string | undefined> private initTexture() { if (this.textureState) return this.tryCloneMaterial() const videoTextureState = (this.videoTextureState = new Reactive< string | HTMLVideoElement | undefined >(undefined)) const textureState = (this.textureState = new Reactive< string | undefined >(undefined)) //@ts-ignore this.createEffect(() => { const url = textureState.get() const videoURL = videoTextureState.get() if (videoURL) { let video: HTMLVideoElement if (typeof videoURL === "string") { video = document.createElement("video") video.crossOrigin = "anonymous" video.src = videoURL video.loop = true video.autoplay = true video.muted = true video.playsInline = true video.play() } else video = videoURL const videoTexture = new VideoTexture( video, undefined, RepeatWrapping, RepeatWrapping ) const { material } = this const { map } = material material.map = videoTexture material.needsUpdate = true this.applyTexture(mapNames) return () => { video.pause() videoTexture.dispose() material.map = map material.needsUpdate = true } } if (!url) return const { material } = this const { map } = material material.map = loadTexture(url) this.applyTexture(mapNames) return () => { material.map = map this.material.needsUpdate = true } }, [videoTextureState.get, textureState.get]) } public get videoTexture() { return this.videoTextureState?.get() } public set videoTexture(url) { this.initTexture() this.videoTextureState!.set(url) } public get texture() { return this.textureState?.get() } public set texture(url) { this.initTexture() this.textureState!.set(url) } private _alphaMap?: string public get alphaMap() { return this._alphaMap } public set alphaMap(val) { this.tryCloneMaterial() this._alphaMap = val this.material.alphaMap = val ? loadTexture(val) : null this.applyTexture(mapNames) } protected _textureRepeat?: Vector2 public get textureRepeat() { return this._textureRepeat } public set textureRepeat(val: Vector2 | number | undefined) { typeof val === "number" && (val = new Vector2(val, val)) this._textureRepeat = val this.applyTexture(mapNames) } protected _textureFlipY?: boolean public get textureFlipY() { return this._textureFlipY } public set textureFlipY(val) { this._textureFlipY = val this.applyTexture(mapNames) } protected _textureRotation?: number public get textureRotation() { return this._textureRotation } public set textureRotation(val) { this._textureRotation = val this.applyTexture(mapNames) } }