@playcanvas/web-components 0.2.1 → 0.2.3
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/README.md +1 -1
- package/dist/app.d.ts +1 -0
- package/dist/components/particlesystem-component.d.ts +52 -0
- package/dist/index.d.ts +3 -2
- package/dist/pwc.cjs +468 -93
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +468 -93
- 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.mjs +468 -94
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.ts +15 -1
- package/package.json +13 -12
- package/src/app.ts +21 -11
- package/src/asset.ts +53 -1
- package/src/components/particlesystem-component.ts +155 -0
- package/src/index.ts +4 -2
- package/src/scene.ts +35 -4
package/src/app.ts
CHANGED
|
@@ -26,7 +26,7 @@ class AppElement extends AsyncElement {
|
|
|
26
26
|
|
|
27
27
|
private _stencil = true;
|
|
28
28
|
|
|
29
|
-
private _highResolution =
|
|
29
|
+
private _highResolution = true;
|
|
30
30
|
|
|
31
31
|
private _hierarchyReady = false;
|
|
32
32
|
|
|
@@ -193,21 +193,33 @@ class AppElement extends AsyncElement {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// New helper to convert CSS coordinates to canvas (picker) coordinates
|
|
197
|
+
private _getPickerCoordinates(event: PointerEvent): { x: number, y: number } {
|
|
198
|
+
// Get the canvas' bounding rectangle in CSS pixels.
|
|
199
|
+
const canvasRect = this._canvas!.getBoundingClientRect();
|
|
200
|
+
// Compute scale factors based on canvas actual resolution vs. its CSS display size.
|
|
201
|
+
const scaleX = this._canvas!.width / canvasRect.width;
|
|
202
|
+
const scaleY = this._canvas!.height / canvasRect.height;
|
|
203
|
+
// Convert the client coordinates accordingly.
|
|
204
|
+
const x = (event.clientX - canvasRect.left) * scaleX;
|
|
205
|
+
const y = (event.clientY - canvasRect.top) * scaleY;
|
|
206
|
+
return { x, y };
|
|
207
|
+
}
|
|
208
|
+
|
|
196
209
|
_onPointerMove(event: PointerEvent) {
|
|
197
210
|
if (!this._picker || !this.app) return;
|
|
198
211
|
|
|
199
212
|
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
200
213
|
if (!camera) return;
|
|
201
214
|
|
|
202
|
-
|
|
203
|
-
const x
|
|
204
|
-
const y = event.clientY - canvasRect.top;
|
|
215
|
+
// Use the helper to convert event coordinates into canvas/picker coordinates.
|
|
216
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
205
217
|
|
|
206
218
|
this._picker.prepare(camera, this.app!.scene);
|
|
207
219
|
const selection = this._picker.getSelection(x, y);
|
|
208
220
|
|
|
209
221
|
// Get the currently hovered entity by walking up the hierarchy
|
|
210
|
-
let newHoverEntity = null;
|
|
222
|
+
let newHoverEntity: EntityElement | null = null;
|
|
211
223
|
if (selection.length > 0) {
|
|
212
224
|
let currentNode: GraphNode | null = selection[0].node;
|
|
213
225
|
while (currentNode !== null) {
|
|
@@ -245,9 +257,8 @@ class AppElement extends AsyncElement {
|
|
|
245
257
|
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
246
258
|
if (!camera) return;
|
|
247
259
|
|
|
248
|
-
|
|
249
|
-
const x
|
|
250
|
-
const y = event.clientY - canvasRect.top;
|
|
260
|
+
// Convert the event's pointer coordinates
|
|
261
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
251
262
|
|
|
252
263
|
this._picker.prepare(camera, this.app!.scene);
|
|
253
264
|
const selection = this._picker.getSelection(x, y);
|
|
@@ -271,9 +282,8 @@ class AppElement extends AsyncElement {
|
|
|
271
282
|
const camera = this.app!.root.findComponent('camera') as CameraComponent;
|
|
272
283
|
if (!camera) return;
|
|
273
284
|
|
|
274
|
-
|
|
275
|
-
const x
|
|
276
|
-
const y = event.clientY - canvasRect.top;
|
|
285
|
+
// Convert CSS coordinates to picker coordinates
|
|
286
|
+
const { x, y } = this._getPickerCoordinates(event);
|
|
277
287
|
|
|
278
288
|
this._picker.prepare(camera, this.app!.scene);
|
|
279
289
|
const selection = this._picker.getSelection(x, y);
|
package/src/asset.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Asset } from 'playcanvas';
|
|
2
2
|
|
|
3
|
+
import { MeshoptDecoder } from '../lib/meshopt_decoder.module.js';
|
|
4
|
+
|
|
3
5
|
const extToType = new Map([
|
|
4
6
|
['bin', 'binary'],
|
|
5
7
|
['css', 'css'],
|
|
@@ -20,6 +22,45 @@ const extToType = new Map([
|
|
|
20
22
|
['webp', 'texture']
|
|
21
23
|
]);
|
|
22
24
|
|
|
25
|
+
|
|
26
|
+
// provide buffer view callback so we can handle models compressed with MeshOptimizer
|
|
27
|
+
// https://github.com/zeux/meshoptimizer
|
|
28
|
+
const processBufferView = (
|
|
29
|
+
gltfBuffer: any,
|
|
30
|
+
buffers: Array<any>,
|
|
31
|
+
continuation: (err: string, result: any) => void
|
|
32
|
+
) => {
|
|
33
|
+
if (gltfBuffer.extensions && gltfBuffer.extensions.EXT_meshopt_compression) {
|
|
34
|
+
const extensionDef = gltfBuffer.extensions.EXT_meshopt_compression;
|
|
35
|
+
|
|
36
|
+
Promise.all([MeshoptDecoder.ready, buffers[extensionDef.buffer]]).then((promiseResult) => {
|
|
37
|
+
const buffer = promiseResult[1];
|
|
38
|
+
|
|
39
|
+
const byteOffset = extensionDef.byteOffset || 0;
|
|
40
|
+
const byteLength = extensionDef.byteLength || 0;
|
|
41
|
+
|
|
42
|
+
const count = extensionDef.count;
|
|
43
|
+
const stride = extensionDef.byteStride;
|
|
44
|
+
|
|
45
|
+
const result = new Uint8Array(count * stride);
|
|
46
|
+
const source = new Uint8Array(buffer.buffer, buffer.byteOffset + byteOffset, byteLength);
|
|
47
|
+
|
|
48
|
+
MeshoptDecoder.decodeGltfBuffer(
|
|
49
|
+
result,
|
|
50
|
+
count,
|
|
51
|
+
stride,
|
|
52
|
+
source,
|
|
53
|
+
extensionDef.mode,
|
|
54
|
+
extensionDef.filter
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
continuation(null, result);
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
continuation(null, null);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
23
64
|
/**
|
|
24
65
|
* The AssetElement interface provides properties and methods for manipulating
|
|
25
66
|
* {@link https://developer.playcanvas.com/user-manual/engine/web-components/tags/pc-asset/ | `<pc-asset>`} elements.
|
|
@@ -54,10 +95,21 @@ class AssetElement extends HTMLElement {
|
|
|
54
95
|
return;
|
|
55
96
|
}
|
|
56
97
|
|
|
57
|
-
|
|
98
|
+
if (type === 'container') {
|
|
99
|
+
this.asset = new Asset(id, type, { url: src }, undefined, {
|
|
100
|
+
// @ts-ignore TODO no definition in pc
|
|
101
|
+
bufferView: {
|
|
102
|
+
processAsync: processBufferView.bind(this)
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
this.asset = new Asset(id, type, { url: src });
|
|
107
|
+
}
|
|
108
|
+
|
|
58
109
|
this.asset.preload = !this._lazy;
|
|
59
110
|
}
|
|
60
111
|
|
|
112
|
+
|
|
61
113
|
destroyAsset() {
|
|
62
114
|
if (this.asset) {
|
|
63
115
|
this.asset.unload();
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ParticleSystemComponent } from 'playcanvas';
|
|
2
|
+
|
|
3
|
+
import { ComponentElement } from './component';
|
|
4
|
+
import { AssetElement } from '../asset';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The ParticleSystemComponentElement interface provides properties and methods for manipulating
|
|
8
|
+
* {@link https://developer.playcanvas.com/user-manual/engine/web-components/tags/pc-particles/ | `<pc-particles>`} elements.
|
|
9
|
+
* The ParticleSystemComponentElement interface also inherits the properties and methods of the
|
|
10
|
+
* {@link HTMLElement} interface.
|
|
11
|
+
*
|
|
12
|
+
* @category Components
|
|
13
|
+
*/
|
|
14
|
+
class ParticleSystemComponentElement extends ComponentElement {
|
|
15
|
+
private _asset: string = '';
|
|
16
|
+
|
|
17
|
+
/** @ignore */
|
|
18
|
+
constructor() {
|
|
19
|
+
super('particlesystem');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getInitialComponentData() {
|
|
23
|
+
const asset = AssetElement.get(this._asset);
|
|
24
|
+
if (!asset) {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if ((asset.resource as any).colorMapAsset) {
|
|
29
|
+
const id = (asset.resource as any).colorMapAsset;
|
|
30
|
+
const colorMapAsset = AssetElement.get(id)?.id;
|
|
31
|
+
if (colorMapAsset) {
|
|
32
|
+
(asset.resource as any).colorMapAsset = colorMapAsset;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return asset.resource;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets the underlying PlayCanvas particle system component.
|
|
41
|
+
* @returns The particle system component.
|
|
42
|
+
*/
|
|
43
|
+
get component(): ParticleSystemComponent | null {
|
|
44
|
+
return super.component as ParticleSystemComponent | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private applyConfig(resource: any) {
|
|
48
|
+
if (!this.component) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Set all the config properties on the component
|
|
53
|
+
for (const key in resource) {
|
|
54
|
+
if (resource.hasOwnProperty(key)) {
|
|
55
|
+
(this.component as any)[key] = resource[key];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private async _loadAsset() {
|
|
61
|
+
const appElement = await this.closestApp?.ready();
|
|
62
|
+
const app = appElement?.app;
|
|
63
|
+
|
|
64
|
+
const asset = AssetElement.get(this._asset);
|
|
65
|
+
if (!asset) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (asset.loaded) {
|
|
70
|
+
this.applyConfig(asset.resource);
|
|
71
|
+
} else {
|
|
72
|
+
asset.once('load', () => {
|
|
73
|
+
this.applyConfig(asset.resource);
|
|
74
|
+
});
|
|
75
|
+
app!.assets.load(asset);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Sets the id of the `pc-asset` to use for the model.
|
|
81
|
+
* @param value - The asset ID.
|
|
82
|
+
*/
|
|
83
|
+
set asset(value: string) {
|
|
84
|
+
this._asset = value;
|
|
85
|
+
if (this.isConnected) {
|
|
86
|
+
this._loadAsset();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Gets the id of the `pc-asset` to use for the model.
|
|
92
|
+
* @returns The asset ID.
|
|
93
|
+
*/
|
|
94
|
+
get asset(): string {
|
|
95
|
+
return this._asset;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Control methods
|
|
99
|
+
/**
|
|
100
|
+
* Starts playing the particle system
|
|
101
|
+
*/
|
|
102
|
+
play() {
|
|
103
|
+
if (this.component) {
|
|
104
|
+
this.component.play();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Pauses the particle system
|
|
110
|
+
*/
|
|
111
|
+
pause() {
|
|
112
|
+
if (this.component) {
|
|
113
|
+
this.component.pause();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Resets the particle system
|
|
119
|
+
*/
|
|
120
|
+
reset() {
|
|
121
|
+
if (this.component) {
|
|
122
|
+
this.component.reset();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Stops the particle system
|
|
128
|
+
*/
|
|
129
|
+
stop() {
|
|
130
|
+
if (this.component) {
|
|
131
|
+
this.component.stop();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static get observedAttributes() {
|
|
136
|
+
return [
|
|
137
|
+
...super.observedAttributes,
|
|
138
|
+
'asset'
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
143
|
+
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
144
|
+
|
|
145
|
+
switch (name) {
|
|
146
|
+
case 'asset':
|
|
147
|
+
this.asset = newValue;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
customElements.define('pc-particles', ParticleSystemComponentElement);
|
|
154
|
+
|
|
155
|
+
export { ParticleSystemComponentElement };
|
package/src/index.ts
CHANGED
|
@@ -20,8 +20,8 @@ import { CameraComponentElement } from './components/camera-component';
|
|
|
20
20
|
import { CollisionComponentElement } from './components/collision-component';
|
|
21
21
|
import { ComponentElement } from './components/component';
|
|
22
22
|
import { ElementComponentElement } from './components/element-component';
|
|
23
|
-
import { SplatComponentElement } from './components/splat-component';
|
|
24
23
|
import { LightComponentElement } from './components/light-component';
|
|
24
|
+
import { ParticleSystemComponentElement } from './components/particlesystem-component';
|
|
25
25
|
import { RenderComponentElement } from './components/render-component';
|
|
26
26
|
import { RigidBodyComponentElement } from './components/rigidbody-component';
|
|
27
27
|
import { ScreenComponentElement } from './components/screen-component';
|
|
@@ -29,6 +29,7 @@ import { ScriptComponentElement } from './components/script-component';
|
|
|
29
29
|
import { ScriptElement } from './components/script';
|
|
30
30
|
import { SoundComponentElement } from './components/sound-component';
|
|
31
31
|
import { SoundSlotElement } from './components/sound-slot';
|
|
32
|
+
import { SplatComponentElement } from './components/splat-component';
|
|
32
33
|
import { MaterialElement } from './material';
|
|
33
34
|
import { ModelElement } from './model';
|
|
34
35
|
import { SceneElement } from './scene';
|
|
@@ -44,7 +45,7 @@ export {
|
|
|
44
45
|
CollisionComponentElement,
|
|
45
46
|
ComponentElement,
|
|
46
47
|
ElementComponentElement,
|
|
47
|
-
|
|
48
|
+
ParticleSystemComponentElement,
|
|
48
49
|
LightComponentElement,
|
|
49
50
|
ListenerComponentElement,
|
|
50
51
|
RenderComponentElement,
|
|
@@ -54,6 +55,7 @@ export {
|
|
|
54
55
|
ScriptElement,
|
|
55
56
|
SoundComponentElement,
|
|
56
57
|
SoundSlotElement,
|
|
58
|
+
SplatComponentElement,
|
|
57
59
|
MaterialElement,
|
|
58
60
|
ModelElement,
|
|
59
61
|
SceneElement,
|
package/src/scene.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Color, Scene } from 'playcanvas';
|
|
1
|
+
import { Color, Scene, Vec3 } from 'playcanvas';
|
|
2
2
|
|
|
3
|
+
import { AppElement } from './app';
|
|
3
4
|
import { AsyncElement } from './async-element';
|
|
4
|
-
import { parseColor } from './utils';
|
|
5
|
+
import { parseColor, parseVec3 } from './utils';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* The SceneElement interface provides properties and methods for manipulating
|
|
@@ -35,6 +36,11 @@ class SceneElement extends AsyncElement {
|
|
|
35
36
|
*/
|
|
36
37
|
private _fogEnd = 1000;
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The gravity of the scene.
|
|
41
|
+
*/
|
|
42
|
+
private _gravity = new Vec3(0, -9.81, 0);
|
|
43
|
+
|
|
38
44
|
/**
|
|
39
45
|
* The PlayCanvas scene instance.
|
|
40
46
|
*/
|
|
@@ -56,7 +62,9 @@ class SceneElement extends AsyncElement {
|
|
|
56
62
|
this.scene.fog.density = this._fogDensity;
|
|
57
63
|
this.scene.fog.start = this._fogStart;
|
|
58
64
|
this.scene.fog.end = this._fogEnd;
|
|
59
|
-
|
|
65
|
+
|
|
66
|
+
const appElement = this.parentElement as AppElement;
|
|
67
|
+
appElement.app!.systems.rigidbody!.gravity.copy(this._gravity);
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
|
|
@@ -155,8 +163,28 @@ class SceneElement extends AsyncElement {
|
|
|
155
163
|
return this._fogEnd;
|
|
156
164
|
}
|
|
157
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Sets the gravity of the scene.
|
|
168
|
+
* @param value - The gravity.
|
|
169
|
+
*/
|
|
170
|
+
set gravity(value: Vec3) {
|
|
171
|
+
this._gravity = value;
|
|
172
|
+
if (this.scene) {
|
|
173
|
+
const appElement = this.parentElement as AppElement;
|
|
174
|
+
appElement.app!.systems.rigidbody!.gravity.copy(value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Gets the gravity of the scene.
|
|
180
|
+
* @returns The gravity.
|
|
181
|
+
*/
|
|
182
|
+
get gravity() {
|
|
183
|
+
return this._gravity;
|
|
184
|
+
}
|
|
185
|
+
|
|
158
186
|
static get observedAttributes() {
|
|
159
|
-
return ['fog', 'fog-color', 'fog-density', 'fog-start', 'fog-end'];
|
|
187
|
+
return ['fog', 'fog-color', 'fog-density', 'fog-start', 'fog-end', 'gravity'];
|
|
160
188
|
}
|
|
161
189
|
|
|
162
190
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
@@ -176,6 +204,9 @@ class SceneElement extends AsyncElement {
|
|
|
176
204
|
case 'fog-end':
|
|
177
205
|
this.fogEnd = parseFloat(newValue);
|
|
178
206
|
break;
|
|
207
|
+
case 'gravity':
|
|
208
|
+
this.gravity = parseVec3(newValue);
|
|
209
|
+
break;
|
|
179
210
|
// ... handle other attributes as well
|
|
180
211
|
}
|
|
181
212
|
}
|