lunchboxjs 0.2.1016 → 0.2.1018
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lunchboxjs.js +309 -499
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +306 -493
- package/package.json +6 -3
- package/src/index.ts +7 -2
- package/extras/Gltf.vue +0 -34
- package/extras/OrbitControlsWrapper.vue +0 -39
package/dist/lunchboxjs.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Lunchbox = {}, global.vue, global.three));
|
|
5
5
|
})(this, (function (exports, vue, THREE) { 'use strict';
|
|
6
6
|
|
|
7
|
-
function
|
|
8
|
-
if (e && e.__esModule) return e;
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
9
8
|
var n = Object.create(null);
|
|
10
9
|
if (e) {
|
|
11
10
|
Object.keys(e).forEach(function (k) {
|
|
@@ -18,41 +17,38 @@
|
|
|
18
17
|
}
|
|
19
18
|
});
|
|
20
19
|
}
|
|
21
|
-
n
|
|
20
|
+
n.default = e;
|
|
22
21
|
return Object.freeze(n);
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
var THREE__namespace = /*#__PURE__*/
|
|
24
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
26
25
|
|
|
27
26
|
function find(target) {
|
|
28
|
-
target = vue.isRef(target) ? target.value : target;
|
|
29
|
-
|
|
27
|
+
target = vue.isRef(target) ? target.value : target;
|
|
28
|
+
// handle standard lunchbox node
|
|
30
29
|
if (isLunchboxStandardNode(target)) {
|
|
31
30
|
return target?.instance;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
}
|
|
32
|
+
// handle component
|
|
35
33
|
if (isLunchboxComponent(target)) {
|
|
36
34
|
return target?.$el?.instance;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
}
|
|
36
|
+
// handle vnode
|
|
40
37
|
if (vue.isVNode(target)) {
|
|
41
38
|
return target.el?.instance;
|
|
42
39
|
}
|
|
43
|
-
|
|
44
40
|
return null;
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
const get = (obj, path, defValue) => {
|
|
48
44
|
// If path is not defined or it has false value
|
|
49
|
-
if (!path) return undefined;
|
|
45
|
+
if (!path) return undefined;
|
|
46
|
+
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
|
|
50
47
|
// Regex explained: https://regexr.com/58j0k
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g);
|
|
49
|
+
// Find value
|
|
50
|
+
const result = pathArray?.reduce((prevObj, key) => prevObj && prevObj[key], obj);
|
|
51
|
+
// If found value is undefined return default value; otherwise return the value
|
|
56
52
|
return result === undefined ? defValue : result;
|
|
57
53
|
};
|
|
58
54
|
|
|
@@ -65,18 +61,15 @@
|
|
|
65
61
|
* Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
|
66
62
|
* Available under MIT license <https://lodash.com/license>
|
|
67
63
|
*/
|
|
68
|
-
|
|
69
64
|
/** `Object#toString` result references. */
|
|
70
65
|
const numberTag = '[object Number]';
|
|
71
66
|
/** Used for built-in method references. */
|
|
72
|
-
|
|
73
67
|
const objectProto = Object.prototype;
|
|
74
68
|
/**
|
|
75
69
|
* Used to resolve the
|
|
76
70
|
* [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
|
|
77
71
|
* of values.
|
|
78
72
|
*/
|
|
79
|
-
|
|
80
73
|
const objectToString = objectProto.toString;
|
|
81
74
|
/**
|
|
82
75
|
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
|
@@ -102,7 +95,6 @@
|
|
|
102
95
|
* _.isObjectLike(null);
|
|
103
96
|
* // => false
|
|
104
97
|
*/
|
|
105
|
-
|
|
106
98
|
function isObjectLike(value) {
|
|
107
99
|
return !!value && typeof value == 'object';
|
|
108
100
|
}
|
|
@@ -132,15 +124,11 @@
|
|
|
132
124
|
* _.isNumber('3');
|
|
133
125
|
* // => false
|
|
134
126
|
*/
|
|
135
|
-
|
|
136
|
-
|
|
137
127
|
const output = function isNumber(value) {
|
|
138
128
|
return typeof value == 'number' || isObjectLike(value) && objectToString.call(value) == numberTag;
|
|
139
129
|
};
|
|
140
|
-
|
|
141
130
|
return output;
|
|
142
131
|
};
|
|
143
|
-
|
|
144
132
|
const isNumber = buildIsNumber();
|
|
145
133
|
|
|
146
134
|
const set = (obj, path, value) => {
|
|
@@ -153,10 +141,11 @@
|
|
|
153
141
|
}, obj);
|
|
154
142
|
};
|
|
155
143
|
|
|
144
|
+
// MAKE SURE THESE MATCH VALUES IN types.EventKey
|
|
156
145
|
/** Type check on whether target is a Lunchbox.EventKey */
|
|
157
|
-
|
|
158
146
|
const isEventKey = target => {
|
|
159
|
-
return ['onClick', 'onContextMenu', 'onDoubleClick', 'onPointerUp', 'onPointerDown', 'onPointerOver', 'onPointerOut', 'onPointerEnter', 'onPointerLeave', 'onPointerMove',
|
|
147
|
+
return ['onClick', 'onContextMenu', 'onDoubleClick', 'onPointerUp', 'onPointerDown', 'onPointerOver', 'onPointerOut', 'onPointerEnter', 'onPointerLeave', 'onPointerMove',
|
|
148
|
+
// 'onPointerMissed',
|
|
160
149
|
// 'onUpdate',
|
|
161
150
|
'onWheel'].includes(target);
|
|
162
151
|
};
|
|
@@ -175,61 +164,61 @@
|
|
|
175
164
|
};
|
|
176
165
|
|
|
177
166
|
/** Create a new Lunchbox comment node. */
|
|
178
|
-
|
|
179
167
|
function createCommentNode(options = {}) {
|
|
180
168
|
const defaults = {
|
|
181
169
|
text: options.text ?? ''
|
|
182
170
|
};
|
|
183
|
-
return new exports.MiniDom.RendererCommentNode({
|
|
171
|
+
return new exports.MiniDom.RendererCommentNode({
|
|
172
|
+
...defaults,
|
|
184
173
|
...options,
|
|
185
174
|
metaType: 'commentMeta'
|
|
186
175
|
});
|
|
187
176
|
}
|
|
188
177
|
/** Create a new DOM node. */
|
|
189
|
-
|
|
190
178
|
function createDomNode(options = {}) {
|
|
191
179
|
const domElement = document.createElement(options.type ?? '');
|
|
192
180
|
const defaults = {
|
|
193
181
|
domElement
|
|
194
182
|
};
|
|
195
|
-
const node = new exports.MiniDom.RendererDomNode({
|
|
183
|
+
const node = new exports.MiniDom.RendererDomNode({
|
|
184
|
+
...defaults,
|
|
196
185
|
...options,
|
|
197
186
|
metaType: 'domMeta'
|
|
198
187
|
});
|
|
199
188
|
return node;
|
|
200
189
|
}
|
|
201
190
|
/** Create a new Lunchbox text node. */
|
|
202
|
-
|
|
203
191
|
function createTextNode(options = {}) {
|
|
204
192
|
const defaults = {
|
|
205
193
|
text: options.text ?? ''
|
|
206
194
|
};
|
|
207
|
-
return new exports.MiniDom.RendererTextNode({
|
|
195
|
+
return new exports.MiniDom.RendererTextNode({
|
|
196
|
+
...options,
|
|
208
197
|
...defaults,
|
|
209
198
|
metaType: 'textMeta'
|
|
210
199
|
});
|
|
211
200
|
}
|
|
212
201
|
/** Create a new Lunchbox standard node. */
|
|
213
|
-
|
|
214
202
|
function createNode(options = {}, props = {}) {
|
|
215
203
|
const defaults = {
|
|
216
204
|
attached: options.attached ?? [],
|
|
217
205
|
attachedArray: options.attachedArray ?? {},
|
|
218
206
|
instance: options.instance ?? null
|
|
219
207
|
};
|
|
220
|
-
const node = new exports.MiniDom.RendererStandardNode({
|
|
208
|
+
const node = new exports.MiniDom.RendererStandardNode({
|
|
209
|
+
...options,
|
|
221
210
|
...defaults,
|
|
222
211
|
metaType: 'standardMeta'
|
|
223
212
|
});
|
|
224
|
-
|
|
225
213
|
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
226
|
-
node.instance = instantiateThreeObject({
|
|
227
|
-
|
|
214
|
+
node.instance = instantiateThreeObject({
|
|
215
|
+
...node,
|
|
216
|
+
props: {
|
|
217
|
+
...node.props,
|
|
228
218
|
...props
|
|
229
219
|
}
|
|
230
220
|
});
|
|
231
221
|
}
|
|
232
|
-
|
|
233
222
|
return node;
|
|
234
223
|
}
|
|
235
224
|
|
|
@@ -244,14 +233,12 @@
|
|
|
244
233
|
if (!node.eventListeners[key]) {
|
|
245
234
|
node.eventListeners[key] = [];
|
|
246
235
|
}
|
|
247
|
-
|
|
248
236
|
if (!node.eventListenerRemoveFunctions[key]) {
|
|
249
237
|
node.eventListenerRemoveFunctions[key] = [];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
238
|
+
}
|
|
239
|
+
// add event listener
|
|
240
|
+
node.eventListeners[key].push(value);
|
|
241
|
+
// if we need it, let's get/create the main raycaster
|
|
255
242
|
if (interactionsRequiringRaycaster.includes(key)) {
|
|
256
243
|
if (node.instance && !interactables.value.includes(node)) {
|
|
257
244
|
// add to interactables
|
|
@@ -259,27 +246,25 @@
|
|
|
259
246
|
node.eventListenerRemoveFunctions[key].push(() => {
|
|
260
247
|
// remove from interactables
|
|
261
248
|
const idx = interactables.value.indexOf(node);
|
|
262
|
-
|
|
263
249
|
if (idx !== -1) {
|
|
264
250
|
interactables.value.splice(idx, 1);
|
|
265
251
|
}
|
|
266
252
|
});
|
|
267
253
|
}
|
|
268
254
|
}
|
|
269
|
-
|
|
270
255
|
return node;
|
|
271
256
|
}
|
|
272
|
-
const interactionsRequiringRaycaster = ['onClick', 'onPointerUp', 'onPointerDown', 'onPointerOver', 'onPointerOut', 'onPointerEnter', 'onPointerLeave', 'onPointerMove'
|
|
257
|
+
const interactionsRequiringRaycaster = ['onClick', 'onPointerUp', 'onPointerDown', 'onPointerOver', 'onPointerOut', 'onPointerEnter', 'onPointerLeave', 'onPointerMove'
|
|
258
|
+
// 'onPointerMissed',
|
|
273
259
|
];
|
|
274
260
|
|
|
275
261
|
const resizeCanvas = (camera, renderer, scene, width, height) => {
|
|
276
262
|
// ignore if no element
|
|
277
263
|
if (!renderer?.domElement || !scene || !camera) return;
|
|
278
264
|
width = width ?? window.innerWidth;
|
|
279
|
-
height = height ?? window.innerHeight;
|
|
280
|
-
|
|
265
|
+
height = height ?? window.innerHeight;
|
|
266
|
+
// update camera
|
|
281
267
|
const aspect = width / height;
|
|
282
|
-
|
|
283
268
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
284
269
|
const perspectiveCamera = camera;
|
|
285
270
|
perspectiveCamera.aspect = aspect;
|
|
@@ -293,11 +278,10 @@
|
|
|
293
278
|
orthoCamera.right = 10;
|
|
294
279
|
orthoCamera.left = -10;
|
|
295
280
|
orthoCamera.updateProjectionMatrix();
|
|
296
|
-
} else ;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
281
|
+
} else ;
|
|
282
|
+
// update canvas
|
|
283
|
+
renderer.setSize(width, height);
|
|
284
|
+
// render immediately so there's no flicker
|
|
301
285
|
if (scene && camera) {
|
|
302
286
|
renderer.render(vue.toRaw(scene), vue.toRaw(camera));
|
|
303
287
|
}
|
|
@@ -312,42 +296,37 @@
|
|
|
312
296
|
height
|
|
313
297
|
};
|
|
314
298
|
};
|
|
315
|
-
|
|
316
299
|
const prepCanvas = (container, camera, renderer, scene, sizePolicy) => {
|
|
317
300
|
const containerElement = container.value?.domElement;
|
|
318
|
-
if (!containerElement) throw new Error('missing container');
|
|
319
|
-
|
|
301
|
+
if (!containerElement) throw new Error('missing container');
|
|
302
|
+
// save and size element
|
|
320
303
|
const resizeCanvasByPolicy = () => {
|
|
321
304
|
if (sizePolicy === 'container') {
|
|
322
305
|
const dims = getInnerDimensions(containerElement);
|
|
323
306
|
resizeCanvas(camera, renderer, scene, dims.width, dims.height);
|
|
324
307
|
} else resizeCanvas(camera, renderer, scene);
|
|
325
308
|
};
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
309
|
+
resizeCanvasByPolicy();
|
|
310
|
+
// attach listeners
|
|
329
311
|
let observer = new ResizeObserver(() => {
|
|
330
312
|
resizeCanvasByPolicy();
|
|
331
|
-
});
|
|
332
|
-
|
|
313
|
+
});
|
|
314
|
+
// window.addEventListener('resize', resizeCanvas)
|
|
333
315
|
if (containerElement) {
|
|
334
316
|
observer.observe(containerElement);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
317
|
+
}
|
|
318
|
+
// cleanup
|
|
338
319
|
return {
|
|
339
320
|
dispose() {
|
|
340
321
|
if (containerElement) {
|
|
341
322
|
observer.unobserve(containerElement);
|
|
342
323
|
}
|
|
343
324
|
}
|
|
344
|
-
|
|
345
325
|
};
|
|
346
326
|
};
|
|
347
327
|
|
|
348
328
|
const LunchboxScene = vue.defineComponent({
|
|
349
329
|
name: 'LunchboxScene',
|
|
350
|
-
|
|
351
330
|
setup(props, {
|
|
352
331
|
slots
|
|
353
332
|
}) {
|
|
@@ -355,12 +334,10 @@
|
|
|
355
334
|
default: () => [slots.default?.()]
|
|
356
335
|
});
|
|
357
336
|
}
|
|
358
|
-
|
|
359
337
|
});
|
|
360
338
|
|
|
361
339
|
const LunchboxEventHandlers = vue.defineComponent({
|
|
362
340
|
name: 'LunchboxEventHandlers',
|
|
363
|
-
|
|
364
341
|
setup() {
|
|
365
342
|
const interactables = useLunchboxInteractables();
|
|
366
343
|
const globals = useGlobals();
|
|
@@ -371,7 +348,6 @@
|
|
|
371
348
|
const inputActive = vue.ref(false);
|
|
372
349
|
let currentIntersections = [];
|
|
373
350
|
const raycaster = new THREE__namespace.Raycaster(new THREE__namespace.Vector3(), new THREE__namespace.Vector3(0, 0, -1));
|
|
374
|
-
|
|
375
351
|
const fireEventsFromIntersections = ({
|
|
376
352
|
element,
|
|
377
353
|
eventKeys,
|
|
@@ -387,52 +363,44 @@
|
|
|
387
363
|
});
|
|
388
364
|
}
|
|
389
365
|
});
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
|
|
366
|
+
};
|
|
367
|
+
// add mouse listener to renderer DOM element when the element is ready
|
|
393
368
|
onRendererReady(v => {
|
|
394
|
-
if (!v?.domElement) return;
|
|
395
|
-
|
|
369
|
+
if (!v?.domElement) return;
|
|
370
|
+
// we have a DOM element, so let's add mouse listeners
|
|
396
371
|
const {
|
|
397
372
|
domElement
|
|
398
373
|
} = v;
|
|
399
|
-
|
|
400
374
|
const mouseMoveListener = evt => {
|
|
401
375
|
const screenWidth = (domElement.width ?? 1) / globals.dpr;
|
|
402
376
|
const screenHeight = (domElement.height ?? 1) / globals.dpr;
|
|
403
377
|
mousePos.value.x = evt.offsetX / screenWidth * 2 - 1;
|
|
404
378
|
mousePos.value.y = -(evt.offsetY / screenHeight) * 2 + 1;
|
|
405
379
|
};
|
|
406
|
-
|
|
407
380
|
const mouseDownListener = () => inputActive.value = true;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
381
|
+
const mouseUpListener = () => inputActive.value = false;
|
|
382
|
+
// add mouse events
|
|
412
383
|
domElement.addEventListener('pointermove', mouseMoveListener);
|
|
413
384
|
domElement.addEventListener('pointerdown', mouseDownListener);
|
|
414
385
|
domElement.addEventListener('pointerup', mouseUpListener);
|
|
415
386
|
});
|
|
416
387
|
const camera = useCamera();
|
|
417
|
-
|
|
418
388
|
const update = () => {
|
|
419
389
|
const c = camera.value;
|
|
420
|
-
if (!c) return;
|
|
421
|
-
|
|
390
|
+
if (!c) return;
|
|
391
|
+
// console.log(camera.value)
|
|
422
392
|
raycaster.setFromCamera(mousePos.value, c);
|
|
423
393
|
const intersections = raycaster.intersectObjects(interactables?.value.map(v => v.instance) ?? []);
|
|
424
394
|
let leaveValues = [],
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
leaveValues = currentIntersections.map(v => v.intersection);
|
|
429
|
-
|
|
395
|
+
entering = [],
|
|
396
|
+
staying = [];
|
|
397
|
+
// intersection arrays
|
|
398
|
+
leaveValues = currentIntersections.map(v => v.intersection);
|
|
399
|
+
// element arrays
|
|
430
400
|
intersections?.forEach(intersection => {
|
|
431
401
|
const currentIdx = currentIntersections.findIndex(v => v.intersection.object === intersection.object);
|
|
432
|
-
|
|
433
402
|
if (currentIdx === -1) {
|
|
434
403
|
const found = interactables?.value.find(v => v.instance?.uuid === intersection.object.uuid);
|
|
435
|
-
|
|
436
404
|
if (found) {
|
|
437
405
|
entering.push({
|
|
438
406
|
element: found,
|
|
@@ -441,18 +409,15 @@
|
|
|
441
409
|
}
|
|
442
410
|
} else {
|
|
443
411
|
const found = interactables?.value.find(v => v.instance?.uuid === intersection.object.uuid);
|
|
444
|
-
|
|
445
412
|
if (found) {
|
|
446
413
|
staying.push({
|
|
447
414
|
element: found,
|
|
448
415
|
intersection
|
|
449
416
|
});
|
|
450
417
|
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
418
|
+
}
|
|
419
|
+
// this is a current intersection, so it won't be in our `leave` array
|
|
454
420
|
const leaveIdx = leaveValues.findIndex(v => v.object.uuid === intersection.object.uuid);
|
|
455
|
-
|
|
456
421
|
if (leaveIdx !== -1) {
|
|
457
422
|
leaveValues.splice(leaveIdx, 1);
|
|
458
423
|
}
|
|
@@ -462,8 +427,8 @@
|
|
|
462
427
|
element: interactables?.value.find(interactable => interactable.instance?.uuid === intersection.object.uuid),
|
|
463
428
|
intersection
|
|
464
429
|
};
|
|
465
|
-
});
|
|
466
|
-
|
|
430
|
+
});
|
|
431
|
+
// new interactions
|
|
467
432
|
entering.forEach(({
|
|
468
433
|
element,
|
|
469
434
|
intersection
|
|
@@ -473,8 +438,8 @@
|
|
|
473
438
|
eventKeys: ['onPointerEnter'],
|
|
474
439
|
intersection
|
|
475
440
|
});
|
|
476
|
-
});
|
|
477
|
-
|
|
441
|
+
});
|
|
442
|
+
// unchanged interactions
|
|
478
443
|
staying.forEach(({
|
|
479
444
|
element,
|
|
480
445
|
intersection
|
|
@@ -485,8 +450,8 @@
|
|
|
485
450
|
eventKeys,
|
|
486
451
|
intersection
|
|
487
452
|
});
|
|
488
|
-
});
|
|
489
|
-
|
|
453
|
+
});
|
|
454
|
+
// exited interactions
|
|
490
455
|
leaving.forEach(({
|
|
491
456
|
element,
|
|
492
457
|
intersection
|
|
@@ -499,28 +464,24 @@
|
|
|
499
464
|
});
|
|
500
465
|
});
|
|
501
466
|
currentIntersections = [].concat(entering, staying);
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
|
|
467
|
+
};
|
|
468
|
+
// update function
|
|
505
469
|
onBeforeRender(update);
|
|
506
|
-
|
|
507
470
|
const teardown = () => offBeforeRender(update);
|
|
508
|
-
|
|
509
471
|
vue.onBeforeUnmount(teardown);
|
|
510
472
|
const clickEventKeys = ['onClick', 'onPointerDown', 'onPointerUp'];
|
|
511
473
|
vue.watch(inputActive, isDown => {
|
|
512
474
|
// run raycaster on click (necessary when `update` is not automatically called,
|
|
513
475
|
// for example in `updateSource` functions)
|
|
514
|
-
update();
|
|
476
|
+
update();
|
|
477
|
+
// meshes with multiple intersections receive multiple callbacks by default -
|
|
515
478
|
// let's make it so they only receive one callback of each type per frame.
|
|
516
479
|
// (ie usually when you click on a mesh, you expect only one click event to fire, even
|
|
517
480
|
// if there are technically multiple intersections with that mesh)
|
|
518
|
-
|
|
519
481
|
const uuidsInteractedWithThisFrame = [];
|
|
520
482
|
currentIntersections.forEach(v => {
|
|
521
483
|
clickEventKeys.forEach(key => {
|
|
522
484
|
const id = v.element.uuid + key;
|
|
523
|
-
|
|
524
485
|
if (isDown && (key === 'onClick' || key === 'onPointerDown')) {
|
|
525
486
|
if (!uuidsInteractedWithThisFrame.includes(id)) {
|
|
526
487
|
v.element.eventListeners[key]?.forEach(cb => cb({
|
|
@@ -538,16 +499,14 @@
|
|
|
538
499
|
}
|
|
539
500
|
});
|
|
540
501
|
});
|
|
541
|
-
});
|
|
502
|
+
});
|
|
503
|
+
// return arbitrary object to ensure instantiation
|
|
542
504
|
// TODO: why can't we return a <raycaster/> here?
|
|
543
|
-
|
|
544
505
|
return () => vue.createVNode(vue.resolveComponent("object3D"), null, null);
|
|
545
506
|
}
|
|
546
|
-
|
|
547
507
|
});
|
|
548
508
|
|
|
549
509
|
/** fixed & fill styling for container */
|
|
550
|
-
|
|
551
510
|
const fillStyle = position => {
|
|
552
511
|
return {
|
|
553
512
|
position,
|
|
@@ -560,7 +519,6 @@
|
|
|
560
519
|
display: 'block'
|
|
561
520
|
};
|
|
562
521
|
};
|
|
563
|
-
|
|
564
522
|
const LunchboxWrapper = vue.defineComponent({
|
|
565
523
|
name: 'Lunchbox',
|
|
566
524
|
props: {
|
|
@@ -582,7 +540,6 @@
|
|
|
582
540
|
zoom: Number,
|
|
583
541
|
updateSource: Object
|
|
584
542
|
},
|
|
585
|
-
|
|
586
543
|
setup(props, context) {
|
|
587
544
|
const canvas = vue.ref();
|
|
588
545
|
let dpr = props.dpr ?? -1;
|
|
@@ -594,101 +551,87 @@
|
|
|
594
551
|
const updateGlobals = useUpdateGlobals();
|
|
595
552
|
const app = useApp();
|
|
596
553
|
const consolidatedCameraProperties = vue.reactive({});
|
|
597
|
-
const startCallbacks = useStartCallbacks();
|
|
598
|
-
|
|
554
|
+
const startCallbacks = useStartCallbacks();
|
|
555
|
+
// https://threejs.org/docs/index.html#manual/en/introduction/Color-management
|
|
599
556
|
if (props.r3f && THREE__namespace?.ColorManagement) {
|
|
600
557
|
THREE__namespace.ColorManagement.legacyMode = false;
|
|
601
558
|
}
|
|
602
|
-
|
|
603
|
-
|
|
559
|
+
const interactables = useLunchboxInteractables();
|
|
560
|
+
// MOUNT
|
|
604
561
|
// ====================
|
|
605
|
-
|
|
606
562
|
vue.onMounted(async () => {
|
|
607
563
|
// canvas needs to exist (or user needs to handle it on their own)
|
|
608
|
-
if (!canvas.value && !context.slots?.renderer?.()?.length) throw new Error('missing canvas');
|
|
609
|
-
|
|
564
|
+
if (!canvas.value && !context.slots?.renderer?.()?.length) throw new Error('missing canvas');
|
|
565
|
+
// no camera provided, so let's create one
|
|
610
566
|
if (!context.slots?.camera?.()?.length) {
|
|
611
567
|
if (props.cameraPosition) {
|
|
612
568
|
consolidatedCameraProperties.position = props.cameraPosition;
|
|
613
569
|
}
|
|
614
|
-
|
|
615
570
|
if (props.cameraLook || props.cameraLookAt) {
|
|
616
571
|
consolidatedCameraProperties.lookAt = props.cameraLook || props.cameraLookAt;
|
|
617
572
|
}
|
|
618
|
-
|
|
619
573
|
if (props.zoom !== undefined) {
|
|
620
574
|
consolidatedCameraProperties.zoom = props.zoom;
|
|
621
575
|
}
|
|
622
|
-
}
|
|
576
|
+
}
|
|
577
|
+
// SCENE
|
|
623
578
|
// ====================
|
|
624
579
|
// set background color
|
|
625
|
-
|
|
626
|
-
|
|
627
580
|
if (scene.value?.$el?.instance && props.background) {
|
|
628
581
|
scene.value.$el.instance.background = new THREE__namespace.Color(props.background);
|
|
629
|
-
}
|
|
582
|
+
}
|
|
583
|
+
// MISC PROPERTIES
|
|
630
584
|
// ====================
|
|
631
|
-
|
|
632
|
-
|
|
633
585
|
if (dpr === -1) {
|
|
634
586
|
dpr = window.devicePixelRatio;
|
|
635
587
|
}
|
|
636
|
-
|
|
637
588
|
updateGlobals?.({
|
|
638
589
|
dpr
|
|
639
590
|
});
|
|
640
|
-
|
|
641
|
-
|
|
591
|
+
while (!renderer.value?.$el?.instance &&
|
|
592
|
+
// TODO: remove `as any`
|
|
642
593
|
!renderer.value?.component?.ctx.$el?.instance) {
|
|
643
594
|
await new Promise(r => requestAnimationFrame(r));
|
|
644
595
|
}
|
|
645
|
-
|
|
646
|
-
|
|
596
|
+
while (!scene.value?.$el?.instance &&
|
|
597
|
+
// TODO: remove `as any`
|
|
647
598
|
!scene.value?.component?.ctx.$el?.instance) {
|
|
648
599
|
await new Promise(r => requestAnimationFrame(r));
|
|
649
600
|
}
|
|
650
|
-
|
|
651
601
|
const normalizedRenderer = renderer.value?.$el?.instance ?? renderer.value?.component?.ctx.$el?.instance;
|
|
652
602
|
normalizedRenderer.setPixelRatio(globals.dpr);
|
|
653
603
|
const normalizedScene = scene.value?.$el?.instance ?? scene.value?.component?.ctx.$el?.instance;
|
|
654
|
-
const normalizedCamera = camera.value?.$el?.instance ?? camera.value?.component?.ctx.$el?.instance;
|
|
604
|
+
const normalizedCamera = camera.value?.$el?.instance ?? camera.value?.component?.ctx.$el?.instance;
|
|
605
|
+
// TODO: update DPR on monitor switch
|
|
655
606
|
// prep canvas (sizing, observe, unmount, etc)
|
|
656
607
|
// (only run if no custom renderer)
|
|
657
|
-
|
|
658
608
|
if (!context.slots?.renderer?.()?.length) {
|
|
659
609
|
// TODO: use dispose
|
|
660
610
|
prepCanvas(container, normalizedCamera, normalizedRenderer, normalizedScene, props.sizePolicy);
|
|
661
|
-
|
|
662
611
|
if (props.r3f) {
|
|
663
612
|
normalizedRenderer.outputEncoding = THREE__namespace.sRGBEncoding;
|
|
664
613
|
normalizedRenderer.toneMapping = THREE__namespace.ACESFilmicToneMapping;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
|
|
614
|
+
}
|
|
615
|
+
// update render sugar
|
|
668
616
|
const sugar = {
|
|
669
617
|
shadow: props.shadow
|
|
670
618
|
};
|
|
671
|
-
|
|
672
619
|
if (sugar?.shadow) {
|
|
673
620
|
normalizedRenderer.shadowMap.enabled = true;
|
|
674
|
-
|
|
675
621
|
if (typeof sugar.shadow === 'object') {
|
|
676
622
|
normalizedRenderer.shadowMap.type = sugar.shadow.type;
|
|
677
623
|
}
|
|
678
624
|
}
|
|
679
|
-
}
|
|
625
|
+
}
|
|
626
|
+
// START
|
|
680
627
|
// ====================
|
|
681
|
-
|
|
682
|
-
|
|
683
628
|
if (!app) {
|
|
684
629
|
throw new Error('error creating app');
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
|
|
630
|
+
}
|
|
631
|
+
// save renderer, scene, camera
|
|
688
632
|
app.config.globalProperties.lunchbox.camera = normalizedCamera;
|
|
689
633
|
app.config.globalProperties.lunchbox.renderer = normalizedRenderer;
|
|
690
634
|
app.config.globalProperties.lunchbox.scene = normalizedScene;
|
|
691
|
-
|
|
692
635
|
for (let startCallback of startCallbacks ?? []) {
|
|
693
636
|
startCallback({
|
|
694
637
|
app,
|
|
@@ -696,10 +639,9 @@
|
|
|
696
639
|
renderer: normalizedRenderer,
|
|
697
640
|
scene: normalizedScene
|
|
698
641
|
});
|
|
699
|
-
}
|
|
642
|
+
}
|
|
643
|
+
// KICK UPDATE
|
|
700
644
|
// ====================
|
|
701
|
-
|
|
702
|
-
|
|
703
645
|
update({
|
|
704
646
|
app,
|
|
705
647
|
camera: normalizedCamera,
|
|
@@ -707,36 +649,35 @@
|
|
|
707
649
|
scene: normalizedScene,
|
|
708
650
|
updateSource: props.updateSource
|
|
709
651
|
});
|
|
710
|
-
});
|
|
652
|
+
});
|
|
653
|
+
// UNMOUNT
|
|
711
654
|
// ====================
|
|
712
|
-
|
|
713
655
|
vue.onBeforeUnmount(() => {
|
|
714
656
|
cancelUpdate();
|
|
715
657
|
cancelUpdateSource();
|
|
716
|
-
});
|
|
658
|
+
});
|
|
659
|
+
// RENDER FUNCTION
|
|
717
660
|
// ====================
|
|
718
|
-
|
|
719
661
|
const containerFillStyle = props.sizePolicy === 'container' ? 'static' : 'absolute';
|
|
720
|
-
const canvasFillStyle = props.sizePolicy === 'container' ? 'static' : 'fixed';
|
|
662
|
+
const canvasFillStyle = props.sizePolicy === 'container' ? 'static' : 'fixed';
|
|
663
|
+
// REACTIVE CUSTOM CAMERAS
|
|
721
664
|
// ====================
|
|
722
665
|
// find first camera with `type.name` property
|
|
723
666
|
// (which indicates a Lunch.Node)
|
|
724
|
-
|
|
725
667
|
const activeCamera = vue.computed(() => {
|
|
726
668
|
const output = context.slots?.camera?.().find(c => c.type?.name);
|
|
727
|
-
|
|
728
669
|
if (output) {
|
|
729
670
|
return output;
|
|
730
671
|
}
|
|
731
|
-
|
|
732
672
|
return output;
|
|
733
|
-
});
|
|
734
|
-
|
|
673
|
+
});
|
|
674
|
+
// TODO: make custom cameras reactive
|
|
735
675
|
vue.watch(activeCamera, async (newVal, oldVal) => {
|
|
736
676
|
// console.log('got camera', newVal)
|
|
737
677
|
if (newVal && newVal?.props?.key !== oldVal?.props?.key) {
|
|
738
678
|
// TODO: remove cast
|
|
739
|
-
camera.value = newVal;
|
|
679
|
+
camera.value = newVal;
|
|
680
|
+
// TODO: why isn't this updating app camera?
|
|
740
681
|
// const el = await waitFor(() => newVal.el)
|
|
741
682
|
// console.log(el)
|
|
742
683
|
// camera.value = el
|
|
@@ -745,10 +686,11 @@
|
|
|
745
686
|
}
|
|
746
687
|
}, {
|
|
747
688
|
immediate: true
|
|
748
|
-
});
|
|
689
|
+
});
|
|
690
|
+
// RENDER FUNCTION
|
|
749
691
|
// ====================
|
|
750
|
-
|
|
751
|
-
|
|
692
|
+
return () => vue.createVNode(vue.Fragment, null, [context.slots?.renderer?.()?.length ?
|
|
693
|
+
// TODO: remove `as any` cast
|
|
752
694
|
renderer.value = context.slots?.renderer?.()[0] : // ...otherwise, add canvas...
|
|
753
695
|
vue.createVNode(vue.Fragment, null, [vue.createVNode("div", {
|
|
754
696
|
"class": "lunchbox-container",
|
|
@@ -769,14 +711,16 @@
|
|
|
769
711
|
powerPreference: !!props.r3f ? 'high-performance' : 'default',
|
|
770
712
|
...(props.rendererArguments ?? {})
|
|
771
713
|
}]
|
|
772
|
-
}), null)]), context.slots?.scene?.()?.length ?
|
|
714
|
+
}), null)]), context.slots?.scene?.()?.length ?
|
|
715
|
+
// TODO: remove `as any` cast
|
|
773
716
|
scene.value = context.slots?.scene?.()[0] : // ...otherwise, add default scene
|
|
774
717
|
// TODO: why does this need to be a separate component? <scene> throws an error
|
|
775
718
|
vue.createVNode(LunchboxScene, {
|
|
776
719
|
"ref": scene
|
|
777
720
|
}, {
|
|
778
721
|
default: () => [context.slots?.default?.()]
|
|
779
|
-
}), context.slots?.camera?.()?.length ?
|
|
722
|
+
}), context.slots?.camera?.()?.length ?
|
|
723
|
+
// TODO: remove `any` cast
|
|
780
724
|
camera.value : props.ortho || props.orthographic ? vue.createVNode(vue.resolveComponent("orthographicCamera"), vue.mergeProps({
|
|
781
725
|
"ref": camera,
|
|
782
726
|
"args": props.cameraArgs ?? []
|
|
@@ -785,22 +729,32 @@
|
|
|
785
729
|
"args": props.cameraArgs ?? [props.r3f ? 75 : 45, 0.5625, 1, 1000]
|
|
786
730
|
}, consolidatedCameraProperties), null), interactables?.value.length && vue.createVNode(LunchboxEventHandlers, null, null)]);
|
|
787
731
|
}
|
|
788
|
-
|
|
789
732
|
});
|
|
790
733
|
|
|
791
734
|
// list of all components to register out of the box
|
|
792
|
-
const autoGeneratedComponents = [
|
|
793
|
-
|
|
794
|
-
'
|
|
735
|
+
const autoGeneratedComponents = [
|
|
736
|
+
// ThreeJS basics
|
|
737
|
+
'mesh', 'instancedMesh', 'scene', 'sprite', 'object3D',
|
|
738
|
+
// geometry
|
|
739
|
+
'instancedBufferGeometry', 'bufferGeometry', 'boxBufferGeometry', 'circleBufferGeometry', 'coneBufferGeometry', 'cylinderBufferGeometry', 'dodecahedronBufferGeometry', 'extrudeBufferGeometry', 'icosahedronBufferGeometry', 'latheBufferGeometry', 'octahedronBufferGeometry', 'parametricBufferGeometry', 'planeBufferGeometry', 'polyhedronBufferGeometry', 'ringBufferGeometry', 'shapeBufferGeometry', 'sphereBufferGeometry', 'tetrahedronBufferGeometry', 'textBufferGeometry', 'torusBufferGeometry', 'torusKnotBufferGeometry', 'tubeBufferGeometry', 'wireframeGeometry', 'parametricGeometry', 'tetrahedronGeometry', 'octahedronGeometry', 'icosahedronGeometry', 'dodecahedronGeometry', 'polyhedronGeometry', 'tubeGeometry', 'torusKnotGeometry', 'torusGeometry',
|
|
740
|
+
// textgeometry has been moved to /examples/jsm/geometries/TextGeometry
|
|
795
741
|
// 'textGeometry',
|
|
796
|
-
'sphereGeometry', 'ringGeometry', 'planeGeometry', 'latheGeometry', 'shapeGeometry', 'extrudeGeometry', 'edgesGeometry', 'coneGeometry', 'cylinderGeometry', 'circleGeometry', 'boxGeometry',
|
|
797
|
-
|
|
798
|
-
'
|
|
799
|
-
|
|
800
|
-
'
|
|
801
|
-
|
|
802
|
-
'
|
|
803
|
-
|
|
742
|
+
'sphereGeometry', 'ringGeometry', 'planeGeometry', 'latheGeometry', 'shapeGeometry', 'extrudeGeometry', 'edgesGeometry', 'coneGeometry', 'cylinderGeometry', 'circleGeometry', 'boxGeometry',
|
|
743
|
+
// materials
|
|
744
|
+
'material', 'shadowMaterial', 'spriteMaterial', 'rawShaderMaterial', 'shaderMaterial', 'pointsMaterial', 'meshPhysicalMaterial', 'meshStandardMaterial', 'meshPhongMaterial', 'meshToonMaterial', 'meshNormalMaterial', 'meshLambertMaterial', 'meshDepthMaterial', 'meshDistanceMaterial', 'meshBasicMaterial', 'meshMatcapMaterial', 'lineDashedMaterial', 'lineBasicMaterial',
|
|
745
|
+
// lights
|
|
746
|
+
'light', 'spotLightShadow', 'spotLight', 'pointLight', 'rectAreaLight', 'hemisphereLight', 'directionalLightShadow', 'directionalLight', 'ambientLight', 'lightShadow', 'ambientLightProbe', 'hemisphereLightProbe', 'lightProbe',
|
|
747
|
+
// textures
|
|
748
|
+
'texture', 'videoTexture', 'dataTexture', 'dataTexture3D', 'compressedTexture', 'cubeTexture', 'canvasTexture', 'depthTexture',
|
|
749
|
+
// Texture loaders
|
|
750
|
+
'textureLoader',
|
|
751
|
+
// misc
|
|
752
|
+
'group', 'catmullRomCurve3', 'points', 'raycaster',
|
|
753
|
+
// helpers
|
|
754
|
+
'cameraHelper',
|
|
755
|
+
// cameras
|
|
756
|
+
'camera', 'perspectiveCamera', 'orthographicCamera', 'cubeCamera', 'arrayCamera',
|
|
757
|
+
// renderers
|
|
804
758
|
'webGLRenderer'
|
|
805
759
|
/*
|
|
806
760
|
// List copied from r3f:
|
|
@@ -846,42 +800,36 @@
|
|
|
846
800
|
fog: FogProps
|
|
847
801
|
fogExp2: FogExp2Props
|
|
848
802
|
shape: ShapeProps
|
|
849
|
-
*/
|
|
850
|
-
];
|
|
851
|
-
|
|
852
|
-
const catalogue = {}; // component creation utility
|
|
803
|
+
*/];
|
|
853
804
|
|
|
805
|
+
const catalogue = {};
|
|
806
|
+
// component creation utility
|
|
854
807
|
const createComponent$1 = tag => vue.defineComponent({
|
|
855
808
|
inheritAttrs: false,
|
|
856
809
|
name: tag,
|
|
857
|
-
|
|
858
810
|
setup(props, context) {
|
|
859
811
|
return () => {
|
|
860
812
|
return vue.h(tag, context.attrs, context.slots?.default?.() || []);
|
|
861
813
|
};
|
|
862
814
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
815
|
+
});
|
|
816
|
+
// turn components into registered map
|
|
867
817
|
const processed = autoGeneratedComponents.map(createComponent$1).reduce((acc, curr) => {
|
|
868
818
|
acc[curr.name] = curr;
|
|
869
819
|
return acc;
|
|
870
820
|
}, {});
|
|
871
|
-
const components = {
|
|
821
|
+
const components = {
|
|
822
|
+
...processed,
|
|
872
823
|
Lunchbox: LunchboxWrapper
|
|
873
824
|
};
|
|
874
825
|
|
|
875
826
|
const createComponent = tag => vue.defineComponent({
|
|
876
827
|
inheritAttrs: false,
|
|
877
828
|
name: tag,
|
|
878
|
-
|
|
879
829
|
render() {
|
|
880
830
|
return vue.h(tag, this.$attrs, this.$slots?.default?.() || []);
|
|
881
831
|
}
|
|
882
|
-
|
|
883
832
|
});
|
|
884
|
-
|
|
885
833
|
const extend = ({
|
|
886
834
|
app,
|
|
887
835
|
...targets
|
|
@@ -900,14 +848,12 @@
|
|
|
900
848
|
// return $attachedArray value if needed
|
|
901
849
|
if (typeof prop === 'string' && prop.startsWith('$attachedArray')) {
|
|
902
850
|
return node.attachedArray[prop.replace('$attachedArray.', '')];
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
|
|
851
|
+
}
|
|
852
|
+
// return $attached value if needed
|
|
906
853
|
if (typeof prop === 'string' && prop.startsWith('$attached')) {
|
|
907
854
|
return node.attached[prop.replace('$attached.', '')];
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
|
|
855
|
+
}
|
|
856
|
+
// otherwise, return plain value
|
|
911
857
|
return prop;
|
|
912
858
|
}
|
|
913
859
|
function processPropAsArray({
|
|
@@ -923,17 +869,17 @@
|
|
|
923
869
|
}
|
|
924
870
|
|
|
925
871
|
function instantiateThreeObject(node) {
|
|
926
|
-
if (!node.type) return null;
|
|
927
|
-
|
|
872
|
+
if (!node.type) return null;
|
|
873
|
+
// what class will we be instantiating?
|
|
928
874
|
const uppercaseType = node.type[0].toUpperCase() + node.type.slice(1);
|
|
929
875
|
const translatedType = uppercaseType.replace(/Lunchbox$/, '');
|
|
930
876
|
const targetClass = catalogue[node.type] || THREE__namespace[uppercaseType] || catalogue[translatedType] || THREE__namespace[translatedType];
|
|
931
|
-
if (!targetClass) throw `${uppercaseType} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;
|
|
932
|
-
|
|
933
|
-
const args = node.props.args ?? [];
|
|
877
|
+
if (!targetClass) throw `${uppercaseType} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;
|
|
878
|
+
// what args have we been provided?
|
|
879
|
+
const args = node.props.args ?? [];
|
|
880
|
+
// replace $attached values with their instances
|
|
934
881
|
// we need to guarantee everything comes back as an array so we can spread $attachedArrays,
|
|
935
882
|
// so we'll use processPropAsArray
|
|
936
|
-
|
|
937
883
|
const argsWrappedInArrays = args.map(arg => {
|
|
938
884
|
return processPropAsArray({
|
|
939
885
|
node,
|
|
@@ -959,12 +905,10 @@
|
|
|
959
905
|
// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
|
|
960
906
|
// find the complete implementation of crypto (msCrypto) on IE11.
|
|
961
907
|
getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
|
|
962
|
-
|
|
963
908
|
if (!getRandomValues) {
|
|
964
909
|
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
|
|
965
910
|
}
|
|
966
911
|
}
|
|
967
|
-
|
|
968
912
|
return getRandomValues(rnds8);
|
|
969
913
|
}
|
|
970
914
|
|
|
@@ -980,15 +924,13 @@
|
|
|
980
924
|
*/
|
|
981
925
|
|
|
982
926
|
var byteToHex = [];
|
|
983
|
-
|
|
984
927
|
for (var i = 0; i < 256; ++i) {
|
|
985
928
|
byteToHex.push((i + 0x100).toString(16).substr(1));
|
|
986
929
|
}
|
|
987
|
-
|
|
988
930
|
function stringify(arr) {
|
|
989
|
-
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
931
|
+
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
932
|
+
// Note: Be careful editing this code! It's been tuned for performance
|
|
990
933
|
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
|
991
|
-
|
|
992
934
|
var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one
|
|
993
935
|
// of the following:
|
|
994
936
|
// - One or more input array values don't map to a hex octet (leading to
|
|
@@ -998,7 +940,6 @@
|
|
|
998
940
|
if (!validate(uuid)) {
|
|
999
941
|
throw TypeError('Stringified UUID is invalid');
|
|
1000
942
|
}
|
|
1001
|
-
|
|
1002
943
|
return uuid;
|
|
1003
944
|
}
|
|
1004
945
|
|
|
@@ -1011,119 +952,97 @@
|
|
|
1011
952
|
|
|
1012
953
|
if (buf) {
|
|
1013
954
|
offset = offset || 0;
|
|
1014
|
-
|
|
1015
955
|
for (var i = 0; i < 16; ++i) {
|
|
1016
956
|
buf[offset + i] = rnds[i];
|
|
1017
957
|
}
|
|
1018
|
-
|
|
1019
958
|
return buf;
|
|
1020
959
|
}
|
|
1021
|
-
|
|
1022
960
|
return stringify(rnds);
|
|
1023
961
|
}
|
|
1024
962
|
|
|
963
|
+
// MiniDom recreates DOM node properties and methods.
|
|
1025
964
|
// Since Vue 3 is a DOM-first framework, many of its nodeOps depend on
|
|
1026
965
|
// properties and methods the DOM naturally contains. MiniDom recreates
|
|
1027
966
|
// those properties (as well as a few from the tree-model npm package)
|
|
1028
967
|
// to make a DOM-like but otherwise agnostic hierarchy structure.
|
|
1029
|
-
|
|
1030
968
|
exports.MiniDom = void 0;
|
|
1031
|
-
|
|
1032
969
|
(function (MiniDom) {
|
|
1033
970
|
class BaseNode {
|
|
1034
971
|
constructor(options = {}, parent) {
|
|
1035
972
|
this.parentNode = options?.parentNode ?? parent ?? null;
|
|
1036
973
|
this.minidomType = 'MinidomBaseNode';
|
|
1037
|
-
this.uuid = options?.uuid ?? v4();
|
|
974
|
+
this.uuid = options?.uuid ?? v4();
|
|
975
|
+
// allNodes.push(this)
|
|
1038
976
|
}
|
|
1039
977
|
|
|
1040
|
-
uuid;
|
|
978
|
+
uuid;
|
|
979
|
+
// DOM FEATURES
|
|
1041
980
|
// ====================
|
|
1042
|
-
|
|
1043
981
|
parentNode;
|
|
1044
|
-
|
|
1045
982
|
get nextSibling() {
|
|
1046
983
|
if (!this.parentNode) return null;
|
|
1047
|
-
const idx = this.parentNode.children.findIndex(n => n.uuid === this.uuid);
|
|
1048
|
-
|
|
984
|
+
const idx = this.parentNode.children.findIndex(n => n.uuid === this.uuid);
|
|
985
|
+
// return next sibling if we're present and not the last child of the parent
|
|
1049
986
|
if (idx !== -1 && idx < this.parentNode.children.length - 1) {
|
|
1050
987
|
return this.parentNode.children[idx + 1];
|
|
1051
988
|
}
|
|
1052
|
-
|
|
1053
989
|
return null;
|
|
1054
990
|
}
|
|
1055
|
-
|
|
1056
991
|
insertBefore(child, anchor) {
|
|
1057
992
|
child.removeAsChildFromAnyParents();
|
|
1058
993
|
child.parentNode = this;
|
|
1059
994
|
const anchorIdx = this.children.findIndex(n => n.uuid === anchor?.uuid);
|
|
1060
|
-
|
|
1061
995
|
if (anchorIdx !== -1) {
|
|
1062
996
|
this.children.splice(anchorIdx, 0, child);
|
|
1063
997
|
} else {
|
|
1064
998
|
this.children.push(child);
|
|
1065
999
|
}
|
|
1066
1000
|
}
|
|
1067
|
-
|
|
1068
1001
|
removeChild(child) {
|
|
1069
1002
|
const idx = this.children.findIndex(n => n?.uuid === child?.uuid);
|
|
1070
|
-
|
|
1071
1003
|
if (idx !== -1) {
|
|
1072
1004
|
this.children.splice(idx, 1);
|
|
1073
1005
|
}
|
|
1074
|
-
}
|
|
1006
|
+
}
|
|
1007
|
+
// TREE FEATURES
|
|
1075
1008
|
// ====================
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
1009
|
children = [];
|
|
1079
|
-
|
|
1080
1010
|
addChild(child) {
|
|
1081
1011
|
if (child) {
|
|
1082
1012
|
// remove child from any other parents
|
|
1083
|
-
child.removeAsChildFromAnyParents();
|
|
1084
|
-
|
|
1013
|
+
child.removeAsChildFromAnyParents();
|
|
1014
|
+
// add to this node
|
|
1085
1015
|
child.parentNode = this;
|
|
1086
1016
|
this.insertBefore(child, null);
|
|
1087
1017
|
}
|
|
1088
|
-
|
|
1089
1018
|
return this;
|
|
1090
1019
|
}
|
|
1091
1020
|
/** Get the array of Nodes representing the path from the root to this Node (inclusive). */
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
1021
|
getPath() {
|
|
1095
1022
|
const output = [];
|
|
1096
1023
|
let current = this;
|
|
1097
|
-
|
|
1098
1024
|
while (current) {
|
|
1099
1025
|
output.unshift(current);
|
|
1100
1026
|
current = current.parentNode;
|
|
1101
1027
|
}
|
|
1102
|
-
|
|
1103
1028
|
return output;
|
|
1104
1029
|
}
|
|
1105
1030
|
/** Drop this node. Removes parent's knowledge of this node
|
|
1106
1031
|
* and resets this node's internal parent. */
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
1032
|
drop() {
|
|
1110
1033
|
// remove as child
|
|
1111
|
-
this.removeAsChildFromAnyParents();
|
|
1112
|
-
|
|
1034
|
+
this.removeAsChildFromAnyParents();
|
|
1035
|
+
// remove parent
|
|
1113
1036
|
this.parentNode = null;
|
|
1114
1037
|
}
|
|
1115
1038
|
/** Walk over the entire subtree. Return falsey value in callback to end early. */
|
|
1116
1039
|
// TODO: depth-first vs breadth-first
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
1040
|
walk(callback) {
|
|
1120
1041
|
const queue = [this, ...this.children];
|
|
1121
1042
|
const traversed = [];
|
|
1122
1043
|
let canContinue = true;
|
|
1123
|
-
|
|
1124
1044
|
while (queue.length && canContinue) {
|
|
1125
1045
|
const current = queue.shift();
|
|
1126
|
-
|
|
1127
1046
|
if (current) {
|
|
1128
1047
|
if (traversed.includes(current)) continue;
|
|
1129
1048
|
traversed.push(current);
|
|
@@ -1133,20 +1052,15 @@
|
|
|
1133
1052
|
canContinue = false;
|
|
1134
1053
|
}
|
|
1135
1054
|
}
|
|
1136
|
-
}
|
|
1055
|
+
}
|
|
1056
|
+
// INTERNAL FEATURES
|
|
1137
1057
|
// ====================
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
1058
|
minidomType;
|
|
1141
|
-
|
|
1142
1059
|
removeAsChildFromAnyParents() {
|
|
1143
1060
|
this.parentNode?.removeChild(this);
|
|
1144
1061
|
}
|
|
1145
|
-
|
|
1146
1062
|
}
|
|
1147
|
-
|
|
1148
1063
|
MiniDom.BaseNode = BaseNode;
|
|
1149
|
-
|
|
1150
1064
|
class RendererBaseNode extends MiniDom.BaseNode {
|
|
1151
1065
|
constructor(options = {}, parent) {
|
|
1152
1066
|
super(options, parent);
|
|
@@ -1158,73 +1072,57 @@
|
|
|
1158
1072
|
this.props = options.props ?? [];
|
|
1159
1073
|
this.type = options.type ?? '';
|
|
1160
1074
|
}
|
|
1161
|
-
|
|
1162
1075
|
eventListeners;
|
|
1163
1076
|
eventListenerRemoveFunctions;
|
|
1164
1077
|
name;
|
|
1165
1078
|
metaType;
|
|
1166
1079
|
props;
|
|
1167
1080
|
type;
|
|
1168
|
-
|
|
1169
1081
|
drop() {
|
|
1170
|
-
super.drop();
|
|
1171
|
-
|
|
1082
|
+
super.drop();
|
|
1083
|
+
// handle remove functions
|
|
1172
1084
|
Object.keys(this.eventListenerRemoveFunctions).forEach(key => {
|
|
1173
1085
|
this.eventListenerRemoveFunctions[key].forEach(func => func());
|
|
1174
1086
|
});
|
|
1175
1087
|
}
|
|
1176
|
-
|
|
1177
1088
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1089
|
+
MiniDom.RendererBaseNode = RendererBaseNode;
|
|
1090
|
+
// ====================
|
|
1180
1091
|
// SPECIFIC RENDERER NODES BELOW
|
|
1181
1092
|
// ====================
|
|
1182
|
-
|
|
1183
1093
|
class RendererRootNode extends MiniDom.RendererBaseNode {
|
|
1184
1094
|
constructor(options = {}, parent) {
|
|
1185
1095
|
super(options, parent);
|
|
1186
1096
|
this.domElement = options.domElement ?? document.createElement('div');
|
|
1187
1097
|
}
|
|
1188
|
-
|
|
1189
1098
|
domElement;
|
|
1190
1099
|
isLunchboxRootNode = true;
|
|
1191
1100
|
}
|
|
1192
|
-
|
|
1193
1101
|
MiniDom.RendererRootNode = RendererRootNode;
|
|
1194
|
-
|
|
1195
1102
|
class RendererCommentNode extends MiniDom.RendererBaseNode {
|
|
1196
1103
|
constructor(options = {}, parent) {
|
|
1197
1104
|
super(options, parent);
|
|
1198
1105
|
this.text = options.text ?? '';
|
|
1199
1106
|
}
|
|
1200
|
-
|
|
1201
1107
|
text;
|
|
1202
1108
|
}
|
|
1203
|
-
|
|
1204
1109
|
MiniDom.RendererCommentNode = RendererCommentNode;
|
|
1205
|
-
|
|
1206
1110
|
class RendererDomNode extends MiniDom.RendererBaseNode {
|
|
1207
1111
|
constructor(options = {}, parent) {
|
|
1208
1112
|
super(options, parent);
|
|
1209
1113
|
this.domElement = options.domElement ?? document.createElement('div');
|
|
1210
1114
|
}
|
|
1211
|
-
|
|
1212
1115
|
domElement;
|
|
1213
1116
|
}
|
|
1214
|
-
|
|
1215
1117
|
MiniDom.RendererDomNode = RendererDomNode;
|
|
1216
|
-
|
|
1217
1118
|
class RendererTextNode extends MiniDom.RendererBaseNode {
|
|
1218
1119
|
constructor(options = {}, parent) {
|
|
1219
1120
|
super(options, parent);
|
|
1220
1121
|
this.text = options.text ?? '';
|
|
1221
1122
|
}
|
|
1222
|
-
|
|
1223
1123
|
text;
|
|
1224
1124
|
}
|
|
1225
|
-
|
|
1226
1125
|
MiniDom.RendererTextNode = RendererTextNode;
|
|
1227
|
-
|
|
1228
1126
|
class RendererStandardNode extends MiniDom.RendererBaseNode {
|
|
1229
1127
|
constructor(options = {}, parent) {
|
|
1230
1128
|
super(options, parent);
|
|
@@ -1232,15 +1130,12 @@
|
|
|
1232
1130
|
this.attachedArray = options.attachedArray ?? {};
|
|
1233
1131
|
this.instance = options.instance ?? null;
|
|
1234
1132
|
}
|
|
1235
|
-
|
|
1236
1133
|
attached;
|
|
1237
1134
|
attachedArray;
|
|
1238
1135
|
instance;
|
|
1239
1136
|
}
|
|
1240
|
-
|
|
1241
1137
|
MiniDom.RendererStandardNode = RendererStandardNode;
|
|
1242
1138
|
})(exports.MiniDom || (exports.MiniDom = {}));
|
|
1243
|
-
|
|
1244
1139
|
function isMinidomNode(item) {
|
|
1245
1140
|
return item?.minidomType === 'RendererNode';
|
|
1246
1141
|
}
|
|
@@ -1269,7 +1164,6 @@
|
|
|
1269
1164
|
if (typeof opts.app.config.globalProperties.lunchbox.frameId === 'number') {
|
|
1270
1165
|
cancelAnimationFrame(opts.app.config.globalProperties.lunchbox.frameId);
|
|
1271
1166
|
}
|
|
1272
|
-
|
|
1273
1167
|
opts.app.config.globalProperties.lunchbox.frameId = requestAnimationFrame(() => update({
|
|
1274
1168
|
app: opts.app,
|
|
1275
1169
|
renderer: opts.renderer,
|
|
@@ -1278,7 +1172,6 @@
|
|
|
1278
1172
|
updateSource: opts.updateSource
|
|
1279
1173
|
}));
|
|
1280
1174
|
};
|
|
1281
|
-
|
|
1282
1175
|
const update = opts => {
|
|
1283
1176
|
if (opts.updateSource) {
|
|
1284
1177
|
if (!opts.app.config.globalProperties.lunchbox.watchStopHandle) {
|
|
@@ -1292,37 +1185,35 @@
|
|
|
1292
1185
|
} else {
|
|
1293
1186
|
// request next frame on a continuous loop
|
|
1294
1187
|
requestUpdate(opts);
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1188
|
+
}
|
|
1189
|
+
// prep options
|
|
1298
1190
|
const {
|
|
1299
1191
|
app,
|
|
1300
1192
|
renderer,
|
|
1301
1193
|
scene
|
|
1302
|
-
} = opts;
|
|
1303
|
-
|
|
1194
|
+
} = opts;
|
|
1195
|
+
// BEFORE RENDER
|
|
1304
1196
|
app.config.globalProperties.lunchbox.beforeRender.forEach(cb => {
|
|
1305
1197
|
cb?.(opts);
|
|
1306
|
-
});
|
|
1307
|
-
|
|
1198
|
+
});
|
|
1199
|
+
// RENDER
|
|
1308
1200
|
if (renderer && scene && opts.app.config.globalProperties.lunchbox.camera) {
|
|
1309
1201
|
if (app.customRender) {
|
|
1310
1202
|
app.customRender(opts);
|
|
1311
1203
|
} else {
|
|
1312
|
-
renderer.render(vue.toRaw(scene), opts.app.config.globalProperties.lunchbox.camera
|
|
1204
|
+
renderer.render(vue.toRaw(scene), opts.app.config.globalProperties.lunchbox.camera
|
|
1205
|
+
// toRaw(camera)
|
|
1313
1206
|
);
|
|
1314
1207
|
}
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1208
|
+
}
|
|
1209
|
+
// AFTER RENDER
|
|
1318
1210
|
app.config.globalProperties.lunchbox.afterRender.forEach(cb => {
|
|
1319
1211
|
cb?.(opts);
|
|
1320
1212
|
});
|
|
1321
|
-
};
|
|
1213
|
+
};
|
|
1214
|
+
// before render
|
|
1322
1215
|
// ====================
|
|
1323
|
-
|
|
1324
1216
|
/** Obtain callback methods for `onBeforeRender` and `offBeforeRender`. Usually used internally by Lunchbox. */
|
|
1325
|
-
|
|
1326
1217
|
const useBeforeRender = () => {
|
|
1327
1218
|
return {
|
|
1328
1219
|
onBeforeRender: vue.inject(onBeforeRenderKey),
|
|
@@ -1334,21 +1225,18 @@
|
|
|
1334
1225
|
* Note that if `updateSource` is set in the Lunchbox wrapper component, this will **only** run
|
|
1335
1226
|
* before a render triggered by that `updateSource`. Normally, the function should run every frame.
|
|
1336
1227
|
*/
|
|
1337
|
-
|
|
1338
1228
|
const onBeforeRender = (cb, index = Infinity) => {
|
|
1339
1229
|
useBeforeRender().onBeforeRender?.(cb, index);
|
|
1340
1230
|
};
|
|
1341
1231
|
/** Remove a function from the `beforeRender` callback list. Useful for tearing down functions added
|
|
1342
1232
|
* by `onBeforeRender`.
|
|
1343
1233
|
*/
|
|
1344
|
-
|
|
1345
1234
|
const offBeforeRender = cb => {
|
|
1346
1235
|
useBeforeRender().offBeforeRender?.(cb);
|
|
1347
|
-
};
|
|
1236
|
+
};
|
|
1237
|
+
// after render
|
|
1348
1238
|
// ====================
|
|
1349
|
-
|
|
1350
1239
|
/** Obtain callback methods for `onAfterRender` and `offAfterRender`. Usually used internally by Lunchbox. */
|
|
1351
|
-
|
|
1352
1240
|
const useAfterRender = () => {
|
|
1353
1241
|
return {
|
|
1354
1242
|
onAfterRender: vue.inject(onBeforeRenderKey),
|
|
@@ -1360,21 +1248,18 @@
|
|
|
1360
1248
|
* Note that if `updateSource` is set in the Lunchbox wrapper component, this will **only** run
|
|
1361
1249
|
* after a render triggered by that `updateSource`. Normally, the function should run every frame.
|
|
1362
1250
|
*/
|
|
1363
|
-
|
|
1364
1251
|
const onAfterRender = (cb, index = Infinity) => {
|
|
1365
1252
|
useBeforeRender().onBeforeRender?.(cb, index);
|
|
1366
1253
|
};
|
|
1367
1254
|
/** Remove a function from the `afterRender` callback list. Useful for tearing down functions added
|
|
1368
1255
|
* by `onAfterRender`.
|
|
1369
1256
|
*/
|
|
1370
|
-
|
|
1371
1257
|
const offAfterRender = cb => {
|
|
1372
1258
|
useBeforeRender().offBeforeRender?.(cb);
|
|
1373
1259
|
};
|
|
1374
1260
|
/** Obtain a function used to cancel the current update frame. Use `cancelUpdate` if you wish
|
|
1375
1261
|
* to immediately invoke the cancellation function. Usually used internally by Lunchbox.
|
|
1376
1262
|
*/
|
|
1377
|
-
|
|
1378
1263
|
const useCancelUpdate = () => {
|
|
1379
1264
|
const frameId = vue.inject(frameIdKey);
|
|
1380
1265
|
return () => {
|
|
@@ -1382,26 +1267,22 @@
|
|
|
1382
1267
|
};
|
|
1383
1268
|
};
|
|
1384
1269
|
/** Cancel the current update frame. Usually used internally by Lunchbox. */
|
|
1385
|
-
|
|
1386
1270
|
const cancelUpdate = () => {
|
|
1387
1271
|
useCancelUpdate()?.();
|
|
1388
1272
|
};
|
|
1389
1273
|
/** Obtain a function used to cancel an update source. Use `cancelUpdateSource` if you wish to
|
|
1390
1274
|
* immediately invoke the cancellation function. Usually used internally by Lunchbox.
|
|
1391
1275
|
*/
|
|
1392
|
-
|
|
1393
1276
|
const useCancelUpdateSource = () => {
|
|
1394
1277
|
const cancel = vue.inject(watchStopHandleKey);
|
|
1395
1278
|
return () => cancel?.();
|
|
1396
1279
|
};
|
|
1397
1280
|
/** Cancel an update source. Usually used internally by Lunchbox. */
|
|
1398
|
-
|
|
1399
1281
|
const cancelUpdateSource = () => {
|
|
1400
1282
|
useCancelUpdateSource()?.();
|
|
1401
1283
|
};
|
|
1402
1284
|
|
|
1403
1285
|
/** Update a single prop on a given node. */
|
|
1404
|
-
|
|
1405
1286
|
function updateObjectProp({
|
|
1406
1287
|
node,
|
|
1407
1288
|
key,
|
|
@@ -1417,37 +1298,33 @@
|
|
|
1417
1298
|
interactables,
|
|
1418
1299
|
value
|
|
1419
1300
|
});
|
|
1420
|
-
}
|
|
1301
|
+
}
|
|
1302
|
+
// update THREE property
|
|
1421
1303
|
// get final key
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
1304
|
const camelKey = key.replace(/-/g, '.');
|
|
1425
|
-
const finalKey = propertyShortcuts[camelKey] || camelKey;
|
|
1426
|
-
|
|
1427
|
-
if (internalLunchboxVueKeys.includes(key) || internalLunchboxVueKeys.includes(finalKey)) return node;
|
|
1428
|
-
|
|
1429
|
-
if (!isLunchboxStandardNode(node)) return node;
|
|
1430
|
-
|
|
1305
|
+
const finalKey = propertyShortcuts[camelKey] || camelKey;
|
|
1306
|
+
// handle and return early if prop is specific to Vue/Lunchbox
|
|
1307
|
+
if (internalLunchboxVueKeys.includes(key) || internalLunchboxVueKeys.includes(finalKey)) return node;
|
|
1308
|
+
// everything else should be Three-specific, so let's cancel if this isn't a standard node
|
|
1309
|
+
if (!isLunchboxStandardNode(node)) return node;
|
|
1310
|
+
// parse $attached values
|
|
1431
1311
|
if (typeof value === 'string' && value.startsWith('$attached')) {
|
|
1432
1312
|
const attachedName = value.replace('$attached.', '');
|
|
1433
1313
|
value = get(node.attached, attachedName, null);
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1314
|
+
}
|
|
1315
|
+
// save instance
|
|
1316
|
+
const target = node.instance;
|
|
1317
|
+
// cancel if no target
|
|
1318
|
+
if (!target) return node;
|
|
1319
|
+
// burrow down until we get property to change
|
|
1441
1320
|
let liveProperty;
|
|
1442
|
-
|
|
1443
1321
|
for (let i = 0; i < nestedPropertiesToCheck.length && !liveProperty; i++) {
|
|
1444
1322
|
const nestedProperty = nestedPropertiesToCheck[i];
|
|
1445
1323
|
const fullPath = [nestedProperty, finalKey].filter(Boolean).join('.');
|
|
1446
1324
|
liveProperty = liveProperty = get(target, fullPath);
|
|
1447
|
-
}
|
|
1325
|
+
}
|
|
1326
|
+
// change property
|
|
1448
1327
|
// first, save as array in case we need to spread it
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
1328
|
if (liveProperty && isNumber(value) && liveProperty?.setScalar) {
|
|
1452
1329
|
// if value is a number and the property has a `setScalar` method, use that
|
|
1453
1330
|
liveProperty.setScalar(value);
|
|
@@ -1462,18 +1339,17 @@
|
|
|
1462
1339
|
} else {
|
|
1463
1340
|
if (!Array.isArray(value)) {
|
|
1464
1341
|
throw new Error('Arguments on a declarative method must be wrapped in an array.\nWorks:\n<example :methodCall="[256]" />\nDoesn\'t work:\n<example :methodCall="256" />');
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1342
|
+
}
|
|
1343
|
+
// if property is a function, let's try calling it
|
|
1468
1344
|
liveProperty.bind(node.instance)(...value);
|
|
1469
|
-
}
|
|
1345
|
+
}
|
|
1346
|
+
// pass the result to the parent
|
|
1470
1347
|
// const parent = node.parentNode
|
|
1471
1348
|
// if (parent) {
|
|
1472
1349
|
// const parentAsLunchboxNode = parent as Lunchbox.Node
|
|
1473
1350
|
// parentAsLunchboxNode.attached[finalKey] = result
|
|
1474
1351
|
// ; (parentAsLunchboxNode.instance as any)[finalKey] = result
|
|
1475
1352
|
// }
|
|
1476
|
-
|
|
1477
1353
|
} else if (get(target, finalKey, undefined) !== undefined) {
|
|
1478
1354
|
// blank strings evaluate to `true`
|
|
1479
1355
|
// <mesh castShadow receiveShadow /> will work the same as
|
|
@@ -1483,25 +1359,20 @@
|
|
|
1483
1359
|
// if you see this error in production, you might need to add `finalKey`
|
|
1484
1360
|
// to `internalLunchboxVueKeys` below
|
|
1485
1361
|
console.log(`No property ${finalKey} found on ${target}`);
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1362
|
+
}
|
|
1363
|
+
// mark that we need to update if needed
|
|
1489
1364
|
const targetTypeRaw = target?.texture?.type || target?.type;
|
|
1490
|
-
|
|
1491
1365
|
if (typeof targetTypeRaw === 'string') {
|
|
1492
1366
|
const targetType = targetTypeRaw.toLowerCase();
|
|
1493
|
-
|
|
1494
1367
|
switch (true) {
|
|
1495
1368
|
case targetType.includes('material'):
|
|
1496
1369
|
target.needsUpdate = true;
|
|
1497
1370
|
break;
|
|
1498
|
-
|
|
1499
1371
|
case targetType.includes('camera') && target.updateProjectionMatrix:
|
|
1500
1372
|
target.updateProjectionMatrix();
|
|
1501
1373
|
break;
|
|
1502
1374
|
}
|
|
1503
1375
|
}
|
|
1504
|
-
|
|
1505
1376
|
return node;
|
|
1506
1377
|
}
|
|
1507
1378
|
const propertyShortcuts = {
|
|
@@ -1511,8 +1382,8 @@
|
|
|
1511
1382
|
};
|
|
1512
1383
|
const nestedPropertiesToCheck = ['', 'parameters'];
|
|
1513
1384
|
/** props that Lunchbox intercepts and prevents passing to created instances */
|
|
1514
|
-
|
|
1515
|
-
|
|
1385
|
+
const internalLunchboxVueKeys = ['args', 'attach', 'attachArray', 'is.default', 'isDefault', 'key', 'onAdded',
|
|
1386
|
+
// 'onReady',
|
|
1516
1387
|
'ref', 'src'];
|
|
1517
1388
|
|
|
1518
1389
|
const autoAttach = ['geometry', 'material'];
|
|
@@ -1520,55 +1391,48 @@
|
|
|
1520
1391
|
const options = {
|
|
1521
1392
|
type,
|
|
1522
1393
|
props: vnodeProps
|
|
1523
|
-
};
|
|
1524
|
-
|
|
1394
|
+
};
|
|
1395
|
+
// handle dom node
|
|
1525
1396
|
const isDomNode = isLunchboxDomComponent(options);
|
|
1526
|
-
|
|
1527
1397
|
if (isDomNode) {
|
|
1528
1398
|
const node = createDomNode(options);
|
|
1529
1399
|
return node;
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1400
|
+
}
|
|
1401
|
+
// handle standard node
|
|
1402
|
+
const node = createNode(options);
|
|
1403
|
+
// autoattach
|
|
1535
1404
|
autoAttach.forEach(key => {
|
|
1536
1405
|
if (type.toLowerCase().endsWith(key)) {
|
|
1537
1406
|
node.props.attach = key;
|
|
1538
1407
|
}
|
|
1539
|
-
});
|
|
1540
|
-
|
|
1408
|
+
});
|
|
1409
|
+
// TODO: array autoattach
|
|
1541
1410
|
return node;
|
|
1542
1411
|
};
|
|
1543
1412
|
|
|
1544
1413
|
const insert = (child, parent, anchor) => {
|
|
1545
1414
|
if (!parent) {
|
|
1546
1415
|
throw new Error('missing parent');
|
|
1547
|
-
}
|
|
1416
|
+
}
|
|
1417
|
+
// add to parent tree node if we have one
|
|
1548
1418
|
// let effectiveParent = parent ?? ensureRootNode()
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
parent.insertBefore(child, anchor); // handle comment & text nodes
|
|
1552
|
-
|
|
1419
|
+
parent.insertBefore(child, anchor);
|
|
1420
|
+
// handle comment & text nodes
|
|
1553
1421
|
if (child.metaType === 'commentMeta' || child.metaType === 'textMeta') {
|
|
1554
1422
|
return;
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1423
|
+
}
|
|
1424
|
+
// handle dom element
|
|
1558
1425
|
if (isLunchboxDomComponent(child)) {
|
|
1559
1426
|
if (isLunchboxDomComponent(parent) || isLunchboxRootNode(parent)) {
|
|
1560
1427
|
parent.domElement.appendChild(child.domElement);
|
|
1561
1428
|
}
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1429
|
+
}
|
|
1430
|
+
// handle standard nodes
|
|
1565
1431
|
if (isLunchboxStandardNode(child)) {
|
|
1566
1432
|
// let effectiveParent = parent
|
|
1567
1433
|
let effectiveParentNodeType = parent.metaType;
|
|
1568
|
-
|
|
1569
1434
|
if (effectiveParentNodeType === 'textMeta' || effectiveParentNodeType === 'commentMeta') {
|
|
1570
1435
|
const path = parent.getPath();
|
|
1571
|
-
|
|
1572
1436
|
for (let i = path.length - 1; i >= 0; i--) {
|
|
1573
1437
|
if (path[i].metaType !== 'textMeta' && path[i].metaType !== 'commentMeta') {
|
|
1574
1438
|
parent = path[i];
|
|
@@ -1576,26 +1440,23 @@
|
|
|
1576
1440
|
}
|
|
1577
1441
|
}
|
|
1578
1442
|
}
|
|
1579
|
-
|
|
1580
1443
|
if (isLunchboxStandardNode(child) && child.instance?.isObject3D && isLunchboxStandardNode(parent) && parent.instance?.isObject3D) {
|
|
1581
1444
|
parent.instance?.add?.(child.instance);
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1445
|
+
}
|
|
1446
|
+
// add attached props
|
|
1585
1447
|
if (child?.props?.attach && isLunchboxStandardNode(parent) && parent?.instance) {
|
|
1586
1448
|
// if this element is a loader and the `src` attribute is being used,
|
|
1587
1449
|
// let's assume we want to create the loader and run `load`
|
|
1588
|
-
const isUsingLoaderSugar = child.type?.toLowerCase().endsWith('loader') && child.props.src && (child.props.attach || child.props.attachArray);
|
|
1589
|
-
|
|
1450
|
+
const isUsingLoaderSugar = child.type?.toLowerCase().endsWith('loader') && child.props.src && (child.props.attach || child.props.attachArray);
|
|
1451
|
+
// run special loader behavior
|
|
1590
1452
|
if (isUsingLoaderSugar) {
|
|
1591
1453
|
runLoader(child, parent);
|
|
1592
1454
|
} else {
|
|
1593
1455
|
// update attached normally
|
|
1594
1456
|
attachToParentInstance(child, parent, child.props.attach);
|
|
1595
1457
|
}
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1458
|
+
}
|
|
1459
|
+
// fire onAdded event
|
|
1599
1460
|
if (child.props?.onAdded) {
|
|
1600
1461
|
child.props.onAdded({
|
|
1601
1462
|
instance: child.instance
|
|
@@ -1603,15 +1464,13 @@
|
|
|
1603
1464
|
}
|
|
1604
1465
|
}
|
|
1605
1466
|
};
|
|
1606
|
-
|
|
1607
1467
|
function runLoader(child, parent) {
|
|
1608
|
-
const loader = child.instance;
|
|
1609
|
-
|
|
1468
|
+
const loader = child.instance;
|
|
1469
|
+
// ensure parent has attached spaces ready
|
|
1610
1470
|
parent.attached = parent.attached || {};
|
|
1611
|
-
parent.attachedArray = parent.attachedArray || {};
|
|
1612
|
-
|
|
1471
|
+
parent.attachedArray = parent.attachedArray || {};
|
|
1472
|
+
// this should never be true, but just in case
|
|
1613
1473
|
if (!child.props.attach) return;
|
|
1614
|
-
|
|
1615
1474
|
if (child.type?.toLowerCase() === 'textureloader') {
|
|
1616
1475
|
// if this is a texture loader, immediately pass
|
|
1617
1476
|
// load function to parent attachment
|
|
@@ -1627,11 +1486,9 @@
|
|
|
1627
1486
|
});
|
|
1628
1487
|
}
|
|
1629
1488
|
}
|
|
1630
|
-
|
|
1631
1489
|
function attachToParentInstance(child, parent, key, value) {
|
|
1632
1490
|
const finalValueToAttach = value ?? child.instance;
|
|
1633
1491
|
const parentInstanceAsAny = parent.instance;
|
|
1634
|
-
|
|
1635
1492
|
if (child.props.attach === key) {
|
|
1636
1493
|
parent.attached = {
|
|
1637
1494
|
[key]: finalValueToAttach,
|
|
@@ -1639,40 +1496,38 @@
|
|
|
1639
1496
|
};
|
|
1640
1497
|
parentInstanceAsAny[key] = value ?? child.instance;
|
|
1641
1498
|
}
|
|
1642
|
-
|
|
1643
1499
|
if (child.props.attachArray === key) {
|
|
1644
1500
|
if (!parent.attachedArray[child.props.attachArray]) {
|
|
1645
1501
|
parent.attachedArray[child.props.attachArray] = [];
|
|
1646
1502
|
}
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1503
|
+
parent.attachedArray[child.props.attachArray].push(finalValueToAttach);
|
|
1504
|
+
// TODO: implement auto-attaching array
|
|
1650
1505
|
parentInstanceAsAny[key] = [parentInstanceAsAny[key]];
|
|
1651
1506
|
}
|
|
1652
1507
|
}
|
|
1653
1508
|
|
|
1654
1509
|
const remove = node => {
|
|
1655
|
-
if (!node) return;
|
|
1656
|
-
|
|
1510
|
+
if (!node) return;
|
|
1511
|
+
// prep subtree
|
|
1657
1512
|
const subtree = [];
|
|
1658
1513
|
node.walk(descendant => {
|
|
1659
1514
|
subtree.push(descendant);
|
|
1660
1515
|
return true;
|
|
1661
|
-
});
|
|
1662
|
-
|
|
1516
|
+
});
|
|
1517
|
+
// clean up subtree
|
|
1663
1518
|
subtree.forEach(n => {
|
|
1664
1519
|
if (isLunchboxStandardNode(n)) {
|
|
1665
1520
|
// try to remove three object
|
|
1666
|
-
n.instance?.removeFromParent?.();
|
|
1667
|
-
|
|
1668
|
-
const dispose =
|
|
1521
|
+
n.instance?.removeFromParent?.();
|
|
1522
|
+
// try to dispose three object
|
|
1523
|
+
const dispose =
|
|
1524
|
+
// calling `dispose` on a scene triggers an error,
|
|
1669
1525
|
// so let's ignore if this node is a scene
|
|
1670
1526
|
n.type !== 'scene' && n.instance?.dispose;
|
|
1671
1527
|
if (dispose) dispose.bind(n.instance)();
|
|
1672
1528
|
n.instance = null;
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1529
|
+
}
|
|
1530
|
+
// drop tree node
|
|
1676
1531
|
n.drop();
|
|
1677
1532
|
});
|
|
1678
1533
|
};
|
|
@@ -1680,45 +1535,38 @@
|
|
|
1680
1535
|
/*
|
|
1681
1536
|
Elements are `create`d from the outside in, then `insert`ed from the inside out.
|
|
1682
1537
|
*/
|
|
1683
|
-
|
|
1684
1538
|
const createNodeOps = () => {
|
|
1685
1539
|
// APP-LEVEL GLOBALS
|
|
1686
1540
|
// ====================
|
|
1687
1541
|
// These need to exist at the app level in a place where the node ops can access them.
|
|
1688
1542
|
// It'd be better to set these via `app.provide` at app creation, but the node ops need access
|
|
1689
1543
|
// to these values before the app is instantiated, so this is the next-best place for them to exist.
|
|
1690
|
-
const interactables = vue.ref([]);
|
|
1544
|
+
const interactables = vue.ref([]);
|
|
1545
|
+
// NODE OPS
|
|
1691
1546
|
// ====================
|
|
1692
|
-
|
|
1693
1547
|
const nodeOps = {
|
|
1694
1548
|
createElement,
|
|
1695
|
-
|
|
1696
1549
|
createText(text) {
|
|
1697
1550
|
return createTextNode({
|
|
1698
1551
|
text
|
|
1699
1552
|
});
|
|
1700
1553
|
},
|
|
1701
|
-
|
|
1702
1554
|
createComment(text) {
|
|
1703
1555
|
return createCommentNode({
|
|
1704
1556
|
text
|
|
1705
1557
|
});
|
|
1706
1558
|
},
|
|
1707
|
-
|
|
1708
1559
|
insert,
|
|
1709
|
-
|
|
1710
1560
|
nextSibling(node) {
|
|
1711
1561
|
const result = node.nextSibling;
|
|
1712
1562
|
if (!result) return null;
|
|
1713
1563
|
return result;
|
|
1714
1564
|
},
|
|
1715
|
-
|
|
1716
1565
|
parentNode(node) {
|
|
1717
1566
|
const result = node.parentNode;
|
|
1718
1567
|
if (!result) return null;
|
|
1719
1568
|
return result;
|
|
1720
1569
|
},
|
|
1721
|
-
|
|
1722
1570
|
patchProp(node, key, prevValue, nextValue) {
|
|
1723
1571
|
if (isLunchboxDomComponent(node)) {
|
|
1724
1572
|
// handle DOM node
|
|
@@ -1730,16 +1578,13 @@
|
|
|
1730
1578
|
} else {
|
|
1731
1579
|
node.domElement.setAttribute(key, nextValue);
|
|
1732
1580
|
}
|
|
1733
|
-
|
|
1734
1581
|
return;
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1582
|
+
}
|
|
1583
|
+
// ignore if root node, or Lunchbox internal prop
|
|
1738
1584
|
if (isLunchboxRootNode(node) || key.startsWith('$')) {
|
|
1739
1585
|
return;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1586
|
+
}
|
|
1587
|
+
// otherwise, update prop
|
|
1743
1588
|
updateObjectProp({
|
|
1744
1589
|
node: node,
|
|
1745
1590
|
key,
|
|
@@ -1747,15 +1592,13 @@
|
|
|
1747
1592
|
value: nextValue
|
|
1748
1593
|
});
|
|
1749
1594
|
},
|
|
1750
|
-
|
|
1751
1595
|
remove,
|
|
1752
|
-
|
|
1753
|
-
|
|
1596
|
+
setElementText() {
|
|
1597
|
+
// noop
|
|
1754
1598
|
},
|
|
1755
|
-
|
|
1756
|
-
|
|
1599
|
+
setText() {
|
|
1600
|
+
// noop
|
|
1757
1601
|
}
|
|
1758
|
-
|
|
1759
1602
|
};
|
|
1760
1603
|
return {
|
|
1761
1604
|
nodeOps,
|
|
@@ -1764,18 +1607,14 @@
|
|
|
1764
1607
|
};
|
|
1765
1608
|
|
|
1766
1609
|
/** The current camera as a computed value. */
|
|
1767
|
-
|
|
1768
1610
|
const useCamera = () => vue.inject(appCameraKey);
|
|
1769
1611
|
/** Run a function using the current camera when it's present. */
|
|
1770
|
-
|
|
1771
1612
|
const onCameraReady = cb => {
|
|
1772
1613
|
const existing = useCamera();
|
|
1773
|
-
|
|
1774
1614
|
if (existing.value) {
|
|
1775
1615
|
cb(existing.value);
|
|
1776
1616
|
return;
|
|
1777
1617
|
}
|
|
1778
|
-
|
|
1779
1618
|
let stopWatch = null;
|
|
1780
1619
|
stopWatch = vue.watch(useCamera(), newVal => {
|
|
1781
1620
|
if (newVal) {
|
|
@@ -1785,18 +1624,14 @@
|
|
|
1785
1624
|
});
|
|
1786
1625
|
};
|
|
1787
1626
|
/** The current renderer as a computed value. */
|
|
1788
|
-
|
|
1789
1627
|
const useRenderer = () => vue.inject(appRenderersKey);
|
|
1790
1628
|
/** Run a function using the current renderer when it's present. */
|
|
1791
|
-
|
|
1792
1629
|
const onRendererReady = cb => {
|
|
1793
1630
|
const existing = useRenderer();
|
|
1794
|
-
|
|
1795
1631
|
if (existing.value) {
|
|
1796
1632
|
cb(existing.value);
|
|
1797
1633
|
return;
|
|
1798
1634
|
}
|
|
1799
|
-
|
|
1800
1635
|
let stopWatch = null;
|
|
1801
1636
|
stopWatch = vue.watch(useRenderer(), newVal => {
|
|
1802
1637
|
if (newVal) {
|
|
@@ -1808,18 +1643,14 @@
|
|
|
1808
1643
|
});
|
|
1809
1644
|
};
|
|
1810
1645
|
/** The current scene as a computed value. */
|
|
1811
|
-
|
|
1812
1646
|
const useScene = () => vue.inject(appSceneKey);
|
|
1813
1647
|
/** Run a function using the current scene when it's present. */
|
|
1814
|
-
|
|
1815
1648
|
const onSceneReady = cb => {
|
|
1816
1649
|
const existing = useScene();
|
|
1817
|
-
|
|
1818
1650
|
if (existing.value) {
|
|
1819
1651
|
cb(existing.value);
|
|
1820
1652
|
return;
|
|
1821
1653
|
}
|
|
1822
|
-
|
|
1823
1654
|
let stopWatch = null;
|
|
1824
1655
|
stopWatch = vue.watch(useScene(), newVal => {
|
|
1825
1656
|
if (newVal) {
|
|
@@ -1829,16 +1660,15 @@
|
|
|
1829
1660
|
}, {
|
|
1830
1661
|
immediate: true
|
|
1831
1662
|
});
|
|
1832
|
-
};
|
|
1663
|
+
};
|
|
1664
|
+
// CUSTOM RENDER SUPPORT
|
|
1833
1665
|
// ====================
|
|
1834
|
-
|
|
1835
1666
|
/** Set a custom render function, overriding the Lunchbox app's default render function.
|
|
1836
1667
|
* Changing this requires the user to manually render their scene.
|
|
1837
1668
|
*
|
|
1838
1669
|
* Invokes immediately - use `useCustomRender().setCustomRender`
|
|
1839
1670
|
* if you need to call somewhere outside of `setup`.
|
|
1840
1671
|
*/
|
|
1841
|
-
|
|
1842
1672
|
const setCustomRender = render => {
|
|
1843
1673
|
useCustomRender()?.setCustomRender?.(render);
|
|
1844
1674
|
};
|
|
@@ -1847,24 +1677,20 @@
|
|
|
1847
1677
|
* Invokes immediately - use `useCustomRender().clearCustomRender`
|
|
1848
1678
|
* if you need to call somewhere outside of `setup`.
|
|
1849
1679
|
*/
|
|
1850
|
-
|
|
1851
1680
|
const clearCustomRender = () => {
|
|
1852
1681
|
useCustomRender()?.clearCustomRender?.();
|
|
1853
1682
|
};
|
|
1854
1683
|
/** Provides `setCustomRender` and `clearCustomRender` functions to be called in a non-`setup` context. */
|
|
1855
|
-
|
|
1856
1684
|
const useCustomRender = () => {
|
|
1857
1685
|
return {
|
|
1858
1686
|
/** Set a custom render function, overriding the Lunchbox app's default render function.
|
|
1859
1687
|
* Changing this requires the user to manually render their scene. */
|
|
1860
1688
|
setCustomRender: vue.inject(setCustomRenderKey),
|
|
1861
|
-
|
|
1862
1689
|
/** Clear the active app's custom render function. */
|
|
1863
1690
|
clearCustomRender: vue.inject(clearCustomRenderKey)
|
|
1864
1691
|
};
|
|
1865
1692
|
};
|
|
1866
1693
|
/** Use app-level globals. */
|
|
1867
|
-
|
|
1868
1694
|
const useGlobals = () => vue.inject(globalsInjectionKey);
|
|
1869
1695
|
/** Construct a function to update your app-level globals.
|
|
1870
1696
|
*
|
|
@@ -1876,29 +1702,23 @@
|
|
|
1876
1702
|
* updateGlobals({ dpr: 2 })
|
|
1877
1703
|
* ```
|
|
1878
1704
|
*/
|
|
1879
|
-
|
|
1880
1705
|
const useUpdateGlobals = () => vue.inject(updateGlobalsInjectionKey);
|
|
1881
1706
|
/** Update app-level globals.
|
|
1882
1707
|
*
|
|
1883
1708
|
* Invokes immediately - use `useUpdateGlobals`
|
|
1884
1709
|
* if you need to call somewhere outside of `setup`.
|
|
1885
1710
|
*/
|
|
1886
|
-
|
|
1887
1711
|
const updateGlobals = newValue => {
|
|
1888
1712
|
useUpdateGlobals()?.(newValue);
|
|
1889
1713
|
};
|
|
1890
1714
|
/** Use the current Lunchbox app. Usually used internally by Lunchbox. */
|
|
1891
|
-
|
|
1892
1715
|
const useApp = () => vue.inject(appKey);
|
|
1893
1716
|
/** Obtain a list of the start callback functions. Usually used internally by Lunchbox. */
|
|
1894
|
-
|
|
1895
1717
|
const useStartCallbacks = () => vue.inject(startCallbackKey);
|
|
1896
1718
|
/** Run a given callback once when the Lunchbox app starts. Include an index to
|
|
1897
1719
|
* splice the callback at that index in the callback queue. */
|
|
1898
|
-
|
|
1899
1720
|
const onStart = (cb, index = Infinity) => {
|
|
1900
1721
|
const callbacks = useStartCallbacks();
|
|
1901
|
-
|
|
1902
1722
|
if (index === Infinity) {
|
|
1903
1723
|
callbacks?.push(cb);
|
|
1904
1724
|
} else {
|
|
@@ -1906,41 +1726,39 @@
|
|
|
1906
1726
|
}
|
|
1907
1727
|
};
|
|
1908
1728
|
/** Obtain a list of interactable objects (registered via onClick, onHover, etc events). Usually used internally by Lunchbox. */
|
|
1909
|
-
|
|
1910
1729
|
const useLunchboxInteractables = () => vue.inject(lunchboxInteractables);
|
|
1911
1730
|
/** Build a computed instance-getter from a specified ref. Defaults to a `toRaw`'d result. */
|
|
1912
|
-
|
|
1913
1731
|
const getInstance = (target, raw = true) => vue.computed(() => {
|
|
1914
1732
|
const output = target.value?.$el?.instance ?? target.value?.instance ?? null;
|
|
1915
1733
|
if (output && raw) return vue.toRaw(output);
|
|
1916
1734
|
return output;
|
|
1917
|
-
});
|
|
1735
|
+
});
|
|
1736
|
+
// CREATE APP
|
|
1918
1737
|
// ====================
|
|
1919
|
-
|
|
1920
|
-
const createApp = root => {
|
|
1738
|
+
const createApp = (root, rootProps = {}) => {
|
|
1921
1739
|
const {
|
|
1922
1740
|
nodeOps,
|
|
1923
1741
|
interactables
|
|
1924
1742
|
} = createNodeOps();
|
|
1925
|
-
const app = vue.createRenderer(nodeOps).createApp(root);
|
|
1743
|
+
const app = vue.createRenderer(nodeOps).createApp(root, rootProps);
|
|
1744
|
+
// provide Lunchbox interaction handlers flag (modified when user references events via
|
|
1926
1745
|
// @click, etc)
|
|
1927
|
-
|
|
1928
|
-
|
|
1746
|
+
app.provide(lunchboxInteractables, interactables);
|
|
1747
|
+
// register all components
|
|
1929
1748
|
// ====================
|
|
1930
|
-
|
|
1931
1749
|
Object.keys(components).forEach(key => {
|
|
1932
1750
|
app?.component(key, components[key]);
|
|
1933
|
-
});
|
|
1751
|
+
});
|
|
1752
|
+
// provide custom renderer functions
|
|
1934
1753
|
// ====================
|
|
1935
|
-
|
|
1936
1754
|
app.provide(setCustomRenderKey, render => {
|
|
1937
1755
|
app.setCustomRender(render);
|
|
1938
1756
|
});
|
|
1939
1757
|
app.provide(clearCustomRenderKey, () => {
|
|
1940
1758
|
app.clearCustomRender();
|
|
1941
|
-
});
|
|
1759
|
+
});
|
|
1760
|
+
// before render
|
|
1942
1761
|
// ====================
|
|
1943
|
-
|
|
1944
1762
|
const beforeRender = [];
|
|
1945
1763
|
app.provide(beforeRenderKey, beforeRender);
|
|
1946
1764
|
app.provide(onBeforeRenderKey, (cb, index = Infinity) => {
|
|
@@ -1955,14 +1773,13 @@
|
|
|
1955
1773
|
beforeRender.splice(cb, 1);
|
|
1956
1774
|
} else {
|
|
1957
1775
|
const idx = beforeRender.findIndex(v => v == cb);
|
|
1958
|
-
|
|
1959
1776
|
if (idx !== -1) {
|
|
1960
1777
|
beforeRender.splice(idx, 1);
|
|
1961
1778
|
}
|
|
1962
1779
|
}
|
|
1963
|
-
});
|
|
1780
|
+
});
|
|
1781
|
+
// after render
|
|
1964
1782
|
// ====================
|
|
1965
|
-
|
|
1966
1783
|
const afterRender = [];
|
|
1967
1784
|
app.provide(afterRenderKey, afterRender);
|
|
1968
1785
|
app.provide(onAfterRenderKey, (cb, index = Infinity) => {
|
|
@@ -1977,14 +1794,13 @@
|
|
|
1977
1794
|
afterRender.splice(cb, 1);
|
|
1978
1795
|
} else {
|
|
1979
1796
|
const idx = afterRender.findIndex(v => v == cb);
|
|
1980
|
-
|
|
1981
1797
|
if (idx !== -1) {
|
|
1982
1798
|
afterRender.splice(idx, 1);
|
|
1983
1799
|
}
|
|
1984
1800
|
}
|
|
1985
|
-
});
|
|
1801
|
+
});
|
|
1802
|
+
// save app-level components
|
|
1986
1803
|
// ====================
|
|
1987
|
-
|
|
1988
1804
|
app.config.globalProperties.lunchbox = vue.reactive({
|
|
1989
1805
|
afterRender,
|
|
1990
1806
|
beforeRender,
|
|
@@ -1993,35 +1809,34 @@
|
|
|
1993
1809
|
frameId: -1,
|
|
1994
1810
|
renderer: null,
|
|
1995
1811
|
scene: null,
|
|
1996
|
-
watchStopHandle: null
|
|
1997
|
-
|
|
1998
|
-
});
|
|
1812
|
+
watchStopHandle: null
|
|
1813
|
+
// TODO: inputActive, mousePos
|
|
1814
|
+
});
|
|
1815
|
+
// provide app-level globals & globals update method
|
|
1999
1816
|
// ====================
|
|
2000
|
-
|
|
2001
1817
|
app.provide(globalsInjectionKey, app.config.globalProperties.lunchbox);
|
|
2002
1818
|
app.provide(updateGlobalsInjectionKey, newGlobals => {
|
|
2003
1819
|
Object.keys(newGlobals).forEach(key => {
|
|
2004
|
-
const typedKey = key;
|
|
2005
|
-
|
|
1820
|
+
const typedKey = key;
|
|
1821
|
+
// TODO: fix
|
|
2006
1822
|
app.config.globalProperties.lunchbox[typedKey] = newGlobals[typedKey];
|
|
2007
1823
|
});
|
|
2008
|
-
});
|
|
1824
|
+
});
|
|
1825
|
+
// frame ID (used for update functions)
|
|
2009
1826
|
// ====================
|
|
2010
|
-
|
|
2011
|
-
|
|
1827
|
+
app.provide(frameIdKey, app.config.globalProperties.lunchbox.frameId);
|
|
1828
|
+
// watch stop handler (used for conditional update loop)
|
|
2012
1829
|
// ====================
|
|
2013
|
-
|
|
2014
|
-
|
|
1830
|
+
app.provide(watchStopHandleKey, app.config.globalProperties.lunchbox.watchStopHandle);
|
|
1831
|
+
// update mount function to match Lunchbox.Node
|
|
2015
1832
|
// ====================
|
|
2016
|
-
|
|
2017
1833
|
const {
|
|
2018
1834
|
mount
|
|
2019
1835
|
} = app;
|
|
2020
|
-
|
|
2021
1836
|
app.mount = (root, ...args) => {
|
|
2022
1837
|
// find DOM element to use as app root
|
|
2023
|
-
const domElement = typeof root === 'string' ? document.querySelector(root) : root;
|
|
2024
|
-
|
|
1838
|
+
const domElement = typeof root === 'string' ? document.querySelector(root) : root;
|
|
1839
|
+
// create or find root node
|
|
2025
1840
|
const rootNode = new exports.MiniDom.RendererRootNode({
|
|
2026
1841
|
domElement,
|
|
2027
1842
|
isLunchboxRootNode: true,
|
|
@@ -2034,44 +1849,41 @@
|
|
|
2034
1849
|
app.provide(appRootNodeKey, rootNode);
|
|
2035
1850
|
const mounted = mount(rootNode, ...args);
|
|
2036
1851
|
return mounted;
|
|
2037
|
-
};
|
|
1852
|
+
};
|
|
1853
|
+
// embed .extend function
|
|
2038
1854
|
// ====================
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
1855
|
app.extend = targets => {
|
|
2042
1856
|
extend({
|
|
2043
1857
|
app: app,
|
|
2044
1858
|
...targets
|
|
2045
1859
|
});
|
|
2046
1860
|
return app;
|
|
2047
|
-
};
|
|
1861
|
+
};
|
|
1862
|
+
// start callback functions
|
|
2048
1863
|
// ====================
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
1864
|
const startCallbacks = [];
|
|
2052
|
-
app.provide(startCallbackKey, startCallbacks);
|
|
1865
|
+
app.provide(startCallbackKey, startCallbacks);
|
|
1866
|
+
// prep for custom render support
|
|
2053
1867
|
// ====================
|
|
2054
|
-
|
|
2055
1868
|
app.setCustomRender = newRender => {
|
|
2056
1869
|
if (app) {
|
|
2057
1870
|
app.customRender = newRender;
|
|
2058
1871
|
}
|
|
2059
|
-
};
|
|
2060
|
-
|
|
2061
|
-
|
|
1872
|
+
};
|
|
1873
|
+
// add custom render removal
|
|
2062
1874
|
app.clearCustomRender = () => {
|
|
2063
1875
|
if (app) {
|
|
2064
1876
|
app.customRender = null;
|
|
2065
1877
|
}
|
|
2066
|
-
};
|
|
1878
|
+
};
|
|
1879
|
+
// provide app
|
|
2067
1880
|
// ====================
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
1881
|
app.provide(appKey, app);
|
|
2071
1882
|
app.provide(appRenderersKey, vue.computed(() => app.config.globalProperties.lunchbox.renderer));
|
|
2072
1883
|
app.provide(appSceneKey, vue.computed(() => app.config.globalProperties.lunchbox.scene));
|
|
2073
|
-
app.provide(appCameraKey, vue.computed(() => app.config.globalProperties.lunchbox.camera));
|
|
2074
|
-
|
|
1884
|
+
app.provide(appCameraKey, vue.computed(() => app.config.globalProperties.lunchbox.camera));
|
|
1885
|
+
app._props;
|
|
1886
|
+
// done
|
|
2075
1887
|
return app;
|
|
2076
1888
|
};
|
|
2077
1889
|
|
|
@@ -2135,6 +1947,4 @@
|
|
|
2135
1947
|
exports.useUpdateGlobals = useUpdateGlobals;
|
|
2136
1948
|
exports.watchStopHandleKey = watchStopHandleKey;
|
|
2137
1949
|
|
|
2138
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2139
|
-
|
|
2140
1950
|
}));
|