import { ComponentPropsOptions , ComponentPublicInstance , defineComponent , InjectionKey , PropType , watch } from 'vue' ; import { Color , Material , MeshBasicMaterial , MeshLambertMaterial , MeshPhongMaterial , MeshPhysicalMaterial , MeshStandardMaterial , MeshToonMaterial , PointsMaterial as TPointsMaterial , Texture , ShadowMaterial as TShadowMaterial } from 'three' ; import { MeshInjectionKey , MeshInterface } from '../meshes/Mesh' ; import { bindObjectProp , propsValues } from '../tools' ; import { BasicMaterialPropsInterface , LambertMaterialPropsInterface , MaterialPropsInterface , PhongMaterialPropsInterface , PhysicalMaterialPropsInterface , PointsMaterialPropsInterface , StandardMaterialPropsInterface , ToonMaterialPropsInterface } from './types' ; export interface MaterialSetupInterface { mesh ? : MeshInterface ; material ? : Material ; createMaterial ? ( ) : Material ; } export interface MaterialInterface extends MaterialSetupInterface { setTexture ( texture , key ) : void ; } export interface MaterialPublicInterface extends ComponentPublicInstance , MaterialInterface { } export const MaterialInjectionKey = Symbol ( 'Material' ) ; const BaseMaterial = defineComponent ( { emits : [ 'created' ] , props : { color : { type : String , default : '#ffffff' } , props : { type : Object as PropType < MaterialPropsInterface > , default : ( ) => ( { } ) } , } , inject : { mesh : MeshInjectionKey as symbol , } , setup ( ) { return { } ; } , provide ( ) { return { [ MaterialInjectionKey as symbol ] : this , } ; } , created ( ) { if ( ! this . mesh ) { console . error ( 'Missing parent Mesh' ) ; return ; } if ( this . createMaterial ) { const material = this . material = this . createMaterial ( ) ; watch ( ( ) => this . color , ( value ) => { material . color . set ( value ) ; } ) ; bindObjectProp ( this , 'props' , material , false , this . setProp ) ; this . $emit ( 'created' , material ) ; this . mesh . setMaterial ( material ) ; } } , unmounted ( ) { this . material ?. dispose ( ) ; } , methods : { getMaterialParams ( ) { return { ... propsValues ( this . $props , [ 'props' ] ) , ... this . props } ; } , setProp ( material , key , value , needsUpdate = false ) { const dstVal = material [ key ] ; if ( dstVal instanceof Color ) dstVal . set ( value ) ; else material [ key ] = value ; material . needsUpdate = needsUpdate ; } , setTexture ( texture , key = 'map' ) { this . setProp ( this . material , key , texture , true ) ; } , } , render ( ) { return this . $slots . default ? this . $slots . default ( ) : [ ] ; } , __hmrId : 'Material' , } ) ; export default BaseMaterial ; export function materialComponent < P extends Readonly < ComponentPropsOptions > > ( name , props , createMaterial ) { return defineComponent ( { name , extends : BaseMaterial , props , methods : { createMaterial ( ) { return createMaterial ( this . getMaterialParams ( ) ) ; } , } , } ) ; } export const BasicMaterial = materialComponent ( 'BasicMaterial' , { props : { type : Object as PropType < BasicMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshBasicMaterial ( opts ) ) ; export const LambertMaterial = materialComponent ( 'LambertMaterial' , { props : { type : Object as PropType < LambertMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshLambertMaterial ( opts ) ) ; export const PhongMaterial = materialComponent ( 'PhongMaterial' , { props : { type : Object as PropType < PhongMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshPhongMaterial ( opts ) ) ; export const PhysicalMaterial = materialComponent ( 'PhysicalMaterial' , { props : { type : Object as PropType < PhysicalMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshPhysicalMaterial ( opts ) ) ; export const PointsMaterial = materialComponent ( 'PointsMaterial' , { props : { type : Object as PropType < PointsMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new TPointsMaterial ( opts ) ) ; export const ShadowMaterial = materialComponent ( 'ShadowMaterial' , { color : { type : String , default : '#000000' } , props : { type : Object as PropType < MaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new TShadowMaterial ( opts ) ) ; export const StandardMaterial = materialComponent ( 'StandardMaterial' , { props : { type : Object as PropType < StandardMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshStandardMaterial ( opts ) ) ; export const ToonMaterial = materialComponent ( 'ToonMaterial' , { props : { type : Object as PropType < ToonMaterialPropsInterface > , default : ( ) => ( { } ) } } , ( opts ) => new MeshToonMaterial ( opts ) ) ;