@playcanvas/web-components 0.13.1 → 0.15.0
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.
- package/dist/colors.d.cts +1 -1
- package/dist/colors.d.ts +1 -1
- package/dist/components/joint-component.d.cts +521 -0
- package/dist/components/joint-component.d.ts +521 -0
- package/dist/custom-elements.json +1029 -0
- package/dist/entity-base.d.cts +1 -7
- package/dist/entity-base.d.ts +1 -7
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/loading-bar.d.cts +1 -35
- package/dist/loading-bar.d.ts +1 -35
- package/dist/material.d.cts +13 -0
- package/dist/material.d.ts +13 -0
- package/dist/model.d.cts +71 -0
- package/dist/model.d.ts +71 -0
- package/dist/node.d.cts +55 -0
- package/dist/node.d.ts +55 -0
- package/dist/parse.d.cts +1 -130
- package/dist/parse.d.ts +1 -130
- package/dist/pwc.cjs +1410 -148
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +1410 -148
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.min.mjs +1 -1
- package/dist/pwc.min.mjs.map +1 -1
- package/dist/pwc.mjs +1410 -149
- package/dist/pwc.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +203 -1
- package/dist/web-types.json +368 -2
- package/package.json +5 -4
- package/src/app.ts +18 -0
- package/src/colors.ts +5 -0
- package/src/components/joint-component.ts +984 -0
- package/src/entity-base.ts +3 -3
- package/src/entity.ts +28 -7
- package/src/index.ts +6 -0
- package/src/loading-bar.ts +2 -3
- package/src/material.ts +29 -0
- package/src/model.ts +156 -0
- package/src/node.ts +279 -9
- package/src/parse.ts +11 -1
package/dist/pwc.mjs
CHANGED
|
@@ -182,6 +182,7 @@ const REMOVAL_DELAY_MS = 250;
|
|
|
182
182
|
* All styling is inline, so the library injects no stylesheet. The colors and height resolve CSS
|
|
183
183
|
* custom properties — `--pc-loading-bar-color`, `--pc-loading-bar-background` and
|
|
184
184
|
* `--pc-loading-bar-height` — so a page can theme the bar from `pc-app` or `:root`.
|
|
185
|
+
* @internal
|
|
185
186
|
*/
|
|
186
187
|
class LoadingBar {
|
|
187
188
|
_track;
|
|
@@ -280,6 +281,11 @@ class LoadingBar {
|
|
|
280
281
|
}
|
|
281
282
|
}
|
|
282
283
|
|
|
284
|
+
/**
|
|
285
|
+
* The CSS color keywords, lowercase name to hex value. Read by `parseColor` to accept color
|
|
286
|
+
* names as attribute values.
|
|
287
|
+
* @internal
|
|
288
|
+
*/
|
|
283
289
|
const CSS_COLORS = {
|
|
284
290
|
aliceblue: '#f0f8ff',
|
|
285
291
|
antiquewhite: '#faebd7',
|
|
@@ -455,7 +461,7 @@ const CSS_COLORS = {
|
|
|
455
461
|
* @param value - The value to split.
|
|
456
462
|
* @param count - The required number of components.
|
|
457
463
|
* @returns The parsed components, or `null`.
|
|
458
|
-
* @
|
|
464
|
+
* @internal
|
|
459
465
|
*/
|
|
460
466
|
const parseComponents = (value, count) => {
|
|
461
467
|
const components = value.trim().split(/\s+/).map(Number);
|
|
@@ -486,6 +492,7 @@ const cloneDefault = (value) => {
|
|
|
486
492
|
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
487
493
|
* @param defaultValue - The value to use when the attribute is absent or removed.
|
|
488
494
|
* @returns The parsed boolean.
|
|
495
|
+
* @internal
|
|
489
496
|
*/
|
|
490
497
|
const parseBool = (value, defaultValue) => {
|
|
491
498
|
return value === null ? defaultValue : value !== 'false';
|
|
@@ -501,6 +508,7 @@ const parseBool = (value, defaultValue) => {
|
|
|
501
508
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
502
509
|
* @param attribute - The attribute name, used in the warning message.
|
|
503
510
|
* @returns The parsed Color object.
|
|
511
|
+
* @internal
|
|
504
512
|
*/
|
|
505
513
|
const parseColor = (value, defaultValue, attribute) => {
|
|
506
514
|
if (value === null) {
|
|
@@ -542,6 +550,7 @@ const parseColor = (value, defaultValue, attribute) => {
|
|
|
542
550
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
543
551
|
* @param attribute - The attribute name, used in the warning message.
|
|
544
552
|
* @returns The resolved enum name.
|
|
553
|
+
* @internal
|
|
545
554
|
*/
|
|
546
555
|
const parseEnum = (value, valid, defaultValue, attribute) => {
|
|
547
556
|
if (value === null) {
|
|
@@ -563,6 +572,7 @@ const parseEnum = (value, valid, defaultValue, attribute) => {
|
|
|
563
572
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
564
573
|
* @param attribute - The attribute name, used in the warning message.
|
|
565
574
|
* @returns The parsed number.
|
|
575
|
+
* @internal
|
|
566
576
|
*/
|
|
567
577
|
const parseNumber = (value, defaultValue, attribute) => {
|
|
568
578
|
if (value === null) {
|
|
@@ -585,6 +595,7 @@ const parseNumber = (value, defaultValue, attribute) => {
|
|
|
585
595
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
586
596
|
* @param attribute - The attribute name, used in the warning message.
|
|
587
597
|
* @returns The parsed Quat object.
|
|
598
|
+
* @internal
|
|
588
599
|
*/
|
|
589
600
|
const parseQuat = (value, defaultValue, attribute) => {
|
|
590
601
|
if (value === null) {
|
|
@@ -608,6 +619,7 @@ const parseQuat = (value, defaultValue, attribute) => {
|
|
|
608
619
|
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
609
620
|
* @param defaultValue - The value to use when the attribute is absent or removed.
|
|
610
621
|
* @returns The parsed tag names.
|
|
622
|
+
* @internal
|
|
611
623
|
*/
|
|
612
624
|
const parseTags = (value, defaultValue = []) => {
|
|
613
625
|
if (value === null) {
|
|
@@ -629,6 +641,7 @@ const parseTags = (value, defaultValue = []) => {
|
|
|
629
641
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
630
642
|
* @param attribute - The attribute name, used in the warning message.
|
|
631
643
|
* @returns The parsed Vec2 object.
|
|
644
|
+
* @internal
|
|
632
645
|
*/
|
|
633
646
|
const parseVec2 = (value, defaultValue, attribute) => {
|
|
634
647
|
if (value === null) {
|
|
@@ -650,6 +663,7 @@ const parseVec2 = (value, defaultValue, attribute) => {
|
|
|
650
663
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
651
664
|
* @param attribute - The attribute name, used in the warning message.
|
|
652
665
|
* @returns The parsed Vec3 object.
|
|
666
|
+
* @internal
|
|
653
667
|
*/
|
|
654
668
|
const parseVec3 = (value, defaultValue, attribute) => {
|
|
655
669
|
if (value === null) {
|
|
@@ -671,6 +685,7 @@ const parseVec3 = (value, defaultValue, attribute) => {
|
|
|
671
685
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
672
686
|
* @param attribute - The attribute name, used in the warning message.
|
|
673
687
|
* @returns The parsed Vec4 object.
|
|
688
|
+
* @internal
|
|
674
689
|
*/
|
|
675
690
|
const parseVec4 = (value, defaultValue, attribute) => {
|
|
676
691
|
if (value === null) {
|
|
@@ -690,6 +705,7 @@ const parseVec4 = (value, defaultValue, attribute) => {
|
|
|
690
705
|
*
|
|
691
706
|
* @param ref - The reference string to resolve.
|
|
692
707
|
* @returns The resolved entity, or `null`.
|
|
708
|
+
* @internal
|
|
693
709
|
*/
|
|
694
710
|
const getEntity = (ref) => {
|
|
695
711
|
if (!ref) {
|
|
@@ -859,6 +875,23 @@ class AppElement extends AsyncElement {
|
|
|
859
875
|
if (this._loadingBar && !this._bar) {
|
|
860
876
|
this._bar = new LoadingBar(this);
|
|
861
877
|
}
|
|
878
|
+
// Upgrade the subtree before reading anything out of it. A subtree cloned from a
|
|
879
|
+
// <template> arrives entirely unupgraded - template content lives in an inert document,
|
|
880
|
+
// where custom element definitions are never looked up - and appending the clone upgrades
|
|
881
|
+
// its elements in tree order, this one before its descendants. The module query below would
|
|
882
|
+
// otherwise find plain HTMLElements with no _getLoadPromise to call, and the boot would die
|
|
883
|
+
// there, leaving the element permanently unready: no canvas, no entities, no application.
|
|
884
|
+
//
|
|
885
|
+
// Upgrading is the fix here rather than skipping whatever has not upgraded, because a
|
|
886
|
+
// <pc-module> is the one child that nothing else ever builds on its own behalf - skipping
|
|
887
|
+
// it would drop the wasm module the app asked for, silently and only for cloned apps.
|
|
888
|
+
// Upgrading runs each descendant's connectedCallback synchronously, a few lines earlier
|
|
889
|
+
// than the parser's path runs them but into the same state they see there: no application
|
|
890
|
+
// yet and _hierarchyReady false, so they defer to the sweeps below. A descendant that
|
|
891
|
+
// disconnects this element from there is caught by the generation check after the await,
|
|
892
|
+
// as any other disconnect is. An already-upgraded subtree - every other insertion path -
|
|
893
|
+
// is left completely untouched.
|
|
894
|
+
customElements.upgrade(this);
|
|
862
895
|
// Get all pc-module elements that are direct children of the pc-app element
|
|
863
896
|
const moduleElements = this.querySelectorAll(':scope > pc-module');
|
|
864
897
|
// Wait for all modules to load
|
|
@@ -1594,7 +1627,7 @@ customElements.define('pc-app', AppElement);
|
|
|
1594
1627
|
/**
|
|
1595
1628
|
* The attribute names of the inline `onpointer*` event handlers, shared by every element that
|
|
1596
1629
|
* fronts an engine entity. Spread into `observedAttributes` by subclasses.
|
|
1597
|
-
* @
|
|
1630
|
+
* @internal
|
|
1598
1631
|
*/
|
|
1599
1632
|
const POINTER_ATTRIBUTES = [
|
|
1600
1633
|
'onpointerenter',
|
|
@@ -1710,6 +1743,30 @@ class EntityBaseElement extends AsyncElement {
|
|
|
1710
1743
|
}
|
|
1711
1744
|
}
|
|
1712
1745
|
|
|
1746
|
+
/**
|
|
1747
|
+
* Creates and parents the entities of every descendant `<pc-entity>` of `root`, in two passes so
|
|
1748
|
+
* that no parent's existence depends on document order. Called wherever a subtree could not build
|
|
1749
|
+
* itself: an element inserted into an application that is already running, and a `<pc-node>` whose
|
|
1750
|
+
* children waited for it to bind.
|
|
1751
|
+
*
|
|
1752
|
+
* Descendants that are not yet custom elements are skipped, because there is nothing useful to do
|
|
1753
|
+
* for them and reaching for `_createEntity` would throw. A subtree cloned from a `<template>`
|
|
1754
|
+
* arrives entirely unupgraded — template content lives in an inert document, where custom element
|
|
1755
|
+
* definitions are never looked up — and appending the clone upgrades its elements in tree order,
|
|
1756
|
+
* an element before its descendants. So a sweep from an element's own `connectedCallback` sees
|
|
1757
|
+
* plain `HTMLElement`s below it. Each becomes an `EntityElement` moments later and its own
|
|
1758
|
+
* `connectedCallback` creates and parents it, by which time the ancestor it parents under has its
|
|
1759
|
+
* entity — the same guarantee tree order gives this sweep.
|
|
1760
|
+
*
|
|
1761
|
+
* @param root - The element whose descendant entities to build.
|
|
1762
|
+
* @param app - The application to create the entities in.
|
|
1763
|
+
* @internal
|
|
1764
|
+
*/
|
|
1765
|
+
const buildDescendantEntities = (root, app) => {
|
|
1766
|
+
const children = Array.from(root.querySelectorAll('pc-entity')).filter((child) => child instanceof EntityElement);
|
|
1767
|
+
children.forEach((child) => child._createEntity(app));
|
|
1768
|
+
children.forEach((child) => child._buildHierarchy(app));
|
|
1769
|
+
};
|
|
1713
1770
|
/**
|
|
1714
1771
|
* The EntityElement interface provides properties and methods for manipulating
|
|
1715
1772
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
@@ -1858,13 +1915,7 @@ class EntityElement extends EntityBaseElement {
|
|
|
1858
1915
|
this._createEntity(app);
|
|
1859
1916
|
this._buildHierarchy(app);
|
|
1860
1917
|
// Handle any child entities that might exist
|
|
1861
|
-
|
|
1862
|
-
childEntities.forEach((child) => {
|
|
1863
|
-
child._createEntity(app);
|
|
1864
|
-
});
|
|
1865
|
-
childEntities.forEach((child) => {
|
|
1866
|
-
child._buildHierarchy(app);
|
|
1867
|
-
});
|
|
1918
|
+
buildDescendantEntities(this, app);
|
|
1868
1919
|
}
|
|
1869
1920
|
}
|
|
1870
1921
|
disconnectedCallback() {
|
|
@@ -4637,219 +4688,1092 @@ class ElementComponentElement extends ComponentElement {
|
|
|
4637
4688
|
set width(value) {
|
|
4638
4689
|
this._width = value;
|
|
4639
4690
|
if (this.component) {
|
|
4640
|
-
this.component.width = value;
|
|
4691
|
+
this.component.width = value;
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
/**
|
|
4695
|
+
* Gets the width of the element component.
|
|
4696
|
+
* @returns The width.
|
|
4697
|
+
*/
|
|
4698
|
+
get width() {
|
|
4699
|
+
return this._width;
|
|
4700
|
+
}
|
|
4701
|
+
/**
|
|
4702
|
+
* Sets whether the element component should wrap lines.
|
|
4703
|
+
* @param value - Whether to wrap lines.
|
|
4704
|
+
*/
|
|
4705
|
+
set wrapLines(value) {
|
|
4706
|
+
this._wrapLines = value;
|
|
4707
|
+
if (this.component) {
|
|
4708
|
+
this.component.wrapLines = value;
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
/**
|
|
4712
|
+
* Gets whether the element component should wrap lines.
|
|
4713
|
+
* @returns Whether to wrap lines.
|
|
4714
|
+
*/
|
|
4715
|
+
get wrapLines() {
|
|
4716
|
+
return this._wrapLines;
|
|
4717
|
+
}
|
|
4718
|
+
/**
|
|
4719
|
+
* Sets whether a text element should automatically reduce its font size (down to `min-font-size`)
|
|
4720
|
+
* so the text fits within the element's width. Requires `auto-width` to be `false`.
|
|
4721
|
+
* @param value - Whether to auto-fit the width.
|
|
4722
|
+
*/
|
|
4723
|
+
set autoFitWidth(value) {
|
|
4724
|
+
this._autoFitWidth = value;
|
|
4725
|
+
if (this.component) {
|
|
4726
|
+
this.component.autoFitWidth = value;
|
|
4727
|
+
}
|
|
4728
|
+
}
|
|
4729
|
+
/**
|
|
4730
|
+
* Gets whether a text element automatically reduces its font size to fit its width.
|
|
4731
|
+
* @returns Whether the width is auto-fit.
|
|
4732
|
+
*/
|
|
4733
|
+
get autoFitWidth() {
|
|
4734
|
+
return this._autoFitWidth;
|
|
4735
|
+
}
|
|
4736
|
+
/**
|
|
4737
|
+
* Sets whether a text element should automatically reduce its font size (down to `min-font-size`)
|
|
4738
|
+
* so the text fits within the element's height. Requires `auto-height` to be `false`.
|
|
4739
|
+
* @param value - Whether to auto-fit the height.
|
|
4740
|
+
*/
|
|
4741
|
+
set autoFitHeight(value) {
|
|
4742
|
+
this._autoFitHeight = value;
|
|
4743
|
+
if (this.component) {
|
|
4744
|
+
this.component.autoFitHeight = value;
|
|
4745
|
+
}
|
|
4746
|
+
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Gets whether a text element automatically reduces its font size to fit its height.
|
|
4749
|
+
* @returns Whether the height is auto-fit.
|
|
4750
|
+
*/
|
|
4751
|
+
get autoFitHeight() {
|
|
4752
|
+
return this._autoFitHeight;
|
|
4753
|
+
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Sets the smallest font size a text element may use when auto-fitting.
|
|
4756
|
+
* @param value - The minimum font size.
|
|
4757
|
+
*/
|
|
4758
|
+
set minFontSize(value) {
|
|
4759
|
+
this._minFontSize = value;
|
|
4760
|
+
if (this.component) {
|
|
4761
|
+
this.component.minFontSize = value;
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
/**
|
|
4765
|
+
* Gets the smallest font size a text element may use when auto-fitting.
|
|
4766
|
+
* @returns The minimum font size.
|
|
4767
|
+
*/
|
|
4768
|
+
get minFontSize() {
|
|
4769
|
+
return this._minFontSize;
|
|
4770
|
+
}
|
|
4771
|
+
/**
|
|
4772
|
+
* Sets the largest font size a text element may use when auto-fitting.
|
|
4773
|
+
* @param value - The maximum font size.
|
|
4774
|
+
*/
|
|
4775
|
+
set maxFontSize(value) {
|
|
4776
|
+
this._maxFontSize = value;
|
|
4777
|
+
if (this.component) {
|
|
4778
|
+
this.component.maxFontSize = value;
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
/**
|
|
4782
|
+
* Gets the largest font size a text element may use when auto-fitting.
|
|
4783
|
+
* @returns The maximum font size.
|
|
4784
|
+
*/
|
|
4785
|
+
get maxFontSize() {
|
|
4786
|
+
return this._maxFontSize;
|
|
4787
|
+
}
|
|
4788
|
+
static get observedAttributes() {
|
|
4789
|
+
return [
|
|
4790
|
+
...super.observedAttributes,
|
|
4791
|
+
'anchor',
|
|
4792
|
+
'auto-width',
|
|
4793
|
+
'auto-height',
|
|
4794
|
+
'auto-fit-width',
|
|
4795
|
+
'auto-fit-height',
|
|
4796
|
+
'color',
|
|
4797
|
+
'enable-markup',
|
|
4798
|
+
'font-asset',
|
|
4799
|
+
'font-size',
|
|
4800
|
+
'max-font-size',
|
|
4801
|
+
'min-font-size',
|
|
4802
|
+
'height',
|
|
4803
|
+
'line-height',
|
|
4804
|
+
'margin',
|
|
4805
|
+
'mask',
|
|
4806
|
+
'opacity',
|
|
4807
|
+
'pivot',
|
|
4808
|
+
'pixels-per-unit',
|
|
4809
|
+
'sprite-asset',
|
|
4810
|
+
'sprite-frame',
|
|
4811
|
+
'text',
|
|
4812
|
+
'texture-asset',
|
|
4813
|
+
'type',
|
|
4814
|
+
'use-input',
|
|
4815
|
+
'width',
|
|
4816
|
+
'wrap-lines'
|
|
4817
|
+
];
|
|
4818
|
+
}
|
|
4819
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
4820
|
+
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4821
|
+
switch (name) {
|
|
4822
|
+
case 'anchor':
|
|
4823
|
+
this.anchor = parseVec4(newValue, new Vec4(0.5, 0.5, 0.5, 0.5), name);
|
|
4824
|
+
break;
|
|
4825
|
+
case 'auto-width':
|
|
4826
|
+
this.autoWidth = parseBool(newValue, true);
|
|
4827
|
+
break;
|
|
4828
|
+
case 'auto-height':
|
|
4829
|
+
this.autoHeight = parseBool(newValue, true);
|
|
4830
|
+
break;
|
|
4831
|
+
case 'auto-fit-width':
|
|
4832
|
+
this.autoFitWidth = parseBool(newValue, false);
|
|
4833
|
+
break;
|
|
4834
|
+
case 'auto-fit-height':
|
|
4835
|
+
this.autoFitHeight = parseBool(newValue, false);
|
|
4836
|
+
break;
|
|
4837
|
+
case 'color':
|
|
4838
|
+
this.color = parseColor(newValue, Color.WHITE, name);
|
|
4839
|
+
break;
|
|
4840
|
+
case 'enable-markup':
|
|
4841
|
+
this.enableMarkup = parseBool(newValue, false);
|
|
4842
|
+
break;
|
|
4843
|
+
case 'font-asset':
|
|
4844
|
+
this.fontAsset = newValue ?? '';
|
|
4845
|
+
break;
|
|
4846
|
+
case 'font-size':
|
|
4847
|
+
this.fontSize = parseNumber(newValue, 32, name);
|
|
4848
|
+
break;
|
|
4849
|
+
case 'max-font-size':
|
|
4850
|
+
this.maxFontSize = parseNumber(newValue, 32, name);
|
|
4851
|
+
break;
|
|
4852
|
+
case 'min-font-size':
|
|
4853
|
+
this.minFontSize = parseNumber(newValue, 8, name);
|
|
4854
|
+
break;
|
|
4855
|
+
case 'height':
|
|
4856
|
+
this.height = parseNumber(newValue, 0, name);
|
|
4857
|
+
break;
|
|
4858
|
+
case 'line-height':
|
|
4859
|
+
this.lineHeight = parseNumber(newValue, 32, name);
|
|
4860
|
+
break;
|
|
4861
|
+
case 'margin':
|
|
4862
|
+
this.margin = parseVec4(newValue, null, name);
|
|
4863
|
+
break;
|
|
4864
|
+
case 'mask':
|
|
4865
|
+
this.mask = parseBool(newValue, false);
|
|
4866
|
+
break;
|
|
4867
|
+
case 'opacity':
|
|
4868
|
+
this.opacity = parseNumber(newValue, 1, name);
|
|
4869
|
+
break;
|
|
4870
|
+
case 'pivot':
|
|
4871
|
+
this.pivot = parseVec2(newValue, new Vec2(0.5, 0.5), name);
|
|
4872
|
+
break;
|
|
4873
|
+
case 'pixels-per-unit':
|
|
4874
|
+
this.pixelsPerUnit = parseNumber(newValue, null, name);
|
|
4875
|
+
break;
|
|
4876
|
+
case 'sprite-asset':
|
|
4877
|
+
this.spriteAsset = newValue ?? '';
|
|
4878
|
+
break;
|
|
4879
|
+
case 'sprite-frame':
|
|
4880
|
+
this.spriteFrame = parseNumber(newValue, 0, name);
|
|
4881
|
+
break;
|
|
4882
|
+
case 'text':
|
|
4883
|
+
this.text = newValue ?? '';
|
|
4884
|
+
break;
|
|
4885
|
+
case 'texture-asset':
|
|
4886
|
+
this.textureAsset = newValue ?? '';
|
|
4887
|
+
break;
|
|
4888
|
+
case 'type':
|
|
4889
|
+
this.type = parseEnum(newValue, ['group', 'image', 'text'], 'group', name);
|
|
4890
|
+
break;
|
|
4891
|
+
case 'use-input':
|
|
4892
|
+
this.useInput = parseBool(newValue, false);
|
|
4893
|
+
break;
|
|
4894
|
+
case 'width':
|
|
4895
|
+
this.width = parseNumber(newValue, 0, name);
|
|
4896
|
+
break;
|
|
4897
|
+
case 'wrap-lines':
|
|
4898
|
+
this.wrapLines = parseBool(newValue, false);
|
|
4899
|
+
break;
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4903
|
+
customElements.define('pc-element', ElementComponentElement);
|
|
4904
|
+
|
|
4905
|
+
/**
|
|
4906
|
+
* The JointComponentElement interface provides properties and methods for manipulating
|
|
4907
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-joint/ | `<pc-joint>`} elements.
|
|
4908
|
+
* The JointComponentElement interface also inherits the properties and methods of the
|
|
4909
|
+
* {@link HTMLElement} interface.
|
|
4910
|
+
*
|
|
4911
|
+
* The entity holding the joint is not itself constrained. Its world transform defines the joint
|
|
4912
|
+
* frame — the anchor point and axes the constraint operates about — with the local X axis as the
|
|
4913
|
+
* primary axis: a hinge rotates about it, a slider translates along it and a ball joint twists
|
|
4914
|
+
* about it. The constrained bodies are referenced by `entity-a` and `entity-b`, both of which need
|
|
4915
|
+
* a rigid body component; leaving `entity-b` empty constrains `entity-a` to a fixed point in world
|
|
4916
|
+
* space. The underlying engine component is in alpha, so its API may change.
|
|
4917
|
+
*
|
|
4918
|
+
* @fires {CustomEvent} break - Fired when the impulse on the joint exceeds `break-impulse` and the
|
|
4919
|
+
* constraint breaks. A broken joint no longer constrains its bodies; calling `refreshFrames()` on
|
|
4920
|
+
* the underlying component re-attaches it. Bubbles and is composed.
|
|
4921
|
+
*
|
|
4922
|
+
* @category Components
|
|
4923
|
+
*/
|
|
4924
|
+
class JointComponentElement extends ComponentElement {
|
|
4925
|
+
/**
|
|
4926
|
+
* The spring damping of the joint per angular axis.
|
|
4927
|
+
*/
|
|
4928
|
+
_angularDamping = new Vec3(1, 1, 1);
|
|
4929
|
+
/**
|
|
4930
|
+
* The rest angle of the joint's angular springs.
|
|
4931
|
+
*/
|
|
4932
|
+
_angularEquilibrium = new Vec3();
|
|
4933
|
+
/**
|
|
4934
|
+
* The rotation limits of the joint about its X axis.
|
|
4935
|
+
*/
|
|
4936
|
+
_angularLimitsX = new Vec2();
|
|
4937
|
+
/**
|
|
4938
|
+
* The rotation limits of the joint about its Y axis.
|
|
4939
|
+
*/
|
|
4940
|
+
_angularLimitsY = new Vec2();
|
|
4941
|
+
/**
|
|
4942
|
+
* The rotation limits of the joint about its Z axis.
|
|
4943
|
+
*/
|
|
4944
|
+
_angularLimitsZ = new Vec2();
|
|
4945
|
+
/**
|
|
4946
|
+
* The rotational degree of freedom of the joint about its X axis.
|
|
4947
|
+
*/
|
|
4948
|
+
_angularMotionX = 'locked';
|
|
4949
|
+
/**
|
|
4950
|
+
* The rotational degree of freedom of the joint about its Y axis.
|
|
4951
|
+
*/
|
|
4952
|
+
_angularMotionY = 'locked';
|
|
4953
|
+
/**
|
|
4954
|
+
* The rotational degree of freedom of the joint about its Z axis.
|
|
4955
|
+
*/
|
|
4956
|
+
_angularMotionZ = 'locked';
|
|
4957
|
+
/**
|
|
4958
|
+
* The spring stiffness of the joint per angular axis.
|
|
4959
|
+
*/
|
|
4960
|
+
_angularStiffness = new Vec3();
|
|
4961
|
+
/**
|
|
4962
|
+
* The impulse above which the joint breaks.
|
|
4963
|
+
*/
|
|
4964
|
+
_breakImpulse = Infinity;
|
|
4965
|
+
/**
|
|
4966
|
+
* Whether collision is enabled between the constrained bodies.
|
|
4967
|
+
*/
|
|
4968
|
+
_enableCollision = false;
|
|
4969
|
+
/**
|
|
4970
|
+
* Whether the joint's limits are enforced.
|
|
4971
|
+
*/
|
|
4972
|
+
_enableLimits = false;
|
|
4973
|
+
/**
|
|
4974
|
+
* The reference to the entity providing the first constrained body.
|
|
4975
|
+
*/
|
|
4976
|
+
_entityA = '';
|
|
4977
|
+
/**
|
|
4978
|
+
* The reference to the entity providing the second constrained body.
|
|
4979
|
+
*/
|
|
4980
|
+
_entityB = '';
|
|
4981
|
+
/**
|
|
4982
|
+
* The rotation or travel limits of the joint.
|
|
4983
|
+
*/
|
|
4984
|
+
_limits = new Vec2(-45, 45);
|
|
4985
|
+
/**
|
|
4986
|
+
* The spring damping of the joint per linear axis.
|
|
4987
|
+
*/
|
|
4988
|
+
_linearDamping = new Vec3(1, 1, 1);
|
|
4989
|
+
/**
|
|
4990
|
+
* The rest point of the joint's linear springs.
|
|
4991
|
+
*/
|
|
4992
|
+
_linearEquilibrium = new Vec3();
|
|
4993
|
+
/**
|
|
4994
|
+
* The translation limits of the joint along its X axis.
|
|
4995
|
+
*/
|
|
4996
|
+
_linearLimitsX = new Vec2();
|
|
4997
|
+
/**
|
|
4998
|
+
* The translation limits of the joint along its Y axis.
|
|
4999
|
+
*/
|
|
5000
|
+
_linearLimitsY = new Vec2();
|
|
5001
|
+
/**
|
|
5002
|
+
* The translation limits of the joint along its Z axis.
|
|
5003
|
+
*/
|
|
5004
|
+
_linearLimitsZ = new Vec2();
|
|
5005
|
+
/**
|
|
5006
|
+
* The linear degree of freedom of the joint along its X axis.
|
|
5007
|
+
*/
|
|
5008
|
+
_linearMotionX = 'locked';
|
|
5009
|
+
/**
|
|
5010
|
+
* The linear degree of freedom of the joint along its Y axis.
|
|
5011
|
+
*/
|
|
5012
|
+
_linearMotionY = 'locked';
|
|
5013
|
+
/**
|
|
5014
|
+
* The linear degree of freedom of the joint along its Z axis.
|
|
5015
|
+
*/
|
|
5016
|
+
_linearMotionZ = 'locked';
|
|
5017
|
+
/**
|
|
5018
|
+
* The spring stiffness of the joint per linear axis.
|
|
5019
|
+
*/
|
|
5020
|
+
_linearStiffness = new Vec3();
|
|
5021
|
+
/**
|
|
5022
|
+
* The maximum torque or force of the joint's motor.
|
|
5023
|
+
*/
|
|
5024
|
+
_maxMotorForce = 0;
|
|
5025
|
+
/**
|
|
5026
|
+
* The target speed of the joint's motor.
|
|
5027
|
+
*/
|
|
5028
|
+
_motorSpeed = 0;
|
|
5029
|
+
/**
|
|
5030
|
+
* The maximum swing of the joint around the joint frame's Y axis.
|
|
5031
|
+
*/
|
|
5032
|
+
_swingLimitY = 45;
|
|
5033
|
+
/**
|
|
5034
|
+
* The maximum swing of the joint around the joint frame's Z axis.
|
|
5035
|
+
*/
|
|
5036
|
+
_swingLimitZ = 45;
|
|
5037
|
+
/**
|
|
5038
|
+
* The maximum twist of the joint about its primary axis.
|
|
5039
|
+
*/
|
|
5040
|
+
_twistLimit = 20;
|
|
5041
|
+
/**
|
|
5042
|
+
* The type of the joint.
|
|
5043
|
+
*/
|
|
5044
|
+
_type = 'fixed';
|
|
5045
|
+
/** @ignore */
|
|
5046
|
+
constructor() {
|
|
5047
|
+
super('joint');
|
|
5048
|
+
}
|
|
5049
|
+
getInitialComponentData() {
|
|
5050
|
+
return {
|
|
5051
|
+
angularDamping: this._angularDamping,
|
|
5052
|
+
angularEquilibrium: this._angularEquilibrium,
|
|
5053
|
+
angularLimitsX: this._angularLimitsX,
|
|
5054
|
+
angularLimitsY: this._angularLimitsY,
|
|
5055
|
+
angularLimitsZ: this._angularLimitsZ,
|
|
5056
|
+
angularMotionX: this._angularMotionX,
|
|
5057
|
+
angularMotionY: this._angularMotionY,
|
|
5058
|
+
angularMotionZ: this._angularMotionZ,
|
|
5059
|
+
angularStiffness: this._angularStiffness,
|
|
5060
|
+
breakImpulse: this._breakImpulse,
|
|
5061
|
+
enableCollision: this._enableCollision,
|
|
5062
|
+
enableLimits: this._enableLimits,
|
|
5063
|
+
entityA: getEntity(this._entityA),
|
|
5064
|
+
entityB: getEntity(this._entityB),
|
|
5065
|
+
limits: this._limits,
|
|
5066
|
+
linearDamping: this._linearDamping,
|
|
5067
|
+
linearEquilibrium: this._linearEquilibrium,
|
|
5068
|
+
linearLimitsX: this._linearLimitsX,
|
|
5069
|
+
linearLimitsY: this._linearLimitsY,
|
|
5070
|
+
linearLimitsZ: this._linearLimitsZ,
|
|
5071
|
+
linearMotionX: this._linearMotionX,
|
|
5072
|
+
linearMotionY: this._linearMotionY,
|
|
5073
|
+
linearMotionZ: this._linearMotionZ,
|
|
5074
|
+
linearStiffness: this._linearStiffness,
|
|
5075
|
+
maxMotorForce: this._maxMotorForce,
|
|
5076
|
+
motorSpeed: this._motorSpeed,
|
|
5077
|
+
swingLimitY: this._swingLimitY,
|
|
5078
|
+
swingLimitZ: this._swingLimitZ,
|
|
5079
|
+
twistLimit: this._twistLimit,
|
|
5080
|
+
type: this._type
|
|
5081
|
+
};
|
|
5082
|
+
}
|
|
5083
|
+
_onBreak() {
|
|
5084
|
+
this.dispatchEvent(new CustomEvent('break', { bubbles: true, composed: true }));
|
|
5085
|
+
}
|
|
5086
|
+
initComponent() {
|
|
5087
|
+
const component = this.component;
|
|
5088
|
+
if (!component) {
|
|
5089
|
+
return;
|
|
5090
|
+
}
|
|
5091
|
+
// A host readiness cycle can re-run this against the same surviving component instance,
|
|
5092
|
+
// so the off/on pair keeps the subscription single either way. Component removal destroys
|
|
5093
|
+
// the instance and its listeners with it, so there is no disconnect-side teardown.
|
|
5094
|
+
component.off('break', this._onBreak, this);
|
|
5095
|
+
component.on('break', this._onBreak, this);
|
|
5096
|
+
}
|
|
5097
|
+
/**
|
|
5098
|
+
* Gets the underlying PlayCanvas joint component.
|
|
5099
|
+
* @returns The joint component.
|
|
5100
|
+
*/
|
|
5101
|
+
get component() {
|
|
5102
|
+
return super.component;
|
|
5103
|
+
}
|
|
5104
|
+
/**
|
|
5105
|
+
* Sets the spring damping of a 6dof joint per angular axis, used on axes with a non-zero
|
|
5106
|
+
* angular-stiffness.
|
|
5107
|
+
* @param value - The angular spring damping.
|
|
5108
|
+
*/
|
|
5109
|
+
set angularDamping(value) {
|
|
5110
|
+
this._angularDamping = value;
|
|
5111
|
+
if (this.component) {
|
|
5112
|
+
this.component.angularDamping = value;
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
/**
|
|
5116
|
+
* Gets the spring damping of the joint per angular axis.
|
|
5117
|
+
* @returns The angular spring damping.
|
|
5118
|
+
*/
|
|
5119
|
+
get angularDamping() {
|
|
5120
|
+
return this._angularDamping;
|
|
5121
|
+
}
|
|
5122
|
+
/**
|
|
5123
|
+
* Sets the rest angle of a 6dof joint's angular springs in degrees per axis, used on axes with
|
|
5124
|
+
* a non-zero angular-stiffness.
|
|
5125
|
+
* @param value - The angular spring rest angles.
|
|
5126
|
+
*/
|
|
5127
|
+
set angularEquilibrium(value) {
|
|
5128
|
+
this._angularEquilibrium = value;
|
|
5129
|
+
if (this.component) {
|
|
5130
|
+
this.component.angularEquilibrium = value;
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
/**
|
|
5134
|
+
* Gets the rest angle of the joint's angular springs.
|
|
5135
|
+
* @returns The angular spring rest angles.
|
|
5136
|
+
*/
|
|
5137
|
+
get angularEquilibrium() {
|
|
5138
|
+
return this._angularEquilibrium;
|
|
5139
|
+
}
|
|
5140
|
+
/**
|
|
5141
|
+
* Sets the lower and upper rotation limit of a 6dof joint about its X axis in degrees, used
|
|
5142
|
+
* when angular-motion-x is limited.
|
|
5143
|
+
* @param value - The X axis rotation limits.
|
|
5144
|
+
*/
|
|
5145
|
+
set angularLimitsX(value) {
|
|
5146
|
+
this._angularLimitsX = value;
|
|
5147
|
+
if (this.component) {
|
|
5148
|
+
this.component.angularLimitsX = value;
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
5151
|
+
/**
|
|
5152
|
+
* Gets the rotation limits of the joint about its X axis.
|
|
5153
|
+
* @returns The X axis rotation limits.
|
|
5154
|
+
*/
|
|
5155
|
+
get angularLimitsX() {
|
|
5156
|
+
return this._angularLimitsX;
|
|
5157
|
+
}
|
|
5158
|
+
/**
|
|
5159
|
+
* Sets the lower and upper rotation limit of a 6dof joint about its Y axis in degrees, used
|
|
5160
|
+
* when angular-motion-y is limited.
|
|
5161
|
+
* @param value - The Y axis rotation limits.
|
|
5162
|
+
*/
|
|
5163
|
+
set angularLimitsY(value) {
|
|
5164
|
+
this._angularLimitsY = value;
|
|
5165
|
+
if (this.component) {
|
|
5166
|
+
this.component.angularLimitsY = value;
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
/**
|
|
5170
|
+
* Gets the rotation limits of the joint about its Y axis.
|
|
5171
|
+
* @returns The Y axis rotation limits.
|
|
5172
|
+
*/
|
|
5173
|
+
get angularLimitsY() {
|
|
5174
|
+
return this._angularLimitsY;
|
|
5175
|
+
}
|
|
5176
|
+
/**
|
|
5177
|
+
* Sets the lower and upper rotation limit of a 6dof joint about its Z axis in degrees, used
|
|
5178
|
+
* when angular-motion-z is limited.
|
|
5179
|
+
* @param value - The Z axis rotation limits.
|
|
5180
|
+
*/
|
|
5181
|
+
set angularLimitsZ(value) {
|
|
5182
|
+
this._angularLimitsZ = value;
|
|
5183
|
+
if (this.component) {
|
|
5184
|
+
this.component.angularLimitsZ = value;
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
/**
|
|
5188
|
+
* Gets the rotation limits of the joint about its Z axis.
|
|
5189
|
+
* @returns The Z axis rotation limits.
|
|
5190
|
+
*/
|
|
5191
|
+
get angularLimitsZ() {
|
|
5192
|
+
return this._angularLimitsZ;
|
|
5193
|
+
}
|
|
5194
|
+
/**
|
|
5195
|
+
* Sets how a 6dof joint constrains rotation about its X axis. Can be `locked`, `limited` or
|
|
5196
|
+
* `free`. Defaults to `locked`.
|
|
5197
|
+
* @param value - The X axis rotational degree of freedom.
|
|
5198
|
+
*/
|
|
5199
|
+
set angularMotionX(value) {
|
|
5200
|
+
this._angularMotionX = value;
|
|
5201
|
+
if (this.component) {
|
|
5202
|
+
this.component.angularMotionX = value;
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
/**
|
|
5206
|
+
* Gets how the joint constrains rotation about its X axis.
|
|
5207
|
+
* @returns The X axis rotational degree of freedom.
|
|
5208
|
+
*/
|
|
5209
|
+
get angularMotionX() {
|
|
5210
|
+
return this._angularMotionX;
|
|
5211
|
+
}
|
|
5212
|
+
/**
|
|
5213
|
+
* Sets how a 6dof joint constrains rotation about its Y axis. Can be `locked`, `limited` or
|
|
5214
|
+
* `free`. Defaults to `locked`.
|
|
5215
|
+
* @param value - The Y axis rotational degree of freedom.
|
|
5216
|
+
*/
|
|
5217
|
+
set angularMotionY(value) {
|
|
5218
|
+
this._angularMotionY = value;
|
|
5219
|
+
if (this.component) {
|
|
5220
|
+
this.component.angularMotionY = value;
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
/**
|
|
5224
|
+
* Gets how the joint constrains rotation about its Y axis.
|
|
5225
|
+
* @returns The Y axis rotational degree of freedom.
|
|
5226
|
+
*/
|
|
5227
|
+
get angularMotionY() {
|
|
5228
|
+
return this._angularMotionY;
|
|
5229
|
+
}
|
|
5230
|
+
/**
|
|
5231
|
+
* Sets how a 6dof joint constrains rotation about its Z axis. Can be `locked`, `limited` or
|
|
5232
|
+
* `free`. Defaults to `locked`.
|
|
5233
|
+
* @param value - The Z axis rotational degree of freedom.
|
|
5234
|
+
*/
|
|
5235
|
+
set angularMotionZ(value) {
|
|
5236
|
+
this._angularMotionZ = value;
|
|
5237
|
+
if (this.component) {
|
|
5238
|
+
this.component.angularMotionZ = value;
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
/**
|
|
5242
|
+
* Gets how the joint constrains rotation about its Z axis.
|
|
5243
|
+
* @returns The Z axis rotational degree of freedom.
|
|
5244
|
+
*/
|
|
5245
|
+
get angularMotionZ() {
|
|
5246
|
+
return this._angularMotionZ;
|
|
5247
|
+
}
|
|
5248
|
+
/**
|
|
5249
|
+
* Sets the spring stiffness of a 6dof joint per angular axis, where 0 disables the spring on
|
|
5250
|
+
* that axis.
|
|
5251
|
+
* @param value - The angular spring stiffness.
|
|
5252
|
+
*/
|
|
5253
|
+
set angularStiffness(value) {
|
|
5254
|
+
this._angularStiffness = value;
|
|
5255
|
+
if (this.component) {
|
|
5256
|
+
this.component.angularStiffness = value;
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
/**
|
|
5260
|
+
* Gets the spring stiffness of the joint per angular axis.
|
|
5261
|
+
* @returns The angular spring stiffness.
|
|
5262
|
+
*/
|
|
5263
|
+
get angularStiffness() {
|
|
5264
|
+
return this._angularStiffness;
|
|
5265
|
+
}
|
|
5266
|
+
/**
|
|
5267
|
+
* Sets the impulse in newton seconds above which the joint breaks. Defaults to `Infinity`,
|
|
5268
|
+
* which makes the joint unbreakable.
|
|
5269
|
+
* @param value - The break impulse.
|
|
5270
|
+
*/
|
|
5271
|
+
set breakImpulse(value) {
|
|
5272
|
+
this._breakImpulse = value;
|
|
5273
|
+
if (this.component) {
|
|
5274
|
+
this.component.breakImpulse = value;
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
/**
|
|
5278
|
+
* Gets the impulse above which the joint breaks.
|
|
5279
|
+
* @returns The break impulse.
|
|
5280
|
+
*/
|
|
5281
|
+
get breakImpulse() {
|
|
5282
|
+
return this._breakImpulse;
|
|
5283
|
+
}
|
|
5284
|
+
/**
|
|
5285
|
+
* Sets whether collision is enabled between the two constrained bodies.
|
|
5286
|
+
* @param value - Whether collision is enabled.
|
|
5287
|
+
*/
|
|
5288
|
+
set enableCollision(value) {
|
|
5289
|
+
this._enableCollision = value;
|
|
5290
|
+
if (this.component) {
|
|
5291
|
+
this.component.enableCollision = value;
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
/**
|
|
5295
|
+
* Gets whether collision is enabled between the two constrained bodies.
|
|
5296
|
+
* @returns Whether collision is enabled.
|
|
5297
|
+
*/
|
|
5298
|
+
get enableCollision() {
|
|
5299
|
+
return this._enableCollision;
|
|
5300
|
+
}
|
|
5301
|
+
/**
|
|
5302
|
+
* Sets whether the limits of a hinge, slider or ball joint are enforced.
|
|
5303
|
+
* @param value - Whether the limits are enforced.
|
|
5304
|
+
*/
|
|
5305
|
+
set enableLimits(value) {
|
|
5306
|
+
this._enableLimits = value;
|
|
5307
|
+
if (this.component) {
|
|
5308
|
+
this.component.enableLimits = value;
|
|
5309
|
+
}
|
|
5310
|
+
}
|
|
5311
|
+
/**
|
|
5312
|
+
* Gets whether the limits of the joint are enforced.
|
|
5313
|
+
* @returns Whether the limits are enforced.
|
|
5314
|
+
*/
|
|
5315
|
+
get enableLimits() {
|
|
5316
|
+
return this._enableLimits;
|
|
5317
|
+
}
|
|
5318
|
+
/**
|
|
5319
|
+
* Sets the reference (CSS selector, element id or entity name) to the `<pc-entity>` providing
|
|
5320
|
+
* the first constrained body. The reference resolves when it is set, so an entity created
|
|
5321
|
+
* later is picked up by setting the attribute again.
|
|
5322
|
+
* @param value - The first body's entity reference.
|
|
5323
|
+
*/
|
|
5324
|
+
set entityA(value) {
|
|
5325
|
+
this._entityA = value;
|
|
5326
|
+
if (this.component) {
|
|
5327
|
+
this.component.entityA = getEntity(value);
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
/**
|
|
5331
|
+
* Gets the reference to the `<pc-entity>` providing the first constrained body.
|
|
5332
|
+
* @returns The first body's entity reference.
|
|
5333
|
+
*/
|
|
5334
|
+
get entityA() {
|
|
5335
|
+
return this._entityA;
|
|
5336
|
+
}
|
|
5337
|
+
/**
|
|
5338
|
+
* Sets the reference (CSS selector, element id or entity name) to the `<pc-entity>` providing
|
|
5339
|
+
* the second constrained body, or empty to constrain the first body to a fixed point in world
|
|
5340
|
+
* space. The reference resolves when it is set, so an entity created later is picked up by
|
|
5341
|
+
* setting the attribute again.
|
|
5342
|
+
* @param value - The second body's entity reference.
|
|
5343
|
+
*/
|
|
5344
|
+
set entityB(value) {
|
|
5345
|
+
this._entityB = value;
|
|
5346
|
+
if (this.component) {
|
|
5347
|
+
this.component.entityB = getEntity(value);
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
/**
|
|
5351
|
+
* Gets the reference to the `<pc-entity>` providing the second constrained body.
|
|
5352
|
+
* @returns The second body's entity reference.
|
|
5353
|
+
*/
|
|
5354
|
+
get entityB() {
|
|
5355
|
+
return this._entityB;
|
|
5356
|
+
}
|
|
5357
|
+
/**
|
|
5358
|
+
* Sets the lower and upper limit of a hinge joint's rotation in degrees, or a slider joint's
|
|
5359
|
+
* travel in meters, applied when enable-limits is set.
|
|
5360
|
+
* @param value - The rotation or travel limits.
|
|
5361
|
+
*/
|
|
5362
|
+
set limits(value) {
|
|
5363
|
+
this._limits = value;
|
|
5364
|
+
if (this.component) {
|
|
5365
|
+
this.component.limits = value;
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
/**
|
|
5369
|
+
* Gets the rotation or travel limits of the joint.
|
|
5370
|
+
* @returns The rotation or travel limits.
|
|
5371
|
+
*/
|
|
5372
|
+
get limits() {
|
|
5373
|
+
return this._limits;
|
|
5374
|
+
}
|
|
5375
|
+
/**
|
|
5376
|
+
* Sets the spring damping of a 6dof joint per linear axis, used on axes with a non-zero
|
|
5377
|
+
* linear-stiffness.
|
|
5378
|
+
* @param value - The linear spring damping.
|
|
5379
|
+
*/
|
|
5380
|
+
set linearDamping(value) {
|
|
5381
|
+
this._linearDamping = value;
|
|
5382
|
+
if (this.component) {
|
|
5383
|
+
this.component.linearDamping = value;
|
|
5384
|
+
}
|
|
5385
|
+
}
|
|
5386
|
+
/**
|
|
5387
|
+
* Gets the spring damping of the joint per linear axis.
|
|
5388
|
+
* @returns The linear spring damping.
|
|
5389
|
+
*/
|
|
5390
|
+
get linearDamping() {
|
|
5391
|
+
return this._linearDamping;
|
|
5392
|
+
}
|
|
5393
|
+
/**
|
|
5394
|
+
* Sets the rest point of a 6dof joint's linear springs in meters per axis, used on axes with a
|
|
5395
|
+
* non-zero linear-stiffness.
|
|
5396
|
+
* @param value - The linear spring rest points.
|
|
5397
|
+
*/
|
|
5398
|
+
set linearEquilibrium(value) {
|
|
5399
|
+
this._linearEquilibrium = value;
|
|
5400
|
+
if (this.component) {
|
|
5401
|
+
this.component.linearEquilibrium = value;
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
/**
|
|
5405
|
+
* Gets the rest point of the joint's linear springs.
|
|
5406
|
+
* @returns The linear spring rest points.
|
|
5407
|
+
*/
|
|
5408
|
+
get linearEquilibrium() {
|
|
5409
|
+
return this._linearEquilibrium;
|
|
5410
|
+
}
|
|
5411
|
+
/**
|
|
5412
|
+
* Sets the lower and upper translation limit of a 6dof joint along its X axis in meters, used
|
|
5413
|
+
* when linear-motion-x is limited.
|
|
5414
|
+
* @param value - The X axis translation limits.
|
|
5415
|
+
*/
|
|
5416
|
+
set linearLimitsX(value) {
|
|
5417
|
+
this._linearLimitsX = value;
|
|
5418
|
+
if (this.component) {
|
|
5419
|
+
this.component.linearLimitsX = value;
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
/**
|
|
5423
|
+
* Gets the translation limits of the joint along its X axis.
|
|
5424
|
+
* @returns The X axis translation limits.
|
|
5425
|
+
*/
|
|
5426
|
+
get linearLimitsX() {
|
|
5427
|
+
return this._linearLimitsX;
|
|
5428
|
+
}
|
|
5429
|
+
/**
|
|
5430
|
+
* Sets the lower and upper translation limit of a 6dof joint along its Y axis in meters, used
|
|
5431
|
+
* when linear-motion-y is limited.
|
|
5432
|
+
* @param value - The Y axis translation limits.
|
|
5433
|
+
*/
|
|
5434
|
+
set linearLimitsY(value) {
|
|
5435
|
+
this._linearLimitsY = value;
|
|
5436
|
+
if (this.component) {
|
|
5437
|
+
this.component.linearLimitsY = value;
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5440
|
+
/**
|
|
5441
|
+
* Gets the translation limits of the joint along its Y axis.
|
|
5442
|
+
* @returns The Y axis translation limits.
|
|
5443
|
+
*/
|
|
5444
|
+
get linearLimitsY() {
|
|
5445
|
+
return this._linearLimitsY;
|
|
5446
|
+
}
|
|
5447
|
+
/**
|
|
5448
|
+
* Sets the lower and upper translation limit of a 6dof joint along its Z axis in meters, used
|
|
5449
|
+
* when linear-motion-z is limited.
|
|
5450
|
+
* @param value - The Z axis translation limits.
|
|
5451
|
+
*/
|
|
5452
|
+
set linearLimitsZ(value) {
|
|
5453
|
+
this._linearLimitsZ = value;
|
|
5454
|
+
if (this.component) {
|
|
5455
|
+
this.component.linearLimitsZ = value;
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
/**
|
|
5459
|
+
* Gets the translation limits of the joint along its Z axis.
|
|
5460
|
+
* @returns The Z axis translation limits.
|
|
5461
|
+
*/
|
|
5462
|
+
get linearLimitsZ() {
|
|
5463
|
+
return this._linearLimitsZ;
|
|
5464
|
+
}
|
|
5465
|
+
/**
|
|
5466
|
+
* Sets how a 6dof joint constrains translation along its X axis. Can be `locked`, `limited` or
|
|
5467
|
+
* `free`. Defaults to `locked`.
|
|
5468
|
+
* @param value - The X axis linear degree of freedom.
|
|
5469
|
+
*/
|
|
5470
|
+
set linearMotionX(value) {
|
|
5471
|
+
this._linearMotionX = value;
|
|
5472
|
+
if (this.component) {
|
|
5473
|
+
this.component.linearMotionX = value;
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
/**
|
|
5477
|
+
* Gets how the joint constrains translation along its X axis.
|
|
5478
|
+
* @returns The X axis linear degree of freedom.
|
|
5479
|
+
*/
|
|
5480
|
+
get linearMotionX() {
|
|
5481
|
+
return this._linearMotionX;
|
|
5482
|
+
}
|
|
5483
|
+
/**
|
|
5484
|
+
* Sets how a 6dof joint constrains translation along its Y axis. Can be `locked`, `limited` or
|
|
5485
|
+
* `free`. Defaults to `locked`.
|
|
5486
|
+
* @param value - The Y axis linear degree of freedom.
|
|
5487
|
+
*/
|
|
5488
|
+
set linearMotionY(value) {
|
|
5489
|
+
this._linearMotionY = value;
|
|
5490
|
+
if (this.component) {
|
|
5491
|
+
this.component.linearMotionY = value;
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
/**
|
|
5495
|
+
* Gets how the joint constrains translation along its Y axis.
|
|
5496
|
+
* @returns The Y axis linear degree of freedom.
|
|
5497
|
+
*/
|
|
5498
|
+
get linearMotionY() {
|
|
5499
|
+
return this._linearMotionY;
|
|
5500
|
+
}
|
|
5501
|
+
/**
|
|
5502
|
+
* Sets how a 6dof joint constrains translation along its Z axis. Can be `locked`, `limited` or
|
|
5503
|
+
* `free`. Defaults to `locked`.
|
|
5504
|
+
* @param value - The Z axis linear degree of freedom.
|
|
5505
|
+
*/
|
|
5506
|
+
set linearMotionZ(value) {
|
|
5507
|
+
this._linearMotionZ = value;
|
|
5508
|
+
if (this.component) {
|
|
5509
|
+
this.component.linearMotionZ = value;
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
/**
|
|
5513
|
+
* Gets how the joint constrains translation along its Z axis.
|
|
5514
|
+
* @returns The Z axis linear degree of freedom.
|
|
5515
|
+
*/
|
|
5516
|
+
get linearMotionZ() {
|
|
5517
|
+
return this._linearMotionZ;
|
|
5518
|
+
}
|
|
5519
|
+
/**
|
|
5520
|
+
* Sets the spring stiffness of a 6dof joint per linear axis, where 0 disables the spring on
|
|
5521
|
+
* that axis.
|
|
5522
|
+
* @param value - The linear spring stiffness.
|
|
5523
|
+
*/
|
|
5524
|
+
set linearStiffness(value) {
|
|
5525
|
+
this._linearStiffness = value;
|
|
5526
|
+
if (this.component) {
|
|
5527
|
+
this.component.linearStiffness = value;
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
/**
|
|
5531
|
+
* Gets the spring stiffness of the joint per linear axis.
|
|
5532
|
+
* @returns The linear spring stiffness.
|
|
5533
|
+
*/
|
|
5534
|
+
get linearStiffness() {
|
|
5535
|
+
return this._linearStiffness;
|
|
5536
|
+
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Sets the maximum torque in newton meters of a hinge joint's motor, or the maximum force in
|
|
5539
|
+
* newtons of a slider joint's motor, where 0 disables the motor.
|
|
5540
|
+
* @param value - The maximum motor torque or force.
|
|
5541
|
+
*/
|
|
5542
|
+
set maxMotorForce(value) {
|
|
5543
|
+
this._maxMotorForce = value;
|
|
5544
|
+
if (this.component) {
|
|
5545
|
+
this.component.maxMotorForce = value;
|
|
4641
5546
|
}
|
|
4642
5547
|
}
|
|
4643
5548
|
/**
|
|
4644
|
-
* Gets the
|
|
4645
|
-
* @returns The
|
|
5549
|
+
* Gets the maximum torque or force of the joint's motor.
|
|
5550
|
+
* @returns The maximum motor torque or force.
|
|
4646
5551
|
*/
|
|
4647
|
-
get
|
|
4648
|
-
return this.
|
|
5552
|
+
get maxMotorForce() {
|
|
5553
|
+
return this._maxMotorForce;
|
|
4649
5554
|
}
|
|
4650
5555
|
/**
|
|
4651
|
-
* Sets
|
|
4652
|
-
*
|
|
5556
|
+
* Sets the target speed of a hinge joint's motor in degrees per second, or a slider joint's
|
|
5557
|
+
* motor in meters per second, active while max-motor-force is greater than 0.
|
|
5558
|
+
* @param value - The motor's target speed.
|
|
4653
5559
|
*/
|
|
4654
|
-
set
|
|
4655
|
-
this.
|
|
5560
|
+
set motorSpeed(value) {
|
|
5561
|
+
this._motorSpeed = value;
|
|
4656
5562
|
if (this.component) {
|
|
4657
|
-
this.component.
|
|
5563
|
+
this.component.motorSpeed = value;
|
|
4658
5564
|
}
|
|
4659
5565
|
}
|
|
4660
5566
|
/**
|
|
4661
|
-
* Gets
|
|
4662
|
-
* @returns
|
|
5567
|
+
* Gets the target speed of the joint's motor.
|
|
5568
|
+
* @returns The motor's target speed.
|
|
4663
5569
|
*/
|
|
4664
|
-
get
|
|
4665
|
-
return this.
|
|
5570
|
+
get motorSpeed() {
|
|
5571
|
+
return this._motorSpeed;
|
|
4666
5572
|
}
|
|
4667
5573
|
/**
|
|
4668
|
-
* Sets
|
|
4669
|
-
*
|
|
4670
|
-
* @param value -
|
|
5574
|
+
* Sets the maximum swing of a ball joint around the joint frame's Y axis in degrees, applied
|
|
5575
|
+
* when enable-limits is set.
|
|
5576
|
+
* @param value - The Y axis swing limit.
|
|
4671
5577
|
*/
|
|
4672
|
-
set
|
|
4673
|
-
this.
|
|
5578
|
+
set swingLimitY(value) {
|
|
5579
|
+
this._swingLimitY = value;
|
|
4674
5580
|
if (this.component) {
|
|
4675
|
-
this.component.
|
|
5581
|
+
this.component.swingLimitY = value;
|
|
4676
5582
|
}
|
|
4677
5583
|
}
|
|
4678
5584
|
/**
|
|
4679
|
-
* Gets
|
|
4680
|
-
* @returns
|
|
5585
|
+
* Gets the maximum swing of the joint around the joint frame's Y axis.
|
|
5586
|
+
* @returns The Y axis swing limit.
|
|
4681
5587
|
*/
|
|
4682
|
-
get
|
|
4683
|
-
return this.
|
|
5588
|
+
get swingLimitY() {
|
|
5589
|
+
return this._swingLimitY;
|
|
4684
5590
|
}
|
|
4685
5591
|
/**
|
|
4686
|
-
* Sets
|
|
4687
|
-
*
|
|
4688
|
-
* @param value -
|
|
5592
|
+
* Sets the maximum swing of a ball joint around the joint frame's Z axis in degrees, applied
|
|
5593
|
+
* when enable-limits is set.
|
|
5594
|
+
* @param value - The Z axis swing limit.
|
|
4689
5595
|
*/
|
|
4690
|
-
set
|
|
4691
|
-
this.
|
|
5596
|
+
set swingLimitZ(value) {
|
|
5597
|
+
this._swingLimitZ = value;
|
|
4692
5598
|
if (this.component) {
|
|
4693
|
-
this.component.
|
|
5599
|
+
this.component.swingLimitZ = value;
|
|
4694
5600
|
}
|
|
4695
5601
|
}
|
|
4696
5602
|
/**
|
|
4697
|
-
* Gets
|
|
4698
|
-
* @returns
|
|
5603
|
+
* Gets the maximum swing of the joint around the joint frame's Z axis.
|
|
5604
|
+
* @returns The Z axis swing limit.
|
|
4699
5605
|
*/
|
|
4700
|
-
get
|
|
4701
|
-
return this.
|
|
5606
|
+
get swingLimitZ() {
|
|
5607
|
+
return this._swingLimitZ;
|
|
4702
5608
|
}
|
|
4703
5609
|
/**
|
|
4704
|
-
* Sets the
|
|
4705
|
-
*
|
|
5610
|
+
* Sets the maximum twist of a ball joint about its primary axis in degrees, applied when
|
|
5611
|
+
* enable-limits is set.
|
|
5612
|
+
* @param value - The twist limit.
|
|
4706
5613
|
*/
|
|
4707
|
-
set
|
|
4708
|
-
this.
|
|
5614
|
+
set twistLimit(value) {
|
|
5615
|
+
this._twistLimit = value;
|
|
4709
5616
|
if (this.component) {
|
|
4710
|
-
this.component.
|
|
5617
|
+
this.component.twistLimit = value;
|
|
4711
5618
|
}
|
|
4712
5619
|
}
|
|
4713
5620
|
/**
|
|
4714
|
-
* Gets the
|
|
4715
|
-
* @returns The
|
|
5621
|
+
* Gets the maximum twist of the joint about its primary axis.
|
|
5622
|
+
* @returns The twist limit.
|
|
4716
5623
|
*/
|
|
4717
|
-
get
|
|
4718
|
-
return this.
|
|
5624
|
+
get twistLimit() {
|
|
5625
|
+
return this._twistLimit;
|
|
4719
5626
|
}
|
|
4720
5627
|
/**
|
|
4721
|
-
* Sets the
|
|
4722
|
-
*
|
|
5628
|
+
* Sets the type of the joint. Can be `fixed`, `ball`, `hinge`, `slider` or `6dof`. Defaults to
|
|
5629
|
+
* `fixed`.
|
|
5630
|
+
* @param value - The joint type.
|
|
4723
5631
|
*/
|
|
4724
|
-
set
|
|
4725
|
-
this.
|
|
5632
|
+
set type(value) {
|
|
5633
|
+
this._type = value;
|
|
4726
5634
|
if (this.component) {
|
|
4727
|
-
this.component.
|
|
5635
|
+
this.component.type = value;
|
|
4728
5636
|
}
|
|
4729
5637
|
}
|
|
4730
5638
|
/**
|
|
4731
|
-
* Gets the
|
|
4732
|
-
* @returns The
|
|
5639
|
+
* Gets the type of the joint.
|
|
5640
|
+
* @returns The joint type.
|
|
4733
5641
|
*/
|
|
4734
|
-
get
|
|
4735
|
-
return this.
|
|
5642
|
+
get type() {
|
|
5643
|
+
return this._type;
|
|
4736
5644
|
}
|
|
4737
5645
|
static get observedAttributes() {
|
|
4738
5646
|
return [
|
|
4739
5647
|
...super.observedAttributes,
|
|
4740
|
-
'
|
|
4741
|
-
'
|
|
4742
|
-
'
|
|
4743
|
-
'
|
|
4744
|
-
'
|
|
4745
|
-
'
|
|
4746
|
-
'
|
|
4747
|
-
'
|
|
4748
|
-
'
|
|
4749
|
-
'
|
|
4750
|
-
'
|
|
4751
|
-
'
|
|
4752
|
-
'
|
|
4753
|
-
'
|
|
4754
|
-
'
|
|
4755
|
-
'
|
|
4756
|
-
'
|
|
4757
|
-
'
|
|
4758
|
-
'
|
|
4759
|
-
'
|
|
4760
|
-
'
|
|
4761
|
-
'
|
|
4762
|
-
'
|
|
4763
|
-
'
|
|
4764
|
-
'
|
|
4765
|
-
'
|
|
5648
|
+
'angular-damping',
|
|
5649
|
+
'angular-equilibrium',
|
|
5650
|
+
'angular-limits-x',
|
|
5651
|
+
'angular-limits-y',
|
|
5652
|
+
'angular-limits-z',
|
|
5653
|
+
'angular-motion-x',
|
|
5654
|
+
'angular-motion-y',
|
|
5655
|
+
'angular-motion-z',
|
|
5656
|
+
'angular-stiffness',
|
|
5657
|
+
'break-impulse',
|
|
5658
|
+
'enable-collision',
|
|
5659
|
+
'enable-limits',
|
|
5660
|
+
'entity-a',
|
|
5661
|
+
'entity-b',
|
|
5662
|
+
'limits',
|
|
5663
|
+
'linear-damping',
|
|
5664
|
+
'linear-equilibrium',
|
|
5665
|
+
'linear-limits-x',
|
|
5666
|
+
'linear-limits-y',
|
|
5667
|
+
'linear-limits-z',
|
|
5668
|
+
'linear-motion-x',
|
|
5669
|
+
'linear-motion-y',
|
|
5670
|
+
'linear-motion-z',
|
|
5671
|
+
'linear-stiffness',
|
|
5672
|
+
'max-motor-force',
|
|
5673
|
+
'motor-speed',
|
|
5674
|
+
'swing-limit-y',
|
|
5675
|
+
'swing-limit-z',
|
|
5676
|
+
'twist-limit',
|
|
5677
|
+
'type'
|
|
4766
5678
|
];
|
|
4767
5679
|
}
|
|
4768
5680
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
4769
5681
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4770
5682
|
switch (name) {
|
|
4771
|
-
case '
|
|
4772
|
-
this.
|
|
5683
|
+
case 'angular-damping':
|
|
5684
|
+
this.angularDamping = parseVec3(newValue, Vec3.ONE, name);
|
|
4773
5685
|
break;
|
|
4774
|
-
case '
|
|
4775
|
-
this.
|
|
5686
|
+
case 'angular-equilibrium':
|
|
5687
|
+
this.angularEquilibrium = parseVec3(newValue, Vec3.ZERO, name);
|
|
4776
5688
|
break;
|
|
4777
|
-
case '
|
|
4778
|
-
this.
|
|
5689
|
+
case 'angular-limits-x':
|
|
5690
|
+
this.angularLimitsX = parseVec2(newValue, Vec2.ZERO, name);
|
|
4779
5691
|
break;
|
|
4780
|
-
case '
|
|
4781
|
-
this.
|
|
5692
|
+
case 'angular-limits-y':
|
|
5693
|
+
this.angularLimitsY = parseVec2(newValue, Vec2.ZERO, name);
|
|
4782
5694
|
break;
|
|
4783
|
-
case '
|
|
4784
|
-
this.
|
|
5695
|
+
case 'angular-limits-z':
|
|
5696
|
+
this.angularLimitsZ = parseVec2(newValue, Vec2.ZERO, name);
|
|
4785
5697
|
break;
|
|
4786
|
-
case '
|
|
4787
|
-
this.
|
|
5698
|
+
case 'angular-motion-x':
|
|
5699
|
+
this.angularMotionX = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4788
5700
|
break;
|
|
4789
|
-
case '
|
|
4790
|
-
this.
|
|
5701
|
+
case 'angular-motion-y':
|
|
5702
|
+
this.angularMotionY = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4791
5703
|
break;
|
|
4792
|
-
case '
|
|
4793
|
-
this.
|
|
5704
|
+
case 'angular-motion-z':
|
|
5705
|
+
this.angularMotionZ = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4794
5706
|
break;
|
|
4795
|
-
case '
|
|
4796
|
-
this.
|
|
5707
|
+
case 'angular-stiffness':
|
|
5708
|
+
this.angularStiffness = parseVec3(newValue, Vec3.ZERO, name);
|
|
4797
5709
|
break;
|
|
4798
|
-
case '
|
|
4799
|
-
this.
|
|
5710
|
+
case 'break-impulse':
|
|
5711
|
+
this.breakImpulse = parseNumber(newValue, Infinity, name);
|
|
4800
5712
|
break;
|
|
4801
|
-
case '
|
|
4802
|
-
this.
|
|
5713
|
+
case 'enable-collision':
|
|
5714
|
+
this.enableCollision = parseBool(newValue, false);
|
|
4803
5715
|
break;
|
|
4804
|
-
case '
|
|
4805
|
-
this.
|
|
5716
|
+
case 'enable-limits':
|
|
5717
|
+
this.enableLimits = parseBool(newValue, false);
|
|
4806
5718
|
break;
|
|
4807
|
-
case '
|
|
4808
|
-
this.
|
|
5719
|
+
case 'entity-a':
|
|
5720
|
+
this.entityA = newValue ?? '';
|
|
4809
5721
|
break;
|
|
4810
|
-
case '
|
|
4811
|
-
this.
|
|
5722
|
+
case 'entity-b':
|
|
5723
|
+
this.entityB = newValue ?? '';
|
|
4812
5724
|
break;
|
|
4813
|
-
case '
|
|
4814
|
-
this.
|
|
5725
|
+
case 'limits':
|
|
5726
|
+
this.limits = parseVec2(newValue, new Vec2(-45, 45), name);
|
|
4815
5727
|
break;
|
|
4816
|
-
case '
|
|
4817
|
-
this.
|
|
5728
|
+
case 'linear-damping':
|
|
5729
|
+
this.linearDamping = parseVec3(newValue, Vec3.ONE, name);
|
|
4818
5730
|
break;
|
|
4819
|
-
case '
|
|
4820
|
-
this.
|
|
5731
|
+
case 'linear-equilibrium':
|
|
5732
|
+
this.linearEquilibrium = parseVec3(newValue, Vec3.ZERO, name);
|
|
4821
5733
|
break;
|
|
4822
|
-
case '
|
|
4823
|
-
this.
|
|
5734
|
+
case 'linear-limits-x':
|
|
5735
|
+
this.linearLimitsX = parseVec2(newValue, Vec2.ZERO, name);
|
|
4824
5736
|
break;
|
|
4825
|
-
case '
|
|
4826
|
-
this.
|
|
5737
|
+
case 'linear-limits-y':
|
|
5738
|
+
this.linearLimitsY = parseVec2(newValue, Vec2.ZERO, name);
|
|
4827
5739
|
break;
|
|
4828
|
-
case '
|
|
4829
|
-
this.
|
|
5740
|
+
case 'linear-limits-z':
|
|
5741
|
+
this.linearLimitsZ = parseVec2(newValue, Vec2.ZERO, name);
|
|
4830
5742
|
break;
|
|
4831
|
-
case '
|
|
4832
|
-
this.
|
|
5743
|
+
case 'linear-motion-x':
|
|
5744
|
+
this.linearMotionX = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4833
5745
|
break;
|
|
4834
|
-
case '
|
|
4835
|
-
this.
|
|
5746
|
+
case 'linear-motion-y':
|
|
5747
|
+
this.linearMotionY = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4836
5748
|
break;
|
|
4837
|
-
case '
|
|
4838
|
-
this.
|
|
5749
|
+
case 'linear-motion-z':
|
|
5750
|
+
this.linearMotionZ = parseEnum(newValue, ['locked', 'limited', 'free'], 'locked', name);
|
|
4839
5751
|
break;
|
|
4840
|
-
case '
|
|
4841
|
-
this.
|
|
5752
|
+
case 'linear-stiffness':
|
|
5753
|
+
this.linearStiffness = parseVec3(newValue, Vec3.ZERO, name);
|
|
4842
5754
|
break;
|
|
4843
|
-
case '
|
|
4844
|
-
this.
|
|
5755
|
+
case 'max-motor-force':
|
|
5756
|
+
this.maxMotorForce = parseNumber(newValue, 0, name);
|
|
4845
5757
|
break;
|
|
4846
|
-
case '
|
|
4847
|
-
this.
|
|
5758
|
+
case 'motor-speed':
|
|
5759
|
+
this.motorSpeed = parseNumber(newValue, 0, name);
|
|
5760
|
+
break;
|
|
5761
|
+
case 'swing-limit-y':
|
|
5762
|
+
this.swingLimitY = parseNumber(newValue, 45, name);
|
|
5763
|
+
break;
|
|
5764
|
+
case 'swing-limit-z':
|
|
5765
|
+
this.swingLimitZ = parseNumber(newValue, 45, name);
|
|
5766
|
+
break;
|
|
5767
|
+
case 'twist-limit':
|
|
5768
|
+
this.twistLimit = parseNumber(newValue, 20, name);
|
|
5769
|
+
break;
|
|
5770
|
+
case 'type':
|
|
5771
|
+
this.type = parseEnum(newValue, ['fixed', 'ball', 'hinge', 'slider', '6dof'], 'fixed', name);
|
|
4848
5772
|
break;
|
|
4849
5773
|
}
|
|
4850
5774
|
}
|
|
4851
5775
|
}
|
|
4852
|
-
customElements.define('pc-
|
|
5776
|
+
customElements.define('pc-joint', JointComponentElement);
|
|
4853
5777
|
|
|
4854
5778
|
/**
|
|
4855
5779
|
* The LayoutChildComponentElement interface provides properties and methods for manipulating
|
|
@@ -6055,6 +6979,7 @@ class MaterialElement extends HTMLElement {
|
|
|
6055
6979
|
_metalnessMapRotation = 0;
|
|
6056
6980
|
_metalnessMapTiling = new Vec2(1, 1);
|
|
6057
6981
|
_metalnessMapUv = 0;
|
|
6982
|
+
_name = 'Untitled';
|
|
6058
6983
|
_normalMap = '';
|
|
6059
6984
|
_normalMapOffset = new Vec2(0, 0);
|
|
6060
6985
|
_normalMapRotation = 0;
|
|
@@ -6172,6 +7097,7 @@ class MaterialElement extends HTMLElement {
|
|
|
6172
7097
|
material.metalnessMapRotation = this._metalnessMapRotation;
|
|
6173
7098
|
material.metalnessMapTiling = this._metalnessMapTiling;
|
|
6174
7099
|
material.metalnessMapUv = this._metalnessMapUv;
|
|
7100
|
+
material.name = this._name;
|
|
6175
7101
|
material.normalMapOffset = this._normalMapOffset;
|
|
6176
7102
|
material.normalMapRotation = this._normalMapRotation;
|
|
6177
7103
|
material.normalMapTiling = this._normalMapTiling;
|
|
@@ -7258,6 +8184,26 @@ class MaterialElement extends HTMLElement {
|
|
|
7258
8184
|
get metalnessMapUv() {
|
|
7259
8185
|
return this._metalnessMapUv;
|
|
7260
8186
|
}
|
|
8187
|
+
/**
|
|
8188
|
+
* Sets the name of the material.
|
|
8189
|
+
* @param value - The material name.
|
|
8190
|
+
*/
|
|
8191
|
+
set name(value) {
|
|
8192
|
+
this._name = value;
|
|
8193
|
+
if (this.material) {
|
|
8194
|
+
// A label rather than shader state, so no update() is scheduled
|
|
8195
|
+
this.material.name = value;
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
/**
|
|
8199
|
+
* Gets the name of the material - the label shown wherever materials surface by name, such
|
|
8200
|
+
* as profilers, GPU captures and the assignments `pc-model.hierarchy()` reports. Purely a
|
|
8201
|
+
* label: element references resolve through `id`.
|
|
8202
|
+
* @returns The material name.
|
|
8203
|
+
*/
|
|
8204
|
+
get name() {
|
|
8205
|
+
return this._name;
|
|
8206
|
+
}
|
|
7261
8207
|
/**
|
|
7262
8208
|
* Sets the id of the `pc-asset` to use as the normal map.
|
|
7263
8209
|
* @param value - The asset id.
|
|
@@ -7829,6 +8775,7 @@ class MaterialElement extends HTMLElement {
|
|
|
7829
8775
|
'metalness-map-rotation',
|
|
7830
8776
|
'metalness-map-tiling',
|
|
7831
8777
|
'metalness-map-uv',
|
|
8778
|
+
'name',
|
|
7832
8779
|
'normal-map',
|
|
7833
8780
|
'normal-map-offset',
|
|
7834
8781
|
'normal-map-rotation',
|
|
@@ -8029,6 +8976,9 @@ class MaterialElement extends HTMLElement {
|
|
|
8029
8976
|
case 'metalness-map-uv':
|
|
8030
8977
|
this.metalnessMapUv = parseNumber(newValue, 0, name);
|
|
8031
8978
|
break;
|
|
8979
|
+
case 'name':
|
|
8980
|
+
this.name = newValue ?? 'Untitled';
|
|
8981
|
+
break;
|
|
8032
8982
|
case 'normal-map':
|
|
8033
8983
|
this.normalMap = newValue ?? '';
|
|
8034
8984
|
break;
|
|
@@ -10574,6 +11524,41 @@ class GSplatComponentElement extends ComponentElement {
|
|
|
10574
11524
|
}
|
|
10575
11525
|
customElements.define('pc-gsplat', GSplatComponentElement);
|
|
10576
11526
|
|
|
11527
|
+
/**
|
|
11528
|
+
* Formats one line of the printable hierarchy: the node's name, an `[index]` marker when the
|
|
11529
|
+
* name is shared by several nodes in the model, the attached component types, and the material
|
|
11530
|
+
* names of a render component.
|
|
11531
|
+
*
|
|
11532
|
+
* @param node - The node to format.
|
|
11533
|
+
* @param counts - The number of nodes bearing each name.
|
|
11534
|
+
* @returns The formatted line.
|
|
11535
|
+
*/
|
|
11536
|
+
const formatNode = (node, counts) => {
|
|
11537
|
+
const index = (counts.get(node.name) ?? 0) > 1 ? ` [${node.index}]` : '';
|
|
11538
|
+
const components = node.components.length > 0 ? ` (${node.components.join(', ')})` : '';
|
|
11539
|
+
// Braces rather than brackets: `[N]` already means a match index on this line
|
|
11540
|
+
const materials = node.materials.length > 0 ? ` {${node.materials.map((slot) => slot.name ?? 'null').join(', ')}}` : '';
|
|
11541
|
+
return `${node.name}${index}${components}${materials}`;
|
|
11542
|
+
};
|
|
11543
|
+
/**
|
|
11544
|
+
* Formats the printable form of a hierarchy subtree.
|
|
11545
|
+
*
|
|
11546
|
+
* @param root - The subtree root.
|
|
11547
|
+
* @param counts - The number of nodes bearing each name.
|
|
11548
|
+
* @returns The tree, one line per node.
|
|
11549
|
+
*/
|
|
11550
|
+
const formatHierarchy = (root, counts) => {
|
|
11551
|
+
const lines = [formatNode(root, counts)];
|
|
11552
|
+
const walk = (node, prefix) => {
|
|
11553
|
+
node.children.forEach((child, i) => {
|
|
11554
|
+
const last = i === node.children.length - 1;
|
|
11555
|
+
lines.push(`${prefix}${last ? '└─ ' : '├─ '}${formatNode(child, counts)}`);
|
|
11556
|
+
walk(child, `${prefix}${last ? ' ' : '│ '}`);
|
|
11557
|
+
});
|
|
11558
|
+
};
|
|
11559
|
+
walk(root, '');
|
|
11560
|
+
return lines.join('\n');
|
|
11561
|
+
};
|
|
10577
11562
|
/**
|
|
10578
11563
|
* The ModelElement interface provides properties and methods for manipulating
|
|
10579
11564
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-model/ | `<pc-model>`} elements.
|
|
@@ -10620,6 +11605,57 @@ class ModelElement extends AsyncElement {
|
|
|
10620
11605
|
get entity() {
|
|
10621
11606
|
return this._entity;
|
|
10622
11607
|
}
|
|
11608
|
+
/**
|
|
11609
|
+
* Returns a snapshot of the instantiated node tree, or `null` while there is none (the
|
|
11610
|
+
* container asset has not loaded, or the element has left the document). One call grounds a
|
|
11611
|
+
* session — a browser console, a test, an agent — in the vocabulary `pc-node` binding
|
|
11612
|
+
* resolves against: the instantiated names ({@link HierarchyNode.name}), paths, match
|
|
11613
|
+
* indices, attached component types and the material assignments of render components
|
|
11614
|
+
* ({@link HierarchyNode.materials}). `String(...)` of the result, or of any node in it,
|
|
11615
|
+
* is the printable form.
|
|
11616
|
+
*
|
|
11617
|
+
* The snapshot is plain data, computed afresh each call: it does not follow later changes
|
|
11618
|
+
* to the hierarchy, and mutating it changes nothing.
|
|
11619
|
+
*
|
|
11620
|
+
* @returns The root of the instantiated node tree, or `null`.
|
|
11621
|
+
*/
|
|
11622
|
+
hierarchy() {
|
|
11623
|
+
const root = this._entity;
|
|
11624
|
+
if (!root) {
|
|
11625
|
+
return null;
|
|
11626
|
+
}
|
|
11627
|
+
// Ordinals are assigned in the traversal resolution searches — pre-order depth-first
|
|
11628
|
+
// from the model root, the root itself included — so each node's index is exactly what
|
|
11629
|
+
// a pc-node's index attribute selects. Once the walk completes, the map holds the total
|
|
11630
|
+
// count per name, which is what the printable form reads to annotate only shared names.
|
|
11631
|
+
const ordinals = new Map();
|
|
11632
|
+
const describe = (entity, pathBelowRoot) => {
|
|
11633
|
+
const index = ordinals.get(entity.name) ?? 0;
|
|
11634
|
+
ordinals.set(entity.name, index + 1);
|
|
11635
|
+
const node = {
|
|
11636
|
+
name: entity.name,
|
|
11637
|
+
// The root has no path below itself; its own name stands in, as it does for
|
|
11638
|
+
// the path a pc-node bound to the root reports.
|
|
11639
|
+
path: pathBelowRoot || entity.name,
|
|
11640
|
+
index,
|
|
11641
|
+
// A plain GraphNode grafted into the hierarchy has no component storage
|
|
11642
|
+
components: Object.keys(entity.c ?? {}).sort(),
|
|
11643
|
+
materials: (entity.render?.meshInstances ?? []).map((meshInstance, slot) => ({
|
|
11644
|
+
index: slot,
|
|
11645
|
+
name: meshInstance.material?.name ?? null
|
|
11646
|
+
})),
|
|
11647
|
+
children: entity.children.map((child) => describe(child, pathBelowRoot ? `${pathBelowRoot}/${child.name}` : child.name))
|
|
11648
|
+
};
|
|
11649
|
+
// Non-enumerable, keeping the snapshot plain data under JSON.stringify, spreads and
|
|
11650
|
+
// key enumeration. Deferred to call time, by which the ordinal map holds its totals.
|
|
11651
|
+
Object.defineProperty(node, 'toString', {
|
|
11652
|
+
enumerable: false,
|
|
11653
|
+
value: () => formatHierarchy(node, ordinals)
|
|
11654
|
+
});
|
|
11655
|
+
return node;
|
|
11656
|
+
};
|
|
11657
|
+
return describe(root, '');
|
|
11658
|
+
}
|
|
10623
11659
|
connectedCallback() {
|
|
10624
11660
|
// A model outside an application is inert and never becomes ready, so awaiting it hangs.
|
|
10625
11661
|
// Warn rather than fail silently, naming the parent it requires, as every other misplaced
|
|
@@ -10778,6 +11814,74 @@ class ModelElement extends AsyncElement {
|
|
|
10778
11814
|
}
|
|
10779
11815
|
customElements.define('pc-model', ModelElement);
|
|
10780
11816
|
|
|
11817
|
+
/**
|
|
11818
|
+
* Parses one mapping into its valid rules, warning for each entry that is not one: an unknown
|
|
11819
|
+
* or missing selector prefix, an empty `name:` value, an `index:` value that is not a
|
|
11820
|
+
* non-negative integer, or a replacement id that is not a non-empty string. An invalid rule
|
|
11821
|
+
* behaves exactly as if absent from the mapping.
|
|
11822
|
+
*
|
|
11823
|
+
* @param overrides - The mapping to parse.
|
|
11824
|
+
* @param label - The element description for warnings.
|
|
11825
|
+
* @returns The valid rules.
|
|
11826
|
+
*/
|
|
11827
|
+
const parseMaterialRules = (overrides, label) => {
|
|
11828
|
+
const rules = [];
|
|
11829
|
+
for (const [selector, id] of Object.entries(overrides)) {
|
|
11830
|
+
if (typeof id !== 'string' || id === '') {
|
|
11831
|
+
console.warn(`${label} material-overrides '${selector}' needs a pc-material id - rule ignored`);
|
|
11832
|
+
}
|
|
11833
|
+
else if (selector.startsWith('name:')) {
|
|
11834
|
+
// The text after the prefix is the selector value, exactly as written - a material
|
|
11835
|
+
// name may legitimately begin or end with whitespace
|
|
11836
|
+
const name = selector.slice('name:'.length);
|
|
11837
|
+
if (name === '') {
|
|
11838
|
+
console.warn(`${label} material-overrides 'name:' selector is empty - rule ignored`);
|
|
11839
|
+
}
|
|
11840
|
+
else {
|
|
11841
|
+
rules.push({ kind: 'name', name, id });
|
|
11842
|
+
}
|
|
11843
|
+
}
|
|
11844
|
+
else if (selector.startsWith('index:')) {
|
|
11845
|
+
// Whitespace around the number is tolerated; Number('') is 0, so blank means NaN
|
|
11846
|
+
const text = selector.slice('index:'.length).trim();
|
|
11847
|
+
const index = text === '' ? NaN : Number(text);
|
|
11848
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
11849
|
+
console.warn(`${label} material-overrides '${selector}' is not a non-negative integer index - rule ignored`);
|
|
11850
|
+
}
|
|
11851
|
+
else {
|
|
11852
|
+
rules.push({ kind: 'index', index, id });
|
|
11853
|
+
}
|
|
11854
|
+
}
|
|
11855
|
+
else {
|
|
11856
|
+
console.warn(`${label} material-overrides '${selector}' has no 'name:' or 'index:' prefix - rule ignored`);
|
|
11857
|
+
}
|
|
11858
|
+
}
|
|
11859
|
+
return rules;
|
|
11860
|
+
};
|
|
11861
|
+
/**
|
|
11862
|
+
* Parses the material-overrides attribute text. Anything but a JSON object — malformed JSON, an
|
|
11863
|
+
* array, a primitive — warns and yields `null`, the absent mapping: a stale mapping must not
|
|
11864
|
+
* survive an attribute value the DOM no longer represents.
|
|
11865
|
+
*
|
|
11866
|
+
* @param text - The attribute text.
|
|
11867
|
+
* @param label - The element description for warnings.
|
|
11868
|
+
* @returns The mapping, or `null`.
|
|
11869
|
+
*/
|
|
11870
|
+
const parseMaterialOverridesAttribute = (text, label) => {
|
|
11871
|
+
let parsed;
|
|
11872
|
+
try {
|
|
11873
|
+
parsed = JSON.parse(text);
|
|
11874
|
+
}
|
|
11875
|
+
catch (error) {
|
|
11876
|
+
console.warn(`${label} material-overrides is not valid JSON - treated as absent: ${error.message}`);
|
|
11877
|
+
return null;
|
|
11878
|
+
}
|
|
11879
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
11880
|
+
console.warn(`${label} material-overrides must be a JSON object - treated as absent`);
|
|
11881
|
+
return null;
|
|
11882
|
+
}
|
|
11883
|
+
return parsed;
|
|
11884
|
+
};
|
|
10781
11885
|
/**
|
|
10782
11886
|
* Computes the Levenshtein distance between two strings, for near-miss suggestions in the
|
|
10783
11887
|
* resolution warnings.
|
|
@@ -10833,6 +11937,13 @@ const levenshtein = (a, b) => {
|
|
|
10833
11937
|
* "x y z" triple.
|
|
10834
11938
|
* @attribute {string} scale - Overrides the node's local scale, as an "x y z" triple.
|
|
10835
11939
|
* @attribute {string} tags - Overrides the node's tags, separated by spaces or commas.
|
|
11940
|
+
* @attribute {string} material-overrides - Overrides material assignments on the bound node's
|
|
11941
|
+
* render component, as a JSON object from selector to `pc-material` id — for example
|
|
11942
|
+
* `{"name:CarPaint": "candy-red", "index:7": "smoked-glass"}`. A `name:X` key selects every mesh
|
|
11943
|
+
* instance whose baseline material is named `X`; an `index:N` key selects mesh instance `N` and
|
|
11944
|
+
* wins over a name rule for the same instance. Assignments no rule matches keep their baseline
|
|
11945
|
+
* materials, and removing the attribute restores all of them. Use `pc-model.hierarchy()` to
|
|
11946
|
+
* discover the names and indices a node offers.
|
|
10836
11947
|
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the node.
|
|
10837
11948
|
* @attribute {string} onpointerleave - Script to run when the pointer moves off the node.
|
|
10838
11949
|
* @attribute {string} onpointermove - Script to run when the pointer moves over the node.
|
|
@@ -10868,12 +11979,25 @@ class NodeElement extends EntityBaseElement {
|
|
|
10868
11979
|
_destroyHandle = null;
|
|
10869
11980
|
/** The authored values displaced by this element's overrides, captured per property. */
|
|
10870
11981
|
_authored = {};
|
|
11982
|
+
/**
|
|
11983
|
+
* The model-authored render component of the bound node, recorded at bind — before child
|
|
11984
|
+
* decorations build — so a render component added later by a child `pc-render` can never
|
|
11985
|
+
* become the override target. `null` when the bound node has none.
|
|
11986
|
+
*/
|
|
11987
|
+
_authoredRender = null;
|
|
11988
|
+
/**
|
|
11989
|
+
* The baseline assignments displaced by the material overrides, captured for every mesh
|
|
11990
|
+
* instance when the first non-empty mapping applies and released when the mapping goes
|
|
11991
|
+
* absent (restoring them) or the binding dissolves.
|
|
11992
|
+
*/
|
|
11993
|
+
_baseline = null;
|
|
10871
11994
|
// Override values. `null` means "no override": the authored value stays in force.
|
|
10872
11995
|
_enabled = null;
|
|
10873
11996
|
_position = null;
|
|
10874
11997
|
_rotation = null;
|
|
10875
11998
|
_scale = null;
|
|
10876
11999
|
_tags = null;
|
|
12000
|
+
_materialOverrides = null;
|
|
10877
12001
|
/**
|
|
10878
12002
|
* The binding state: `pending` until the host instantiates and `name` resolves, `bound`
|
|
10879
12003
|
* once decorated, `missing`/`ambiguous`/`duplicate` when resolution failed (each also
|
|
@@ -11007,6 +12131,7 @@ class NodeElement extends EntityBaseElement {
|
|
|
11007
12131
|
this._destroyHandle = target.once('destroy', this._onEntityDestroy, this);
|
|
11008
12132
|
this._state = 'bound';
|
|
11009
12133
|
this._path = this._pathOf(target, hostEntity);
|
|
12134
|
+
this._authoredRender = target.render ?? null;
|
|
11010
12135
|
this._applyOverrides();
|
|
11011
12136
|
this._onReady();
|
|
11012
12137
|
this._buildChildren();
|
|
@@ -11037,6 +12162,7 @@ class NodeElement extends EntityBaseElement {
|
|
|
11037
12162
|
this._entity = null;
|
|
11038
12163
|
this._path = null;
|
|
11039
12164
|
this._authored = {};
|
|
12165
|
+
this._authoredRender = null;
|
|
11040
12166
|
// Component decorations come off through the same hook the host-ready cycle uses. A
|
|
11041
12167
|
// dissolve that never rebinds fires no ready event, so the sweep is explicit - after
|
|
11042
12168
|
// `_entity` is cleared, so the hook sees a host without an entity.
|
|
@@ -11058,6 +12184,9 @@ class NodeElement extends EntityBaseElement {
|
|
|
11058
12184
|
this._entity = null;
|
|
11059
12185
|
this._path = null;
|
|
11060
12186
|
this._authored = {};
|
|
12187
|
+
this._authoredRender = null;
|
|
12188
|
+
// The mesh instances died with the entity - the capture is dropped, not restored
|
|
12189
|
+
this._baseline = null;
|
|
11061
12190
|
this._state = 'pending';
|
|
11062
12191
|
this._resetReady();
|
|
11063
12192
|
}
|
|
@@ -11072,13 +12201,7 @@ class NodeElement extends EntityBaseElement {
|
|
|
11072
12201
|
if (!app) {
|
|
11073
12202
|
return;
|
|
11074
12203
|
}
|
|
11075
|
-
|
|
11076
|
-
childEntities.forEach((child) => {
|
|
11077
|
-
child._createEntity(app);
|
|
11078
|
-
});
|
|
11079
|
-
childEntities.forEach((child) => {
|
|
11080
|
-
child._buildHierarchy(app);
|
|
11081
|
-
});
|
|
12204
|
+
buildDescendantEntities(this, app);
|
|
11082
12205
|
}
|
|
11083
12206
|
/**
|
|
11084
12207
|
* Applies every override that is explicitly set, capturing the authored value it displaces.
|
|
@@ -11099,6 +12222,9 @@ class NodeElement extends EntityBaseElement {
|
|
|
11099
12222
|
if (this._tags !== null) {
|
|
11100
12223
|
this.tags = this._tags;
|
|
11101
12224
|
}
|
|
12225
|
+
if (this._materialOverrides !== null) {
|
|
12226
|
+
this._applyMaterialOverrides();
|
|
12227
|
+
}
|
|
11102
12228
|
}
|
|
11103
12229
|
/**
|
|
11104
12230
|
* Restores every authored value this element's overrides displaced. The override values
|
|
@@ -11124,6 +12250,104 @@ class NodeElement extends EntityBaseElement {
|
|
|
11124
12250
|
entity.tags.add(authored.tags);
|
|
11125
12251
|
}
|
|
11126
12252
|
this._authored = {};
|
|
12253
|
+
this._restoreBaseline();
|
|
12254
|
+
}
|
|
12255
|
+
/**
|
|
12256
|
+
* Applies the material mapping to the authored render component: parse the mapping's valid
|
|
12257
|
+
* rules, capture the baseline on first application, then recompute every assignment from
|
|
12258
|
+
* that baseline - name rules write over it, index rules write over them, so `index:` wins -
|
|
12259
|
+
* and assign whatever changed. An absent mapping, or one with no valid rules, restores the
|
|
12260
|
+
* baseline instead. Called while bound, from `_applyOverrides` and the property setter.
|
|
12261
|
+
*/
|
|
12262
|
+
_applyMaterialOverrides() {
|
|
12263
|
+
const label = `pc-node '${this._name}'`;
|
|
12264
|
+
const rules = this._materialOverrides ? parseMaterialRules(this._materialOverrides, label) : [];
|
|
12265
|
+
if (rules.length === 0) {
|
|
12266
|
+
this._restoreBaseline();
|
|
12267
|
+
return;
|
|
12268
|
+
}
|
|
12269
|
+
if (!this._baseline) {
|
|
12270
|
+
if (!this._authoredRender) {
|
|
12271
|
+
console.warn(`${label} is bound to a node without an authored render component - material-overrides ignored`);
|
|
12272
|
+
return;
|
|
12273
|
+
}
|
|
12274
|
+
this._baseline = this._authoredRender.meshInstances.map((meshInstance) => ({
|
|
12275
|
+
meshInstance,
|
|
12276
|
+
material: meshInstance.material ?? null,
|
|
12277
|
+
name: meshInstance.material?.name ?? null
|
|
12278
|
+
}));
|
|
12279
|
+
}
|
|
12280
|
+
const baseline = this._baseline;
|
|
12281
|
+
/** Resolves a replacement id, warning when it does not resolve. */
|
|
12282
|
+
const resolveReplacement = (id) => {
|
|
12283
|
+
const material = MaterialElement.get(id);
|
|
12284
|
+
if (!material) {
|
|
12285
|
+
console.warn(`${label} material-overrides could not resolve pc-material '${id}' - rule ignored`);
|
|
12286
|
+
}
|
|
12287
|
+
return material ?? null;
|
|
12288
|
+
};
|
|
12289
|
+
// Recompute the whole list from the baseline: name rules write over it, index rules
|
|
12290
|
+
// write over them. Recomputing makes mapping edits order-independent, and a rule whose
|
|
12291
|
+
// replacement does not resolve simply leaves the layer below it in force.
|
|
12292
|
+
const resolved = baseline.map((assignment) => assignment.material);
|
|
12293
|
+
for (const rule of rules) {
|
|
12294
|
+
if (rule.kind !== 'name') {
|
|
12295
|
+
continue;
|
|
12296
|
+
}
|
|
12297
|
+
const material = resolveReplacement(rule.id);
|
|
12298
|
+
if (!material) {
|
|
12299
|
+
continue;
|
|
12300
|
+
}
|
|
12301
|
+
let matched = false;
|
|
12302
|
+
baseline.forEach((assignment, index) => {
|
|
12303
|
+
if (assignment.name === rule.name) {
|
|
12304
|
+
resolved[index] = material;
|
|
12305
|
+
matched = true;
|
|
12306
|
+
}
|
|
12307
|
+
});
|
|
12308
|
+
if (!matched) {
|
|
12309
|
+
const names = baseline.map((assignment) => `'${assignment.name}'`).join(', ');
|
|
12310
|
+
console.warn(`${label} material-overrides 'name:${rule.name}' matches no assignment - ` +
|
|
12311
|
+
`baseline names: ${names || '(none)'}`);
|
|
12312
|
+
}
|
|
12313
|
+
}
|
|
12314
|
+
for (const rule of rules) {
|
|
12315
|
+
if (rule.kind !== 'index') {
|
|
12316
|
+
continue;
|
|
12317
|
+
}
|
|
12318
|
+
if (rule.index >= baseline.length) {
|
|
12319
|
+
console.warn(`${label} material-overrides 'index:${rule.index}' is out of range - ` +
|
|
12320
|
+
`${baseline.length} assignment(s)`);
|
|
12321
|
+
continue;
|
|
12322
|
+
}
|
|
12323
|
+
const material = resolveReplacement(rule.id);
|
|
12324
|
+
if (material) {
|
|
12325
|
+
resolved[rule.index] = material;
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12328
|
+
baseline.forEach((assignment, index) => {
|
|
12329
|
+
// The engine setter rebuilds material and shader state even for a redundant write,
|
|
12330
|
+
// so only actual changes are assigned
|
|
12331
|
+
if (assignment.meshInstance.material !== resolved[index]) {
|
|
12332
|
+
assignment.meshInstance.material = resolved[index];
|
|
12333
|
+
}
|
|
12334
|
+
});
|
|
12335
|
+
}
|
|
12336
|
+
/**
|
|
12337
|
+
* Restores every baseline assignment the material overrides displaced and releases the
|
|
12338
|
+
* capture, so the next non-empty mapping captures afresh. Safe to call without a capture.
|
|
12339
|
+
*/
|
|
12340
|
+
_restoreBaseline() {
|
|
12341
|
+
const baseline = this._baseline;
|
|
12342
|
+
if (!baseline) {
|
|
12343
|
+
return;
|
|
12344
|
+
}
|
|
12345
|
+
this._baseline = null;
|
|
12346
|
+
for (const assignment of baseline) {
|
|
12347
|
+
if (assignment.meshInstance.material !== assignment.material) {
|
|
12348
|
+
assignment.meshInstance.material = assignment.material;
|
|
12349
|
+
}
|
|
12350
|
+
}
|
|
11127
12351
|
}
|
|
11128
12352
|
/**
|
|
11129
12353
|
* Renders the path of `node` below `root`, for the `path` property and the resolution
|
|
@@ -11344,8 +12568,41 @@ class NodeElement extends EntityBaseElement {
|
|
|
11344
12568
|
get tags() {
|
|
11345
12569
|
return this._tags;
|
|
11346
12570
|
}
|
|
12571
|
+
/**
|
|
12572
|
+
* Sets the material overrides: a sparse mapping from selector to `pc-material` id, applied
|
|
12573
|
+
* to the bound node's authored render component. A `name:X` key selects every mesh instance
|
|
12574
|
+
* whose baseline material is named `X`; an `index:N` key selects mesh instance `N` and wins
|
|
12575
|
+
* over a name rule for the same instance. Assignments no rule matches keep their baseline
|
|
12576
|
+
* materials. `null` clears the mapping, restoring every baseline assignment.
|
|
12577
|
+
* @param value - The mapping, or `null`.
|
|
12578
|
+
*/
|
|
12579
|
+
set materialOverrides(value) {
|
|
12580
|
+
// Copied and frozen: later caller mutation of the passed object must not silently
|
|
12581
|
+
// disagree with the mapping the element applied
|
|
12582
|
+
this._materialOverrides = value === null ? null : Object.freeze({ ...value });
|
|
12583
|
+
if (this._state === 'bound') {
|
|
12584
|
+
this._applyMaterialOverrides();
|
|
12585
|
+
}
|
|
12586
|
+
}
|
|
12587
|
+
/**
|
|
12588
|
+
* Gets the material overrides.
|
|
12589
|
+
* @returns The mapping, or `null` while no override is set.
|
|
12590
|
+
*/
|
|
12591
|
+
get materialOverrides() {
|
|
12592
|
+
return this._materialOverrides;
|
|
12593
|
+
}
|
|
11347
12594
|
static get observedAttributes() {
|
|
11348
|
-
return [
|
|
12595
|
+
return [
|
|
12596
|
+
'enabled',
|
|
12597
|
+
'index',
|
|
12598
|
+
'material-overrides',
|
|
12599
|
+
'name',
|
|
12600
|
+
'position',
|
|
12601
|
+
'rotation',
|
|
12602
|
+
'scale',
|
|
12603
|
+
'tags',
|
|
12604
|
+
...POINTER_ATTRIBUTES
|
|
12605
|
+
];
|
|
11349
12606
|
}
|
|
11350
12607
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
11351
12608
|
switch (name) {
|
|
@@ -11370,6 +12627,10 @@ class NodeElement extends EntityBaseElement {
|
|
|
11370
12627
|
}
|
|
11371
12628
|
}
|
|
11372
12629
|
break;
|
|
12630
|
+
case 'material-overrides':
|
|
12631
|
+
this.materialOverrides =
|
|
12632
|
+
newValue === null ? null : parseMaterialOverridesAttribute(newValue, `pc-node '${this._name}'`);
|
|
12633
|
+
break;
|
|
11373
12634
|
case 'name':
|
|
11374
12635
|
this.name = newValue ?? '';
|
|
11375
12636
|
break;
|
|
@@ -11916,5 +13177,5 @@ class SkyElement extends AsyncElement {
|
|
|
11916
13177
|
}
|
|
11917
13178
|
customElements.define('pc-sky', SkyElement);
|
|
11918
13179
|
|
|
11919
|
-
export { AppElement, AssetElement, AsyncElement, ButtonComponentElement, CameraComponentElement, CollisionComponentElement, ComponentElement, ElementComponentElement, EntityBaseElement, EntityElement, GSplatComponentElement, LayoutChildComponentElement, LayoutGroupComponentElement, LightComponentElement, ListenerComponentElement, MaterialElement, ModelElement, ModuleElement, NodeElement, ParticleSystemComponentElement, RenderComponentElement, RigidBodyComponentElement, SceneElement, ScreenComponentElement, ScriptComponentElement, ScriptElement, ScrollViewComponentElement, ScrollbarComponentElement, SkyElement, SoundComponentElement, SoundSlotElement, whenReady };
|
|
13180
|
+
export { AppElement, AssetElement, AsyncElement, ButtonComponentElement, CameraComponentElement, CollisionComponentElement, ComponentElement, ElementComponentElement, EntityBaseElement, EntityElement, GSplatComponentElement, JointComponentElement, LayoutChildComponentElement, LayoutGroupComponentElement, LightComponentElement, ListenerComponentElement, MaterialElement, ModelElement, ModuleElement, NodeElement, ParticleSystemComponentElement, RenderComponentElement, RigidBodyComponentElement, SceneElement, ScreenComponentElement, ScriptComponentElement, ScriptElement, ScrollViewComponentElement, ScrollbarComponentElement, SkyElement, SoundComponentElement, SoundSlotElement, whenReady };
|
|
11920
13181
|
//# sourceMappingURL=pwc.mjs.map
|