From 29ad07eabde2b46fc357f944efa44fcce0bdb5f1 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 12 Mar 2024 16:42:18 +0000 Subject: [PATCH] export almost works --- src/3rd/js/aframe/build/three.module.js | 2 + src/3rd/js/plugin/frontend/$editor.js | 104 +++++++++++++++++++++--- src/3rd/js/plugin/frontend/frontend.js | 37 +++++++-- src/3rd/js/plugin/frontend/snackbar.js | 2 + src/xrfragment/XRF.hx | 1 + 5 files changed, 129 insertions(+), 17 deletions(-) diff --git a/src/3rd/js/aframe/build/three.module.js b/src/3rd/js/aframe/build/three.module.js index 11c6835..5e593a9 100644 --- a/src/3rd/js/aframe/build/three.module.js +++ b/src/3rd/js/aframe/build/three.module.js @@ -11,6 +11,7 @@ import { MTLLoader } from 'super-three/examples/jsm/loaders/MTLLoader'; import * as BufferGeometryUtils from 'super-three/examples/jsm/utils/BufferGeometryUtils'; import { LightProbeGenerator } from 'super-three/examples/jsm/lights/LightProbeGenerator'; import { TransformControls } from 'super-three/examples/jsm/controls/TransformControls.js'; +import { GLTFExporter } from 'super-three/examples/jsm/exporters/GLTFExporter.js'; var THREE = window.THREE = SUPER_THREE; @@ -28,6 +29,7 @@ THREE.OBB = OBB; THREE.BufferGeometryUtils = BufferGeometryUtils; THREE.LightProbeGenerator = LightProbeGenerator; THREE.TransformControls = TransformControls; +THREE.GLTFExporter = GLTFExporter; //THREE.Text = Text export default THREE; diff --git a/src/3rd/js/plugin/frontend/$editor.js b/src/3rd/js/plugin/frontend/$editor.js index a6d8c73..8b21ba1 100644 --- a/src/3rd/js/plugin/frontend/$editor.js +++ b/src/3rd/js/plugin/frontend/$editor.js @@ -1,4 +1,62 @@ // reactive component for displaying the menu + +$editorPopup = (el) => new Proxy({ + + html: (opts) => ` +
+ #${$editor.selected.name} + + + + + + + + + + + + + + + +
href + +
src + +
tag + +
+
+ + `, + + init(opts){ + el.innerHTML = this.html(opts) + return el + }, + +},{ + + get(me,k,v){ return me[k] }, + + set(me,k,v){ + me[k] = v + } + +}) + + $editor = (el,opts) => new Proxy({ html: ` @@ -13,6 +71,10 @@ $editor = (el,opts) => new Proxy({ width: 30px; margin-top: 7px; } + .edit-btn.enabled, + .edit-btn.enabled:hover{ + background:black; + } .edit-btn i.gg-pen{ margin-top: -26px; margin-left: 4px; @@ -30,23 +92,26 @@ $editor = (el,opts) => new Proxy({ el.innerHTML = this.html window.frontend.el.querySelector('#topbar').appendChild(el); el.querySelector('.edit-btn').addEventListener('click', () => $editor.enabled = true ) + + document.addEventListener('download', (e) => this.updateOriginalScene(e.detail) ) return this }, editNode(){ if( !this.enabled ) return console.log("not editing") - console.log("click!") - $editor.enabled = false // disable selections + $editor.enabled = false // disable selections this.enableHref(this.selected,true) // re-enable hrefs - notify(`${this.selected.name}
${this.getMetaData(this.selected)}`) - notify(`XR Fragment: #${this.selected.name}

${this.getMetaData(this.selected)}`) + //`XR Fragment: #${this.selected.name}

${this.getMetaData(this.selected)}`),{ + notify( $editorPopup( document.createElement('div') ).init(this) , { + timeout:false, + onclose: () => xrf.scene.remove( this.helper ) + }) }, initEdit(scene){ AFRAME.scenes[0].addEventListener('click', () => this.editNode() ) scene.traverse( (n) => { let highlight = (n) => (e) => { - console.log(n.name) if( this.selected ) this.enableHref(this.selected,true) // re-enable href of previous selection if( this.helper){ if( this.helper.selected == n.uuid ) return // already selected @@ -62,17 +127,20 @@ $editor = (el,opts) => new Proxy({ xrf.scene.add(this.helper) let div = document.createElement('div') - notify(`XR Fragment: #${n.name}

${this.getMetaData(this.selected)}`) + notify(`#${n.name}
${this.getMetaData(this.selected)}`) this.enableHref(n,false) // prevent clicks from doing their usual teleporting/executions } - if( n.geometry ) n.addEventListener('mousemove', n.highlightOnMouseMove = highlight(n) ) + if( n.material ) n.addEventListener('mousemove', n.highlightOnMouseMove = highlight(n) ) }) console.log("inited scene") }, getMetaData(n){ - return `href: ${n.userData.href}
src: ${n.userData.src}
tag: ${n.userData.tag}` + let html = `${n.userData.href ? `href${n.userData.href}
`:''}` + html += `${n.userData.src ? `src${n.userData.src}
` :''}` + html += `${n.userData.tag ? `tag${n.userData.tag}
` :''}` + return html }, enableHref(n, state){ @@ -86,6 +154,15 @@ $editor = (el,opts) => new Proxy({ n.userData.XRF.href.exec = exec.bak } } + }, + + updateOriginalScene(opts){ + let {scene,ext} = opts + xrf.scene.traverse( (n) => { + if( n.edited && scene.getObjectByName(n.name) ){ + scene.getObjectByName(n.name).userData = n.userData + } + }) } }, @@ -98,20 +175,25 @@ $editor = (el,opts) => new Proxy({ switch( k ){ case "enabled":{ + lookctl = $('[look-controls]').components['look-controls'] if( v ){ + lookctl.pause() // prevent click-conflict notify("click an object to reveal XR Fragment metadata") xrf.interactive.raycastAll = true if( !xrf.scene.initEdit ) me.initEdit(xrf.scene) + + lookctl.pause() // prevent click-conflict + el.querySelector('.edit-btn').classList.add(['enabled']) }else{ - console.log("idsabled") + lookctl.pause() // prevent click-conflict xrf.scene.traverse( (n) => { me.enableHref(n,true) if( n.highlightOnMouseMove ){ n.removeEventListener( 'mousemove', n.highlightOnMouseMove ) } }) - me.helper.remove() - console.log("removed events") + lookctl.play() // prevent click-conflict (resume) + el.querySelector('.edit-btn').classList.remove(['enabled']) } break; } diff --git a/src/3rd/js/plugin/frontend/frontend.js b/src/3rd/js/plugin/frontend/frontend.js index 9300013..2c282f4 100644 --- a/src/3rd/js/plugin/frontend/frontend.js +++ b/src/3rd/js/plugin/frontend/frontend.js @@ -239,15 +239,38 @@ window.frontend = (opts) => new Proxy({ }, download(){ - function fetchAndDownload(dataurl, filename) { + // setup exporters + let defaultExporter = THREE.GLTFExporter + xrf.loaders['gltf'].exporter = defaultExporter + xrf.loaders['glb'].exporter = defaultExporter + + function download(dataurl, filename) { var a = document.createElement("a"); a.href = dataurl; a.setAttribute("download", filename); a.click(); return false; } - let file = document.location.search.replace(/\?/,'') - fetchAndDownload( file, file ) + + function exportScene(scene,ext){ + const exporter = new (xrf.loaders[ext].exporter || defaultExporter) + document.dispatchEvent( new CustomEvent('download',{detail:{scene,ext}}) ) + exporter.parse( + scene, + function ( glb ) { download(glb, `${file}.${ext}`) }, // ready + function ( error ) { console.error(error) }, // error + {binary:true} + ); + } + + // load original scene and overwrite with updates + let url = document.location.search.replace(/\?/,'') + let {urlObj,dir,file,hash,ext} = xrf.navigator.origin = xrf.parseUrl(url) + const Loader = xrf.loaders[ext] + loader = new Loader().setPath( dir ) + loader.load(url, (model) => { + exportScene(model.scene,ext,file) + }) }, updateHashPosition(randomize){ @@ -269,9 +292,11 @@ window.frontend = (opts) => new Proxy({ let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}` let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'') - newHash += `&${lastPos}` - document.location.hash = newHash.replace(/&&/,'&') - .replace(/#&/,'') + if( lastPos != "pos=" ){ + newHash += `&${lastPos}` + document.location.hash = newHash.replace(/&&/,'&') + .replace(/#&/,'') + } this.copyToClipboard( window.location.href ); }, diff --git a/src/3rd/js/plugin/frontend/snackbar.js b/src/3rd/js/plugin/frontend/snackbar.js index 07d9b46..1eeaf6f 100644 --- a/src/3rd/js/plugin/frontend/snackbar.js +++ b/src/3rd/js/plugin/frontend/snackbar.js @@ -131,6 +131,8 @@ window.SnackBar = function(userOptions) { _Container.removeChild(_Element); } catch (e) { } }, 1000); + if( _Options.onclose ) _Options.onclose() + }; _Options = { ..._OptionDefaults, ...userOptions } diff --git a/src/xrfragment/XRF.hx b/src/xrfragment/XRF.hx index 08020ef..8ba17b5 100644 --- a/src/xrfragment/XRF.hx +++ b/src/xrfragment/XRF.hx @@ -95,6 +95,7 @@ class XRF { guessType(this, value); // 1. extract the type // validate var ok:Bool = true; + if( value.length == 0 ) ok = false; if( !is(T_FLOAT) && is(T_VECTOR2) && !(Std.isOfType(x,Float) && Std.isOfType(y,Float)) ) ok = false; if( !(is(T_VECTOR2) || is(T_STRING)) && is(T_VECTOR3) && !(Std.isOfType(x,Float) && Std.isOfType(y,Float) && Std.isOfType(z,Float)) ) ok = false; return ok;