refactor media fragments
This commit is contained in:
parent
1851ee1d4f
commit
e8308d738b
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 MiB |
|
@ -6,4 +6,5 @@ for topic in Fragments Macros; do
|
||||||
mmark --html RFC_XR_$topic.md | grep -vE '(<!--{|}-->)' > RFC_XR_$topic.html
|
mmark --html RFC_XR_$topic.md | grep -vE '(<!--{|}-->)' > RFC_XR_$topic.html
|
||||||
xml2rfc --v3 RFC_XR_$topic.xml # RFC_XR_$topic.txt
|
xml2rfc --v3 RFC_XR_$topic.xml # RFC_XR_$topic.txt
|
||||||
sed -i 's/Expires: .*//g' RFC_XR_$topic.txt
|
sed -i 's/Expires: .*//g' RFC_XR_$topic.txt
|
||||||
|
convert -size 700x2400 xc:white -font "FreeMono" +antialias -pointsize 12 -fill black -annotate +15+15 "@RFC_XR_Fragments.txt" -colorspace gray +dither -posterize 6 RF6_XR_Fragments.png
|
||||||
done
|
done
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
mmark
|
mmark
|
||||||
xml2rfc
|
xml2rfc
|
||||||
wkhtmltopdf-bin
|
wkhtmltopdf-bin
|
||||||
|
imagemagick
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ XRWG.match = (str,types,level) => {
|
||||||
return n
|
return n
|
||||||
})
|
})
|
||||||
str = str.toLowerCase()
|
str = str.toLowerCase()
|
||||||
|
.replace(/[-\*]/,'') // remove excludes and wildcards
|
||||||
if( level <10 ) res = res.filter( (n) => n.key == str )
|
if( level <10 ) res = res.filter( (n) => n.key == str )
|
||||||
if( level >=10 ) res = res.filter( (n) => n.word == str || n.key == str )
|
if( level >=10 ) res = res.filter( (n) => n.word == str || n.key == str )
|
||||||
if( level >30 ) res = res.filter( (n) => n.word.match(str) || n.key == str )
|
if( level >30 ) res = res.filter( (n) => n.word.match(str) || n.key == str )
|
||||||
|
|
|
@ -4,6 +4,13 @@ AFRAME.registerComponent('xrf-gaze',{
|
||||||
schema:{
|
schema:{
|
||||||
spawn:{type:'boolean',default:false},
|
spawn:{type:'boolean',default:false},
|
||||||
},
|
},
|
||||||
|
events:{
|
||||||
|
"fusing": function(e){
|
||||||
|
if( e.detail.mouseEvent ) return // ignore click event
|
||||||
|
console.dir(e)
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
setGazer: function(state){
|
setGazer: function(state){
|
||||||
let cam = document.querySelector("[camera]")
|
let cam = document.querySelector("[camera]")
|
||||||
if( state ){
|
if( state ){
|
||||||
|
@ -15,7 +22,6 @@ AFRAME.registerComponent('xrf-gaze',{
|
||||||
raycaster="objects: .ray"
|
raycaster="objects: .ray"
|
||||||
visible="true"
|
visible="true"
|
||||||
position="0 0 -1"
|
position="0 0 -1"
|
||||||
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
|
|
||||||
material="color: #BBBBBB; shader: flat">
|
material="color: #BBBBBB; shader: flat">
|
||||||
</a-entity>`
|
</a-entity>`
|
||||||
}else{
|
}else{
|
||||||
|
@ -25,9 +31,12 @@ AFRAME.registerComponent('xrf-gaze',{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init:function(data){
|
init:function(data){
|
||||||
let enabled = () => AFRAME.utils.device.isMobile()
|
|
||||||
let setVisible = (state) => {
|
let setVisible = (state) => {
|
||||||
if( enabled() ) this.setGazer(state)
|
if( AFRAME.utils.device.isMobile() ){
|
||||||
|
this.setGazer(state)
|
||||||
|
if( state || xrf.debug ) this.el.setAttribute("geometry","primitive: ring; radiusInner: 0.02; radiusOuter: 0.03")
|
||||||
|
else this.el.removeAttribute("geometry")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|
|
@ -3,17 +3,29 @@
|
||||||
// it allows metadata-keys ('foo' e.g.) of 3D scene-nodes (.userData.foo e.g.) to
|
// it allows metadata-keys ('foo' e.g.) of 3D scene-nodes (.userData.foo e.g.) to
|
||||||
// react by executing code
|
// react by executing code
|
||||||
|
|
||||||
let pub = function( url, model, flags ){ // evaluate fragments in url
|
let pub = function( url, node_or_model, flags ){ // evaluate fragments in url
|
||||||
if( !url ) return
|
if( !url ) return
|
||||||
if( !url.match(/#/) ) url = `#${url}`
|
if( !url.match(/#/) ) url = `#${url}`
|
||||||
model = model || xrf.model
|
|
||||||
let { THREE, camera } = xrf
|
let { THREE, camera } = xrf
|
||||||
let frag = xrf.URI.parse( url, flags )
|
let frag = xrf.URI.parse( url, flags )
|
||||||
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE, hashbus: xrf.hashbus }
|
let fromNode = node_or_model != xrf.model
|
||||||
|
|
||||||
|
let opts = {
|
||||||
|
frag,
|
||||||
|
mesh: fromNode ? node_or_model : xrf.camera,
|
||||||
|
model: xrf.model,
|
||||||
|
camera: xrf.camera,
|
||||||
|
scene: xrf.scene,
|
||||||
|
renderer: xrf.renderer,
|
||||||
|
THREE: xrf.THREE,
|
||||||
|
hashbus: xrf.hashbus
|
||||||
|
}
|
||||||
xrf.emit('hashbus',opts)
|
xrf.emit('hashbus',opts)
|
||||||
.then( () => {
|
.then( () => {
|
||||||
for ( let k in frag ){
|
for ( let k in frag ){
|
||||||
pub.fragment(k,opts)
|
let nodeAlias = fromNode && opts.mesh && opts.mesh.userData && opts.mesh.userData[k] && opts.mesh.userData[k][0] == '#'
|
||||||
|
if( nodeAlias ) pub(opts.mesh.userData[k], opts.mesh) // evaluate node alias
|
||||||
|
else pub.fragment(k,opts)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return frag
|
return frag
|
||||||
|
@ -37,7 +49,7 @@ pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
let frag = opts.frag[k];
|
let frag = opts.frag[k];
|
||||||
|
|
||||||
let isPVorMediaFrag = frag.is( xrf.XRF.PV_EXECUTE ) || frag.is( xrf.XRF.T_MEDIAFRAG)
|
let isPVorMediaFrag = frag.is( xrf.XRF.PV_EXECUTE ) || frag.is( xrf.XRF.T_MEDIAFRAG)
|
||||||
if( !opts.skipXRWG && isPVorMediaFrag ) pub.XRWG(opts)
|
if( !opts.skipXRWG && isPVorMediaFrag ) pub.XRWG(k,opts)
|
||||||
|
|
||||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||||
xrf.emit(k,opts)
|
xrf.emit(k,opts)
|
||||||
|
@ -48,32 +60,37 @@ pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub.XRWG = (opts) => {
|
pub.XRWG = (word,opts) => {
|
||||||
let {frag,scene,model,renderer} = opts
|
let {frag,scene,model,renderer} = opts
|
||||||
|
|
||||||
// if this query was triggered by an src-value, lets filter it
|
// if this query was triggered by an src-value, lets filter it
|
||||||
const isSRC = opts.embedded && opts.embedded.fragment == 'src'
|
const isSRC = opts.embedded && opts.embedded.fragment == 'src'
|
||||||
if( !isSRC ){ // spec : https://xrfragment.org/#src
|
if( !isSRC ){ // spec : https://xrfragment.org/#src
|
||||||
for ( let i in frag ) {
|
|
||||||
let v = frag[i]
|
|
||||||
let id = v.is( xrf.XRF.T_DYNAMIC ) ? v.fragment : v.string || v.fragment
|
|
||||||
if( id == '#' || !id ) return
|
|
||||||
let match = xrf.XRWG.match(id)
|
|
||||||
|
|
||||||
if( v.is( xrf.XRF.PV_EXECUTE ) && !v.is( xrf.XRF.T_DYNAMIC ) ){
|
let triggeredByMesh = opts.model != opts.mesh
|
||||||
// evaluate aliases
|
|
||||||
match.map( (w) => {
|
let v = frag[word]
|
||||||
if( w.key == `#${id}` ){
|
let id = v.is( xrf.XRF.T_DYNAMICKEY ) ? word : v.string || word
|
||||||
if( w.value && w.value[0] == '#' ){
|
|
||||||
// if value is alias, execute fragment value
|
if( id == '#' || !id ) return
|
||||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
let match = xrf.XRWG.match(id)
|
||||||
}
|
|
||||||
|
if( !triggeredByMesh && (v.is( xrf.XRF.PV_EXECUTE ) || v.is( xrf.XRF.T_DYNAMIC)) && !v.is( xrf.XRF.T_DYNAMICKEYVALUE ) ){
|
||||||
|
// evaluate global aliases or tag/objectnames
|
||||||
|
match.map( (w) => {
|
||||||
|
if( w.key == `#${id}` ){
|
||||||
|
if( w.value && w.value[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 })
|
})
|
||||||
}else{
|
xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
|
||||||
xrf.emit('dynamicKeyValue',{ ...opts,v,frag,id,match,scene })
|
}else if( v.string ){
|
||||||
}
|
// evaluate global aliases
|
||||||
|
xrf.emit('dynamicKeyValue',{ ...opts,v,frag,id,match,scene })
|
||||||
|
}else{
|
||||||
|
xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
xrf.frag = {}
|
xrf.frag = {dynamic:{}}
|
||||||
xrf.model = {}
|
xrf.model = {}
|
||||||
xrf.mixers = []
|
xrf.mixers = []
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ xrf.patchRenderer = function(opts){
|
||||||
xrf.clock = new xrf.THREE.Clock()
|
xrf.clock = new xrf.THREE.Clock()
|
||||||
renderer.render = ((render) => function(scene,camera){
|
renderer.render = ((render) => function(scene,camera){
|
||||||
// update clock
|
// update clock
|
||||||
let time = xrf.clock.getDelta()
|
let time = xrf.clock.delta = xrf.clock.getDelta()
|
||||||
xrf.emit('render',{scene,camera,time,render}) // allow fragments to do something at renderframe
|
xrf.emit('render',{scene,camera,time,render}) // allow fragments to do something at renderframe
|
||||||
render(scene,camera)
|
render(scene,camera)
|
||||||
xrf.emit('renderPost',{scene,camera,time,render,renderer}) // allow fragments to do something after renderframe
|
xrf.emit('renderPost',{scene,camera,time,render,renderer}) // allow fragments to do something after renderframe
|
||||||
|
|
|
@ -30,6 +30,12 @@ xrf.interactiveGroup = function(THREE,renderer,camera){
|
||||||
const raycaster = new Raycaster();
|
const raycaster = new Raycaster();
|
||||||
const tempMatrix = new Matrix4();
|
const tempMatrix = new Matrix4();
|
||||||
|
|
||||||
|
let dispatchEvent = (object,_event) => {
|
||||||
|
object.dispatchEvent(_event)
|
||||||
|
// bubble up
|
||||||
|
object.traverseAncestors( (n) => n.userData && n.userData.href && n.dispatchEvent(_event) )
|
||||||
|
}
|
||||||
|
|
||||||
// Pointer Events
|
// Pointer Events
|
||||||
|
|
||||||
const element = renderer.domElement;
|
const element = renderer.domElement;
|
||||||
|
@ -56,12 +62,12 @@ xrf.interactiveGroup = function(THREE,renderer,camera){
|
||||||
|
|
||||||
_event.type = event.type;
|
_event.type = event.type;
|
||||||
_event.data.set( uv.x, 1 - uv.y );
|
_event.data.set( uv.x, 1 - uv.y );
|
||||||
object.dispatchEvent( _event );
|
dispatchEvent( object, _event );
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
if( object.selected ) {
|
if( object.selected ) {
|
||||||
_event.type = 'mouseleave'
|
_event.type = 'mouseleave'
|
||||||
object.dispatchEvent(_event)
|
dispatchEvent( object, _event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,12 +112,12 @@ xrf.interactiveGroup = function(THREE,renderer,camera){
|
||||||
_event.type = events[ event.type ];
|
_event.type = events[ event.type ];
|
||||||
_event.data.set( uv.x, 1 - uv.y );
|
_event.data.set( uv.x, 1 - uv.y );
|
||||||
|
|
||||||
object.dispatchEvent( _event );
|
dispatchEvent( object, _event );
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
if( object.selected ) {
|
if( object.selected ) {
|
||||||
_event.type = 'mouseleave'
|
_event.type = 'mouseleave'
|
||||||
object.dispatchEvent(_event)
|
dispatchEvent( object, _event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
// this is called by navigator.js rather than by a URL e.g.
|
||||||
|
|
||||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||||
let {scene,model} = opts;
|
let {scene,model} = opts;
|
||||||
scene.traverse( (n) => {
|
scene.traverse( (n) => {
|
||||||
if( n.userData && n.userData['#'] ){
|
if( n.userData && n.userData['#'] ){
|
||||||
let frag = xrf.URI.parse( n.userData['#'] )
|
let frag = xrf.URI.parse( n.userData['#'] )
|
||||||
if( !n.parent && document.location.hash.length < 2){
|
if( !n.parent && document.location.hash.length < 2){
|
||||||
xrf.navigator.to( n.userData['#'] ) // evaluate static XR fragments
|
xrf.navigator.to( n.userData['#'] ) // evaluate default XR fragments (global-level)
|
||||||
}else{
|
}else{
|
||||||
xrf.hashbus.pub( n.userData['#'] ) // evaluate static XR fragments
|
xrf.hashbus.pub( n.userData['#'], n ) // evaluate default XR fragments (node-level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
// this holds all the URI Template variables (https://www.rfc-editor.org/rfc/rfc6570)
|
||||||
|
|
||||||
|
xrf.addEventListener('parseModel', (opts) => {
|
||||||
|
let {model,url,file} = opts
|
||||||
|
if( model.isSRC || opts.isSRC ) return // ignore SRC models
|
||||||
|
xrf.URI.vars = new Proxy({},{
|
||||||
|
set(me,k,v){ me[k] = v },
|
||||||
|
get(me,k ){
|
||||||
|
if( k == '__object' ){
|
||||||
|
let obj = {}
|
||||||
|
for( let i in xrf.URI.vars ) obj[i] = xrf.URI.vars[i]()
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
return me[k]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
model.scene.traverse( (n) => {
|
||||||
|
if( n.userData ){
|
||||||
|
for( let i in n.userData ){
|
||||||
|
if( i[0] == '#' || i.match(/^(href|src|tag)$/) ) continue // ignore XR Fragment aliases
|
||||||
|
xrf.URI.vars[i] = () => n.userData[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
xrf.addEventListener('dynamicKeyValue', (opts) => {
|
||||||
|
// select active camera if any
|
||||||
|
let {id,match,v} = opts
|
||||||
|
|
||||||
|
if( !v.is( xrf.XRF.CUSTOMFRAG) ) return // only process custom frags from here
|
||||||
|
|
||||||
|
// check if fragment is an objectname
|
||||||
|
if( match.length > 0 ){
|
||||||
|
xrf.frag.dynamic.material(v,opts)
|
||||||
|
}else{
|
||||||
|
if( !xrf.URI.vars[ v.string ] ) return // only assign to known values
|
||||||
|
xrf.URI.vars[ id ] = xrf.URI.vars[ v.string ] // update var
|
||||||
|
if( xrf.debug ) console.log(`URI.vars[${id}]='${v.string}'`)
|
||||||
|
|
||||||
|
xrf.scene.traverse( (n) => { // reflect new changes
|
||||||
|
if( n.userData && n.userData.src && n.userData.srcTemplate ){
|
||||||
|
let srcOldFragments = n.userData.src.replace(/.*#/,'')
|
||||||
|
let srcNewFragments = xrf.frag.src.expandURI( n ).replace(/.*#/,'')
|
||||||
|
if( srcOldFragments != srcNewFragments ){
|
||||||
|
console.log(`URI.vars[${id}] => updating ${n.name}`)
|
||||||
|
let frag = xrf.hashbus.pub( srcNewFragments, n )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,14 @@
|
||||||
|
// switch camera when multiple cameras for url #mycameraname
|
||||||
|
|
||||||
|
xrf.addEventListener('dynamicKey', (opts) => {
|
||||||
|
// select active camera if any
|
||||||
|
let {id,match,v} = opts
|
||||||
|
match.map( (w) => {
|
||||||
|
w.nodes.map( (node) => {
|
||||||
|
if( node.isCamera ){
|
||||||
|
console.log("switching camera to cam: "+node.name)
|
||||||
|
xrf.model.camera = node
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,7 +1,3 @@
|
||||||
/*
|
|
||||||
* TODO: refactor/fix this (queries are being refactored to filters)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
xrf.addEventListener('dynamicKey', (opts) => {
|
xrf.addEventListener('dynamicKey', (opts) => {
|
||||||
let {scene,id,match,v} = opts
|
let {scene,id,match,v} = opts
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
xrf.frag.dynamic.material = function(v,opts){
|
||||||
|
let {match} = opts
|
||||||
|
|
||||||
|
setMaterial = (mesh,material,reset) => {
|
||||||
|
if( !mesh.materialOriginal ) mesh.materialOriginal = mesh.material
|
||||||
|
if( reset ) mesh.material = mesh.materialOriginal
|
||||||
|
else mesh.material = material
|
||||||
|
}
|
||||||
|
|
||||||
|
// update material in case of <tag_or_object>[*]=<materialname>
|
||||||
|
let material
|
||||||
|
xrf.scene.traverse( (n) => n.material && (n.material.name == v.string) && (material = n.material) )
|
||||||
|
if( !material && !v.reset ) return // nothing to do
|
||||||
|
|
||||||
|
if( material ) xrf.frag.dynamic.material.setMatch(match,material,v)
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.frag.dynamic.material.setMatch = function(match,material,v){
|
||||||
|
match.map( (m) => {
|
||||||
|
m.nodes.map( (n) => {
|
||||||
|
n.material = setMaterial( n, material, v.reset )
|
||||||
|
if( v.filter.q.deep ) n.traverse( (c) => c.material && setMaterial( c, material, v.reset ) )
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('dynamicKey', (opts) => {
|
||||||
|
|
||||||
|
let {v,match} = opts
|
||||||
|
|
||||||
|
if( v.reset ){
|
||||||
|
xrf.frag.dynamic.material.setMatch(match,null,v)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
|
@ -62,7 +62,7 @@ xrf.frag.href = function(v, opts){
|
||||||
xrf.interactive.objects.map( (o) => {
|
xrf.interactive.objects.map( (o) => {
|
||||||
let newState = o.name == mesh.name ? state : false
|
let newState = o.name == mesh.name ? state : false
|
||||||
if( o.material ){
|
if( o.material ){
|
||||||
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
|
if( o.material.uniforms && o.material.uniforms.selected ) o.material.uniforms.selected.value = newState
|
||||||
//if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
//if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
||||||
if( o.material.emissive ){
|
if( o.material.emissive ){
|
||||||
if( !o.material.emissive.original ) o.material.emissive.original = o.material.emissive.clone()
|
if( !o.material.emissive.original ) o.material.emissive.original = o.material.emissive.clone()
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
xrf.frag.suv = function(v, opts){
|
||||||
|
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
||||||
|
|
||||||
|
if( !mesh.geometry ) return // nothing to do here
|
||||||
|
|
||||||
|
xrf.frag.uv.init(mesh)
|
||||||
|
mesh.suv.x = v.x
|
||||||
|
mesh.suv.y = v.y !== undefined ? v.y : v.x
|
||||||
|
mesh.suv.loop = v.loop === true ? true : false
|
||||||
|
xrf.frag.uv.scroll(mesh)
|
||||||
|
}
|
|
@ -4,17 +4,25 @@ xrf.frag.src = function(v, opts){
|
||||||
opts.embedded = v // indicate embedded XR fragment
|
opts.embedded = v // indicate embedded XR fragment
|
||||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||||
|
|
||||||
let url = v.string
|
let url = xrf.frag.src.expandURI( mesh, v.string )
|
||||||
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
||||||
opts.isLocal = v.string[0] == '#'
|
opts.isLocal = v.string[0] == '#'
|
||||||
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
||||||
opts.isSRC = true
|
opts.isSRC = true
|
||||||
|
|
||||||
if(xrf.debug) console.log(`src.js: instancing ${opts.isLocal?'local':'remote'} object ${url}`)
|
if(xrf.debug) console.log(`src.js: instancing ${opts.isLocal?'local':'remote'} object ${url}`)
|
||||||
|
|
||||||
if( opts.isLocal ){
|
if( opts.isLocal ){
|
||||||
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
||||||
}else xrf.frag.src.externalSRC(url,srcFrag,opts) // external file
|
}else xrf.frag.src.externalSRC(url,srcFrag,opts) // external file
|
||||||
|
|
||||||
|
xrf.hashbus.pub( url.replace(/.*#/,''), mesh) // eval src-url fragments
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.frag.src.expandURI = function(mesh,uri){
|
||||||
|
if( uri ) mesh.userData.srcTemplate = uri
|
||||||
|
mesh.userData.src = xrf.URI.template( mesh.userData.srcTemplate, xrf.URI.vars.__object )
|
||||||
|
return mesh.userData.src
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
|
@ -32,7 +40,7 @@ xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
}else{
|
}else{
|
||||||
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
||||||
mesh.add(scene)
|
mesh.add(scene)
|
||||||
xrf.emit('parseModel', {...opts, scene, model})
|
xrf.emit('parseModel', {...opts, isSRC:true, scene, model})
|
||||||
}
|
}
|
||||||
// flag everything isSRC & isXRF
|
// flag everything isSRC & isXRF
|
||||||
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
||||||
|
@ -66,7 +74,9 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
||||||
fetch(url, { method: 'HEAD' })
|
fetch(url, { method: 'HEAD' })
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
let mimetype = res.headers.get('Content-type')
|
let mimetype = res.headers.get('Content-type')
|
||||||
if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/) ) mimetype = 'gltf'
|
if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/) ) mimetype = 'gltf'
|
||||||
|
if( url.replace(/#.*/,'').match(/\.(frag|fs|glsl)$/) ) mimetype = 'x-shader/x-fragment'
|
||||||
|
if( url.replace(/#.*/,'').match(/\.(vert|vs)$/) ) mimetype = 'x-shader/x-fragment'
|
||||||
//if( url.match(/\.(fbx|stl|obj)$/) ) mimetype =
|
//if( url.match(/\.(fbx|stl|obj)$/) ) mimetype =
|
||||||
opts = { ...opts, frag, mimetype }
|
opts = { ...opts, frag, mimetype }
|
||||||
return xrf.frag.src.type[ mimetype ] ? xrf.frag.src.type[ mimetype ](url,opts) : xrf.frag.src.type.unknown(url,opts)
|
return xrf.frag.src.type[ mimetype ] ? xrf.frag.src.type[ mimetype ](url,opts) : xrf.frag.src.type.unknown(url,opts)
|
||||||
|
@ -98,7 +108,6 @@ xrf.frag.src.scale = function(scene, opts, url){
|
||||||
|
|
||||||
// remove invisible objects (hidden by selectors) which might corrupt boundingbox size-detection
|
// remove invisible objects (hidden by selectors) which might corrupt boundingbox size-detection
|
||||||
let cleanScene = scene.clone()
|
let cleanScene = scene.clone()
|
||||||
if( !cleanScene ) debugger
|
|
||||||
let remove = []
|
let remove = []
|
||||||
const notVisible = (n) => !n.visible || (n.material && !n.material.visible)
|
const notVisible = (n) => !n.visible || (n.material && !n.material.visible)
|
||||||
cleanScene.traverse( (n) => notVisible(n) && n.children.length == 0 && (remove.push(n)) )
|
cleanScene.traverse( (n) => notVisible(n) && n.children.length == 0 && (remove.push(n)) )
|
||||||
|
|
|
@ -23,7 +23,8 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
let sound = isPositionalAudio ? new THREE.PositionalAudio( camera.listener)
|
let sound = isPositionalAudio ? new THREE.PositionalAudio( camera.listener)
|
||||||
: new THREE.Audio( camera.listener )
|
: new THREE.Audio( camera.listener )
|
||||||
|
|
||||||
mesh.audio = {}
|
mesh.media = mesh.media || {}
|
||||||
|
mesh.media.audio = { play: () => mesh.media.audio.autoplay = true }
|
||||||
|
|
||||||
audioLoader.load( url.replace(/#.*/,''), function( buffer ) {
|
audioLoader.load( url.replace(/#.*/,''), function( buffer ) {
|
||||||
|
|
||||||
|
@ -36,9 +37,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
//sound.setDirectionalCone( 360, 360, 0.01 );
|
//sound.setDirectionalCone( 360, 360, 0.01 );
|
||||||
}
|
}
|
||||||
|
|
||||||
sound.playXRF = (t) => {
|
mesh.add(sound)
|
||||||
mesh.add(sound)
|
|
||||||
|
sound.pub = (t) => {
|
||||||
try{
|
try{
|
||||||
|
sound.t = t
|
||||||
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
||||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||||
|
|
||||||
|
@ -65,11 +68,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}catch(e){ console.warn(e) }
|
}catch(e){ console.warn(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// autoplay if user already requested play
|
// autoplay if user already requested play (before the sound was loaded)
|
||||||
let autoplay = mesh.audio && mesh.audio.autoplay
|
let autoplay = mesh.media.audio && mesh.media.audio.autoplay
|
||||||
mesh.audio = sound
|
mesh.media.audio = sound
|
||||||
if( autoplay ){
|
if( autoplay ){
|
||||||
xrf.hashbus.pub(mesh.audio.autoplay)
|
xrf.hashbus.pub(mesh.media.audio.autoplay)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* extensions: .frag/.fs/.vs/.vert
|
||||||
|
*/
|
||||||
|
|
||||||
|
xrf.frag.src.type['x-shader/x-fragment'] = function(url,opts){
|
||||||
|
let {mesh,THREE} = opts
|
||||||
|
|
||||||
|
let isFragmentShader = /\.(fs|frag|glsl)$/
|
||||||
|
let isVertexShader = /\.(vs|vert)$/
|
||||||
|
|
||||||
|
let shaderReqs = []
|
||||||
|
let shaderCode = {}
|
||||||
|
let shader = {
|
||||||
|
fragment: { code: '', url: url.match( isFragmentShader ) ? url : '' },
|
||||||
|
vertex: { code: '', url: url.match( isVertexShader ) ? url : '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
var onShaderLoaded = ((args) => (type, status, code) => {
|
||||||
|
shader[type].status = status
|
||||||
|
shader[type].code = code
|
||||||
|
if( shader.fragment.code && shader.vertex.code ){
|
||||||
|
|
||||||
|
let oldMaterial = mesh.material
|
||||||
|
mesh.material = new THREE.RawShaderMaterial({
|
||||||
|
uniforms: {
|
||||||
|
time: { value: 1.0 },
|
||||||
|
resolution: { value: new THREE.Vector2(1.0,1.0) }
|
||||||
|
},
|
||||||
|
// basic shaders include following common vars/funcs: https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderChunk/common.glsl.js
|
||||||
|
fragmentShader: shader.fragment.status == 200 ? shader.fragment.code : THREE.ShaderChunk.meshbasic_frag,
|
||||||
|
vertexShader: shader.vertex.status == 200 ? shader.vertex.code : THREE.ShaderChunk.meshbasic_vert,
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
mesh.material.needsUpdate = true
|
||||||
|
mesh.needsUpdate = true
|
||||||
|
|
||||||
|
mesh.onBeforeRender = () => {
|
||||||
|
if( !mesh.material || !mesh.material.uniforms ) return mesh.onBeforeRender = function(){}
|
||||||
|
mesh.material.uniforms.time.value = xrf.clock.elapsedTime
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})({})
|
||||||
|
|
||||||
|
// sidecar-load vertex shader file
|
||||||
|
if( shader.fragment.url && !shader.vertex.url ){
|
||||||
|
shader.vertex.url = shader.fragment.url.replace(/\.fs$/, '.vs')
|
||||||
|
.replace(/\.frag$/, '.vert')
|
||||||
|
}
|
||||||
|
|
||||||
|
if( shader.fragment.url ){
|
||||||
|
fetch(shader.fragment.url)
|
||||||
|
.then( (res) => res.text().then( (code) => onShaderLoaded('fragment',res.status,code) ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
if( shader.vertex.url ){
|
||||||
|
fetch(shader.vertex.url)
|
||||||
|
.then( (res) => res.text().then( (code) => onShaderLoaded('vertex',res.status,code) ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.frag.src.type['x-shader/x-vertex'] = xrf.frag.src.type['x-shader/x-fragment']
|
||||||
|
|
|
@ -74,6 +74,9 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
|
|
||||||
this.setupListeners = () => {
|
this.setupListeners = () => {
|
||||||
|
|
||||||
|
// below is a somewhat weird tapdance to render the portals **after** the scene
|
||||||
|
// is rendered (otherwise it messes up occlusion)
|
||||||
|
|
||||||
mesh.onAfterRender = function(renderer, scene, camera, geometry, material, group ){
|
mesh.onAfterRender = function(renderer, scene, camera, geometry, material, group ){
|
||||||
mesh.portal.needUpdate = true
|
mesh.portal.needUpdate = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@ let loadVideo = (mimetype) => function(url,opts){
|
||||||
const THREE = xrf.THREE
|
const THREE = xrf.THREE
|
||||||
let frag = xrf.URI.parse( url )
|
let frag = xrf.URI.parse( url )
|
||||||
|
|
||||||
let video = mesh.video = document.createElement('video')
|
mesh.media = mesh.media || {}
|
||||||
|
|
||||||
|
let video = mesh.media.video = document.createElement('video')
|
||||||
video.setAttribute("crossOrigin","anonymous")
|
video.setAttribute("crossOrigin","anonymous")
|
||||||
video.setAttribute("playsinline",'')
|
video.setAttribute("playsinline",'')
|
||||||
video.addEventListener('loadedmetadata', function(){
|
video.addEventListener('loadedmetadata', function(){
|
||||||
|
@ -17,21 +19,23 @@ let loadVideo = (mimetype) => function(url,opts){
|
||||||
// set range
|
// set range
|
||||||
video.addEventListener('timeupdate', function timeupdate() {
|
video.addEventListener('timeupdate', function timeupdate() {
|
||||||
if (video.t && video.t.y !== undefined && video.t.y > video.t.x && Math.abs(video.currentTime) >= video.t.y ){
|
if (video.t && video.t.y !== undefined && video.t.y > video.t.x && Math.abs(video.currentTime) >= video.t.y ){
|
||||||
if( video.t.speed.length ) video.currentTime = video.t.x // speed means loop
|
if( video.looping ) video.currentTime = video.t.x // speed means loop
|
||||||
else video.pause()
|
else video.pause()
|
||||||
}
|
}
|
||||||
},false)
|
},false)
|
||||||
})
|
})
|
||||||
|
|
||||||
video.src = url
|
video.src = url
|
||||||
video.playXRF = (t) => {
|
video.speed = 1.0
|
||||||
|
video.looping = false
|
||||||
|
video.pub = (t) => {
|
||||||
video.t = t
|
video.t = t
|
||||||
video.pause()
|
video.pause()
|
||||||
if( t.x !== undefined && t.x == t.y ) return // stop paused
|
if( t.x !== undefined && t.x == t.y ) return // stop paused
|
||||||
else{
|
else{
|
||||||
video.currentTime = t.x
|
video.currentTime = t.x
|
||||||
video.time = t.x
|
video.time = t.x
|
||||||
video.playbackRate = Math.abs( t.speed.length ? t.speed[0] : 1.0 ) // html5 video does not support reverseplay :/
|
video.playbackRate = Math.abs( video.speed ) // html5 video does not support reverseplay :/
|
||||||
video.play()
|
video.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
xrf.frag.suv = function(v, opts){
|
||||||
|
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
||||||
|
|
||||||
|
if( !mesh.geometry ) return // nothing to do here
|
||||||
|
|
||||||
|
xrf.frag.uv.init(mesh)
|
||||||
|
mesh.suv.x = v.x
|
||||||
|
mesh.suv.y = v.y !== undefined ? v.y : v.x
|
||||||
|
mesh.suv.loop = v.loop === true ? true : false
|
||||||
|
mesh.onBeforeRender = xrf.frag.uv.scroll
|
||||||
|
}
|
|
@ -1,5 +1,15 @@
|
||||||
|
// this is the global #t mediafragment handler (which affects the 3D animation)
|
||||||
|
|
||||||
xrf.frag.t = function(v, opts){
|
xrf.frag.t = function(v, opts){
|
||||||
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
||||||
|
|
||||||
|
// handle object media players
|
||||||
|
if( mesh && mesh.media ){
|
||||||
|
for( let i in mesh.media ) mesh.media[i].pub(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise handle global 3D animations
|
||||||
if( !model.mixer ) return
|
if( !model.mixer ) return
|
||||||
if( !model.animations || model.animations[0] == undefined ){
|
if( !model.animations || model.animations[0] == undefined ){
|
||||||
console.warn('no animations found in model')
|
console.warn('no animations found in model')
|
||||||
|
@ -11,10 +21,10 @@ xrf.frag.t = function(v, opts){
|
||||||
mixer.t = v
|
mixer.t = v
|
||||||
|
|
||||||
// update speed
|
// update speed
|
||||||
mixer.timeScale = mixer.loop.speed = v.x
|
mixer.timeScale = mixer.loop.speed || 1.0
|
||||||
mixer.loop.speedAbs = Math.abs(v.x)
|
mixer.loop.speedAbs = Math.abs( mixer.timeScale )
|
||||||
|
|
||||||
if( v.y != undefined || v.z != undefined ) mixer.updateLoop( v )
|
mixer.updateLoop( v )
|
||||||
|
|
||||||
// play animations
|
// play animations
|
||||||
mixer.play( v )
|
mixer.play( v )
|
||||||
|
@ -31,7 +41,7 @@ xrf.addEventListener('parseModel', (opts) => {
|
||||||
let {model} = opts
|
let {model} = opts
|
||||||
let mixer = model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
let mixer = model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||||
mixer.model = model
|
mixer.model = model
|
||||||
mixer.loop = {timeStart:0,timeStop:0}
|
mixer.loop = {timeStart:0,timeStop:0,speed:1.0}
|
||||||
mixer.i = xrf.mixers.length
|
mixer.i = xrf.mixers.length
|
||||||
mixer.actions = []
|
mixer.actions = []
|
||||||
|
|
||||||
|
@ -41,7 +51,6 @@ xrf.addEventListener('parseModel', (opts) => {
|
||||||
mixer.actions.push( mixer.clipAction( anim, model.scene ) )
|
mixer.actions.push( mixer.clipAction( anim, model.scene ) )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
mixer.checkZombies = (animations) => {
|
mixer.checkZombies = (animations) => {
|
||||||
if( mixer.zombieCheck ) return // fire only once
|
if( mixer.zombieCheck ) return // fire only once
|
||||||
animations.map( (anim) => {
|
animations.map( (anim) => {
|
||||||
|
@ -62,7 +71,7 @@ xrf.addEventListener('parseModel', (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer.play = (t) => {
|
mixer.play = (t) => {
|
||||||
mixer.isPlaying = t.x != 0
|
mixer.isPlaying = t.x !== undefined && t.x != t.y
|
||||||
mixer.updateLoop(t)
|
mixer.updateLoop(t)
|
||||||
xrf.emit( mixer.isPlaying === false ? 'stop' : 'play',{isPlaying: mixer.isPlaying})
|
xrf.emit( mixer.isPlaying === false ? 'stop' : 'play',{isPlaying: mixer.isPlaying})
|
||||||
}
|
}
|
||||||
|
@ -72,17 +81,15 @@ xrf.addEventListener('parseModel', (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer.updateLoop = (t) => {
|
mixer.updateLoop = (t) => {
|
||||||
mixer.loop.timeStart = t.y != undefined ? t.y : mixer.loop.timeStart
|
mixer.loop.timeStart = t.x != undefined ? t.x : mixer.loop.timeStart
|
||||||
mixer.loop.timeStop = t.z != undefined ? t.z : mixer.loop.timeStop
|
mixer.loop.timeStop = t.y != undefined ? t.y : mixer.loop.timeStop
|
||||||
mixer.actions.map( (action) => {
|
mixer.actions.map( (action) => {
|
||||||
if( mixer.loop.timeStart != undefined ){
|
if( mixer.loop.timeStart != undefined ){
|
||||||
action.time = mixer.loop.timeStart
|
action.time = mixer.loop.timeStart
|
||||||
action.setLoop( xrf.THREE.LoopOnce, )
|
action.setLoop( xrf.THREE.LoopOnce, )
|
||||||
action.timeScale = mixer.timeScale
|
action.timeScale = mixer.timeScale
|
||||||
action.enabled = true
|
action.enabled = true
|
||||||
if( t.x != 0 ){
|
if( t.x === 0 ) action.play()
|
||||||
action.play()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
mixer.setTime(mixer.loop.timeStart)
|
mixer.setTime(mixer.loop.timeStart)
|
||||||
|
@ -152,19 +159,6 @@ xrf.addEventListener('render', (opts) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
xrf.addEventListener('dynamicKey', (opts) => {
|
|
||||||
// select active camera if any
|
|
||||||
let {id,match,v} = opts
|
|
||||||
match.map( (w) => {
|
|
||||||
w.nodes.map( (node) => {
|
|
||||||
if( node.isCamera ){
|
|
||||||
console.log("switching camera to cam: "+node.name)
|
|
||||||
xrf.model.camera = node
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove mixers and stop mixers when loading another scene
|
// remove mixers and stop mixers when loading another scene
|
||||||
xrf.addEventListener('reset', (opts) => {
|
xrf.addEventListener('reset', (opts) => {
|
||||||
xrf.mixers.map( (m) => m.stop())
|
xrf.mixers.map( (m) => m.stop())
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
xrf.frag.uv = function(v, opts){
|
||||||
|
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
||||||
|
|
||||||
|
if( !mesh.geometry ) return // nothing to do here
|
||||||
|
|
||||||
|
xrf.frag.uv.init(mesh)
|
||||||
|
mesh.uv.x = v.x
|
||||||
|
mesh.uv.y = v.y !== undefined ? v.y : v.x
|
||||||
|
mesh.onBeforeRender = xrf.frag.uv.scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.frag.uv.init = function(mesh){
|
||||||
|
if( !mesh.uv ) mesh.uv = {x:0, y:0, w:1, h:1, uv:false}
|
||||||
|
if( !mesh.suv ) mesh.suv = {x:1, y:1, loop:false }
|
||||||
|
let uv = mesh.geometry.getAttribute("uv")
|
||||||
|
if( !uv.old ) uv.old = uv.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.frag.uv.scroll = function(){
|
||||||
|
if( this.suv.x > 0.0 || this.suv.y > 0.0 ){
|
||||||
|
|
||||||
|
let diff = 0.0 // distance to end-state (non-looping mode)
|
||||||
|
let uv = this.geometry.getAttribute("uv")
|
||||||
|
|
||||||
|
// translate!
|
||||||
|
for( let i = 0; i < uv.count; i++ ){
|
||||||
|
let u = uv.getX(i)
|
||||||
|
let v = uv.getY(i)
|
||||||
|
let uTarget = uv.old.getX(i) + this.uv.x
|
||||||
|
let vTarget = uv.old.getY(i) + this.uv.y
|
||||||
|
|
||||||
|
if( this.suv.loop ){
|
||||||
|
u += this.suv.x * xrf.clock.delta
|
||||||
|
v += this.suv.y * xrf.clock.delta
|
||||||
|
}else{
|
||||||
|
|
||||||
|
// recover from super-high uv-values due to looped scrolling
|
||||||
|
if( Math.abs(u-uTarget) > 1.0 ) u = uv.old.getX(i)
|
||||||
|
if( Math.abs(v-vTarget) > 1.0 ) v = uv.old.getY(i)
|
||||||
|
|
||||||
|
u = u > uTarget ? u + (this.suv.x * -xrf.clock.delta)
|
||||||
|
: u + (this.suv.x * xrf.clock.delta)
|
||||||
|
v = v > vTarget ? v + (this.suv.y * -xrf.clock.delta)
|
||||||
|
: v + (this.suv.y * xrf.clock.delta)
|
||||||
|
diff += Math.abs( u - uTarget ) // are we done yet? (non-looping mode)
|
||||||
|
diff += Math.abs( v - vTarget )
|
||||||
|
|
||||||
|
}
|
||||||
|
uv.setXY(i,u,v)
|
||||||
|
}
|
||||||
|
uv.needsUpdate = true
|
||||||
|
|
||||||
|
if( !this.suv.loop && diff < 0.05 ){ // stop animating if done
|
||||||
|
this.onBeforeRender = function(){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
xrf.frag.xywh = function(v, opts){
|
||||||
|
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
|
||||||
|
xrf.mediafragment.init(mesh)
|
||||||
|
mesh.xywh.x = v.floats[0]
|
||||||
|
mesh.xywh.y = v.floats[1] !== undefined ? v.floats[1] : mesh.xywh.x
|
||||||
|
mesh.xywh.w = v.floats[2] !== undefined ? v.floats[2] : mesh.xywh.y
|
||||||
|
mesh.xywh.h = v.floats[3] !== undefined ? v.floats[3] : mesh.xywh.w
|
||||||
|
// TODO: nondestructive cropping of texture (not superimportant now)
|
||||||
|
}
|
|
@ -18,16 +18,17 @@ class Test {
|
||||||
test( "url.json", Spec.load("src/spec/url.json") );
|
test( "url.json", Spec.load("src/spec/url.json") );
|
||||||
test( "pos.json", Spec.load("src/spec/pos.json") );
|
test( "pos.json", Spec.load("src/spec/pos.json") );
|
||||||
test( "t.json", Spec.load("src/spec/t.json") );
|
test( "t.json", Spec.load("src/spec/t.json") );
|
||||||
test( "xywh.json", Spec.load("src/spec/xywh.json") );
|
test( "xywh.json", Spec.load("src/spec/xywh.json") );
|
||||||
test( "s.json", Spec.load("src/spec/s.json") );
|
test( "s.json", Spec.load("src/spec/s.json") );
|
||||||
test( "sxy.json", Spec.load("src/spec/sxy.json") );
|
test( "suv.json", Spec.load("src/spec/suv.json") );
|
||||||
|
test( "suv.json", Spec.load("src/spec/uv.json") );
|
||||||
test( "filter.selectors.json", Spec.load("src/spec/filter.selectors.json") );
|
test( "filter.selectors.json", Spec.load("src/spec/filter.selectors.json") );
|
||||||
//test( Spec.load("src/spec/tmp.json") );
|
//test( Spec.load("src/spec/tmp.json") );
|
||||||
if( errors > 1 ) trace("\n-----\n[ ❌] "+errors+" errors :/");
|
if( errors > 1 ) trace("\n-----\n[ ❌] "+errors+" errors :/");
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function test( topic:String, spec:Array<Dynamic>):Void {
|
static public function test( topic:String, spec:Array<Dynamic>):Void {
|
||||||
trace("\n[.] running "+topic);
|
trace("\n[ . ] running "+topic);
|
||||||
var Filter = xrfragment.Filter;
|
var Filter = xrfragment.Filter;
|
||||||
for( i in 0...spec.length ){
|
for( i in 0...spec.length ){
|
||||||
var f:Filter = null;
|
var f:Filter = null;
|
||||||
|
@ -52,7 +53,7 @@ class Test {
|
||||||
if( item.expect.fn == "equal.mediafragmentT" ) valid = equalMediaFragment(res,item,"t");
|
if( item.expect.fn == "equal.mediafragmentT" ) valid = equalMediaFragment(res,item,"t");
|
||||||
if( item.expect.fn == "equal.mediafragmentXYWH") valid = equalMediaFragment(res,item,"xywh");
|
if( item.expect.fn == "equal.mediafragmentXYWH") valid = equalMediaFragment(res,item,"xywh");
|
||||||
if( item.expect.fn == "equal.mediafragmentS") valid = equalMediaFragment(res,item,"s");
|
if( item.expect.fn == "equal.mediafragmentS") valid = equalMediaFragment(res,item,"s");
|
||||||
if( item.expect.fn == "equal.mediafragmentSXY") valid = equalMediaFragment(res,item,"sxy");
|
if( item.expect.fn == "equal.mediafragmentSUV") valid = equalMediaFragment(res,item,"suv");
|
||||||
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 == "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;
|
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 ? "[ ✔ ] " : "[ ❌] ";
|
var ok:String = valid ? "[ ✔ ] " : "[ ❌] ";
|
||||||
|
|
|
@ -10,6 +10,5 @@
|
||||||
{"fn":"filter","data":"price=>2", "expect":{ "fn":"testProperty","input":["price","1"],"out":false}},
|
{"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","5"],"out":false}},
|
||||||
{"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","1"],"out":true}},
|
{"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","1"],"out":true}},
|
||||||
{"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":1},"label":"foo should be deep"}
|
||||||
{"fn":"url","data":"#foo**", "expect":{ "fn":"testFilterDeep","input":["foo"],"out":2},"label":"foo should be deep incl. embeds"}
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[
|
[
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#s=1", "expect":{ "fn":"equal.mediafragmentSpeed", "input":"0","out":"1"},"label":"playback speed"},
|
{"fn":"url","data":"http://foo.com?foo=1#s=1", "expect":{ "fn":"equal.x", "input":"s","out":"1"},"label":"playback speed"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#s=0.5", "expect":{ "fn":"equal.mediafragmentSpeed", "input":"0","out":"0.5"},"label":"playback speed"},
|
{"fn":"url","data":"http://foo.com?foo=1#s=0.5", "expect":{ "fn":"equal.x", "input":"s","out":"0.5"},"label":"playback speed"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#s=-0.5", "expect":{ "fn":"equal.mediafragmentSpeed", "input":"0","out":"-0.5"},"label":"playback speed"}
|
{"fn":"url","data":"http://foo.com?foo=1#s=-0.5", "expect":{ "fn":"equal.x", "input":"s","out":"-0.5"},"label":"playback speed"}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[
|
[
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#sxy=l:0,0.1", "expect":{ "fn":"equal.mediafragmentSXY", "input":"1","out":"0.2"},"label":"sxy"},
|
{"fn":"url","data":"http://foo.com?foo=1#suv=l:0,0.1", "expect":{ "fn":"equal.mediafragmentSUV", "input":"1","out":"0.1"},"label":"suv"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#sxy=0,0.1", "expect":{ "fn":"equal.mediafragmentSXY", "input":"1","out":"0.2"},"label":"sxy looped"}
|
{"fn":"url","data":"http://foo.com?foo=1#suv=0.2,0.1", "expect":{ "fn":"equal.mediafragmentSUV", "input":"0","out":"0.2"},"label":"suv looped"}
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,8 +8,5 @@
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=1,100", "expect":{ "fn":"equal.xy", "input":"t","out":"1,100"},"label":"a equal.xy"},
|
{"fn":"url","data":"http://foo.com?foo=1#t=1,100", "expect":{ "fn":"equal.xy", "input":"t","out":"1,100"},"label":"a equal.xy"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=2,500", "expect":{ "fn":"testBrowserOverride", "input":"t","out":true},"label":"browser URI can override t (defined in asset)"},
|
{"fn":"url","data":"http://foo.com?foo=1#t=2,500", "expect":{ "fn":"testBrowserOverride", "input":"t","out":true},"label":"browser URI can override t (defined in asset)"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment"},
|
{"fn":"url","data":"http://foo.com?foo=1#t=1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment"},
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=l:1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment loop"},
|
{"fn":"url","data":"http://foo.com?foo=1#t=l:1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment loop"}
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=v:l:1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment uv loop "},
|
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=v:1,100,400,500", "expect":{ "fn":"equal.mediafragmentT", "input":"3","out":"500"},"label":"a equal.mediafragment uv"},
|
|
||||||
{"fn":"url","data":"http://foo.com?foo=1#t=v:1,2", "expect":{ "fn":"testParsed", "input":"mycustom","out":true},"label":"test uv is set"}
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[
|
||||||
|
{"fn":"url","data":"http://foo.com?foo=1#uv=1.2,2.2", "expect":{ "fn":"equal.xy", "input":"uv","out":"1.2,2.2"},"label":"equal.string uv"}
|
||||||
|
]
|
|
@ -15,27 +15,27 @@ class Parser {
|
||||||
// here we define allowed characteristics & datatypes for each fragment (stored as bitmasked int for performance purposes)
|
// here we define allowed characteristics & datatypes for each fragment (stored as bitmasked int for performance purposes)
|
||||||
var Frag:Map<String, Int> = new Map<String, Int>();
|
var Frag:Map<String, Int> = new Map<String, Int>();
|
||||||
|
|
||||||
Frag.set("#", XRF.ASSET | XRF.T_PREDEFINED_VIEW | XRF.PV_EXECUTE );
|
Frag.set("#", XRF.IMMUTABLE | XRF.T_PREDEFINED_VIEW | XRF.PV_EXECUTE );
|
||||||
Frag.set("src", XRF.ASSET | XRF.T_URL );
|
Frag.set("src", XRF.T_URL );
|
||||||
Frag.set("href", XRF.ASSET | XRF.T_URL | XRF.T_PREDEFINED_VIEW );
|
Frag.set("href", XRF.T_URL | XRF.T_PREDEFINED_VIEW );
|
||||||
Frag.set("tag", XRF.ASSET | XRF.T_STRING );
|
Frag.set("tag", XRF.IMMUTABLE | XRF.T_STRING );
|
||||||
|
|
||||||
// spatial category: query selector / object manipulation
|
// spatial category: query selector / object manipulation
|
||||||
Frag.set("pos", XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.T_STRING | XRF.METADATA | XRF.NAVIGATOR );
|
Frag.set("pos", XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.T_STRING | XRF.METADATA | XRF.NAVIGATOR );
|
||||||
Frag.set("rot", XRF.QUERY_OPERATOR | XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.METADATA | XRF.NAVIGATOR );
|
Frag.set("rot", XRF.QUERY_OPERATOR | XRF.PV_OVERRIDE | XRF.T_VECTOR3 | XRF.METADATA | XRF.NAVIGATOR );
|
||||||
|
|
||||||
// category: media fragments
|
// category: media fragments
|
||||||
Frag.set("t", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_MEDIAFRAG | XRF.NAVIGATOR | XRF.METADATA);
|
Frag.set("t", XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_MEDIAFRAG | XRF.NAVIGATOR | XRF.METADATA);
|
||||||
Frag.set("xywh", XRF.ASSET | XRF.PV_OVERRIDE | XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_MEDIAFRAG | XRF.NAVIGATOR | XRF.METADATA);
|
Frag.set("xywh", XRF.T_FLOAT | XRF.T_VECTOR2 | XRF.T_MEDIAFRAG | XRF.NAVIGATOR | XRF.METADATA);
|
||||||
|
Frag.set("s", XRF.PV_OVERRIDE | XRF.T_MEDIAFRAG | XRF.T_FLOAT );
|
||||||
|
Frag.set("uv", XRF.T_VECTOR2 | XRF.T_MEDIAFRAG );
|
||||||
|
Frag.set("suv", XRF.T_VECTOR2 | XRF.T_MEDIAFRAG );
|
||||||
|
|
||||||
// category: author / metadata
|
// category: author / metadata
|
||||||
Frag.set("namespace", XRF.ASSET | XRF.T_STRING );
|
Frag.set("namespace", XRF.IMMUTABLE | XRF.T_STRING );
|
||||||
Frag.set("SPDX", XRF.ASSET | XRF.T_STRING );
|
Frag.set("SPDX", XRF.IMMUTABLE | XRF.T_STRING );
|
||||||
Frag.set("unit", XRF.ASSET | XRF.T_STRING );
|
Frag.set("unit", XRF.IMMUTABLE | XRF.T_STRING );
|
||||||
Frag.set("description", XRF.ASSET | XRF.T_STRING );
|
Frag.set("description", XRF.IMMUTABLE | XRF.T_STRING );
|
||||||
|
|
||||||
// category: multiparty
|
|
||||||
Frag.set("session", XRF.ASSET | XRF.T_URL | XRF.PV_OVERRIDE | XRF.NAVIGATOR | XRF.METADATA | XRF.PROMPT );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* # Spec
|
* # Spec
|
||||||
|
@ -51,11 +51,12 @@ class Parser {
|
||||||
|
|
||||||
// dynamic fragments cases: predefined views & assign/binds
|
// dynamic fragments cases: predefined views & assign/binds
|
||||||
var isPVDynamic:Bool = key.length > 0 && !Frag.exists(key);
|
var isPVDynamic:Bool = key.length > 0 && !Frag.exists(key);
|
||||||
var isPVDefault:Bool = value.length == 0 && key.length > 0 && key == "#";
|
if( isPVDynamic ){ // 1. add key(values) to store as [predefined view](predefined_view) or dynamic assignment
|
||||||
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 );
|
var v:XRF = new XRF(key, XRF.PV_EXECUTE | XRF.NAVIGATOR, index );
|
||||||
v.validate(value); // ignore failures (empty values are allowed)
|
v.validate(value); // ignore failures (empty values are allowed)
|
||||||
v.flags = XRF.set( XRF.T_DYNAMIC, v.flags );
|
v.flags = XRF.set( XRF.T_DYNAMICKEY, v.flags );
|
||||||
|
if( !Frag.exists(key) ) v.flags = XRF.set( XRF.CUSTOMFRAG, v.flags );
|
||||||
|
if( value.length == 0 ) v.flags = XRF.set( XRF.T_DYNAMICKEYVALUE, v.flags );
|
||||||
store.set( keyStripped, v );
|
store.set( keyStripped, v );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -67,11 +68,11 @@ class Parser {
|
||||||
trace("⚠ fragment '"+key+"' has incompatible value ("+value+")");// 1. don't add to store if value-type is incorrect
|
trace("⚠ fragment '"+key+"' has incompatible value ("+value+")");// 1. don't add to store if value-type is incorrect
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
store.set( keyStripped, v); // 1. if valid, add to store
|
store.set( keyStripped, v); // 1. if valid, add to store
|
||||||
if( debug ) trace("✔ "+key+": "+v.string);
|
if( debug ) trace("✔ "+key+": "+v.string);
|
||||||
}else{ // 1. expose (but mark) non-offical fragments too
|
}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);
|
||||||
v.noXRF = true;
|
v.flags = XRF.set( XRF.CUSTOMFRAG, v.flags );
|
||||||
store.set( keyStripped ,v);
|
store.set( keyStripped ,v);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -52,6 +52,19 @@ class URI {
|
||||||
}
|
}
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keep
|
||||||
|
public static function template(uri:String, vars:Dynamic):String {
|
||||||
|
var parts = uri.split("#");
|
||||||
|
if( parts.length == 1 ) return uri; // we only do level1 fragment expansion
|
||||||
|
var frag = parts[1];
|
||||||
|
frag = StringTools.replace(frag,"{","::");
|
||||||
|
frag = StringTools.replace(frag,"}","::");
|
||||||
|
frag = new haxe.Template(frag).execute(vars);
|
||||||
|
frag = StringTools.replace(frag,"null",""); // *TODO* needs regex to check for [#&]null[&]
|
||||||
|
parts[1] = frag;
|
||||||
|
return parts.join("#");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,14 +10,14 @@ class XRF {
|
||||||
* this class represents a fragment (value)
|
* this class represents a fragment (value)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// public static inline readonly ASSET
|
// public static inline readonly IMMUTABLE
|
||||||
|
|
||||||
// scope types (powers of 2)
|
// scope types (powers of 2)
|
||||||
public static var ASSET:Int = 1; // fragment is immutable
|
public static var IMMUTABLE:Int = 1; // fragment is immutable
|
||||||
public static var PROP_BIND:Int = 2; // fragment binds/controls one property with another
|
public static var PROP_BIND:Int = 2; // fragment binds/controls one property with another
|
||||||
public static var QUERY_OPERATOR:Int = 4; // fragment will be applied to result of filterselecto
|
public static var QUERY_OPERATOR:Int = 4; // fragment will be applied to result of filterselecto
|
||||||
public static var PROMPT:Int = 8; // ask user whether this fragment value can be changed
|
public static var PROMPT:Int = 8; // ask user whether this fragment value can be changed
|
||||||
public static var ROUNDROBIN:Int = 16; // evaluation of this (multi) value can be roundrobined
|
public static var CUSTOMFRAG:Int = 16; // evaluation of this (multi) value can be roundrobined
|
||||||
public static var NAVIGATOR:Int = 32; // fragment can be overridden by (manual) browser URI change
|
public static var NAVIGATOR:Int = 32; // fragment can be overridden by (manual) browser URI change
|
||||||
public static var METADATA:Int = 64; // fragment can be overridden by an embedded URL
|
public static var METADATA:Int = 64; // fragment can be overridden by an embedded URL
|
||||||
public static var PV_OVERRIDE:Int = 128; // embedded fragment can be overridden when specified in predefined view value
|
public static var PV_OVERRIDE:Int = 128; // embedded fragment can be overridden when specified in predefined view value
|
||||||
|
@ -33,7 +33,8 @@ class XRF {
|
||||||
public static var T_PREDEFINED_VIEW:Int = 524288;
|
public static var T_PREDEFINED_VIEW:Int = 524288;
|
||||||
public static var T_STRING:Int = 1048576;
|
public static var T_STRING:Int = 1048576;
|
||||||
public static var T_MEDIAFRAG:Int = 2097152;
|
public static var T_MEDIAFRAG:Int = 2097152;
|
||||||
public static var T_DYNAMIC:Int = 4194304;
|
public static var T_DYNAMICKEY:Int = 4194304;
|
||||||
|
public static var T_DYNAMICKEYVALUE:Int = 8388608;
|
||||||
|
|
||||||
// regexes
|
// 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 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})$/`
|
||||||
|
@ -43,12 +44,13 @@ class XRF {
|
||||||
public static var isUrl:EReg = ~/(:\/\/)?\..*/; // 1. url/file */`
|
public static var isUrl:EReg = ~/(:\/\/)?\..*/; // 1. url/file */`
|
||||||
public static var isUrlOrPretypedView: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 operators:EReg = ~/(^[-]|^[!]|[\*]$)/g; // 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 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 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 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\.]+$/` )
|
public static var isNumber:EReg = ~/^[0-9\.]+$/; // 1. detect number values like `foo=1` (reference regex= `/^[0-9\.]+$/` )
|
||||||
public static var isMediaFrag:EReg = ~/^(uv:)?(l:)?([0-9\.,\*]+)$/; // 1. detect (extended) media fragment
|
public static var isMediaFrag:EReg = ~/^(l:)?([0-9\.,\*]+)$/; // 1. detect (extended) media fragment
|
||||||
|
public static var isReset:EReg = ~/^!/; // 1. detect reset operation
|
||||||
|
|
||||||
// value holder(s) // |------|------|--------|----------------------------------|
|
// value holder(s) // |------|------|--------|----------------------------------|
|
||||||
public var fragment:String;
|
public var fragment:String;
|
||||||
|
@ -58,15 +60,13 @@ class XRF {
|
||||||
public var y:Float;
|
public var y:Float;
|
||||||
public var z:Float;
|
public var z:Float;
|
||||||
public var floats:Array<Float> = new Array<Float>();
|
public var floats:Array<Float> = new Array<Float>();
|
||||||
public var speed:Array<Float> = new Array<Float>();
|
|
||||||
public var color:String; // |string| color| FFFFFF (hex) | #fog=5m,FFAACC |
|
public var color:String; // |string| color| FFFFFF (hex) | #fog=5m,FFAACC |
|
||||||
public var string:String; // |string| | | #q=-sun |
|
public var string:String; // |string| | | #q=-sun |
|
||||||
public var int:Int; // |int | | [-]x[xxxxx] | #price:>=100 |
|
public var int:Int; // |int | | [-]x[xxxxx] | #price:>=100 |
|
||||||
public var float:Float; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 |
|
public var float:Float; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 |
|
||||||
public var filter:Filter;
|
public var filter:Filter;
|
||||||
public var noXRF:Bool;
|
public var reset:Bool;
|
||||||
public var loop:Bool;
|
public var loop:Bool;
|
||||||
public var uv:Bool;
|
|
||||||
//
|
//
|
||||||
public function new(_fragment:String,_flags:Int,?_index:Int){
|
public function new(_fragment:String,_flags:Int,?_index:Int){
|
||||||
fragment = _fragment;
|
fragment = _fragment;
|
||||||
|
@ -99,16 +99,13 @@ class XRF {
|
||||||
@:keep
|
@:keep
|
||||||
public function guessType(v:XRF, str:String):Void {
|
public function guessType(v:XRF, str:String):Void {
|
||||||
v.string = str;
|
v.string = str;
|
||||||
|
if( isReset.match(v.fragment) ) v.reset = true;
|
||||||
if( !Std.isOfType(str,String) ) return;
|
if( !Std.isOfType(str,String) ) return;
|
||||||
if( str.length > 0 ){
|
if( str.length > 0 ){
|
||||||
if( str.split("l:").length > 1 ){
|
if( str.split("l:").length > 1 ){
|
||||||
str = str.split("l:")[1];
|
str = str.split("l:")[1];
|
||||||
v.loop = true;
|
v.loop = true;
|
||||||
}
|
}
|
||||||
if( str.split("uv:").length > 1 ){
|
|
||||||
str = str.split("uv:")[1];
|
|
||||||
v.uv = true;
|
|
||||||
}
|
|
||||||
if( str.split(",").length > 1){ // 1. `,` assumes 1D/2D/3D vector-values like x[,y[,z]]
|
if( str.split(",").length > 1){ // 1. `,` assumes 1D/2D/3D vector-values like x[,y[,z]]
|
||||||
var xyzn:Array<String> = str.split(","); // 1. parseFloat(..) and parseInt(..) is applied to vector/float and int values
|
var xyzn:Array<String> = str.split(","); // 1. parseFloat(..) and parseInt(..) is applied to vector/float and int values
|
||||||
if( xyzn.length > 0 ) v.x = Std.parseFloat(xyzn[0]); // 1. anything else will be treated as string-value
|
if( xyzn.length > 0 ) v.x = Std.parseFloat(xyzn[0]); // 1. anything else will be treated as string-value
|
||||||
|
@ -127,6 +124,7 @@ class XRF {
|
||||||
if( isInt.match(str) ){
|
if( isInt.match(str) ){
|
||||||
v.int = Std.parseInt(str);
|
v.int = Std.parseInt(str);
|
||||||
v.x = cast(v.int);
|
v.x = cast(v.int);
|
||||||
|
v.floats.push( cast(v.x) );
|
||||||
}
|
}
|
||||||
v.filter = new Filter(v.fragment+"="+v.string);
|
v.filter = new Filter(v.fragment+"="+v.string);
|
||||||
}else v.filter = new Filter(v.fragment);
|
}else v.filter = new Filter(v.fragment);
|
||||||
|
|
Loading…
Reference in New Issue