work in progress [might break]

This commit is contained in:
Leon van Kammen 2023-11-23 12:30:18 +01:00
parent f11a647bb7
commit cc3f58f493
10 changed files with 39 additions and 23 deletions

View File

@ -512,6 +512,8 @@ It's simple but powerful syntax which allows filtering the scene using searcheng
> \* = `#-/cube` hides object `cube` only in the root-scene (not nested `cube` objects)<br> `#-cube` hides both object `cube` in the root-scene <b>AND</b> nested `skybox` objects |
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.).
[» 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)
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/3)

Binary file not shown.

View File

@ -35,6 +35,8 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
pub.fragment = (k, opts ) => { // evaluate one fragment
let frag = opts.frag[k];
if( frag.is( xrf.XRF.PV_EXECUTE ) ) pub.XRWG({...opts,frag})
// call native function (xrf/env.js e.g.), or pass it to user decorator
xrf.emit(k,opts)
.then( () => {
@ -46,6 +48,7 @@ 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'
@ -62,15 +65,12 @@ pub.XRWG = (opts) => {
match.map( (w) => {
if( w.key == `#${id}` ){
if( w.value && w.value[0] == '#' ){
frag = xrf.URI.parse( w.value )
v = Object.values(frag)[0]
// if value is alias, execute fragment value
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
}
}
})
if( !match.length ) xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
}else{
xrf.emit('dynamicKeyValue',{ ...opts,v,frag,id,match,scene })
}

View File

@ -23,7 +23,7 @@ xrf.filter = function(query, cb){
xrf.filter.scene = function(opts){
let {scene,frag} = opts
console.dir(opts)
xrf.filter
.sort(frag) // get (sorted) filters from XR Fragments
.process(frag,scene,opts) // show/hide things
@ -45,7 +45,7 @@ xrf.filter.process = function(frag,scene,opts){
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,'')
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 )
@ -84,6 +84,12 @@ xrf.filter.process = function(frag,scene,opts){
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
frag.filters.map( (v) => {
const filter = v.filter.get()
@ -91,19 +97,21 @@ xrf.filter.process = function(frag,scene,opts){
let processed = {}
scene.traverse( (m) => {
if( filter.root && m.isSRC ) return // ignore src nodes when root is specific (#/VR #/AR e.g.)
// filter on value(expression) #foo=>3 e.g.
// 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
}
// include/exclude object(s) when id/tag matches (#foo or #-foo e.g.)
if( hasNameOrTag(m,name_or_tag,filter) ){
setVisible(m,filter.show)
}
})
// 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)
})
})
})

View File

@ -17,8 +17,8 @@ xrf.frag.src.addModel = (model,url,frag,opts) => {
let {mesh} = opts
let scene = model.scene
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
mesh.traverse( (n) => n.isSRC = n.isXRF = true ) // mark everything isSRC & isXRF
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)

View File

@ -15,11 +15,11 @@ let loadVideo = (mimetype) => function(url,opts){
mat.map = texture
mesh.material = mat
// set range
video.addEventListener('timeupdate', function timeupdate() {
if (video.t && video.currentTime < video.t.y || video.currentTime >= video.t.z ) {
vid.currentTime = video.t.y
}
},false)
//video.addEventListener('timeupdate', function timeupdate() {
// if (frag.t && video.currentTime < frag.t.y || video.currentTime >= frag.t.z ) {
// video.currentTime = frag.t.y
// }
//},false)
})
video.src = url

View File

@ -34,6 +34,7 @@ xrf.addEventListener('parseModel', (opts) => {
model.animations.map( (anim) => {
anim.optimize()
console.log("action: "+anim.name)
mixer.actions.push( mixer.clipAction( anim, model.scene ) )
})

View File

@ -56,7 +56,7 @@ class Filter {
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 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){

View File

@ -9,7 +9,7 @@ import xrfragment.XRF;
class Parser {
public static var error:String = "";
public static var debug:Bool = false;
public static var keyClean:EReg = ~/(\*$|^-|\/)/g;
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<Dynamic>,?index:Int):Bool {
@ -53,7 +53,7 @@ class Parser {
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); // will fail but will parse multiple args for us (separated by |)
v.validate(value); // ignore failures (empty values are allowed)
store.set( keyClean.replace(key,''), v );
return true;
}

View File

@ -18,6 +18,7 @@ createScene = (noadd) => {
b.userData.score = 2
b.userData.tag = "foo bar"
c.userData.tag = "flop flap"
a.userData.tag = "VR"
a.userData.price = 1
b.userData.price = 5
c.userData.price = 10
@ -103,3 +104,7 @@ 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)
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"`})