From cee01894b99b9e4f3e7f14ab1111b0ca99fd54c0 Mon Sep 17 00:00:00 2001 From: Kevin Levron Date: Tue, 4 May 2021 01:07:57 +0200 Subject: [PATCH] wip : refactor props (#54) --- src/core/Object3D.ts | 4 ++-- src/core/Renderer.ts | 6 ++--- src/materials/Material.ts | 50 ++++++++++----------------------------- src/materials/Texture.ts | 4 ++-- src/tools.ts | 25 +++++++++++++++----- 5 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/core/Object3D.ts b/src/core/Object3D.ts index 0863c8f..8b636a5 100644 --- a/src/core/Object3D.ts +++ b/src/core/Object3D.ts @@ -1,6 +1,6 @@ import { Object3D, Scene } from 'three' import { ComponentPublicInstance, defineComponent, PropType, watch } from 'vue' -import { bindOptions, bindProp } from '../tools' +import { bindObjectProp, bindProp } from '../tools' import { RendererInjectionKey, RendererInterface } from './Renderer' import { SceneInjectionKey } from './Scene' @@ -83,7 +83,7 @@ export default defineComponent({ bindProp(this, 'userData', o3d.userData) bindProp(this, 'visible', o3d) - bindOptions(o3d, this.props) + bindObjectProp(this, 'props', o3d) this.$emit('created', o3d) diff --git a/src/core/Renderer.ts b/src/core/Renderer.ts index e4f38df..d942421 100644 --- a/src/core/Renderer.ts +++ b/src/core/Renderer.ts @@ -1,8 +1,8 @@ /* eslint-disable no-use-before-define */ -import { Camera, NoToneMapping, PCFShadowMap, Scene, WebGLRenderer } from 'three' +import { Camera, Scene, WebGLRenderer } from 'three' import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer' import { ComponentPublicInstance, defineComponent, InjectionKey, PropType } from 'vue' -import { bindOptions } from '../tools' +import { bindObjectProp } from '../tools' import { PointerPublicConfigInterface } from './usePointer' import useThree, { SizeInterface, ThreeConfigInterface, ThreeInterface } from './useThree' @@ -136,7 +136,7 @@ export default defineComponent({ if (props.height) config.height = parseInt(props.height) const three = useThree(config) - bindOptions(three.renderer, props.props) + bindObjectProp(props, 'props', three.renderer) const renderFn: {(): void} = () => {} diff --git a/src/materials/Material.ts b/src/materials/Material.ts index e01847a..e614e69 100644 --- a/src/materials/Material.ts +++ b/src/materials/Material.ts @@ -1,7 +1,7 @@ -import { ComponentPublicInstance, defineComponent, InjectionKey, PropType, watch } from 'vue' -import { FrontSide, Material, NormalBlending, Texture } from 'three' +import { ComponentPublicInstance, defineComponent, InjectionKey } from 'vue' +import { Material, Texture } from 'three' import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh' -import { bindOptions } from '../tools' +import { bindObjectProp } from '../tools' export interface MaterialSetupInterface { mesh?: MeshInterface @@ -10,7 +10,6 @@ export interface MaterialSetupInterface { } export interface MaterialInterface extends MaterialSetupInterface { - setProp(key: string, value: unknown, needsUpdate: boolean): void setTexture(texture: Texture | null, key: string): void } @@ -24,16 +23,7 @@ export default defineComponent({ mesh: MeshInjectionKey as symbol, }, props: { - color: { type: [String, Number] as PropType, default: '#ffffff' }, - blending: { type: Number, default: NormalBlending }, - alphaTest: { type: Number, default: 0 }, - depthTest: { type: Boolean, default: true }, - depthWrite: { type: Boolean, default: true }, - fog: { type: Boolean, default: true }, - opacity: { type: Number, default: 1 }, - side: { type: Number, default: FrontSide }, - transparent: Boolean, - vertexColors: Boolean, + color: { type: String, default: '#ffffff' }, props: { type: Object, default: () => ({}) }, }, setup(): MaterialSetupInterface { @@ -52,38 +42,24 @@ export default defineComponent({ if (this.createMaterial) { this.material = this.createMaterial() - bindOptions(this.material, this.props) + bindObjectProp(this, 'props', this.material, this.setProp) this.mesh.setMaterial(this.material) - this.addWatchers() } }, unmounted() { this.material?.dispose() }, methods: { - setProp(key: string, value: any, needsUpdate = false) { - if (this.material) { - // @ts-ignore - this.material[key] = value - this.material.needsUpdate = needsUpdate - } + getProps() { + return { color: this.color, ...this.props } + }, + setProp(dst: any, key: string, value: any, needsUpdate = false) { + if (key === 'color') dst[key].set(value) + else dst[key] = value + dst.needsUpdate = needsUpdate }, setTexture(texture: Texture | null, key = 'map') { - this.setProp(key, texture, true) - }, - addWatchers() { - ['color', 'alphaTest', 'blending', 'depthTest', 'depthWrite', 'fog', 'opacity', 'side', 'transparent'].forEach(p => { - // @ts-ignore - watch(() => this[p], (value) => { - if (p === 'color') { - // @ts-ignore - this.material.color.set(value) - } else { - // @ts-ignore - this.material[p] = value - } - }) - }) + this.setProp(this, key, texture, true) }, }, render() { diff --git a/src/materials/Texture.ts b/src/materials/Texture.ts index a73a8d7..c0036b8 100644 --- a/src/materials/Texture.ts +++ b/src/materials/Texture.ts @@ -1,6 +1,6 @@ import { defineComponent, PropType, watch } from 'vue' import { ShaderMaterial, Texture, TextureLoader } from 'three' -import { bindOptions } from '../tools' +import { bindObjectProp } from '../tools' import { MaterialInjectionKey, MaterialInterface } from './Material' export interface TexureInterface { @@ -40,7 +40,7 @@ export default defineComponent({ initTexture() { if (!this.texture) return - bindOptions(this.texture, this.props) + bindObjectProp(this, 'props', this.texture) if (!this.material) return this.material.setTexture(this.texture, this.name) diff --git a/src/tools.ts b/src/tools.ts index d8f1d72..05ceb19 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -1,16 +1,29 @@ -import { toRef, watch } from 'vue' +import { toRef, watch, WatchStopHandle } from 'vue' -export function applyOptions(dst: any, options: Record): void { +type OptionSetter = (dst: any, key: string, value: any) => void + +export function applyObjectProps( + dst: any, + options: Record, + setter?: OptionSetter +): void { if (options instanceof Object) { Object.entries(options).forEach(([key, value]) => { - dst[key] = value + if (setter) setter(dst, key, value) + else dst[key] = value }) } } -export function bindOptions(dst: any, options: Record): void { - applyOptions(dst, options) - watch(() => options, (value) => { applyOptions(dst, value) }, { deep: true }) +export function bindObjectProp( + src: any, + prop: string, + dst: any, + setter?: OptionSetter +): WatchStopHandle { + applyObjectProps(dst, src[prop], setter) + const r = toRef(src, prop) + return watch(r, (value) => { applyObjectProps(dst, value, setter) }) } export function setFromProp(o: Record, prop: Record): void {