From 89e5af7d282eac34f3db6c0e2e67d409f51c7005 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Thu, 14 Sep 2023 10:21:16 +0200 Subject: [PATCH] huge refactor because of xrmacro vs xrfragment separation+2 --- src/3rd/js/aframe/xrf-button.js | 2 +- src/3rd/js/three/index.js | 5 +- src/3rd/js/three/navigator.js | 5 +- src/3rd/js/three/xrf/bg.js | 7 --- src/3rd/js/three/xrf/env.js | 11 ---- src/3rd/js/three/xrf/fog.js | 9 ---- src/3rd/js/three/xrf/href.js | 7 +-- src/3rd/js/three/xrf/mov.js | 10 ---- src/3rd/js/three/xrf/pos.js | 21 ++------ src/3rd/js/three/xrf/predefinedView.js | 37 +++++++------- src/3rd/js/three/xrf/q.js | 70 +++++++------------------- src/3rd/js/three/xrf/rot.js | 28 +++-------- src/3rd/js/three/xrf/scale.js | 15 ------ src/3rd/js/three/xrf/show.js | 13 ----- src/3rd/js/three/xrf/src.js | 42 ++++++++-------- src/xrfragment/Parser.hx | 5 +- src/xrfragment/XRF.hx | 1 + 17 files changed, 85 insertions(+), 203 deletions(-) delete mode 100644 src/3rd/js/three/xrf/bg.js delete mode 100644 src/3rd/js/three/xrf/env.js delete mode 100644 src/3rd/js/three/xrf/fog.js delete mode 100644 src/3rd/js/three/xrf/mov.js delete mode 100644 src/3rd/js/three/xrf/scale.js delete mode 100644 src/3rd/js/three/xrf/show.js diff --git a/src/3rd/js/aframe/xrf-button.js b/src/3rd/js/aframe/xrf-button.js index 43ea9d6..14877e1 100644 --- a/src/3rd/js/aframe/xrf-button.js +++ b/src/3rd/js/aframe/xrf-button.js @@ -38,7 +38,7 @@ window.AFRAME.registerComponent('xrf-button', { el.setAttribute('material', { color: this.color, transparent:true, - opacity:0.3 + opacity:0.5 }); el.setAttribute('pressable', ''); labelEl.setAttribute('position', '0 0 0.01'); diff --git a/src/3rd/js/three/index.js b/src/3rd/js/three/index.js index 36c854b..468d526 100644 --- a/src/3rd/js/three/index.js +++ b/src/3rd/js/three/index.js @@ -57,9 +57,11 @@ xrf.parseModel = function(model,url){ xrf.getLastModel = () => xrf.model.last xrf.eval = function( url, model, flags ){ // evaluate fragments in url + if( !url ) return + if( !url.match(/#/) ) url = `#${url}` model = model || xrf.model let { THREE, camera } = xrf - let frag = xrf.URI.parse( url, flags || xrf.XRF.NAVIGATOR ) + let frag = xrf.URI.parse( url, flags != undefined ? flags : xrf.XRF.NAVIGATOR ) let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } xrf.emit('eval',opts) .then( () => { @@ -67,6 +69,7 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url xrf.eval.fragment(k,opts) } }) + return frag } xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model diff --git a/src/3rd/js/three/navigator.js b/src/3rd/js/three/navigator.js index ce93df9..85f2474 100644 --- a/src/3rd/js/three/navigator.js +++ b/src/3rd/js/three/navigator.js @@ -8,6 +8,7 @@ xrf.navigator.to = (url,flags,loader,data) => { if( !file || xrf.model.file == file ){ // we're already loaded xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments + xrf.navigator.updateHash(hash) return resolve(xrf.model) } @@ -33,8 +34,10 @@ xrf.navigator.to = (url,flags,loader,data) => { // spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view) xrf.eval( url, model ) // and eval URI XR fragments xrf.add( model.scene ) - if( !hash.match(/pos=/) ) + if( !hash.match(/pos=/) ){ xrf.eval( '#pos=0,0,0' ) // set default position if not specified + } + xrf.navigator.updateHash(hash) resolve(model) } diff --git a/src/3rd/js/three/xrf/bg.js b/src/3rd/js/three/xrf/bg.js deleted file mode 100644 index 0ed938b..0000000 --- a/src/3rd/js/three/xrf/bg.js +++ /dev/null @@ -1,7 +0,0 @@ -xrf.frag.bg = function(v, opts){ - let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - console.log("└ bg "+v.x+","+v.y+","+v.z); - if( scene.background ) delete scene.background - scene.background = new THREE.Color( v.x, v.y, v.z ) -} diff --git a/src/3rd/js/three/xrf/env.js b/src/3rd/js/three/xrf/env.js deleted file mode 100644 index 25d204a..0000000 --- a/src/3rd/js/three/xrf/env.js +++ /dev/null @@ -1,11 +0,0 @@ -xrf.frag.env = function(v, opts){ - let { mesh, model, camera, scene, renderer, THREE} = opts - let env = mesh.getObjectByName(v.string) - if( !env ) return console.warn("xrf.env "+v.string+" not found") - env.material.map.mapping = THREE.EquirectangularReflectionMapping; - scene.environment = env.material.map - //scene.texture = env.material.map - renderer.toneMapping = THREE.ACESFilmicToneMapping; - renderer.toneMappingExposure = 2; - console.log(` └ applied image '${v.string}' as environment map`) -} diff --git a/src/3rd/js/three/xrf/fog.js b/src/3rd/js/three/xrf/fog.js deleted file mode 100644 index 8ccc87f..0000000 --- a/src/3rd/js/three/xrf/fog.js +++ /dev/null @@ -1,9 +0,0 @@ -xrf.frag.fog = function(v, opts){ - let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - console.log("└ fog "+v.x+","+v.y); - if( v.x == 0 && v.y == 0 ){ - if( scene.fog ) delete scene.fog - scene.fog = null; - }else scene.fog = new THREE.Fog( scene.background, v.x, v.y ); -} diff --git a/src/3rd/js/three/xrf/href.js b/src/3rd/js/three/xrf/href.js index f52f16b..4a17011 100644 --- a/src/3rd/js/three/xrf/href.js +++ b/src/3rd/js/three/xrf/href.js @@ -96,9 +96,10 @@ xrf.frag.href = function(v, opts){ .emit('href',{click:true,mesh,xrf:v}) // let all listeners agree .then( () => { const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined - //const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined - if( !v.string.match(/pos=/) ) v.string += `${v.string[0] == '#' ? '&' : '#'}${lastPos}` // always commit last position - console.log(v.string) + // always keep a trail of last positions before we navigate + if( !v.string.match(/pos=/) ) v.string += `${v.string[0] == '#' ? '&' : '#'}${lastPos}` + if( !document.location.hash.match(/pos=/) ) xrf.navigator.to(`#${lastPos}`,flags) + xrf.navigator.to(v.string,flags) // let's surf to HREF! }) } diff --git a/src/3rd/js/three/xrf/mov.js b/src/3rd/js/three/xrf/mov.js deleted file mode 100644 index 60dbe1b..0000000 --- a/src/3rd/js/three/xrf/mov.js +++ /dev/null @@ -1,10 +0,0 @@ -xrf.frag.mov = function(v, opts){ - let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - if( frag.q ){ // only operate on queried object(s) - frag.q.getObjects().map( (o) => { - o.position.add( new THREE.Vector3( v.x, v.y, v.z ) ) - }) - } - -} diff --git a/src/3rd/js/three/xrf/pos.js b/src/3rd/js/three/xrf/pos.js index 3779b6e..4a00a78 100644 --- a/src/3rd/js/three/xrf/pos.js +++ b/src/3rd/js/three/xrf/pos.js @@ -1,21 +1,6 @@ xrf.frag.pos = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - if( frag.q ){ // only operate on queried object(s) - - // apply roundrobin (if any) - if( v.args ) v = v.args[ xrf.roundrobin(v,model) ] - - frag.q.getObjects().map( (o) => { - // if object has no parent (name == 'Scene') use absolute positioning, otherwise relative to parent - o.position.x = o.parent.name == 'Scene' ? v.x : o.positionOriginal.x + v.x - o.position.y = o.parent.name == 'Scene' ? v.z : o.positionOriginal.y + v.z - o.position.z = o.parent.name == 'Scene' ? v.y : o.positionOriginal.z + v.y - }) - }else{ - camera.position.x = v.x - camera.position.y = v.y - camera.position.z = v.z - } - + camera.position.x = v.x + camera.position.y = v.y + camera.position.z = v.z } diff --git a/src/3rd/js/three/xrf/predefinedView.js b/src/3rd/js/three/xrf/predefinedView.js index 2969398..5731213 100644 --- a/src/3rd/js/three/xrf/predefinedView.js +++ b/src/3rd/js/three/xrf/predefinedView.js @@ -45,7 +45,7 @@ xrf.frag.updatePredefinedView = (opts) => { let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } if( frag[k].is( xrf.XRF.PV_EXECUTE ) && scene.XRF_PV_ORIGIN != k ){ // cyclic detection traverseScene(frag[k],scene) // recurse predefined views - }else xrf.eval.fragment(k,opts) + } } }) } @@ -63,27 +63,28 @@ xrf.frag.updatePredefinedView = (opts) => { }) } - let pviews = [] - for ( let i in frag ) { - let v = frag[i] - if( v.is( xrf.XRF.PV_EXECUTE ) ){ - scene.XRF_PV_ORIGIN = v.string - if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ] - // wait for nested instances to arrive at the scene ? - traverseScene(v,scene) - if( v.string ) pviews.push(v.string) - }else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`) + // if this query was triggered by an src-value, lets filter it + const isSRC = opts.embedded && opts.embedded.fragment == 'src' + if( isSRC ){ // spec : https://xrfragment.org/#src + console.log("filtering predefined view of src") + console.dir(frag) + }else{ + for ( let i in frag ) { + let v = frag[i] + if( v.is( xrf.XRF.PV_EXECUTE ) ){ + scene.XRF_PV_ORIGIN = v.string + // wait for nested instances to arrive at the scene ? + traverseScene(v,scene) + } + } } - if( pviews.length ) xrf.navigator.updateHash( pviews.join("&") ) } // react to url changes -//xrf.addEventListener('updateHash', (opts) => { -// console.log("update hash"); -// console.dir(opts) -// let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA ) -// xrf.frag.updatePredefinedView({frag,scene:xrf.scene}) -//}) +xrf.addEventListener('updateHash', (opts) => { + let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA ) + xrf.frag.updatePredefinedView({frag,scene:xrf.scene}) +}) // clicking href url with predefined view xrf.addEventListener('href', (opts) => { diff --git a/src/3rd/js/three/xrf/q.js b/src/3rd/js/three/xrf/q.js index 818086a..a911ae7 100644 --- a/src/3rd/js/three/xrf/q.js +++ b/src/3rd/js/three/xrf/q.js @@ -21,57 +21,21 @@ xrf.frag.q = function(v, opts){ return o }) } - - // spec: https://xrfragment.org/#src - const instanceScene = () => { - v.scene = new THREE.Group() - for ( let i in v.query ) { - let target = v.query[i] - if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`) - if( i == '*' ){ - let cloneScene = scene.clone() - // add interactive elements (href's e.g.) *TODO* this is called by both internal/external src's - v.scene.add( xrf.interactive.clone() ) - cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) ) - target.mesh = v.scene - }else{ - if( !v.scene.getObjectByName(i) && target.id === true ){ - console.log(` └ query-ing mesh: ${i}`) - v.scene.add( target.mesh = scene.getObjectByName(i).clone() ) - } - } - if( target.id != undefined && target.mesh ){ - target.mesh.position.set(0,0,0) - target.mesh.rotation.set(0,0,0) - } - } - // hide negative selectors - let negative = [] - v.scene.traverse( (mesh) => { - for ( let i in v.query ) { - if( mesh.name == i && v.query[i].id === false ) negative.push(mesh) - } - }) - negative.map( (mesh) => mesh.visible = false ) - } - - // spec: https://xrfragment.org/#queries - const showHide = () => { - let q = frag.q.query - scene.traverse( (mesh) => { - for ( let i in q ) { - let isMeshId = q[i].id != undefined - let isMeshClass = q[i].class != undefined - let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass - if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.) - if( isMeshId && i == mesh.name ) mesh.visible = q[i].id - if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class - if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i]) - } - }) - } - - const doLocalInstancing = opts.embedded && opts.embedded.fragment == 'src' && opts.embedded.string[0] == '#' - if( doLocalInstancing ) instanceScene() // spec : https://xrfragment.org/#src - else showHide() // spec : https://xrfragment.org/#queries + xrf.frag.q.filter(scene,frag) // spec : https://xrfragment.org/#queries +} + +xrf.frag.q.filter = function(scene,frag){ + // spec: https://xrfragment.org/#queries + let q = frag.q.query + scene.traverse( (mesh) => { + for ( let i in q ) { + let isMeshId = q[i].id != undefined + let isMeshClass = q[i].class != undefined + let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass + if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.) + if( isMeshId && i == mesh.name ) mesh.visible = q[i].id + if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class + if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i]) + } + }) } diff --git a/src/3rd/js/three/xrf/rot.js b/src/3rd/js/three/xrf/rot.js index 0887c99..578825e 100644 --- a/src/3rd/js/three/xrf/rot.js +++ b/src/3rd/js/three/xrf/rot.js @@ -1,24 +1,10 @@ xrf.frag.rot = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - // apply roundrobin (if any) - if( v.args ) v = v.args[ xrf.roundrobin(v,model) ] - - if( frag.q ){ // only operate on queried object(s) - frag.q.getObjects().map( (o) => { - o.rotation.set( - v.x * Math.PI / 180, - v.y * Math.PI / 180, - v.z * Math.PI / 180 - ) - }) - }else{ - console.log(" └ setting camera rotation to "+v.string) - camera.rotation.set( - v.x * Math.PI / 180, - v.y * Math.PI / 180, - v.z * Math.PI / 180 - ) - camera.updateMatrixWorld() - } + console.log(" └ setting camera rotation to "+v.string) + camera.rotation.set( + v.x * Math.PI / 180, + v.y * Math.PI / 180, + v.z * Math.PI / 180 + ) + camera.updateMatrixWorld() } diff --git a/src/3rd/js/three/xrf/scale.js b/src/3rd/js/three/xrf/scale.js deleted file mode 100644 index 9fcdf37..0000000 --- a/src/3rd/js/three/xrf/scale.js +++ /dev/null @@ -1,15 +0,0 @@ -xrf.frag.scale = function(v, opts){ - let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - // apply roundrobin (if any) - if( v.args ) v = v.args[ xrf.roundrobin(v,model) ] - - if( frag.q ){ // only operate on queried object(s) - frag.q.getObjects().map( (o) => { - o.scale.x = v.x - o.scale.y = v.y - o.scale.z = v.z - }) - } - -} diff --git a/src/3rd/js/three/xrf/show.js b/src/3rd/js/three/xrf/show.js deleted file mode 100644 index a2c0551..0000000 --- a/src/3rd/js/three/xrf/show.js +++ /dev/null @@ -1,13 +0,0 @@ -xrf.frag.show = function(v, opts){ - let { frag, mesh, model, camera, scene, renderer, THREE} = opts - - // apply roundrobin (if any) - if( v.args ) v = v.args[ xrf.roundrobin(v,model) ] - - if( frag.q ){ // only operate on queried object(s) - frag.q.getObjects().map( (o) => { - o.visible = v.int == 1; - }) - } - -} diff --git a/src/3rd/js/three/xrf/src.js b/src/3rd/js/three/xrf/src.js index 1bee51f..82223db 100644 --- a/src/3rd/js/three/xrf/src.js +++ b/src/3rd/js/three/xrf/src.js @@ -10,27 +10,29 @@ xrf.frag.src = function(v, opts){ let frag = xrfragment.URI.parse(v.string) const localSRC = () => { - - setTimeout( () => { - // scale URI XR Fragments inside src-value + let obj + + // cherrypicking of object(s) + if( !frag.q ){ for( var i in frag ){ + if( scene.getObjectByName(i) ) src.add( obj = scene.getObjectByName(i).clone() ) xrf.eval.fragment(i, Object.assign(opts,{frag, model,scene})) } - if( frag.q.query ){ - let srcScene = frag.q.scene // three/xrf/q.js initializes .scene - if( !srcScene || !srcScene.visible ) return - console.log(" └ inserting "+i+" (srcScene)") - srcScene.position.set(0,0,0) - srcScene.rotation.set(0,0,0) - srcScene.traverse( (m) => { - m.isSRC = true - if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion - xrf.eval.mesh(m,{scene,recursive:true}) - }) - if( srcScene.visible ) src.add( srcScene ) - } - xrf.frag.src.scale( src, opts ) - },10) + if( src.children.length == 1 ) obj.position.set(0,0,0); + } + + // filtering of objects using query + if( frag.q ){ + src = scene.clone(); + src.isSRC = true; + xrf.frag.q.filter(src,frag) + } + src.traverse( (m) => { + m.isSRC = true + if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion + xrf.eval.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src + }) + xrf.frag.src.scale( src, opts ) } const externalSRC = () => { @@ -46,8 +48,8 @@ xrf.frag.src = function(v, opts){ .catch( console.error ) } - if( v.string[0] == "#" ) localSRC() // current file - else externalSRC() // external file + if( v.string[0] == "#" ) setTimeout( localSRC, 10 ) // current file + else externalSRC() // external file } // scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects diff --git a/src/xrfragment/Parser.hx b/src/xrfragment/Parser.hx index 9cb3692..5d652fb 100644 --- a/src/xrfragment/Parser.hx +++ b/src/xrfragment/Parser.hx @@ -85,9 +85,10 @@ class Parser { } store.set(key, v ); // 1. if valid, add to store if( debug ) trace("✔ "+key+": "+v.string); - }else{ // 1. prefix non-offical fragment key's with underscore (and add to store) + }else{ // 1. expose (but mark) non-offical fragments too if( Std.isOfType(value, String) ) v.guessType(v,value); - store.set("_"+key,v); + v.noXRF = true; + store.set(key,v); } return true; diff --git a/src/xrfragment/XRF.hx b/src/xrfragment/XRF.hx index cda44c1..3e72cf6 100644 --- a/src/xrfragment/XRF.hx +++ b/src/xrfragment/XRF.hx @@ -56,6 +56,7 @@ class XRF { public var float:Float; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 | public var args:Array; // |array | mixed| \|-separated | #pos=0,0,0\|90,0,0 | public var query:Query; + public var noXRF:Bool; // public function new(_fragment:String,_flags:Int){ fragment = _fragment;