playground: fully working (snapshots left as future work) and other quality of life improvements

This commit is contained in:
Yeicor
2025-07-25 17:59:40 +02:00
parent a63d018850
commit 8a435b5f1a
15 changed files with 289 additions and 81 deletions

View File

@@ -11,9 +11,9 @@ import {NetworkManager, NetworkUpdateEvent, NetworkUpdateEventModel} from "./mis
import {SceneMgr} from "./misc/scene";
import {Document} from "@gltf-transform/core";
import type ModelViewerWrapperT from "./viewer/ModelViewerWrapper.vue";
import {mdiPlus} from '@mdi/js'
import {mdiCube, mdiPlus, mdiScriptTextPlay} from '@mdi/js'
// @ts-expect-error
import SvgIcon from '@jamescoyle/vue-icon';
import {toBuffer} from "./misc/gltf.ts";
// NOTE: The ModelViewer library is big (THREE.js), so we split it and import it asynchronously
const ModelViewerWrapper = defineAsyncComponent({
@@ -22,7 +22,7 @@ const ModelViewerWrapper = defineAsyncComponent({
delay: 0,
});
let openSidebarsByDefault: Ref<boolean> = ref(window.innerWidth > 1200);
let openSidebarsByDefault: Ref<boolean> = ref(window.innerWidth > window.innerHeight);
const sceneUrl = ref("")
const viewer: Ref<InstanceType<typeof ModelViewerWrapperT> | null> = ref(null);
@@ -81,6 +81,7 @@ let networkMgr = new NetworkManager();
networkMgr.addEventListener('update-early',
(e) => viewer.value?.onProgress((e as CustomEvent<Array<any>>).detail.length * 0.01));
networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUpdateEvent));
let preloadingModels = ref<Array<string>>([]);
(async () => { // Start loading all configured models ASAP
let sett = await settings();
if (sett.preload.length > 0) {
@@ -91,17 +92,16 @@ networkMgr.addEventListener('update', (e) => onModelUpdateRequest(e as NetworkUp
}
});
for (let model of sett.preload) {
await networkMgr.load(model);
preloadingModels.value.push(model);
let removeFromPreloadingModels = () => {
preloadingModels.value = preloadingModels.value.filter((m) => m !== model);
};
networkMgr.load(model).then(removeFromPreloadingModels).catch((e) => {
removeFromPreloadingModels()
console.error("Error preloading model", model, e);
});
}
} else { // Skip to interface without models (useful for playground mode)
console.debug("Showing empty gltf document to load the interface without models.");
// FIXME: Empty document breaks the playground-loaded models (using preload seems to fix this, maybe __helpers issue?)
let emptyDoc = new Document();
emptyDoc.createScene();
let buffer = await toBuffer(emptyDoc);
let blob = new Blob([buffer], {type: 'model/gltf-binary'});
sceneUrl.value = URL.createObjectURL(blob);
}
} // else No preloaded models (useful for playground mode)
})();
async function loadModelManual() {
@@ -115,7 +115,28 @@ async function loadModelManual() {
<!-- The main content of the app is the model-viewer with the SVG "2D" overlay -->
<v-main id="main">
<model-viewer-wrapper ref="viewer" :src="sceneUrl"/>
<model-viewer-wrapper v-if="sceneDocument.getRoot().listMeshes().length > 0" ref="viewer" :src="sceneUrl"/>
<!-- A nice no model loaded alternative to avoid breaking model-viewer-wrapper -->
<div v-else style="height: 100%; overflow-y: auto">
<v-toolbar-title class="text-center ma-16 text-h5">No model loaded</v-toolbar-title>
<v-btn @click="() => tools?.openPlayground()" class="mx-auto d-block my-4">
<svg-icon :path="mdiScriptTextPlay" type="mdi"/>&nbsp; Open playground...
</v-btn>
<v-btn @click="networkMgr.load('https://yeicor-3d.github.io/yet-another-cad-viewer/logo.glb')"
class="mx-auto d-block my-4">
<svg-icon :path="mdiCube" type="mdi"/>&nbsp; Load demo model...
</v-btn>
<v-btn @click="loadModelManual" class="mx-auto d-block my-4">
<svg-icon :path="mdiPlus" type="mdi"/>&nbsp; Load model manually...
</v-btn>
<span v-if="preloadingModels.length > 0" class="d-block text-center my-16">
<span class="d-block text-center text-h6">Still trying to load the following:</span>
<span class="d-block text-center" v-for="(model, index) in preloadingModels" :key="index">
{{ model }}<span v-if="index < preloadingModels.length - 1">, </span>
</span>
</span>
</div>
</v-main>
<!-- The left collapsible sidebar has the list of models -->