lunchboxjs 0.1.4003 → 0.1.4004
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 +77 -15
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +77 -15
- package/package.json +1 -1
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +47 -9
- package/src/components/LunchboxWrapper/resizeCanvas.ts +12 -4
- package/src/core/ensure.ts +27 -5
- package/src/core/update.ts +1 -1
- package/src/index.ts +1 -1
- package/src/types.ts +3 -0
package/dist/lunchboxjs.js
CHANGED
|
@@ -30,27 +30,36 @@
|
|
|
30
30
|
const resizeCanvas = (width, height) => {
|
|
31
31
|
const renderer = ensureRenderer.value?.instance;
|
|
32
32
|
const scene = ensuredScene.value.instance;
|
|
33
|
+
const camera = ensuredCamera.value;
|
|
33
34
|
// ignore if no element
|
|
34
|
-
if (!renderer?.domElement || !scene)
|
|
35
|
+
if (!renderer?.domElement || !scene || !camera)
|
|
35
36
|
return;
|
|
36
37
|
width = width ?? window.innerWidth;
|
|
37
38
|
height = height ?? window.innerHeight;
|
|
38
39
|
// update camera
|
|
39
40
|
const aspect = width / height;
|
|
40
|
-
const camera = ensuredCamera.value;
|
|
41
41
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
42
42
|
const perspectiveCamera = camera.instance;
|
|
43
43
|
perspectiveCamera.aspect = aspect;
|
|
44
44
|
perspectiveCamera.updateProjectionMatrix();
|
|
45
45
|
}
|
|
46
|
+
else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
47
|
+
// console.log('TODO: ortho camera update')
|
|
48
|
+
const orthoCamera = camera.instance;
|
|
49
|
+
const heightInTermsOfWidth = height / width;
|
|
50
|
+
orthoCamera.top = heightInTermsOfWidth * 10;
|
|
51
|
+
orthoCamera.bottom = -heightInTermsOfWidth * 10;
|
|
52
|
+
orthoCamera.right = 10;
|
|
53
|
+
orthoCamera.left = -10;
|
|
54
|
+
orthoCamera.updateProjectionMatrix();
|
|
55
|
+
}
|
|
46
56
|
else {
|
|
47
|
-
console.log('TODO: ortho camera
|
|
57
|
+
console.log('TODO: non-ortho or perspective camera');
|
|
48
58
|
}
|
|
49
59
|
// update canvas
|
|
50
60
|
renderer.setSize(width, height);
|
|
51
61
|
// render immediately so there's no flicker
|
|
52
62
|
if (scene && camera.instance) {
|
|
53
|
-
// const cameraInstance = scene.traverse(v => )
|
|
54
63
|
renderer.render(vue.toRaw(scene), vue.toRaw(camera.instance));
|
|
55
64
|
}
|
|
56
65
|
};
|
|
@@ -95,8 +104,11 @@
|
|
|
95
104
|
props: {
|
|
96
105
|
// These should match the Lunchbox.WrapperProps interface
|
|
97
106
|
background: String,
|
|
107
|
+
cameraArgs: Array,
|
|
98
108
|
cameraPosition: Array,
|
|
99
109
|
dpr: Number,
|
|
110
|
+
ortho: Boolean,
|
|
111
|
+
orthographic: Boolean,
|
|
100
112
|
rendererProperties: Object,
|
|
101
113
|
shadow: [Boolean, Object],
|
|
102
114
|
transparent: Boolean,
|
|
@@ -107,6 +119,7 @@
|
|
|
107
119
|
const dpr = vue.ref(props.dpr ?? -1);
|
|
108
120
|
const container = vue.ref();
|
|
109
121
|
let renderer;
|
|
122
|
+
let camera;
|
|
110
123
|
let scene;
|
|
111
124
|
// MOUNT
|
|
112
125
|
// ====================
|
|
@@ -114,12 +127,6 @@
|
|
|
114
127
|
// canvas needs to exist
|
|
115
128
|
if (!canvas.value)
|
|
116
129
|
throw new Error('missing canvas');
|
|
117
|
-
// ensure camera
|
|
118
|
-
const camera = ensuredCamera.value.instance;
|
|
119
|
-
// move camera if needed
|
|
120
|
-
if (camera && props.cameraPosition) {
|
|
121
|
-
camera.position.set(...props.cameraPosition);
|
|
122
|
-
}
|
|
123
130
|
// RENDERER
|
|
124
131
|
// ====================
|
|
125
132
|
// is there already a renderer?
|
|
@@ -176,6 +183,43 @@
|
|
|
176
183
|
rendererReady.value = true;
|
|
177
184
|
return;
|
|
178
185
|
}
|
|
186
|
+
// CAMERA
|
|
187
|
+
// ====================
|
|
188
|
+
// is there already a camera?
|
|
189
|
+
camera = tryGetNodeWithInstanceType([
|
|
190
|
+
'PerspectiveCamera',
|
|
191
|
+
'OrthographicCamera',
|
|
192
|
+
]);
|
|
193
|
+
// if not, let's create one
|
|
194
|
+
if (!camera) {
|
|
195
|
+
// create ortho camera
|
|
196
|
+
if (props.ortho || props.orthographic) {
|
|
197
|
+
// const size: Vector2 = new Vector2()
|
|
198
|
+
ensuredCamera.value = createNode({
|
|
199
|
+
props: { args: props.cameraArgs ?? [] },
|
|
200
|
+
type: 'OrthographicCamera',
|
|
201
|
+
uuid: fallbackCameraUuid,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
ensuredCamera.value = createNode({
|
|
206
|
+
props: {
|
|
207
|
+
args: props.cameraArgs ?? [45, 0.5625, 1, 1000],
|
|
208
|
+
},
|
|
209
|
+
type: 'PerspectiveCamera',
|
|
210
|
+
uuid: fallbackCameraUuid,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
cameraReady.value = true;
|
|
214
|
+
camera = ensuredCamera.value;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
cameraReady.value = true;
|
|
218
|
+
}
|
|
219
|
+
// move camera if needed
|
|
220
|
+
if (camera && props.cameraPosition) {
|
|
221
|
+
camera.instance?.position.set(...props.cameraPosition);
|
|
222
|
+
}
|
|
179
223
|
// SCENE
|
|
180
224
|
// ====================
|
|
181
225
|
scene = ensuredScene.value;
|
|
@@ -202,7 +246,7 @@
|
|
|
202
246
|
// console.log(scene)
|
|
203
247
|
update({
|
|
204
248
|
app: vue.getCurrentInstance().appContext.app,
|
|
205
|
-
camera,
|
|
249
|
+
camera: camera.instance,
|
|
206
250
|
renderer: renderer.instance,
|
|
207
251
|
scene: scene.instance,
|
|
208
252
|
});
|
|
@@ -849,9 +893,27 @@
|
|
|
849
893
|
// ENSURE CAMERA
|
|
850
894
|
// ====================
|
|
851
895
|
const fallbackCameraUuid = 'FALLBACK_CAMERA';
|
|
852
|
-
const
|
|
853
|
-
|
|
896
|
+
const defaultCamera = buildEnsured(['PerspectiveCamera', 'OrthographicCamera'], fallbackCameraUuid, { args: [45, 0.5625, 1, 1000] });
|
|
897
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
898
|
+
* Functions waiting for a Camera need to wait for this to be true. */
|
|
899
|
+
const cameraReady = vue.ref(false);
|
|
900
|
+
const ensuredCamera = vue.computed({
|
|
901
|
+
get() {
|
|
902
|
+
return (cameraReady.value ? defaultCamera.value : null);
|
|
903
|
+
},
|
|
904
|
+
set(val) {
|
|
905
|
+
const t = val.type ?? '';
|
|
906
|
+
const pascalType = t[0].toUpperCase() + t.slice(1);
|
|
907
|
+
overrides[pascalType] = val;
|
|
908
|
+
},
|
|
854
909
|
});
|
|
910
|
+
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
911
|
+
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
912
|
+
// fallbackCameraUuid,
|
|
913
|
+
// {
|
|
914
|
+
// args: [45, 0.5625, 1, 1000],
|
|
915
|
+
// }
|
|
916
|
+
// )
|
|
855
917
|
// ENSURE RENDERER
|
|
856
918
|
// ====================
|
|
857
919
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
@@ -1205,7 +1267,7 @@
|
|
|
1205
1267
|
app: opts.app,
|
|
1206
1268
|
renderer: ensureRenderer.value?.instance,
|
|
1207
1269
|
scene: ensuredScene.value.instance,
|
|
1208
|
-
camera: ensuredCamera.value
|
|
1270
|
+
camera: ensuredCamera.value?.instance,
|
|
1209
1271
|
}));
|
|
1210
1272
|
// prep options
|
|
1211
1273
|
const { app, renderer, scene, camera } = opts;
|
|
@@ -1600,7 +1662,7 @@
|
|
|
1600
1662
|
inputActive,
|
|
1601
1663
|
mousePos,
|
|
1602
1664
|
};
|
|
1603
|
-
const camera = vue.computed(() => ensuredCamera.value
|
|
1665
|
+
const camera = vue.computed(() => ensuredCamera.value?.instance ?? null);
|
|
1604
1666
|
const renderer = vue.computed(() => ensureRenderer.value?.instance ?? null);
|
|
1605
1667
|
const scene = vue.computed(() => ensuredScene.value.instance);
|
|
1606
1668
|
// CUSTOM RENDER SUPPORT
|
package/dist/lunchboxjs.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue"),require("three"),require("lodash")):"function"==typeof define&&define.amd?define(["exports","vue","three","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LunchboxRenderer={},e.vue,e.three,e.lodash)}(this,(function(e,t,n,r){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var a=o(n);const s=[],i=(e,n)=>{const r=$.value?.instance,o=U.value.instance;if(!r?.domElement||!o)return;const a=(e=e??window.innerWidth)/(n=n??window.innerHeight),s=k.value;if("perspectivecamera"===s.type?.toLowerCase()){const e=s.instance;e.aspect=a,e.updateProjectionMatrix()}else console.log("TODO: ortho camera update");r.setSize(e,n),o&&s.instance&&r.render(t.toRaw(o),t.toRaw(s.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraPosition:Array,dpr:Number,rendererProperties:Object,shadow:[Boolean,Object],transparent:Boolean},setup(e,o){const a=t.ref(),s=t.ref(!0),d=t.ref(e.dpr??-1),u=t.ref();let l,p;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");const o=k.value.instance;if(o&&e.cameraPosition&&o.position.set(...e.cameraPosition),l=B(["WebGLRenderer"]),l)return s.value=!1,void(F.value=!0);{const t={antialias:!0,canvas:a.value.domElement};e.transparent&&(t.alpha=!0),$.value=v({type:"WebGLRenderer",uuid:S,props:{args:[t]}}),F.value=!0;const n=$,o={shadow:e.shadow};n.value.instance&&o?.shadow&&(n.value.instance.shadowMap.enabled=!0,"object"==typeof o.shadow&&(n.value.instance.shadowMap.type=o.shadow.type)),e.rendererProperties&&Object.keys(e.rendererProperties).forEach((t=>{r.set(n.value,t,e.rendererProperties[t])})),l=n.value}if(p=U.value,p&&p.instance&&e.background&&(p.instance.background=new n.Color(e.background)),-1===d.value&&(d.value=window.devicePixelRatio),!l?.instance)throw new Error("missing renderer");l.instance.setPixelRatio(d.value),ue.dpr.value=d.value,((e,t,n)=>{const r=e.value?.domElement;if(!r)throw new Error("missing container");i();const o=new ResizeObserver((([e])=>{i()}));r&&o.observe(r),n((()=>{t&&o.unobserve(t)}))})(u,l.instance.domElement,t.onBeforeUnmount),te({app:t.getCurrentInstance().appContext.app,camera:o,renderer:l.instance,scene:p.instance})})),t.onBeforeUnmount((()=>{re()})),()=>[o.slots.default?.()??null,t.h("div",{style:c("absolute"),ref:u},[s.value?t.h("canvas",{style:c("fixed"),class:"lunchbox-canvas",ref:a}):null])]}},u={},l=["canvas","div","LunchboxWrapper"],p={...["mesh","instancedMesh","scene","sprite","object3D","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","sphereGeometry","ringGeometry","planeGeometry","latheGeometry","shapeGeometry","extrudeGeometry","edgesGeometry","coneGeometry","cylinderGeometry","circleGeometry","boxGeometry","material","shadowMaterial","spriteMaterial","rawShaderMaterial","shaderMaterial","pointsMaterial","meshPhysicalMaterial","meshStandardMaterial","meshPhongMaterial","meshToonMaterial","meshNormalMaterial","meshLambertMaterial","meshDepthMaterial","meshDistanceMaterial","meshBasicMaterial","meshMatcapMaterial","lineDashedMaterial","lineBasicMaterial","light","spotLightShadow","spotLight","pointLight","rectAreaLight","hemisphereLight","directionalLightShadow","directionalLight","ambientLight","lightShadow","ambientLightProbe","hemisphereLightProbe","lightProbe","texture","videoTexture","dataTexture","dataTexture3D","compressedTexture","cubeTexture","canvasTexture","depthTexture","textureLoader","group","catmullRomCurve3","points","cameraHelper","camera","perspectiveCamera","orthographicCamera","cubeCamera","arrayCamera","webGLRenderer"].map((e=>t.defineComponent({inheritAttrs:!1,name:e,setup:(n,r)=>()=>t.h(e,r.attrs,r.slots?.default?.()||[])}))).reduce(((e,t)=>(e[t.name]=t,e))),Lunchbox:d};const m=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),h=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return l.includes(t??"")},f=e=>"standardMeta"===e?.metaType,y=e=>e.isLunchboxRootNode;function v(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new H.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||y(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=u[e.type]||a[t];if(!n)throw`${t} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;const r=(e.props.args??[]).map((t=>function({node:e,prop:t}){const n="string"==typeof t&&t.startsWith("$attachedArray"),r=function({node:e,prop:t}){if("string"==typeof t&&t.startsWith("$attachedArray"))return e.attachedArray[t.replace("$attachedArray.","")];if("string"==typeof t&&t.startsWith("$attached"))return e.attached[t.replace("$attached.","")];return t}({node:e,prop:t});return Array.isArray(r)&&n?r:[r]}({node:e,prop:t})));let o=[];r.forEach((e=>{o=o.concat(e)}));return new n(...o)}({...r,props:{...r.props,...t}})),"scene"===r.type&&(U.value=r),r}const b=[],x=t.ref(!1);function g({node:e,key:n,value:r}){var o;if(e.eventListeners[n]||(e.eventListeners[n]=[]),e.eventListenerRemoveFunctions[n]||(e.eventListenerRemoveFunctions[n]=[]),e.eventListeners[n].push(r),R.includes(n)&&(W.value,e.instance&&!b.includes(e)&&(o=e,b.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=b.indexOf(e);-1!==t&&b.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>x.value),(t=>{const r=P.map((e=>e.element)).findIndex((t=>t.instance&&t.instance.uuid===e.instance?.uuid));-1!==r&&((!t||"onClick"!==n&&"onPointerDown"!==n)&&(t||"onPointerUp"!==n)||e.eventListeners[n].forEach((e=>{e({intersection:P[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const R=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let w,E,A;const C=t.ref({x:1/0,y:1/0});let L=!1;let P=[];const M=()=>{const e=W.value?.instance,t=k.value?.instance;if(!e||!t)return;e.setFromCamera(ue.mousePos.value,t);const n=e.intersectObjects(b.map((e=>e.instance)));let r=[],o=[],a=[];r=P.map((e=>e.intersection)),n?.forEach((e=>{const t=P.findIndex((t=>t.intersection.object===e.object));if(-1===t){const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=b.find((t=>t.instance?.uuid===e.object.uuid));t&&a.push({element:t,intersection:e})}const n=r.findIndex((t=>t.object.uuid===e.object.uuid));-1!==n&&r.splice(n,1)}));const s=r.map((e=>({element:b.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{G({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),P=[].concat(o,a)},G=({element:e,eventKeys:t,intersection:n})=>{e&&t.forEach((t=>{e.eventListeners[t]&&e.eventListeners[t].forEach((e=>{e({intersection:n})}))}))};function N(t={}){return e.lunchboxTree||(e.lunchboxTree=new H.RendererRootNode(t)),e.lunchboxTree}function B(e){Array.isArray(e)||(e=[e]);for(let t of e)if(O[t])return O[t];for(let t of e){const e=T[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return T[t]=n,n}}return null}e.lunchboxTree=void 0;const T=t.reactive({}),O=t.reactive({});function j(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)T[t]||(T[t]=null),O[t]||(O[t]=null);return t.computed({get(){const t=B(e);if(t)return t;const a=N(),s=v({type:e[0],uuid:n,props:r});return a.addChild(s),T[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}})}const k=j(["PerspectiveCamera","OrthographicCamera"],"FALLBACK_CAMERA",{args:[45,.5625,1,1e3]}),S="FALLBACK_RENDERER",D=j(["WebGLRenderer"],S,{}),F=t.ref(!1),$=t.computed({get:()=>F.value?D.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),U=j("Scene","FALLBACK_SCENE"),W=j("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>$.value),(e=>{e?.instance&&(L||(w=t=>{const n=(e.instance.domElement.width??1)/ue.dpr.value,r=(e.instance.domElement.height??1)/ue.dpr.value;C.value.x=t.offsetX/n*2-1,C.value.y=-t.offsetY/r*2+1},E=()=>x.value=!0,A=()=>x.value=!1,e.instance.domElement.addEventListener("mousemove",w),e.instance.domElement.addEventListener("mousedown",E),e.instance.domElement.addEventListener("mouseup",A),ne(M),L=!0),n&&n())}),{immediate:!0})})(e))),I=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var K,_=new Uint8Array(16);function V(){if(!K&&!(K="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return K(_)}var q=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function z(e){return"string"==typeof e&&q.test(e)}for(var H,Y=[],X=0;X<256;++X)Y.push((X+256).toString(16).substr(1));function J(e,t,n){var r=(e=e||{}).random||(e.rng||V)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(var o=0;o<16;++o)t[n+o]=r[o];return t}return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=(Y[e[t+0]]+Y[e[t+1]]+Y[e[t+2]]+Y[e[t+3]]+"-"+Y[e[t+4]]+Y[e[t+5]]+"-"+Y[e[t+6]]+Y[e[t+7]]+"-"+Y[e[t+8]]+Y[e[t+9]]+"-"+Y[e[t+10]]+Y[e[t+11]]+Y[e[t+12]]+Y[e[t+13]]+Y[e[t+14]]+Y[e[t+15]]).toLowerCase();if(!z(n))throw TypeError("Stringified UUID is invalid");return n}(r)}!function(e){e.BaseNode=class{constructor(e={},t){this.parentNode=e?.parentNode??t??null,this.minidomType="MinidomBaseNode",this.uuid=e?.uuid??J(),s.push(this)}uuid;parentNode;get nextSibling(){if(!this.parentNode)return null;const e=this.parentNode.children.findIndex((e=>e.uuid===this.uuid));return-1!==e&&e<this.parentNode.children.length-1?this.parentNode.children[e+1]:null}insertBefore(e,t){e.removeAsChildFromAnyParents(),e.parentNode=this;const n=this.children.findIndex((e=>e.uuid===t?.uuid));-1!==n?this.children.splice(n,0,e):this.children.push(e)}removeChild(e){const t=this.children.findIndex((t=>t?.uuid===e?.uuid));-1!==t&&this.children.splice(t,1)}children=[];addChild(e){return e&&(e.removeAsChildFromAnyParents(),e.parentNode=this,this.insertBefore(e,null)),this}getPath(){const e=[];let t=this;for(;t;)e.unshift(t),t=t.parentNode;return e}drop(){this.parentNode=null,this.removeAsChildFromAnyParents()}walk(e){const t=[this,...this.children],n=[];let r=!0;for(;t.length&&r;){const o=t.shift();if(o){if(n.includes(o))continue;n.push(o),t.push(...o.children.filter((e=>!n.includes(e)))),r=e(o)}else r=!1}}minidomType;removeAsChildFromAnyParents(){s.forEach((e=>e.removeChild(this)))}};class t extends e.BaseNode{constructor(e={},t){super(e,t),this.minidomType="RendererNode",this.eventListeners={},this.eventListenerRemoveFunctions={},this.name=e.name??"",this.metaType=e.metaType??"standardMeta",this.props=e.props??[],this.type=e.type??""}eventListeners;eventListenerRemoveFunctions;name;metaType;props;type;drop(){super.drop(),Object.keys(this.eventListenerRemoveFunctions).forEach((e=>{this.eventListenerRemoveFunctions[e].forEach((e=>e()))}))}}e.RendererBaseNode=t;class n extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement;isLunchboxRootNode=!0}e.RendererRootNode=n;class r extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererCommentNode=r;class o extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement}e.RendererDomNode=o;class a extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererTextNode=a;class i extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.attached=e.attached??[],this.attachedArray=e.attachedArray??{},this.instance=e.instance??null}attached;attachedArray;instance}e.RendererStandardNode=i}(H||(H={}));let Q;(new H.RendererRootNode).minidomType="RootNode";const Z=[],ee=[],te=e=>{Q=requestAnimationFrame((()=>te({app:e.app,renderer:$.value?.instance,scene:U.value.instance,camera:k.value.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;Z.forEach((t=>{t&&t(e)})),r&&o&&a&&(n.customRender?n.customRender(e):r.render(t.toRaw(o),t.toRaw(a))),ee.forEach((t=>{t&&t(e)}))},ne=(e,t=1/0)=>{t===1/0?Z.push(e):Z.splice(t,0,e)},re=()=>{Q&&cancelAnimationFrame(Q)};const oe={x:"position.x",y:"position.y",z:"position.z"},ae=["","parameters"],se=["args","attach","attachArray","key","onAdded","ref","src"],ie=["geometry","material"];function ce(e,t,n,r){const o=r??e.instance,a=t.instance;e.props.attach===n&&(t.attached={[n]:o,...t.attached||{}},a[n]=r??e.instance),e.props.attachArray===n&&(t.attachedArray[e.props.attachArray]||(t.attachedArray[e.props.attachArray]=[]),t.attachedArray[e.props.attachArray].push(o),a[n]=[a[n]])}const de={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(h(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new H.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=v(o);return ie.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new H.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new H.RendererCommentNode({...t,...e,metaType:"commentMeta"})}({text:e}),insert:(e,t,n)=>{let r=t??N();if(r.insertBefore(e,n),"commentMeta"!==e.metaType&&"textMeta"!==e.metaType&&(h(e)&&(h(t)||y(t))&&t.domElement.appendChild(e.domElement),f(e))){let n=r.metaType;if("textMeta"===n||"commentMeta"===n){const e=r.getPath();for(let t=e.length-1;t>=0;t--)if("textMeta"!==e[t].metaType&&"commentMeta"!==e[t].metaType){r=e[t];break}}if("standardMeta"===e.metaType&&"scene"!==e.type&&y(r)){const t=U.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else f(e)&&e.instance?.isObject3D&&f(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&f(t)&&t?.instance){e.type?.toLowerCase().endsWith("loader")&&e.props.src&&(e.props.attach||e.props.attachArray)?function(e,t){const n=e.instance;if(t.attached=t.attached||{},t.attachedArray=t.attachedArray||{},!e.props.attach)return;if("textureloader"===e.type?.toLowerCase()){const r=n.load(e.props.src);ce(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{ce(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):ce(e,t,e.props.attach)}e.props?.onAdded&&e.props.onAdded({instance:e.instance})}},nextSibling(e){const t=e.nextSibling;return t||null},parentNode(e){const t=e.parentNode;return t||null},patchProp(e,t,n,o){h(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):y(e)||t.startsWith("$")||function({node:e,key:t,value:n}){if((e=>["onClick","onContextMenu","onDoubleClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove","onWheel"].includes(e))(t))return g({node:e,key:t,value:n});if(se.includes(t))return e;if(!f(e))return e;if("string"==typeof n&&n.startsWith("$attached")){const t=n.replace("$attached.","");n=r.get(e.attached,t,null)}const o=e.instance;if(!o)return e;const a=t.replace(/-/g,".");let s,i=oe[a]||a;for(let e=0;e<ae.length&&!s;e++){const t=[ae[e],i].filter(Boolean).join(".");s=s=r.get(o,t)}if(s&&r.isNumber(n)&&s.setScalar)s.setScalar(n);else if(s&&s.set){const e=Array.isArray(n)?n:[n];o[i].set(...e)}else"function"==typeof s?s.bind(e.instance)(...n):void 0!==r.get(o,i,void 0)?r.set(o,i,""===n||n):console.log(`No property ${i} found on ${o}`);const c=o?.texture?.type||o?.type;if("string"==typeof c){const e=c.toLowerCase();switch(!0){case e.includes("material"):o.needsUpdate=!0;break;case e.includes("camera")&&o.updateProjectionMatrix:o.updateProjectionMatrix()}}}({node:e,key:t,value:o})},remove:e=>{if(!e)return;const t=Object.keys(O),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>O[t]?.uuid===e.uuid));if(n&&(O[n]=null),f(e)){e.instance?.removeFromParent?.();const t="scene"!==e.type&&e.instance?.dispose;t&&t.bind(e.instance)(),e.instance=null}e.drop();const r=s.findIndex((t=>t.uuid===e.uuid));-1!==r&&s.splice(r,1)}))},setElementText(){},setText(){}},ue={dpr:t.ref(1),inputActive:x,mousePos:C},le=t.computed((()=>k.value.instance)),pe=t.computed((()=>$.value?.instance??null)),me=t.computed((()=>U.value.instance));let he=null,fe=null;e.camera=le,e.clearCustomRender=()=>{he?he.clearCustomRender():fe=null},e.createApp=e=>{he=t.createRenderer(de).createApp(e),Object.keys(p).forEach((e=>{he.component(e,p[e])}));const{mount:n}=he;return he.mount=(e,...t)=>{const r=N({domElement:"string"==typeof e?document.querySelector(e):e,isLunchboxRootNode:!0,name:"root",metaType:"rootMeta",type:"root",uuid:"LUNCHBOX_ROOT"});he.rootNode=r;return n(r,...t)},he.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,I(n)),u[n]=t[n]}))})({app:he,...e}),he),he.setCustomRender=e=>{he.customRender=e},fe&&(he.setCustomRender(fe),fe=null),he.clearCustomRender=()=>{he.customRender=null},he},e.find=function(e){return e=t.isRef(e)?e.value:e,f(e)?e?.instance:m(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=ue,e.onAfterRender=(e,t=1/0)=>{t===1/0?ee.push(e):ee.splice(t,0,e)},e.onBeforeRender=ne,e.renderer=pe,e.scene=me,e.setCustomRender=e=>{he?he.setCustomRender(e):fe=e},Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue"),require("three"),require("lodash")):"function"==typeof define&&define.amd?define(["exports","vue","three","lodash"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LunchboxRenderer={},e.vue,e.three,e.lodash)}(this,(function(e,t,n,r){"use strict";function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var a=o(n);const s=[],i=(e,n)=>{const r=I.value?.instance,o=K.value.instance,a=F.value;if(!r?.domElement||!o||!a)return;const s=(e=e??window.innerWidth)/(n=n??window.innerHeight);if("perspectivecamera"===a.type?.toLowerCase()){const e=a.instance;e.aspect=s,e.updateProjectionMatrix()}else if("orthographiccamera"===a.type?.toLowerCase()){const t=a.instance,r=n/e;t.top=10*r,t.bottom=10*-r,t.right=10,t.left=-10,t.updateProjectionMatrix()}else console.log("TODO: non-ortho or perspective camera");r.setSize(e,n),o&&a.instance&&r.render(t.toRaw(o),t.toRaw(a.instance))},c=e=>({position:e,top:0,right:0,bottom:0,left:0,width:"100%",height:"100%"}),d={name:"Lunchbox",props:{background:String,cameraArgs:Array,cameraPosition:Array,dpr:Number,ortho:Boolean,orthographic:Boolean,rendererProperties:Object,shadow:[Boolean,Object],transparent:Boolean},setup(e,o){const a=t.ref(),s=t.ref(!0),d=t.ref(e.dpr??-1),u=t.ref();let l,p,m;return t.onMounted((()=>{if(!a.value)throw new Error("missing canvas");if(l=N(["WebGLRenderer"]),l)return s.value=!1,void(W.value=!0);{const t={antialias:!0,canvas:a.value.domElement};e.transparent&&(t.alpha=!0),I.value=v({type:"WebGLRenderer",uuid:$,props:{args:[t]}}),W.value=!0;const n=I,o={shadow:e.shadow};n.value.instance&&o?.shadow&&(n.value.instance.shadowMap.enabled=!0,"object"==typeof o.shadow&&(n.value.instance.shadowMap.type=o.shadow.type)),e.rendererProperties&&Object.keys(e.rendererProperties).forEach((t=>{r.set(n.value,t,e.rendererProperties[t])})),l=n.value}if(p=N(["PerspectiveCamera","OrthographicCamera"]),p?D.value=!0:(e.ortho||e.orthographic?F.value=v({props:{args:e.cameraArgs??[]},type:"OrthographicCamera",uuid:k}):F.value=v({props:{args:e.cameraArgs??[45,.5625,1,1e3]},type:"PerspectiveCamera",uuid:k}),D.value=!0,p=F.value),p&&e.cameraPosition&&p.instance?.position.set(...e.cameraPosition),m=K.value,m&&m.instance&&e.background&&(m.instance.background=new n.Color(e.background)),-1===d.value&&(d.value=window.devicePixelRatio),!l?.instance)throw new Error("missing renderer");l.instance.setPixelRatio(d.value),me.dpr.value=d.value,((e,t,n)=>{const r=e.value?.domElement;if(!r)throw new Error("missing container");i();const o=new ResizeObserver((([e])=>{i()}));r&&o.observe(r),n((()=>{t&&o.unobserve(t)}))})(u,l.instance.domElement,t.onBeforeUnmount),oe({app:t.getCurrentInstance().appContext.app,camera:p.instance,renderer:l.instance,scene:m.instance})})),t.onBeforeUnmount((()=>{se()})),()=>[o.slots.default?.()??null,t.h("div",{style:c("absolute"),ref:u},[s.value?t.h("canvas",{style:c("fixed"),class:"lunchbox-canvas",ref:a}):null])]}},u={},l=["canvas","div","LunchboxWrapper"],p={...["mesh","instancedMesh","scene","sprite","object3D","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","sphereGeometry","ringGeometry","planeGeometry","latheGeometry","shapeGeometry","extrudeGeometry","edgesGeometry","coneGeometry","cylinderGeometry","circleGeometry","boxGeometry","material","shadowMaterial","spriteMaterial","rawShaderMaterial","shaderMaterial","pointsMaterial","meshPhysicalMaterial","meshStandardMaterial","meshPhongMaterial","meshToonMaterial","meshNormalMaterial","meshLambertMaterial","meshDepthMaterial","meshDistanceMaterial","meshBasicMaterial","meshMatcapMaterial","lineDashedMaterial","lineBasicMaterial","light","spotLightShadow","spotLight","pointLight","rectAreaLight","hemisphereLight","directionalLightShadow","directionalLight","ambientLight","lightShadow","ambientLightProbe","hemisphereLightProbe","lightProbe","texture","videoTexture","dataTexture","dataTexture3D","compressedTexture","cubeTexture","canvasTexture","depthTexture","textureLoader","group","catmullRomCurve3","points","cameraHelper","camera","perspectiveCamera","orthographicCamera","cubeCamera","arrayCamera","webGLRenderer"].map((e=>t.defineComponent({inheritAttrs:!1,name:e,setup:(n,r)=>()=>t.h(e,r.attrs,r.slots?.default?.()||[])}))).reduce(((e,t)=>(e[t.name]=t,e))),Lunchbox:d};const m=e=>e?.$el&&e?.$el?.hasOwnProperty?.("instance"),h=e=>{if("domMeta"===e?.metaType)return!0;const t="string"==typeof e?e:e?.type;return l.includes(t??"")},f=e=>"standardMeta"===e?.metaType,y=e=>e.isLunchboxRootNode;function v(e={},t={}){const n={attached:e.attached??[],attachedArray:e.attachedArray??{},instance:e.instance??null},r=new J.RendererStandardNode({...e,...n,metaType:"standardMeta"});return!r.type||y(r)||r.instance||(r.instance=function(e){if(!e.type)return null;const t=e.type[0].toUpperCase()+e.type.slice(1),n=u[e.type]||a[t];if(!n)throw`${t} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`;const r=(e.props.args??[]).map((t=>function({node:e,prop:t}){const n="string"==typeof t&&t.startsWith("$attachedArray"),r=function({node:e,prop:t}){if("string"==typeof t&&t.startsWith("$attachedArray"))return e.attachedArray[t.replace("$attachedArray.","")];if("string"==typeof t&&t.startsWith("$attached"))return e.attached[t.replace("$attached.","")];return t}({node:e,prop:t});return Array.isArray(r)&&n?r:[r]}({node:e,prop:t})));let o=[];r.forEach((e=>{o=o.concat(e)}));return new n(...o)}({...r,props:{...r.props,...t}})),"scene"===r.type&&(K.value=r),r}const g=[],b=t.ref(!1);function x({node:e,key:n,value:r}){var o;if(e.eventListeners[n]||(e.eventListeners[n]=[]),e.eventListenerRemoveFunctions[n]||(e.eventListenerRemoveFunctions[n]=[]),e.eventListeners[n].push(r),R.includes(n)&&(_.value,e.instance&&!g.includes(e)&&(o=e,g.push(o),e.eventListenerRemoveFunctions[n].push((()=>(e=>{const t=g.indexOf(e);-1!==t&&g.splice(t,1)})(e))))),"onClick"===n||"onPointerDown"===n||"onPointerUp"===n){const r=t.watch((()=>b.value),(t=>{const r=P.map((e=>e.element)).findIndex((t=>t.instance&&t.instance.uuid===e.instance?.uuid));-1!==r&&((!t||"onClick"!==n&&"onPointerDown"!==n)&&(t||"onPointerUp"!==n)||e.eventListeners[n].forEach((e=>{e({intersection:P[r].intersection})})))}));e.eventListenerRemoveFunctions[n].push(r)}return e}const R=["onClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove"];let w,C,E;const A=t.ref({x:1/0,y:1/0});let L=!1;let P=[];const M=()=>{const e=_.value?.instance,t=F.value?.instance;if(!e||!t)return;e.setFromCamera(me.mousePos.value,t);const n=e.intersectObjects(g.map((e=>e.instance)));let r=[],o=[],a=[];r=P.map((e=>e.intersection)),n?.forEach((e=>{const t=P.findIndex((t=>t.intersection.object===e.object));if(-1===t){const t=g.find((t=>t.instance?.uuid===e.object.uuid));t&&o.push({element:t,intersection:e})}else{const t=g.find((t=>t.instance?.uuid===e.object.uuid));t&&a.push({element:t,intersection:e})}const n=r.findIndex((t=>t.object.uuid===e.object.uuid));-1!==n&&r.splice(n,1)}));const s=r.map((e=>({element:g.find((t=>t.instance?.uuid===e.object.uuid)),intersection:e})));o.forEach((({element:e,intersection:t})=>{B({element:e,eventKeys:["onPointerEnter"],intersection:t})})),a.forEach((({element:e,intersection:t})=>{B({element:e,eventKeys:["onPointerOver","onPointerMove"],intersection:t})})),s.forEach((({element:e,intersection:t})=>{B({element:e,eventKeys:["onPointerLeave","onPointerOut"],intersection:t})})),P=[].concat(o,a)},B=({element:e,eventKeys:t,intersection:n})=>{e&&t.forEach((t=>{e.eventListeners[t]&&e.eventListeners[t].forEach((e=>{e({intersection:n})}))}))};function G(t={}){return e.lunchboxTree||(e.lunchboxTree=new J.RendererRootNode(t)),e.lunchboxTree}function N(e){Array.isArray(e)||(e=[e]);for(let t of e)if(O[t])return O[t];for(let t of e){const e=T[t]||s.find((e=>e.type?.toLowerCase()===t.toLowerCase()));if(e){const n=e;return T[t]=n,n}}return null}e.lunchboxTree=void 0;const T=t.reactive({}),O=t.reactive({});function j(e,n,r={},o=null){Array.isArray(e)||(e=[e]);for(let t of e)T[t]||(T[t]=null),O[t]||(O[t]=null);return t.computed({get(){const t=N(e);if(t)return t;const a=G(),s=v({type:e[0],uuid:n,props:r});return a.addChild(s),T[e[0]]=s,o&&o(s),s},set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}})}const k="FALLBACK_CAMERA",S=j(["PerspectiveCamera","OrthographicCamera"],k,{args:[45,.5625,1,1e3]}),D=t.ref(!1),F=t.computed({get:()=>D.value?S.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),$="FALLBACK_RENDERER",U=j(["WebGLRenderer"],$,{}),W=t.ref(!1),I=t.computed({get:()=>W.value?U.value:null,set(e){const t=e.type??"",n=t[0].toUpperCase()+t.slice(1);O[n]=e}}),K=j("Scene","FALLBACK_SCENE"),_=j("Raycaster","AUTO_RAYCASTER",{},(e=>(e=>{if(!e.instance)return;let n=null;n=t.watch((()=>I.value),(e=>{e?.instance&&(L||(w=t=>{const n=(e.instance.domElement.width??1)/me.dpr.value,r=(e.instance.domElement.height??1)/me.dpr.value;A.value.x=t.offsetX/n*2-1,A.value.y=-t.offsetY/r*2+1},C=()=>b.value=!0,E=()=>b.value=!1,e.instance.domElement.addEventListener("mousemove",w),e.instance.domElement.addEventListener("mousedown",C),e.instance.domElement.addEventListener("mouseup",E),ae(M),L=!0),n&&n())}),{immediate:!0})})(e))),V=e=>t.defineComponent({inheritAttrs:!1,name:e,render(){return t.h(e,this.$attrs,this.$slots?.default?.()||[])}});var q,z=new Uint8Array(16);function H(){if(!q&&!(q="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return q(z)}var Y=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function X(e){return"string"==typeof e&&Y.test(e)}for(var J,Q=[],Z=0;Z<256;++Z)Q.push((Z+256).toString(16).substr(1));function ee(e,t,n){var r=(e=e||{}).random||(e.rng||H)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(var o=0;o<16;++o)t[n+o]=r[o];return t}return function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=(Q[e[t+0]]+Q[e[t+1]]+Q[e[t+2]]+Q[e[t+3]]+"-"+Q[e[t+4]]+Q[e[t+5]]+"-"+Q[e[t+6]]+Q[e[t+7]]+"-"+Q[e[t+8]]+Q[e[t+9]]+"-"+Q[e[t+10]]+Q[e[t+11]]+Q[e[t+12]]+Q[e[t+13]]+Q[e[t+14]]+Q[e[t+15]]).toLowerCase();if(!X(n))throw TypeError("Stringified UUID is invalid");return n}(r)}!function(e){e.BaseNode=class{constructor(e={},t){this.parentNode=e?.parentNode??t??null,this.minidomType="MinidomBaseNode",this.uuid=e?.uuid??ee(),s.push(this)}uuid;parentNode;get nextSibling(){if(!this.parentNode)return null;const e=this.parentNode.children.findIndex((e=>e.uuid===this.uuid));return-1!==e&&e<this.parentNode.children.length-1?this.parentNode.children[e+1]:null}insertBefore(e,t){e.removeAsChildFromAnyParents(),e.parentNode=this;const n=this.children.findIndex((e=>e.uuid===t?.uuid));-1!==n?this.children.splice(n,0,e):this.children.push(e)}removeChild(e){const t=this.children.findIndex((t=>t?.uuid===e?.uuid));-1!==t&&this.children.splice(t,1)}children=[];addChild(e){return e&&(e.removeAsChildFromAnyParents(),e.parentNode=this,this.insertBefore(e,null)),this}getPath(){const e=[];let t=this;for(;t;)e.unshift(t),t=t.parentNode;return e}drop(){this.parentNode=null,this.removeAsChildFromAnyParents()}walk(e){const t=[this,...this.children],n=[];let r=!0;for(;t.length&&r;){const o=t.shift();if(o){if(n.includes(o))continue;n.push(o),t.push(...o.children.filter((e=>!n.includes(e)))),r=e(o)}else r=!1}}minidomType;removeAsChildFromAnyParents(){s.forEach((e=>e.removeChild(this)))}};class t extends e.BaseNode{constructor(e={},t){super(e,t),this.minidomType="RendererNode",this.eventListeners={},this.eventListenerRemoveFunctions={},this.name=e.name??"",this.metaType=e.metaType??"standardMeta",this.props=e.props??[],this.type=e.type??""}eventListeners;eventListenerRemoveFunctions;name;metaType;props;type;drop(){super.drop(),Object.keys(this.eventListenerRemoveFunctions).forEach((e=>{this.eventListenerRemoveFunctions[e].forEach((e=>e()))}))}}e.RendererBaseNode=t;class n extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement;isLunchboxRootNode=!0}e.RendererRootNode=n;class r extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererCommentNode=r;class o extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.domElement=e.domElement??document.createElement("div")}domElement}e.RendererDomNode=o;class a extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.text=e.text??""}text}e.RendererTextNode=a;class i extends e.RendererBaseNode{constructor(e={},t){super(e,t),this.attached=e.attached??[],this.attachedArray=e.attachedArray??{},this.instance=e.instance??null}attached;attachedArray;instance}e.RendererStandardNode=i}(J||(J={}));let te;(new J.RendererRootNode).minidomType="RootNode";const ne=[],re=[],oe=e=>{te=requestAnimationFrame((()=>oe({app:e.app,renderer:I.value?.instance,scene:K.value.instance,camera:F.value?.instance})));const{app:n,renderer:r,scene:o,camera:a}=e;ne.forEach((t=>{t&&t(e)})),r&&o&&a&&(n.customRender?n.customRender(e):r.render(t.toRaw(o),t.toRaw(a))),re.forEach((t=>{t&&t(e)}))},ae=(e,t=1/0)=>{t===1/0?ne.push(e):ne.splice(t,0,e)},se=()=>{te&&cancelAnimationFrame(te)};const ie={x:"position.x",y:"position.y",z:"position.z"},ce=["","parameters"],de=["args","attach","attachArray","key","onAdded","ref","src"],ue=["geometry","material"];function le(e,t,n,r){const o=r??e.instance,a=t.instance;e.props.attach===n&&(t.attached={[n]:o,...t.attached||{}},a[n]=r??e.instance),e.props.attachArray===n&&(t.attachedArray[e.props.attachArray]||(t.attachedArray[e.props.attachArray]=[]),t.attachedArray[e.props.attachArray].push(o),a[n]=[a[n]])}const pe={createElement:(e,t,n,r)=>{const o={type:e};r&&(o.props=r);if(h(e)){const e=function(e={}){const t={domElement:document.createElement(e.type??"")};return new J.RendererDomNode({...t,...e,metaType:"domMeta"})}(o);return e}const a=v(o);return ue.forEach((t=>{e.toLowerCase().endsWith(t)&&(a.props.attach=t)})),a},createText:e=>function(e={}){const t={text:e.text??""};return new J.RendererTextNode({...e,...t,metaType:"textMeta"})}({text:e}),createComment:e=>function(e={}){const t={text:e.text??""};return new J.RendererCommentNode({...t,...e,metaType:"commentMeta"})}({text:e}),insert:(e,t,n)=>{let r=t??G();if(r.insertBefore(e,n),"commentMeta"!==e.metaType&&"textMeta"!==e.metaType&&(h(e)&&(h(t)||y(t))&&t.domElement.appendChild(e.domElement),f(e))){let n=r.metaType;if("textMeta"===n||"commentMeta"===n){const e=r.getPath();for(let t=e.length-1;t>=0;t--)if("textMeta"!==e[t].metaType&&"commentMeta"!==e[t].metaType){r=e[t];break}}if("standardMeta"===e.metaType&&"scene"!==e.type&&y(r)){const t=K.value;t.instance&&e&&t.addChild(e),e.instance&&e.instance.isObject3D&&t.instance&&t!==e&&t.instance.add(e.instance)}else f(e)&&e.instance?.isObject3D&&f(r)&&r.instance?.isObject3D&&r.instance?.add?.(e.instance);if(e?.props?.attach&&f(t)&&t?.instance){e.type?.toLowerCase().endsWith("loader")&&e.props.src&&(e.props.attach||e.props.attachArray)?function(e,t){const n=e.instance;if(t.attached=t.attached||{},t.attachedArray=t.attachedArray||{},!e.props.attach)return;if("textureloader"===e.type?.toLowerCase()){const r=n.load(e.props.src);le(e,t,e.props.attach,r)}else n.load(e.props.src,(n=>{le(e,t,e.props.attach,n)}),null,(e=>{throw new Error(e)}))}(e,t):le(e,t,e.props.attach)}e.props?.onAdded&&e.props.onAdded({instance:e.instance})}},nextSibling(e){const t=e.nextSibling;return t||null},parentNode(e){const t=e.parentNode;return t||null},patchProp(e,t,n,o){h(e)?"style"===t?Object.keys(o).forEach((t=>{e.domElement.style[t]=o[t]})):e.domElement.setAttribute(t,o):y(e)||t.startsWith("$")||function({node:e,key:t,value:n}){if((e=>["onClick","onContextMenu","onDoubleClick","onPointerUp","onPointerDown","onPointerOver","onPointerOut","onPointerEnter","onPointerLeave","onPointerMove","onWheel"].includes(e))(t))return x({node:e,key:t,value:n});if(de.includes(t))return e;if(!f(e))return e;if("string"==typeof n&&n.startsWith("$attached")){const t=n.replace("$attached.","");n=r.get(e.attached,t,null)}const o=e.instance;if(!o)return e;const a=t.replace(/-/g,".");let s,i=ie[a]||a;for(let e=0;e<ce.length&&!s;e++){const t=[ce[e],i].filter(Boolean).join(".");s=s=r.get(o,t)}if(s&&r.isNumber(n)&&s.setScalar)s.setScalar(n);else if(s&&s.set){const e=Array.isArray(n)?n:[n];o[i].set(...e)}else"function"==typeof s?s.bind(e.instance)(...n):void 0!==r.get(o,i,void 0)?r.set(o,i,""===n||n):console.log(`No property ${i} found on ${o}`);const c=o?.texture?.type||o?.type;if("string"==typeof c){const e=c.toLowerCase();switch(!0){case e.includes("material"):o.needsUpdate=!0;break;case e.includes("camera")&&o.updateProjectionMatrix:o.updateProjectionMatrix()}}}({node:e,key:t,value:o})},remove:e=>{if(!e)return;const t=Object.keys(O),n=[];e.walk((e=>(n.push(e),!0))),n.forEach((e=>{const n=t.find((t=>O[t]?.uuid===e.uuid));if(n&&(O[n]=null),f(e)){e.instance?.removeFromParent?.();const t="scene"!==e.type&&e.instance?.dispose;t&&t.bind(e.instance)(),e.instance=null}e.drop();const r=s.findIndex((t=>t.uuid===e.uuid));-1!==r&&s.splice(r,1)}))},setElementText(){},setText(){}},me={dpr:t.ref(1),inputActive:b,mousePos:A},he=t.computed((()=>F.value?.instance??null)),fe=t.computed((()=>I.value?.instance??null)),ye=t.computed((()=>K.value.instance));let ve=null,ge=null;e.camera=he,e.clearCustomRender=()=>{ve?ve.clearCustomRender():ge=null},e.createApp=e=>{ve=t.createRenderer(pe).createApp(e),Object.keys(p).forEach((e=>{ve.component(e,p[e])}));const{mount:n}=ve;return ve.mount=(e,...t)=>{const r=G({domElement:"string"==typeof e?document.querySelector(e):e,isLunchboxRootNode:!0,name:"root",metaType:"rootMeta",type:"root",uuid:"LUNCHBOX_ROOT"});ve.rootNode=r;return n(r,...t)},ve.extend=e=>((({app:e,...t})=>{Object.keys(t).forEach((n=>{e.component(n,V(n)),u[n]=t[n]}))})({app:ve,...e}),ve),ve.setCustomRender=e=>{ve.customRender=e},ge&&(ve.setCustomRender(ge),ge=null),ve.clearCustomRender=()=>{ve.customRender=null},ve},e.find=function(e){return e=t.isRef(e)?e.value:e,f(e)?e?.instance:m(e)?e?.$el?.instance:t.isVNode(e)?e.el?.instance:null},e.globals=me,e.onAfterRender=(e,t=1/0)=>{t===1/0?re.push(e):re.splice(t,0,e)},e.onBeforeRender=ae,e.renderer=fe,e.scene=ye,e.setCustomRender=e=>{ve?ve.setCustomRender(e):ge=e},Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
@@ -9,27 +9,36 @@ const allNodes = [];
|
|
|
9
9
|
const resizeCanvas = (width, height) => {
|
|
10
10
|
const renderer = ensureRenderer.value?.instance;
|
|
11
11
|
const scene = ensuredScene.value.instance;
|
|
12
|
+
const camera = ensuredCamera.value;
|
|
12
13
|
// ignore if no element
|
|
13
|
-
if (!renderer?.domElement || !scene)
|
|
14
|
+
if (!renderer?.domElement || !scene || !camera)
|
|
14
15
|
return;
|
|
15
16
|
width = width ?? window.innerWidth;
|
|
16
17
|
height = height ?? window.innerHeight;
|
|
17
18
|
// update camera
|
|
18
19
|
const aspect = width / height;
|
|
19
|
-
const camera = ensuredCamera.value;
|
|
20
20
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
21
21
|
const perspectiveCamera = camera.instance;
|
|
22
22
|
perspectiveCamera.aspect = aspect;
|
|
23
23
|
perspectiveCamera.updateProjectionMatrix();
|
|
24
24
|
}
|
|
25
|
+
else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
26
|
+
// console.log('TODO: ortho camera update')
|
|
27
|
+
const orthoCamera = camera.instance;
|
|
28
|
+
const heightInTermsOfWidth = height / width;
|
|
29
|
+
orthoCamera.top = heightInTermsOfWidth * 10;
|
|
30
|
+
orthoCamera.bottom = -heightInTermsOfWidth * 10;
|
|
31
|
+
orthoCamera.right = 10;
|
|
32
|
+
orthoCamera.left = -10;
|
|
33
|
+
orthoCamera.updateProjectionMatrix();
|
|
34
|
+
}
|
|
25
35
|
else {
|
|
26
|
-
console.log('TODO: ortho camera
|
|
36
|
+
console.log('TODO: non-ortho or perspective camera');
|
|
27
37
|
}
|
|
28
38
|
// update canvas
|
|
29
39
|
renderer.setSize(width, height);
|
|
30
40
|
// render immediately so there's no flicker
|
|
31
41
|
if (scene && camera.instance) {
|
|
32
|
-
// const cameraInstance = scene.traverse(v => )
|
|
33
42
|
renderer.render(toRaw(scene), toRaw(camera.instance));
|
|
34
43
|
}
|
|
35
44
|
};
|
|
@@ -74,8 +83,11 @@ const LunchboxWrapper = {
|
|
|
74
83
|
props: {
|
|
75
84
|
// These should match the Lunchbox.WrapperProps interface
|
|
76
85
|
background: String,
|
|
86
|
+
cameraArgs: Array,
|
|
77
87
|
cameraPosition: Array,
|
|
78
88
|
dpr: Number,
|
|
89
|
+
ortho: Boolean,
|
|
90
|
+
orthographic: Boolean,
|
|
79
91
|
rendererProperties: Object,
|
|
80
92
|
shadow: [Boolean, Object],
|
|
81
93
|
transparent: Boolean,
|
|
@@ -86,6 +98,7 @@ const LunchboxWrapper = {
|
|
|
86
98
|
const dpr = ref(props.dpr ?? -1);
|
|
87
99
|
const container = ref();
|
|
88
100
|
let renderer;
|
|
101
|
+
let camera;
|
|
89
102
|
let scene;
|
|
90
103
|
// MOUNT
|
|
91
104
|
// ====================
|
|
@@ -93,12 +106,6 @@ const LunchboxWrapper = {
|
|
|
93
106
|
// canvas needs to exist
|
|
94
107
|
if (!canvas.value)
|
|
95
108
|
throw new Error('missing canvas');
|
|
96
|
-
// ensure camera
|
|
97
|
-
const camera = ensuredCamera.value.instance;
|
|
98
|
-
// move camera if needed
|
|
99
|
-
if (camera && props.cameraPosition) {
|
|
100
|
-
camera.position.set(...props.cameraPosition);
|
|
101
|
-
}
|
|
102
109
|
// RENDERER
|
|
103
110
|
// ====================
|
|
104
111
|
// is there already a renderer?
|
|
@@ -155,6 +162,43 @@ const LunchboxWrapper = {
|
|
|
155
162
|
rendererReady.value = true;
|
|
156
163
|
return;
|
|
157
164
|
}
|
|
165
|
+
// CAMERA
|
|
166
|
+
// ====================
|
|
167
|
+
// is there already a camera?
|
|
168
|
+
camera = tryGetNodeWithInstanceType([
|
|
169
|
+
'PerspectiveCamera',
|
|
170
|
+
'OrthographicCamera',
|
|
171
|
+
]);
|
|
172
|
+
// if not, let's create one
|
|
173
|
+
if (!camera) {
|
|
174
|
+
// create ortho camera
|
|
175
|
+
if (props.ortho || props.orthographic) {
|
|
176
|
+
// const size: Vector2 = new Vector2()
|
|
177
|
+
ensuredCamera.value = createNode({
|
|
178
|
+
props: { args: props.cameraArgs ?? [] },
|
|
179
|
+
type: 'OrthographicCamera',
|
|
180
|
+
uuid: fallbackCameraUuid,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
ensuredCamera.value = createNode({
|
|
185
|
+
props: {
|
|
186
|
+
args: props.cameraArgs ?? [45, 0.5625, 1, 1000],
|
|
187
|
+
},
|
|
188
|
+
type: 'PerspectiveCamera',
|
|
189
|
+
uuid: fallbackCameraUuid,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
cameraReady.value = true;
|
|
193
|
+
camera = ensuredCamera.value;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
cameraReady.value = true;
|
|
197
|
+
}
|
|
198
|
+
// move camera if needed
|
|
199
|
+
if (camera && props.cameraPosition) {
|
|
200
|
+
camera.instance?.position.set(...props.cameraPosition);
|
|
201
|
+
}
|
|
158
202
|
// SCENE
|
|
159
203
|
// ====================
|
|
160
204
|
scene = ensuredScene.value;
|
|
@@ -181,7 +225,7 @@ const LunchboxWrapper = {
|
|
|
181
225
|
// console.log(scene)
|
|
182
226
|
update({
|
|
183
227
|
app: getCurrentInstance().appContext.app,
|
|
184
|
-
camera,
|
|
228
|
+
camera: camera.instance,
|
|
185
229
|
renderer: renderer.instance,
|
|
186
230
|
scene: scene.instance,
|
|
187
231
|
});
|
|
@@ -828,9 +872,27 @@ function buildEnsured(pascalCaseTypes, fallbackUuid, props = {}, callback = null
|
|
|
828
872
|
// ENSURE CAMERA
|
|
829
873
|
// ====================
|
|
830
874
|
const fallbackCameraUuid = 'FALLBACK_CAMERA';
|
|
831
|
-
const
|
|
832
|
-
|
|
875
|
+
const defaultCamera = buildEnsured(['PerspectiveCamera', 'OrthographicCamera'], fallbackCameraUuid, { args: [45, 0.5625, 1, 1000] });
|
|
876
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
877
|
+
* Functions waiting for a Camera need to wait for this to be true. */
|
|
878
|
+
const cameraReady = ref(false);
|
|
879
|
+
const ensuredCamera = computed({
|
|
880
|
+
get() {
|
|
881
|
+
return (cameraReady.value ? defaultCamera.value : null);
|
|
882
|
+
},
|
|
883
|
+
set(val) {
|
|
884
|
+
const t = val.type ?? '';
|
|
885
|
+
const pascalType = t[0].toUpperCase() + t.slice(1);
|
|
886
|
+
overrides[pascalType] = val;
|
|
887
|
+
},
|
|
833
888
|
});
|
|
889
|
+
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
890
|
+
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
891
|
+
// fallbackCameraUuid,
|
|
892
|
+
// {
|
|
893
|
+
// args: [45, 0.5625, 1, 1000],
|
|
894
|
+
// }
|
|
895
|
+
// )
|
|
834
896
|
// ENSURE RENDERER
|
|
835
897
|
// ====================
|
|
836
898
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
@@ -1184,7 +1246,7 @@ const update = (opts) => {
|
|
|
1184
1246
|
app: opts.app,
|
|
1185
1247
|
renderer: ensureRenderer.value?.instance,
|
|
1186
1248
|
scene: ensuredScene.value.instance,
|
|
1187
|
-
camera: ensuredCamera.value
|
|
1249
|
+
camera: ensuredCamera.value?.instance,
|
|
1188
1250
|
}));
|
|
1189
1251
|
// prep options
|
|
1190
1252
|
const { app, renderer, scene, camera } = opts;
|
|
@@ -1579,7 +1641,7 @@ const globals = {
|
|
|
1579
1641
|
inputActive,
|
|
1580
1642
|
mousePos,
|
|
1581
1643
|
};
|
|
1582
|
-
const camera = computed(() => ensuredCamera.value
|
|
1644
|
+
const camera = computed(() => ensuredCamera.value?.instance ?? null);
|
|
1583
1645
|
const renderer = computed(() => ensureRenderer.value?.instance ?? null);
|
|
1584
1646
|
const scene = computed(() => ensuredScene.value.instance);
|
|
1585
1647
|
// CUSTOM RENDER SUPPORT
|
package/package.json
CHANGED
|
@@ -8,11 +8,13 @@ import {
|
|
|
8
8
|
WritableComputedRef,
|
|
9
9
|
} from 'vue'
|
|
10
10
|
import {
|
|
11
|
+
cameraReady,
|
|
11
12
|
cancelUpdate,
|
|
12
13
|
createNode,
|
|
13
14
|
ensuredCamera,
|
|
14
15
|
ensureRenderer,
|
|
15
16
|
ensuredScene,
|
|
17
|
+
fallbackCameraUuid,
|
|
16
18
|
fallbackRendererUuid,
|
|
17
19
|
MiniDom,
|
|
18
20
|
rendererReady,
|
|
@@ -21,7 +23,7 @@ import {
|
|
|
21
23
|
} from '../../core'
|
|
22
24
|
import { set } from 'lodash'
|
|
23
25
|
import { globals, Lunch } from '../..'
|
|
24
|
-
import { Color } from 'three'
|
|
26
|
+
import { Color, Vector2 } from 'three'
|
|
25
27
|
import { prepCanvas } from './prepCanvas'
|
|
26
28
|
|
|
27
29
|
/** fixed & fill styling for container */
|
|
@@ -42,8 +44,11 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
42
44
|
props: {
|
|
43
45
|
// These should match the Lunchbox.WrapperProps interface
|
|
44
46
|
background: String,
|
|
47
|
+
cameraArgs: Array,
|
|
45
48
|
cameraPosition: Array,
|
|
46
49
|
dpr: Number,
|
|
50
|
+
ortho: Boolean,
|
|
51
|
+
orthographic: Boolean,
|
|
47
52
|
rendererProperties: Object,
|
|
48
53
|
shadow: [Boolean, Object],
|
|
49
54
|
transparent: Boolean,
|
|
@@ -54,6 +59,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
54
59
|
const dpr = ref(props.dpr ?? -1)
|
|
55
60
|
const container = ref<MiniDom.RendererDomNode>()
|
|
56
61
|
let renderer: Lunch.Node<THREE.WebGLRenderer> | null
|
|
62
|
+
let camera: Lunch.Node<THREE.Camera> | null
|
|
57
63
|
let scene: MiniDom.RendererStandardNode<THREE.Scene>
|
|
58
64
|
|
|
59
65
|
// MOUNT
|
|
@@ -62,13 +68,6 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
62
68
|
// canvas needs to exist
|
|
63
69
|
if (!canvas.value) throw new Error('missing canvas')
|
|
64
70
|
|
|
65
|
-
// ensure camera
|
|
66
|
-
const camera = ensuredCamera.value.instance
|
|
67
|
-
// move camera if needed
|
|
68
|
-
if (camera && props.cameraPosition) {
|
|
69
|
-
camera.position.set(...props.cameraPosition)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
71
|
// RENDERER
|
|
73
72
|
// ====================
|
|
74
73
|
// is there already a renderer?
|
|
@@ -139,6 +138,45 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
139
138
|
return
|
|
140
139
|
}
|
|
141
140
|
|
|
141
|
+
// CAMERA
|
|
142
|
+
// ====================
|
|
143
|
+
// is there already a camera?
|
|
144
|
+
camera = tryGetNodeWithInstanceType([
|
|
145
|
+
'PerspectiveCamera',
|
|
146
|
+
'OrthographicCamera',
|
|
147
|
+
])
|
|
148
|
+
// if not, let's create one
|
|
149
|
+
if (!camera) {
|
|
150
|
+
// create ortho camera
|
|
151
|
+
if (props.ortho || props.orthographic) {
|
|
152
|
+
// const size: Vector2 = new Vector2()
|
|
153
|
+
|
|
154
|
+
ensuredCamera.value = createNode<THREE.OrthographicCamera>({
|
|
155
|
+
props: { args: props.cameraArgs ?? [] },
|
|
156
|
+
type: 'OrthographicCamera',
|
|
157
|
+
uuid: fallbackCameraUuid,
|
|
158
|
+
})
|
|
159
|
+
} else {
|
|
160
|
+
ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
|
|
161
|
+
props: {
|
|
162
|
+
args: props.cameraArgs ?? [45, 0.5625, 1, 1000],
|
|
163
|
+
},
|
|
164
|
+
type: 'PerspectiveCamera',
|
|
165
|
+
uuid: fallbackCameraUuid,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
cameraReady.value = true
|
|
170
|
+
|
|
171
|
+
camera = ensuredCamera.value
|
|
172
|
+
} else {
|
|
173
|
+
cameraReady.value = true
|
|
174
|
+
}
|
|
175
|
+
// move camera if needed
|
|
176
|
+
if (camera && props.cameraPosition) {
|
|
177
|
+
camera.instance?.position.set(...props.cameraPosition)
|
|
178
|
+
}
|
|
179
|
+
|
|
142
180
|
// SCENE
|
|
143
181
|
// ====================
|
|
144
182
|
scene = ensuredScene.value
|
|
@@ -171,7 +209,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
171
209
|
// console.log(scene)
|
|
172
210
|
update({
|
|
173
211
|
app: getCurrentInstance()!.appContext.app as Lunch.App,
|
|
174
|
-
camera,
|
|
212
|
+
camera: camera.instance,
|
|
175
213
|
renderer: renderer.instance,
|
|
176
214
|
scene: scene.instance,
|
|
177
215
|
})
|
|
@@ -4,29 +4,37 @@ import { toRaw } from 'vue'
|
|
|
4
4
|
export const resizeCanvas = (width?: number, height?: number) => {
|
|
5
5
|
const renderer = ensureRenderer.value?.instance
|
|
6
6
|
const scene = ensuredScene.value.instance
|
|
7
|
+
const camera = ensuredCamera.value
|
|
7
8
|
|
|
8
9
|
// ignore if no element
|
|
9
|
-
if (!renderer?.domElement || !scene) return
|
|
10
|
+
if (!renderer?.domElement || !scene || !camera) return
|
|
10
11
|
|
|
11
12
|
width = width ?? window.innerWidth
|
|
12
13
|
height = height ?? window.innerHeight
|
|
13
14
|
|
|
14
15
|
// update camera
|
|
15
16
|
const aspect = width / height
|
|
16
|
-
const camera = ensuredCamera.value
|
|
17
17
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
18
18
|
const perspectiveCamera = camera.instance as THREE.PerspectiveCamera
|
|
19
19
|
perspectiveCamera.aspect = aspect
|
|
20
20
|
perspectiveCamera.updateProjectionMatrix()
|
|
21
|
+
} else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
22
|
+
// console.log('TODO: ortho camera update')
|
|
23
|
+
const orthoCamera = camera.instance as THREE.OrthographicCamera
|
|
24
|
+
const heightInTermsOfWidth = height / width
|
|
25
|
+
orthoCamera.top = heightInTermsOfWidth * 10
|
|
26
|
+
orthoCamera.bottom = -heightInTermsOfWidth * 10
|
|
27
|
+
orthoCamera.right = 10
|
|
28
|
+
orthoCamera.left = -10
|
|
29
|
+
orthoCamera.updateProjectionMatrix()
|
|
21
30
|
} else {
|
|
22
|
-
console.log('TODO: ortho camera
|
|
31
|
+
console.log('TODO: non-ortho or perspective camera')
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
// update canvas
|
|
26
35
|
renderer.setSize(width, height)
|
|
27
36
|
// render immediately so there's no flicker
|
|
28
37
|
if (scene && camera.instance) {
|
|
29
|
-
// const cameraInstance = scene.traverse(v => )
|
|
30
38
|
renderer.render(toRaw(scene), toRaw(camera.instance))
|
|
31
39
|
}
|
|
32
40
|
}
|
package/src/core/ensure.ts
CHANGED
|
@@ -127,13 +127,35 @@ function buildEnsured<T extends THREE.Object3D>(
|
|
|
127
127
|
// ENSURE CAMERA
|
|
128
128
|
// ====================
|
|
129
129
|
export const fallbackCameraUuid = 'FALLBACK_CAMERA'
|
|
130
|
-
export const
|
|
130
|
+
export const defaultCamera = buildEnsured(
|
|
131
131
|
['PerspectiveCamera', 'OrthographicCamera'],
|
|
132
132
|
fallbackCameraUuid,
|
|
133
|
-
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
{ args: [45, 0.5625, 1, 1000] }
|
|
134
|
+
) as unknown as WritableComputedRef<Lunch.Node<THREE.Camera>>
|
|
135
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
136
|
+
* Functions waiting for a Camera need to wait for this to be true. */
|
|
137
|
+
export const cameraReady = ref(false)
|
|
138
|
+
|
|
139
|
+
export const ensuredCamera = computed<Lunch.Node<THREE.Camera> | null>({
|
|
140
|
+
get() {
|
|
141
|
+
return (
|
|
142
|
+
cameraReady.value ? (defaultCamera.value as any) : (null as any)
|
|
143
|
+
) as any
|
|
144
|
+
},
|
|
145
|
+
set(val: any) {
|
|
146
|
+
const t = val.type ?? ''
|
|
147
|
+
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
148
|
+
overrides[pascalType] = val as any
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
153
|
+
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
154
|
+
// fallbackCameraUuid,
|
|
155
|
+
// {
|
|
156
|
+
// args: [45, 0.5625, 1, 1000],
|
|
157
|
+
// }
|
|
158
|
+
// )
|
|
137
159
|
|
|
138
160
|
// ENSURE RENDERER
|
|
139
161
|
// ====================
|
package/src/core/update.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const globals = {
|
|
|
30
30
|
mousePos,
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export const camera = computed(() => ensuredCamera.value
|
|
33
|
+
export const camera = computed(() => ensuredCamera.value?.instance ?? null)
|
|
34
34
|
export const renderer = computed(() => ensureRenderer.value?.instance ?? null)
|
|
35
35
|
export const scene = computed(() => ensuredScene.value.instance)
|
|
36
36
|
|
package/src/types.ts
CHANGED
|
@@ -138,8 +138,11 @@ export declare namespace Lunch {
|
|
|
138
138
|
|
|
139
139
|
interface WrapperProps {
|
|
140
140
|
background?: string
|
|
141
|
+
cameraArgs?: any[]
|
|
141
142
|
cameraPosition?: [number, number, number]
|
|
142
143
|
dpr?: number
|
|
144
|
+
ortho?: boolean
|
|
145
|
+
orthographic?: boolean
|
|
143
146
|
rendererProperties?: Partial<THREE.WebGLRenderer>
|
|
144
147
|
shadow?: ShadowSugar
|
|
145
148
|
transparent?: boolean
|