Quellcode durchsuchen

Support deep access in bindToValue, Add light shadow uiconfig

master
Palash Bansal vor 1 Jahr
Ursprung
Commit
646acbc5bf
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden

+ 4
- 7
examples/directional-light/script.ts Datei anzeigen

@@ -52,13 +52,10 @@ async function init() {
light.position.set(2, 2, 2)
light.lookAt(0, 0, 0)
light.castShadow = true
light.shadow.mapSize.setScalar(1024)
light.shadow.camera.near = 0.1
light.shadow.camera.far = 10
light.shadow.camera.top = 2
light.shadow.camera.bottom = -2
light.shadow.camera.left = -2
light.shadow.camera.right = 2
light.shadowMapSize.setScalar(1024)
light.shadowNear = 0.1
light.shadowFar = 10
light.shadowFrustum = 4

viewer.renderManager.renderer.shadowMap.type = PCFSoftShadowMap


+ 3
- 3
examples/point-light/script.ts Datei anzeigen

@@ -54,9 +54,9 @@ async function init() {
light.distance = 10
light.decay = 1
light.castShadow = true
light.shadow.mapSize.setScalar(1024)
light.shadow.camera.near = 0.1
light.shadow.camera.far = 10
light.shadowMapSize.setScalar(1024)
light.shadowNear = 0.1
light.shadowFar = 10

viewer.renderManager.renderer.shadowMap.type = PCFSoftShadowMap


+ 6
- 9
examples/progressive-hdr-shadows-exp/script.ts Datei anzeigen

@@ -4,7 +4,7 @@ import {
BasicShadowMap,
Color,
DataUtils,
DirectionalLight,
DirectionalLight, DirectionalLight2,
IObject3D,
LoadingScreenPlugin,
MaterialExtension,
@@ -141,19 +141,16 @@ float ambientOcclusion = getShadow( directionalShadowMap[ ii ], edls.shadowMapSi
}

function createDirLight(viewer: ThreeViewer) {
const directionalLight = new DirectionalLight(0xffffff, 4)
const directionalLight = new DirectionalLight2(0xffffff, 4)
directionalLight.position.set(-2, -2, 2)
directionalLight.lookAt(0, 0, 0)
directionalLight.color.set(0xffffff)
directionalLight.intensity = 0
directionalLight.castShadow = true
directionalLight.shadow.mapSize.setScalar(1024)
directionalLight.shadow.camera.near = 0.1
directionalLight.shadow.camera.far = 10
directionalLight.shadow.camera.top = 2
directionalLight.shadow.camera.bottom = -2
directionalLight.shadow.camera.left = -2
directionalLight.shadow.camera.right = 2
directionalLight.shadowMapSize.setScalar(1024)
directionalLight.shadowNear = 0.1
directionalLight.shadowFar = 10
directionalLight.shadowFrustum = 4
viewer.scene.addObject(directionalLight, {addToRoot: true})
// move to index 0 in parent.children, so that directionalLight always has index 0 in shader. required for material extension
const parent = directionalLight.parent!

+ 6
- 9
examples/progressive-plugin/script.ts Datei anzeigen

@@ -2,7 +2,7 @@ import {
_testFinish,
BasicShadowMap,
Box3B,
DirectionalLight,
DirectionalLight2,
IObject3D,
LoadingScreenPlugin,
Mesh,
@@ -50,17 +50,14 @@ async function init() {
ground.receiveShadow = true
viewer.scene.addObject(ground)

const directionalLight = viewer.scene.addObject(new DirectionalLight(0xffffff, 4))
const directionalLight = viewer.scene.addObject(new DirectionalLight2(0xffffff, 4))
directionalLight.position.set(2, 2, 2)
directionalLight.lookAt(0, 0, 0)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.setScalar(1024)
directionalLight.shadow.camera.near = 0.1
directionalLight.shadow.camera.far = 10
directionalLight.shadow.camera.top = 2
directionalLight.shadow.camera.bottom = -2
directionalLight.shadow.camera.left = -2
directionalLight.shadow.camera.right = 2
directionalLight.shadowMapSize.setScalar(1024)
directionalLight.shadowNear = 0.1
directionalLight.shadowFar = 10
directionalLight.shadowFrustum = 4

viewer.renderManager.renderer.shadowMap.type = BasicShadowMap


+ 5
- 5
examples/spot-light/script.ts Datei anzeigen

@@ -56,11 +56,11 @@ async function init() {
light.distance = 5
light.decay = 0.5
light.castShadow = true
light.shadow.mapSize.setScalar(1024)
light.shadow.camera.near = 0.1
light.shadow.camera.far = 10
light.shadow.camera.aspect = 1
light.shadow.camera.fov = 45
light.shadowMapSize.setScalar(1024)
light.shadowNear = 0.1
light.shadowFar = 10
light.shadowAspect = 1
light.shadowFov = 45

viewer.renderManager.renderer.shadowMap.type = PCFSoftShadowMap


+ 4
- 7
examples/sscontactshadows-plugin/script.ts Datei anzeigen

@@ -54,13 +54,10 @@ async function init() {
light.position.set(2, 2, 2)
light.lookAt(0, 0, 0)
light.castShadow = true
light.shadow.mapSize.setScalar(1024)
light.shadow.camera.near = 0.1
light.shadow.camera.far = 10
light.shadow.camera.top = 2
light.shadow.camera.bottom = -2
light.shadow.camera.left = -2
light.shadow.camera.right = 2
light.shadowMapSize.setScalar(1024)
light.shadowNear = 0.1
light.shadowFar = 10
light.shadowFrustum = 4

viewer.renderManager.renderer.shadowMap.type = PCFSoftShadowMap


+ 2
- 57
examples/ssgi-plugin/script.ts Datei anzeigen

@@ -82,63 +82,8 @@ async function init() {
light.lookAt(-25, 0, 0)
light.intensity = 30
light.castShadow = true
light.shadow.camera.left = -25
light.shadow.camera.right = 25
light.shadow.camera.top = 25
light.shadow.camera.bottom = -25
light.shadow.mapSize.set(1024, 1024)

// todo add to DirectionalLight
light.uiConfig.children!.push({
type: 'vec2',
label: 'Shadow Map Size',
property: [light?.shadow, 'mapSize'],
onChange: ()=>{
light.shadow.map?.dispose()
light.shadow.mapPass?.dispose()
light.shadow.map = null as any
light.shadow.mapPass = null as any
},
},
{
type: 'slider',
bounds: [-0.001, 0.001],
stepSize: 0.00002,
label: 'Shadow Bias',
property: [light?.shadow, 'bias'],
onChange: (e)=>light.setDirty(e),
},
{
type: 'slider',
bounds: [-0.1, 0.1],
stepSize: 0.005,
label: 'Shadow Normal Bias',
property: [light?.shadow, 'normalBias'],
onChange: (e)=>light.setDirty(e),
},
{
type: 'slider',
bounds: [0, 5],
label: 'Shadow radius',
property: [light?.shadow, 'radius'],
onChange: (e)=>light.setDirty(e),
},
{
type: 'slider',
bounds: [0.1, 50],
label: 'Shadow frustum',
// property: [light.shadow, 'radius'],
getValue: ()=>{
return light.shadow.camera.right * 2
},
setValue: (v: number)=>{
light.shadow.camera.left = -v / 2
light.shadow.camera.right = v / 2
light.shadow.camera.top = v / 2
light.shadow.camera.bottom = -v / 2
},
onChange: (e)=>light.setDirty(e),
})
light.shadowFrustum = 50
light.shadowMapSize.set(1024, 1024)

ui.appendChild(light.uiConfig)
}

+ 2
- 0
src/assetmanager/MaterialManager.ts Datei anzeigen

@@ -12,6 +12,7 @@ import {
PhysicalMaterial,
UnlitLineMaterial,
UnlitMaterial,
ObjectShaderMaterial,
} from '../core'
import {downloadFile} from 'ts-browser-helpers'
import {MaterialExtension} from '../materials'
@@ -31,6 +32,7 @@ export class MaterialManager<T = ''> extends EventDispatcher<BaseEvent, T> {
UnlitLineMaterial.MaterialTemplate,
LineMaterial2.MaterialTemplate,
LegacyPhongMaterial.MaterialTemplate,
ObjectShaderMaterial.MaterialTemplate,
]

private _materials: IMaterial[] = []

+ 1
- 1
src/core/light/AmbientLight2.ts Datei anzeigen

@@ -66,7 +66,7 @@ export class AmbientLight2 extends AmbientLight implements ILight<undefined> {
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 67
- 8
src/core/light/DirectionalLight2.ts Datei anzeigen

@@ -1,11 +1,19 @@
import {Color, ColorRepresentation, DirectionalLight, DirectionalLightShadow, Euler, Vector3} from 'three'
import {Color, ColorRepresentation, DirectionalLight, DirectionalLightShadow, Euler, Vector2, Vector3} from 'three'
import {ILight, ILightEvent, ILightEventTypes} from './ILight'
import {iLightCommons} from '../object/iLightCommons'
import {IObject3D} from '../IObject'
import {uiColor, UiObjectConfig, uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
import {onChange3} from 'ts-browser-helpers'
import {uiColor, uiNumber, UiObjectConfig, uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
import {onChange2, onChange3} from 'ts-browser-helpers'
import {bindToValue} from '../../three'

// todo: add LightShadow uiconfig
/**
* Extension of three.js DirectionalLight with additional properties for serialization and UI
* A directional light is a light source that has a position but no dimensions - a single point in space that emits light in a specific direction.
*
* Note - gltf serialization is handled by {@link GLTFLightExtrasExtension}
*
* @category Lights
*/
// todo: add Light section in the readme detailing these ...2 lights
@uiPanelContainer('Directional Light')
export class DirectionalLight2<
@@ -35,20 +43,72 @@ export class DirectionalLight2<
@onChange3('setDirty')
declare castShadow: boolean

@uiVector('Shadow Map Size')
@bindToValue({obj: 'shadow', key: 'mapSize', onChange: DirectionalLight2.prototype._mapSizeChanged, onChangeParams: false})
shadowMapSize: Vector2

protected _mapSizeChanged() {
this.shadow.map?.dispose()
this.shadow.mapPass?.dispose()
this.shadow.map = null as any
this.shadow.mapPass = null as any
this.setDirty({change: 'shadowMapSize'})
}

@uiSlider('Shadow Bias', [-0.001, 0.001], 0.00001)
@bindToValue({obj: 'shadow', key: 'bias', onChange: 'setDirty'})
shadowBias: number

@uiSlider('Shadow Normal Bias', [-0.1, 0.1], 0.005)
@bindToValue({obj: 'shadow', key: 'normalBias', onChange: 'setDirty'})
shadowNormalBias: number

@uiSlider('Shadow Radius', [0, 5], 0.01)
@bindToValue({obj: 'shadow', key: 'radius', onChange: 'setDirty'})
shadowRadius: number

@uiSlider('Shadow Frustum', [0.1, 50], 0.01)
@onChange2(DirectionalLight2.prototype._shadowFrustumChanged)
shadowFrustum: number

@uiNumber('Shadow Near')
@bindToValue({obj: 'shadow', key: ['camera', 'near'], onChange: DirectionalLight2.prototype._shadowCamUpdate})
shadowNear: number

@uiNumber('Shadow Far')
@bindToValue({obj: 'shadow', key: ['camera', 'far'], onChange: DirectionalLight2.prototype._shadowCamUpdate})
shadowFar: number

protected _shadowFrustumChanged() {
const v = this.shadowFrustum
this.shadow.camera.left = -v / 2
this.shadow.camera.right = v / 2
this.shadow.camera.top = v / 2
this.shadow.camera.bottom = -v / 2
this.shadow.camera.updateProjectionMatrix()
this.setDirty({change: 'shadowFrustum'})
}

protected _shadowCamUpdate(change?: string) {
this.shadow.camera.updateProjectionMatrix()
this.setDirty({change})
}

constructor(color?: ColorRepresentation, intensity?: number) {
super(color, intensity)
this.target.position.set(0, 0, -1) // because of GLTF spec: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual
this.add(this.target) // todo: make sure the child isn't exported in gltf
iLightCommons.upgradeLight.call(this)
this.shadowFrustum = 10
}

autoScale() {
console.warn('AutoScale not supported on Lights')
console.warn('DirectionalLight2: AutoScale not supported on Lights')
return this
}

autoCenter() {
console.warn('AutoCenter not supported on Lights')
console.warn('DirectionalLight2: AutoCenter not supported on Lights')
return this
}

@@ -66,7 +126,6 @@ export class DirectionalLight2<
return this
}


// region inherited type fixes
// re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936

@@ -80,7 +139,7 @@ export class DirectionalLight2<
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 1
- 1
src/core/light/HemisphereLight2.ts Datei anzeigen

@@ -70,7 +70,7 @@ export class HemisphereLight2 extends HemisphereLight implements ILight<undefine
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 53
- 2
src/core/light/PointLight2.ts Datei anzeigen

@@ -1,10 +1,16 @@
import {Color, ColorRepresentation, PointLight, PointLightShadow, Vector3} from 'three'
import {Color, ColorRepresentation, PointLight, PointLightShadow, Vector2, Vector3} from 'three'
import {ILight, ILightEvent} from './ILight'
import {iLightCommons} from '../object/iLightCommons'
import {IObject3D} from '../IObject'
import {uiColor, uiNumber, UiObjectConfig, uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
import {onChange3} from 'ts-browser-helpers'
import {bindToValue} from '../../three'

/**
* Extension of three.js PointLight with additional properties for serialization and UI
*
* Note - gltf serialization is handled by {@link GLTFLightExtrasExtension}
*/
@uiPanelContainer('Point Light')
export class PointLight2 extends PointLight implements ILight<PointLightShadow> {
assetType = 'light' as const
@@ -28,12 +34,57 @@ export class PointLight2 extends PointLight implements ILight<PointLightShadow>
@uiNumber('Decay')
@onChange3('setDirty')
declare decay: number
@uiNumber('Power')
@onChange3('setDirty')
declare power: number

@uiVector('Position', undefined, undefined, (that: PointLight2)=>({onChange: ()=>that.setDirty()}))
declare readonly position: Vector3

@uiToggle('Cast Shadow')
@onChange3('setDirty')
declare castShadow: boolean

@uiVector('Shadow Map Size')
@bindToValue({obj: 'shadow', key: 'mapSize', onChange: PointLight2.prototype._mapSizeChanged, onChangeParams: false})
shadowMapSize: Vector2

protected _mapSizeChanged() {
this.shadow.map?.dispose()
this.shadow.mapPass?.dispose()
this.shadow.map = null as any
this.shadow.mapPass = null as any
this.setDirty({change: 'shadowMapSize'})
}

@uiSlider('Shadow Bias', [-0.001, 0.001], 0.00001)
@bindToValue({obj: 'shadow', key: 'bias', onChange: 'setDirty'})
shadowBias: number

@uiSlider('Shadow Radius', [0, 5], 0.01)
@bindToValue({obj: 'shadow', key: 'radius', onChange: 'setDirty'})
shadowRadius: number

@uiNumber('Shadow Near')
@bindToValue({obj: 'shadow', key: ['camera', 'near'], onChange: PointLight2.prototype._shadowCamUpdate})
shadowNear: number

@uiNumber('Shadow Far')
@bindToValue({obj: 'shadow', key: ['camera', 'far'], onChange: PointLight2.prototype._shadowCamUpdate})
shadowFar: number

@uiNumber('Shadow Aspect')
@bindToValue({obj: 'shadow', key: 'aspect', onChange: PointLight2.prototype._shadowCamUpdate})
shadowAspect: number

@uiSlider('Shadow FOV', [1, 179], 1)
@bindToValue({obj: 'shadow', key: 'fov', onChange: PointLight2.prototype._shadowCamUpdate})
shadowFov: number

protected _shadowCamUpdate(change?: string) {
this.shadow.camera.updateProjectionMatrix()
this.setDirty({change})
}
constructor(color?: ColorRepresentation, intensity?: number, distance?: number, decay?: number) {
super(color, intensity, distance, decay)
iLightCommons.upgradeLight.call(this)
@@ -77,7 +128,7 @@ export class PointLight2 extends PointLight implements ILight<PointLightShadow>
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 1
- 1
src/core/light/RectAreaLight2.ts Datei anzeigen

@@ -75,7 +75,7 @@ export class RectAreaLight2 extends RectAreaLight implements ILight<undefined> {
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 54
- 4
src/core/light/SpotLight2.ts Datei anzeigen

@@ -1,10 +1,16 @@
import {Color, ColorRepresentation, Euler, SpotLight, SpotLightShadow, Vector3} from 'three'
import {Color, ColorRepresentation, Euler, SpotLight, SpotLightShadow, Vector2, Vector3} from 'three'
import {ILight, ILightEvent} from './ILight'
import {iLightCommons} from '../object/iLightCommons'
import {IObject3D} from '../IObject'
import {uiColor, uiInput, UiObjectConfig, uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
import {uiColor, uiInput, uiNumber, UiObjectConfig, uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
import {onChange3} from 'ts-browser-helpers'
import {bindToValue} from '../../three'

/**
* Extension of three.js SpotLight with additional properties for serialization and UI
*
* Note - gltf serialization is handled by {@link GLTFLightExtrasExtension}
*/
@uiPanelContainer('Spot Light')
export class SpotLight2 extends SpotLight implements ILight<SpotLightShadow> {
assetType = 'light' as const
@@ -42,6 +48,51 @@ export class SpotLight2 extends SpotLight implements ILight<SpotLightShadow> {
@onChange3('setDirty')
declare castShadow: boolean

@uiVector('Shadow Map Size')
@bindToValue({obj: 'shadow', key: 'mapSize', onChange: SpotLight2.prototype._mapSizeChanged, onChangeParams: false})
shadowMapSize: Vector2

protected _mapSizeChanged() {
this.shadow.map?.dispose()
this.shadow.mapPass?.dispose()
this.shadow.map = null as any
this.shadow.mapPass = null as any
this.setDirty({change: 'shadowMapSize'})
}

@uiSlider('Shadow Bias', [-0.001, 0.001], 0.00001)
@bindToValue({obj: 'shadow', key: 'bias', onChange: 'setDirty'})
shadowBias: number

@uiSlider('Shadow Radius', [0, 5], 0.01)
@bindToValue({obj: 'shadow', key: 'radius', onChange: 'setDirty'})
shadowRadius: number

@uiSlider('Shadow Focus', [0, 1], 0.001)
@bindToValue({obj: 'shadow', key: 'focus', onChange: 'setDirty'})
shadowFocus: number

@uiNumber('Shadow Near')
@bindToValue({obj: 'shadow', key: ['camera', 'near'], onChange: SpotLight2.prototype._shadowCamUpdate})
shadowNear: number

@uiNumber('Shadow Far')
@bindToValue({obj: 'shadow', key: ['camera', 'far'], onChange: SpotLight2.prototype._shadowCamUpdate})
shadowFar: number

@uiNumber('Shadow Aspect')
@bindToValue({obj: 'shadow', key: 'aspect', onChange: SpotLight2.prototype._shadowCamUpdate})
shadowAspect: number

@uiSlider('Shadow FOV', [1, 179], 1)
@bindToValue({obj: 'shadow', key: 'fov', onChange: SpotLight2.prototype._shadowCamUpdate})
shadowFov: number

protected _shadowCamUpdate(change?: string) {
this.shadow.camera.updateProjectionMatrix()
this.setDirty({change})
}

constructor(color?: ColorRepresentation, intensity?: number, distance?: number,
angle?: number,
penumbra?: number,
@@ -76,7 +127,6 @@ export class SpotLight2 extends SpotLight implements ILight<SpotLightShadow> {
return this
}


// region inherited type fixes
// re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936

@@ -90,7 +140,7 @@ export class SpotLight2 extends SpotLight implements ILight<SpotLightShadow> {
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 1
- 1
src/core/object/Mesh2.ts Datei anzeigen

@@ -44,7 +44,7 @@ export class Mesh2<
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ILightEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]
dispose: (removeFromParent?: boolean) => void


+ 1
- 1
src/core/object/RootScene.ts Datei anzeigen

@@ -587,7 +587,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
dispatchEvent: (event: ISceneEvent) => void
declare parent: null
declare parent: IObject3D | null
declare children: IObject3D[]

// endregion

+ 6
- 3
src/core/object/iLightCommons.ts Datei anzeigen

@@ -3,9 +3,12 @@ import {IObjectProcessor, IObjectSetDirtyOptions} from '../IObject'
import {iObjectCommons} from './iObjectCommons'

export const iLightCommons = {
setDirty: function(this: ILight, options?: IObjectSetDirtyOptions): void {
this.dispatchEvent({bubbleToParent: true, ...options, type: 'lightUpdate', light: this, object: this}) // this sets sceneUpdate in root scene
iObjectCommons.setDirty.call(this, options)
setDirty: function(this: ILight, options?: IObjectSetDirtyOptions, ...args: any[]): void {
if (typeof options === 'string') { // just incase called by decorators
options = {change: options}
}
this.dispatchEvent({bubbleToParent: true, ...options, type: 'lightUpdate', light: this, object: this, args}) // this sets sceneUpdate in root scene
iObjectCommons.setDirty.call(this, options, ...args)
},
upgradeLight: upgradeLight,
refreshUi: iObjectCommons.refreshUi,

+ 5
- 2
src/core/object/iObjectCommons.ts Datei anzeigen

@@ -11,8 +11,11 @@ import {iMaterialCommons} from '../material/iMaterialCommons'
import {ILight} from '../light/ILight'

export const iObjectCommons = {
setDirty: function(this: IObject3D, options?: IObjectSetDirtyOptions): void {
this.dispatchEvent({bubbleToParent: true, ...options, type: 'objectUpdate', object: this}) // this sets sceneUpdate in root scene
setDirty: function(this: IObject3D, options?: IObjectSetDirtyOptions, ...args: any[]): void {
if (typeof options === 'string') { // just incase called by decorators
options = {change: options}
}
this.dispatchEvent({bubbleToParent: true, ...options, type: 'objectUpdate', object: this, args}) // this sets sceneUpdate in root scene
if (options?.refreshUi !== false && options?.last !== false) this.refreshUi?.()
// console.log('object update')
},

+ 12
- 4
src/three/utils/decorators.ts Datei anzeigen

@@ -1,4 +1,4 @@
import {FnCaller, getOrCall, objectHasOwn, safeSetProperty, ValOrFunc} from 'ts-browser-helpers'
import {FnCaller, getOrCall, objectHasOwn, safeSetProperty, ValOrArr, ValOrFunc} from 'ts-browser-helpers'

/**
*
@@ -132,15 +132,23 @@ export function matDefineBool(key?: string|symbol, customDefines?: any, thisMat
* @param processVal - function that processes the value before setting it.
* @param invProcessVal - function that processes the value before returning it.
*/
export function bindToValue({obj, key, processVal, invProcessVal, onChange, onChangeParams = true}: {obj?: ValOrFunc<any>, key?: ValOrFunc<string | symbol>, onChange?: ((...args: any[]) => any)|string, processVal?: (newVal: any) => any, invProcessVal?: (val: any) => any, onChangeParams?: boolean}): PropertyDecorator {
export function bindToValue({obj, key, processVal, invProcessVal, onChange, onChangeParams = true}: {obj?: ValOrFunc<any>, key?: ValOrFunc<ValOrArr<string | symbol>>, onChange?: ((...args: any[]) => any)|string, processVal?: (newVal: any) => any, invProcessVal?: (val: any) => any, onChangeParams?: boolean}): PropertyDecorator {
const cPropKey = !!key

return (targetPrototype: any, propertyKey: string|symbol, descriptor?: TypedPropertyDescriptor<any>) => {
const getTarget = (_this: any)=>{
let t = getOrCall(obj) || _this
if (typeof t === 'string') t = _this[t]
const p = cPropKey ? getOrCall(key) || propertyKey : propertyKey
return {t, p}
let p1 = cPropKey ? getOrCall(key) || propertyKey : propertyKey
let p: string|symbol
if (Array.isArray(p1)) {
while (p1.length > 1 && t && typeof t === 'object') {
t = t[p1[0]]
p1 = p1.slice(1)
}
p = p1.length ? p1[0] : propertyKey
} else p = p1
return {t, p: p}
}
const prop = {
get() {

Laden…
Abbrechen
Speichern