work in progress [might break]
This commit is contained in:
parent
f11a647bb7
commit
cc3f58f493
|
@ -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.
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) )
|
||||
})
|
||||
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"`})
|
||||
|
|
Loading…
Reference in New Issue