From 2262168c3e788b373afb3a48097a6768805ab7ce Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Fri, 24 Nov 2023 17:32:53 +0100 Subject: [PATCH] stable: new filters work + separated scenes + pos=world1 works --- doc/RFC_XR_Fragments.md | 30 +++++- example/assets/index.glb | Bin 1830088 -> 1964824 bytes src/3rd/js/aframe/index.js | 13 ++- src/3rd/js/three/hashbus.js | 1 - src/3rd/js/three/index.js | 6 ++ src/3rd/js/three/util/collision.js | 9 ++ src/3rd/js/three/xrf/dynamic/filter.js | 82 ++++++++-------- src/3rd/js/three/xrf/pos.js | 18 +++- src/3rd/js/three/xrf/src.js | 8 +- src/3rd/js/three/xrf/src/audio.js | 2 + src/3rd/js/three/xrf/src/non-euclidian.js | 11 ++- src/Test.hx | 2 + src/spec/filter.selectors.json | 6 +- src/spec/pos.json | 6 ++ src/spec/url.json | 2 - src/xrfragment/Filter.hx | 24 ++--- src/xrfragment/Parser.hx | 11 ++- src/xrfragment/XRF.hx | 19 ++-- test/aframe/filter.js | 108 +++++++++------------- 19 files changed, 202 insertions(+), 156 deletions(-) create mode 100644 src/3rd/js/three/util/collision.js create mode 100644 src/spec/pos.json diff --git a/doc/RFC_XR_Fragments.md b/doc/RFC_XR_Fragments.md index a6519f0..d44d70a 100644 --- a/doc/RFC_XR_Fragments.md +++ b/doc/RFC_XR_Fragments.md @@ -279,7 +279,7 @@ For example, to render a portal with a preview-version of the scene, create an 3 | fragment | type | functionality | |----------|--------|------------------------------| -| #pos=0,0,0 | vector3 | (re)position camera | +| #pos=0,0,0 | vector3 or string| (re)position camera based on coordinates directly, or indirectly using objectname (its worldposition) | | #t=0,100 | vector3 | set playback speed, and (re)position looprange of scene-animation or `src`-mediacontent | | #rot=0,90,0 | vector3 | rotate camera | @@ -366,7 +366,7 @@ Resizing will be happen accordingly to its placeholder object `aquariumcube`, se 1. local/remote content is instanced by the `src` (filter) value (and attaches it to the placeholder mesh containing the `src` property) 2. by default all objects are loaded into the instanced src (scene) object (but not shown yet) -2. local `src` values (`#...` e.g.) starting with a non-negating filter (`#cube` e.g.) will make that object (with name `cube`) the new root of the scene at position 0,0,0 +2. local `src` values (`#...` e.g.) starting with a non-negating filter (`#cube` e.g.) will (deep)reparent that object (with name `cube`) as the new root of the scene at position 0,0,0 3. local `src` values should respect (negative) filters (`#-foo&price=>3`) 4. the instanced scene (from a `src` value) should be scaled accordingly to its placeholder object or scaled relatively based on the scale-property (of a geometry-less placeholder, an 'empty'-object in blender e.g.). For more info see Chapter Scaling. 5. external `src` values should be served with appropriate mimetype (so the XR Fragment-compatible browser will now how to render it). The bare minimum supported mimetypes are: @@ -415,6 +415,14 @@ navigation, portals & mutations [» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/href.gltf#L192)
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/1)
+## Walking surfaces + +XR Fragment-compatible viewers can infer this data based scanning the scene for: + +1. materialless (nameless & textureless) mesh-objects (without `src` and `href`) + +> optionally the viewer can offer thumbstick, mouse or joystick teleport-tools for non-roomscale VR/AR setups. + ## UX spec End-users should always have read/write access to: @@ -503,16 +511,19 @@ It's simple but powerful syntax which allows filtering the scene using searcheng ## including/excluding +By default, selectors work like photoshop-layers: they scan for matching layer(name/properties) within the scene-graph. +Each matched object (not their children) will be toggled (in)visible when selecting. + | operator | info | |----------|-------------------------------------------------------------------------------------------------------------------------------| | `-` | hides object(s) (`#-myobject&-objects` e.g. | | `=` | indicates an object-embedded custom property key/value (`#price=4&category=foo` e.g.) | | `=>` `=<`| compare float or int number (`#price=>4` e.g.) | -| `/` | reference to root-scene.
Useful in case of (preventing) showing/hiding objects in nested scenes (instanced by `src`) (*) | +| `*` | deepselect: automatically select children of selected object, including local (nonremote) embedded objects (starting with `#`)| -> \* = `#-/cube` hides object `cube` only in the root-scene (not nested `cube` objects)
`#-cube` hides both object `cube` in the root-scene AND nested `skybox` objects | +> NOTE 1: after an external embedded object has been instanced (`src: https://y.com/bar.fbx#room` e.g.), filters do not affect them anymore (reason: local tag/name collisions can be mitigated easily, but not in case of remote content). -Nested selection is always implied (there's no `*` `>`/`<` css-like operators on purpose) which keeps XR Fragments easy to implement, and still allows fine-grained control chaining nested selectors (`#-sky&house&-table` e.g.). +> NOTE 2: depending on the used 3D framework, toggling objects (in)visible should happen by enabling/disableing writing to the colorbuffer (to allow children being still visible while their parents are invisible). [» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/q.js) [» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/filter.gltf#L192) @@ -929,6 +940,15 @@ This document has no IANA actions. * [NLNET](https://nlnet.nl) * [Future of Text](https://futureoftext.org) * [visual-meta.info](https://visual-meta.info) +* Michiel Leenaars +* Gerben van der Broeke +* Mauve +* Jens Finkhäuser +* Marc Belmont +* Tim Gerritsen +* Frode Hegland +* Brandel Zackernuk +* Mark Anderson # Appendix: Definitions diff --git a/example/assets/index.glb b/example/assets/index.glb index 72dae665648e5c7fe0fb6ae5efdac31156b6aa4a..2f3cdbf42bf607bd6fd2b9cd13a3e3b9ffde744b 100644 GIT binary patch delta 122007 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 delta 76851 zcmeFZcYGC9_vk${2_f`ALT^cso^pDDyi( zAtzve04a)!9mL)Mu{Z8_?U}$i!QcIS?tSl{FPh!g-fOSE_spDoewq9FdsAy&GpT=9 zL({a^ziX^@|6bo#YlE?UyK$mYfj7tP^5wYQo*cKw#h;r$Dbwzu-Q(vkz+aHR5P#tu zx0i8V#(B*@QrEhIK3_QC3Wj`PnIkXc4+aB%>VBUu;0^$0H-+56U^o|!dW}1N4=Vv#eKu#`=ewQ~C^m>CKa-S>UGe?ieFkLko znggm`>kqraUbip61a6R*IYKUvKNR!__zQ>KAx}=OCokyr_+4SQ?9CPSyUm}feQ!>i zl^phlJudJKyI9ff_j?827iO}6-{HTcuh*@%&rlzDhh4A*ZVOq#Iq31w z7GS$Bx7TMLt@TxrkQVa81(zof2!zSh{{23;4-pE42Iid-AxM z6ME*FL|?#fB7R{tey>wL>0g2BU*Puj$Wl;MqF_^8{GH6Yz-)AbG40UUZ=j zE@|`nLV&Tc~H;RYYrIQY@qFzSoq``pO5ngFdwI(+W1%O{K!B6vb! zKSV+bkfBgebYuH34IAlAknJG4i;7`M0-g|)ASg%?&1O#H(_jhqZg&u&1|C}YY%TKo zSQSfxeL=95=y)Kt=r%G0e8@a~Y1_MJR5ovGvgZGjEpeu~v*|{2d3LfG3FH_~_&l)1 zuhb8vgkCPUm^IYGFN8#$Fc_%0%Nz8Wr&pw#nK>!uBbgp^Nwccv=b7`7Km-!uP?k3j zJK@8mxY0qcGIbub3H=mCp#46N&s>&OWPXrY)jXQDE5Is@#m0uQ4qi`=Cokk;*XRz? zjEM|{1T&TZt8mB zg5_cszswx+20|e)6wv}J1|t9X4$(rtnYEy{^!q+y>M zg9?Gs9HdP(K`^Rbv=xtd!KiX%^q{%4+5Dh84q(&fd|1ldVY>}UeHeK{Wg z@Emj6>3Zgt<~6HbGH&Lq2~$STnlN<=w8=MPO|CYFW_B}O3vvy2$ei2iRh%&zfi_~3 zkT-0WXsO6$7(ayxW&h$@lu-q*FwO`w6!eCDSR3KSovrJbyV_JWA8x(NK*N-4_fh@qXU~ ze<#u#RJ_1kou4NZQ1<2pU$v@NPntS)#>`n$r;IcI@Gmu&1*_mC!3iBkWkmLHofsj4 zK>SQltQcq!Qh6|w;)WopOPMdj>oQAyuVMata20dq6*o_ah3tx@bBkke+nn;cU>d@N zM}@j!q`AQSAyCb%9oplSumfi#HcBQyA_)f2VGJG7A}z#R#28`X5=M(xG00OT?@ksbji|RuYFw z1c@B7ZC751SP9;-5o|P^6nJkKI>~Ol5Socq^itTlrP;J7-MqBe#GMe+5ZR%6OrbV` z9rj{kv1B$mWE0>|s0YarXSInoom!f~;@akjPAi3#EJ|FC1PLD4KOe>iGmmTVD@yoq z%eZQGfrm#$B#dfk7G7M#K&*OPyotSqB$no=p_CDG6GoIVgJ?E#qG-YXh1%li6|NMa;vr2T z#X+TTxDO`9`6)r-pa5lwwg_tp%M|nv-D{by%l71pg8GTRIQ8PZiOaDK2&Nnm1(r~c zqZY1{0Mic^z!sZhE-&K@3cWEBP*yB3OoA<<%$RWqqShr+V;WAaOo-mgx_ZdGrN==( zmK)`jLkyYM)sGTFag03cL8F`iyf!l!xF>2uqT^zG4p z$+|kJAQ`X*>+UD8K~?J@Ze3%Ux#EQ&73jTtTnVQZXxrI2Ik^{Tjh9Cz=@Ot z6sDTcGAI^Mk&Ft)9q)n^hty$-NH_p3{e)^re8?tQlc6om)q}RnMA#}KQ49s=S-B92 zn+LPtN0Wn!lX3@xG2#%7gdn{^b$|28kQ8&>;Ogf5K~2rq25&DykU3rw>4^SHWT=9F z0(nRJku@<7vIr(n?kj?LRz%C|QM?qyKE85?94^p&AAX%M66Ylc+Vhxk_+xgWGW*cU z%@U^!QkVeOIdlfiM+c{w$Cjm-_Y7aIb_t{L6c|)7%4|qj_phfpxoO~zLrfSV98i

tvH%Iq+h~;0{L?xhVLb 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 diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js index 7eb62ed..4d3ed9d 100644 --- a/src/3rd/js/aframe/index.js +++ b/src/3rd/js/aframe/index.js @@ -26,7 +26,18 @@ window.AFRAME.registerComponent('xrf', { }) if( !XRF.camera ) throw 'xrfragment: no camera detected, please declare ABOVE entities with xrf-attributes' - xrf.addEventListener('navigateLoaded', () => setTimeout( () => AFRAME.fade.out(),500) ) + xrf.addEventListener('navigateLoaded', () => { + setTimeout( () => AFRAME.fade.out(),500) + + // *TODO* this does not really belong here perhaps + let blinkControls = document.querySelector('[blink-controls]') + if( blinkControls ){ + blinkControls = blinkControls.components['blink-controls'] + blinkControls.defaultCollisionMeshes = xrf.getCollisionMeshes() + blinkControls.update() + } + }) + xrf.addEventListener('href', (opts) => { if( opts.click){ let p = opts.promise() diff --git a/src/3rd/js/three/hashbus.js b/src/3rd/js/three/hashbus.js index 8bfe31f..1c9c158 100644 --- a/src/3rd/js/three/hashbus.js +++ b/src/3rd/js/three/hashbus.js @@ -48,7 +48,6 @@ pub.fragment = (k, opts ) => { // evaluate one fragment pub.XRWG = (opts) => { let {frag,scene,model,renderer} = opts - console.dir(opts) // if this query was triggered by an src-value, lets filter it const isSRC = opts.embedded && opts.embedded.fragment == 'src' diff --git a/src/3rd/js/three/index.js b/src/3rd/js/three/index.js index e251960..a74c6a6 100644 --- a/src/3rd/js/three/index.js +++ b/src/3rd/js/three/index.js @@ -100,3 +100,9 @@ xrf.add = (object) => { object.isXRF = true // mark for easy deletion when replacing scene xrf.scene.add(object) } + +xrf.hasNoMaterial = (mesh) => { + const hasTexture = mesh.material && mesh.material.map + const hasMaterialName = mesh.material && mesh.material.name.length > 0 + return mesh.geometry && !hasMaterialName && !hasTexture +} diff --git a/src/3rd/js/three/util/collision.js b/src/3rd/js/three/util/collision.js new file mode 100644 index 0000000..54895b8 --- /dev/null +++ b/src/3rd/js/three/util/collision.js @@ -0,0 +1,9 @@ +xrf.getCollisionMeshes = () => { + let meshes = [] + xrf.scene.traverse( (n) => { + if( !n.userData.href && !n.userData.src && xrf.hasNoMaterial(n) ){ + meshes.push(n) + } + }) + return meshes +} diff --git a/src/3rd/js/three/xrf/dynamic/filter.js b/src/3rd/js/three/xrf/dynamic/filter.js index 4a976cc..510e9cf 100644 --- a/src/3rd/js/three/xrf/dynamic/filter.js +++ b/src/3rd/js/three/xrf/dynamic/filter.js @@ -42,13 +42,28 @@ xrf.filter.sort = function(frag){ } xrf.filter.process = function(frag,scene,opts){ + const cleanupKey = (k) => k.replace(/[-\*\/]/g,'') + let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false const hasName = (m,name,filter) => m.name == name const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) || String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) ) - const cleanupKey = (k) => k.replace(/[-\*\/]/g,'') - - let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false - let showers = frag.filters.filter( (v) => v.filter.get().show === true ) + // utility functions + const getOrCloneMaterial = (o) => { + if( o.material ){ + if( o.material.isXRF ) return o.material + o.material = o.material.clone() + o.material.isXRF = true + return o.material + } + return {} + } + const setVisible = (n,visible,filter,processed) => { + if( processed && processed[n.uuid] ) return + getOrCloneMaterial(n).visible = visible + console.log(n.name+" => "+(visible?"show":"hide")) + if( filter.deep ) n.traverse( (m) => getOrCloneMaterial(m).visible = visible ) + if( processed ) processed[n.uuid] == true + } // spec 2: https://xrfragment.org/doc/RFC_XR_Macros.html#embedding-xr-content-using-src // reparent scene based on objectname in case it matches a (non-negating) selector @@ -63,56 +78,35 @@ xrf.filter.process = function(frag,scene,opts){ } } - const setVisible = (n,visible,processed) => { - if( processed && processed[n.uuid] ) return - n.visible = visible - n.traverse( (n) => n.visible = visible ) - - // for hidden parents, clone material and set material to invisible - // otherwise n will not be rendered - if( visible ){ - n.traverseAncestors( (parent) => { - if( !parent.visible ){ - parent.visible = true - if( parent.material && !parent.material.isXRF ){ - parent.material = parent.material.clone() - parent.material.visible = false - } - } - }) - } - if( processed ) processed[n.uuid] == true - } - - const insideSRC = (m) => { - let src = false - m.traverseAncestors( (n) => n.isSRC ? src = true : false ) - return src - } - // then show/hide things based on secondary selectors + // we don't use the XRWG (everything) because we process only the given (sub)scene frag.filters.map( (v) => { const filter = v.filter.get() const name_or_tag = cleanupKey(v.fragment) let processed = {} + let extembeds = {} + // hide external objects temporarely scene.traverse( (m) => { - // filter on value(expression) #foo=>3 e.g. *TODO* do this in XRWG - if( filter.value && m.userData[filter.key] ){ - if( filter.root && insideSRC(m) ) return - const visible = v.filter.testProperty(filter.key, m.userData[filter.key], filter.show === false ) - setVisible(m,visible,processed) - return + if( m.isSRCExternal ){ + m.traverse( (n) => (extembeds[ n.uuid ] = m) && (n.visible = false) ) } }) - // include/exclude object(s) when id/tag matches (#foo or #-foo e.g.) - let matches = xrf.XRWG.match(name_or_tag) - matches.map( (match) => { - match.nodes.map( (node) => { - if( filter.root && insideSRC(node) ) return - setVisible(node,filter.show) - }) + + scene.traverseVisible( (m) => { + // filter on value(expression) #foo=>3 e.g. *TODO* do this in XRWG + if( filter.value && m.userData[filter.key] ){ + const visible = v.filter.testProperty(filter.key, m.userData[filter.key], filter.show === false ) + setVisible(m,visible,filter,processed) + return + } + if( hasNameOrTag(m,name_or_tag,filter ) ){ + setVisible(m,filter.show,filter) + } }) + + // show external objects again + for ( let i in extembeds ) extembeds[i].visible = true }) return xrf.filter diff --git a/src/3rd/js/three/xrf/pos.js b/src/3rd/js/three/xrf/pos.js index 4a00a78..0f0398e 100644 --- a/src/3rd/js/three/xrf/pos.js +++ b/src/3rd/js/three/xrf/pos.js @@ -1,6 +1,18 @@ xrf.frag.pos = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts - camera.position.x = v.x - camera.position.y = v.y - camera.position.z = v.z + + + // spec: indirect coordinate using objectname: https://xrfragment.org/#navigating%203D + if( v.x == undefined ){ + let obj = scene.getObjectByName(v.string) + if( !obj ) return + let pos = obj.position.clone() + obj.getWorldPosition(pos) + camera.position.copy(pos) + }else{ + // spec: direct coordinate: https://xrfragment.org/#navigating%203D + camera.position.x = v.x + camera.position.y = v.y + camera.position.z = v.z + } } diff --git a/src/3rd/js/three/xrf/src.js b/src/3rd/js/three/xrf/src.js index 641696b..a6ba327 100644 --- a/src/3rd/js/three/xrf/src.js +++ b/src/3rd/js/three/xrf/src.js @@ -18,7 +18,6 @@ xrf.frag.src.addModel = (model,url,frag,opts) => { let scene = model.scene xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene if( mesh.material ) mesh.material.visible = false // hide placeholder object - mesh.traverse( (n) => n.isSRC = n.isXRF = true ) // mark everything isSRC & isXRF //enableSourcePortation(scene) if( xrf.frag.src.renderAsPortal(mesh) ){ if( !opts.isLocal ) xrf.scene.add(scene) @@ -27,14 +26,15 @@ xrf.frag.src.addModel = (model,url,frag,opts) => { xrf.frag.src.scale( scene, opts, url ) // scale scene mesh.add(scene) } + // flag everything isSRC & isXRF + mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true }) xrf.emit('parseModel', {...opts, scene, model}) } xrf.frag.src.renderAsPortal = (mesh) => { - const hasTexture = mesh.material && mesh.material.map + // *TODO* should support better isFlat(mesh) check const isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4 - const hasMaterialName = mesh.material && mesh.material.name.length > 0 - return mesh.geometry && !hasMaterialName && !hasTexture && isPlane + return xrf.hasNoMaterial(mesh) && isPlane } xrf.frag.src.enableSourcePortation = (src) => { diff --git a/src/3rd/js/three/xrf/src/audio.js b/src/3rd/js/three/xrf/src/audio.js index 7ee11b4..1f137a2 100644 --- a/src/3rd/js/three/xrf/src/audio.js +++ b/src/3rd/js/three/xrf/src/audio.js @@ -11,6 +11,8 @@ let loadAudio = (mimetype) => function(url,opts){ let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) let frag = xrf.URI.parse( url ) + return + /* WebAudio: setup context via THREEjs */ if( !camera.listener ){ camera.listener = new THREE.AudioListener(); diff --git a/src/3rd/js/three/xrf/src/non-euclidian.js b/src/3rd/js/three/xrf/src/non-euclidian.js index 1138cd9..99789d8 100644 --- a/src/3rd/js/three/xrf/src/non-euclidian.js +++ b/src/3rd/js/three/xrf/src/non-euclidian.js @@ -85,8 +85,8 @@ xrf.portalNonEuclidian = function(opts){ let stencilObject = mesh.portal.stencilObject let newScale = mesh.scale let cameraDirection = mesh.portal.cameraDirection - let cameraPosition = mesh.portal.cameraPosition - let raycaster = mesh.portal.raycaster + let cameraPosition = mesh.portal.cameraPosition + let raycaster = mesh.portal.raycaster // init if( !opts.isLocal ) stencilObject.visible = true @@ -149,7 +149,7 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){ mesh.material.colorWrite = false; mesh.material.stencilWrite = true; mesh.material.stencilRef = xrf.portalNonEuclidian.stencilRef; - mesh.renderOrder = xrf.portalNonEuclidian.stencilRef; + mesh.renderOrder = 0;//xrf.portalNonEuclidian.stencilRef; mesh.material.stencilFunc = THREE.AlwaysStencilFunc; mesh.material.stencilZPass = THREE.ReplaceStencilOp; //mesh.material.stencilFail = THREE.ReplaceStencilOp; @@ -157,5 +157,10 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){ return mesh } +xrf.addEventListener('parseModel',(opts) => { + const scene = opts.model.scene + scene.traverse( (n) => n.renderOrder = 10 ) // rendering everything *after* the stencil buffers +}) + xrf.portalNonEuclidian.stencilRef = 1 diff --git a/src/Test.hx b/src/Test.hx index 7878d72..f77962f 100644 --- a/src/Test.hx +++ b/src/Test.hx @@ -16,6 +16,7 @@ class Test { static public function main():Void { test( "url.json", Spec.load("src/spec/url.json") ); + test( "pos.json", Spec.load("src/spec/pos.json") ); test( "t.json", Spec.load("src/spec/t.json") ); test( "filter.selectors.json", Spec.load("src/spec/filter.selectors.json") ); //test( Spec.load("src/spec/tmp.json") ); @@ -46,6 +47,7 @@ class Test { if( item.expect.fn == "equal.xy" ) valid = equalXY(res,item); if( item.expect.fn == "equal.xyz" ) valid = equalXYZ(res,item); if( item.expect.fn == "testFilterRoot" ) valid = res.exists(item.expect.input[0]) && res.get(item.expect.input[0]).filter.get().root == item.expect.out; + if( item.expect.fn == "testFilterDeep" ) valid = res.exists(item.expect.input[0]) && res.get(item.expect.input[0]).filter.get().deep == item.expect.out; var ok:String = valid ? "[ ✔ ] " : "[ ❌] "; trace( ok + item.fn + ": '" + item.data + "'" + (item.label ? " (" + (item.label?item.label:item.expect.fn) +")" : "")); if( !valid ) errors += 1; diff --git a/src/spec/filter.selectors.json b/src/spec/filter.selectors.json index 5da1d62..7d6a253 100644 --- a/src/spec/filter.selectors.json +++ b/src/spec/filter.selectors.json @@ -10,8 +10,6 @@ {"fn":"filter","data":"price=>2", "expect":{ "fn":"testProperty","input":["price","1"],"out":false}}, {"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","5"],"out":false}}, {"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","1"],"out":true}}, - {"fn":"url","data":"#/foo", "expect":{ "fn":"testFilterRoot","input":["foo"],"out":true},"label":"foo should be root-only"}, - {"fn":"url","data":"#/foo&foo","expect":{ "fn":"testFilterRoot","input":["foo"],"out":false},"label":"foo should recursively selected"}, - {"fn":"url","data":"#/foo&foo&/bar", "expect":{ "fn":"testFilterRoot","input":["foo"],"out":false},"label":"bar should be root-only"}, - {"fn":"url","data":"#-/foo", "expect":{ "fn":"testFilterRoot","input":["foo"],"out":true},"label":"foo should be root-only"} + {"fn":"url","data":"#foo*", "expect":{ "fn":"testFilterDeep","input":["foo"],"out":1},"label":"foo should be deep"}, + {"fn":"url","data":"#foo**", "expect":{ "fn":"testFilterDeep","input":["foo"],"out":2},"label":"foo should be deep incl. embeds"} ] diff --git a/src/spec/pos.json b/src/spec/pos.json new file mode 100644 index 0000000..bf533c6 --- /dev/null +++ b/src/spec/pos.json @@ -0,0 +1,6 @@ +[ + {"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2", "expect":{ "fn":"equal.string", "input":"pos","out":"1.2,2.2"},"label":"equal.string"}, + {"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2,3", "expect":{ "fn":"equal.xyz", "input":"pos","out":"1.2,2.2,3"},"label":"equal.xyz"}, + {"fn":"url","data":"http://foo.com?foo=1#pos=1,2,3", "expect":{ "fn":"equal.xyz", "input":"pos","out":"1,2,3"},"label":"pos equal.xyz"}, + {"fn":"url","data":"http://foo.com?foo=1#pos=world2", "expect":{ "fn":"equal.string", "input":"pos","out":"world2"},"label":"pos equal.xyz"} +] diff --git a/src/spec/url.json b/src/spec/url.json index 49957eb..95672b3 100644 --- a/src/spec/url.json +++ b/src/spec/url.json @@ -1,6 +1,4 @@ [ - {"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2", "expect":{ "fn":"equal.xyz", "input":"pos","out":false},"label":"equal.xyz: should trigger incompatible type)"}, - {"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2,3", "expect":{ "fn":"equal.xyz", "input":"pos","out":"1.2,2.2,3"},"label":"equal.xyz"}, {"fn":"url","data":"http://foo.com?foo=1#mypredefinedview", "expect":{ "fn":"testPredefinedView", "input":"mypredefinedview","out":true},"label":"test predefined view executed"}, {"fn":"url","data":"http://foo.com?foo=1#mypredefinedview&another", "expect":{ "fn":"testPredefinedView", "input":"another","out":true},"label":"test predefined view executed (multiple)"}, {"fn":"url","data":"http://foo.com?foo=1#mypredefinedview&another", "expect":{ "fn":"testPredefinedView", "input":"mypredefinedview","out":true},"label":"test predefined view executed (multiple)"}, diff --git a/src/xrfragment/Filter.hx b/src/xrfragment/Filter.hx index 3810ba4..467680f 100644 --- a/src/xrfragment/Filter.hx +++ b/src/xrfragment/Filter.hx @@ -2,6 +2,7 @@ // Copyright (c) 2023 Leon van Kammen/NLNET package xrfragment; +import xrfragment.XRF; //return untyped __js__("window.location.search"); #if js @@ -52,12 +53,6 @@ class Filter { private var str:String = ""; private var q:haxe.DynamicAccess = {}; // 1. create an associative array/object to store filter-arguments as objects - private var isProp:EReg = ~/^.*=[><=]?/; // 1. detect object id's & properties `foo=1` and `foo` (reference regex= `~/^.*=[><=]?/` ) - private var isExclude:EReg = ~/^-/; // 1. detect excluders like `-foo`,`-foo=1`,`-.foo`,`-/foo` (reference regex= `/^-/` ) - private var isRoot:EReg = ~/^[-]?\//; // 1. detect root selectors like `/foo` (reference regex= `/^[-]?\//` ) - private var isNumber:EReg = ~/^[0-9\.]+$/; // 1. detect number values like `foo=1` (reference regex= `/^[0-9\.]+$/` ) - private var operators:EReg = ~/(^-)?(\/)?/; // 1. detect operators so you can easily strip keys (reference regex= `/(^-|\*$)/` ) - private var isSelectorExclude:EReg = ~/^-/; // 1. detect exclude keys like `-foo` (reference regex= `/^-/` ) public function new(str:String){ if( str != null ) this.parse(str); @@ -84,24 +79,23 @@ class Filter { var filter:haxe.DynamicAccess = {}; if( q.get(prefix+k) ) filter = q.get(prefix+k); - if( isProp.match(str) ){ // 1. WHEN when a `=` key/value is detected: + if( XRF.isProp.match(str) ){ // 1. WHEN when a `=` key/value is detected: var oper:String = ""; if( str.indexOf(">") != -1 ) oper = ">"; // 1. then scan for `>` operator if( str.indexOf("<") != -1 ) oper = "<"; // 1. then scan for `<` operator - if( isExclude.match(k) ){ + if( XRF.isExclude.match(k) ){ k = k.substr(1); // 1. then strip operators from key: convert "-foo" into "foo" } v = v.substr(oper.length); // 1. then strip operators from value: change value ">=foo" into "foo" if( oper.length == 0 ) oper = "="; // 1. when no operators detected, assume operator '=' var rule:haxe.DynamicAccess = {}; - if( isNumber.match(v) ) rule[ oper ] = Std.parseFloat(v); + if( XRF.isNumber.match(v) ) rule[ oper ] = Std.parseFloat(v); else rule[oper] = v; q.set('expr',rule); - }else{ // 1. ELSE we are dealing with an object - q.set("root", isRoot.match(str) ? true : false ); // 1. and we set `root` to `true` or `false` (true=`/` root selector is present) } - q.set("show", isExclude.match(str) ? false : true ); // 1. therefore we we set `show` to `true` or `false` (false=excluder `-`) - q.set("key", operators.replace(k,'') ); + q.set("deep", XRF.isDeep.match(str) ? k.split("*").length-1 : 0 ); // 1. and we set `deep` to >0 or based on * occurences (true=`*` deep selector is present) + q.set("show", XRF.isExclude.match(str) ? false : true ); // 1. therefore we we set `show` to `true` or `false` (false=excluder `-`) + q.set("key", XRF.operators.replace(k,'') ); q.set("value",v); } for( i in 0...token.length ) process( token[i] ); @@ -153,8 +147,8 @@ class Filter { if( Reflect.field(f,'!=') != null && testprop( Std.string(value) == Std.string(Reflect.field(f,'!='))) && exclude ) qualify += 1; }else{ if( Reflect.field(f,'*') != null && testprop( Std.parseFloat(value) != null ) ) qualify += 1; - if( Reflect.field(f,'>') != null && testprop( Std.parseFloat(value) > Std.parseFloat(Reflect.field(f,'>' )) ) ) qualify += 1; - if( Reflect.field(f,'<') != null && testprop( Std.parseFloat(value) < Std.parseFloat(Reflect.field(f,'<' )) ) ) qualify += 1; + if( Reflect.field(f,'>') != null && testprop( Std.parseFloat(value) >= Std.parseFloat(Reflect.field(f,'>' )) ) ) qualify += 1; + if( Reflect.field(f,'<') != null && testprop( Std.parseFloat(value) <= Std.parseFloat(Reflect.field(f,'<' )) ) ) qualify += 1; if( Reflect.field(f,'=') != null && ( testprop( value == Reflect.field(f,'=')) || testprop( Std.parseFloat(value) == Std.parseFloat(Reflect.field(f,'='))) diff --git a/src/xrfragment/Parser.hx b/src/xrfragment/Parser.hx index c89e496..386bb67 100644 --- a/src/xrfragment/Parser.hx +++ b/src/xrfragment/Parser.hx @@ -9,7 +9,6 @@ import xrfragment.XRF; class Parser { public static var error:String = ""; public static var debug:Bool = false; - public static var keyClean:EReg = ~/(^-)?(\/)?/; // 1. detect - and / operators so you can easily strip keys (reference regex= ~/(^-)?(\/)?/; ) @:keep public static function parse(key:String,value:String,store:haxe.DynamicAccess,?index:Int):Bool { @@ -22,7 +21,7 @@ class Parser { Frag.set("tag", XRF.ASSET | XRF.T_STRING ); // spatial category: query selector / object manipulation - Frag.set("pos", XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.T_STRING_OBJ | XRF.METADATA | XRF.NAVIGATOR ); + Frag.set("pos", XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.T_STRING | XRF.T_STRING_OBJ | XRF.METADATA | XRF.NAVIGATOR ); Frag.set("rot", XRF.QUERY_OPERATOR | XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.METADATA | XRF.NAVIGATOR ); // category: animation @@ -48,13 +47,15 @@ class Parser { // 1. requirement: receive arguments: key (string), value (string), store (writable associative array/object) + var keyStripped:String = XRF.operators.replace( key, '' ); + // dynamic fragments cases: predefined views & assign/binds var isPVDynamic:Bool = key.length > 0 && !Frag.exists(key); var isPVDefault:Bool = value.length == 0 && key.length > 0 && key == "#"; if( isPVDynamic ){ //|| isPVDefault ){ // 1. add keys without values to store as [predefined view](predefined_view) var v:XRF = new XRF(key, XRF.PV_EXECUTE | XRF.NAVIGATOR, index ); v.validate(value); // ignore failures (empty values are allowed) - store.set( keyClean.replace(key,''), v ); + store.set( keyStripped, v ); return true; } @@ -65,12 +66,12 @@ class Parser { trace("⚠ fragment '"+key+"' has incompatible value ("+value+")");// 1. don't add to store if value-type is incorrect return false; } - store.set( keyClean.replace(key,''), v); // 1. if valid, add to store + store.set( keyStripped, v); // 1. if valid, add to store if( debug ) trace("✔ "+key+": "+v.string); }else{ // 1. expose (but mark) non-offical fragments too if( Std.isOfType(value, String) ) v.guessType(v,value); v.noXRF = true; - store.set( keyClean.replace(key,'') ,v); + store.set( keyStripped ,v); } return true; } diff --git a/src/xrfragment/XRF.hx b/src/xrfragment/XRF.hx index ab536b5..1c24914 100644 --- a/src/xrfragment/XRF.hx +++ b/src/xrfragment/XRF.hx @@ -36,13 +36,18 @@ class XRF { public static var T_STRING_OBJ_PROP:Int = 4194304; // regexes - public static var isColor:EReg = ~/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; // 1. hex colors are detected using regex `/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/` - public static var isInt:EReg = ~/^[-0-9]+$/; // 1. integers are detected using regex `/^[0-9]+$/` - public static var isFloat:EReg = ~/^[-0-9]+\.[0-9]+$/; // 1. floats are detected using regex `/^[0-9]+\.[0-9]+$/` - public static var isVector:EReg = ~/([,]+|\w)/; // 1. vectors are detected using regex `/[,]/` (but can also be an string referring to an entity-ID in the asset) - public static var isUrl:EReg = ~/(:\/\/)?\..*/; // 1. url/file */` + public static var isColor:EReg = ~/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; // 1. hex colors are detected using regex `/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/` + public static var isInt:EReg = ~/^[-0-9]+$/; // 1. integers are detected using regex `/^[0-9]+$/` + public static var isFloat:EReg = ~/^[-0-9]+\.[0-9]+$/; // 1. floats are detected using regex `/^[0-9]+\.[0-9]+$/` + public static var isVector:EReg = ~/([,]+|\w)/; // 1. vectors are detected using regex `/[,]/` (but can also be an string referring to an entity-ID in the asset) + public static var isUrl:EReg = ~/(:\/\/)?\..*/; // 1. url/file */` public static var isUrlOrPretypedView:EReg = ~/(^#|:\/\/)?\..*/; // 1. url/file */` - public static var isString:EReg = ~/.*/; // 1. anything else is string `/.*/` + public static var isString:EReg = ~/.*/; // 1. anything else is string `/.*/` + public static var operators:EReg = ~/(^-|[\*]+)/; // 1. detect operators so you can easily strip keys (reference regex= `~/(^-)?(\/)?(\*)?/` ) + public static var isProp:EReg = ~/^.*=[><=]?/; // 1. detect object id's & properties `foo=1` and `foo` (reference regex= `~/^.*=[><=]?/` ) + public static var isExclude:EReg = ~/^-/; // 1. detect excluders like `-foo`,`-foo=1`,`-.foo`,`-/foo` (reference regex= `/^-/` ) + public static var isDeep:EReg = ~/\*/; // 1. detect deep selectors like `foo*` (reference regex= `/\*$/` ) + public static var isNumber:EReg = ~/^[0-9\.]+$/; // 1. detect number values like `foo=1` (reference regex= `/^[0-9\.]+$/` ) // value holder(s) // |------|------|--------|----------------------------------| public var fragment:String; @@ -83,7 +88,7 @@ class XRF { // validate var ok:Bool = true; if( !is(T_FLOAT) && is(T_VECTOR2) && !(Std.isOfType(x,Float) && Std.isOfType(y,Float)) ) ok = false; - if( !is(T_VECTOR2) && is(T_VECTOR3) && !(Std.isOfType(x,Float) && Std.isOfType(y,Float) && Std.isOfType(z,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; } diff --git a/test/aframe/filter.js b/test/aframe/filter.js index d951857..a1f515a 100644 --- a/test/aframe/filter.js +++ b/test/aframe/filter.js @@ -2,33 +2,40 @@ THREE = AFRAME.THREE createScene = (noadd) => { - let obj = {a:{},b:{},c:{}} + let obj = {a:{},b:{},c:{},d:{},extembed:{}} for ( let i in obj ){ obj[i] = new THREE.Object3D() obj[i].name = i obj[i].material = {visible:true, clone: () => ({visible:true}) } } - let {a,b,c} = obj - let scene = new THREE.Scene() + let {a,b,c,d,extembed} = obj + let scene = xrf.scene = new THREE.Scene() if( !noadd ){ a.add(b) b.add(c) scene.add(a) + extembed.add(d) + scene.add(extembed) } b.userData.score = 2 - b.userData.tag = "foo bar" - c.userData.tag = "flop flap" a.userData.tag = "VR" + b.userData.tag = "foo hide" + c.userData.tag = "flop flap VR" a.userData.price = 1 b.userData.price = 5 c.userData.price = 10 - return {a,b,c,scene} + b.isSRC = "local" + d.userData.tag = "VR" + extembed.isSRC = true + extembed.isSRCExternal = true + return {a,b,c,d,extembed,scene} } -filterScene = (URI) => { +filterScene = (URI,opts) => { + opts = opts || {} frag = xrf.URI.parse(URI) - var {a,b,c,scene} = createScene() - xrf.filter.scene({scene,frag}) + var {a,b,c,d,extembed,scene} = createScene() + xrf.filter.scene({...opts,scene,frag}) scene.visible = (objname, expected, checkMaterial) => { let o = scene.getObjectByName(objname) @@ -42,69 +49,46 @@ filterScene = (URI) => { } scn = filterScene("#b") -test = () => !scn.visible("a") && scn.visible("b",true) && scn.visible("c",true) +test = () => scn.visible("a",true,true) && scn.visible("b",true) && scn.visible("c",true) console.assert( test(), {scn,reason:`objectname: #b `}) -scn = filterScene("#-b") -test = () => scn.visible("a",true) && scn.visible("b",false) && scn.visible("c",false) -console.assert( test(), {scn,reason:`objectname: #-b `}) +scn = filterScene("#-b") +test = () => scn.visible("a",true,true) && scn.visible("b",false,true) && scn.visible("c",true) && scn.visible("c",true,true) +console.assert( test(), {scn,reason:`objectname: #-b`}) -scn = filterScene("#a&-b") -test = () => scn.visible("a",true) && scn.visible("b",false) && scn.visible("c",false) -console.assert( test(), {scn,reason:`objectname: #a&-b `}) +scn = filterScene("#-b*") +test = () => scn.visible("a",true,true) && scn.visible("b",false,true) && scn.visible("c",false,true) +console.assert( test(), {scn,reason:`objectname: #b*`}) -scn = filterScene("#-b&b") +scn = filterScene("#b",{reparent:true}) +test = () => scn.visible("a",false) && scn.visible("b",true) && scn.visible("c",true) +console.assert( test(), {scn,reason:`objectname: #b (reparent scene)`}) + +scn = filterScene("#-b&b*") test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) console.assert( test(), {scn,reason:`objectname: #-b&b `}) -scn = filterScene("#-c") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",false) -console.assert( test(), {scn,reason:`objectname: #-c `}) - -scn = filterScene("#score") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) +scn = filterScene("#-a&score*") +test = () => scn.visible("a",false,true) && scn.visible("b",true,true) && scn.visible("c",true,true) console.assert( test(), {scn,reason:`propertyfilter: #score `}) -scn = filterScene("#score=>1") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`propertyfilter: #score>=1`}) - -scn = filterScene("#score=2") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) +scn = filterScene("#-a&score*=2") +test = () => scn.visible("a",false,true) && scn.visible("b",true) && scn.visible("c",true) console.assert( test(), {scn,reason:`propertyfilter: #score=2`}) -scn = filterScene("#score=>3") -test = () => scn.visible("a",true) && scn.visible("b",false) && scn.visible("c",false) -console.assert( test(), {scn,reason:`propertyfilter: #score=>3`}) - -scn = filterScene("#-score=>1") -test = () => scn.visible("a",true) && scn.visible("b",false) && scn.visible("c",false) -console.assert( test(), {scn,reason:`propertyfilter: #-score=>1`}) - -scn = filterScene("#-score=>1&c") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("b",false,true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`propertyfilter: #-score=>1&c`}) - -scn = filterScene("#-foo") -test = () => scn.visible("a",true) && scn.visible("b",false) && scn.visible("b",false) -console.assert( test(), {scn,reason:`tagfilter: #-foo `}) - -scn = filterScene("#-c&flop") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`tagfilter: #-c&flop`}) - -scn = filterScene("#-b&-foo&bar&flop") -test = () => scn.visible("a",true) && scn.visible("b",true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`tagfilter: #-b&-foo&bar&flop`}) - -scn = filterScene("#-b&-foo&bar&flop&-bar&flop") -test = () => scn.visible("a",true) && scn.visible("b",false,true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`tagfilter: #-b&-foo&bar&flop&-bar&flop"`}) - -scn = filterScene("#-price&price=>5") -test = () => scn.visible("a",false,true) && scn.visible("b",true) && scn.visible("c",true) +scn = filterScene("#-price*&price=>5") +test = () => scn.visible("a",false,true) && scn.visible("b",true,true) && scn.visible("c",true,true) console.assert( test(), {scn,reason:`tagfilter: #-price&price=>5"`}) -scn = filterScene("#-/VR&b") -test = () => scn.visible("a",false,true) && scn.visible("b",true) && scn.visible("c",true) -console.assert( test(), {scn,reason:`tagfilter: #-/VR&b"`}) +scn = filterScene("#-hide*") +test = () => scn.visible("a",true,true) && scn.visible("b",false,true) && scn.visible("c",false,true) +console.assert( test(), {scn,reason:`tagfilter: #-hide*"`}) + +scn = filterScene("#-VR") +test = () => scn.visible("a",false,true) && scn.visible("b",true,true) && scn.visible("c",false,true) && scn.visible("extembed",true,true) && scn.visible("d",true,true) +console.assert( test(), {scn,reason:`tagfilter: #-VR"`}) + +scn = filterScene("#-VR*") +test = () => scn.visible("a",false,true) && scn.visible("b",false,true) && scn.visible("c",false,true) && scn.visible("extembed",true,true) && scn.visible("d",true,true) +console.assert( test(), {scn,reason:`tagfilter: #-VR*"`}) +