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