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}
+
+
+
+ `,
+
+ 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;