@p100-web/core-three 100.0.63 → 100.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/dist/App.d.ts +40 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/App.js +171 -0
  4. package/dist/App.js.map +1 -0
  5. package/dist/ComponentFactory.d.ts +5 -0
  6. package/dist/ComponentFactory.d.ts.map +1 -0
  7. package/dist/ComponentFactory.js +17 -0
  8. package/dist/ComponentFactory.js.map +1 -0
  9. package/dist/PCanvas.d.ts +171 -0
  10. package/dist/PCanvas.d.ts.map +1 -0
  11. package/dist/PCanvas.js +992 -0
  12. package/dist/PCanvas.js.map +1 -0
  13. package/dist/ThreeEngine.d.ts +25 -0
  14. package/dist/ThreeEngine.d.ts.map +1 -0
  15. package/dist/ThreeEngine.js +102 -0
  16. package/dist/ThreeEngine.js.map +1 -0
  17. package/dist/ThreeNodeRenderer.d.ts +32 -0
  18. package/dist/ThreeNodeRenderer.d.ts.map +1 -0
  19. package/dist/ThreeNodeRenderer.js +87 -0
  20. package/dist/ThreeNodeRenderer.js.map +1 -0
  21. package/dist/index.d.ts +7 -7
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +7 -7
  24. package/dist/index.js.map +1 -1
  25. package/dist/media/AudioLoader.d.ts +32 -0
  26. package/dist/media/AudioLoader.d.ts.map +1 -0
  27. package/dist/media/AudioLoader.js +110 -0
  28. package/dist/media/AudioLoader.js.map +1 -0
  29. package/dist/media/EnvironmentLoader.d.ts +40 -0
  30. package/dist/media/EnvironmentLoader.d.ts.map +1 -0
  31. package/dist/media/EnvironmentLoader.js +120 -0
  32. package/dist/media/EnvironmentLoader.js.map +1 -0
  33. package/dist/media/ImageLoader.d.ts +36 -0
  34. package/dist/media/ImageLoader.d.ts.map +1 -0
  35. package/dist/media/ImageLoader.js +160 -0
  36. package/dist/media/ImageLoader.js.map +1 -0
  37. package/dist/media/MediaLoader.d.ts +14 -0
  38. package/dist/media/MediaLoader.d.ts.map +1 -0
  39. package/dist/media/MediaLoader.js +70 -0
  40. package/dist/media/MediaLoader.js.map +1 -0
  41. package/dist/media/ModelLoader.d.ts +49 -0
  42. package/dist/media/ModelLoader.d.ts.map +1 -0
  43. package/dist/media/ModelLoader.js +223 -0
  44. package/dist/media/ModelLoader.js.map +1 -0
  45. package/dist/media/VideoLoader.d.ts +35 -0
  46. package/dist/media/VideoLoader.d.ts.map +1 -0
  47. package/dist/media/VideoLoader.js +105 -0
  48. package/dist/media/VideoLoader.js.map +1 -0
  49. package/dist/pcomponents/PAnimator.d.ts +24 -0
  50. package/dist/pcomponents/PAnimator.d.ts.map +1 -0
  51. package/dist/pcomponents/PAnimator.js +129 -0
  52. package/dist/pcomponents/PAnimator.js.map +1 -0
  53. package/dist/pcomponents/PBasicMaterial.d.ts +17 -0
  54. package/dist/pcomponents/PBasicMaterial.d.ts.map +1 -0
  55. package/dist/pcomponents/PBasicMaterial.js +142 -0
  56. package/dist/pcomponents/PBasicMaterial.js.map +1 -0
  57. package/dist/pcomponents/PCollider.d.ts +11 -0
  58. package/dist/pcomponents/PCollider.d.ts.map +1 -0
  59. package/dist/pcomponents/PCollider.js +61 -0
  60. package/dist/pcomponents/PCollider.js.map +1 -0
  61. package/dist/pcomponents/PCubeGeometry.d.ts +8 -0
  62. package/dist/pcomponents/PCubeGeometry.d.ts.map +1 -0
  63. package/dist/pcomponents/PCubeGeometry.js +23 -0
  64. package/dist/pcomponents/PCubeGeometry.js.map +1 -0
  65. package/dist/pcomponents/PEnvironment.d.ts +14 -0
  66. package/dist/pcomponents/PEnvironment.d.ts.map +1 -0
  67. package/dist/pcomponents/PEnvironment.js +86 -0
  68. package/dist/pcomponents/PEnvironment.js.map +1 -0
  69. package/dist/pcomponents/PImageBackground.d.ts +14 -0
  70. package/dist/pcomponents/PImageBackground.d.ts.map +1 -0
  71. package/dist/pcomponents/PImageBackground.js +85 -0
  72. package/dist/pcomponents/PImageBackground.js.map +1 -0
  73. package/dist/pcomponents/PLight.d.ts +8 -0
  74. package/dist/pcomponents/PLight.d.ts.map +1 -0
  75. package/dist/pcomponents/PLight.js +22 -0
  76. package/dist/pcomponents/PLight.js.map +1 -0
  77. package/dist/pcomponents/PLightDirectional.d.ts +8 -0
  78. package/dist/pcomponents/PLightDirectional.d.ts.map +1 -0
  79. package/dist/pcomponents/PLightDirectional.js +36 -0
  80. package/dist/pcomponents/PLightDirectional.js.map +1 -0
  81. package/dist/pcomponents/PMaskedMaterial.d.ts +17 -0
  82. package/dist/pcomponents/PMaskedMaterial.d.ts.map +1 -0
  83. package/dist/pcomponents/PMaskedMaterial.js +214 -0
  84. package/dist/pcomponents/PMaskedMaterial.js.map +1 -0
  85. package/dist/pcomponents/PModelGLTF.d.ts +18 -0
  86. package/dist/pcomponents/PModelGLTF.d.ts.map +1 -0
  87. package/dist/pcomponents/PModelGLTF.js +98 -0
  88. package/dist/pcomponents/PModelGLTF.js.map +1 -0
  89. package/dist/pcomponents/PPhysicalMaterial.d.ts +13 -0
  90. package/dist/pcomponents/PPhysicalMaterial.d.ts.map +1 -0
  91. package/dist/pcomponents/PPhysicalMaterial.js +106 -0
  92. package/dist/pcomponents/PPhysicalMaterial.js.map +1 -0
  93. package/dist/pcomponents/PPlaneGeometry.d.ts +8 -0
  94. package/dist/pcomponents/PPlaneGeometry.d.ts.map +1 -0
  95. package/dist/pcomponents/PPlaneGeometry.js +23 -0
  96. package/dist/pcomponents/PPlaneGeometry.js.map +1 -0
  97. package/dist/pcomponents/PProjectRoot.d.ts +8 -0
  98. package/dist/pcomponents/PProjectRoot.d.ts.map +1 -0
  99. package/dist/pcomponents/PProjectRoot.js +24 -0
  100. package/dist/pcomponents/PProjectRoot.js.map +1 -0
  101. package/dist/pcomponents/PSlider.d.ts +16 -0
  102. package/dist/pcomponents/PSlider.d.ts.map +1 -0
  103. package/dist/pcomponents/PSlider.js +69 -0
  104. package/dist/pcomponents/PSlider.js.map +1 -0
  105. package/dist/pcomponents/PSound.d.ts +17 -0
  106. package/dist/pcomponents/PSound.d.ts.map +1 -0
  107. package/dist/pcomponents/PSound.js +110 -0
  108. package/dist/pcomponents/PSound.js.map +1 -0
  109. package/dist/pcomponents/PSphereGeometry.d.ts +9 -0
  110. package/dist/pcomponents/PSphereGeometry.d.ts.map +1 -0
  111. package/dist/pcomponents/PSphereGeometry.js +24 -0
  112. package/dist/pcomponents/PSphereGeometry.js.map +1 -0
  113. package/dist/pcomponents/PSprite.d.ts +14 -0
  114. package/dist/pcomponents/PSprite.d.ts.map +1 -0
  115. package/dist/pcomponents/PSprite.js +79 -0
  116. package/dist/pcomponents/PSprite.js.map +1 -0
  117. package/dist/pcomponents/PSpriteAnimation.d.ts +15 -0
  118. package/dist/pcomponents/PSpriteAnimation.d.ts.map +1 -0
  119. package/dist/pcomponents/PSpriteAnimation.js +80 -0
  120. package/dist/pcomponents/PSpriteAnimation.js.map +1 -0
  121. package/dist/pcomponents/PText.d.ts +10 -0
  122. package/dist/pcomponents/PText.d.ts.map +1 -0
  123. package/dist/pcomponents/PText.js +44 -0
  124. package/dist/pcomponents/PText.js.map +1 -0
  125. package/dist/pcomponents/PVideoBackground.d.ts +13 -0
  126. package/dist/pcomponents/PVideoBackground.d.ts.map +1 -0
  127. package/dist/pcomponents/PVideoBackground.js +85 -0
  128. package/dist/pcomponents/PVideoBackground.js.map +1 -0
  129. package/dist/pcomponents/PVideoPlayer.d.ts +5 -0
  130. package/dist/pcomponents/PVideoPlayer.d.ts.map +1 -0
  131. package/dist/pcomponents/PVideoPlayer.js +12 -0
  132. package/dist/pcomponents/PVideoPlayer.js.map +1 -0
  133. package/dist/pcomponents.d.ts +21 -21
  134. package/dist/pcomponents.d.ts.map +1 -1
  135. package/dist/pcomponents.js +21 -21
  136. package/dist/pcomponents.js.map +1 -1
  137. package/dist/postprocessing/PSSRPass.d.ts +19 -0
  138. package/dist/postprocessing/PSSRPass.d.ts.map +1 -0
  139. package/dist/postprocessing/PSSRPass.js +69 -0
  140. package/dist/postprocessing/PSSRPass.js.map +1 -0
  141. package/dist/postprocessing/ThreeJsPostProcessor.d.ts +32 -0
  142. package/dist/postprocessing/ThreeJsPostProcessor.d.ts.map +1 -0
  143. package/dist/postprocessing/ThreeJsPostProcessor.js +264 -0
  144. package/dist/postprocessing/ThreeJsPostProcessor.js.map +1 -0
  145. package/dist/three/ColliderObject3D.d.ts +19 -0
  146. package/dist/three/ColliderObject3D.d.ts.map +1 -0
  147. package/dist/three/ColliderObject3D.js +146 -0
  148. package/dist/three/ColliderObject3D.js.map +1 -0
  149. package/dist/three/FreeCameraControls.d.ts +30 -0
  150. package/dist/three/FreeCameraControls.d.ts.map +1 -0
  151. package/dist/three/FreeCameraControls.js +158 -0
  152. package/dist/three/FreeCameraControls.js.map +1 -0
  153. package/dist/three/OrbitCameraControls.d.ts +24 -0
  154. package/dist/three/OrbitCameraControls.d.ts.map +1 -0
  155. package/dist/three/OrbitCameraControls.js +81 -0
  156. package/dist/three/OrbitCameraControls.js.map +1 -0
  157. package/dist/three/VrCameraControls.d.ts +28 -0
  158. package/dist/three/VrCameraControls.d.ts.map +1 -0
  159. package/dist/three/VrCameraControls.js +124 -0
  160. package/dist/three/VrCameraControls.js.map +1 -0
  161. package/package.json +9 -4
  162. package/index.ts +0 -14
@@ -0,0 +1,992 @@
1
+ import { Clock, Color, PerspectiveCamera, Raycaster, Scene, Vector2, WebGLRenderer, Group, MathUtils, SRGBColorSpace, } from "three";
2
+ import { Group as TweenGroup } from "@tweenjs/tween.js";
3
+ import ThreeJsPostProcessor from "./postprocessing/ThreeJsPostProcessor";
4
+ import { PEvent, PostProcessingSystems, Workers, AdaptivePerformance, } from "@p100-web/core";
5
+ const _pointer = new Vector2(-1000, -1000);
6
+ const _size = new Vector2(0, 0);
7
+ let _offset = 0;
8
+ const _cameraColor = new Color(0x000000);
9
+ const SLEEP_INTERVAL = 600;
10
+ export default class PCanvas {
11
+ constructor(context) {
12
+ this._disposed = true;
13
+ this._canvas = null;
14
+ this._renderer = null;
15
+ this._controls = null;
16
+ // PP
17
+ this._composer = null;
18
+ this._updates = [];
19
+ this._clock = new Clock();
20
+ this._tweens = new TweenGroup();
21
+ this._startHoverId = null;
22
+ this._backgroundColor = new Color(0x000000);
23
+ this._cameraUpdate = null;
24
+ this._hoverCanvas = false;
25
+ this._hoverWindow = false;
26
+ this._isAdmin = false;
27
+ //
28
+ // BACKGROUND / ENVIRONMENT
29
+ //
30
+ this._environment = null;
31
+ //
32
+ // EXTERNAL EVENTS
33
+ //
34
+ this.onExternalEvent = (e) => {
35
+ const event = this.context.getExternalEvent(e.detail.name);
36
+ if (event) {
37
+ if (PEvent.Debug) {
38
+ console.log("<[EXTERNAL IN-EVENT]> [" +
39
+ event.name +
40
+ "] [" +
41
+ e.detail.payload +
42
+ "]");
43
+ }
44
+ event.emit(e.detail.payload);
45
+ }
46
+ else {
47
+ this.context.error("Event not found");
48
+ }
49
+ };
50
+ this.onMouseEnter = (_event) => {
51
+ this._hoverCanvas = true;
52
+ this.updateHoverState();
53
+ };
54
+ this.onMouseExit = (_event) => {
55
+ this._hoverCanvas = false;
56
+ this.updateHoverState();
57
+ };
58
+ //
59
+ // STATS
60
+ //
61
+ this._stats = null;
62
+ //
63
+ // MOUSE
64
+ //
65
+ /**
66
+ * Event callback when mouse moves.
67
+ */
68
+ this.onMouseMove = (event) => {
69
+ _pointer.x = ((event.clientX - _offset) / _size.x) * 2 - 1;
70
+ _pointer.y = -(event.clientY / _size.y) * 2 + 1;
71
+ if (!this._hoverWindow)
72
+ this.onWindowEnter();
73
+ if (!this._hoverCanvas)
74
+ this.onMouseEnter(event);
75
+ };
76
+ this._wasDown = false;
77
+ /**
78
+ * User pressed down on canvas
79
+ */
80
+ this.onCanvasClickDown = (e) => {
81
+ e.preventDefault();
82
+ this._wasDown = true;
83
+ if (e.button === 0 && this._isRaycasting) {
84
+ if (this.hovered) {
85
+ this._startHoverId = this.hovered.id;
86
+ }
87
+ }
88
+ };
89
+ /**
90
+ * User pressed up on canvas
91
+ */
92
+ this.onCanvasClickUp = (e) => {
93
+ if (!this._wasDown) {
94
+ return;
95
+ }
96
+ this._wasDown = false;
97
+ e.preventDefault();
98
+ if (e.button === 0 && this._isRaycasting) {
99
+ const hovered = this.hovered && this.hovered.id === this._startHoverId
100
+ ? this.hovered
101
+ : null;
102
+ if (!this._editor && hovered)
103
+ hovered.collider?.native_onClick();
104
+ this.context.onClick(hovered, e.ctrlKey || e.metaKey, e.shiftKey);
105
+ }
106
+ this._startHoverId = null;
107
+ };
108
+ //
109
+ // RENDER LOOP
110
+ //
111
+ this._hasUpdators = false;
112
+ // Keep track of ongoing animations
113
+ this._hasTweens = false;
114
+ //
115
+ // Sleeping
116
+ //
117
+ this._isSleeping = false;
118
+ this._isSleepEnabled = false;
119
+ this._isHoveringAdmin = false;
120
+ this.onWindowHide = () => {
121
+ this._performanceCounter?.pause();
122
+ };
123
+ this.onWindowEnter = () => {
124
+ this._hoverWindow = true;
125
+ this.updateHoverState();
126
+ };
127
+ this.onWindowExit = () => {
128
+ this._hoverWindow = false;
129
+ this.updateHoverState();
130
+ };
131
+ //
132
+ // SETTINGS
133
+ //
134
+ this._debug = false;
135
+ //
136
+ // QUALITY
137
+ //
138
+ this._renderScale = 1;
139
+ // private _isInteracting = false;
140
+ // private _interactiveReduction = false;
141
+ this._maxScale = 1;
142
+ this._minScale = 1;
143
+ this._adaptiveQuality = false;
144
+ this._estimating = false;
145
+ this._baseQuality = 100;
146
+ this._currentQuality = -100;
147
+ this._estimatedQuality = 0;
148
+ this._performanceCounter = null;
149
+ //_skipFrameActive - true if we are currently dropping frames
150
+ this._skipFrameActive = false;
151
+ this.onPerformanceEstimated = (quality, fps, estimating) => {
152
+ // console.log(
153
+ // "onPerformanceEstimated() document.hidden:",
154
+ // document.hidden,
155
+ // quality,
156
+ // Math.round(fps),
157
+ // estimating
158
+ // );
159
+ this._estimatedQuality = quality;
160
+ // Should we change quality level?
161
+ if (this._adaptiveQuality) {
162
+ // Did we stop estimating?
163
+ if (estimating === false && this._estimating) {
164
+ this.context.clearWorkFlag(Workers.AdaptivePerformance);
165
+ if (this._debug)
166
+ console.log("[PCanvas] onPerformanceEstimated() STOPPED", Math.round(fps), quality);
167
+ }
168
+ else if (estimating && !this._estimating) {
169
+ this.context.setWorkFlag(Workers.AdaptivePerformance);
170
+ if (this._debug)
171
+ console.log("[PCanvas] onPerformanceEstimated() STARTED", Math.round(fps), quality);
172
+ }
173
+ if (!this._skipFrameActive && quality <= 75 && fps < 50) {
174
+ this.setSkipFrameActive(true);
175
+ this.setQuality(100);
176
+ }
177
+ else if (this._currentQuality !== quality) {
178
+ this.setQuality(quality);
179
+ }
180
+ this._estimating = estimating;
181
+ }
182
+ this.snooze();
183
+ };
184
+ //
185
+ // WORKER/INTERACTION
186
+ //
187
+ this._isWorking = false;
188
+ this._isSceneRunning = false;
189
+ //
190
+ // UPDATE
191
+ //
192
+ this._renderCounter = 0;
193
+ this._renderInterval = 2;
194
+ this.update = () => {
195
+ if (this._disposed) {
196
+ console.log("<<<<<<<<< DISPOSED >>>>>>>>>>>");
197
+ return;
198
+ }
199
+ if (this._hasTweens) {
200
+ this._tweens.update();
201
+ if (this._tweens.allStopped()) {
202
+ this._tweens.removeAll();
203
+ this._hasTweens = false;
204
+ this.context.clearWorkFlag(Workers.Animating);
205
+ }
206
+ }
207
+ if (this._cameraUpdate)
208
+ this._cameraUpdate();
209
+ const delta = this._clock.getDelta();
210
+ if (this._hasUpdators) {
211
+ for (const update of this._updates) {
212
+ update(delta);
213
+ }
214
+ }
215
+ if (this._isRaycasting) {
216
+ this.raycast();
217
+ }
218
+ this._stats?.update(delta);
219
+ if (this._renderCounter >= this._renderInterval) {
220
+ if (this._composer)
221
+ this._composer.render();
222
+ else
223
+ this._renderer.render(this._sceneNode, this._cameraNode);
224
+ this._renderCounter = 0;
225
+ }
226
+ if (!this._isSleeping) {
227
+ this._performanceCounter?.update(delta);
228
+ }
229
+ this._renderCounter++;
230
+ };
231
+ //
232
+ // RAYCASTER
233
+ //
234
+ this._isRaycasting = false;
235
+ this._editor = false;
236
+ this.hovered = null;
237
+ this.colliders = [];
238
+ this.context = context;
239
+ this._isAdmin = context.isAdmin();
240
+ // Create a Scene
241
+ const scene = new Scene();
242
+ this._sceneNode = scene;
243
+ this._sceneNode.background = _cameraColor;
244
+ // Create a Camera
245
+ const cameraNode = new PerspectiveCamera(70, 1280 / 720, 0.1, 6);
246
+ this._cameraNode = cameraNode;
247
+ this._cameraNode.layers.mask = 1;
248
+ this._raycaster = new Raycaster();
249
+ this._raycaster.layers.mask = 2;
250
+ // Add root node
251
+ const rootNode = new Group();
252
+ this._rootNode = rootNode;
253
+ // Add nodes to scene
254
+ rootNode.add(cameraNode);
255
+ scene.add(rootNode);
256
+ }
257
+ render(canvas, width, height, settings) {
258
+ if (this._disposed === false)
259
+ throw new Error("PCanvas was already rendered");
260
+ if (canvas.dataset.rendered)
261
+ throw new Error("The canvas was disposed, create a new");
262
+ this._disposed = false;
263
+ this._cameraNode.near = settings.renderer.near;
264
+ this._cameraNode.far = settings.renderer.far;
265
+ const rendererArgs = settings.postProcessing?.enabled === PostProcessingSystems.THREEJS
266
+ ? {
267
+ powerPreference: "high-performance",
268
+ antialias: false,
269
+ stencil: settings.renderer.stencil,
270
+ depth: false,
271
+ }
272
+ : {
273
+ powerPreference: "high-performance",
274
+ antialias: settings.renderer.antialias,
275
+ stencil: settings.renderer.stencil,
276
+ depth: settings.renderer.depth,
277
+ };
278
+ const renderer = new WebGLRenderer({
279
+ ...rendererArgs,
280
+ canvas: canvas,
281
+ });
282
+ renderer.outputColorSpace = SRGBColorSpace;
283
+ _size.x = width;
284
+ _size.y = height;
285
+ this._renderer = renderer;
286
+ this._canvas = canvas;
287
+ // if (settings.postProcessing?.enabled === PostProcessingSystems.PMNDRS) {
288
+ // renderer.toneMapping = NoToneMapping;
289
+ // } else {
290
+ renderer.toneMapping = settings.renderer.toneMapping;
291
+ renderer.toneMappingExposure = settings.renderer.toneMappingExposure;
292
+ // }
293
+ this.setupShadows(settings.renderer.useShadows);
294
+ renderer.setSize(_size.x, _size.y, true);
295
+ renderer.setClearColor(_cameraColor);
296
+ renderer.clear();
297
+ if (settings.postProcessing?.enabled === PostProcessingSystems.THREEJS) {
298
+ this.setupPostProcessing(settings.postProcessing);
299
+ }
300
+ if (!this._cameraNode)
301
+ throw new Error("Missing camera");
302
+ this._cameraNode.aspect = width / height;
303
+ this._cameraNode.updateProjectionMatrix();
304
+ document.addEventListener("mouseenter", this.onWindowEnter);
305
+ document.addEventListener("mouseleave", this.onWindowExit);
306
+ document.addEventListener("visibilitychange", this.onWindowHide);
307
+ canvas.addEventListener("pointermove", this.onMouseMove);
308
+ canvas.addEventListener("mouseenter", this.onMouseEnter);
309
+ canvas.addEventListener("mouseleave", this.onMouseExit);
310
+ canvas.addEventListener("pointerdown", this.onCanvasClickDown);
311
+ canvas.addEventListener("pointerup", this.onCanvasClickUp);
312
+ canvas.addEventListener("p100-in-event", this.onExternalEvent);
313
+ this.startRenderLoop();
314
+ }
315
+ /**
316
+ * Should be called after render() and restore()
317
+ */
318
+ init(settings) {
319
+ // Set FOV
320
+ this.setFOV(settings.renderer.fov);
321
+ this._cameraNode.fov = settings.renderer.fov;
322
+ this._cameraNode.updateProjectionMatrix();
323
+ // Set background color
324
+ this.setBackgroundColor(settings.renderer.background);
325
+ // Work quality
326
+ if (settings.quality) {
327
+ this.initQualitySettings(settings.quality);
328
+ }
329
+ }
330
+ restore(canvas, settings) {
331
+ this.render(canvas, _size.width, _size.height, settings);
332
+ }
333
+ disable() { }
334
+ dispose() {
335
+ // console.log("[PCanvas] DISPOSE()");
336
+ if (this._disposed === true)
337
+ throw new Error("PCanvas was already disposed");
338
+ this.stopRenderLoop();
339
+ this._disposed = true;
340
+ if (this._adaptiveQuality) {
341
+ this._performanceCounter?.dispose();
342
+ this.context.clearWorkFlag(Workers.AdaptivePerformance);
343
+ }
344
+ if (this._controls) {
345
+ this._controls.dispose();
346
+ this._controls = null;
347
+ }
348
+ const renderer = this._renderer;
349
+ const canvas = this._canvas;
350
+ if (!canvas)
351
+ throw new Error("Missing canvas");
352
+ document.removeEventListener("mouseenter", this.onWindowEnter);
353
+ document.removeEventListener("mouseleave", this.onWindowExit);
354
+ document.removeEventListener("visibilitychange", this.onWindowHide);
355
+ canvas.removeEventListener("pointermove", this.onMouseMove);
356
+ canvas.removeEventListener("mouseenter", this.onMouseEnter);
357
+ canvas.removeEventListener("mouseleave", this.onMouseExit);
358
+ canvas.removeEventListener("pointerdown", this.onCanvasClickDown);
359
+ canvas.removeEventListener("pointerup", this.onCanvasClickUp);
360
+ canvas.removeEventListener("p100-in-event", this.onExternalEvent);
361
+ canvas.dataset.rendered = "true";
362
+ if (this._composer !== null) {
363
+ this._composer.dispose();
364
+ }
365
+ renderer.dispose();
366
+ renderer.forceContextLoss();
367
+ this._renderer = null;
368
+ this._composer?.dispose();
369
+ this._composer = null;
370
+ }
371
+ enable() {
372
+ if (this._renderer) {
373
+ // this._renderer.shadowMap.needsUpdate = true;
374
+ }
375
+ }
376
+ getComposer() {
377
+ return this._composer;
378
+ }
379
+ getEnvironment() {
380
+ return this._environment;
381
+ }
382
+ setEnvironment(environment) {
383
+ if (this._environment !== null) {
384
+ this.context.error("Already had an environment");
385
+ return;
386
+ }
387
+ this._environment = environment;
388
+ this.updateEnvironment();
389
+ }
390
+ updateEnvironment() {
391
+ if (this._environment === null) {
392
+ }
393
+ else {
394
+ const scene = this._sceneNode;
395
+ if (this._environment.environment) {
396
+ scene.environment = this._environment.getTexture();
397
+ scene.environmentRotation.y = MathUtils.degToRad(180 + this._environment.rotation);
398
+ scene.environmentIntensity = this._environment.intensity;
399
+ }
400
+ else if (scene.environment === this._environment.getTexture()) {
401
+ scene.environment = null;
402
+ }
403
+ if (this._environment.background) {
404
+ scene.background = this._environment.getTexture();
405
+ scene.backgroundRotation.y = MathUtils.degToRad(180 + this._environment.rotation);
406
+ scene.backgroundIntensity = this._environment.intensity;
407
+ }
408
+ else if (scene.background === this._environment.getTexture()) {
409
+ scene.background = null;
410
+ scene.background = this._backgroundColor;
411
+ }
412
+ }
413
+ }
414
+ setBackgroundColor(bg) {
415
+ this._backgroundColor = new Color(bg);
416
+ const current = this._sceneNode.background;
417
+ if (current && current.isColor) {
418
+ this._sceneNode.background = this._backgroundColor;
419
+ }
420
+ }
421
+ clearEnvironment(environment) {
422
+ const scene = this._sceneNode;
423
+ if (this._environment !== environment) {
424
+ this.context.error("Clear environment called with invalid PEnvironment");
425
+ return;
426
+ }
427
+ if (this._environment === null) {
428
+ this.context.error("No environtment");
429
+ return;
430
+ }
431
+ if (this._environment.environment) {
432
+ scene.environment = null;
433
+ }
434
+ if (this._environment.background) {
435
+ scene.background = null;
436
+ scene.background = this._backgroundColor;
437
+ }
438
+ this._environment = null;
439
+ }
440
+ //
441
+ // RENDERER
442
+ //
443
+ setToneMapping(value) {
444
+ this._renderer.toneMapping = value;
445
+ }
446
+ setToneMappingExposure(value) {
447
+ this._renderer.toneMappingExposure = value;
448
+ }
449
+ setFOV(fov) {
450
+ this._cameraNode.fov = fov;
451
+ this._cameraNode.updateProjectionMatrix();
452
+ }
453
+ setNearFar(near = -1, far = -1) {
454
+ if (near > 0)
455
+ this._cameraNode.near = near;
456
+ if (far > 0)
457
+ this._cameraNode.far = far;
458
+ this._cameraNode.updateProjectionMatrix();
459
+ }
460
+ //
461
+ // SHADOWS
462
+ //
463
+ setupShadows(value) {
464
+ const renderer = this._renderer;
465
+ if (value > 0) {
466
+ // Enable
467
+ renderer.shadowMap.autoUpdate = false;
468
+ console.log("TODO: manual shadows");
469
+ renderer.shadowMap.enabled = true;
470
+ renderer.shadowMap.type = (value - 1);
471
+ renderer.shadowMap.needsUpdate = true;
472
+ }
473
+ else {
474
+ // Disable
475
+ renderer.shadowMap.enabled = false;
476
+ renderer.shadowMap.needsUpdate = true;
477
+ renderer.shadowMap.autoUpdate = false;
478
+ }
479
+ renderer.clear();
480
+ }
481
+ //
482
+ // CONTROLS
483
+ //
484
+ getCameraNode() {
485
+ return this._cameraNode;
486
+ }
487
+ setCameraControls(controls) {
488
+ if (this._controls) {
489
+ this._controls.dispose();
490
+ }
491
+ this._controls = controls;
492
+ }
493
+ getCameraControls() {
494
+ return this._controls;
495
+ }
496
+ //
497
+ // POST PROCESSING
498
+ //
499
+ setupPostProcessing(settings) {
500
+ // if (settings.enabled === PostProcessingSystems.PMNDRS) {
501
+ // // this._composer = new PmndrsPostProcessor(
502
+ // // settings,
503
+ // // this._sceneNode,
504
+ // // this._renderer!,
505
+ // // this._cameraNode,
506
+ // // _size
507
+ // // );
508
+ // } else if (settings.enabled === PostProcessingSystems.THREEJS) {
509
+ this._composer = new ThreeJsPostProcessor(settings, this._sceneNode, this._renderer, this._cameraNode, _size);
510
+ // }
511
+ }
512
+ /**
513
+ * Base settings has changed for post processing
514
+ */
515
+ updatePostProcessingSettings(field, settings) {
516
+ if (this._composer === null)
517
+ return;
518
+ // Note: If we are updating all, then we will restart the context really soon
519
+ if (field === "postProcessing.samples") {
520
+ this._composer.updateAASamples(settings.samples);
521
+ }
522
+ else {
523
+ const needsResize = this._composer?.updatePostProcessing(settings, field);
524
+ if (needsResize) {
525
+ this._composer.resizeEffects();
526
+ }
527
+ }
528
+ }
529
+ //
530
+ // DOM
531
+ //
532
+ /**
533
+ * Helper function to trigger events
534
+ */
535
+ emit(type, detail, bubbles) {
536
+ if (this._canvas !== null) {
537
+ this._canvas.dispatchEvent(new CustomEvent(type, {
538
+ bubbles: bubbles,
539
+ detail: detail,
540
+ }));
541
+ }
542
+ }
543
+ /**
544
+ * Add <canvas/> event listener
545
+ */
546
+ addEventListener(type, callback) {
547
+ this._canvas.addEventListener(type, callback);
548
+ }
549
+ /**
550
+ * Add <canvas/> event listener
551
+ */
552
+ removeEventListener(type, callback) {
553
+ this._canvas.removeEventListener(type, callback);
554
+ }
555
+ registerStats(updator) {
556
+ this._stats = updator;
557
+ }
558
+ //
559
+ // WINDOW
560
+ //
561
+ /**
562
+ * Return mouse position
563
+ */
564
+ getPointer() {
565
+ return this._hoverCanvas ? _pointer : null;
566
+ }
567
+ getSize() {
568
+ return _size;
569
+ }
570
+ onWindowResize(width, height, resize) {
571
+ if (this._canvas) {
572
+ _offset = this._canvas.getBoundingClientRect().x;
573
+ }
574
+ _size.x = width;
575
+ _size.y = height;
576
+ this._renderer?.setSize(width, height, true);
577
+ if (this._composer !== null) {
578
+ if (resize)
579
+ this._composer.resize(width, height);
580
+ else
581
+ this._composer.setSize(width, height);
582
+ }
583
+ this.snooze();
584
+ if (this._cameraNode !== null) {
585
+ this._cameraNode.aspect = width / height;
586
+ this._cameraNode.updateProjectionMatrix();
587
+ }
588
+ if (this._isSleepEnabled) {
589
+ this._renderCounter = this._currentQuality;
590
+ }
591
+ }
592
+ //
593
+ // THREE NODES
594
+ //
595
+ getThreeSceneNode() {
596
+ return this._sceneNode;
597
+ }
598
+ getThreeRenderer() {
599
+ return this._renderer;
600
+ }
601
+ getCanvasElement() {
602
+ return this._canvas;
603
+ }
604
+ getThreeRootNode() {
605
+ return this._rootNode;
606
+ }
607
+ getThreeCamera() {
608
+ return this._cameraNode;
609
+ }
610
+ registerUpdate(f) {
611
+ const oldCount = this._updates.length;
612
+ this._updates = [...this._updates, f];
613
+ this._hasUpdators = this._updates.length > 0;
614
+ if (oldCount === 0 && this._hasUpdators) {
615
+ this.context.setWorkFlag(Workers.Updators);
616
+ }
617
+ }
618
+ unregisterUpdate(f) {
619
+ this._updates = this._updates.filter((u) => u !== f);
620
+ this._hasUpdators = this._updates.length > 0;
621
+ if (!this._hasUpdators) {
622
+ this.context.clearWorkFlag(Workers.Updators);
623
+ }
624
+ }
625
+ startRenderLoop() {
626
+ if (!this._renderer)
627
+ throw new Error("No renderer");
628
+ // Start rendering
629
+ this._renderer.setAnimationLoop(this.update);
630
+ }
631
+ stopRenderLoop() {
632
+ if (!this._renderer)
633
+ throw new Error("No renderer");
634
+ // Stop rendering
635
+ this._renderer.setAnimationLoop(null);
636
+ }
637
+ addTween(tween) {
638
+ const didHaveTweens = this._hasTweens;
639
+ this._hasTweens = true;
640
+ this._tweens.add(tween);
641
+ if (!didHaveTweens && this._hasTweens) {
642
+ this.context.setWorkFlag(Workers.Animating);
643
+ }
644
+ }
645
+ setCameraUpdate(updateFunction) {
646
+ this._cameraUpdate = updateFunction;
647
+ }
648
+ updateHoverState() {
649
+ const isHoveringAdmin = this._isAdmin && this._hoverWindow && !this._hoverCanvas;
650
+ if (isHoveringAdmin !== this._isHoveringAdmin) {
651
+ if (isHoveringAdmin) {
652
+ this._isHoveringAdmin = true;
653
+ this.context.setWorkFlag(Workers.Admin);
654
+ }
655
+ else {
656
+ this._isHoveringAdmin = false;
657
+ this.context.clearWorkFlag(Workers.Admin);
658
+ }
659
+ }
660
+ }
661
+ isSleepEnabled() {
662
+ return this._isSleepEnabled;
663
+ }
664
+ setIsSleepEnabled(value) {
665
+ if (this._isSceneRunning)
666
+ this._renderInterval = this._skipFrameActive ? 2 : 1;
667
+ this._isSleepEnabled = value;
668
+ this.updateHoverState();
669
+ if (!value) {
670
+ this._isSleeping = false;
671
+ this.context.getOwner().setSleepState(false);
672
+ }
673
+ }
674
+ snooze() {
675
+ this._renderCounter = this._renderInterval;
676
+ }
677
+ updateRendererSettings(field, isettings) {
678
+ const settings = isettings.renderer;
679
+ if (field === "renderer" || field === "renderer.fov") {
680
+ this.setFOV(settings.fov);
681
+ }
682
+ if (field === "renderer" ||
683
+ field === "renderer.near" ||
684
+ field === "renderer.far") {
685
+ this.setNearFar(settings.near, settings.far);
686
+ }
687
+ if (field === "renderer" || field === "renderer.toneMapping") {
688
+ this.setToneMapping(settings.toneMapping);
689
+ }
690
+ if (field === "renderer" || field === "renderer.toneMappingExposure") {
691
+ this.setToneMappingExposure(settings.toneMappingExposure);
692
+ }
693
+ }
694
+ updateQualitySettings(field, isettings) {
695
+ const settings = isettings.quality;
696
+ if (field === "quality" || field === "quality.sleep") {
697
+ this.setIsSleepEnabled(settings.sleep);
698
+ }
699
+ if (field === "quality" || field === "quality.adaptive") {
700
+ this.setIsAdaptiveQualityEnabled(settings);
701
+ this.updateSkipFrameState(settings);
702
+ }
703
+ if (field === "quality" || field === "quality.minScale") {
704
+ this._minScale = settings.minScale;
705
+ this.updateRenderScale(false);
706
+ }
707
+ if (field === "quality" || field === "quality.maxScale") {
708
+ this._maxScale = settings.maxScale;
709
+ this.updateRenderScale(false);
710
+ }
711
+ if (field === "quality" || field === "quality.baseQuality") {
712
+ this._baseQuality = settings.baseQuality;
713
+ if (!this._adaptiveQuality) {
714
+ this._estimatedQuality = this._baseQuality;
715
+ }
716
+ this.setQuality(this._baseQuality);
717
+ }
718
+ if (field === "quality" || field === "quality.skipFrame") {
719
+ this.updateSkipFrameState(settings);
720
+ }
721
+ if (field === "quality" || field === "quality.debug") {
722
+ this._debug = settings.debug;
723
+ if (this._performanceCounter)
724
+ this._performanceCounter.debug = settings.debug;
725
+ }
726
+ }
727
+ initQualitySettings(settings) {
728
+ this.setIsSleepEnabled(settings.sleep);
729
+ this._maxScale = settings.maxScale;
730
+ this._minScale = settings.minScale;
731
+ this._baseQuality = settings.baseQuality;
732
+ this._debug = settings.debug;
733
+ this.setIsAdaptiveQualityEnabled(settings);
734
+ this.updateSkipFrameState(settings);
735
+ }
736
+ getRenderScale() {
737
+ return this._renderScale;
738
+ }
739
+ getCurrentQuality() {
740
+ return this._currentQuality;
741
+ }
742
+ getEstimatedQuality() {
743
+ return this._estimatedQuality;
744
+ }
745
+ getRenderInterval() {
746
+ return this._renderInterval;
747
+ }
748
+ updateSkipFrameState(settings) {
749
+ // Skip frame is automatically handled if we are in adaptive mode
750
+ if (this._adaptiveQuality) {
751
+ // Adaptive Quality
752
+ this._skipFrameActive = false;
753
+ if (this._isSceneRunning)
754
+ this._renderInterval = 1;
755
+ }
756
+ else {
757
+ // Manual Quality
758
+ this.setSkipFrameActive(settings.skipFrame);
759
+ }
760
+ }
761
+ setSkipFrameActive(value) {
762
+ if (value) {
763
+ // Turn on
764
+ this._skipFrameActive = true;
765
+ if (this._isSceneRunning)
766
+ this._renderInterval = 2;
767
+ if (this._debug)
768
+ console.log("[PCanvas] Skip Frame ON", this._renderInterval);
769
+ }
770
+ else {
771
+ this._skipFrameActive = false;
772
+ if (this._isSceneRunning)
773
+ this._renderInterval = 1;
774
+ // Turn off
775
+ if (this._debug)
776
+ console.log("[PCanvas] Skip Frame OFF", this._renderInterval);
777
+ }
778
+ }
779
+ setIsAdaptiveQualityEnabled(settings) {
780
+ this._adaptiveQuality = settings.adaptive;
781
+ this._estimating = this._adaptiveQuality;
782
+ if (settings.adaptive) {
783
+ this._estimatedQuality = 100;
784
+ this.setQuality(this._estimatedQuality);
785
+ this._performanceCounter = new AdaptivePerformance(this.onPerformanceEstimated);
786
+ this._performanceCounter.debug = settings.debug;
787
+ this.context.setWorkFlag(Workers.AdaptivePerformance);
788
+ if (this._isSceneRunning) {
789
+ this._performanceCounter.init(this._currentQuality);
790
+ }
791
+ }
792
+ else {
793
+ this._performanceCounter?.dispose();
794
+ this._performanceCounter = null;
795
+ this._estimatedQuality = this._baseQuality;
796
+ this.setQuality(this._baseQuality);
797
+ this.context.clearWorkFlag(Workers.AdaptivePerformance);
798
+ }
799
+ }
800
+ /**
801
+ * Quality is always clamped to steps of 0.05
802
+ */
803
+ setQuality(quality) {
804
+ if (this._currentQuality !== quality) {
805
+ this._performanceCounter?.setCurrentQuality(quality);
806
+ this._currentQuality = quality;
807
+ //
808
+ // POST PROCESSING
809
+ const resizePostProcessing = this._composer?.setCurrentQuality(quality) || false;
810
+ //
811
+ // RENDER SCALE
812
+ this.updateRenderScale(resizePostProcessing);
813
+ }
814
+ }
815
+ updateRenderScale(forced) {
816
+ const qualityScale = MathUtils.lerp(this._minScale, this._maxScale, this._currentQuality * 0.01);
817
+ const newScale = Math.min(Math.max(qualityScale, this._minScale), this._maxScale);
818
+ const resizePixelRatio = Math.abs(this._renderScale - newScale) >= 0.01;
819
+ if (forced || resizePixelRatio) {
820
+ if (resizePixelRatio) {
821
+ // console.log(
822
+ // "[PCanvas] Change PixelRatio [",
823
+ // this._renderScale.toFixed(2),
824
+ // "] -> [",
825
+ // newScale.toFixed(2),
826
+ // "]"
827
+ // );
828
+ this._renderScale = newScale;
829
+ }
830
+ if (this._composer) {
831
+ this._composer.setPixelRatio(this._renderScale);
832
+ this.snooze();
833
+ }
834
+ else {
835
+ this._renderer.setPixelRatio(this._renderScale);
836
+ this.snooze();
837
+ }
838
+ }
839
+ }
840
+ onSceneRunning() {
841
+ if (this._debug)
842
+ console.log("[PCanvas] onSceneRunning()");
843
+ this._isSceneRunning = true;
844
+ this._renderInterval = this._skipFrameActive ? 2 : 1;
845
+ if (this._adaptiveQuality) {
846
+ this._performanceCounter.init(this._currentQuality);
847
+ }
848
+ else {
849
+ this.sleepCheck();
850
+ }
851
+ }
852
+ onWorkStarted(_workers) {
853
+ this._isWorking = true;
854
+ // if (this._debug)
855
+ // console.log("[PCanvas] onWorkStarted()", Workers[_workers]);
856
+ if (this._isSleepEnabled && this._isSleeping) {
857
+ this._isSleeping = false;
858
+ this._renderInterval = this._skipFrameActive ? 2 : 1;
859
+ this.setQuality(this._estimatedQuality);
860
+ this.context.getOwner().setSleepState(false);
861
+ }
862
+ }
863
+ onWorkStopped(_workers) {
864
+ this._isWorking = false;
865
+ // if (this._debug)
866
+ // console.log("[PCanvas] onWorkStopped: ", Workers[_workers]);
867
+ // Do we need to change sleep state?
868
+ this.sleepCheck();
869
+ }
870
+ sleepCheck() {
871
+ if (this._isSleepEnabled && !this._isSleeping && !this._isWorking) {
872
+ this.sleep();
873
+ }
874
+ }
875
+ sleep() {
876
+ // if (this._debug) console.log("[PCanvas] sleep()");
877
+ // This will force one last render
878
+ this._isSleeping = true;
879
+ this._renderInterval = SLEEP_INTERVAL;
880
+ this.setQuality(Math.min(100, this._estimatedQuality + 50));
881
+ this.context.getOwner().setSleepState(true);
882
+ this.snooze();
883
+ }
884
+ addCollider(object) {
885
+ this.colliders.push(object);
886
+ }
887
+ removeCollider(object) {
888
+ const index = this.colliders.indexOf(object);
889
+ if (index >= 0) {
890
+ this.colliders.splice(index, 1);
891
+ }
892
+ }
893
+ getRaycaster() {
894
+ return this._raycaster;
895
+ }
896
+ enableRaycaster() {
897
+ this._isRaycasting = true;
898
+ this.hovered = null;
899
+ this._startHoverId = null;
900
+ if (!this._rootNode) {
901
+ console.error("Warning: no root node!");
902
+ }
903
+ }
904
+ disableRaycaster() {
905
+ this._isRaycasting = false;
906
+ this._startHoverId = null;
907
+ if (this.hovered) {
908
+ // console.log("disableRaycaster() while hovered");
909
+ this.setHovered(null, null);
910
+ }
911
+ }
912
+ updateEditorMode(editor) {
913
+ this._editor = editor;
914
+ }
915
+ raycast() {
916
+ const raycaster = this._raycaster;
917
+ // Get pointer, null if outside canvas
918
+ const pointer = this.getPointer();
919
+ if (pointer !== null) {
920
+ raycaster.setFromCamera(pointer, this._cameraNode);
921
+ const intersects = raycaster.intersectObjects(this.colliders, false);
922
+ this.onHover(intersects.length > 0 ? intersects : null);
923
+ }
924
+ else {
925
+ this.onHover(null);
926
+ }
927
+ }
928
+ /**
929
+ * Set current hovered object.
930
+ */
931
+ setHovered(node, point) {
932
+ const hovered = this.hovered;
933
+ if (node === null) {
934
+ // Skip if nothing is hovered
935
+ if (hovered === null) {
936
+ return;
937
+ }
938
+ this.snooze();
939
+ this.hovered = null;
940
+ // EventSystem.emit("hover-exit", hovered.id, hovered.id, DataType.Node);
941
+ this.context.onHoverExit(hovered);
942
+ if (!this._editor) {
943
+ hovered.collider?.native_onHoverExit();
944
+ }
945
+ }
946
+ else {
947
+ // Skip if already hovered
948
+ if (hovered === node) {
949
+ // if (!this._editor && node.collider?.native_onHover) {
950
+ // node.collider.native_onHover(point);
951
+ // }
952
+ return;
953
+ }
954
+ this.snooze();
955
+ // Did we have something hovered?
956
+ if (hovered) {
957
+ this.setHovered(null, null);
958
+ }
959
+ this.hovered = node;
960
+ this.context.onHoverEnter(node);
961
+ if (!this._editor) {
962
+ this.hovered?.collider?.native_onHoverEnter(point);
963
+ }
964
+ }
965
+ }
966
+ /**
967
+ * User hovers collider
968
+ */
969
+ onHover(intersects) {
970
+ let object3D = null;
971
+ let distance = 999999;
972
+ let point = null;
973
+ if (intersects !== null) {
974
+ for (const intersect of intersects) {
975
+ // Check that we hover a valid target
976
+ if (intersect.object.visible && intersect.distance < distance) {
977
+ object3D = intersect.object;
978
+ distance = intersect.distance;
979
+ point = intersect.point;
980
+ }
981
+ }
982
+ }
983
+ if (object3D === null) {
984
+ this.setHovered(null, null);
985
+ return;
986
+ }
987
+ const collider = object3D.collider || object3D.userData.collider;
988
+ if (collider)
989
+ this.setHovered(collider.node, point);
990
+ }
991
+ }
992
+ //# sourceMappingURL=PCanvas.js.map