@needle-tools/engine 2.67.6-pre → 2.67.7-pre
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/CHANGELOG.md +9 -0
- package/dist/needle-engine.js +5784 -5766
- package/dist/needle-engine.umd.cjs +83 -83
- package/lib/engine/engine_context.d.ts +170 -0
- package/lib/engine/engine_context.js +855 -0
- package/lib/engine/engine_context.js.map +1 -0
- package/lib/engine/engine_setup.d.ts +1 -166
- package/lib/engine/engine_setup.js +2 -839
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_time.d.ts +2 -0
- package/lib/engine/engine_time.js +4 -1
- package/lib/engine/engine_time.js.map +1 -1
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/ui/Canvas.d.ts +4 -1
- package/lib/engine-components/ui/Canvas.js +17 -1
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +1 -2
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Text.js +4 -0
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/ui/Utils.js +6 -4
- package/lib/engine-components/ui/Utils.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_context.ts +957 -0
- package/src/engine/engine_setup.ts +2 -941
- package/src/engine/engine_time.ts +4 -1
- package/src/engine-components/AnimatorController.ts +2 -2
- package/src/engine-components/ui/Canvas.ts +19 -1
- package/src/engine-components/ui/EventSystem.ts +1 -2
- package/src/engine-components/ui/Text.ts +3 -0
- package/src/engine-components/ui/Utils.ts +6 -4
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
import { Camera, Clock, DepthTexture, PerspectiveCamera, WebGLRenderer, WebGLRenderTarget } from 'three'
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { Input } from './engine_input';
|
|
4
|
+
import { Physics } from './engine_physics';
|
|
5
|
+
import { Time } from './engine_time';
|
|
6
|
+
import { NetworkConnection } from './engine_networking';
|
|
7
|
+
|
|
8
|
+
import * as looputils from './engine_mainloop_utils';
|
|
9
|
+
import * as utils from "./engine_utils";
|
|
10
|
+
|
|
11
|
+
import { EffectComposer, RenderPass } from "postprocessing";
|
|
12
|
+
|
|
13
|
+
import { AssetDatabase } from './engine_assetdatabase';
|
|
14
|
+
|
|
15
|
+
import { logHierarchy } from './engine_three_utils';
|
|
16
|
+
|
|
17
|
+
import * as Stats from 'three/examples/jsm/libs/stats.module';
|
|
18
|
+
import { RendererData } from './engine_rendererdata';
|
|
19
|
+
import { Addressables } from './engine_addressables';
|
|
20
|
+
import { Application } from './engine_application';
|
|
21
|
+
import { LightDataRegistry, ILightDataRegistry } from './engine_lightdata';
|
|
22
|
+
import { PlayerViewManager } from './engine_playerview';
|
|
23
|
+
|
|
24
|
+
import { CoroutineData, ICamera, IComponent, IContext, ILight } from "./engine_types"
|
|
25
|
+
import { destroy, foreachComponent } from './engine_gameobject';
|
|
26
|
+
import { ContextEvent, ContextRegistry } from './engine_context_registry';
|
|
27
|
+
// import { createCameraWithOrbitControl } from '../engine-components/CameraUtils';
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
const debug = utils.getParam("debugSetup");
|
|
31
|
+
const stats = utils.getParam("stats");
|
|
32
|
+
const debugActive = utils.getParam("debugactive");
|
|
33
|
+
const debugframerate = utils.getParam("debugframerate");
|
|
34
|
+
|
|
35
|
+
// this is where functions that setup unity scenes will be pushed into
|
|
36
|
+
// those will be accessed from our custom html element to load them into their context
|
|
37
|
+
export const build_scene_functions: { [name: string]: (context: Context) => Promise<void> } = {};
|
|
38
|
+
|
|
39
|
+
export declare class LoadingProgressArgs {
|
|
40
|
+
name: string;
|
|
41
|
+
progress: ProgressEvent;
|
|
42
|
+
index: number;
|
|
43
|
+
count: number;
|
|
44
|
+
}
|
|
45
|
+
export declare class LoadingOptions {
|
|
46
|
+
progress: (args: LoadingProgressArgs) => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ContextArgs {
|
|
50
|
+
name?: string;
|
|
51
|
+
alias?: string;
|
|
52
|
+
domElement: HTMLElement | null;
|
|
53
|
+
renderer?: THREE.WebGLRenderer = undefined;
|
|
54
|
+
hash?: string;
|
|
55
|
+
|
|
56
|
+
constructor(domElement: HTMLElement | null) {
|
|
57
|
+
this.domElement = domElement ?? document.body;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export enum FrameEvent {
|
|
62
|
+
EarlyUpdate = 0,
|
|
63
|
+
Update = 1,
|
|
64
|
+
LateUpdate = 2,
|
|
65
|
+
OnBeforeRender = 3,
|
|
66
|
+
OnAfterRender = 4,
|
|
67
|
+
PrePhysicsStep = 9,
|
|
68
|
+
PostPhysicsStep = 10,
|
|
69
|
+
Undefined = -1,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export enum XRSessionMode {
|
|
73
|
+
ImmersiveVR = "immersive-vr",
|
|
74
|
+
ImmersiveAR = "immersive-ar",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export declare type OnBeforeRenderCallback = (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, group: THREE.Group) => void
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
export function registerComponent(script: IComponent, context?: Context) {
|
|
81
|
+
if (!script) return;
|
|
82
|
+
const new_scripts = context?.new_scripts ?? Context.Current.new_scripts;
|
|
83
|
+
if (!new_scripts.includes(script)) {
|
|
84
|
+
new_scripts.push(script);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class Context implements IContext {
|
|
89
|
+
|
|
90
|
+
private static _current: Context;
|
|
91
|
+
|
|
92
|
+
static get Current(): Context {
|
|
93
|
+
return this._current;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static set Current(context: Context) {
|
|
97
|
+
ContextRegistry.Current = context;
|
|
98
|
+
this._current = context;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
name: string;
|
|
102
|
+
alias: string | undefined | null;
|
|
103
|
+
isManagedExternally: boolean = false;
|
|
104
|
+
isPaused: boolean = false;
|
|
105
|
+
runInBackground: boolean = false;
|
|
106
|
+
targetFrameRate?: number;
|
|
107
|
+
|
|
108
|
+
/** used to append to loaded assets */
|
|
109
|
+
hash?: string;
|
|
110
|
+
|
|
111
|
+
domElement: HTMLElement;
|
|
112
|
+
get resolutionScaleFactor() { return this._resolutionScaleFactor; }
|
|
113
|
+
/** use to scale the resolution up or down of the renderer. default is 1 */
|
|
114
|
+
set resolutionScaleFactor(val: number) {
|
|
115
|
+
if (val === this._resolutionScaleFactor) return;
|
|
116
|
+
if (typeof val !== "number") return;
|
|
117
|
+
if (val <= 0) {
|
|
118
|
+
console.error("Invalid resolution scale factor", val);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this._resolutionScaleFactor = val;
|
|
122
|
+
this.updateSize();
|
|
123
|
+
}
|
|
124
|
+
private _resolutionScaleFactor: number = 1;
|
|
125
|
+
|
|
126
|
+
// domElement.clientLeft etc doesnt return absolute position
|
|
127
|
+
private _boundingClientRectFrame: number = -1;
|
|
128
|
+
private _boundingClientRect: DOMRect | null = null;
|
|
129
|
+
private _domX; private _domY;
|
|
130
|
+
private calculateBoundingClientRect() {
|
|
131
|
+
// workaround for mozilla webXR viewer
|
|
132
|
+
if (this.isInAR) {
|
|
133
|
+
this._domX = 0;
|
|
134
|
+
this._domY = 0;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (this._boundingClientRectFrame === this.time.frame) return;
|
|
138
|
+
this._boundingClientRectFrame = this.time.frame;
|
|
139
|
+
this._boundingClientRect = this.domElement.getBoundingClientRect();
|
|
140
|
+
this._domX = this._boundingClientRect.x;
|
|
141
|
+
this._domY = this._boundingClientRect.y;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get domWidth(): number {
|
|
145
|
+
// for mozilla XR
|
|
146
|
+
if (this.isInAR) return window.innerWidth;
|
|
147
|
+
return this.domElement.clientWidth;
|
|
148
|
+
}
|
|
149
|
+
get domHeight(): number {
|
|
150
|
+
// for mozilla XR
|
|
151
|
+
if (this.isInAR) return window.innerHeight;
|
|
152
|
+
return this.domElement.clientHeight;
|
|
153
|
+
}
|
|
154
|
+
get domX(): number {
|
|
155
|
+
this.calculateBoundingClientRect();
|
|
156
|
+
return this._domX;
|
|
157
|
+
}
|
|
158
|
+
get domY(): number {
|
|
159
|
+
this.calculateBoundingClientRect();
|
|
160
|
+
return this._domY;
|
|
161
|
+
}
|
|
162
|
+
get isInXR() { return this.renderer.xr?.isPresenting || false; }
|
|
163
|
+
xrSessionMode: XRSessionMode | undefined = undefined;
|
|
164
|
+
get isInVR() { return this.xrSessionMode === XRSessionMode.ImmersiveVR; }
|
|
165
|
+
get isInAR() { return this.xrSessionMode === XRSessionMode.ImmersiveAR; }
|
|
166
|
+
get xrSession() { return this.renderer.xr?.getSession(); }
|
|
167
|
+
get arOverlayElement(): HTMLElement {
|
|
168
|
+
const el = this.domElement as any;
|
|
169
|
+
if (typeof el.getAROverlayContainer === "function")
|
|
170
|
+
return el.getAROverlayContainer();
|
|
171
|
+
return this.domElement;
|
|
172
|
+
}
|
|
173
|
+
/** Current event of the update cycle */
|
|
174
|
+
get currentFrameEvent(): FrameEvent {
|
|
175
|
+
return this._currentFrameEvent;
|
|
176
|
+
}
|
|
177
|
+
private _currentFrameEvent: FrameEvent = FrameEvent.Undefined;
|
|
178
|
+
|
|
179
|
+
scene: THREE.Scene;
|
|
180
|
+
renderer: THREE.WebGLRenderer;
|
|
181
|
+
composer: EffectComposer | null = null;
|
|
182
|
+
|
|
183
|
+
// all scripts
|
|
184
|
+
scripts: IComponent[] = [];
|
|
185
|
+
scripts_pausedChanged: IComponent[] = [];
|
|
186
|
+
// scripts with update event
|
|
187
|
+
scripts_earlyUpdate: IComponent[] = [];
|
|
188
|
+
scripts_update: IComponent[] = [];
|
|
189
|
+
scripts_lateUpdate: IComponent[] = [];
|
|
190
|
+
scripts_onBeforeRender: IComponent[] = [];
|
|
191
|
+
scripts_onAfterRender: IComponent[] = [];
|
|
192
|
+
scripts_WithCorroutines: IComponent[] = [];
|
|
193
|
+
coroutines: { [FrameEvent: number]: Array<CoroutineData> } = {}
|
|
194
|
+
|
|
195
|
+
get mainCamera(): THREE.Camera | null {
|
|
196
|
+
if (this.mainCameraComponent) {
|
|
197
|
+
const cam = this.mainCameraComponent as ICamera;
|
|
198
|
+
if (!cam.cam)
|
|
199
|
+
cam.buildCamera();
|
|
200
|
+
return cam.cam;
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
mainCameraComponent: ICamera | undefined;
|
|
205
|
+
|
|
206
|
+
post_setup_callbacks: Function[] = [];
|
|
207
|
+
pre_update_callbacks: Function[] = [];
|
|
208
|
+
pre_render_callbacks: Function[] = [];
|
|
209
|
+
post_render_callbacks: Function[] = [];
|
|
210
|
+
|
|
211
|
+
new_scripts: IComponent[] = [];
|
|
212
|
+
new_script_start: IComponent[] = [];
|
|
213
|
+
new_scripts_pre_setup_callbacks: Function[] = [];
|
|
214
|
+
new_scripts_post_setup_callbacks: Function[] = [];
|
|
215
|
+
|
|
216
|
+
application: Application;
|
|
217
|
+
time: Time;
|
|
218
|
+
input: Input;
|
|
219
|
+
physics: Physics;
|
|
220
|
+
connection: NetworkConnection;
|
|
221
|
+
/**
|
|
222
|
+
* @deprecated AssetDataBase is deprecated
|
|
223
|
+
*/
|
|
224
|
+
assets: AssetDatabase;
|
|
225
|
+
mainLight: ILight | null = null;
|
|
226
|
+
rendererData: RendererData;
|
|
227
|
+
addressables: Addressables;
|
|
228
|
+
lightmaps: ILightDataRegistry;
|
|
229
|
+
players: PlayerViewManager;
|
|
230
|
+
|
|
231
|
+
get isCreated() { return this._isCreated; }
|
|
232
|
+
|
|
233
|
+
private _sizeChanged: boolean = false;
|
|
234
|
+
private _isCreated: boolean = false;
|
|
235
|
+
private _isVisible: boolean = false;
|
|
236
|
+
|
|
237
|
+
private _stats: Stats.default | null = stats ? Stats.default() : null;
|
|
238
|
+
|
|
239
|
+
constructor(args?: ContextArgs) {
|
|
240
|
+
this.name = args?.name || "";
|
|
241
|
+
this.alias = args?.alias;
|
|
242
|
+
this.domElement = args?.domElement || document.body;
|
|
243
|
+
this.hash = args?.hash;
|
|
244
|
+
if (args?.renderer) {
|
|
245
|
+
this.renderer = args.renderer;
|
|
246
|
+
this.isManagedExternally = true;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.renderer = new WebGLRenderer({
|
|
250
|
+
antialias: true
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// some tonemapping other than "NONE" is required for adjusting exposure with EXR environments
|
|
254
|
+
this.renderer.toneMappingExposure = 1; // range [0...inf] instead of the usual -15..15
|
|
255
|
+
this.renderer.toneMapping = THREE.NoToneMapping; // could also set to LinearToneMapping, ACESFilmicToneMapping
|
|
256
|
+
|
|
257
|
+
this.renderer.setClearColor(new THREE.Color('lightgrey'), 0);
|
|
258
|
+
// @ts-ignore
|
|
259
|
+
this.renderer.antialias = true;
|
|
260
|
+
// @ts-ignore
|
|
261
|
+
this.renderer.alpha = false;
|
|
262
|
+
this.renderer.shadowMap.enabled = true;
|
|
263
|
+
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
264
|
+
this.renderer.setSize(this.domWidth, this.domHeight);
|
|
265
|
+
this.renderer.outputEncoding = THREE.sRGBEncoding;
|
|
266
|
+
this.renderer.physicallyCorrectLights = true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.scene = new THREE.Scene();
|
|
270
|
+
|
|
271
|
+
ContextRegistry.register(this);
|
|
272
|
+
|
|
273
|
+
this.application = new Application(this);
|
|
274
|
+
this.time = new Time();
|
|
275
|
+
this.input = new Input(this);
|
|
276
|
+
this.physics = new Physics(this);
|
|
277
|
+
this.connection = new NetworkConnection(this);
|
|
278
|
+
this.assets = new AssetDatabase();
|
|
279
|
+
this.rendererData = new RendererData(this);
|
|
280
|
+
this.addressables = new Addressables(this);
|
|
281
|
+
this.lightmaps = new LightDataRegistry(this);
|
|
282
|
+
this.players = new PlayerViewManager(this);
|
|
283
|
+
|
|
284
|
+
const resizeCallback = () => this._sizeChanged = true;
|
|
285
|
+
window.addEventListener('resize', resizeCallback);
|
|
286
|
+
this._disposeCallbacks.push(() => window.removeEventListener('resize', resizeCallback));
|
|
287
|
+
|
|
288
|
+
const resizeObserver = new ResizeObserver(_ => this._sizeChanged = true);
|
|
289
|
+
resizeObserver.observe(this.domElement);
|
|
290
|
+
this._disposeCallbacks.push(() => resizeObserver.disconnect());
|
|
291
|
+
|
|
292
|
+
this._intersectionObserver = new IntersectionObserver(entries => {
|
|
293
|
+
this._isVisible = entries[0].isIntersecting;
|
|
294
|
+
});
|
|
295
|
+
this._disposeCallbacks.push(() => this._intersectionObserver?.disconnect());
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
private _intersectionObserver: IntersectionObserver | null = null;
|
|
300
|
+
private internalOnUpdateVisible() {
|
|
301
|
+
this._intersectionObserver?.disconnect();
|
|
302
|
+
this._intersectionObserver?.observe(this.domElement);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private _disposeCallbacks: Function[] = [];
|
|
306
|
+
|
|
307
|
+
// private _requestSizeUpdate : boolean = false;
|
|
308
|
+
|
|
309
|
+
updateSize() {
|
|
310
|
+
if (!this.isManagedExternally && !this.renderer.xr.isPresenting) {
|
|
311
|
+
this._sizeChanged = false;
|
|
312
|
+
const scaleFactor = this.resolutionScaleFactor;
|
|
313
|
+
const width = this.domWidth * scaleFactor;
|
|
314
|
+
const height = this.domHeight * scaleFactor;
|
|
315
|
+
const camera = this.mainCamera as PerspectiveCamera;
|
|
316
|
+
this.updateAspect(camera);
|
|
317
|
+
this.renderer.setSize(width, height);
|
|
318
|
+
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
319
|
+
// avoid setting pixel values here since this can cause pingpong updates
|
|
320
|
+
// e.g. when system scale is set to 125%
|
|
321
|
+
// https://github.com/needle-tools/needle-engine-support/issues/69
|
|
322
|
+
this.renderer.domElement.style.width = "100%";
|
|
323
|
+
this.renderer.domElement.style.height = "100%";
|
|
324
|
+
if (this.composer) {
|
|
325
|
+
this.composer.setSize?.call(this.composer, width, height);
|
|
326
|
+
if ("setPixelRatio" in this.composer && typeof this.composer.setPixelRatio === "function")
|
|
327
|
+
this.composer.setPixelRatio?.call(this.composer, window.devicePixelRatio);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
updateAspect(camera: THREE.PerspectiveCamera, width?: number, height?: number) {
|
|
333
|
+
if (!camera) return;
|
|
334
|
+
if (width === undefined)
|
|
335
|
+
width = this.domWidth;
|
|
336
|
+
if (height === undefined)
|
|
337
|
+
height = this.domHeight;
|
|
338
|
+
const pa = camera.aspect;
|
|
339
|
+
camera.aspect = width / height;
|
|
340
|
+
if (pa !== camera.aspect)
|
|
341
|
+
camera.updateProjectionMatrix();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
onCreate(buildScene?: (context: Context, loadingOptions?: LoadingOptions) => Promise<void>, opts?: LoadingOptions) {
|
|
345
|
+
if (this._isCreated) {
|
|
346
|
+
console.warn("Context already created");
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
this._isCreated = true;
|
|
350
|
+
return this.internalOnCreate(buildScene, opts);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
onDestroy() {
|
|
354
|
+
if (!this._isCreated) return;
|
|
355
|
+
this._isCreated = false;
|
|
356
|
+
destroy(this.scene, true);
|
|
357
|
+
this.renderer?.setAnimationLoop(null);
|
|
358
|
+
if (!this.isManagedExternally) {
|
|
359
|
+
this.renderer?.dispose();
|
|
360
|
+
}
|
|
361
|
+
for (const cb of this._disposeCallbacks) {
|
|
362
|
+
try {
|
|
363
|
+
cb();
|
|
364
|
+
}
|
|
365
|
+
catch (e) {
|
|
366
|
+
console.error("Error in on dispose callback:", e, cb);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (this.domElement?.parentElement) {
|
|
370
|
+
this.domElement.parentElement.removeChild(this.domElement);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
ContextRegistry.dispatchCallback(ContextEvent.ContextDestroyed, this);
|
|
374
|
+
ContextRegistry.unregister(this);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
registerCoroutineUpdate(script: IComponent, coroutine: Generator, evt: FrameEvent): Generator {
|
|
378
|
+
if (!this.coroutines[evt]) this.coroutines[evt] = [];
|
|
379
|
+
this.coroutines[evt].push({ comp: script, main: coroutine });
|
|
380
|
+
return coroutine;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
unregisterCoroutineUpdate(coroutine: Generator, evt: FrameEvent): void {
|
|
384
|
+
if (!this.coroutines[evt]) return;
|
|
385
|
+
const idx = this.coroutines[evt].findIndex(c => c.main === coroutine);
|
|
386
|
+
if (idx >= 0) this.coroutines[evt].splice(idx, 1);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
stopAllCoroutinesFrom(script: IComponent) {
|
|
390
|
+
for (const evt in this.coroutines) {
|
|
391
|
+
const rout: CoroutineData[] = this.coroutines[evt];
|
|
392
|
+
for (let i = rout.length - 1; i >= 0; i--) {
|
|
393
|
+
const r = rout[i];
|
|
394
|
+
if (r.comp === script) {
|
|
395
|
+
rout.splice(i, 1);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private _cameraStack: ICamera[] = [];
|
|
402
|
+
|
|
403
|
+
setCurrentCamera(cam: ICamera) {
|
|
404
|
+
if (!cam) return;
|
|
405
|
+
if (!cam.cam) cam.buildCamera(); // < to build camera
|
|
406
|
+
if (!cam.cam) {
|
|
407
|
+
console.warn("Camera component is missing camera", cam)
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const index = this._cameraStack.indexOf(cam);
|
|
411
|
+
if (index >= 0) this._cameraStack.splice(index, 1);
|
|
412
|
+
this._cameraStack.push(cam);
|
|
413
|
+
this.mainCameraComponent = cam;
|
|
414
|
+
const camera = cam.cam as THREE.PerspectiveCamera;
|
|
415
|
+
if (camera.isPerspectiveCamera)
|
|
416
|
+
this.updateAspect(camera);
|
|
417
|
+
(this.mainCameraComponent as ICamera)?.applyClearFlagsIfIsActiveCamera();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
removeCamera(cam?: ICamera | null) {
|
|
421
|
+
if (!cam) return;
|
|
422
|
+
const index = this._cameraStack.indexOf(cam);
|
|
423
|
+
if (index >= 0) this._cameraStack.splice(index, 1);
|
|
424
|
+
|
|
425
|
+
if (this.mainCameraComponent === cam) {
|
|
426
|
+
this.mainCameraComponent = undefined;
|
|
427
|
+
|
|
428
|
+
if (this._cameraStack.length > 0) {
|
|
429
|
+
const last = this._cameraStack[this._cameraStack.length - 1];
|
|
430
|
+
this.setCurrentCamera(last);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private _onBeforeRenderListeners: { [key: string]: OnBeforeRenderCallback[] } = {};
|
|
436
|
+
|
|
437
|
+
/** use this to subscribe to onBeforeRender events on threejs objects */
|
|
438
|
+
addBeforeRenderListener(target: THREE.Object3D, callback: OnBeforeRenderCallback) {
|
|
439
|
+
if (!this._onBeforeRenderListeners[target.uuid]) {
|
|
440
|
+
this._onBeforeRenderListeners[target.uuid] = [];
|
|
441
|
+
const onBeforeRenderCallback = (renderer, scene, camera, geometry, material, group) => {
|
|
442
|
+
const arr = this._onBeforeRenderListeners[target.uuid];
|
|
443
|
+
if (!arr) return;
|
|
444
|
+
for (let i = 0; i < arr.length; i++) {
|
|
445
|
+
const fn = arr[i];
|
|
446
|
+
fn(renderer, scene, camera, geometry, material, group);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
target.onBeforeRender = onBeforeRenderCallback as any;
|
|
450
|
+
}
|
|
451
|
+
this._onBeforeRenderListeners[target.uuid].push(callback);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
removeBeforeRenderListener(target: THREE.Object3D, callback: OnBeforeRenderCallback) {
|
|
455
|
+
if (this._onBeforeRenderListeners[target.uuid]) {
|
|
456
|
+
const arr = this._onBeforeRenderListeners[target.uuid];
|
|
457
|
+
const idx = arr.indexOf(callback);
|
|
458
|
+
if (idx >= 0) arr.splice(idx, 1);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private _requireDepthTexture: boolean = false;
|
|
463
|
+
private _requireColorTexture: boolean = false;
|
|
464
|
+
private _renderTarget?: WebGLRenderTarget;
|
|
465
|
+
private _isRendering: boolean = false;
|
|
466
|
+
|
|
467
|
+
get isRendering() { return this._isRendering; }
|
|
468
|
+
|
|
469
|
+
setRequireDepth(val: boolean) {
|
|
470
|
+
this._requireDepthTexture = val;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
setRequireColor(val: boolean) {
|
|
474
|
+
this._requireColorTexture = val;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
get depthTexture(): THREE.DepthTexture | null {
|
|
478
|
+
return this._renderTarget?.depthTexture || null;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
get opaqueColorTexture(): THREE.Texture | null {
|
|
482
|
+
return this._renderTarget?.texture || null;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** returns true if the dom element is visible on screen */
|
|
486
|
+
get isVisibleToUser() {
|
|
487
|
+
if (this.isInXR) return true;
|
|
488
|
+
if (!this._isVisible) return false;
|
|
489
|
+
const style = getComputedStyle(this.domElement);
|
|
490
|
+
return style.visibility !== "hidden" && style.display !== "none" && style.opacity !== "0";
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
private async internalOnCreate(buildScene?: (context: Context, opts?: LoadingOptions) => Promise<void>, opts?: LoadingOptions) {
|
|
495
|
+
|
|
496
|
+
// TODO: we could configure if we need physics
|
|
497
|
+
await this.physics.createWorld();
|
|
498
|
+
|
|
499
|
+
// load and create scene
|
|
500
|
+
let prepare_succeeded = true;
|
|
501
|
+
try {
|
|
502
|
+
Context.Current = this;
|
|
503
|
+
if (buildScene)
|
|
504
|
+
await buildScene(this, opts);
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
console.error(err);
|
|
508
|
+
prepare_succeeded = false;
|
|
509
|
+
}
|
|
510
|
+
if (!prepare_succeeded) return;
|
|
511
|
+
|
|
512
|
+
this.internalOnUpdateVisible();
|
|
513
|
+
|
|
514
|
+
// console.log(prepare_succeeded);
|
|
515
|
+
|
|
516
|
+
if (!this.isManagedExternally)
|
|
517
|
+
this.domElement.prepend(this.renderer.domElement);
|
|
518
|
+
|
|
519
|
+
Context._current = this;
|
|
520
|
+
|
|
521
|
+
// Setup
|
|
522
|
+
Context._current = this;
|
|
523
|
+
for (let i = 0; i < this.new_scripts.length; i++) {
|
|
524
|
+
const script = this.new_scripts[i];
|
|
525
|
+
if (script.gameObject !== undefined && script.gameObject !== null) {
|
|
526
|
+
if (script.gameObject.userData === undefined) script.gameObject.userData = {};
|
|
527
|
+
if (script.gameObject.userData.components === undefined) script.gameObject.userData.components = [];
|
|
528
|
+
const arr = script.gameObject.userData.components;
|
|
529
|
+
if (!arr.includes(script)) arr.push(script);
|
|
530
|
+
}
|
|
531
|
+
// if (script.gameObject && !this.raycastTargets.includes(script.gameObject)) {
|
|
532
|
+
// this.raycastTargets.push(script.gameObject);
|
|
533
|
+
// }
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// const context = new SerializationContext(this.scene);
|
|
537
|
+
// for (let i = 0; i < this.new_scripts.length; i++) {
|
|
538
|
+
// const script = this.new_scripts[i];
|
|
539
|
+
// const ser = script as unknown as ISerializable;
|
|
540
|
+
// if (ser.$serializedTypes === undefined) continue;
|
|
541
|
+
// context.context = this;
|
|
542
|
+
// context.object = script.gameObject;
|
|
543
|
+
// deserializeObject(ser, script, context);
|
|
544
|
+
// }
|
|
545
|
+
|
|
546
|
+
// resolve post setup callbacks (things that rely on threejs objects having references to components)
|
|
547
|
+
if (this.post_setup_callbacks) {
|
|
548
|
+
for (let i = 0; i < this.post_setup_callbacks.length; i++) {
|
|
549
|
+
Context._current = this;
|
|
550
|
+
await this.post_setup_callbacks[i](this);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (!this.mainCamera) {
|
|
555
|
+
Context._current = this;
|
|
556
|
+
let camera: ICamera | null = null;
|
|
557
|
+
foreachComponent(this.scene, comp => {
|
|
558
|
+
const cam = comp as ICamera;
|
|
559
|
+
if (cam?.isCamera) {
|
|
560
|
+
looputils.updateActiveInHierarchyWithoutEventCall(cam.gameObject);
|
|
561
|
+
if (!cam.activeAndEnabled) return undefined;
|
|
562
|
+
if (cam.tag === "MainCamera") {
|
|
563
|
+
camera = cam;
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
else camera = cam;
|
|
567
|
+
}
|
|
568
|
+
return undefined;
|
|
569
|
+
});
|
|
570
|
+
if (camera) {
|
|
571
|
+
this.setCurrentCamera(camera);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
ContextRegistry.dispatchCallback(ContextEvent.MissingCamera, this);
|
|
575
|
+
if (!this.mainCamera && !this.isManagedExternally)
|
|
576
|
+
console.error("MISSING camera", this);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
Context._current = this;
|
|
581
|
+
looputils.processNewScripts(this);
|
|
582
|
+
|
|
583
|
+
// const mainCam = this.mainCameraComponent as Camera;
|
|
584
|
+
// if (mainCam) {
|
|
585
|
+
// mainCam.applyClearFlagsIfIsActiveCamera();
|
|
586
|
+
// }
|
|
587
|
+
|
|
588
|
+
if (!this.isManagedExternally && this.composer && this.mainCamera) {
|
|
589
|
+
const renderPass = new RenderPass(this.scene, this.mainCamera);
|
|
590
|
+
this.renderer.setSize(this.domWidth, this.domHeight);
|
|
591
|
+
this.composer.addPass(renderPass);
|
|
592
|
+
this.composer.setSize(this.domWidth, this.domHeight);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
this._sizeChanged = true;
|
|
596
|
+
|
|
597
|
+
if (this._stats) {
|
|
598
|
+
this._stats.showPanel(1);
|
|
599
|
+
this.domElement.appendChild(this._stats.dom);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
this.renderer.setAnimationLoop(this.render.bind(this));
|
|
603
|
+
|
|
604
|
+
if (debug)
|
|
605
|
+
logHierarchy(this.scene, true);
|
|
606
|
+
|
|
607
|
+
ContextRegistry.dispatchCallback(ContextEvent.ContextCreated, this);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private _accumulatedTime = 0;
|
|
611
|
+
private _framerateClock = new Clock();
|
|
612
|
+
|
|
613
|
+
private render(_, frame) {
|
|
614
|
+
|
|
615
|
+
this._currentFrameEvent = FrameEvent.Undefined;
|
|
616
|
+
|
|
617
|
+
if (this.isInXR === false && this.targetFrameRate !== undefined) {
|
|
618
|
+
this._accumulatedTime += this._framerateClock.getDelta();
|
|
619
|
+
if (this._accumulatedTime < (1 / this.targetFrameRate)) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
this._accumulatedTime = 0;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
this._stats?.begin();
|
|
626
|
+
|
|
627
|
+
Context._current = this;
|
|
628
|
+
if (this.onHandlePaused()) return;
|
|
629
|
+
|
|
630
|
+
Context._current = this;
|
|
631
|
+
this.time.update();
|
|
632
|
+
if (debugframerate)
|
|
633
|
+
console.log("FPS", (this.time.smoothedFps).toFixed(0));
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
looputils.processNewScripts(this);
|
|
637
|
+
looputils.updateIsActive(this.scene);
|
|
638
|
+
looputils.processStart(this);
|
|
639
|
+
|
|
640
|
+
while (this._cameraStack.length > 0 && (!this.mainCameraComponent || this.mainCameraComponent.destroyed)) {
|
|
641
|
+
this._cameraStack.splice(this._cameraStack.length - 1, 1);
|
|
642
|
+
const last = this._cameraStack[this._cameraStack.length - 1];
|
|
643
|
+
this.setCurrentCamera(last);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (this.pre_update_callbacks) {
|
|
647
|
+
for (const i in this.pre_update_callbacks) {
|
|
648
|
+
this.pre_update_callbacks[i]();
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
this._currentFrameEvent = FrameEvent.EarlyUpdate;
|
|
653
|
+
|
|
654
|
+
for (let i = 0; i < this.scripts_earlyUpdate.length; i++) {
|
|
655
|
+
const script = this.scripts_earlyUpdate[i];
|
|
656
|
+
if (!script.activeAndEnabled) continue;
|
|
657
|
+
if (script.earlyUpdate !== undefined) {
|
|
658
|
+
Context._current = this;
|
|
659
|
+
script.earlyUpdate();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
this.executeCoroutines(FrameEvent.EarlyUpdate);
|
|
663
|
+
if (this.onHandlePaused()) return;
|
|
664
|
+
|
|
665
|
+
this._currentFrameEvent = FrameEvent.Update;
|
|
666
|
+
|
|
667
|
+
for (let i = 0; i < this.scripts_update.length; i++) {
|
|
668
|
+
const script = this.scripts_update[i];
|
|
669
|
+
if (!script.activeAndEnabled) continue;
|
|
670
|
+
if (script.update !== undefined) {
|
|
671
|
+
Context._current = this;
|
|
672
|
+
script.update();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
this.executeCoroutines(FrameEvent.Update);
|
|
676
|
+
if (this.onHandlePaused()) return;
|
|
677
|
+
|
|
678
|
+
this._currentFrameEvent = FrameEvent.LateUpdate;
|
|
679
|
+
|
|
680
|
+
for (let i = 0; i < this.scripts_lateUpdate.length; i++) {
|
|
681
|
+
const script = this.scripts_lateUpdate[i];
|
|
682
|
+
if (!script.activeAndEnabled) continue;
|
|
683
|
+
if (script.lateUpdate !== undefined) {
|
|
684
|
+
Context._current = this;
|
|
685
|
+
script.lateUpdate();
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// this.mainLight = null;
|
|
690
|
+
this.executeCoroutines(FrameEvent.LateUpdate);
|
|
691
|
+
if (this.onHandlePaused()) return;
|
|
692
|
+
|
|
693
|
+
const physicsSteps = 1;
|
|
694
|
+
const dt = this.time.deltaTime / physicsSteps;
|
|
695
|
+
for (let i = 0; i < physicsSteps; i++) {
|
|
696
|
+
this._currentFrameEvent = FrameEvent.PrePhysicsStep;
|
|
697
|
+
this.executeCoroutines(FrameEvent.PrePhysicsStep);
|
|
698
|
+
this.physics.step(dt);
|
|
699
|
+
this._currentFrameEvent = FrameEvent.PostPhysicsStep;
|
|
700
|
+
this.executeCoroutines(FrameEvent.PostPhysicsStep);
|
|
701
|
+
}
|
|
702
|
+
this.physics.postStep();
|
|
703
|
+
if (this.onHandlePaused()) return;
|
|
704
|
+
|
|
705
|
+
if (this.isVisibleToUser) {
|
|
706
|
+
|
|
707
|
+
this._currentFrameEvent = FrameEvent.OnBeforeRender;
|
|
708
|
+
|
|
709
|
+
// should we move these callbacks in the regular three onBeforeRender events?
|
|
710
|
+
for (let i = 0; i < this.scripts_onBeforeRender.length; i++) {
|
|
711
|
+
const script = this.scripts_onBeforeRender[i];
|
|
712
|
+
if (!script.activeAndEnabled) continue;
|
|
713
|
+
// if(script.isActiveAndEnabled === false) continue;
|
|
714
|
+
if (script.onBeforeRender !== undefined) {
|
|
715
|
+
Context._current = this;
|
|
716
|
+
script.onBeforeRender(frame);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
this.executeCoroutines(FrameEvent.OnBeforeRender);
|
|
721
|
+
|
|
722
|
+
if (this._sizeChanged)
|
|
723
|
+
this.updateSize();
|
|
724
|
+
|
|
725
|
+
if (this.pre_render_callbacks) {
|
|
726
|
+
for (const i in this.pre_render_callbacks) {
|
|
727
|
+
this.pre_render_callbacks[i]();
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
if (!this.isManagedExternally) {
|
|
733
|
+
looputils.runPrewarm(this);
|
|
734
|
+
this._currentFrameEvent = FrameEvent.Undefined;
|
|
735
|
+
this.renderNow();
|
|
736
|
+
this._currentFrameEvent = FrameEvent.OnAfterRender;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
for (let i = 0; i < this.scripts_onAfterRender.length; i++) {
|
|
741
|
+
const script = this.scripts_onAfterRender[i];
|
|
742
|
+
if (!script.activeAndEnabled) continue;
|
|
743
|
+
if (script.onAfterRender !== undefined) {
|
|
744
|
+
Context._current = this;
|
|
745
|
+
script.onAfterRender();
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
this.executeCoroutines(FrameEvent.OnAfterRender);
|
|
750
|
+
|
|
751
|
+
if (this.post_render_callbacks) {
|
|
752
|
+
for (const i in this.post_render_callbacks) {
|
|
753
|
+
this.post_render_callbacks[i]();
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
this._currentFrameEvent = -1;
|
|
759
|
+
|
|
760
|
+
this.connection.sendBufferedMessagesNow();
|
|
761
|
+
|
|
762
|
+
this._stats?.end();
|
|
763
|
+
|
|
764
|
+
if (this.time.frame === 1) {
|
|
765
|
+
this.domElement.dispatchEvent(new CustomEvent("ready"));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
renderNow(camera?: Camera) {
|
|
770
|
+
if (!camera) {
|
|
771
|
+
camera = this.mainCamera as Camera;
|
|
772
|
+
if (!camera) return false;
|
|
773
|
+
}
|
|
774
|
+
this._isRendering = true;
|
|
775
|
+
this.renderRequiredTextures();
|
|
776
|
+
// if (camera === this.mainCameraComponent?.cam) {
|
|
777
|
+
// if (this.mainCameraComponent.activeTexture) {
|
|
778
|
+
|
|
779
|
+
// }
|
|
780
|
+
// }
|
|
781
|
+
if (this.composer && !this.isInXR) {
|
|
782
|
+
this.composer.render(this.time.deltaTime);
|
|
783
|
+
}
|
|
784
|
+
else if (camera) {
|
|
785
|
+
this.renderer.render(this.scene, camera);
|
|
786
|
+
}
|
|
787
|
+
this._isRendering = false;
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** returns true if we should return out of the frame loop */
|
|
792
|
+
private _wasPaused: boolean = false;
|
|
793
|
+
private onHandlePaused(): boolean {
|
|
794
|
+
const paused = this.evaluatePaused();
|
|
795
|
+
if (this._wasPaused !== paused) {
|
|
796
|
+
if (debugActive) console.log("Paused?", paused, "context:" + this.alias);
|
|
797
|
+
for (let i = 0; i < this.scripts_pausedChanged.length; i++) {
|
|
798
|
+
const script = this.scripts_pausedChanged[i];
|
|
799
|
+
if (!script.activeAndEnabled) continue;
|
|
800
|
+
if (script.onPausedChanged !== undefined) {
|
|
801
|
+
Context._current = this;
|
|
802
|
+
script.onPausedChanged(paused, this._wasPaused);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
this._wasPaused = paused;
|
|
807
|
+
return paused;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
private evaluatePaused(): boolean {
|
|
811
|
+
if (this.isInXR) return false;
|
|
812
|
+
if (this.isPaused) return true;
|
|
813
|
+
// if the element is not visible use the runInBackground flag to determine if we should continue
|
|
814
|
+
if (this.runInBackground) {
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
const paused = !this.isVisibleToUser;
|
|
818
|
+
return paused;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
private renderRequiredTextures() {
|
|
822
|
+
if (!this.mainCamera) return;
|
|
823
|
+
if (!this._requireDepthTexture && !this._requireColorTexture) return;
|
|
824
|
+
if (!this._renderTarget) {
|
|
825
|
+
this._renderTarget = new THREE.WebGLRenderTarget(this.domWidth, this.domHeight);
|
|
826
|
+
if (this._requireDepthTexture) {
|
|
827
|
+
const dt = new DepthTexture(this.domWidth, this.domHeight);;
|
|
828
|
+
this._renderTarget.depthTexture = dt;
|
|
829
|
+
}
|
|
830
|
+
if (this._requireColorTexture) {
|
|
831
|
+
this._renderTarget.texture = new THREE.Texture();
|
|
832
|
+
this._renderTarget.texture.generateMipmaps = false;
|
|
833
|
+
this._renderTarget.texture.minFilter = THREE.NearestFilter;
|
|
834
|
+
this._renderTarget.texture.magFilter = THREE.NearestFilter;
|
|
835
|
+
this._renderTarget.texture.format = THREE.RGBAFormat;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
const rt = this._renderTarget;
|
|
839
|
+
if (rt.texture) {
|
|
840
|
+
rt.texture.encoding = this.renderer.outputEncoding;
|
|
841
|
+
}
|
|
842
|
+
const prevTarget = this.renderer.getRenderTarget();
|
|
843
|
+
this.renderer.setRenderTarget(rt);
|
|
844
|
+
this.renderer.render(this.scene, this.mainCamera);
|
|
845
|
+
this.renderer.setRenderTarget(prevTarget);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
private executeCoroutines(evt: FrameEvent) {
|
|
849
|
+
if (this.coroutines[evt]) {
|
|
850
|
+
const evts = this.coroutines[evt];
|
|
851
|
+
for (let i = 0; i < evts.length; i++) {
|
|
852
|
+
try {
|
|
853
|
+
const evt = evts[i];
|
|
854
|
+
// TODO we might want to keep coroutines playing even if the component is disabled or inactive
|
|
855
|
+
const remove = !evt.comp || evt.comp.destroyed || !evt.main || evt.comp["enabled"] === false;
|
|
856
|
+
if (remove) {
|
|
857
|
+
evts.splice(i, 1);
|
|
858
|
+
--i;
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
const iter = evt.chained;
|
|
862
|
+
if (iter && iter.length > 0) {
|
|
863
|
+
const last: Generator = iter[iter.length - 1];
|
|
864
|
+
const res = last.next();
|
|
865
|
+
if (res.done) {
|
|
866
|
+
iter.pop();
|
|
867
|
+
}
|
|
868
|
+
if (isGenerator(res)) {
|
|
869
|
+
if (!evt.chained) evt.chained = [];
|
|
870
|
+
evt.chained.push(res.value);
|
|
871
|
+
}
|
|
872
|
+
if (!res.done) continue;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const res = evt.main.next();
|
|
876
|
+
if (res.done === true) {
|
|
877
|
+
evts.splice(i, 1);
|
|
878
|
+
--i;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
const val = res.value;
|
|
882
|
+
if (isGenerator(val)) {
|
|
883
|
+
// invoke once if its a generator
|
|
884
|
+
// this means e.g. WaitForFrame(1) works and will capture
|
|
885
|
+
// the frame it was created
|
|
886
|
+
const gen = val as Generator;
|
|
887
|
+
const res = gen.next();
|
|
888
|
+
if (res.done) continue;
|
|
889
|
+
if (!evt.chained) evt.chained = [];
|
|
890
|
+
evt.chained.push(val as Generator);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
catch (e) {
|
|
894
|
+
console.error(e);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function isGenerator(val: any): boolean {
|
|
900
|
+
if (val) {
|
|
901
|
+
if (val.next && val.return) {
|
|
902
|
+
return true;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return false;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
// const scene = new THREE.Scene();
|
|
913
|
+
// const useComposer = utils.getParam("postfx");
|
|
914
|
+
// const renderer = new WebGLRenderer({ antialias: true });
|
|
915
|
+
// const composer = useComposer ? new EffectComposer(renderer) : undefined;
|
|
916
|
+
|
|
917
|
+
// renderer.setClearColor(new THREE.Color('lightgrey'), 0)
|
|
918
|
+
// renderer.antialias = true;
|
|
919
|
+
// renderer.alpha = false;
|
|
920
|
+
// renderer.shadowMap.enabled = true;
|
|
921
|
+
// renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
922
|
+
// renderer.setSize(window.innerWidth, window.innerHeight);
|
|
923
|
+
// renderer.outputEncoding = THREE.sRGBEncoding;
|
|
924
|
+
// renderer.physicallyCorrectLights = true;
|
|
925
|
+
// document.body.appendChild(renderer.domElement);
|
|
926
|
+
|
|
927
|
+
// // generation pushes loading requests in this array
|
|
928
|
+
// const sceneData: {
|
|
929
|
+
// mainCamera: THREE.Camera | undefined
|
|
930
|
+
// } = {
|
|
931
|
+
// preparing: [],
|
|
932
|
+
// resolving: [],
|
|
933
|
+
// scripts: [],
|
|
934
|
+
// raycastTargets: [],
|
|
935
|
+
// mainCamera: undefined,
|
|
936
|
+
// mainCameraComponent: undefined,
|
|
937
|
+
// };
|
|
938
|
+
|
|
939
|
+
// // contains a list of functions to be called after loading is done
|
|
940
|
+
// const post_setup_callbacks = [];
|
|
941
|
+
|
|
942
|
+
// const pre_render_Callbacks = [];
|
|
943
|
+
// const post_render_callbacks = [];
|
|
944
|
+
|
|
945
|
+
// const new_scripts = [];
|
|
946
|
+
// const new_scripts_post_setup_callbacks = [];
|
|
947
|
+
// const new_scripts_pre_setup_callbacks = [];
|
|
948
|
+
|
|
949
|
+
// export {
|
|
950
|
+
// scene, renderer, composer,
|
|
951
|
+
// new_scripts,
|
|
952
|
+
// new_scripts_post_setup_callbacks, new_scripts_pre_setup_callbacks,
|
|
953
|
+
// sceneData,
|
|
954
|
+
// post_setup_callbacks,
|
|
955
|
+
// pre_render_Callbacks,
|
|
956
|
+
// post_render_callbacks
|
|
957
|
+
// }
|