@playcanvas/web-components 0.10.1 → 0.11.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/app.d.ts +103 -32
- package/dist/components/camera-component.d.ts +13 -13
- package/dist/components/screen-component.d.ts +25 -4
- package/dist/components/scrollview-component.d.ts +6 -4
- package/dist/custom-elements.json +239 -96
- package/dist/entity.d.ts +13 -0
- package/dist/parse.d.ts +4 -2
- package/dist/pwc.cjs +308 -156
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +308 -156
- 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 +309 -157
- package/dist/pwc.mjs.map +1 -1
- package/dist/sky.d.ts +12 -11
- package/dist/vscode.html-custom-data.json +40 -20
- package/dist/web-types.json +67 -48
- package/package.json +1 -1
- package/src/app.ts +189 -79
- package/src/components/camera-component.ts +31 -26
- package/src/components/screen-component.ts +42 -12
- package/src/components/scrollview-component.ts +6 -4
- package/src/entity.ts +35 -17
- package/src/parse.ts +5 -3
- package/src/sky.ts +26 -25
package/dist/pwc.cjs
CHANGED
|
@@ -489,7 +489,9 @@ const parseColor = (value, defaultValue, attribute) => {
|
|
|
489
489
|
* the value is invalid — the latter also logs a warning listing the valid names.
|
|
490
490
|
*
|
|
491
491
|
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
492
|
-
* @param valid - The valid names: an array, or a map whose keys are the valid names.
|
|
492
|
+
* @param valid - The valid names: an array, or a map whose keys are the valid names. Only the keys
|
|
493
|
+
* are read, so the map's value type is unconstrained - engine enums are mostly numeric constants,
|
|
494
|
+
* but some (e.g. `SCALEMODE_BLEND`) are strings.
|
|
493
495
|
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
494
496
|
* @param attribute - The attribute name, used in the warning message.
|
|
495
497
|
* @returns The resolved enum name.
|
|
@@ -677,12 +679,24 @@ class AppElement extends AsyncElement {
|
|
|
677
679
|
_alpha = true;
|
|
678
680
|
_backend = 'webgpu';
|
|
679
681
|
_antialias = true;
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
682
|
+
_depthBuffer = true;
|
|
683
|
+
_stencilBuffer = true;
|
|
684
|
+
_maxPixelRatio = Infinity;
|
|
683
685
|
_loadingBar = true;
|
|
686
|
+
/**
|
|
687
|
+
* Set once the graphics options above have been handed to `createGraphicsDevice`, after which
|
|
688
|
+
* writing any of them changes nothing. Guards the warning in {@link _warnIfBooted}, and is
|
|
689
|
+
* cleared on disconnect so a re-connected element boots from its current attributes.
|
|
690
|
+
*/
|
|
691
|
+
_optionsLocked = false;
|
|
684
692
|
_bar = null;
|
|
685
693
|
_hierarchyReady = false;
|
|
694
|
+
/**
|
|
695
|
+
* The elements backing this application's entities, keyed by the entity itself. Registered
|
|
696
|
+
* by EntityElement at creation and removed when an entity is destroyed, this joins engine
|
|
697
|
+
* scene nodes back to their owning elements by identity - never by name.
|
|
698
|
+
*/
|
|
699
|
+
_entityElements = new Map();
|
|
686
700
|
_picker = null;
|
|
687
701
|
_hasPointerListeners = {
|
|
688
702
|
pointerenter: false,
|
|
@@ -750,15 +764,19 @@ class AppElement extends AsyncElement {
|
|
|
750
764
|
null: ['null']
|
|
751
765
|
};
|
|
752
766
|
const deviceTypes = backendToDeviceTypes[this._backend] || [];
|
|
767
|
+
this._optionsLocked = true;
|
|
753
768
|
const device = await playcanvas.createGraphicsDevice(this._canvas, {
|
|
754
769
|
// @ts-ignore - alpha needs to be documented
|
|
755
770
|
alpha: this._alpha,
|
|
756
771
|
antialias: this._antialias,
|
|
757
|
-
depth: this.
|
|
772
|
+
depth: this._depthBuffer,
|
|
758
773
|
deviceTypes: deviceTypes,
|
|
759
|
-
stencil: this.
|
|
774
|
+
stencil: this._stencilBuffer
|
|
760
775
|
});
|
|
761
|
-
|
|
776
|
+
// Assigned rather than resolved to a number here: the engine caps against the live
|
|
777
|
+
// window.devicePixelRatio on every resize, so an uncapped Infinity keeps following the
|
|
778
|
+
// display when a window moves between monitors of differing density.
|
|
779
|
+
device.maxPixelRatio = this._maxPixelRatio;
|
|
762
780
|
const createOptions = new playcanvas.AppOptions();
|
|
763
781
|
createOptions.graphicsDevice = device;
|
|
764
782
|
createOptions.keyboard = new playcanvas.Keyboard(window);
|
|
@@ -885,12 +903,15 @@ class AppElement extends AsyncElement {
|
|
|
885
903
|
});
|
|
886
904
|
}
|
|
887
905
|
disconnectedCallback() {
|
|
906
|
+
this._optionsLocked = false;
|
|
888
907
|
this._pickerDestroy();
|
|
889
|
-
// Clean up the application
|
|
908
|
+
// Clean up the application. Destroying it destroys every entity, whose destroy hooks
|
|
909
|
+
// unregister them - clear() covers any entity the engine no longer reached.
|
|
890
910
|
if (this._app) {
|
|
891
911
|
this._app.destroy();
|
|
892
912
|
this._app = null;
|
|
893
913
|
}
|
|
914
|
+
this._entityElements.clear();
|
|
894
915
|
this._loadProgress = 0;
|
|
895
916
|
this._bar?.destroy();
|
|
896
917
|
this._bar = null;
|
|
@@ -956,6 +977,74 @@ class AppElement extends AsyncElement {
|
|
|
956
977
|
pointermove: false
|
|
957
978
|
};
|
|
958
979
|
}
|
|
980
|
+
/**
|
|
981
|
+
* Registers the element that created an entity. Called by EntityElement when it creates its
|
|
982
|
+
* entity.
|
|
983
|
+
*
|
|
984
|
+
* @param entity - The entity.
|
|
985
|
+
* @param element - The element that created it.
|
|
986
|
+
* @ignore
|
|
987
|
+
*/
|
|
988
|
+
_registerEntityElement(entity, element) {
|
|
989
|
+
this._entityElements.set(entity, element);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Removes the registration for a destroyed entity. Called by EntityElement.
|
|
993
|
+
*
|
|
994
|
+
* @param entity - The entity.
|
|
995
|
+
* @ignore
|
|
996
|
+
*/
|
|
997
|
+
_unregisterEntityElement(entity) {
|
|
998
|
+
this._entityElements.delete(entity);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Returns the `<pc-entity>` element whose backing entity is `entity`, or `null` if the
|
|
1002
|
+
* entity was not created by an element of this application - for example, a node inside a
|
|
1003
|
+
* model's instantiated hierarchy, or an entity created through the engine API.
|
|
1004
|
+
*
|
|
1005
|
+
* @param entity - The entity to look up.
|
|
1006
|
+
* @returns The element backing the entity, or `null`.
|
|
1007
|
+
*/
|
|
1008
|
+
elementFromEntity(entity) {
|
|
1009
|
+
return this._entityElements.get(entity) ?? null;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Resolves the element that owns a picked node: the nearest node up the parent chain -
|
|
1013
|
+
* starting with the node itself - that was created by a `<pc-entity>` of this application.
|
|
1014
|
+
* A hit inside a model's instantiated hierarchy therefore resolves to the element hosting
|
|
1015
|
+
* the model.
|
|
1016
|
+
*
|
|
1017
|
+
* @param node - The picked node, or `null`.
|
|
1018
|
+
* @returns The owning element, or `null`.
|
|
1019
|
+
*/
|
|
1020
|
+
_elementFromNode(node) {
|
|
1021
|
+
while (node !== null) {
|
|
1022
|
+
const element = this._entityElements.get(node);
|
|
1023
|
+
if (element) {
|
|
1024
|
+
return element;
|
|
1025
|
+
}
|
|
1026
|
+
node = node.parent;
|
|
1027
|
+
}
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Like {@link _elementFromNode}, but skips elements without a listener for `type`, so a hit
|
|
1032
|
+
* on an unlistened child still reaches a listening ancestor.
|
|
1033
|
+
*
|
|
1034
|
+
* @param node - The picked node, or `null`.
|
|
1035
|
+
* @param type - The pointer event type a listener is required for.
|
|
1036
|
+
* @returns The nearest listening element, or `null`.
|
|
1037
|
+
*/
|
|
1038
|
+
_elementWithListener(node, type) {
|
|
1039
|
+
while (node !== null) {
|
|
1040
|
+
const element = this._entityElements.get(node);
|
|
1041
|
+
if (element?.hasListeners(type)) {
|
|
1042
|
+
return element;
|
|
1043
|
+
}
|
|
1044
|
+
node = node.parent;
|
|
1045
|
+
}
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
959
1048
|
// New helper to convert CSS coordinates to canvas (picker) coordinates
|
|
960
1049
|
_getPickerCoordinates(event) {
|
|
961
1050
|
// Get the canvas' bounding rectangle in CSS pixels.
|
|
@@ -1001,17 +1090,9 @@ class AppElement extends AsyncElement {
|
|
|
1001
1090
|
const node = await this._pickNode(event);
|
|
1002
1091
|
if (token !== this._pickToken || !this._picker)
|
|
1003
1092
|
return;
|
|
1004
|
-
//
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
while (currentNode !== null) {
|
|
1008
|
-
const entityElement = this.querySelector(`pc-entity[name="${currentNode.name}"]`);
|
|
1009
|
-
if (entityElement) {
|
|
1010
|
-
newHoverEntity = entityElement;
|
|
1011
|
-
break;
|
|
1012
|
-
}
|
|
1013
|
-
currentNode = currentNode.parent;
|
|
1014
|
-
}
|
|
1093
|
+
// The hovered element is the nearest one up the node's parent chain, listening or not -
|
|
1094
|
+
// dispatch is gated per event type below
|
|
1095
|
+
const newHoverEntity = this._elementFromNode(node);
|
|
1015
1096
|
// Handle enter/leave events
|
|
1016
1097
|
if (this._hoveredEntity !== newHoverEntity) {
|
|
1017
1098
|
if (this._hoveredEntity && this._hoveredEntity.hasListeners('pointerleave')) {
|
|
@@ -1031,26 +1112,22 @@ class AppElement extends AsyncElement {
|
|
|
1031
1112
|
async _onPointerDown(event) {
|
|
1032
1113
|
if (!this._picker || !this.app)
|
|
1033
1114
|
return;
|
|
1034
|
-
|
|
1115
|
+
const node = await this._pickNode(event);
|
|
1035
1116
|
if (!this._picker)
|
|
1036
1117
|
return; // the element disconnected while the pick was in flight
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
entityElement.dispatchEvent(new PointerEvent('pointerdown', event));
|
|
1041
|
-
break;
|
|
1042
|
-
}
|
|
1043
|
-
currentNode = currentNode.parent;
|
|
1118
|
+
const entityElement = this._elementWithListener(node, 'pointerdown');
|
|
1119
|
+
if (entityElement) {
|
|
1120
|
+
entityElement.dispatchEvent(new PointerEvent('pointerdown', event));
|
|
1044
1121
|
}
|
|
1045
1122
|
}
|
|
1046
1123
|
async _onPointerUp(event) {
|
|
1047
1124
|
if (!this._picker || !this.app)
|
|
1048
1125
|
return;
|
|
1049
1126
|
const node = await this._pickNode(event);
|
|
1050
|
-
if (!
|
|
1051
|
-
return;
|
|
1052
|
-
const entityElement = this.
|
|
1053
|
-
if (entityElement
|
|
1127
|
+
if (!this._picker)
|
|
1128
|
+
return; // the element disconnected while the pick was in flight
|
|
1129
|
+
const entityElement = this._elementWithListener(node, 'pointerup');
|
|
1130
|
+
if (entityElement) {
|
|
1054
1131
|
entityElement.dispatchEvent(new PointerEvent('pointerup', event));
|
|
1055
1132
|
}
|
|
1056
1133
|
}
|
|
@@ -1080,28 +1157,43 @@ class AppElement extends AsyncElement {
|
|
|
1080
1157
|
}
|
|
1081
1158
|
}
|
|
1082
1159
|
/**
|
|
1083
|
-
*
|
|
1160
|
+
* Warns that a graphics option was written too late to have any effect. These options are read
|
|
1161
|
+
* once, when the element connects and creates its graphics device, so a later write updates
|
|
1162
|
+
* only the element's own property - silently, without this.
|
|
1163
|
+
*
|
|
1164
|
+
* @param name - The name of the option, as its attribute.
|
|
1165
|
+
*/
|
|
1166
|
+
_warnIfBooted(name) {
|
|
1167
|
+
if (this._optionsLocked) {
|
|
1168
|
+
console.warn(`Attribute '${name}' on <pc-app> is only read when the application boots, so this change has no effect. Set it before the element is connected, or remove and re-insert the element to reboot with the new value.`);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Sets whether the frame buffer has an alpha channel, which is what lets the page show through
|
|
1173
|
+
* wherever the scene has not drawn. Read only when the application boots.
|
|
1084
1174
|
* @param value - The alpha flag.
|
|
1085
1175
|
*/
|
|
1086
1176
|
set alpha(value) {
|
|
1177
|
+
this._warnIfBooted('alpha');
|
|
1087
1178
|
this._alpha = value;
|
|
1088
1179
|
}
|
|
1089
1180
|
/**
|
|
1090
|
-
* Gets the alpha
|
|
1181
|
+
* Gets whether the frame buffer has an alpha channel.
|
|
1091
1182
|
* @returns The alpha flag.
|
|
1092
1183
|
*/
|
|
1093
1184
|
get alpha() {
|
|
1094
1185
|
return this._alpha;
|
|
1095
1186
|
}
|
|
1096
1187
|
/**
|
|
1097
|
-
* Sets the
|
|
1188
|
+
* Sets whether the frame buffer is anti-aliased. Read only when the application boots.
|
|
1098
1189
|
* @param value - The antialias flag.
|
|
1099
1190
|
*/
|
|
1100
1191
|
set antialias(value) {
|
|
1192
|
+
this._warnIfBooted('antialias');
|
|
1101
1193
|
this._antialias = value;
|
|
1102
1194
|
}
|
|
1103
1195
|
/**
|
|
1104
|
-
* Gets the
|
|
1196
|
+
* Gets whether the frame buffer is anti-aliased.
|
|
1105
1197
|
* @returns The antialias flag.
|
|
1106
1198
|
*/
|
|
1107
1199
|
get antialias() {
|
|
@@ -1109,10 +1201,11 @@ class AppElement extends AsyncElement {
|
|
|
1109
1201
|
}
|
|
1110
1202
|
/**
|
|
1111
1203
|
* Sets the graphics backend. Defaults to 'webgpu', which falls back to 'webgl2' if WebGPU
|
|
1112
|
-
* is not supported by the browser.
|
|
1204
|
+
* is not supported by the browser. Read only when the application boots.
|
|
1113
1205
|
* @param value - The graphics backend ('webgpu', 'webgl2', or 'null').
|
|
1114
1206
|
*/
|
|
1115
1207
|
set backend(value) {
|
|
1208
|
+
this._warnIfBooted('backend');
|
|
1116
1209
|
this._backend = value;
|
|
1117
1210
|
}
|
|
1118
1211
|
/**
|
|
@@ -1123,18 +1216,20 @@ class AppElement extends AsyncElement {
|
|
|
1123
1216
|
return this._backend;
|
|
1124
1217
|
}
|
|
1125
1218
|
/**
|
|
1126
|
-
* Sets the depth
|
|
1127
|
-
*
|
|
1219
|
+
* Sets whether the frame buffer has a depth buffer, which the renderer needs to resolve which
|
|
1220
|
+
* surface is nearest the camera. Read only when the application boots.
|
|
1221
|
+
* @param value - The depth buffer flag.
|
|
1128
1222
|
*/
|
|
1129
|
-
set
|
|
1130
|
-
this.
|
|
1223
|
+
set depthBuffer(value) {
|
|
1224
|
+
this._warnIfBooted('depth-buffer');
|
|
1225
|
+
this._depthBuffer = value;
|
|
1131
1226
|
}
|
|
1132
1227
|
/**
|
|
1133
|
-
* Gets the depth
|
|
1134
|
-
* @returns The depth flag.
|
|
1228
|
+
* Gets whether the frame buffer has a depth buffer.
|
|
1229
|
+
* @returns The depth buffer flag.
|
|
1135
1230
|
*/
|
|
1136
|
-
get
|
|
1137
|
-
return this.
|
|
1231
|
+
get depthBuffer() {
|
|
1232
|
+
return this._depthBuffer;
|
|
1138
1233
|
}
|
|
1139
1234
|
/**
|
|
1140
1235
|
* Gets the hierarchy ready flag.
|
|
@@ -1144,24 +1239,6 @@ class AppElement extends AsyncElement {
|
|
|
1144
1239
|
get hierarchyReady() {
|
|
1145
1240
|
return this._hierarchyReady;
|
|
1146
1241
|
}
|
|
1147
|
-
/**
|
|
1148
|
-
* Sets the high resolution flag. When true, the application will render at the device's
|
|
1149
|
-
* physical resolution. When false, the application will render at CSS resolution.
|
|
1150
|
-
* @param value - The high resolution flag.
|
|
1151
|
-
*/
|
|
1152
|
-
set highResolution(value) {
|
|
1153
|
-
this._highResolution = value;
|
|
1154
|
-
if (this.app) {
|
|
1155
|
-
this.app.graphicsDevice.maxPixelRatio = value ? window.devicePixelRatio : 1;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
/**
|
|
1159
|
-
* Gets the high resolution flag.
|
|
1160
|
-
* @returns The high resolution flag.
|
|
1161
|
-
*/
|
|
1162
|
-
get highResolution() {
|
|
1163
|
-
return this._highResolution;
|
|
1164
|
-
}
|
|
1165
1242
|
/**
|
|
1166
1243
|
* Sets whether the application shows its built-in loading bar while it boots and preloads its
|
|
1167
1244
|
* assets. Enabled by default; setting `false` removes the bar immediately, while setting
|
|
@@ -1186,21 +1263,45 @@ class AppElement extends AsyncElement {
|
|
|
1186
1263
|
return this._loadingBar;
|
|
1187
1264
|
}
|
|
1188
1265
|
/**
|
|
1189
|
-
* Sets the
|
|
1190
|
-
*
|
|
1266
|
+
* Sets the cap on the pixel ratio the application renders at. The canvas is sized by the
|
|
1267
|
+
* smaller of this value and the display's own device pixel ratio, so the default of `Infinity`
|
|
1268
|
+
* renders at full physical resolution, `1` renders at CSS resolution, and an intermediate
|
|
1269
|
+
* value such as `2` keeps a dense display sharp without paying for every one of its pixels.
|
|
1270
|
+
* Must be greater than 0. Unlike the other graphics options, this applies immediately.
|
|
1271
|
+
* @param value - The maximum pixel ratio.
|
|
1272
|
+
*/
|
|
1273
|
+
set maxPixelRatio(value) {
|
|
1274
|
+
this._maxPixelRatio = value;
|
|
1275
|
+
if (this.app) {
|
|
1276
|
+
this.app.graphicsDevice.maxPixelRatio = value;
|
|
1277
|
+
this.app.resizeCanvas();
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Gets the cap on the pixel ratio the application renders at.
|
|
1282
|
+
* @returns The maximum pixel ratio.
|
|
1283
|
+
*/
|
|
1284
|
+
get maxPixelRatio() {
|
|
1285
|
+
return this._maxPixelRatio;
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Sets whether the frame buffer has a stencil buffer, which stencil-based effects and UI
|
|
1289
|
+
* masking need. Read only when the application boots.
|
|
1290
|
+
* @param value - The stencil buffer flag.
|
|
1191
1291
|
*/
|
|
1192
|
-
set
|
|
1193
|
-
this.
|
|
1292
|
+
set stencilBuffer(value) {
|
|
1293
|
+
this._warnIfBooted('stencil-buffer');
|
|
1294
|
+
this._stencilBuffer = value;
|
|
1194
1295
|
}
|
|
1195
1296
|
/**
|
|
1196
|
-
* Gets the stencil
|
|
1197
|
-
* @returns The stencil flag.
|
|
1297
|
+
* Gets whether the frame buffer has a stencil buffer.
|
|
1298
|
+
* @returns The stencil buffer flag.
|
|
1198
1299
|
*/
|
|
1199
|
-
get
|
|
1200
|
-
return this.
|
|
1300
|
+
get stencilBuffer() {
|
|
1301
|
+
return this._stencilBuffer;
|
|
1201
1302
|
}
|
|
1202
1303
|
static get observedAttributes() {
|
|
1203
|
-
return ['alpha', 'antialias', 'backend', 'depth', '
|
|
1304
|
+
return ['alpha', 'antialias', 'backend', 'depth-buffer', 'loading-bar', 'max-pixel-ratio', 'stencil-buffer'];
|
|
1204
1305
|
}
|
|
1205
1306
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
1206
1307
|
switch (name) {
|
|
@@ -1213,17 +1314,17 @@ class AppElement extends AsyncElement {
|
|
|
1213
1314
|
case 'backend':
|
|
1214
1315
|
this.backend = parseEnum(newValue, ['webgpu', 'webgl2', 'null'], 'webgpu', name);
|
|
1215
1316
|
break;
|
|
1216
|
-
case 'depth':
|
|
1217
|
-
this.
|
|
1218
|
-
break;
|
|
1219
|
-
case 'high-resolution':
|
|
1220
|
-
this.highResolution = parseBool(newValue, true);
|
|
1317
|
+
case 'depth-buffer':
|
|
1318
|
+
this.depthBuffer = parseBool(newValue, true);
|
|
1221
1319
|
break;
|
|
1222
1320
|
case 'loading-bar':
|
|
1223
1321
|
this.loadingBar = parseBool(newValue, true);
|
|
1224
1322
|
break;
|
|
1225
|
-
case '
|
|
1226
|
-
this.
|
|
1323
|
+
case 'max-pixel-ratio':
|
|
1324
|
+
this.maxPixelRatio = parseNumber(newValue, Infinity, name);
|
|
1325
|
+
break;
|
|
1326
|
+
case 'stencil-buffer':
|
|
1327
|
+
this.stencilBuffer = parseBool(newValue, true);
|
|
1227
1328
|
break;
|
|
1228
1329
|
}
|
|
1229
1330
|
}
|
|
@@ -1292,6 +1393,11 @@ class EntityElement extends AsyncElement {
|
|
|
1292
1393
|
*/
|
|
1293
1394
|
_built = false;
|
|
1294
1395
|
_entity = null;
|
|
1396
|
+
/**
|
|
1397
|
+
* The application element this entity is registered with, cached at creation time so the
|
|
1398
|
+
* entity can be unregistered even once this element has left the DOM.
|
|
1399
|
+
*/
|
|
1400
|
+
_appElement = null;
|
|
1295
1401
|
/**
|
|
1296
1402
|
* The PlayCanvas entity instance. `null` until the element is ready, and again once it has
|
|
1297
1403
|
* been removed from the document — await {@link whenReady} or the element's `ready()`
|
|
@@ -1321,6 +1427,27 @@ class EntityElement extends AsyncElement {
|
|
|
1321
1427
|
if (this._tags.length > 0) {
|
|
1322
1428
|
entity.tags.add(this._tags);
|
|
1323
1429
|
}
|
|
1430
|
+
// Register with the owning application, which joins engine nodes back to elements by
|
|
1431
|
+
// identity (never by name), and hook the entity's destruction. The engine fires 'destroy'
|
|
1432
|
+
// for every entity in a destroyed subtree, so the element learns of its entity's death no
|
|
1433
|
+
// matter who causes it: this element, an ancestor, the whole application, or a user
|
|
1434
|
+
// script calling entity.destroy().
|
|
1435
|
+
this._appElement = this.closestApp;
|
|
1436
|
+
this._appElement?._registerEntityElement(entity, this);
|
|
1437
|
+
entity.once('destroy', this._onEntityDestroy, this);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Handles the destruction of the backing entity. Resets the element so a later re-insertion
|
|
1441
|
+
* starts clean: `_built` must be cleared alongside `_entity`, or buildHierarchy would bail
|
|
1442
|
+
* and a re-created entity would never be parented.
|
|
1443
|
+
*
|
|
1444
|
+
* @param entity - The entity that was destroyed.
|
|
1445
|
+
*/
|
|
1446
|
+
_onEntityDestroy(entity) {
|
|
1447
|
+
this._appElement?._unregisterEntityElement(entity);
|
|
1448
|
+
this._appElement = null;
|
|
1449
|
+
this._entity = null;
|
|
1450
|
+
this._built = false;
|
|
1324
1451
|
}
|
|
1325
1452
|
buildHierarchy(app) {
|
|
1326
1453
|
if (!this.entity || this._built)
|
|
@@ -1363,22 +1490,11 @@ class EntityElement extends AsyncElement {
|
|
|
1363
1490
|
}
|
|
1364
1491
|
}
|
|
1365
1492
|
disconnectedCallback() {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
// on re-insertion, so the descendant would get a fresh entity that is never parented.
|
|
1372
|
-
const children = this.querySelectorAll('pc-entity');
|
|
1373
|
-
children.forEach((child) => {
|
|
1374
|
-
child._entity = null;
|
|
1375
|
-
child._built = false;
|
|
1376
|
-
});
|
|
1377
|
-
// Destroy the entity
|
|
1378
|
-
this.entity.destroy();
|
|
1379
|
-
this._entity = null;
|
|
1380
|
-
this._built = false;
|
|
1381
|
-
}
|
|
1493
|
+
// Destroying the entity destroys its whole subtree, and the engine fires 'destroy' for
|
|
1494
|
+
// every entity in it - so _onEntityDestroy resets this element AND every descendant
|
|
1495
|
+
// element before the descendants' own disconnectedCallbacks run. Their entities are null
|
|
1496
|
+
// by then, making this call a no-op for them.
|
|
1497
|
+
this._entity?.destroy();
|
|
1382
1498
|
}
|
|
1383
1499
|
/**
|
|
1384
1500
|
* Sets the enabled state of the entity.
|
|
@@ -2525,6 +2641,10 @@ class ButtonComponentElement extends ComponentElement {
|
|
|
2525
2641
|
}
|
|
2526
2642
|
customElements.define('pc-button', ButtonComponentElement);
|
|
2527
2643
|
|
|
2644
|
+
const projections = new Map([
|
|
2645
|
+
['perspective', playcanvas.PROJECTION_PERSPECTIVE],
|
|
2646
|
+
['orthographic', playcanvas.PROJECTION_ORTHOGRAPHIC]
|
|
2647
|
+
]);
|
|
2528
2648
|
const tonemaps = new Map([
|
|
2529
2649
|
['none', playcanvas.TONEMAP_NONE],
|
|
2530
2650
|
['linear', playcanvas.TONEMAP_LINEAR],
|
|
@@ -2555,7 +2675,7 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2555
2675
|
_gamma = 'srgb';
|
|
2556
2676
|
_horizontalFov = false;
|
|
2557
2677
|
_nearClip = 0.1;
|
|
2558
|
-
|
|
2678
|
+
_projection = 'perspective';
|
|
2559
2679
|
_orthoHeight = 10;
|
|
2560
2680
|
_priority = 0;
|
|
2561
2681
|
_rect = new playcanvas.Vec4(0, 0, 1, 1);
|
|
@@ -2579,12 +2699,12 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2579
2699
|
gammaCorrection: this._gamma === 'srgb' ? playcanvas.GAMMA_SRGB : playcanvas.GAMMA_NONE,
|
|
2580
2700
|
horizontalFov: this._horizontalFov,
|
|
2581
2701
|
nearClip: this._nearClip,
|
|
2582
|
-
projection: this.
|
|
2702
|
+
projection: projections.get(this._projection) ?? playcanvas.PROJECTION_PERSPECTIVE,
|
|
2583
2703
|
orthoHeight: this._orthoHeight,
|
|
2584
2704
|
priority: this._priority,
|
|
2585
2705
|
rect: this._rect,
|
|
2586
2706
|
scissorRect: this._scissorRect,
|
|
2587
|
-
toneMapping: tonemaps.get(this._tonemap)
|
|
2707
|
+
toneMapping: tonemaps.get(this._tonemap) ?? playcanvas.TONEMAP_NONE
|
|
2588
2708
|
};
|
|
2589
2709
|
}
|
|
2590
2710
|
get xrAvailable() {
|
|
@@ -2826,23 +2946,6 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2826
2946
|
get nearClip() {
|
|
2827
2947
|
return this._nearClip;
|
|
2828
2948
|
}
|
|
2829
|
-
/**
|
|
2830
|
-
* Sets the orthographic projection of the camera.
|
|
2831
|
-
* @param value - The orthographic projection.
|
|
2832
|
-
*/
|
|
2833
|
-
set orthographic(value) {
|
|
2834
|
-
this._orthographic = value;
|
|
2835
|
-
if (this.component) {
|
|
2836
|
-
this.component.projection = value ? playcanvas.PROJECTION_ORTHOGRAPHIC : playcanvas.PROJECTION_PERSPECTIVE;
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
/**
|
|
2840
|
-
* Gets the orthographic projection of the camera.
|
|
2841
|
-
* @returns The orthographic projection.
|
|
2842
|
-
*/
|
|
2843
|
-
get orthographic() {
|
|
2844
|
-
return this._orthographic;
|
|
2845
|
-
}
|
|
2846
2949
|
/**
|
|
2847
2950
|
* Sets the orthographic height of the camera.
|
|
2848
2951
|
* @param value - The orthographic height.
|
|
@@ -2877,6 +2980,23 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2877
2980
|
get priority() {
|
|
2878
2981
|
return this._priority;
|
|
2879
2982
|
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Sets the projection of the camera. Use `orthoHeight` to size an orthographic projection.
|
|
2985
|
+
* @param value - The projection ('perspective' or 'orthographic').
|
|
2986
|
+
*/
|
|
2987
|
+
set projection(value) {
|
|
2988
|
+
this._projection = value;
|
|
2989
|
+
if (this.component) {
|
|
2990
|
+
this.component.projection = projections.get(value) ?? playcanvas.PROJECTION_PERSPECTIVE;
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Gets the projection of the camera.
|
|
2995
|
+
* @returns The projection.
|
|
2996
|
+
*/
|
|
2997
|
+
get projection() {
|
|
2998
|
+
return this._projection;
|
|
2999
|
+
}
|
|
2880
3000
|
/**
|
|
2881
3001
|
* Sets the rect of the camera.
|
|
2882
3002
|
* @param value - The rect.
|
|
@@ -2943,9 +3063,9 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2943
3063
|
'gamma',
|
|
2944
3064
|
'horizontal-fov',
|
|
2945
3065
|
'near-clip',
|
|
2946
|
-
'orthographic',
|
|
2947
3066
|
'ortho-height',
|
|
2948
3067
|
'priority',
|
|
3068
|
+
'projection',
|
|
2949
3069
|
'rect',
|
|
2950
3070
|
'scissor-rect',
|
|
2951
3071
|
'tonemap'
|
|
@@ -2990,15 +3110,15 @@ class CameraComponentElement extends ComponentElement {
|
|
|
2990
3110
|
case 'near-clip':
|
|
2991
3111
|
this.nearClip = parseNumber(newValue, 0.1, name);
|
|
2992
3112
|
break;
|
|
2993
|
-
case 'orthographic':
|
|
2994
|
-
this.orthographic = parseBool(newValue, false);
|
|
2995
|
-
break;
|
|
2996
3113
|
case 'ortho-height':
|
|
2997
3114
|
this.orthoHeight = parseNumber(newValue, 10, name);
|
|
2998
3115
|
break;
|
|
2999
3116
|
case 'priority':
|
|
3000
3117
|
this.priority = parseNumber(newValue, 0, name);
|
|
3001
3118
|
break;
|
|
3119
|
+
case 'projection':
|
|
3120
|
+
this.projection = parseEnum(newValue, projections, 'perspective', name);
|
|
3121
|
+
break;
|
|
3002
3122
|
case 'rect':
|
|
3003
3123
|
this.rect = parseVec4(newValue, new playcanvas.Vec4(0, 0, 1, 1), name);
|
|
3004
3124
|
break;
|
|
@@ -7416,6 +7536,14 @@ class RigidBodyComponentElement extends ComponentElement {
|
|
|
7416
7536
|
}
|
|
7417
7537
|
customElements.define('pc-rigidbody', RigidBodyComponentElement);
|
|
7418
7538
|
|
|
7539
|
+
// The engine's SCALEMODE_* constants are the strings 'none' and 'blend', so this map happens to be
|
|
7540
|
+
// an identity. It is still the right shape: it supplies parseEnum's valid-name list, it is what the
|
|
7541
|
+
// manifest generator reads the enum values from, and it keeps the attribute vocabulary independent
|
|
7542
|
+
// of constants the engine is free to change.
|
|
7543
|
+
const scaleModes = new Map([
|
|
7544
|
+
['none', playcanvas.SCALEMODE_NONE],
|
|
7545
|
+
['blend', playcanvas.SCALEMODE_BLEND]
|
|
7546
|
+
]);
|
|
7419
7547
|
/**
|
|
7420
7548
|
* The ScreenComponentElement interface provides properties and methods for manipulating
|
|
7421
7549
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-screen/ | `<pc-screen>`} elements.
|
|
@@ -7429,7 +7557,7 @@ class ScreenComponentElement extends ComponentElement {
|
|
|
7429
7557
|
_resolution = new playcanvas.Vec2(640, 320);
|
|
7430
7558
|
_referenceResolution = new playcanvas.Vec2(640, 320);
|
|
7431
7559
|
_priority = 0;
|
|
7432
|
-
|
|
7560
|
+
_scaleMode = 'none';
|
|
7433
7561
|
_scaleBlend = 0.5;
|
|
7434
7562
|
/** @ignore */
|
|
7435
7563
|
constructor() {
|
|
@@ -7441,7 +7569,7 @@ class ScreenComponentElement extends ComponentElement {
|
|
|
7441
7569
|
referenceResolution: this._referenceResolution,
|
|
7442
7570
|
resolution: this._resolution,
|
|
7443
7571
|
scaleBlend: this._scaleBlend,
|
|
7444
|
-
scaleMode: this.
|
|
7572
|
+
scaleMode: scaleModes.get(this._scaleMode) ?? playcanvas.SCALEMODE_NONE,
|
|
7445
7573
|
screenSpace: this._screenSpace
|
|
7446
7574
|
};
|
|
7447
7575
|
}
|
|
@@ -7479,23 +7607,44 @@ class ScreenComponentElement extends ComponentElement {
|
|
|
7479
7607
|
get resolution() {
|
|
7480
7608
|
return this._resolution;
|
|
7481
7609
|
}
|
|
7610
|
+
/**
|
|
7611
|
+
* Sets how the screen's `resolution` and `referenceResolution` are weighted against each other
|
|
7612
|
+
* when `scaleMode` is `blend`, from 0 (follow the resolution) to 1 (follow the reference
|
|
7613
|
+
* resolution). Ignored while `scaleMode` is `none`.
|
|
7614
|
+
* @param value - The scale blend factor.
|
|
7615
|
+
*/
|
|
7482
7616
|
set scaleBlend(value) {
|
|
7483
7617
|
this._scaleBlend = value;
|
|
7484
7618
|
if (this.component) {
|
|
7485
7619
|
this.component.scaleBlend = this._scaleBlend;
|
|
7486
7620
|
}
|
|
7487
7621
|
}
|
|
7622
|
+
/**
|
|
7623
|
+
* Gets how the screen's resolutions are weighted against each other.
|
|
7624
|
+
* @returns The scale blend factor.
|
|
7625
|
+
*/
|
|
7488
7626
|
get scaleBlend() {
|
|
7489
7627
|
return this._scaleBlend;
|
|
7490
7628
|
}
|
|
7491
|
-
|
|
7492
|
-
|
|
7629
|
+
/**
|
|
7630
|
+
* Sets how the screen scales its contents. `none` renders at `resolution` and ignores
|
|
7631
|
+
* `referenceResolution`; `blend` scales between the two, weighted by `scaleBlend`, which is what
|
|
7632
|
+
* keeps a UI laid out at one resolution usable at another. Requires `screenSpace` - the engine
|
|
7633
|
+
* forces `none` on a world-space screen, which does not support scaling.
|
|
7634
|
+
* @param value - The scale mode ('none' or 'blend').
|
|
7635
|
+
*/
|
|
7636
|
+
set scaleMode(value) {
|
|
7637
|
+
this._scaleMode = value;
|
|
7493
7638
|
if (this.component) {
|
|
7494
|
-
this.component.scaleMode =
|
|
7639
|
+
this.component.scaleMode = scaleModes.get(value) ?? playcanvas.SCALEMODE_NONE;
|
|
7495
7640
|
}
|
|
7496
7641
|
}
|
|
7497
|
-
|
|
7498
|
-
|
|
7642
|
+
/**
|
|
7643
|
+
* Gets how the screen scales its contents.
|
|
7644
|
+
* @returns The scale mode.
|
|
7645
|
+
*/
|
|
7646
|
+
get scaleMode() {
|
|
7647
|
+
return this._scaleMode;
|
|
7499
7648
|
}
|
|
7500
7649
|
set screenSpace(value) {
|
|
7501
7650
|
this._screenSpace = value;
|
|
@@ -7509,12 +7658,12 @@ class ScreenComponentElement extends ComponentElement {
|
|
|
7509
7658
|
static get observedAttributes() {
|
|
7510
7659
|
return [
|
|
7511
7660
|
...super.observedAttributes,
|
|
7512
|
-
'blend',
|
|
7513
7661
|
'screen-space',
|
|
7514
7662
|
'resolution',
|
|
7515
7663
|
'reference-resolution',
|
|
7516
7664
|
'priority',
|
|
7517
|
-
'scale-blend'
|
|
7665
|
+
'scale-blend',
|
|
7666
|
+
'scale-mode'
|
|
7518
7667
|
];
|
|
7519
7668
|
}
|
|
7520
7669
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
@@ -7532,8 +7681,8 @@ class ScreenComponentElement extends ComponentElement {
|
|
|
7532
7681
|
case 'scale-blend':
|
|
7533
7682
|
this.scaleBlend = parseNumber(newValue, 0.5, name);
|
|
7534
7683
|
break;
|
|
7535
|
-
case '
|
|
7536
|
-
this.
|
|
7684
|
+
case 'scale-mode':
|
|
7685
|
+
this.scaleMode = parseEnum(newValue, scaleModes, 'none', name);
|
|
7537
7686
|
break;
|
|
7538
7687
|
case 'screen-space':
|
|
7539
7688
|
this.screenSpace = parseBool(newValue, false);
|
|
@@ -7756,7 +7905,8 @@ class ScrollViewComponentElement extends ComponentElement {
|
|
|
7756
7905
|
return super.component;
|
|
7757
7906
|
}
|
|
7758
7907
|
/**
|
|
7759
|
-
* Sets whether horizontal
|
|
7908
|
+
* Sets whether scrolling along the horizontal axis is enabled. This is a toggle, unlike the
|
|
7909
|
+
* `orientation` of a `<pc-scrollbar>`, for which `horizontal` is one of the accepted values.
|
|
7760
7910
|
* @param value - Whether horizontal scrolling is enabled.
|
|
7761
7911
|
*/
|
|
7762
7912
|
set horizontal(value) {
|
|
@@ -7766,14 +7916,15 @@ class ScrollViewComponentElement extends ComponentElement {
|
|
|
7766
7916
|
}
|
|
7767
7917
|
}
|
|
7768
7918
|
/**
|
|
7769
|
-
* Gets whether horizontal
|
|
7919
|
+
* Gets whether scrolling along the horizontal axis is enabled.
|
|
7770
7920
|
* @returns Whether horizontal scrolling is enabled.
|
|
7771
7921
|
*/
|
|
7772
7922
|
get horizontal() {
|
|
7773
7923
|
return this._horizontal;
|
|
7774
7924
|
}
|
|
7775
7925
|
/**
|
|
7776
|
-
* Sets whether vertical
|
|
7926
|
+
* Sets whether scrolling along the vertical axis is enabled. This is a toggle, unlike the
|
|
7927
|
+
* `orientation` of a `<pc-scrollbar>`, for which `vertical` is one of the accepted values.
|
|
7777
7928
|
* @param value - Whether vertical scrolling is enabled.
|
|
7778
7929
|
*/
|
|
7779
7930
|
set vertical(value) {
|
|
@@ -7783,7 +7934,7 @@ class ScrollViewComponentElement extends ComponentElement {
|
|
|
7783
7934
|
}
|
|
7784
7935
|
}
|
|
7785
7936
|
/**
|
|
7786
|
-
* Gets whether vertical
|
|
7937
|
+
* Gets whether scrolling along the vertical axis is enabled.
|
|
7787
7938
|
* @returns Whether vertical scrolling is enabled.
|
|
7788
7939
|
*/
|
|
7789
7940
|
get vertical() {
|
|
@@ -9773,7 +9924,7 @@ class SkyElement extends AsyncElement {
|
|
|
9773
9924
|
_center = new playcanvas.Vec3(0, 0.01, 0);
|
|
9774
9925
|
_intensity = 1;
|
|
9775
9926
|
_rotation = new playcanvas.Vec3();
|
|
9776
|
-
|
|
9927
|
+
_mipLevel = 0;
|
|
9777
9928
|
_lighting = false;
|
|
9778
9929
|
_scale = new playcanvas.Vec3(100, 100, 100);
|
|
9779
9930
|
_type = 'infinite';
|
|
@@ -9807,7 +9958,7 @@ class SkyElement extends AsyncElement {
|
|
|
9807
9958
|
this._scene.sky.node.setLocalScale(this._scale);
|
|
9808
9959
|
this._scene.sky.center = this._center;
|
|
9809
9960
|
this._scene.skyboxIntensity = this._intensity;
|
|
9810
|
-
this._scene.skyboxMip = this.
|
|
9961
|
+
this._scene.skyboxMip = this._mipLevel;
|
|
9811
9962
|
}
|
|
9812
9963
|
async _loadSkybox() {
|
|
9813
9964
|
const appElement = await this.closestApp?.ready();
|
|
@@ -9899,23 +10050,6 @@ class SkyElement extends AsyncElement {
|
|
|
9899
10050
|
get intensity() {
|
|
9900
10051
|
return this._intensity;
|
|
9901
10052
|
}
|
|
9902
|
-
/**
|
|
9903
|
-
* Sets the mip level of the skybox.
|
|
9904
|
-
* @param value - The mip level.
|
|
9905
|
-
*/
|
|
9906
|
-
set level(value) {
|
|
9907
|
-
this._level = value;
|
|
9908
|
-
if (this._scene) {
|
|
9909
|
-
this._scene.skyboxMip = this._level;
|
|
9910
|
-
}
|
|
9911
|
-
}
|
|
9912
|
-
/**
|
|
9913
|
-
* Gets the mip level of the skybox.
|
|
9914
|
-
* @returns The mip level.
|
|
9915
|
-
*/
|
|
9916
|
-
get level() {
|
|
9917
|
-
return this._level;
|
|
9918
|
-
}
|
|
9919
10053
|
/**
|
|
9920
10054
|
* Sets whether the skybox is used as a light source.
|
|
9921
10055
|
* @param value - Whether to use lighting.
|
|
@@ -9930,6 +10064,24 @@ class SkyElement extends AsyncElement {
|
|
|
9930
10064
|
get lighting() {
|
|
9931
10065
|
return this._lighting;
|
|
9932
10066
|
}
|
|
10067
|
+
/**
|
|
10068
|
+
* Sets the mip level of the skybox, where 0 is the sharpest. Raising it selects a blurrier mip,
|
|
10069
|
+
* which is how a skybox is softened without blurring the texture itself.
|
|
10070
|
+
* @param value - The mip level.
|
|
10071
|
+
*/
|
|
10072
|
+
set mipLevel(value) {
|
|
10073
|
+
this._mipLevel = value;
|
|
10074
|
+
if (this._scene) {
|
|
10075
|
+
this._scene.skyboxMip = this._mipLevel;
|
|
10076
|
+
}
|
|
10077
|
+
}
|
|
10078
|
+
/**
|
|
10079
|
+
* Gets the mip level of the skybox.
|
|
10080
|
+
* @returns The mip level.
|
|
10081
|
+
*/
|
|
10082
|
+
get mipLevel() {
|
|
10083
|
+
return this._mipLevel;
|
|
10084
|
+
}
|
|
9933
10085
|
/**
|
|
9934
10086
|
* Sets the Euler rotation of the skybox.
|
|
9935
10087
|
* @param value - The rotation.
|
|
@@ -9986,7 +10138,7 @@ class SkyElement extends AsyncElement {
|
|
|
9986
10138
|
return this._type;
|
|
9987
10139
|
}
|
|
9988
10140
|
static get observedAttributes() {
|
|
9989
|
-
return ['asset', 'center', 'intensity', '
|
|
10141
|
+
return ['asset', 'center', 'intensity', 'lighting', 'mip-level', 'rotation', 'scale', 'type'];
|
|
9990
10142
|
}
|
|
9991
10143
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
9992
10144
|
switch (name) {
|
|
@@ -9999,12 +10151,12 @@ class SkyElement extends AsyncElement {
|
|
|
9999
10151
|
case 'intensity':
|
|
10000
10152
|
this.intensity = parseNumber(newValue, 1, name);
|
|
10001
10153
|
break;
|
|
10002
|
-
case 'level':
|
|
10003
|
-
this.level = parseNumber(newValue, 0, name);
|
|
10004
|
-
break;
|
|
10005
10154
|
case 'lighting':
|
|
10006
10155
|
this.lighting = parseBool(newValue, false);
|
|
10007
10156
|
break;
|
|
10157
|
+
case 'mip-level':
|
|
10158
|
+
this.mipLevel = parseNumber(newValue, 0, name);
|
|
10159
|
+
break;
|
|
10008
10160
|
case 'rotation':
|
|
10009
10161
|
this.rotation = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
10010
10162
|
break;
|