huge refactor because of xrmacro vs xrfragment separation+2

This commit is contained in:
Leon van Kammen 2023-09-14 10:21:16 +02:00
parent ed5ecc5be6
commit 89e5af7d28
17 changed files with 85 additions and 203 deletions

View file

@ -38,7 +38,7 @@ window.AFRAME.registerComponent('xrf-button', {
el.setAttribute('material', { el.setAttribute('material', {
color: this.color, color: this.color,
transparent:true, transparent:true,
opacity:0.3 opacity:0.5
}); });
el.setAttribute('pressable', ''); el.setAttribute('pressable', '');
labelEl.setAttribute('position', '0 0 0.01'); labelEl.setAttribute('position', '0 0 0.01');

View file

@ -57,9 +57,11 @@ xrf.parseModel = function(model,url){
xrf.getLastModel = () => xrf.model.last xrf.getLastModel = () => xrf.model.last
xrf.eval = function( url, model, flags ){ // evaluate fragments in url xrf.eval = function( url, model, flags ){ // evaluate fragments in url
if( !url ) return
if( !url.match(/#/) ) url = `#${url}`
model = model || xrf.model model = model || xrf.model
let { THREE, camera } = xrf 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 } let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
xrf.emit('eval',opts) xrf.emit('eval',opts)
.then( () => { .then( () => {
@ -67,6 +69,7 @@ xrf.eval = function( url, model, flags ){ // evaluate fragments in url
xrf.eval.fragment(k,opts) xrf.eval.fragment(k,opts)
} }
}) })
return frag
} }
xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model xrf.eval.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) inside mesh of model

View file

@ -8,6 +8,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
if( !file || xrf.model.file == file ){ // we're already loaded if( !file || xrf.model.file == file ){ // we're already loaded
xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments xrf.eval( url, xrf.model, flags ) // and eval local URI XR fragments
xrf.navigator.updateHash(hash)
return resolve(xrf.model) 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) // spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
xrf.eval( url, model ) // and eval URI XR fragments xrf.eval( url, model ) // and eval URI XR fragments
xrf.add( model.scene ) 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.eval( '#pos=0,0,0' ) // set default position if not specified
}
xrf.navigator.updateHash(hash)
resolve(model) resolve(model)
} }

View file

@ -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 )
}

View file

@ -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`)
}

View file

@ -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 );
}

View file

@ -96,9 +96,10 @@ xrf.frag.href = function(v, opts){
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree .emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => { .then( () => {
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
//const flags = v.string[0] == '#' && v.string.match(/(\||#q)/) ? xrf.XRF.PV_OVERRIDE : undefined // always keep a trail of last positions before we navigate
if( !v.string.match(/pos=/) ) v.string += `${v.string[0] == '#' ? '&' : '#'}${lastPos}` // always commit last position if( !v.string.match(/pos=/) ) v.string += `${v.string[0] == '#' ? '&' : '#'}${lastPos}`
console.log(v.string) if( !document.location.hash.match(/pos=/) ) xrf.navigator.to(`#${lastPos}`,flags)
xrf.navigator.to(v.string,flags) // let's surf to HREF! xrf.navigator.to(v.string,flags) // let's surf to HREF!
}) })
} }

View file

@ -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 ) )
})
}
}

View file

@ -1,21 +1,6 @@
xrf.frag.pos = function(v, opts){ xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
camera.position.x = v.x
if( frag.q ){ // only operate on queried object(s) camera.position.y = v.y
camera.position.z = v.z
// 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
}
} }

View file

@ -45,7 +45,7 @@ xrf.frag.updatePredefinedView = (opts) => {
let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE } 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 if( frag[k].is( xrf.XRF.PV_EXECUTE ) && scene.XRF_PV_ORIGIN != k ){ // cyclic detection
traverseScene(frag[k],scene) // recurse predefined views traverseScene(frag[k],scene) // recurse predefined views
}else xrf.eval.fragment(k,opts) }
} }
}) })
} }
@ -63,27 +63,28 @@ xrf.frag.updatePredefinedView = (opts) => {
}) })
} }
let pviews = [] // if this query was triggered by an src-value, lets filter it
for ( let i in frag ) { const isSRC = opts.embedded && opts.embedded.fragment == 'src'
let v = frag[i] if( isSRC ){ // spec : https://xrfragment.org/#src
if( v.is( xrf.XRF.PV_EXECUTE ) ){ console.log("filtering predefined view of src")
scene.XRF_PV_ORIGIN = v.string console.dir(frag)
if( v.args ) v = v.args[ xrf.roundrobin(v,xrf.model) ] }else{
// wait for nested instances to arrive at the scene ? for ( let i in frag ) {
traverseScene(v,scene) let v = frag[i]
if( v.string ) pviews.push(v.string) if( v.is( xrf.XRF.PV_EXECUTE ) ){
}else if( v.is( xrf.XRF.NAVIGATOR ) ) pviews.push(`${i}=${v.string}`) 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 // react to url changes
//xrf.addEventListener('updateHash', (opts) => { xrf.addEventListener('updateHash', (opts) => {
// console.log("update hash"); let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
// console.dir(opts) xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
// 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 // clicking href url with predefined view
xrf.addEventListener('href', (opts) => { xrf.addEventListener('href', (opts) => {

View file

@ -21,57 +21,21 @@ xrf.frag.q = function(v, opts){
return o return o
}) })
} }
xrf.frag.q.filter(scene,frag) // spec : https://xrfragment.org/#queries
// spec: https://xrfragment.org/#src }
const instanceScene = () => {
v.scene = new THREE.Group() xrf.frag.q.filter = function(scene,frag){
for ( let i in v.query ) { // spec: https://xrfragment.org/#queries
let target = v.query[i] let q = frag.q.query
if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`) scene.traverse( (mesh) => {
if( i == '*' ){ for ( let i in q ) {
let cloneScene = scene.clone() let isMeshId = q[i].id != undefined
// add interactive elements (href's e.g.) *TODO* this is called by both internal/external src's let isMeshClass = q[i].class != undefined
v.scene.add( xrf.interactive.clone() ) let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId && !isMeshClass
cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) ) if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
target.mesh = v.scene if( isMeshId && i == mesh.name ) mesh.visible = q[i].id
}else{ if( isMeshClass && i == mesh.userData.class ) mesh.visible = q[i].class
if( !v.scene.getObjectByName(i) && target.id === true ){ if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])
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
} }

View file

@ -1,24 +1,10 @@
xrf.frag.rot = function(v, opts){ xrf.frag.rot = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera rotation to "+v.string)
// apply roundrobin (if any) camera.rotation.set(
if( v.args ) v = v.args[ xrf.roundrobin(v,model) ] v.x * Math.PI / 180,
v.y * Math.PI / 180,
if( frag.q ){ // only operate on queried object(s) v.z * Math.PI / 180
frag.q.getObjects().map( (o) => { )
o.rotation.set( camera.updateMatrixWorld()
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()
}
} }

View file

@ -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
})
}
}

View file

@ -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;
})
}
}

View file

@ -10,27 +10,29 @@ xrf.frag.src = function(v, opts){
let frag = xrfragment.URI.parse(v.string) let frag = xrfragment.URI.parse(v.string)
const localSRC = () => { const localSRC = () => {
let obj
setTimeout( () => {
// scale URI XR Fragments inside src-value // cherrypicking of object(s)
if( !frag.q ){
for( var i in frag ){ 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})) xrf.eval.fragment(i, Object.assign(opts,{frag, model,scene}))
} }
if( frag.q.query ){ if( src.children.length == 1 ) obj.position.set(0,0,0);
let srcScene = frag.q.scene // three/xrf/q.js initializes .scene }
if( !srcScene || !srcScene.visible ) return
console.log(" └ inserting "+i+" (srcScene)") // filtering of objects using query
srcScene.position.set(0,0,0) if( frag.q ){
srcScene.rotation.set(0,0,0) src = scene.clone();
srcScene.traverse( (m) => { src.isSRC = true;
m.isSRC = true xrf.frag.q.filter(src,frag)
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion }
xrf.eval.mesh(m,{scene,recursive:true}) src.traverse( (m) => {
}) m.isSRC = true
if( srcScene.visible ) src.add( srcScene ) 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 ) })
},10) xrf.frag.src.scale( src, opts )
} }
const externalSRC = () => { const externalSRC = () => {
@ -46,8 +48,8 @@ xrf.frag.src = function(v, opts){
.catch( console.error ) .catch( console.error )
} }
if( v.string[0] == "#" ) localSRC() // current file if( v.string[0] == "#" ) setTimeout( localSRC, 10 ) // current file
else externalSRC() // external file else externalSRC() // external file
} }
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects // scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects

View file

@ -85,9 +85,10 @@ class Parser {
} }
store.set(key, v ); // 1. if valid, add to store store.set(key, v ); // 1. if valid, add to store
if( debug ) trace(" "+key+": "+v.string); 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); if( Std.isOfType(value, String) ) v.guessType(v,value);
store.set("_"+key,v); v.noXRF = true;
store.set(key,v);
} }
return true; return true;

View file

@ -56,6 +56,7 @@ class XRF {
public var float:Float; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 | public var float:Float; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 |
public var args:Array<XRF>; // |array | mixed| \|-separated | #pos=0,0,0\|90,0,0 | public var args:Array<XRF>; // |array | mixed| \|-separated | #pos=0,0,0\|90,0,0 |
public var query:Query; public var query:Query;
public var noXRF:Bool;
// //
public function new(_fragment:String,_flags:Int){ public function new(_fragment:String,_flags:Int){
fragment = _fragment; fragment = _fragment;