@combeenation/3d-viewer 4.0.0-beta1 → 4.0.0-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +1 -0
  2. package/dist/lib-cjs/api/classes/element.d.ts +12 -16
  3. package/dist/lib-cjs/api/classes/element.js +129 -194
  4. package/dist/lib-cjs/api/classes/element.js.map +1 -1
  5. package/dist/lib-cjs/api/classes/event.d.ts +1 -15
  6. package/dist/lib-cjs/api/classes/event.js +1 -15
  7. package/dist/lib-cjs/api/classes/event.js.map +1 -1
  8. package/dist/lib-cjs/api/classes/parameter.d.ts +7 -101
  9. package/dist/lib-cjs/api/classes/parameter.js +21 -141
  10. package/dist/lib-cjs/api/classes/parameter.js.map +1 -1
  11. package/dist/lib-cjs/api/classes/parameterObservable.js +36 -11
  12. package/dist/lib-cjs/api/classes/parameterObservable.js.map +1 -1
  13. package/dist/lib-cjs/api/classes/placementAnimation.d.ts +2 -2
  14. package/dist/lib-cjs/api/classes/placementAnimation.js +0 -11
  15. package/dist/lib-cjs/api/classes/placementAnimation.js.map +1 -1
  16. package/dist/lib-cjs/api/classes/variant.d.ts +14 -48
  17. package/dist/lib-cjs/api/classes/variant.js +56 -320
  18. package/dist/lib-cjs/api/classes/variant.js.map +1 -1
  19. package/dist/lib-cjs/api/classes/variantInstance.d.ts +1 -5
  20. package/dist/lib-cjs/api/classes/variantInstance.js +0 -10
  21. package/dist/lib-cjs/api/classes/variantInstance.js.map +1 -1
  22. package/dist/lib-cjs/api/classes/viewer.d.ts +3 -6
  23. package/dist/lib-cjs/api/classes/viewer.js +59 -133
  24. package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
  25. package/dist/lib-cjs/api/internal/sceneSetup.d.ts +1 -5
  26. package/dist/lib-cjs/api/internal/sceneSetup.js +71 -75
  27. package/dist/lib-cjs/api/internal/sceneSetup.js.map +1 -1
  28. package/dist/lib-cjs/api/util/babylonHelper.d.ts +4 -54
  29. package/dist/lib-cjs/api/util/babylonHelper.js +8 -160
  30. package/dist/lib-cjs/api/util/babylonHelper.js.map +1 -1
  31. package/dist/lib-cjs/api/util/globalTypes.d.ts +12 -62
  32. package/dist/lib-cjs/api/util/resourceHelper.d.ts +8 -8
  33. package/dist/lib-cjs/api/util/resourceHelper.js +24 -63
  34. package/dist/lib-cjs/api/util/resourceHelper.js.map +1 -1
  35. package/dist/lib-cjs/index.d.ts +22 -24
  36. package/dist/lib-cjs/index.js +38 -42
  37. package/dist/lib-cjs/index.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/api/classes/element.ts +117 -146
  40. package/src/api/classes/{parameterizable.ts → elementParameterizable.ts} +1 -12
  41. package/src/api/classes/event.ts +1 -16
  42. package/src/api/classes/parameter.ts +22 -153
  43. package/src/api/classes/parameterObservable.ts +31 -9
  44. package/src/api/classes/placementAnimation.ts +0 -10
  45. package/src/api/classes/variant.ts +51 -187
  46. package/src/api/classes/variantInstance.ts +1 -8
  47. package/src/api/classes/viewer.ts +11 -68
  48. package/src/api/internal/sceneSetup.ts +109 -99
  49. package/src/api/util/babylonHelper.ts +10 -171
  50. package/src/api/util/globalTypes.ts +14 -71
  51. package/src/api/util/resourceHelper.ts +23 -31
  52. package/src/dev.ts +6 -2
  53. package/src/index.ts +23 -27
  54. package/src/pagesconfig.json +13 -8
  55. package/src/api/classes/variantParameterizable.ts +0 -73
  56. package/src/api/classes/viewerLight.ts +0 -330
  57. package/src/api/util/stringHelper.ts +0 -26
@@ -1,40 +1,35 @@
1
1
  import { HighlightLayer } from '@babylonjs/core/Layers/highlightLayer';
2
- import { Light } from '@babylonjs/core/Lights/light';
3
- import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
4
2
  import { Material } from '@babylonjs/core/Materials/material';
5
3
  import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
6
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
4
+ import { Axis, Space } from '@babylonjs/core/Maths/math.axis';
7
5
  import { Color3 } from '@babylonjs/core/Maths/math.color';
8
6
  import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
9
7
  import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
10
8
  import { Mesh } from '@babylonjs/core/Meshes/mesh';
11
9
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
12
- import { has, isArray, isNumber, isPlainObject, merge, union } from 'lodash-es';
10
+ import { Texture } from '@babylonjs/core/Materials/Textures/texture';
11
+ import { cloneDeep, concat, get, isArray, merge, union } from 'lodash-es';
13
12
  import {
14
13
  activateTransformNode as activate,
15
14
  addToHighlightLayer,
16
- addToShadowGenerator,
17
15
  assertTransformNode,
18
16
  cloneTransformNode,
19
17
  cloneTransformNodeMaterial,
20
18
  deactivateTransformNode as deactivate,
21
19
  getClientRectFromMesh,
22
- injectNodeMetadata,
20
+ injectTransformNodeMetadata,
23
21
  mapToDottedNodes,
24
- moveTransformNode,
25
22
  removeFromHighlightLayer,
26
- removeFromShadowGenerator,
27
- rotateTransformNode,
28
23
  setMaterial,
29
24
  setMaterialColor,
30
25
  setMaterialMetallness,
31
26
  setMaterialRoughness,
32
- setMaterialTexture,
33
- setReceiveShadows
27
+ setMaterialTexture
34
28
  } from '../util/babylonHelper';
35
- import { createImageBitmapFromImgSrc, createImageBitmapFromSvg } from '../util/resourceHelper';
36
- import { VariantParameterizable } from './../classes/variantParameterizable';
29
+ import { createImageUrlFromSvg, mergeMaps } from '../util/resourceHelper';
37
30
  import { DottedPath } from './dottedPath';
31
+ import { ElementParameterizable } from './elementParameterizable';
32
+ import { Event } from './event';
38
33
  import { Parameter } from './parameter';
39
34
  import { Variant } from './variant';
40
35
 
@@ -45,20 +40,24 @@ import { Variant } from './variant';
45
40
  * When used in typings, refer to via its alias {@link VariantElement} to prevent name clashes with the web APIs
46
41
  * [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) class
47
42
  */
48
- export class Element extends VariantParameterizable {
49
-
50
- public readonly nodes: TransformNode[] = [];
43
+ export class Element extends ElementParameterizable {
51
44
 
52
45
  protected readonly _dottedNodes: Map<DottedPath, TransformNode> = new Map();
53
46
 
47
+ protected readonly _parameterObservers: Map<string, ParameterObserver[]> = new Map();
48
+
54
49
  protected _highlightLayer?: HighlightLayer;
55
50
 
51
+ protected _paintableTextureId: number = 0;
52
+
53
+ public readonly nodes: TransformNode[] = [];
54
+
56
55
  /**
57
56
  * Constructor.
58
57
  */
59
- protected constructor( public readonly variant: Variant,
58
+ public constructor( public readonly variant: Variant,
60
59
  public readonly name: string ) {
61
- super( variant, name );
60
+ super();
62
61
  if ( process.env.NODE_ENV?.toLowerCase().includes('dev')) {
63
62
  this.assertPathDefinitions();
64
63
  }
@@ -73,13 +72,6 @@ export class Element extends VariantParameterizable {
73
72
  this.addParameterObservers();
74
73
  }
75
74
 
76
- /**
77
- * Creates an {@link Element} with given name.
78
- */
79
- public static async create( variant: Variant, name: string ): Promise<Element> {
80
- return new Element( variant, name );
81
- }
82
-
83
75
  /**
84
76
  * The {@link DottedPath} in the built tree of {@link Element}s.
85
77
  * E.g. "_.top-1.sub-2.sub-sub-3.el-1"
@@ -222,11 +214,41 @@ export class Element extends VariantParameterizable {
222
214
  }
223
215
 
224
216
  /**
225
- * @see {@link VariantParameterizable.commitParameters}
217
+ * Places the given {@link ParameterBag} in the {@link Element}'s parameters, replaces all patterns in the
218
+ * {@link StructureJson} and broadcasts all {@link ParameterObserver}s.
219
+ *
226
220
  * @emit {@link Event.ELEMENT_PARAMETER_COMMITTED}
227
221
  */
228
- public async commitParameters( parameters?: ParameterBag ): Promise<VariantParameterizable> {
229
- return super.commitParameters( parameters );
222
+ public async commitParameters( parameters?: ParameterBag ): Promise<Element> {
223
+ if( !parameters ) {
224
+ parameters = {};
225
+ }
226
+ const oldParameters = cloneDeep( this.parameters );
227
+ merge( this.parameters, parameters );
228
+ // handle parameter observers
229
+ let observerPromises: Promise<void | ParameterObserver>[] = [];
230
+ for( const parameter in this.parameters ) {
231
+ const oldParameterValue = oldParameters[parameter];
232
+ const newParameterValue = this.parameters[parameter];
233
+ this.variant.assertParameter( this.variant.inheritedParameterDeclaration, parameter, newParameterValue );
234
+ if( oldParameterValue === newParameterValue ) {
235
+ continue;
236
+ }
237
+ // parameter changed
238
+ const parameterObservers = mergeMaps( this._parameterObservers, this.parameterObservers );
239
+ if( parameterObservers.has( parameter ) ) {
240
+ const observers = parameterObservers.get( parameter )!;
241
+ observerPromises = concat(observerPromises, observers.map( observer => {
242
+ const observerResult = observer( this, oldParameterValue, newParameterValue );
243
+ return Promise.resolve( observerResult ).then( () => {
244
+ this.broadcastEvent( Event.ELEMENT_PARAMETER_COMMITTED,
245
+ this, parameter, oldParameterValue, newParameterValue );
246
+ } );
247
+ } ) );
248
+ }
249
+ }
250
+ await Promise.all( observerPromises );
251
+ return this;
230
252
  }
231
253
 
232
254
  /**
@@ -258,48 +280,45 @@ export class Element extends VariantParameterizable {
258
280
  }
259
281
 
260
282
  /**
261
- * Draws a `ImageBitmap` or `OffscreenCanvas` onto a `paintable` defined via {@link PaintableDefinition}.
283
+ * Draws a image onto a `paintable` defined via {@link PaintableDefinition}.
262
284
  */
263
- public drawPaintable( paintable: string, imageSource: CanvasImageSource ): Element {
264
- const paintableDefinition = this.getPaintableDefinition( paintable );
285
+ public async drawPaintable( paintable: string, imageSource: string ): Promise<Element> {
265
286
  const node = this.getPaintableNode( paintable );
266
287
  if( !(node instanceof AbstractMesh) ) {
267
288
  throw new Error( `The path must be an instance of "AbstractMesh" for paintable "${paintable}" ` +
268
289
  `in element "${this.id}".` );
269
290
  }
270
- if( node.material && !has( node.metadata, 'dirty.material' ) ) {
291
+ if( node.material && !get( node.metadata, 'dirty.material' ) ) {
271
292
  cloneTransformNodeMaterial( node );
272
293
  }
273
294
  if( !node.material ) {
274
295
  node.material = new StandardMaterial( `${this.id}.${paintable}.material`, this.variant.viewer.scene );
275
296
  }
276
297
  node.material.transparencyMode = Material.MATERIAL_ALPHATESTANDBLEND;
277
- if( !has( node.metadata, 'dirty.material.texture' ) ) {
298
+ if( !get( node.metadata, 'dirty.material.texture' ) ) {
278
299
  // inject initial value and mark as dirty
279
- injectNodeMetadata( node, { dirty: { material: { texture: true } } } );
280
- }
281
- const widthAndHeight = {
282
- width: imageSource.width,
283
- height: imageSource.height
284
- };
285
- if( isNumber( paintableDefinition.textureOptions ) ) {
286
- widthAndHeight.width = paintableDefinition.textureOptions;
287
- widthAndHeight.height = paintableDefinition.textureOptions;
288
- } else if( isPlainObject( paintableDefinition.textureOptions ) ) {
289
- widthAndHeight.width = paintableDefinition.textureOptions.width;
290
- widthAndHeight.height = paintableDefinition.textureOptions.height;
300
+ injectTransformNodeMetadata( node, { dirty: { material: { texture: true } } }, false );
291
301
  }
292
- const texture = new DynamicTexture(
293
- `${this.id}.${paintable}.texture`,
294
- widthAndHeight,
295
- this.variant.viewer.scene,
296
- false
297
- );
298
- setMaterialTexture( node, texture, false );
299
- const ctx = texture.getContext();
300
- // flip texture context horizontal with translate and scale
301
- ctx.drawImage( imageSource, 0, 0);
302
- texture.update( false );
302
+
303
+ await new Promise<void>(resolve => {
304
+ const paintableTexture = Texture.CreateFromBase64String(
305
+ imageSource,
306
+ `${this.id}.${paintable}.texture.${this._paintableTextureId}`,
307
+ this.variant.viewer.scene,
308
+ undefined,
309
+ false,
310
+ undefined,
311
+ () => {
312
+ setMaterialTexture( node, paintableTexture, false );
313
+ resolve();
314
+ }
315
+ );
316
+
317
+ // NOTE: Paintable texture need an individual id, otherwise the already existing texture on this id does not get overwritten
318
+ // Maybe think of a disposal logic here in the future
319
+ this._paintableTextureId++;
320
+ });
321
+
303
322
  return this;
304
323
  }
305
324
 
@@ -307,16 +326,15 @@ export class Element extends VariantParameterizable {
307
326
  * Draws a SVG string onto a `paintable` defined via {@link PaintableDefinition}.
308
327
  */
309
328
  public async drawPaintableFromSvg( paintable: string, svgSource: string ): Promise<Element> {
310
- const source = await createImageBitmapFromSvg( svgSource );
311
- return this.drawPaintable( paintable, source );
329
+ const imageUrl = await createImageUrlFromSvg( svgSource );
330
+ return this.drawPaintable( paintable, imageUrl );
312
331
  }
313
332
 
314
333
  /**
315
334
  * Draws an Image from source (URL/URI) onto a `paintable` defined via {@link PaintableDefinition}.
316
335
  */
317
336
  public async drawPaintableFromImgSrc( paintable: string, imgSource: string ): Promise<Element> {
318
- const source = await createImageBitmapFromImgSrc( imgSource );
319
- return this.drawPaintable( paintable, source );
337
+ return this.drawPaintable( paintable, imgSource );
320
338
  }
321
339
 
322
340
  /**
@@ -333,12 +351,12 @@ export class Element extends VariantParameterizable {
333
351
  }
334
352
  if( visible === true ) {
335
353
  element.nodes.forEach( node => {
336
- injectNodeMetadata( node, { visibility: node.isEnabled() } );
354
+ injectTransformNodeMetadata( node, { visibility: node.isEnabled() } );
337
355
  activate( node );
338
356
  } );
339
357
  } else if( visible === false ) {
340
358
  element.nodes.forEach( node => {
341
- injectNodeMetadata( node, { visibility: node.isEnabled() } );
359
+ injectTransformNodeMetadata( node, { visibility: node.isEnabled() } );
342
360
  deactivate( node );
343
361
  } );
344
362
  }
@@ -354,7 +372,7 @@ export class Element extends VariantParameterizable {
354
372
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
355
373
  const material = element.variant.getMaterial( newValue.toString() );
356
374
  element.nodes.forEach( node => {
357
- assertTransformNode(node, (node: AbstractMesh) => {
375
+ assertTransformNode(node, (node: TransformNode) => {
358
376
  if( node instanceof InstancedMesh ) {
359
377
  throw new Error( `Changing parameter "${Parameter.MATERIAL}" ` +
360
378
  `of an InstancedMesh is not supported. ` +
@@ -369,19 +387,19 @@ export class Element extends VariantParameterizable {
369
387
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
370
388
  const color = Parameter.parseColor( newValue );
371
389
  element.nodes.forEach( node => {
372
- assertTransformNode(node, (node: AbstractMesh) => {
390
+ assertTransformNode(node, (node: TransformNode) => {
373
391
  if( node instanceof InstancedMesh ) {
374
392
  throw new Error( `Changing parameter "${Parameter.MATERIAL_COLOR}" ` +
375
393
  `of an InstancedMesh is not supported. ` +
376
394
  `Tried to change node "${node.id}" on element "${element.id}".` );
377
395
  }
378
396
  });
379
- if( !has( node.metadata, 'dirty.material' ) ) {
397
+ if( !get( node.metadata, 'dirty.material' ) ) {
380
398
  cloneTransformNodeMaterial( node );
381
399
  }
382
- if( !has( node.metadata, 'dirty.material.color' ) ) {
400
+ if( !get( node.metadata, 'dirty.material.color' ) ) {
383
401
  // inject initial value and mark as dirty
384
- injectNodeMetadata( node, { dirty: { material: { color: oldValue } } } );
402
+ injectTransformNodeMetadata( node, { dirty: { material: { color: oldValue } } } );
385
403
  }
386
404
  setMaterialColor( node, color );
387
405
  } );
@@ -391,19 +409,19 @@ export class Element extends VariantParameterizable {
391
409
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
392
410
  const metallness = Parameter.parseNumber( newValue );
393
411
  element.nodes.forEach( node => {
394
- assertTransformNode(node, (node: AbstractMesh) => {
412
+ assertTransformNode(node, (node: TransformNode) => {
395
413
  if( node instanceof InstancedMesh ) {
396
414
  throw new Error( `Changing parameter "${Parameter.MATERIAL_METALLNESS}" ` +
397
415
  `of an InstancedMesh is not supported. ` +
398
416
  `Tried to change node "${node.id}" on element "${element.id}".` );
399
417
  }
400
418
  });
401
- if( !has( node.metadata, 'dirty.material' ) ) {
419
+ if( !get( node.metadata, 'dirty.material' ) ) {
402
420
  cloneTransformNodeMaterial( node );
403
421
  }
404
- if( !has( node.metadata, 'dirty.material.metallness' ) ) {
422
+ if( !get( node.metadata, 'dirty.material.metallness' ) ) {
405
423
  // inject initial value and mark as dirty
406
- injectNodeMetadata( node, { dirty: { material: { metallness: oldValue } } } );
424
+ injectTransformNodeMetadata( node, { dirty: { material: { metallness: oldValue } } } );
407
425
  }
408
426
  setMaterialMetallness( node, metallness );
409
427
  } );
@@ -413,19 +431,19 @@ export class Element extends VariantParameterizable {
413
431
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
414
432
  const roughness = Parameter.parseNumber( newValue );
415
433
  element.nodes.forEach( node => {
416
- assertTransformNode(node, (node: AbstractMesh) => {
434
+ assertTransformNode(node, (node: TransformNode) => {
417
435
  if( node instanceof InstancedMesh ) {
418
436
  throw new Error( `Changing parameter "${Parameter.MATERIAL_ROUGHNESS}" ` +
419
437
  `of an InstancedMesh is not supported. ` +
420
438
  `Tried to change node "${node.id}" on element "${element.id}".` );
421
439
  }
422
440
  });
423
- if( !has( node.metadata, 'dirty.material' ) ) {
441
+ if( !get( node.metadata, 'dirty.material' ) ) {
424
442
  cloneTransformNodeMaterial( node );
425
443
  }
426
- if( !has( node.metadata, 'dirty.material.roughness' ) ) {
444
+ if( !get( node.metadata, 'dirty.material.roughness' ) ) {
427
445
  // inject initial value and mark as dirty
428
- injectNodeMetadata( node, { dirty: { material: { roughness: oldValue } } } );
446
+ injectTransformNodeMetadata( node, { dirty: { material: { roughness: oldValue } } } );
429
447
  }
430
448
  setMaterialRoughness( node, roughness );
431
449
  } );
@@ -481,7 +499,7 @@ export class Element extends VariantParameterizable {
481
499
  // Add/Remove meshes to previously created highlight layers.
482
500
  if( highlighted === true ) {
483
501
  element.nodes.forEach( node => {
484
- assertTransformNode(node, (node: AbstractMesh) => {
502
+ assertTransformNode(node, (node: TransformNode) => {
485
503
  if( node instanceof InstancedMesh ) {
486
504
  throw new Error( `Changing parameter "${Parameter.HIGHLIGHTED}" ` +
487
505
  `of an InstancedMesh is not supported. ` +
@@ -508,61 +526,35 @@ export class Element extends VariantParameterizable {
508
526
  this._parameterObservers.set( Parameter.POSITION, [
509
527
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
510
528
  // we have to deal just with root nodes here due to relative impacts in a node tree
511
- element.nodes.forEach( node => moveTransformNode( node, Parameter.parseVector( newValue ) ) );
529
+ element.nodes.forEach( node => {
530
+ // remember absolute position and reset it before translating
531
+ if( !get( node.metadata, 'position' ) ) {
532
+ node.metadata.position = node.absolutePosition.clone();
533
+ }
534
+ node.setAbsolutePosition( node.metadata.position );
535
+ // move
536
+ const distance = Parameter.parseVector( newValue );
537
+ node.translate( Axis.X, distance.x, Space.WORLD );
538
+ node.translate( Axis.Y, distance.y, Space.WORLD );
539
+ node.translate( Axis.Z, distance.z, Space.WORLD );
540
+ } );
512
541
  }
513
542
  ] );
514
543
  this._parameterObservers.set( Parameter.ROTATION, [
515
544
  async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
516
- // The current implementation (rotating around coordinates 0,0,0) implicitly mutates the position of a node.
517
- // Since a user expects the rotation after the positioning, we have to manually fire the position observers.
518
- // Without calling these observers, the pivot and the position of a node is initially the same before rotating,
519
- // so there is no rotation happening at all.
520
- if( Parameter.POSITION in element.inheritedParameters ) {
521
- await element.commitParameter( Parameter.POSITION, element.inheritedParameters[Parameter.POSITION] );
522
- }
523
545
  // we have to deal just with root nodes here due to relative impacts in a node tree
524
- element.nodes.forEach( node => rotateTransformNode( node, Parameter.parseRotation( newValue ) ) );
525
- }
526
- ] );
527
- this._parameterObservers.set( Parameter.CAST_SHADOW, [
528
- async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
529
- let castShadow;
530
- try {
531
- castShadow = Parameter.parseBoolean( newValue );
532
- } catch( e ) {
533
- return;
534
- }
535
- let lightCsl = element.inheritedParameters[Parameter.CAST_SHADOW_FROM_LIGHTS];
536
- if( ! lightCsl ) {
537
- lightCsl = element.variant.inheritedViewerLights.map( l => l.name ).join( ',' );
538
- }
539
- if( castShadow === true ) {
540
- await this.castShadowValueHandler( lightCsl, addToShadowGenerator );
541
- }
542
- if( castShadow === false ) {
543
- await this.castShadowValueHandler( lightCsl, removeFromShadowGenerator );
544
- }
545
- }
546
- ] );
547
- this._parameterObservers.set( Parameter.CAST_SHADOW_FROM_LIGHTS, [
548
- async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
549
- // TODO: Possible performance issue in combination with CAST_SHADOW, since both observers are initially called
550
- // when CAST_SHADOW and CAST_SHADOW_FROM_LIGHTS are defined in the spec.
551
- const lightCsl = element.variant.inheritedViewerLights.map( l => l.name ).join( ',' );
552
- // cleanup all shadow generators
553
- await this.castShadowValueHandler( lightCsl, removeFromShadowGenerator );
554
- if( element.castShadow === true ) {
555
- // if newValue is undefined or '' then set newValue to lightCsl (use all lights)
556
- if( !newValue ) {
557
- newValue = lightCsl;
546
+ element.nodes.forEach( node => {
547
+ // remember absolute rotation and reset it before translating
548
+ if(!get( node.metadata, 'rotation' ) ) {
549
+ node.metadata.rotation = node.rotation.clone();
558
550
  }
559
- await this.castShadowValueHandler( newValue, addToShadowGenerator );
560
- }
561
- }
562
- ] );
563
- this._parameterObservers.set( Parameter.RECEIVE_SHADOWS, [
564
- async ( element: Element, oldValue: ParameterValue, newValue: ParameterValue ) => {
565
- element.nodes.forEach( node => setReceiveShadows( node, Parameter.parseBoolean( newValue ) ) );
551
+ node.rotation = node.metadata.rotation;
552
+ // rotate
553
+ const rotation = Parameter.parseRotation( newValue );
554
+ node.rotate( Axis.X, rotation.x, Space.WORLD );
555
+ node.rotate( Axis.Y, rotation.y, Space.WORLD );
556
+ node.rotate( Axis.Z, rotation.z, Space.WORLD );
557
+ } );
566
558
  }
567
559
  ] );
568
560
  return this;
@@ -611,25 +603,4 @@ export class Element extends VariantParameterizable {
611
603
  } );
612
604
  }
613
605
 
614
- /**
615
- * Handles callback for given light parameter.
616
- */
617
- private async castShadowValueHandler( lightCsl: ParameterValue, mutator: CallableFunction ) {
618
- let lights: Light[] = [];
619
- for( const lightName of Parameter.parseCommaSeparatedList( lightCsl ) ) {
620
- const viewerLight = await this.variant.getViewerLight( lightName );
621
- if( viewerLight ) {
622
- lights.push( viewerLight.light );
623
- }
624
- }
625
- const shadowGenerators = lights
626
- .map( light => light?.getShadowGenerator() as ShadowGenerator )
627
- .filter( Boolean );
628
- shadowGenerators.forEach( generator => {
629
- this.nodes.forEach( node => {
630
- mutator( generator, node );
631
- } );
632
- } );
633
- }
634
-
635
606
  }
@@ -1,7 +1,7 @@
1
1
  import { Parameter } from './parameter';
2
2
  import { ParameterObservable } from './parameterObservable';
3
3
 
4
- export abstract class Parameterizable extends ParameterObservable {
4
+ export abstract class ElementParameterizable extends ParameterObservable {
5
5
 
6
6
  protected parameterDeclaration: ParameterDeclarations = Parameter.declarations;
7
7
 
@@ -55,17 +55,6 @@ export abstract class Parameterizable extends ParameterObservable {
55
55
  return this.parameters[Parameter.ROTATION].toString();
56
56
  }
57
57
 
58
- get castShadow(): boolean | undefined {
59
- if( !(Parameter.CAST_SHADOW in this.parameters) ) {
60
- return undefined;
61
- }
62
- try {
63
- return Parameter.parseBoolean( this.parameters[Parameter.CAST_SHADOW] );
64
- } catch( e ) {
65
- return undefined;
66
- }
67
- }
68
-
69
58
  public async show(): Promise<ParameterObservable> {
70
59
  await this.commitParameter( Parameter.VISIBLE, true );
71
60
  return this;
@@ -262,28 +262,13 @@ export class Event {
262
262
  * * {@link Element}
263
263
  *
264
264
  * Payload:
265
- * * element: {@link Element}
265
+ * * variant: {@link Element}
266
266
  * * parameter: string
267
267
  * * oldValue: string
268
268
  * * newValue: string
269
269
  */
270
270
  public static readonly ELEMENT_PARAMETER_COMMITTED = 'elementParameterCommitted';
271
271
 
272
- /**
273
- * Fired after a parameter on an {@link ViewerLight} has been committed.
274
- *
275
- * Scopes:
276
- * * Global
277
- * * {@link ViewerLight}
278
- *
279
- * Payload:
280
- * * light: {@link ViewerLight}
281
- * * parameter: string
282
- * * oldValue: string
283
- * * newValue: string
284
- */
285
- public static readonly VIEWER_LIGHT_PARAMETER_COMMITTED = 'viewerLightParameterCommitted';
286
-
287
272
  /**
288
273
  * Fired after a parameter on an {@link SceneManager} has been committed.
289
274
  *