build
This commit is contained in:
parent
29744defef
commit
9e1ea98b96
15 changed files with 122369 additions and 4591 deletions
321
dist/xrfragment.aframe.js
vendored
321
dist/xrfragment.aframe.js
vendored
|
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
||||||
delete opts.promise
|
delete opts.promise
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('reset', () => {
|
||||||
|
// *TODO* do this nicely
|
||||||
|
// xrf._listeners['renderPost'] = []
|
||||||
|
// xrf._listeners['render'] = []
|
||||||
|
})
|
||||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||||
|
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
||||||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||||
xrf.add( xrf.interactive )
|
xrf.add( xrf.interactive )
|
||||||
xrf.layers = 0
|
xrf.layers = 0
|
||||||
|
|
||||||
|
// reset certain events
|
||||||
xrf.emit('reset',{})
|
xrf.emit('reset',{})
|
||||||
// remove mixers
|
// remove mixers
|
||||||
xrf.mixers.map( (m) => m.stop())
|
xrf.mixers.map( (m) => m.stop())
|
||||||
|
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
|
||||||
|
//if( !file.match(/\./) || file.match(/\.html/) ){
|
||||||
|
// debugger
|
||||||
|
// let inIframe
|
||||||
|
// try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
|
||||||
|
// return inIframe ? window.parent.postMessage({ url: v.string }, '*') : window.open( v.string, '_blank')
|
||||||
|
//}
|
||||||
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
||||||
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||||
// always commit current location (keep a trail of last positions before we navigate)
|
// always commit current location (keep a trail of last positions before we navigate)
|
||||||
|
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
||||||
let url = v.string
|
let url = 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)
|
||||||
|
|
||||||
if( opts.isLocal ){
|
if( opts.isLocal ){
|
||||||
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
||||||
|
|
@ -1187,22 +1203,21 @@ xrf.frag.src = function(v, opts){
|
||||||
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
let {mesh} = opts
|
let {mesh} = opts
|
||||||
let scene = model.scene
|
let scene = model.scene
|
||||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||||
//enableSourcePortation(scene)
|
//enableSourcePortation(scene)
|
||||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||||
// only add remote objects, because
|
// only add remote objects, because
|
||||||
// local scene-objects are already added to scene
|
// local scene-objects are already added to scene
|
||||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||||
return
|
|
||||||
}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})
|
||||||
}
|
}
|
||||||
// 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 })
|
||||||
xrf.emit('parseModel', {...opts, scene, model})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||||
|
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||||
let {model,scene} = opts
|
let {model,mesh,scene} = opts
|
||||||
let _model = {
|
setTimeout( () => {
|
||||||
animations: model.animations,
|
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||||
scene: scene.clone()
|
let _model = {
|
||||||
}
|
animations: model.animations,
|
||||||
_model.scenes = [_model.scene]
|
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
}
|
||||||
|
_model.scenes = [_model.scene]
|
||||||
|
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||||
|
},500 )
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
||||||
|
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
||||||
xrf.frag.src.filterScene = (scene,opts) => {
|
xrf.frag.src.filterScene = (scene,opts) => {
|
||||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||||
|
|
||||||
xrf.filter.scene({scene,frag,reparent:true})
|
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||||
|
|
||||||
scene.traverse( (m) => {
|
if( !opts.isLocal ){
|
||||||
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
scene.traverse( (m) => {
|
||||||
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
||||||
})
|
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
||||||
|
})
|
||||||
|
}
|
||||||
return scene
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
||||||
xrf.filter.scene = function(opts){
|
xrf.filter.scene = function(opts){
|
||||||
let {scene,frag} = opts
|
let {scene,frag} = opts
|
||||||
|
|
||||||
xrf.filter
|
scene = xrf.filter
|
||||||
.sort(frag) // get (sorted) filters from XR Fragments
|
.sort(frag) // get (sorted) filters from XR Fragments
|
||||||
.process(frag,scene,opts) // show/hide things
|
.process(frag,scene,opts) // show/hide things
|
||||||
|
|
||||||
|
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
||||||
return xrf.filter
|
return xrf.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opts = {copyScene:true} in case you want a copy of the scene (not filter the current scene inplace)
|
||||||
xrf.filter.process = function(frag,scene,opts){
|
xrf.filter.process = function(frag,scene,opts){
|
||||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||||
const hasName = (m,name,filter) => m.name == name
|
const hasName = (m,name,filter) => m.name == name
|
||||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
const getOrCloneMaterial = (o) => {
|
const getOrCloneMaterial = (o) => {
|
||||||
if( o.material ){
|
if( o.material ){
|
||||||
|
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
let obj
|
let obj
|
||||||
frag.target = firstFilter
|
frag.target = firstFilter
|
||||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||||
if(obj){
|
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
if(obj ){
|
||||||
obj.position.set(0,0,0)
|
obj.position.set(0,0,0)
|
||||||
scene.add( obj )
|
if( opts.copyScene ){
|
||||||
|
opts.copyScene = new xrf.THREE.Scene()
|
||||||
|
opts.copyScene.children[0] = obj
|
||||||
|
scene = opts.copyScene
|
||||||
|
}else{
|
||||||
|
// empty current scene and add obj
|
||||||
|
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||||
|
scene.add( obj )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,7 +1750,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
// hide external objects temporarely
|
// hide external objects temporarely
|
||||||
scene.traverse( (m) => {
|
scene.traverse( (m) => {
|
||||||
if( m.isSRCExternal ){
|
if( m.isSRCExternal ){
|
||||||
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (n.visible = false) )
|
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (m.visible = false) )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1740,7 +1770,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
for ( let i in extembeds ) extembeds[i].visible = true
|
for ( let i in extembeds ) extembeds[i].visible = true
|
||||||
})
|
})
|
||||||
|
|
||||||
return xrf.filter
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||||
|
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
let frag = xrf.URI.parse( url )
|
let frag = xrf.URI.parse( url )
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
/* WebAudio: setup context via THREEjs */
|
/* WebAudio: setup context via THREEjs */
|
||||||
if( !camera.listener ){
|
if( !camera.listener ){
|
||||||
camera.listener = new THREE.AudioListener();
|
camera.listener = new THREE.AudioListener();
|
||||||
// *FIXME* camera vs camerarig conflict
|
// *FIXME* camera vs camerarig conflict
|
||||||
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
||||||
|
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}
|
}
|
||||||
|
|
||||||
sound.playXRF = (t) => {
|
sound.playXRF = (t) => {
|
||||||
|
mesh.add(sound)
|
||||||
|
try{
|
||||||
|
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
||||||
|
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||||
|
|
||||||
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
let hardcodedLoop = frag.t != undefined
|
||||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
||||||
|
if( t && t.x != 0 ){
|
||||||
|
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
||||||
|
t.x = Math.abs(t.x)
|
||||||
|
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
||||||
|
// setting loop
|
||||||
|
if( t.z ) sound.setLoop( true )
|
||||||
|
// apply embedded audio/video samplerate/fps or global mixer fps
|
||||||
|
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
||||||
|
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
||||||
|
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
||||||
|
|
||||||
let hardcodedLoop = frag.t != undefined
|
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||||
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
if( t.y != undefined ){
|
||||||
if( t && t.x != 0 ){
|
sound.setLoopStart( loopStart )
|
||||||
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
sound.offset = loopStart
|
||||||
t.x = Math.abs(t.x)
|
}
|
||||||
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
sound.play()
|
||||||
// setting loop
|
|
||||||
if( t.z ) sound.setLoop( true )
|
|
||||||
// apply embedded audio/video samplerate/fps or global mixer fps
|
|
||||||
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
|
||||||
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
|
||||||
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
|
||||||
|
|
||||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
|
||||||
if( t.y != undefined ){
|
|
||||||
sound.setLoopStart( loopStart )
|
|
||||||
sound.offset = loopStart
|
|
||||||
}
|
}
|
||||||
sound.play()
|
}catch(e){ console.warn(e) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mesh.add(sound)
|
mesh.audio = sound
|
||||||
});
|
});
|
||||||
|
|
||||||
mesh.audio = sound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let audioMimeTypes = [
|
let audioMimeTypes = [
|
||||||
|
|
@ -1968,6 +1996,18 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let loadHTML = (mimetype) => function(url,opts){
|
||||||
|
let {mesh,src,camera} = opts
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
|
let frag = xrf.URI.parse( url )
|
||||||
|
console.warn("todo: html viewer for src not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlMimeTypes = [
|
||||||
|
'text/html'
|
||||||
|
]
|
||||||
|
htmlMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadHTML(mimetype) )
|
||||||
/*
|
/*
|
||||||
* mimetype: image/png
|
* mimetype: image/png
|
||||||
* mimetype: image/jpg
|
* mimetype: image/jpg
|
||||||
|
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
let {mesh,THREE} = opts
|
let {mesh,THREE} = opts
|
||||||
let restrictTo3DBoundingBox = mesh.geometry
|
let restrictTo3DBoundingBox = mesh.geometry
|
||||||
|
|
||||||
let renderEquirect = (texture) => {
|
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
map: null,
|
||||||
texture.needsUpdate = true
|
transparent: url.match(/(png|gif)/) ? true : false,
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
side: THREE.DoubleSide,
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
color: 0xFFFFFF,
|
||||||
texture.magFilter = THREE.NearestFilter
|
opacity:1
|
||||||
texture.minFilter = THREE.NearestFilter
|
});
|
||||||
|
|
||||||
// poor man's equi-portal
|
|
||||||
mesh.material = new THREE.ShaderMaterial( {
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
uniforms: {
|
|
||||||
pano: { value: texture },
|
|
||||||
selected: { value: false },
|
|
||||||
},
|
|
||||||
vertexShader: `
|
|
||||||
vec3 portalPosition;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
void main() {
|
|
||||||
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
|
|
||||||
portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
vDistance = length(portalPosition - cameraPosition);
|
|
||||||
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
fragmentShader: `
|
|
||||||
#define RECIPROCAL_PI2 0.15915494
|
|
||||||
uniform sampler2D pano;
|
|
||||||
uniform bool selected;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
void main() {
|
|
||||||
vec3 direction = normalize(vWorldPosition - cameraPosition );
|
|
||||||
vec2 sampleUV;
|
|
||||||
sampleUV.y = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
|
|
||||||
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2;
|
|
||||||
sampleUV.x += 0.33; // adjust focus to AFRAME's a-scene.components.screenshot.capture()
|
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
|
||||||
vec4 selected_color = selected ? color*vec4(1.5) : color;
|
|
||||||
gl_FragColor = selected_color;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
mesh.material.needsUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderImage = (texture) => {
|
let renderImage = (texture) => {
|
||||||
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
||||||
|
|
@ -2042,26 +2040,15 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const geometry = new THREE.BoxGeometry();
|
mesh.material.map = texture
|
||||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
mesh.needsUpdate = true
|
||||||
map: texture,
|
|
||||||
transparent: url.match(/(png|gif)/) ? true : false,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
color: 0xFFFFFF,
|
|
||||||
opacity:1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLoad = (texture) => {
|
let onLoad = (texture) => {
|
||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
texture.wrapS = THREE.RepeatWrapping;
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
texture.wrapT = THREE.RepeatWrapping;
|
||||||
// detect equirectangular image
|
renderImage(texture)
|
||||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
|
||||||
renderEquirect(texture)
|
|
||||||
}else{
|
|
||||||
renderImage(texture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
||||||
|
|
@ -2076,6 +2063,7 @@ xrf.frag.src.type['image/jpeg'] = xrf.frag.src.type['image/png']
|
||||||
xrf.portalNonEuclidian = function(opts){
|
xrf.portalNonEuclidian = function(opts){
|
||||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||||
|
|
||||||
|
|
||||||
mesh.portal = {
|
mesh.portal = {
|
||||||
pos: mesh.position.clone(),
|
pos: mesh.position.clone(),
|
||||||
posWorld: new xrf.THREE.Vector3(),
|
posWorld: new xrf.THREE.Vector3(),
|
||||||
|
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
cameraPosition: new THREE.Vector3(),
|
cameraPosition: new THREE.Vector3(),
|
||||||
raycaster: new THREE.Raycaster(),
|
raycaster: new THREE.Raycaster(),
|
||||||
isLocal: opts.isLocal,
|
isLocal: opts.isLocal,
|
||||||
isLens: false
|
isLens: false,
|
||||||
|
isInside: false,
|
||||||
|
setStencil: (stencilRef) => mesh.portal.stencilObjects.traverse( (n) => showPortal(n, stencilRef == 0) && n.stencil && n.stencil(stencilRef) ),
|
||||||
|
positionObjectsIfNeeded: (pos,scale) => !mesh.portal.isLens && mesh.portal.stencilObjects.traverse( (n) => n.positionAtStencil && (n.positionAtStencil(pos,scale)) )
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
||||||
const addStencilFeature = (n) => {
|
const addStencilFeature = (n) => {
|
||||||
if( n.stencil ) return n // run once
|
if( n.stencil ) return n // run once
|
||||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
|
||||||
if( !mesh.portal.isLens ){
|
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||||
n.position.copy( sRef == 0 ? pos : newPos )
|
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
n.position.copy( newPos || pos )
|
||||||
else n.scale.copy( scale )
|
n.scale.copy( scale )
|
||||||
n.updateMatrixWorld(true)
|
n.updateMatrixWorld(true)
|
||||||
}
|
}
|
||||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
// curry function
|
||||||
}
|
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||||
)( n.position.clone(), n.scale.clone() )
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||||
.map(addStencilFeature)
|
.map(addStencilFeature)
|
||||||
|
|
||||||
//// add missing lights to make sure things get lit properly
|
|
||||||
xrf.scene.traverse( (n) => n.isLight &&
|
|
||||||
!stencilObjects.find( (o) => o.uuid == n.uuid ) &&
|
|
||||||
stencilObjects.push(n)
|
|
||||||
)
|
|
||||||
|
|
||||||
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
||||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||||
mesh.portal.stencilObjects.children = stencilObjects
|
mesh.portal.stencilObjects.children = stencilObjects
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||||
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
||||||
|
|
||||||
// clone so it won't be affected by other fragments
|
|
||||||
setTimeout( (mesh) => {
|
|
||||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
|
||||||
}, 0, mesh )
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
xrf.addEventListener('renderPost', (opts) => {
|
xrf.addEventListener('renderPost', (opts) => {
|
||||||
let {scene,camera,time,render,renderer} = opts
|
let {scene,camera,time,render,renderer} = opts
|
||||||
|
|
||||||
if( mesh.portal && mesh.portal.stencilObjects ){
|
if( mesh.portal.needUpdate && mesh.portal && mesh.portal.stencilObjects ){
|
||||||
|
let cameraDirection = mesh.portal.cameraDirection
|
||||||
|
let cameraPosition = mesh.portal.cameraPosition
|
||||||
let stencilRef = mesh.portal.stencilRef
|
let stencilRef = mesh.portal.stencilRef
|
||||||
let newPos = mesh.portal.posWorld
|
let newPos = mesh.portal.posWorld
|
||||||
let stencilObject = mesh.portal.stencilObject
|
let stencilObject = mesh.portal.stencilObject
|
||||||
let newScale = mesh.scale
|
let newScale = mesh.scale
|
||||||
let cameraDirection = mesh.portal.cameraDirection
|
|
||||||
let cameraPosition = mesh.portal.cameraPosition
|
|
||||||
let raycaster = mesh.portal.raycaster
|
let raycaster = mesh.portal.raycaster
|
||||||
|
|
||||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||||
cam.getWorldPosition(cameraPosition)
|
cam.getWorldPosition(cameraPosition)
|
||||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
|
||||||
cam.getWorldDirection(cameraDirection)
|
cam.getWorldDirection(cameraDirection)
|
||||||
|
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||||
|
|
||||||
// init
|
// init
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,false) && n.stencil && n.stencil(stencilRef,newPos,newScale) )
|
mesh.portal.setStencil(stencilRef)
|
||||||
renderer.autoClear = false
|
renderer.autoClear = false
|
||||||
renderer.autoClearDepth = false
|
renderer.autoClearDepth = false
|
||||||
renderer.autoClearColor = false
|
renderer.autoClearColor = false
|
||||||
|
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
renderer.autoClearDepth = true
|
renderer.autoClearDepth = true
|
||||||
renderer.autoClearColor = true
|
renderer.autoClearColor = true
|
||||||
renderer.autoClearStencil = true
|
renderer.autoClearStencil = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,true) && n.stencil && (n.stencil(0)) )
|
mesh.portal.setStencil(0)
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
}
|
}
|
||||||
mesh.portal.needUpdate = false
|
mesh.portal.needUpdate = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.setupListeners()
|
.setupListeners()
|
||||||
.setupStencilObjects(scene,opts)
|
.setupStencilObjects(scene,opts)
|
||||||
|
|
||||||
|
// move portal objects to portalposition
|
||||||
|
if( mesh.portal.stencilObjects ) mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
||||||
|
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
||||||
|
|
||||||
xrf.addEventListener('parseModel',(opts) => {
|
xrf.addEventListener('parseModel',(opts) => {
|
||||||
const scene = opts.model.scene
|
const scene = opts.model.scene
|
||||||
// scene.traverse( (n) => n.renderOrder = 10 ) // rendering everything *after* the stencil buffers
|
//for( let i in scene.children ) scene.children[i].renderOrder = 10 // render outer layers last (worldspheres e.g.)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// (re)set portalObjects when entering/leaving a portal
|
||||||
|
let updatePortals = (opts) => {
|
||||||
|
xrf.scene.traverse( (n) => {
|
||||||
|
if( !n.portal ) return
|
||||||
|
// move objects back to the portal
|
||||||
|
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
|
||||||
|
n.portal.isInside = false
|
||||||
|
})
|
||||||
|
if( opts.mesh && opts.mesh.portal && opts.click ){
|
||||||
|
opts.mesh.portal.isInside = true
|
||||||
|
opts.mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are teleporting there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('href', (opts) => opts.click && updatePortals(opts) )
|
||||||
|
xrf.addEventListener('navigate', updatePortals )
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef = 1
|
xrf.portalNonEuclidian.stencilRef = 1
|
||||||
|
|
||||||
let loadVideo = (mimetype) => function(url,opts){
|
let loadVideo = (mimetype) => function(url,opts){
|
||||||
|
|
@ -2335,9 +2337,20 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
// *TODO* this does not really belong here perhaps
|
// *TODO* this does not really belong here perhaps
|
||||||
let blinkControls = document.querySelector('[blink-controls]')
|
let blinkControls = document.querySelector('[blink-controls]')
|
||||||
if( blinkControls ){
|
if( blinkControls ){
|
||||||
blinkControls = blinkControls.components['blink-controls']
|
let els = xrf.getCollisionMeshes()
|
||||||
blinkControls.defaultCollisionMeshes = xrf.getCollisionMeshes()
|
let invisible = false
|
||||||
blinkControls.update()
|
els.map( (mesh) => {
|
||||||
|
if( !invisible ){
|
||||||
|
invisible = mesh.material.clone()
|
||||||
|
invisible.visible = false
|
||||||
|
}
|
||||||
|
mesh.material = invisible
|
||||||
|
let el = document.createElement("a-entity")
|
||||||
|
el.setAttribute("xrf-get", mesh.name )
|
||||||
|
el.setAttribute("class","floor")
|
||||||
|
$('a-scene').appendChild(el)
|
||||||
|
})
|
||||||
|
blinkControls.components['blink-controls'].update({collisionEntities:true})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -2420,13 +2433,6 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
els.map( (el) => document.querySelector('a-scene').removeChild(el) )
|
els.map( (el) => document.querySelector('a-scene').removeChild(el) )
|
||||||
})
|
})
|
||||||
|
|
||||||
aScene.addEventListener('enter-vr', () => {
|
|
||||||
// undo lookup-control shenanigans (which blocks updating camerarig position in VR)
|
|
||||||
document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true
|
|
||||||
document.querySelector('[camera]').removeAttribute("look-controls")
|
|
||||||
document.querySelector('[camera]').removeAttribute("wasd-controls")
|
|
||||||
})
|
|
||||||
|
|
||||||
AFRAME.XRF.navigator.to(this.data)
|
AFRAME.XRF.navigator.to(this.data)
|
||||||
.then( (model) => {
|
.then( (model) => {
|
||||||
let gets = [ ...document.querySelectorAll('[xrf-get]') ]
|
let gets = [ ...document.querySelectorAll('[xrf-get]') ]
|
||||||
|
|
@ -2657,9 +2663,10 @@ window.AFRAME.registerComponent('xrf-get', {
|
||||||
|
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
|
|
||||||
if( !this.mesh && this.el.className == "ray" ){
|
if( !this.mesh ){
|
||||||
let scene = AFRAME.XRF.scene
|
let scene = AFRAME.XRF.scene
|
||||||
let mesh = this.mesh = scene.getObjectByName(meshname);
|
let mesh = this.mesh = scene.getObjectByName(meshname);
|
||||||
|
if( !this.el.className.match(/ray/) ) this.el.className += " ray"
|
||||||
if (!mesh){
|
if (!mesh){
|
||||||
console.error("mesh with name '"+meshname+"' not found in model")
|
console.error("mesh with name '"+meshname+"' not found in model")
|
||||||
return;
|
return;
|
||||||
|
|
@ -2684,12 +2691,12 @@ window.AFRAME.registerComponent('xrf-get', {
|
||||||
}
|
}
|
||||||
this.el.setObject3D('mesh',mesh)
|
this.el.setObject3D('mesh',mesh)
|
||||||
if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
|
if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
|
||||||
}
|
}else console.warn("xrf-get ignore: "+JSON.stringify(this.data))
|
||||||
},500)
|
}, evt && evt.timeout ? evt.timeout: 500)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.el.emit("update")
|
this.el.emit("update",{timeout:0})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
118002
dist/xrfragment.module.js
vendored
118002
dist/xrfragment.module.js
vendored
File diff suppressed because it is too large
Load diff
288
dist/xrfragment.three.js
vendored
288
dist/xrfragment.three.js
vendored
|
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
||||||
delete opts.promise
|
delete opts.promise
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('reset', () => {
|
||||||
|
// *TODO* do this nicely
|
||||||
|
// xrf._listeners['renderPost'] = []
|
||||||
|
// xrf._listeners['render'] = []
|
||||||
|
})
|
||||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||||
|
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
||||||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||||
xrf.add( xrf.interactive )
|
xrf.add( xrf.interactive )
|
||||||
xrf.layers = 0
|
xrf.layers = 0
|
||||||
|
|
||||||
|
// reset certain events
|
||||||
xrf.emit('reset',{})
|
xrf.emit('reset',{})
|
||||||
// remove mixers
|
// remove mixers
|
||||||
xrf.mixers.map( (m) => m.stop())
|
xrf.mixers.map( (m) => m.stop())
|
||||||
|
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
|
||||||
|
//if( !file.match(/\./) || file.match(/\.html/) ){
|
||||||
|
// debugger
|
||||||
|
// let inIframe
|
||||||
|
// try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
|
||||||
|
// return inIframe ? window.parent.postMessage({ url: v.string }, '*') : window.open( v.string, '_blank')
|
||||||
|
//}
|
||||||
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
||||||
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||||
// always commit current location (keep a trail of last positions before we navigate)
|
// always commit current location (keep a trail of last positions before we navigate)
|
||||||
|
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
||||||
let url = v.string
|
let url = 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)
|
||||||
|
|
||||||
if( opts.isLocal ){
|
if( opts.isLocal ){
|
||||||
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
||||||
|
|
@ -1187,22 +1203,21 @@ xrf.frag.src = function(v, opts){
|
||||||
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
let {mesh} = opts
|
let {mesh} = opts
|
||||||
let scene = model.scene
|
let scene = model.scene
|
||||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||||
//enableSourcePortation(scene)
|
//enableSourcePortation(scene)
|
||||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||||
// only add remote objects, because
|
// only add remote objects, because
|
||||||
// local scene-objects are already added to scene
|
// local scene-objects are already added to scene
|
||||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||||
return
|
|
||||||
}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})
|
||||||
}
|
}
|
||||||
// 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 })
|
||||||
xrf.emit('parseModel', {...opts, scene, model})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||||
|
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||||
let {model,scene} = opts
|
let {model,mesh,scene} = opts
|
||||||
let _model = {
|
setTimeout( () => {
|
||||||
animations: model.animations,
|
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||||
scene: scene.clone()
|
let _model = {
|
||||||
}
|
animations: model.animations,
|
||||||
_model.scenes = [_model.scene]
|
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
}
|
||||||
|
_model.scenes = [_model.scene]
|
||||||
|
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||||
|
},500 )
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
||||||
|
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
||||||
xrf.frag.src.filterScene = (scene,opts) => {
|
xrf.frag.src.filterScene = (scene,opts) => {
|
||||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||||
|
|
||||||
xrf.filter.scene({scene,frag,reparent:true})
|
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||||
|
|
||||||
scene.traverse( (m) => {
|
if( !opts.isLocal ){
|
||||||
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
scene.traverse( (m) => {
|
||||||
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
||||||
})
|
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
||||||
|
})
|
||||||
|
}
|
||||||
return scene
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
||||||
xrf.filter.scene = function(opts){
|
xrf.filter.scene = function(opts){
|
||||||
let {scene,frag} = opts
|
let {scene,frag} = opts
|
||||||
|
|
||||||
xrf.filter
|
scene = xrf.filter
|
||||||
.sort(frag) // get (sorted) filters from XR Fragments
|
.sort(frag) // get (sorted) filters from XR Fragments
|
||||||
.process(frag,scene,opts) // show/hide things
|
.process(frag,scene,opts) // show/hide things
|
||||||
|
|
||||||
|
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
||||||
return xrf.filter
|
return xrf.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opts = {copyScene:true} in case you want a copy of the scene (not filter the current scene inplace)
|
||||||
xrf.filter.process = function(frag,scene,opts){
|
xrf.filter.process = function(frag,scene,opts){
|
||||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||||
const hasName = (m,name,filter) => m.name == name
|
const hasName = (m,name,filter) => m.name == name
|
||||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
const getOrCloneMaterial = (o) => {
|
const getOrCloneMaterial = (o) => {
|
||||||
if( o.material ){
|
if( o.material ){
|
||||||
|
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
let obj
|
let obj
|
||||||
frag.target = firstFilter
|
frag.target = firstFilter
|
||||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||||
if(obj){
|
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
if(obj ){
|
||||||
obj.position.set(0,0,0)
|
obj.position.set(0,0,0)
|
||||||
scene.add( obj )
|
if( opts.copyScene ){
|
||||||
|
opts.copyScene = new xrf.THREE.Scene()
|
||||||
|
opts.copyScene.children[0] = obj
|
||||||
|
scene = opts.copyScene
|
||||||
|
}else{
|
||||||
|
// empty current scene and add obj
|
||||||
|
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||||
|
scene.add( obj )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,7 +1750,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
// hide external objects temporarely
|
// hide external objects temporarely
|
||||||
scene.traverse( (m) => {
|
scene.traverse( (m) => {
|
||||||
if( m.isSRCExternal ){
|
if( m.isSRCExternal ){
|
||||||
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (n.visible = false) )
|
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (m.visible = false) )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1740,7 +1770,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
for ( let i in extembeds ) extembeds[i].visible = true
|
for ( let i in extembeds ) extembeds[i].visible = true
|
||||||
})
|
})
|
||||||
|
|
||||||
return xrf.filter
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||||
|
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
let frag = xrf.URI.parse( url )
|
let frag = xrf.URI.parse( url )
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
/* WebAudio: setup context via THREEjs */
|
/* WebAudio: setup context via THREEjs */
|
||||||
if( !camera.listener ){
|
if( !camera.listener ){
|
||||||
camera.listener = new THREE.AudioListener();
|
camera.listener = new THREE.AudioListener();
|
||||||
// *FIXME* camera vs camerarig conflict
|
// *FIXME* camera vs camerarig conflict
|
||||||
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
||||||
|
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}
|
}
|
||||||
|
|
||||||
sound.playXRF = (t) => {
|
sound.playXRF = (t) => {
|
||||||
|
mesh.add(sound)
|
||||||
|
try{
|
||||||
|
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
||||||
|
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||||
|
|
||||||
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
let hardcodedLoop = frag.t != undefined
|
||||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
||||||
|
if( t && t.x != 0 ){
|
||||||
|
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
||||||
|
t.x = Math.abs(t.x)
|
||||||
|
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
||||||
|
// setting loop
|
||||||
|
if( t.z ) sound.setLoop( true )
|
||||||
|
// apply embedded audio/video samplerate/fps or global mixer fps
|
||||||
|
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
||||||
|
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
||||||
|
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
||||||
|
|
||||||
let hardcodedLoop = frag.t != undefined
|
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||||
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
if( t.y != undefined ){
|
||||||
if( t && t.x != 0 ){
|
sound.setLoopStart( loopStart )
|
||||||
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
sound.offset = loopStart
|
||||||
t.x = Math.abs(t.x)
|
}
|
||||||
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
sound.play()
|
||||||
// setting loop
|
|
||||||
if( t.z ) sound.setLoop( true )
|
|
||||||
// apply embedded audio/video samplerate/fps or global mixer fps
|
|
||||||
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
|
||||||
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
|
||||||
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
|
||||||
|
|
||||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
|
||||||
if( t.y != undefined ){
|
|
||||||
sound.setLoopStart( loopStart )
|
|
||||||
sound.offset = loopStart
|
|
||||||
}
|
}
|
||||||
sound.play()
|
}catch(e){ console.warn(e) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mesh.add(sound)
|
mesh.audio = sound
|
||||||
});
|
});
|
||||||
|
|
||||||
mesh.audio = sound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let audioMimeTypes = [
|
let audioMimeTypes = [
|
||||||
|
|
@ -1968,6 +1996,18 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let loadHTML = (mimetype) => function(url,opts){
|
||||||
|
let {mesh,src,camera} = opts
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
|
let frag = xrf.URI.parse( url )
|
||||||
|
console.warn("todo: html viewer for src not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlMimeTypes = [
|
||||||
|
'text/html'
|
||||||
|
]
|
||||||
|
htmlMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadHTML(mimetype) )
|
||||||
/*
|
/*
|
||||||
* mimetype: image/png
|
* mimetype: image/png
|
||||||
* mimetype: image/jpg
|
* mimetype: image/jpg
|
||||||
|
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
let {mesh,THREE} = opts
|
let {mesh,THREE} = opts
|
||||||
let restrictTo3DBoundingBox = mesh.geometry
|
let restrictTo3DBoundingBox = mesh.geometry
|
||||||
|
|
||||||
let renderEquirect = (texture) => {
|
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
map: null,
|
||||||
texture.needsUpdate = true
|
transparent: url.match(/(png|gif)/) ? true : false,
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
side: THREE.DoubleSide,
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
color: 0xFFFFFF,
|
||||||
texture.magFilter = THREE.NearestFilter
|
opacity:1
|
||||||
texture.minFilter = THREE.NearestFilter
|
});
|
||||||
|
|
||||||
// poor man's equi-portal
|
|
||||||
mesh.material = new THREE.ShaderMaterial( {
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
uniforms: {
|
|
||||||
pano: { value: texture },
|
|
||||||
selected: { value: false },
|
|
||||||
},
|
|
||||||
vertexShader: `
|
|
||||||
vec3 portalPosition;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
void main() {
|
|
||||||
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
|
|
||||||
portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
vDistance = length(portalPosition - cameraPosition);
|
|
||||||
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
fragmentShader: `
|
|
||||||
#define RECIPROCAL_PI2 0.15915494
|
|
||||||
uniform sampler2D pano;
|
|
||||||
uniform bool selected;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
void main() {
|
|
||||||
vec3 direction = normalize(vWorldPosition - cameraPosition );
|
|
||||||
vec2 sampleUV;
|
|
||||||
sampleUV.y = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
|
|
||||||
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2;
|
|
||||||
sampleUV.x += 0.33; // adjust focus to AFRAME's a-scene.components.screenshot.capture()
|
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
|
||||||
vec4 selected_color = selected ? color*vec4(1.5) : color;
|
|
||||||
gl_FragColor = selected_color;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
mesh.material.needsUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderImage = (texture) => {
|
let renderImage = (texture) => {
|
||||||
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
||||||
|
|
@ -2042,26 +2040,15 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const geometry = new THREE.BoxGeometry();
|
mesh.material.map = texture
|
||||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
mesh.needsUpdate = true
|
||||||
map: texture,
|
|
||||||
transparent: url.match(/(png|gif)/) ? true : false,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
color: 0xFFFFFF,
|
|
||||||
opacity:1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLoad = (texture) => {
|
let onLoad = (texture) => {
|
||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
texture.wrapS = THREE.RepeatWrapping;
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
texture.wrapT = THREE.RepeatWrapping;
|
||||||
// detect equirectangular image
|
renderImage(texture)
|
||||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
|
||||||
renderEquirect(texture)
|
|
||||||
}else{
|
|
||||||
renderImage(texture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
||||||
|
|
@ -2076,6 +2063,7 @@ xrf.frag.src.type['image/jpeg'] = xrf.frag.src.type['image/png']
|
||||||
xrf.portalNonEuclidian = function(opts){
|
xrf.portalNonEuclidian = function(opts){
|
||||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||||
|
|
||||||
|
|
||||||
mesh.portal = {
|
mesh.portal = {
|
||||||
pos: mesh.position.clone(),
|
pos: mesh.position.clone(),
|
||||||
posWorld: new xrf.THREE.Vector3(),
|
posWorld: new xrf.THREE.Vector3(),
|
||||||
|
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
cameraPosition: new THREE.Vector3(),
|
cameraPosition: new THREE.Vector3(),
|
||||||
raycaster: new THREE.Raycaster(),
|
raycaster: new THREE.Raycaster(),
|
||||||
isLocal: opts.isLocal,
|
isLocal: opts.isLocal,
|
||||||
isLens: false
|
isLens: false,
|
||||||
|
isInside: false,
|
||||||
|
setStencil: (stencilRef) => mesh.portal.stencilObjects.traverse( (n) => showPortal(n, stencilRef == 0) && n.stencil && n.stencil(stencilRef) ),
|
||||||
|
positionObjectsIfNeeded: (pos,scale) => !mesh.portal.isLens && mesh.portal.stencilObjects.traverse( (n) => n.positionAtStencil && (n.positionAtStencil(pos,scale)) )
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
||||||
const addStencilFeature = (n) => {
|
const addStencilFeature = (n) => {
|
||||||
if( n.stencil ) return n // run once
|
if( n.stencil ) return n // run once
|
||||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
|
||||||
if( !mesh.portal.isLens ){
|
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||||
n.position.copy( sRef == 0 ? pos : newPos )
|
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
n.position.copy( newPos || pos )
|
||||||
else n.scale.copy( scale )
|
n.scale.copy( scale )
|
||||||
n.updateMatrixWorld(true)
|
n.updateMatrixWorld(true)
|
||||||
}
|
}
|
||||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
// curry function
|
||||||
}
|
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||||
)( n.position.clone(), n.scale.clone() )
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||||
.map(addStencilFeature)
|
.map(addStencilFeature)
|
||||||
|
|
||||||
//// add missing lights to make sure things get lit properly
|
|
||||||
xrf.scene.traverse( (n) => n.isLight &&
|
|
||||||
!stencilObjects.find( (o) => o.uuid == n.uuid ) &&
|
|
||||||
stencilObjects.push(n)
|
|
||||||
)
|
|
||||||
|
|
||||||
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
||||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||||
mesh.portal.stencilObjects.children = stencilObjects
|
mesh.portal.stencilObjects.children = stencilObjects
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||||
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
||||||
|
|
||||||
// clone so it won't be affected by other fragments
|
|
||||||
setTimeout( (mesh) => {
|
|
||||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
|
||||||
}, 0, mesh )
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
xrf.addEventListener('renderPost', (opts) => {
|
xrf.addEventListener('renderPost', (opts) => {
|
||||||
let {scene,camera,time,render,renderer} = opts
|
let {scene,camera,time,render,renderer} = opts
|
||||||
|
|
||||||
if( mesh.portal && mesh.portal.stencilObjects ){
|
if( mesh.portal.needUpdate && mesh.portal && mesh.portal.stencilObjects ){
|
||||||
|
let cameraDirection = mesh.portal.cameraDirection
|
||||||
|
let cameraPosition = mesh.portal.cameraPosition
|
||||||
let stencilRef = mesh.portal.stencilRef
|
let stencilRef = mesh.portal.stencilRef
|
||||||
let newPos = mesh.portal.posWorld
|
let newPos = mesh.portal.posWorld
|
||||||
let stencilObject = mesh.portal.stencilObject
|
let stencilObject = mesh.portal.stencilObject
|
||||||
let newScale = mesh.scale
|
let newScale = mesh.scale
|
||||||
let cameraDirection = mesh.portal.cameraDirection
|
|
||||||
let cameraPosition = mesh.portal.cameraPosition
|
|
||||||
let raycaster = mesh.portal.raycaster
|
let raycaster = mesh.portal.raycaster
|
||||||
|
|
||||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||||
cam.getWorldPosition(cameraPosition)
|
cam.getWorldPosition(cameraPosition)
|
||||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
|
||||||
cam.getWorldDirection(cameraDirection)
|
cam.getWorldDirection(cameraDirection)
|
||||||
|
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||||
|
|
||||||
// init
|
// init
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,false) && n.stencil && n.stencil(stencilRef,newPos,newScale) )
|
mesh.portal.setStencil(stencilRef)
|
||||||
renderer.autoClear = false
|
renderer.autoClear = false
|
||||||
renderer.autoClearDepth = false
|
renderer.autoClearDepth = false
|
||||||
renderer.autoClearColor = false
|
renderer.autoClearColor = false
|
||||||
|
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
renderer.autoClearDepth = true
|
renderer.autoClearDepth = true
|
||||||
renderer.autoClearColor = true
|
renderer.autoClearColor = true
|
||||||
renderer.autoClearStencil = true
|
renderer.autoClearStencil = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,true) && n.stencil && (n.stencil(0)) )
|
mesh.portal.setStencil(0)
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
}
|
}
|
||||||
mesh.portal.needUpdate = false
|
mesh.portal.needUpdate = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.setupListeners()
|
.setupListeners()
|
||||||
.setupStencilObjects(scene,opts)
|
.setupStencilObjects(scene,opts)
|
||||||
|
|
||||||
|
// move portal objects to portalposition
|
||||||
|
if( mesh.portal.stencilObjects ) mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
||||||
|
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
||||||
|
|
||||||
xrf.addEventListener('parseModel',(opts) => {
|
xrf.addEventListener('parseModel',(opts) => {
|
||||||
const scene = opts.model.scene
|
const scene = opts.model.scene
|
||||||
// scene.traverse( (n) => n.renderOrder = 10 ) // rendering everything *after* the stencil buffers
|
//for( let i in scene.children ) scene.children[i].renderOrder = 10 // render outer layers last (worldspheres e.g.)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// (re)set portalObjects when entering/leaving a portal
|
||||||
|
let updatePortals = (opts) => {
|
||||||
|
xrf.scene.traverse( (n) => {
|
||||||
|
if( !n.portal ) return
|
||||||
|
// move objects back to the portal
|
||||||
|
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
|
||||||
|
n.portal.isInside = false
|
||||||
|
})
|
||||||
|
if( opts.mesh && opts.mesh.portal && opts.click ){
|
||||||
|
opts.mesh.portal.isInside = true
|
||||||
|
opts.mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are teleporting there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('href', (opts) => opts.click && updatePortals(opts) )
|
||||||
|
xrf.addEventListener('navigate', updatePortals )
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef = 1
|
xrf.portalNonEuclidian.stencilRef = 1
|
||||||
|
|
||||||
let loadVideo = (mimetype) => function(url,opts){
|
let loadVideo = (mimetype) => function(url,opts){
|
||||||
|
|
|
||||||
288
dist/xrfragment.three.module.js
vendored
288
dist/xrfragment.three.module.js
vendored
|
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
||||||
delete opts.promise
|
delete opts.promise
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('reset', () => {
|
||||||
|
// *TODO* do this nicely
|
||||||
|
// xrf._listeners['renderPost'] = []
|
||||||
|
// xrf._listeners['render'] = []
|
||||||
|
})
|
||||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||||
|
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
||||||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||||
xrf.add( xrf.interactive )
|
xrf.add( xrf.interactive )
|
||||||
xrf.layers = 0
|
xrf.layers = 0
|
||||||
|
|
||||||
|
// reset certain events
|
||||||
xrf.emit('reset',{})
|
xrf.emit('reset',{})
|
||||||
// remove mixers
|
// remove mixers
|
||||||
xrf.mixers.map( (m) => m.stop())
|
xrf.mixers.map( (m) => m.stop())
|
||||||
|
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
|
||||||
|
//if( !file.match(/\./) || file.match(/\.html/) ){
|
||||||
|
// debugger
|
||||||
|
// let inIframe
|
||||||
|
// try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
|
||||||
|
// return inIframe ? window.parent.postMessage({ url: v.string }, '*') : window.open( v.string, '_blank')
|
||||||
|
//}
|
||||||
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
||||||
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||||
// always commit current location (keep a trail of last positions before we navigate)
|
// always commit current location (keep a trail of last positions before we navigate)
|
||||||
|
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
||||||
let url = v.string
|
let url = 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)
|
||||||
|
|
||||||
if( opts.isLocal ){
|
if( opts.isLocal ){
|
||||||
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
||||||
|
|
@ -1187,22 +1203,21 @@ xrf.frag.src = function(v, opts){
|
||||||
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
let {mesh} = opts
|
let {mesh} = opts
|
||||||
let scene = model.scene
|
let scene = model.scene
|
||||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||||
//enableSourcePortation(scene)
|
//enableSourcePortation(scene)
|
||||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||||
// only add remote objects, because
|
// only add remote objects, because
|
||||||
// local scene-objects are already added to scene
|
// local scene-objects are already added to scene
|
||||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||||
return
|
|
||||||
}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})
|
||||||
}
|
}
|
||||||
// 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 })
|
||||||
xrf.emit('parseModel', {...opts, scene, model})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||||
|
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||||
let {model,scene} = opts
|
let {model,mesh,scene} = opts
|
||||||
let _model = {
|
setTimeout( () => {
|
||||||
animations: model.animations,
|
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||||
scene: scene.clone()
|
let _model = {
|
||||||
}
|
animations: model.animations,
|
||||||
_model.scenes = [_model.scene]
|
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
}
|
||||||
|
_model.scenes = [_model.scene]
|
||||||
|
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||||
|
},500 )
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
||||||
|
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
||||||
xrf.frag.src.filterScene = (scene,opts) => {
|
xrf.frag.src.filterScene = (scene,opts) => {
|
||||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||||
|
|
||||||
xrf.filter.scene({scene,frag,reparent:true})
|
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||||
|
|
||||||
scene.traverse( (m) => {
|
if( !opts.isLocal ){
|
||||||
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
scene.traverse( (m) => {
|
||||||
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
||||||
})
|
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
||||||
|
})
|
||||||
|
}
|
||||||
return scene
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
||||||
xrf.filter.scene = function(opts){
|
xrf.filter.scene = function(opts){
|
||||||
let {scene,frag} = opts
|
let {scene,frag} = opts
|
||||||
|
|
||||||
xrf.filter
|
scene = xrf.filter
|
||||||
.sort(frag) // get (sorted) filters from XR Fragments
|
.sort(frag) // get (sorted) filters from XR Fragments
|
||||||
.process(frag,scene,opts) // show/hide things
|
.process(frag,scene,opts) // show/hide things
|
||||||
|
|
||||||
|
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
||||||
return xrf.filter
|
return xrf.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opts = {copyScene:true} in case you want a copy of the scene (not filter the current scene inplace)
|
||||||
xrf.filter.process = function(frag,scene,opts){
|
xrf.filter.process = function(frag,scene,opts){
|
||||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||||
const hasName = (m,name,filter) => m.name == name
|
const hasName = (m,name,filter) => m.name == name
|
||||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
const getOrCloneMaterial = (o) => {
|
const getOrCloneMaterial = (o) => {
|
||||||
if( o.material ){
|
if( o.material ){
|
||||||
|
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
let obj
|
let obj
|
||||||
frag.target = firstFilter
|
frag.target = firstFilter
|
||||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||||
if(obj){
|
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
if(obj ){
|
||||||
obj.position.set(0,0,0)
|
obj.position.set(0,0,0)
|
||||||
scene.add( obj )
|
if( opts.copyScene ){
|
||||||
|
opts.copyScene = new xrf.THREE.Scene()
|
||||||
|
opts.copyScene.children[0] = obj
|
||||||
|
scene = opts.copyScene
|
||||||
|
}else{
|
||||||
|
// empty current scene and add obj
|
||||||
|
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||||
|
scene.add( obj )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,7 +1750,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
// hide external objects temporarely
|
// hide external objects temporarely
|
||||||
scene.traverse( (m) => {
|
scene.traverse( (m) => {
|
||||||
if( m.isSRCExternal ){
|
if( m.isSRCExternal ){
|
||||||
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (n.visible = false) )
|
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (m.visible = false) )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1740,7 +1770,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
for ( let i in extembeds ) extembeds[i].visible = true
|
for ( let i in extembeds ) extembeds[i].visible = true
|
||||||
})
|
})
|
||||||
|
|
||||||
return xrf.filter
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||||
|
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
let frag = xrf.URI.parse( url )
|
let frag = xrf.URI.parse( url )
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
/* WebAudio: setup context via THREEjs */
|
/* WebAudio: setup context via THREEjs */
|
||||||
if( !camera.listener ){
|
if( !camera.listener ){
|
||||||
camera.listener = new THREE.AudioListener();
|
camera.listener = new THREE.AudioListener();
|
||||||
// *FIXME* camera vs camerarig conflict
|
// *FIXME* camera vs camerarig conflict
|
||||||
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
|
||||||
|
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}
|
}
|
||||||
|
|
||||||
sound.playXRF = (t) => {
|
sound.playXRF = (t) => {
|
||||||
|
mesh.add(sound)
|
||||||
|
try{
|
||||||
|
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
||||||
|
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||||
|
|
||||||
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
let hardcodedLoop = frag.t != undefined
|
||||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
||||||
|
if( t && t.x != 0 ){
|
||||||
|
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
||||||
|
t.x = Math.abs(t.x)
|
||||||
|
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
||||||
|
// setting loop
|
||||||
|
if( t.z ) sound.setLoop( true )
|
||||||
|
// apply embedded audio/video samplerate/fps or global mixer fps
|
||||||
|
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
||||||
|
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
||||||
|
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
||||||
|
|
||||||
let hardcodedLoop = frag.t != undefined
|
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||||
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
|
if( t.y != undefined ){
|
||||||
if( t && t.x != 0 ){
|
sound.setLoopStart( loopStart )
|
||||||
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
|
sound.offset = loopStart
|
||||||
t.x = Math.abs(t.x)
|
}
|
||||||
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
|
sound.play()
|
||||||
// setting loop
|
|
||||||
if( t.z ) sound.setLoop( true )
|
|
||||||
// apply embedded audio/video samplerate/fps or global mixer fps
|
|
||||||
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
|
|
||||||
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
|
|
||||||
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
|
|
||||||
|
|
||||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
|
||||||
if( t.y != undefined ){
|
|
||||||
sound.setLoopStart( loopStart )
|
|
||||||
sound.offset = loopStart
|
|
||||||
}
|
}
|
||||||
sound.play()
|
}catch(e){ console.warn(e) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mesh.add(sound)
|
mesh.audio = sound
|
||||||
});
|
});
|
||||||
|
|
||||||
mesh.audio = sound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let audioMimeTypes = [
|
let audioMimeTypes = [
|
||||||
|
|
@ -1968,6 +1996,18 @@ xrf.frag.src.type['gltf'] = function( url, opts ){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let loadHTML = (mimetype) => function(url,opts){
|
||||||
|
let {mesh,src,camera} = opts
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
|
let frag = xrf.URI.parse( url )
|
||||||
|
console.warn("todo: html viewer for src not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlMimeTypes = [
|
||||||
|
'text/html'
|
||||||
|
]
|
||||||
|
htmlMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadHTML(mimetype) )
|
||||||
/*
|
/*
|
||||||
* mimetype: image/png
|
* mimetype: image/png
|
||||||
* mimetype: image/jpg
|
* mimetype: image/jpg
|
||||||
|
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
let {mesh,THREE} = opts
|
let {mesh,THREE} = opts
|
||||||
let restrictTo3DBoundingBox = mesh.geometry
|
let restrictTo3DBoundingBox = mesh.geometry
|
||||||
|
|
||||||
let renderEquirect = (texture) => {
|
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
map: null,
|
||||||
texture.needsUpdate = true
|
transparent: url.match(/(png|gif)/) ? true : false,
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
side: THREE.DoubleSide,
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
color: 0xFFFFFF,
|
||||||
texture.magFilter = THREE.NearestFilter
|
opacity:1
|
||||||
texture.minFilter = THREE.NearestFilter
|
});
|
||||||
|
|
||||||
// poor man's equi-portal
|
|
||||||
mesh.material = new THREE.ShaderMaterial( {
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
uniforms: {
|
|
||||||
pano: { value: texture },
|
|
||||||
selected: { value: false },
|
|
||||||
},
|
|
||||||
vertexShader: `
|
|
||||||
vec3 portalPosition;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
void main() {
|
|
||||||
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
|
|
||||||
portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
vDistance = length(portalPosition - cameraPosition);
|
|
||||||
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
fragmentShader: `
|
|
||||||
#define RECIPROCAL_PI2 0.15915494
|
|
||||||
uniform sampler2D pano;
|
|
||||||
uniform bool selected;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
void main() {
|
|
||||||
vec3 direction = normalize(vWorldPosition - cameraPosition );
|
|
||||||
vec2 sampleUV;
|
|
||||||
sampleUV.y = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
|
|
||||||
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2;
|
|
||||||
sampleUV.x += 0.33; // adjust focus to AFRAME's a-scene.components.screenshot.capture()
|
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
|
||||||
vec4 selected_color = selected ? color*vec4(1.5) : color;
|
|
||||||
gl_FragColor = selected_color;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
mesh.material.needsUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderImage = (texture) => {
|
let renderImage = (texture) => {
|
||||||
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
||||||
|
|
@ -2042,26 +2040,15 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const geometry = new THREE.BoxGeometry();
|
mesh.material.map = texture
|
||||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
mesh.needsUpdate = true
|
||||||
map: texture,
|
|
||||||
transparent: url.match(/(png|gif)/) ? true : false,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
color: 0xFFFFFF,
|
|
||||||
opacity:1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLoad = (texture) => {
|
let onLoad = (texture) => {
|
||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
texture.wrapS = THREE.RepeatWrapping;
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
texture.wrapT = THREE.RepeatWrapping;
|
||||||
// detect equirectangular image
|
renderImage(texture)
|
||||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
|
||||||
renderEquirect(texture)
|
|
||||||
}else{
|
|
||||||
renderImage(texture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
||||||
|
|
@ -2076,6 +2063,7 @@ xrf.frag.src.type['image/jpeg'] = xrf.frag.src.type['image/png']
|
||||||
xrf.portalNonEuclidian = function(opts){
|
xrf.portalNonEuclidian = function(opts){
|
||||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||||
|
|
||||||
|
|
||||||
mesh.portal = {
|
mesh.portal = {
|
||||||
pos: mesh.position.clone(),
|
pos: mesh.position.clone(),
|
||||||
posWorld: new xrf.THREE.Vector3(),
|
posWorld: new xrf.THREE.Vector3(),
|
||||||
|
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
cameraPosition: new THREE.Vector3(),
|
cameraPosition: new THREE.Vector3(),
|
||||||
raycaster: new THREE.Raycaster(),
|
raycaster: new THREE.Raycaster(),
|
||||||
isLocal: opts.isLocal,
|
isLocal: opts.isLocal,
|
||||||
isLens: false
|
isLens: false,
|
||||||
|
isInside: false,
|
||||||
|
setStencil: (stencilRef) => mesh.portal.stencilObjects.traverse( (n) => showPortal(n, stencilRef == 0) && n.stencil && n.stencil(stencilRef) ),
|
||||||
|
positionObjectsIfNeeded: (pos,scale) => !mesh.portal.isLens && mesh.portal.stencilObjects.traverse( (n) => n.positionAtStencil && (n.positionAtStencil(pos,scale)) )
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
|
||||||
const addStencilFeature = (n) => {
|
const addStencilFeature = (n) => {
|
||||||
if( n.stencil ) return n // run once
|
if( n.stencil ) return n // run once
|
||||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
|
||||||
if( !mesh.portal.isLens ){
|
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||||
n.position.copy( sRef == 0 ? pos : newPos )
|
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
n.position.copy( newPos || pos )
|
||||||
else n.scale.copy( scale )
|
n.scale.copy( scale )
|
||||||
n.updateMatrixWorld(true)
|
n.updateMatrixWorld(true)
|
||||||
}
|
}
|
||||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
// curry function
|
||||||
}
|
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||||
)( n.position.clone(), n.scale.clone() )
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||||
.map(addStencilFeature)
|
.map(addStencilFeature)
|
||||||
|
|
||||||
//// add missing lights to make sure things get lit properly
|
|
||||||
xrf.scene.traverse( (n) => n.isLight &&
|
|
||||||
!stencilObjects.find( (o) => o.uuid == n.uuid ) &&
|
|
||||||
stencilObjects.push(n)
|
|
||||||
)
|
|
||||||
|
|
||||||
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
||||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||||
mesh.portal.stencilObjects.children = stencilObjects
|
mesh.portal.stencilObjects.children = stencilObjects
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||||
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
||||||
|
|
||||||
// clone so it won't be affected by other fragments
|
|
||||||
setTimeout( (mesh) => {
|
|
||||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
|
||||||
}, 0, mesh )
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
xrf.addEventListener('renderPost', (opts) => {
|
xrf.addEventListener('renderPost', (opts) => {
|
||||||
let {scene,camera,time,render,renderer} = opts
|
let {scene,camera,time,render,renderer} = opts
|
||||||
|
|
||||||
if( mesh.portal && mesh.portal.stencilObjects ){
|
if( mesh.portal.needUpdate && mesh.portal && mesh.portal.stencilObjects ){
|
||||||
|
let cameraDirection = mesh.portal.cameraDirection
|
||||||
|
let cameraPosition = mesh.portal.cameraPosition
|
||||||
let stencilRef = mesh.portal.stencilRef
|
let stencilRef = mesh.portal.stencilRef
|
||||||
let newPos = mesh.portal.posWorld
|
let newPos = mesh.portal.posWorld
|
||||||
let stencilObject = mesh.portal.stencilObject
|
let stencilObject = mesh.portal.stencilObject
|
||||||
let newScale = mesh.scale
|
let newScale = mesh.scale
|
||||||
let cameraDirection = mesh.portal.cameraDirection
|
|
||||||
let cameraPosition = mesh.portal.cameraPosition
|
|
||||||
let raycaster = mesh.portal.raycaster
|
let raycaster = mesh.portal.raycaster
|
||||||
|
|
||||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||||
cam.getWorldPosition(cameraPosition)
|
cam.getWorldPosition(cameraPosition)
|
||||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
|
||||||
cam.getWorldDirection(cameraDirection)
|
cam.getWorldDirection(cameraDirection)
|
||||||
|
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||||
|
|
||||||
// init
|
// init
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,false) && n.stencil && n.stencil(stencilRef,newPos,newScale) )
|
mesh.portal.setStencil(stencilRef)
|
||||||
renderer.autoClear = false
|
renderer.autoClear = false
|
||||||
renderer.autoClearDepth = false
|
renderer.autoClearDepth = false
|
||||||
renderer.autoClearColor = false
|
renderer.autoClearColor = false
|
||||||
|
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
renderer.autoClearDepth = true
|
renderer.autoClearDepth = true
|
||||||
renderer.autoClearColor = true
|
renderer.autoClearColor = true
|
||||||
renderer.autoClearStencil = true
|
renderer.autoClearStencil = true
|
||||||
mesh.portal.stencilObjects.traverse( (n) => showPortal(n,true) && n.stencil && (n.stencil(0)) )
|
mesh.portal.setStencil(0)
|
||||||
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
}
|
}
|
||||||
mesh.portal.needUpdate = false
|
mesh.portal.needUpdate = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.setupListeners()
|
.setupListeners()
|
||||||
.setupStencilObjects(scene,opts)
|
.setupStencilObjects(scene,opts)
|
||||||
|
|
||||||
|
// move portal objects to portalposition
|
||||||
|
if( mesh.portal.stencilObjects ) mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
||||||
|
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
||||||
|
|
||||||
xrf.addEventListener('parseModel',(opts) => {
|
xrf.addEventListener('parseModel',(opts) => {
|
||||||
const scene = opts.model.scene
|
const scene = opts.model.scene
|
||||||
// scene.traverse( (n) => n.renderOrder = 10 ) // rendering everything *after* the stencil buffers
|
//for( let i in scene.children ) scene.children[i].renderOrder = 10 // render outer layers last (worldspheres e.g.)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// (re)set portalObjects when entering/leaving a portal
|
||||||
|
let updatePortals = (opts) => {
|
||||||
|
xrf.scene.traverse( (n) => {
|
||||||
|
if( !n.portal ) return
|
||||||
|
// move objects back to the portal
|
||||||
|
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
|
||||||
|
n.portal.isInside = false
|
||||||
|
})
|
||||||
|
if( opts.mesh && opts.mesh.portal && opts.click ){
|
||||||
|
opts.mesh.portal.isInside = true
|
||||||
|
opts.mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are teleporting there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('href', (opts) => opts.click && updatePortals(opts) )
|
||||||
|
xrf.addEventListener('navigate', updatePortals )
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef = 1
|
xrf.portalNonEuclidian.stencilRef = 1
|
||||||
|
|
||||||
let loadVideo = (mimetype) => function(url,opts){
|
let loadVideo = (mimetype) => function(url,opts){
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,13 @@
|
||||||
window.$ = (s) => document.querySelector(s)
|
window.$ = (s) => document.querySelector(s)
|
||||||
if( document.location.search.length > 2 )
|
if( document.location.search.length > 2 )
|
||||||
$('#home').setAttribute('xrf', document.location.search.substr(1)+document.location.hash )
|
$('#home').setAttribute('xrf', document.location.search.substr(1)+document.location.hash )
|
||||||
|
|
||||||
|
// allow iframe to open url
|
||||||
|
window.addEventListener('message', (event) => {
|
||||||
|
if (event.data && event.data.url) {
|
||||||
|
window.open(event.data.url, '_blank');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$('a-scene').addEventListener('XRF', () => {
|
$('a-scene').addEventListener('XRF', () => {
|
||||||
|
|
@ -58,7 +65,7 @@
|
||||||
|
|
||||||
// reroute console messages to snackbar notifications
|
// reroute console messages to snackbar notifications
|
||||||
console.log = ( (log) => function(str){
|
console.log = ( (log) => function(str){
|
||||||
if( String(str).match(/:.*#/) ) window.notify(str)
|
if( String(str).match(/(:.*#|note:)/) ) window.notify(str)
|
||||||
log(str)
|
log(str)
|
||||||
})(console.log)
|
})(console.log)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ input[type="submit"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
#overlay{
|
#overlay{
|
||||||
background: #FFF;
|
background: #FFFb;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -1 +0,0 @@
|
||||||
../dist
|
|
||||||
|
|
@ -72,6 +72,20 @@ Reflect.deleteField = function(o,field) {
|
||||||
delete(o[field]);
|
delete(o[field]);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
Reflect.copy = function(o) {
|
||||||
|
if(o == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var o2 = { };
|
||||||
|
var _g = 0;
|
||||||
|
var _g1 = Reflect.fields(o);
|
||||||
|
while(_g < _g1.length) {
|
||||||
|
var f = _g1[_g];
|
||||||
|
++_g;
|
||||||
|
o2[f] = Reflect.field(o,f);
|
||||||
|
}
|
||||||
|
return o2;
|
||||||
|
};
|
||||||
var Std = function() { };
|
var Std = function() { };
|
||||||
Std.__name__ = true;
|
Std.__name__ = true;
|
||||||
Std.string = function(s) {
|
Std.string = function(s) {
|
||||||
|
|
@ -133,40 +147,38 @@ StringTools.trim = function(s) {
|
||||||
var Test = function() { };
|
var Test = function() { };
|
||||||
Test.__name__ = true;
|
Test.__name__ = true;
|
||||||
Test.main = function() {
|
Test.main = function() {
|
||||||
Test.test("url.json",[{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : false}, label : "equal.xyz: should trigger incompatible type)", data : "http://foo.com?foo=1#pos=1.2,2.2"},{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : "1.2,2.2,3"}, label : "equal.xyz", data : "http://foo.com?foo=1#pos=1.2,2.2,3"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "q", out : false}, label : "browser URI cannot override q (defined in asset)", data : "http://foo.com?foo=1#q=-bar"},{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed", data : "http://foo.com?foo=1#mypredefinedview"},{ fn : "url", expect : { fn : "testPredefinedView", input : "another", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testParsed", input : "mycustom", out : true}, label : "test custom property", data : "http://foo.com?foo=1#mycustom=foo"}]);
|
Test.test("url.json",[{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed", data : "http://foo.com?foo=1#mypredefinedview"},{ fn : "url", expect : { fn : "testPredefinedView", input : "another", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testPredefinedView", input : "mypredefinedview", out : true}, label : "test predefined view executed (multiple)", data : "http://foo.com?foo=1#mypredefinedview&another"},{ fn : "url", expect : { fn : "testParsed", input : "mycustom", out : true}, label : "test custom property", data : "http://foo.com?foo=1#mycustom=foo"}]);
|
||||||
|
Test.test("pos.json",[{ fn : "url", expect : { fn : "equal.string", input : "pos", out : "1.2,2.2"}, label : "equal.string", data : "http://foo.com?foo=1#pos=1.2,2.2"},{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : "1.2,2.2,3"}, label : "equal.xyz", data : "http://foo.com?foo=1#pos=1.2,2.2,3"},{ fn : "url", expect : { fn : "equal.xyz", input : "pos", out : "1,2,3"}, label : "pos equal.xyz", data : "http://foo.com?foo=1#pos=1,2,3"},{ fn : "url", expect : { fn : "equal.string", input : "pos", out : "world2"}, label : "pos equal.xyz", data : "http://foo.com?foo=1#pos=world2"}]);
|
||||||
Test.test("t.json",[{ fn : "url", expect : { fn : "equal.x", input : "t", out : "1"}, label : "a equal.x", data : "http://foo.com?foo=1#t=1"},{ fn : "url", expect : { fn : "equal.x", input : "t", out : "-1"}, label : "a equal.x", data : "http://foo.com?foo=1#t=-1"},{ fn : "url", expect : { fn : "equal.x", input : "t", out : "-1.02"}, label : "a equal.x", data : "http://foo.com?foo=1#t=-1.02"},{ fn : "url", expect : { fn : "equal.xy", input : "t", out : "1,2"}, label : "a equal.xy", data : "http://foo.com?foo=1#t=1,2,3"},{ fn : "url", expect : { fn : "equal.xyz", input : "t", out : "1,2,3"}, label : "a equal.xyz", data : "http://foo.com?foo=1#t=1,2,3"},{ fn : "url", expect : { fn : "equal.xyz", input : "t", out : "1,-2,3"}, label : "a equal.xyz", data : "http://foo.com?foo=1#t=1,-2,3"},{ fn : "url", expect : { fn : "equal.xy", input : "t", out : "1,100"}, label : "a equal.xy", data : "http://foo.com?foo=1#t=1,100"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "t", out : true}, label : "browser URI can override t (defined in asset)", data : "http://foo.com?foo=1#t=2,500"}]);
|
Test.test("t.json",[{ fn : "url", expect : { fn : "equal.x", input : "t", out : "1"}, label : "a equal.x", data : "http://foo.com?foo=1#t=1"},{ fn : "url", expect : { fn : "equal.x", input : "t", out : "-1"}, label : "a equal.x", data : "http://foo.com?foo=1#t=-1"},{ fn : "url", expect : { fn : "equal.x", input : "t", out : "-1.02"}, label : "a equal.x", data : "http://foo.com?foo=1#t=-1.02"},{ fn : "url", expect : { fn : "equal.xy", input : "t", out : "1,2"}, label : "a equal.xy", data : "http://foo.com?foo=1#t=1,2,3"},{ fn : "url", expect : { fn : "equal.xyz", input : "t", out : "1,2,3"}, label : "a equal.xyz", data : "http://foo.com?foo=1#t=1,2,3"},{ fn : "url", expect : { fn : "equal.xyz", input : "t", out : "1,-2,3"}, label : "a equal.xyz", data : "http://foo.com?foo=1#t=1,-2,3"},{ fn : "url", expect : { fn : "equal.xy", input : "t", out : "1,100"}, label : "a equal.xy", data : "http://foo.com?foo=1#t=1,100"},{ fn : "url", expect : { fn : "testBrowserOverride", input : "t", out : true}, label : "browser URI can override t (defined in asset)", data : "http://foo.com?foo=1#t=2,500"}]);
|
||||||
Test.test("q.selectors.json",[{ fn : "query", expect : { fn : "testProperty", input : ["tag","bar"], out : true}, data : "tag:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "tag:bar -tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, data : "tag:bar -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","bar"], out : true}, data : "tag:bar -tag:bar tag:bar"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:>5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo bar:>5 tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, label : "tag:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo", data : "tag:foo -tag:foo tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["id","foo"], out : true}, label : "id:foo?", data : "tag:foo -foo foo"},{ fn : "query", expect : { fn : "testQueryRoot", input : ["foo"], out : true}, label : "foo should be root-only", data : "/foo"},{ fn : "query", expect : { fn : "testQueryRoot", input : ["foo"], out : false}, label : "foo should recursively selected", data : "/foo foo"}]);
|
Test.test("filter.selectors.json",[{ fn : "url", expect : { fn : "testParsed", input : "myid", out : true}, label : "myid exists", data : "http://foo.com?foo=1#foo*&-sometag&-someid&myid"},{ fn : "url", expect : { fn : "testParsed", input : "tag", out : true}, label : "tag exists", data : "http://foo.com?foo=1#tag=bar"},{ fn : "url", expect : { fn : "testParsed", input : "tag", out : true}, label : "tag exists", data : "http://foo.com?foo=1#-tag=bar"},{ fn : "url", expect : { fn : "testParsed", input : "price", out : true}, label : "filter test", data : "http://foo.com?foo=1#price=>2"},{ fn : "filter", expect : { fn : "testProperty", input : ["tag","bar"], out : true}, data : "tag=bar"},{ fn : "filter", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "-tag=foo"},{ fn : "filter", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "-tag*=foo"},{ fn : "filter", expect : { fn : "testProperty", input : ["tag","3"], out : false}, data : "-tag=>2"},{ fn : "filter", expect : { fn : "testProperty", input : ["price","1"], out : false}, data : "price=>2"},{ fn : "filter", expect : { fn : "testProperty", input : ["price","5"], out : false}, data : "price=<2"},{ fn : "filter", expect : { fn : "testProperty", input : ["price","1"], out : true}, data : "price=<2"},{ fn : "url", expect : { fn : "testFilterDeep", input : ["foo"], out : 1}, label : "foo should be deep", data : "#foo*"},{ fn : "url", expect : { fn : "testFilterDeep", input : ["foo"], out : 2}, label : "foo should be deep incl. embeds", data : "#foo**"}]);
|
||||||
Test.test("q.root.json",[]);
|
|
||||||
Test.test("q.rules.json",[{ fn : "query", expect : { fn : "testProperty", input : ["price","10"], out : true}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","10"], out : false}, data : "price:>=15"},{ fn : "query", expect : { fn : "testProperty", input : ["price","4"], out : false}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","0"], out : false}, data : "price:>=5"},{ fn : "query", expect : { fn : "testProperty", input : ["price","2"], out : true}, data : "price:>=2"},{ fn : "query", expect : { fn : "testProperty", input : ["price","1"], out : false}, label : "price=1", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["price","0"], out : true}, label : "price=0", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["price","6"], out : true}, label : "price=6", data : "price:>=5 price:0"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : true}, data : "tag:foo"},{ fn : "query", expect : { fn : "testProperty", input : ["tag","foo"], out : false}, data : "-tag:foo"},{ fn : "query", expect : { fn : "testPropertyExclude", input : ["tag","foo"], out : true}, label : "testExclude", data : "-tag:foo"},{ fn : "query", expect : { fn : "test", input : [{ price : 5}], out : true}, data : ".foo price:5 -tag:foo"},{ fn : "query", expect : { fn : "test", input : [{ tag : "foo", price : 5}], out : false}, data : ".foo price:5 -tag:foo"}]);
|
|
||||||
if(Test.errors > 1) {
|
if(Test.errors > 1) {
|
||||||
console.log("src/Test.hx:24:","\n-----\n[ ❌] " + Test.errors + " errors :/");
|
console.log("src/Test.hx:23:","\n-----\n[ ❌] " + Test.errors + " errors :/");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Test.test = function(topic,spec) {
|
Test.test = function(topic,spec) {
|
||||||
console.log("src/Test.hx:28:","\n[.] running " + topic);
|
console.log("src/Test.hx:27:","\n[.] running " + topic);
|
||||||
var Query = xrfragment_Query;
|
var Filter = xrfragment_Filter;
|
||||||
var _g = 0;
|
var _g = 0;
|
||||||
var _g1 = spec.length;
|
var _g1 = spec.length;
|
||||||
while(_g < _g1) {
|
while(_g < _g1) {
|
||||||
var i = _g++;
|
var i = _g++;
|
||||||
var q = null;
|
var f = null;
|
||||||
var res = null;
|
var res = null;
|
||||||
var valid = false;
|
var valid = false;
|
||||||
var item = spec[i];
|
var item = spec[i];
|
||||||
if(item.fn == "query") {
|
f = new xrfragment_Filter(item.data);
|
||||||
q = new xrfragment_Query(item.data);
|
res = xrfragment_URI.parse(item.data,null);
|
||||||
}
|
|
||||||
if(item.fn == "url") {
|
|
||||||
res = xrfragment_URI.parse(item.data,0);
|
|
||||||
}
|
|
||||||
if(item.expect.fn == "test") {
|
if(item.expect.fn == "test") {
|
||||||
valid = item.expect.out == q.test(item.expect.input[0]);
|
valid = item.expect.out == f.test(item.expect.input[0]);
|
||||||
}
|
}
|
||||||
if(item.expect.fn == "testProperty") {
|
if(item.expect.fn == "testProperty") {
|
||||||
valid = item.expect.out == q.testProperty(item.expect.input[0],item.expect.input[1]);
|
valid = item.expect.out == f.testProperty(item.expect.input[0],item.expect.input[1]);
|
||||||
|
}
|
||||||
|
if(item.expect.fn == "testPropertyInt") {
|
||||||
|
valid = item.expect.out == f.testProperty(item.expect.input[0],item.expect.input[1]);
|
||||||
}
|
}
|
||||||
if(item.expect.fn == "testPropertyExclude") {
|
if(item.expect.fn == "testPropertyExclude") {
|
||||||
valid = item.expect.out == q.testProperty(item.expect.input[0],item.expect.input[1],true);
|
valid = item.expect.out == f.testProperty(item.expect.input[0],item.expect.input[1],true);
|
||||||
}
|
}
|
||||||
if(item.expect.fn == "testParsed") {
|
if(item.expect.fn == "testParsed") {
|
||||||
valid = item.expect.out == Object.prototype.hasOwnProperty.call(res,item.expect.input);
|
valid = item.expect.out == Object.prototype.hasOwnProperty.call(res,item.expect.input);
|
||||||
|
|
@ -199,11 +211,14 @@ Test.test = function(topic,spec) {
|
||||||
if(item.expect.fn == "equal.xyz") {
|
if(item.expect.fn == "equal.xyz") {
|
||||||
valid = Test.equalXYZ(res,item);
|
valid = Test.equalXYZ(res,item);
|
||||||
}
|
}
|
||||||
if(item.expect.fn == "testQueryRoot") {
|
if(item.expect.fn == "testFilterRoot") {
|
||||||
valid = item.expect.out == q.get()[item.expect.input[0]].root;
|
valid = Object.prototype.hasOwnProperty.call(res,item.expect.input[0]) && res[item.expect.input[0]].filter.get().root == item.expect.out;
|
||||||
|
}
|
||||||
|
if(item.expect.fn == "testFilterDeep") {
|
||||||
|
valid = Object.prototype.hasOwnProperty.call(res,item.expect.input[0]) && res[item.expect.input[0]].filter.get().deep == item.expect.out;
|
||||||
}
|
}
|
||||||
var ok = valid ? "[ ✔ ] " : "[ ❌] ";
|
var ok = valid ? "[ ✔ ] " : "[ ❌] ";
|
||||||
console.log("src/Test.hx:51:",ok + Std.string(item.fn) + ": '" + Std.string(item.data) + "'" + (item.label ? " (" + (item.label ? item.label : item.expect.fn) + ")" : ""));
|
console.log("src/Test.hx:52:",ok + Std.string(item.fn) + ": '" + Std.string(item.data) + "'" + (item.label ? " (" + (item.label ? item.label : item.expect.fn) + ")" : ""));
|
||||||
if(!valid) {
|
if(!valid) {
|
||||||
Test.errors += 1;
|
Test.errors += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -315,83 +330,22 @@ js_Boot.__string_rec = function(o,s) {
|
||||||
return String(o);
|
return String(o);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { };
|
var xrfragment_Filter = $hx_exports["xrfragment"]["Filter"] = function(str) {
|
||||||
xrfragment_Parser.__name__ = true;
|
|
||||||
xrfragment_Parser.parse = function(key,value,store) {
|
|
||||||
var Frag_h = Object.create(null);
|
|
||||||
Frag_h["#"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW | xrfragment_XRF.PV_EXECUTE;
|
|
||||||
Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT;
|
|
||||||
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
|
|
||||||
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
|
|
||||||
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
|
||||||
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
|
|
||||||
Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["rot"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
|
|
||||||
Frag_h["mov"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["show"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_INT | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["env"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["t"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_STRING | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["tv"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["gravity"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["physics"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["fov"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_INT | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["clip"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["fog"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["bg"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
|
||||||
Frag_h["namespace"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
|
||||||
Frag_h["SPDX"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
|
||||||
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
|
||||||
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
|
||||||
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA | xrfragment_XRF.PROMPT;
|
|
||||||
var isPVDynamic = value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key);
|
|
||||||
var isPVDefault = value.length == 0 && key.length > 0 && key == "#";
|
|
||||||
if(isPVDynamic) {
|
|
||||||
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
|
|
||||||
v.validate(key);
|
|
||||||
store[key] = v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var v = new xrfragment_XRF(key,Frag_h[key]);
|
|
||||||
if(Object.prototype.hasOwnProperty.call(Frag_h,key)) {
|
|
||||||
if(!v.validate(value)) {
|
|
||||||
console.log("src/xrfragment/Parser.hx:80:","⚠ fragment '" + key + "' has incompatible value (" + value + ")");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
store[key] = v;
|
|
||||||
if(xrfragment_Parser.debug) {
|
|
||||||
console.log("src/xrfragment/Parser.hx:84:","✔ " + key + ": " + v.string);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(typeof(value) == "string") {
|
|
||||||
v.guessType(v,value);
|
|
||||||
}
|
|
||||||
v.noXRF = true;
|
|
||||||
store[key] = v;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
|
|
||||||
this.isNumber = new EReg("^[0-9\\.]+$","");
|
|
||||||
this.isRoot = new EReg("^[-]?/","");
|
|
||||||
this.isExclude = new EReg("^-","");
|
|
||||||
this.isProp = new EReg("^.*:[><=!]?","");
|
|
||||||
this.q = { };
|
this.q = { };
|
||||||
this.str = "";
|
this.str = "";
|
||||||
if(str != null) {
|
if(str != null) {
|
||||||
this.parse(str);
|
this.parse(str);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xrfragment_Query.__name__ = true;
|
xrfragment_Filter.__name__ = true;
|
||||||
xrfragment_Query.prototype = {
|
xrfragment_Filter.prototype = {
|
||||||
toObject: function() {
|
toObject: function() {
|
||||||
return this.q;
|
return Reflect.copy(this.q);
|
||||||
}
|
}
|
||||||
,get: function() {
|
,get: function() {
|
||||||
return this.q;
|
return Reflect.copy(this.q);
|
||||||
}
|
}
|
||||||
,parse: function(str) {
|
,parse: function(str) {
|
||||||
var _gthis = this;
|
|
||||||
var token = str.split(" ");
|
var token = str.split(" ");
|
||||||
var q = { };
|
var q = { };
|
||||||
var process = function(str,prefix) {
|
var process = function(str,prefix) {
|
||||||
|
|
@ -399,59 +353,42 @@ xrfragment_Query.prototype = {
|
||||||
prefix = "";
|
prefix = "";
|
||||||
}
|
}
|
||||||
str = StringTools.trim(str);
|
str = StringTools.trim(str);
|
||||||
var k = str.split(":")[0];
|
var k = str.split("=")[0];
|
||||||
var v = str.split(":")[1];
|
var v = str.split("=")[1];
|
||||||
var filter = { };
|
var filter = { };
|
||||||
if(q[prefix + k]) {
|
if(q[prefix + k]) {
|
||||||
filter = q[prefix + k];
|
filter = q[prefix + k];
|
||||||
}
|
}
|
||||||
filter["rules"] = filter["rules"] != null ? filter["rules"] : [];
|
if(xrfragment_XRF.isProp.match(str)) {
|
||||||
if(_gthis.isProp.match(str)) {
|
|
||||||
var oper = "";
|
var oper = "";
|
||||||
if(str.indexOf("*") != -1) {
|
|
||||||
oper = "*";
|
|
||||||
}
|
|
||||||
if(str.indexOf(">") != -1) {
|
if(str.indexOf(">") != -1) {
|
||||||
oper = ">";
|
oper = ">";
|
||||||
}
|
}
|
||||||
if(str.indexOf("<") != -1) {
|
if(str.indexOf("<") != -1) {
|
||||||
oper = "<";
|
oper = "<";
|
||||||
}
|
}
|
||||||
if(str.indexOf(">=") != -1) {
|
if(xrfragment_XRF.isExclude.match(k)) {
|
||||||
oper = ">=";
|
|
||||||
}
|
|
||||||
if(str.indexOf("<=") != -1) {
|
|
||||||
oper = "<=";
|
|
||||||
}
|
|
||||||
if(_gthis.isExclude.match(k)) {
|
|
||||||
oper = "!=";
|
|
||||||
k = HxOverrides.substr(k,1,null);
|
k = HxOverrides.substr(k,1,null);
|
||||||
} else {
|
|
||||||
v = HxOverrides.substr(v,oper.length,null);
|
|
||||||
}
|
}
|
||||||
|
v = HxOverrides.substr(v,oper.length,null);
|
||||||
if(oper.length == 0) {
|
if(oper.length == 0) {
|
||||||
oper = "=";
|
oper = "=";
|
||||||
}
|
}
|
||||||
var rule = { };
|
var rule = { };
|
||||||
if(_gthis.isNumber.match(v)) {
|
if(xrfragment_XRF.isNumber.match(v)) {
|
||||||
rule[oper] = parseFloat(v);
|
rule[oper] = parseFloat(v);
|
||||||
} else {
|
} else {
|
||||||
rule[oper] = v;
|
rule[oper] = v;
|
||||||
}
|
}
|
||||||
filter["rules"].push(rule);
|
q["expr"] = rule;
|
||||||
q[k] = filter;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
filter["id"] = _gthis.isExclude.match(str) ? false : true;
|
|
||||||
filter["root"] = _gthis.isRoot.match(str);
|
|
||||||
if(_gthis.isExclude.match(str)) {
|
|
||||||
str = HxOverrides.substr(str,1,null);
|
|
||||||
}
|
|
||||||
if(_gthis.isRoot.match(str)) {
|
|
||||||
str = HxOverrides.substr(str,1,null);
|
|
||||||
}
|
|
||||||
q[str] = filter;
|
|
||||||
}
|
}
|
||||||
|
var value = xrfragment_XRF.isDeep.match(str) ? k.split("*").length - 1 : 0;
|
||||||
|
q["deep"] = value;
|
||||||
|
var value = xrfragment_XRF.isExclude.match(str) ? false : true;
|
||||||
|
q["show"] = value;
|
||||||
|
var value = k.replace(xrfragment_XRF.operators.r,"");
|
||||||
|
q["key"] = value;
|
||||||
|
q["value"] = v;
|
||||||
};
|
};
|
||||||
var _g = 0;
|
var _g = 0;
|
||||||
var _g1 = token.length;
|
var _g1 = token.length;
|
||||||
|
|
@ -500,49 +437,75 @@ xrfragment_Query.prototype = {
|
||||||
return v[property];
|
return v[property];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var _g = 0;
|
if(Reflect.field(this.q,"expr")) {
|
||||||
var _g1 = Reflect.fields(this.q);
|
var f = Reflect.field(this.q,"expr");
|
||||||
while(_g < _g1.length) {
|
if(!Reflect.field(this.q,"show")) {
|
||||||
var k = _g1[_g];
|
if(Reflect.field(f,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(f,"!="))) && exclude) {
|
||||||
++_g;
|
++qualify;
|
||||||
var filter = Reflect.field(this.q,k);
|
}
|
||||||
if(filter.rules == null) {
|
} else {
|
||||||
continue;
|
if(Reflect.field(f,"*") != null && testprop(parseFloat(value) != null)) {
|
||||||
}
|
++qualify;
|
||||||
var rules = filter.rules;
|
}
|
||||||
var _g2 = 0;
|
if(Reflect.field(f,">") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(f,">")))) {
|
||||||
while(_g2 < rules.length) {
|
++qualify;
|
||||||
var rule = rules[_g2];
|
}
|
||||||
++_g2;
|
if(Reflect.field(f,"<") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(f,"<")))) {
|
||||||
if(exclude) {
|
++qualify;
|
||||||
if(Reflect.field(rule,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(rule,"!="))) && exclude) {
|
}
|
||||||
++qualify;
|
if(Reflect.field(f,"=") != null && (testprop(value == Reflect.field(f,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(f,"="))))) {
|
||||||
}
|
++qualify;
|
||||||
} else {
|
|
||||||
if(Reflect.field(rule,"*") != null && testprop(parseFloat(value) != null)) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
if(Reflect.field(rule,">") != null && testprop(parseFloat(value) > parseFloat(Reflect.field(rule,">")))) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
if(Reflect.field(rule,"<") != null && testprop(parseFloat(value) < parseFloat(Reflect.field(rule,"<")))) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
if(Reflect.field(rule,">=") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(rule,">=")))) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
if(Reflect.field(rule,"<=") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(rule,"<=")))) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
if(Reflect.field(rule,"=") != null && (testprop(value == Reflect.field(rule,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(rule,"="))))) {
|
|
||||||
++qualify;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return qualify > 0;
|
return qualify > 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { };
|
||||||
|
xrfragment_Parser.__name__ = true;
|
||||||
|
xrfragment_Parser.parse = function(key,value,store,index) {
|
||||||
|
var Frag_h = Object.create(null);
|
||||||
|
Frag_h["#"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW | xrfragment_XRF.PV_EXECUTE;
|
||||||
|
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
|
||||||
|
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
|
||||||
|
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
||||||
|
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
|
||||||
|
Frag_h["rot"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
|
||||||
|
Frag_h["t"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_STRING | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
||||||
|
Frag_h["tv"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
|
||||||
|
Frag_h["namespace"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
||||||
|
Frag_h["SPDX"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
||||||
|
Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
||||||
|
Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
|
||||||
|
Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA | xrfragment_XRF.PROMPT;
|
||||||
|
var keyStripped = key.replace(xrfragment_XRF.operators.r,"");
|
||||||
|
var isPVDynamic = key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key);
|
||||||
|
var isPVDefault = value.length == 0 && key.length > 0 && key == "#";
|
||||||
|
if(isPVDynamic) {
|
||||||
|
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR,index);
|
||||||
|
v.validate(value);
|
||||||
|
store[keyStripped] = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var v = new xrfragment_XRF(key,Frag_h[key],index);
|
||||||
|
if(Object.prototype.hasOwnProperty.call(Frag_h,key)) {
|
||||||
|
if(!v.validate(value)) {
|
||||||
|
console.log("src/xrfragment/Parser.hx:66:","⚠ fragment '" + key + "' has incompatible value (" + value + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
store[keyStripped] = v;
|
||||||
|
if(xrfragment_Parser.debug) {
|
||||||
|
console.log("src/xrfragment/Parser.hx:70:","✔ " + key + ": " + v.string);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(typeof(value) == "string") {
|
||||||
|
v.guessType(v,value);
|
||||||
|
}
|
||||||
|
v.noXRF = true;
|
||||||
|
store[keyStripped] = v;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
|
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
|
||||||
xrfragment_URI.__name__ = true;
|
xrfragment_URI.__name__ = true;
|
||||||
xrfragment_URI.parse = function(url,filter) {
|
xrfragment_URI.parse = function(url,filter) {
|
||||||
|
|
@ -564,7 +527,7 @@ xrfragment_URI.parse = function(url,filter) {
|
||||||
var s = regexPlus.split(splitByEqual[1]).join(" ");
|
var s = regexPlus.split(splitByEqual[1]).join(" ");
|
||||||
value = decodeURIComponent(s.split("+").join(" "));
|
value = decodeURIComponent(s.split("+").join(" "));
|
||||||
}
|
}
|
||||||
var ok = xrfragment_Parser.parse(key,value,store);
|
var ok = xrfragment_Parser.parse(key,value,store,i);
|
||||||
}
|
}
|
||||||
if(filter != null && filter != 0) {
|
if(filter != null && filter != 0) {
|
||||||
var _g = 0;
|
var _g = 0;
|
||||||
|
|
@ -580,9 +543,10 @@ xrfragment_URI.parse = function(url,filter) {
|
||||||
}
|
}
|
||||||
return store;
|
return store;
|
||||||
};
|
};
|
||||||
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags) {
|
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
|
||||||
this.fragment = _fragment;
|
this.fragment = _fragment;
|
||||||
this.flags = _flags;
|
this.flags = _flags;
|
||||||
|
this.index = _index;
|
||||||
};
|
};
|
||||||
xrfragment_XRF.__name__ = true;
|
xrfragment_XRF.__name__ = true;
|
||||||
xrfragment_XRF.set = function(flag,flags) {
|
xrfragment_XRF.set = function(flag,flags) {
|
||||||
|
|
@ -601,45 +565,50 @@ xrfragment_XRF.prototype = {
|
||||||
}
|
}
|
||||||
,validate: function(value) {
|
,validate: function(value) {
|
||||||
this.guessType(this,value);
|
this.guessType(this,value);
|
||||||
if(this.fragment == "q") {
|
|
||||||
this.query = new xrfragment_Query(value).get();
|
|
||||||
}
|
|
||||||
var ok = true;
|
var ok = true;
|
||||||
if(!this.is(xrfragment_XRF.T_FLOAT) && this.is(xrfragment_XRF.T_VECTOR2) && !(typeof(this.x) == "number" && typeof(this.y) == "number")) {
|
if(!this.is(xrfragment_XRF.T_FLOAT) && this.is(xrfragment_XRF.T_VECTOR2) && !(typeof(this.x) == "number" && typeof(this.y) == "number")) {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if(!this.is(xrfragment_XRF.T_VECTOR2) && this.is(xrfragment_XRF.T_VECTOR3) && !(typeof(this.x) == "number" && typeof(this.y) == "number" && typeof(this.z) == "number")) {
|
if(!(this.is(xrfragment_XRF.T_VECTOR2) || this.is(xrfragment_XRF.T_STRING)) && this.is(xrfragment_XRF.T_VECTOR3) && !(typeof(this.x) == "number" && typeof(this.y) == "number" && typeof(this.z) == "number")) {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
,guessType: function(v,str) {
|
,guessType: function(v,str) {
|
||||||
v.string = str;
|
v.string = str;
|
||||||
if(str.split(",").length > 1) {
|
if(typeof(str) != "string") {
|
||||||
var xyzw = str.split(",");
|
return;
|
||||||
if(xyzw.length > 0) {
|
|
||||||
v.x = parseFloat(xyzw[0]);
|
|
||||||
}
|
|
||||||
if(xyzw.length > 1) {
|
|
||||||
v.y = parseFloat(xyzw[1]);
|
|
||||||
}
|
|
||||||
if(xyzw.length > 2) {
|
|
||||||
v.z = parseFloat(xyzw[2]);
|
|
||||||
}
|
|
||||||
if(xyzw.length > 3) {
|
|
||||||
v.w = parseFloat(xyzw[3]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(xrfragment_XRF.isColor.match(str)) {
|
if(str.length > 0) {
|
||||||
v.color = str;
|
if(str.split(",").length > 1) {
|
||||||
}
|
var xyzw = str.split(",");
|
||||||
if(xrfragment_XRF.isFloat.match(str)) {
|
if(xyzw.length > 0) {
|
||||||
v.x = parseFloat(str);
|
v.x = parseFloat(xyzw[0]);
|
||||||
v.float = v.x;
|
}
|
||||||
}
|
if(xyzw.length > 1) {
|
||||||
if(xrfragment_XRF.isInt.match(str)) {
|
v.y = parseFloat(xyzw[1]);
|
||||||
v.int = Std.parseInt(str);
|
}
|
||||||
v.x = v.int;
|
if(xyzw.length > 2) {
|
||||||
|
v.z = parseFloat(xyzw[2]);
|
||||||
|
}
|
||||||
|
if(xyzw.length > 3) {
|
||||||
|
v.w = parseFloat(xyzw[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(xrfragment_XRF.isColor.match(str)) {
|
||||||
|
v.color = str;
|
||||||
|
}
|
||||||
|
if(xrfragment_XRF.isFloat.match(str)) {
|
||||||
|
v.x = parseFloat(str);
|
||||||
|
v.float = v.x;
|
||||||
|
}
|
||||||
|
if(xrfragment_XRF.isInt.match(str)) {
|
||||||
|
v.int = Std.parseInt(str);
|
||||||
|
v.x = v.int;
|
||||||
|
}
|
||||||
|
v.filter = new xrfragment_Filter(v.fragment + "=" + v.string);
|
||||||
|
} else {
|
||||||
|
v.filter = new xrfragment_Filter(v.fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -678,6 +647,11 @@ xrfragment_XRF.isVector = new EReg("([,]+|\\w)","");
|
||||||
xrfragment_XRF.isUrl = new EReg("(://)?\\..*","");
|
xrfragment_XRF.isUrl = new EReg("(://)?\\..*","");
|
||||||
xrfragment_XRF.isUrlOrPretypedView = new EReg("(^#|://)?\\..*","");
|
xrfragment_XRF.isUrlOrPretypedView = new EReg("(^#|://)?\\..*","");
|
||||||
xrfragment_XRF.isString = new EReg(".*","");
|
xrfragment_XRF.isString = new EReg(".*","");
|
||||||
|
xrfragment_XRF.operators = new EReg("(^-|[\\*]+)","");
|
||||||
|
xrfragment_XRF.isProp = new EReg("^.*=[><=]?","");
|
||||||
|
xrfragment_XRF.isExclude = new EReg("^-","");
|
||||||
|
xrfragment_XRF.isDeep = new EReg("\\*","");
|
||||||
|
xrfragment_XRF.isNumber = new EReg("^[0-9\\.]+$","");
|
||||||
Test.main();
|
Test.main();
|
||||||
})({});
|
})({});
|
||||||
var xrfragment = $hx_exports["xrfragment"];
|
var xrfragment = $hx_exports["xrfragment"];
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class EReg:
|
||||||
_hx_class_name = "EReg"
|
_hx_class_name = "EReg"
|
||||||
__slots__ = ("pattern", "matchObj", "_hx_global")
|
__slots__ = ("pattern", "matchObj", "_hx_global")
|
||||||
_hx_fields = ["pattern", "matchObj", "global"]
|
_hx_fields = ["pattern", "matchObj", "global"]
|
||||||
_hx_methods = ["split"]
|
_hx_methods = ["split", "replace"]
|
||||||
|
|
||||||
def __init__(self,r,opt):
|
def __init__(self,r,opt):
|
||||||
self.matchObj = None
|
self.matchObj = None
|
||||||
|
|
@ -107,12 +107,35 @@ class EReg:
|
||||||
else:
|
else:
|
||||||
return [HxString.substring(s,0,self.matchObj.start()), HxString.substr(s,self.matchObj.end(),None)]
|
return [HxString.substring(s,0,self.matchObj.start()), HxString.substr(s,self.matchObj.end(),None)]
|
||||||
|
|
||||||
|
def replace(self,s,by):
|
||||||
|
_this = by.split("$$")
|
||||||
|
by = "_hx_#repl#__".join([python_Boot.toString1(x1,'') for x1 in _this])
|
||||||
|
def _hx_local_0(x):
|
||||||
|
res = by
|
||||||
|
g = x.groups()
|
||||||
|
_g = 0
|
||||||
|
_g1 = len(g)
|
||||||
|
while (_g < _g1):
|
||||||
|
i = _g
|
||||||
|
_g = (_g + 1)
|
||||||
|
gs = g[i]
|
||||||
|
if (gs is None):
|
||||||
|
continue
|
||||||
|
delimiter = ("$" + HxOverrides.stringOrNull(str((i + 1))))
|
||||||
|
_this = (list(res) if ((delimiter == "")) else res.split(delimiter))
|
||||||
|
res = gs.join([python_Boot.toString1(x1,'') for x1 in _this])
|
||||||
|
_this = res.split("_hx_#repl#__")
|
||||||
|
res = "$".join([python_Boot.toString1(x1,'') for x1 in _this])
|
||||||
|
return res
|
||||||
|
replace = _hx_local_0
|
||||||
|
return python_lib_Re.sub(self.pattern,replace,s,(0 if (self._hx_global) else 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Reflect:
|
class Reflect:
|
||||||
_hx_class_name = "Reflect"
|
_hx_class_name = "Reflect"
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
_hx_statics = ["field", "deleteField"]
|
_hx_statics = ["field", "deleteField", "copy"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def field(o,field):
|
def field(o,field):
|
||||||
|
|
@ -129,6 +152,20 @@ class Reflect:
|
||||||
o.__delattr__(field)
|
o.__delattr__(field)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def copy(o):
|
||||||
|
if (o is None):
|
||||||
|
return None
|
||||||
|
o2 = _hx_AnonObject({})
|
||||||
|
_g = 0
|
||||||
|
_g1 = python_Boot.fields(o)
|
||||||
|
while (_g < len(_g1)):
|
||||||
|
f = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
|
||||||
|
_g = (_g + 1)
|
||||||
|
value = Reflect.field(o,f)
|
||||||
|
setattr(o2,(("_hx_" + f) if ((f in python_Boot.keywords)) else (("_hx_" + f) if (((((len(f) > 2) and ((ord(f[0]) == 95))) and ((ord(f[1]) == 95))) and ((ord(f[(len(f) - 1)]) != 95)))) else f)),value)
|
||||||
|
return o2
|
||||||
|
|
||||||
|
|
||||||
class Std:
|
class Std:
|
||||||
_hx_class_name = "Std"
|
_hx_class_name = "Std"
|
||||||
|
|
@ -385,37 +422,36 @@ class Test:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def main():
|
def main():
|
||||||
Test.test("url.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': False}), 'label': "equal.xyz: should trigger incompatible type)", 'data': "http://foo.com?foo=1#pos=1.2,2.2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': "1.2,2.2,3"}), 'label': "equal.xyz", 'data': "http://foo.com?foo=1#pos=1.2,2.2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "q", 'out': False}), 'label': "browser URI cannot override q (defined in asset)", 'data': "http://foo.com?foo=1#q=-bar"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed", 'data': "http://foo.com?foo=1#mypredefinedview"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "another", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "mycustom", 'out': True}), 'label': "test custom property", 'data': "http://foo.com?foo=1#mycustom=foo"})])
|
Test.test("url.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed", 'data': "http://foo.com?foo=1#mypredefinedview"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "another", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testPredefinedView", 'input': "mypredefinedview", 'out': True}), 'label': "test predefined view executed (multiple)", 'data': "http://foo.com?foo=1#mypredefinedview&another"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "mycustom", 'out': True}), 'label': "test custom property", 'data': "http://foo.com?foo=1#mycustom=foo"})])
|
||||||
|
Test.test("pos.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.string", 'input': "pos", 'out': "1.2,2.2"}), 'label': "equal.string", 'data': "http://foo.com?foo=1#pos=1.2,2.2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': "1.2,2.2,3"}), 'label': "equal.xyz", 'data': "http://foo.com?foo=1#pos=1.2,2.2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "pos", 'out': "1,2,3"}), 'label': "pos equal.xyz", 'data': "http://foo.com?foo=1#pos=1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.string", 'input': "pos", 'out': "world2"}), 'label': "pos equal.xyz", 'data': "http://foo.com?foo=1#pos=world2"})])
|
||||||
Test.test("t.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "1"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=1"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "-1"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=-1"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "-1.02"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=-1.02"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xy", 'input': "t", 'out': "1,2"}), 'label': "a equal.xy", 'data': "http://foo.com?foo=1#t=1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "t", 'out': "1,2,3"}), 'label': "a equal.xyz", 'data': "http://foo.com?foo=1#t=1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "t", 'out': "1,-2,3"}), 'label': "a equal.xyz", 'data': "http://foo.com?foo=1#t=1,-2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xy", 'input': "t", 'out': "1,100"}), 'label': "a equal.xy", 'data': "http://foo.com?foo=1#t=1,100"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "t", 'out': True}), 'label': "browser URI can override t (defined in asset)", 'data': "http://foo.com?foo=1#t=2,500"})])
|
Test.test("t.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "1"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=1"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "-1"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=-1"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.x", 'input': "t", 'out': "-1.02"}), 'label': "a equal.x", 'data': "http://foo.com?foo=1#t=-1.02"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xy", 'input': "t", 'out': "1,2"}), 'label': "a equal.xy", 'data': "http://foo.com?foo=1#t=1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "t", 'out': "1,2,3"}), 'label': "a equal.xyz", 'data': "http://foo.com?foo=1#t=1,2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xyz", 'input': "t", 'out': "1,-2,3"}), 'label': "a equal.xyz", 'data': "http://foo.com?foo=1#t=1,-2,3"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "equal.xy", 'input': "t", 'out': "1,100"}), 'label': "a equal.xy", 'data': "http://foo.com?foo=1#t=1,100"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testBrowserOverride", 'input': "t", 'out': True}), 'label': "browser URI can override t (defined in asset)", 'data': "http://foo.com?foo=1#t=2,500"})])
|
||||||
Test.test("q.selectors.json",[_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "bar"], 'out': True}), 'data': "tag:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "tag:bar -tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'data': "tag:bar -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "bar"], 'out': True}), 'data': "tag:bar -tag:bar tag:bar"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:>5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo bar:>5 tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'label': "tag:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo", 'data': "tag:foo -tag:foo tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["id", "foo"], 'out': True}), 'label': "id:foo?", 'data': "tag:foo -foo foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testQueryRoot", 'input': ["foo"], 'out': True}), 'label': "foo should be root-only", 'data': "/foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testQueryRoot", 'input': ["foo"], 'out': False}), 'label': "foo should recursively selected", 'data': "/foo foo"})])
|
Test.test("filter.selectors.json",[_hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "myid", 'out': True}), 'label': "myid exists", 'data': "http://foo.com?foo=1#foo*&-sometag&-someid&myid"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "tag", 'out': True}), 'label': "tag exists", 'data': "http://foo.com?foo=1#tag=bar"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "tag", 'out': True}), 'label': "tag exists", 'data': "http://foo.com?foo=1#-tag=bar"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testParsed", 'input': "price", 'out': True}), 'label': "filter test", 'data': "http://foo.com?foo=1#price=>2"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "bar"], 'out': True}), 'data': "tag=bar"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "-tag=foo"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "-tag*=foo"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "3"], 'out': False}), 'data': "-tag=>2"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "1"], 'out': False}), 'data': "price=>2"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "5"], 'out': False}), 'data': "price=<2"}), _hx_AnonObject({'fn': "filter", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "1"], 'out': True}), 'data': "price=<2"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testFilterDeep", 'input': ["foo"], 'out': 1}), 'label': "foo should be deep", 'data': "#foo*"}), _hx_AnonObject({'fn': "url", 'expect': _hx_AnonObject({'fn': "testFilterDeep", 'input': ["foo"], 'out': 2}), 'label': "foo should be deep incl. embeds", 'data': "#foo**"})])
|
||||||
Test.test("q.root.json",[])
|
|
||||||
Test.test("q.rules.json",[_hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "10"], 'out': True}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "10"], 'out': False}), 'data': "price:>=15"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "4"], 'out': False}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "0"], 'out': False}), 'data': "price:>=5"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "2"], 'out': True}), 'data': "price:>=2"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "1"], 'out': False}), 'label': "price=1", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "0"], 'out': True}), 'label': "price=0", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["price", "6"], 'out': True}), 'label': "price=6", 'data': "price:>=5 price:0"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': True}), 'data': "tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testProperty", 'input': ["tag", "foo"], 'out': False}), 'data': "-tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "testPropertyExclude", 'input': ["tag", "foo"], 'out': True}), 'label': "testExclude", 'data': "-tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "test", 'input': [_hx_AnonObject({'price': 5})], 'out': True}), 'data': ".foo price:5 -tag:foo"}), _hx_AnonObject({'fn': "query", 'expect': _hx_AnonObject({'fn': "test", 'input': [_hx_AnonObject({'tag': "foo", 'price': 5})], 'out': False}), 'data': ".foo price:5 -tag:foo"})])
|
|
||||||
if (Test.errors > 1):
|
if (Test.errors > 1):
|
||||||
print(str((("\n-----\n[ ❌] " + Std.string(Test.errors)) + " errors :/")))
|
print(str((("\n-----\n[ ❌] " + Std.string(Test.errors)) + " errors :/")))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test(topic,spec):
|
def test(topic,spec):
|
||||||
print(str(("\n[.] running " + ("null" if topic is None else topic))))
|
print(str(("\n[.] running " + ("null" if topic is None else topic))))
|
||||||
Query = xrfragment_Query
|
Filter = xrfragment_Filter
|
||||||
_g = 0
|
_g = 0
|
||||||
_g1 = len(spec)
|
_g1 = len(spec)
|
||||||
while (_g < _g1):
|
while (_g < _g1):
|
||||||
i = _g
|
i = _g
|
||||||
_g = (_g + 1)
|
_g = (_g + 1)
|
||||||
q = None
|
f = None
|
||||||
res = None
|
res = None
|
||||||
valid = False
|
valid = False
|
||||||
item = (spec[i] if i >= 0 and i < len(spec) else None)
|
item = (spec[i] if i >= 0 and i < len(spec) else None)
|
||||||
if (Reflect.field(item,"fn") == "query"):
|
f = xrfragment_Filter(Reflect.field(item,"data"))
|
||||||
q = xrfragment_Query(Reflect.field(item,"data"))
|
res = xrfragment_URI.parse(Reflect.field(item,"data"),None)
|
||||||
if (Reflect.field(item,"fn") == "url"):
|
|
||||||
res = xrfragment_URI.parse(Reflect.field(item,"data"),0)
|
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "test"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "test"):
|
||||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == q.test(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)))
|
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == f.test(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)))
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testProperty"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testProperty"):
|
||||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == q.testProperty(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0),HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 1)))
|
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == f.testProperty(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0),HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 1)))
|
||||||
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testPropertyInt"):
|
||||||
|
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == f.testProperty(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0),HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 1)))
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testPropertyExclude"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testPropertyExclude"):
|
||||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == q.testProperty(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0),HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 1),True))
|
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == f.testProperty(HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0),HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 1),True))
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testParsed"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testParsed"):
|
||||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == python_Boot.hasField(res,Reflect.field(Reflect.field(item,"expect"),"input")))
|
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == python_Boot.hasField(res,Reflect.field(Reflect.field(item,"expect"),"input")))
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testPredefinedView"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testPredefinedView"):
|
||||||
|
|
@ -434,8 +470,10 @@ class Test:
|
||||||
valid = Test.equalXY(res,item)
|
valid = Test.equalXY(res,item)
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "equal.xyz"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "equal.xyz"):
|
||||||
valid = Test.equalXYZ(res,item)
|
valid = Test.equalXYZ(res,item)
|
||||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testQueryRoot"):
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testFilterRoot"):
|
||||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == HxOverrides.arrayGet(q.get(), HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)).root)
|
valid = (python_Boot.hasField(res,HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)) and (HxOverrides.eq(Reflect.field(Reflect.field(Reflect.field(Reflect.field(res,HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)),"filter"),"get")(),"root"),Reflect.field(Reflect.field(item,"expect"),"out"))))
|
||||||
|
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testFilterDeep"):
|
||||||
|
valid = (python_Boot.hasField(res,HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)) and (HxOverrides.eq(Reflect.field(Reflect.field(Reflect.field(Reflect.field(res,HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)),"filter"),"get")(),"deep"),Reflect.field(Reflect.field(item,"expect"),"out"))))
|
||||||
ok = ("[ ✔ ] " if valid else "[ ❌] ")
|
ok = ("[ ✔ ] " if valid else "[ ❌] ")
|
||||||
print(str((((((("null" if ok is None else ok) + Std.string(Reflect.field(item,"fn"))) + ": '") + Std.string(Reflect.field(item,"data"))) + "'") + HxOverrides.stringOrNull(((((" (" + HxOverrides.stringOrNull(((Reflect.field(item,"label") if (Reflect.field(item,"label")) else Reflect.field(Reflect.field(item,"expect"),"fn"))))) + ")") if (Reflect.field(item,"label")) else ""))))))
|
print(str((((((("null" if ok is None else ok) + Std.string(Reflect.field(item,"fn"))) + ": '") + Std.string(Reflect.field(item,"data"))) + "'") + HxOverrides.stringOrNull(((((" (" + HxOverrides.stringOrNull(((Reflect.field(item,"label") if (Reflect.field(item,"label")) else Reflect.field(Reflect.field(item,"expect"),"fn"))))) + ")") if (Reflect.field(item,"label")) else ""))))))
|
||||||
if (not valid):
|
if (not valid):
|
||||||
|
|
@ -1078,7 +1116,11 @@ class python_HaxeIterator:
|
||||||
class python_internal_ArrayImpl:
|
class python_internal_ArrayImpl:
|
||||||
_hx_class_name = "python.internal.ArrayImpl"
|
_hx_class_name = "python.internal.ArrayImpl"
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
_hx_statics = ["concat", "copy", "iterator", "keyValueIterator", "indexOf", "lastIndexOf", "join", "toString", "pop", "push", "unshift", "remove", "contains", "shift", "slice", "sort", "splice", "map", "filter", "insert", "reverse", "_get"]
|
_hx_statics = ["get_length", "concat", "copy", "iterator", "keyValueIterator", "indexOf", "lastIndexOf", "join", "toString", "pop", "push", "unshift", "remove", "contains", "shift", "slice", "sort", "splice", "map", "filter", "insert", "reverse", "_get"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_length(x):
|
||||||
|
return len(x)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def concat(a1,a2):
|
def concat(a1,a2):
|
||||||
|
|
@ -1214,7 +1256,7 @@ class python_internal_ArrayImpl:
|
||||||
class HxOverrides:
|
class HxOverrides:
|
||||||
_hx_class_name = "HxOverrides"
|
_hx_class_name = "HxOverrides"
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
_hx_statics = ["eq", "stringOrNull", "push", "arrayGet"]
|
_hx_statics = ["eq", "stringOrNull", "filter", "length", "arrayGet"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def eq(a,b):
|
def eq(a,b):
|
||||||
|
|
@ -1230,12 +1272,18 @@ class HxOverrides:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def push(x,e):
|
def filter(x,f):
|
||||||
if isinstance(x,list):
|
if isinstance(x,list):
|
||||||
_this = x
|
return list(filter(f,x))
|
||||||
_this.append(e)
|
return x.filter(f)
|
||||||
return len(_this)
|
|
||||||
return x.push(e)
|
@staticmethod
|
||||||
|
def length(x):
|
||||||
|
if isinstance(x,str):
|
||||||
|
return len(x)
|
||||||
|
elif isinstance(x,list):
|
||||||
|
return len(x)
|
||||||
|
return x.length
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def arrayGet(a,i):
|
def arrayGet(a,i):
|
||||||
|
|
@ -1267,7 +1315,7 @@ class python_internal_MethodClosure:
|
||||||
class HxString:
|
class HxString:
|
||||||
_hx_class_name = "HxString"
|
_hx_class_name = "HxString"
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
_hx_statics = ["split", "charCodeAt", "charAt", "lastIndexOf", "toUpperCase", "toLowerCase", "indexOf", "indexOfImpl", "toString", "substring", "substr"]
|
_hx_statics = ["split", "charCodeAt", "charAt", "lastIndexOf", "toUpperCase", "toLowerCase", "indexOf", "indexOfImpl", "toString", "get_length", "substring", "substr"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def split(s,d):
|
def split(s,d):
|
||||||
|
|
@ -1346,6 +1394,10 @@ class HxString:
|
||||||
def toString(s):
|
def toString(s):
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_length(s):
|
||||||
|
return len(s)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def substring(s,startIndex,endIndex = None):
|
def substring(s,startIndex,endIndex = None):
|
||||||
if (startIndex < 0):
|
if (startIndex < 0):
|
||||||
|
|
@ -1374,156 +1426,73 @@ class HxString:
|
||||||
return s[startIndex:(startIndex + _hx_len)]
|
return s[startIndex:(startIndex + _hx_len)]
|
||||||
|
|
||||||
|
|
||||||
class xrfragment_Parser:
|
class xrfragment_Filter:
|
||||||
_hx_class_name = "xrfragment.Parser"
|
_hx_class_name = "xrfragment.Filter"
|
||||||
__slots__ = ()
|
__slots__ = ("str", "q")
|
||||||
_hx_statics = ["error", "debug", "parse"]
|
_hx_fields = ["str", "q"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def parse(key,value,store):
|
|
||||||
Frag = haxe_ds_StringMap()
|
|
||||||
Frag.h["#"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW) | xrfragment_XRF.PV_EXECUTE)
|
|
||||||
Frag.h["prio"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_INT)
|
|
||||||
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
|
|
||||||
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
|
|
||||||
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
|
||||||
Frag.h["pos"] = ((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
|
|
||||||
Frag.h["q"] = ((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["scale"] = (((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["rot"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
|
|
||||||
Frag.h["mov"] = (((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["show"] = (((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_INT) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["env"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["t"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_STRING) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["tv"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["gravity"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["physics"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["fov"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_INT) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["clip"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["fog"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["bg"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
|
||||||
Frag.h["namespace"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
|
||||||
Frag.h["SPDX"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
|
||||||
Frag.h["unit"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
|
||||||
Frag.h["description"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
|
||||||
Frag.h["session"] = (((((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA) | xrfragment_XRF.PROMPT)
|
|
||||||
isPVDynamic = (((len(value) == 0) and ((len(key) > 0))) and (not (key in Frag.h)))
|
|
||||||
isPVDefault = (((len(value) == 0) and ((len(key) > 0))) and ((key == "#")))
|
|
||||||
if isPVDynamic:
|
|
||||||
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR))
|
|
||||||
v.validate(key)
|
|
||||||
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
|
|
||||||
return True
|
|
||||||
v = xrfragment_XRF(key,Frag.h.get(key,None))
|
|
||||||
if (key in Frag.h):
|
|
||||||
if (not v.validate(value)):
|
|
||||||
print(str((((("⚠ fragment '" + ("null" if key is None else key)) + "' has incompatible value (") + ("null" if value is None else value)) + ")")))
|
|
||||||
return False
|
|
||||||
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
|
|
||||||
if xrfragment_Parser.debug:
|
|
||||||
print(str(((("✔ " + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string))))
|
|
||||||
else:
|
|
||||||
if Std.isOfType(value,str):
|
|
||||||
v.guessType(v,value)
|
|
||||||
v.noXRF = True
|
|
||||||
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class xrfragment_Query:
|
|
||||||
_hx_class_name = "xrfragment.Query"
|
|
||||||
__slots__ = ("str", "q", "isProp", "isExclude", "isRoot", "isNumber")
|
|
||||||
_hx_fields = ["str", "q", "isProp", "isExclude", "isRoot", "isNumber"]
|
|
||||||
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
|
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
|
||||||
|
|
||||||
def __init__(self,_hx_str):
|
def __init__(self,_hx_str):
|
||||||
self.isNumber = EReg("^[0-9\\.]+$","")
|
|
||||||
self.isRoot = EReg("^[-]?/","")
|
|
||||||
self.isExclude = EReg("^-","")
|
|
||||||
self.isProp = EReg("^.*:[><=!]?","")
|
|
||||||
self.q = _hx_AnonObject({})
|
self.q = _hx_AnonObject({})
|
||||||
self.str = ""
|
self.str = ""
|
||||||
if (_hx_str is not None):
|
if (_hx_str is not None):
|
||||||
self.parse(_hx_str)
|
self.parse(_hx_str)
|
||||||
|
|
||||||
def toObject(self):
|
def toObject(self):
|
||||||
return self.q
|
return Reflect.copy(self.q)
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return self.q
|
return Reflect.copy(self.q)
|
||||||
|
|
||||||
def parse(self,_hx_str):
|
def parse(self,_hx_str):
|
||||||
_gthis = self
|
|
||||||
token = _hx_str.split(" ")
|
token = _hx_str.split(" ")
|
||||||
q = _hx_AnonObject({})
|
q = _hx_AnonObject({})
|
||||||
def _hx_local_0(_hx_str,prefix = None):
|
def _hx_local_0(_hx_str,prefix = None):
|
||||||
if (prefix is None):
|
if (prefix is None):
|
||||||
prefix = ""
|
prefix = ""
|
||||||
_hx_str = StringTools.trim(_hx_str)
|
_hx_str = StringTools.trim(_hx_str)
|
||||||
k = HxOverrides.arrayGet(_hx_str.split(":"), 0)
|
k = HxOverrides.arrayGet(_hx_str.split("="), 0)
|
||||||
v = HxOverrides.arrayGet(_hx_str.split(":"), 1)
|
v = HxOverrides.arrayGet(_hx_str.split("="), 1)
|
||||||
_hx_filter = _hx_AnonObject({})
|
_hx_filter = _hx_AnonObject({})
|
||||||
if Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k))):
|
if Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k))):
|
||||||
_hx_filter = Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k)))
|
_hx_filter = Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k)))
|
||||||
value = (Reflect.field(_hx_filter,"rules") if ((Reflect.field(_hx_filter,"rules") is not None)) else list())
|
_this = xrfragment_XRF.isProp
|
||||||
setattr(_hx_filter,(("_hx_" + "rules") if (("rules" in python_Boot.keywords)) else (("_hx_" + "rules") if (((((len("rules") > 2) and ((ord("rules"[0]) == 95))) and ((ord("rules"[1]) == 95))) and ((ord("rules"[(len("rules") - 1)]) != 95)))) else "rules")),value)
|
|
||||||
_this = _gthis.isProp
|
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
if (_this.matchObj is not None):
|
if (_this.matchObj is not None):
|
||||||
oper = ""
|
oper = ""
|
||||||
startIndex = None
|
startIndex = None
|
||||||
if (((_hx_str.find("*") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"*",startIndex))) != -1):
|
|
||||||
oper = "*"
|
|
||||||
startIndex = None
|
|
||||||
if (((_hx_str.find(">") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,">",startIndex))) != -1):
|
if (((_hx_str.find(">") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,">",startIndex))) != -1):
|
||||||
oper = ">"
|
oper = ">"
|
||||||
startIndex = None
|
startIndex = None
|
||||||
if (((_hx_str.find("<") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<",startIndex))) != -1):
|
if (((_hx_str.find("<") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<",startIndex))) != -1):
|
||||||
oper = "<"
|
oper = "<"
|
||||||
startIndex = None
|
_this = xrfragment_XRF.isExclude
|
||||||
if (((_hx_str.find(">=") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,">=",startIndex))) != -1):
|
|
||||||
oper = ">="
|
|
||||||
startIndex = None
|
|
||||||
if (((_hx_str.find("<=") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<=",startIndex))) != -1):
|
|
||||||
oper = "<="
|
|
||||||
_this = _gthis.isExclude
|
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,k)
|
_this.matchObj = python_lib_Re.search(_this.pattern,k)
|
||||||
if (_this.matchObj is not None):
|
if (_this.matchObj is not None):
|
||||||
oper = "!="
|
|
||||||
k = HxString.substr(k,1,None)
|
k = HxString.substr(k,1,None)
|
||||||
else:
|
v = HxString.substr(v,len(oper),None)
|
||||||
v = HxString.substr(v,len(oper),None)
|
|
||||||
if (len(oper) == 0):
|
if (len(oper) == 0):
|
||||||
oper = "="
|
oper = "="
|
||||||
rule = _hx_AnonObject({})
|
rule = _hx_AnonObject({})
|
||||||
_this = _gthis.isNumber
|
_this = xrfragment_XRF.isNumber
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,v)
|
_this.matchObj = python_lib_Re.search(_this.pattern,v)
|
||||||
if (_this.matchObj is not None):
|
if (_this.matchObj is not None):
|
||||||
value = Std.parseFloat(v)
|
value = Std.parseFloat(v)
|
||||||
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
|
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
|
||||||
else:
|
else:
|
||||||
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
|
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
|
||||||
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
|
setattr(q,(("_hx_" + "expr") if (("expr" in python_Boot.keywords)) else (("_hx_" + "expr") if (((((len("expr") > 2) and ((ord("expr"[0]) == 95))) and ((ord("expr"[1]) == 95))) and ((ord("expr"[(len("expr") - 1)]) != 95)))) else "expr")),rule)
|
||||||
setattr(q,(("_hx_" + k) if ((k in python_Boot.keywords)) else (("_hx_" + k) if (((((len(k) > 2) and ((ord(k[0]) == 95))) and ((ord(k[1]) == 95))) and ((ord(k[(len(k) - 1)]) != 95)))) else k)),_hx_filter)
|
_this = xrfragment_XRF.isDeep
|
||||||
return
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
else:
|
value = ((Reflect.field(k.split("*"),"length") - 1) if ((_this.matchObj is not None)) else 0)
|
||||||
_this = _gthis.isExclude
|
setattr(q,(("_hx_" + "deep") if (("deep" in python_Boot.keywords)) else (("_hx_" + "deep") if (((((len("deep") > 2) and ((ord("deep"[0]) == 95))) and ((ord("deep"[1]) == 95))) and ((ord("deep"[(len("deep") - 1)]) != 95)))) else "deep")),value)
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
_this = xrfragment_XRF.isExclude
|
||||||
value = (False if ((_this.matchObj is not None)) else True)
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
setattr(_hx_filter,(("_hx_" + "id") if (("id" in python_Boot.keywords)) else (("_hx_" + "id") if (((((len("id") > 2) and ((ord("id"[0]) == 95))) and ((ord("id"[1]) == 95))) and ((ord("id"[(len("id") - 1)]) != 95)))) else "id")),value)
|
value = (False if ((_this.matchObj is not None)) else True)
|
||||||
_this = _gthis.isRoot
|
setattr(q,(("_hx_" + "show") if (("show" in python_Boot.keywords)) else (("_hx_" + "show") if (((((len("show") > 2) and ((ord("show"[0]) == 95))) and ((ord("show"[1]) == 95))) and ((ord("show"[(len("show") - 1)]) != 95)))) else "show")),value)
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
value = xrfragment_XRF.operators.replace(k,"")
|
||||||
value = (_this.matchObj is not None)
|
setattr(q,(("_hx_" + "key") if (("key" in python_Boot.keywords)) else (("_hx_" + "key") if (((((len("key") > 2) and ((ord("key"[0]) == 95))) and ((ord("key"[1]) == 95))) and ((ord("key"[(len("key") - 1)]) != 95)))) else "key")),value)
|
||||||
setattr(_hx_filter,(("_hx_" + "root") if (("root" in python_Boot.keywords)) else (("_hx_" + "root") if (((((len("root") > 2) and ((ord("root"[0]) == 95))) and ((ord("root"[1]) == 95))) and ((ord("root"[(len("root") - 1)]) != 95)))) else "root")),value)
|
setattr(q,(("_hx_" + "value") if (("value" in python_Boot.keywords)) else (("_hx_" + "value") if (((((len("value") > 2) and ((ord("value"[0]) == 95))) and ((ord("value"[1]) == 95))) and ((ord("value"[(len("value") - 1)]) != 95)))) else "value")),v)
|
||||||
_this = _gthis.isExclude
|
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
|
||||||
if (_this.matchObj is not None):
|
|
||||||
_hx_str = HxString.substr(_hx_str,1,None)
|
|
||||||
_this = _gthis.isRoot
|
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
|
||||||
if (_this.matchObj is not None):
|
|
||||||
_hx_str = HxString.substr(_hx_str,1,None)
|
|
||||||
setattr(q,(("_hx_" + _hx_str) if ((_hx_str in python_Boot.keywords)) else (("_hx_" + _hx_str) if (((((len(_hx_str) > 2) and ((ord(_hx_str[0]) == 95))) and ((ord(_hx_str[1]) == 95))) and ((ord(_hx_str[(len(_hx_str) - 1)]) != 95)))) else _hx_str)),_hx_filter)
|
|
||||||
process = _hx_local_0
|
process = _hx_local_0
|
||||||
_g = 0
|
_g = 0
|
||||||
_g1 = len(token)
|
_g1 = len(token)
|
||||||
|
|
@ -1563,8 +1532,8 @@ class xrfragment_Query:
|
||||||
fails = 0
|
fails = 0
|
||||||
qualify = 0
|
qualify = 0
|
||||||
def _hx_local_2(expr):
|
def _hx_local_2(expr):
|
||||||
nonlocal fails
|
|
||||||
nonlocal conds
|
nonlocal conds
|
||||||
|
nonlocal fails
|
||||||
conds = (conds + 1)
|
conds = (conds + 1)
|
||||||
fails = (fails + (0 if expr else 1))
|
fails = (fails + (0 if expr else 1))
|
||||||
return expr
|
return expr
|
||||||
|
|
@ -1573,39 +1542,69 @@ class xrfragment_Query:
|
||||||
v = Reflect.field(self.q,value)
|
v = Reflect.field(self.q,value)
|
||||||
if (Reflect.field(v,property) is not None):
|
if (Reflect.field(v,property) is not None):
|
||||||
return Reflect.field(v,property)
|
return Reflect.field(v,property)
|
||||||
_g = 0
|
if Reflect.field(self.q,"expr"):
|
||||||
_g1 = python_Boot.fields(self.q)
|
f = Reflect.field(self.q,"expr")
|
||||||
while (_g < len(_g1)):
|
if (not Reflect.field(self.q,"show")):
|
||||||
k = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
|
if (((Reflect.field(f,"!=") is not None) and testprop((Std.string(value) == Std.string(Reflect.field(f,"!="))))) and exclude):
|
||||||
_g = (_g + 1)
|
qualify = (qualify + 1)
|
||||||
_hx_filter = Reflect.field(self.q,k)
|
else:
|
||||||
if (Reflect.field(_hx_filter,"rules") is None):
|
if ((Reflect.field(f,"*") is not None) and testprop((Std.parseFloat(value) is not None))):
|
||||||
continue
|
qualify = (qualify + 1)
|
||||||
rules = Reflect.field(_hx_filter,"rules")
|
if ((Reflect.field(f,">") is not None) and testprop((Std.parseFloat(value) >= Std.parseFloat(Reflect.field(f,">"))))):
|
||||||
_g2 = 0
|
qualify = (qualify + 1)
|
||||||
while (_g2 < len(rules)):
|
if ((Reflect.field(f,"<") is not None) and testprop((Std.parseFloat(value) <= Std.parseFloat(Reflect.field(f,"<"))))):
|
||||||
rule = (rules[_g2] if _g2 >= 0 and _g2 < len(rules) else None)
|
qualify = (qualify + 1)
|
||||||
_g2 = (_g2 + 1)
|
if ((Reflect.field(f,"=") is not None) and ((testprop((value == Reflect.field(f,"="))) or testprop((Std.parseFloat(value) == Std.parseFloat(Reflect.field(f,"="))))))):
|
||||||
if exclude:
|
qualify = (qualify + 1)
|
||||||
if (((Reflect.field(rule,"!=") is not None) and testprop((Std.string(value) == Std.string(Reflect.field(rule,"!="))))) and exclude):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
else:
|
|
||||||
if ((Reflect.field(rule,"*") is not None) and testprop((Std.parseFloat(value) is not None))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
if ((Reflect.field(rule,">") is not None) and testprop((Std.parseFloat(value) > Std.parseFloat(Reflect.field(rule,">"))))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
if ((Reflect.field(rule,"<") is not None) and testprop((Std.parseFloat(value) < Std.parseFloat(Reflect.field(rule,"<"))))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
if ((Reflect.field(rule,">=") is not None) and testprop((Std.parseFloat(value) >= Std.parseFloat(Reflect.field(rule,">="))))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
if ((Reflect.field(rule,"<=") is not None) and testprop((Std.parseFloat(value) <= Std.parseFloat(Reflect.field(rule,"<="))))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
if ((Reflect.field(rule,"=") is not None) and ((testprop((value == Reflect.field(rule,"="))) or testprop((Std.parseFloat(value) == Std.parseFloat(Reflect.field(rule,"="))))))):
|
|
||||||
qualify = (qualify + 1)
|
|
||||||
return (qualify > 0)
|
return (qualify > 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class xrfragment_Parser:
|
||||||
|
_hx_class_name = "xrfragment.Parser"
|
||||||
|
__slots__ = ()
|
||||||
|
_hx_statics = ["error", "debug", "parse"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse(key,value,store,index = None):
|
||||||
|
Frag = haxe_ds_StringMap()
|
||||||
|
Frag.h["#"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW) | xrfragment_XRF.PV_EXECUTE)
|
||||||
|
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
|
||||||
|
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
|
||||||
|
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
||||||
|
Frag.h["pos"] = (((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
|
||||||
|
Frag.h["rot"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
|
||||||
|
Frag.h["t"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_STRING) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
||||||
|
Frag.h["tv"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
|
||||||
|
Frag.h["namespace"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
||||||
|
Frag.h["SPDX"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
||||||
|
Frag.h["unit"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
||||||
|
Frag.h["description"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
|
||||||
|
Frag.h["session"] = (((((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA) | xrfragment_XRF.PROMPT)
|
||||||
|
keyStripped = xrfragment_XRF.operators.replace(key,"")
|
||||||
|
isPVDynamic = ((len(key) > 0) and (not (key in Frag.h)))
|
||||||
|
isPVDefault = (((len(value) == 0) and ((len(key) > 0))) and ((key == "#")))
|
||||||
|
if isPVDynamic:
|
||||||
|
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR),index)
|
||||||
|
v.validate(value)
|
||||||
|
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
|
||||||
|
return True
|
||||||
|
v = xrfragment_XRF(key,Frag.h.get(key,None),index)
|
||||||
|
if (key in Frag.h):
|
||||||
|
if (not v.validate(value)):
|
||||||
|
print(str((((("⚠ fragment '" + ("null" if key is None else key)) + "' has incompatible value (") + ("null" if value is None else value)) + ")")))
|
||||||
|
return False
|
||||||
|
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
|
||||||
|
if xrfragment_Parser.debug:
|
||||||
|
print(str(((("✔ " + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string))))
|
||||||
|
else:
|
||||||
|
if Std.isOfType(value,str):
|
||||||
|
v.guessType(v,value)
|
||||||
|
v.noXRF = True
|
||||||
|
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class xrfragment_URI:
|
class xrfragment_URI:
|
||||||
_hx_class_name = "xrfragment.URI"
|
_hx_class_name = "xrfragment.URI"
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
@ -1638,7 +1637,7 @@ class xrfragment_URI:
|
||||||
if (len(splitByEqual) > 1):
|
if (len(splitByEqual) > 1):
|
||||||
_this1 = regexPlus.split((splitByEqual[1] if 1 < len(splitByEqual) else None))
|
_this1 = regexPlus.split((splitByEqual[1] if 1 < len(splitByEqual) else None))
|
||||||
value = python_lib_urllib_Parse.unquote(" ".join([python_Boot.toString1(x1,'') for x1 in _this1]))
|
value = python_lib_urllib_Parse.unquote(" ".join([python_Boot.toString1(x1,'') for x1 in _this1]))
|
||||||
ok = xrfragment_Parser.parse(key,value,store)
|
ok = xrfragment_Parser.parse(key,value,store,i)
|
||||||
if ((_hx_filter is not None) and ((_hx_filter != 0))):
|
if ((_hx_filter is not None) and ((_hx_filter != 0))):
|
||||||
_g = 0
|
_g = 0
|
||||||
_g1 = python_Boot.fields(store)
|
_g1 = python_Boot.fields(store)
|
||||||
|
|
@ -1653,14 +1652,14 @@ class xrfragment_URI:
|
||||||
|
|
||||||
class xrfragment_XRF:
|
class xrfragment_XRF:
|
||||||
_hx_class_name = "xrfragment.XRF"
|
_hx_class_name = "xrfragment.XRF"
|
||||||
__slots__ = ("fragment", "flags", "x", "y", "z", "w", "color", "string", "int", "float", "query", "noXRF")
|
__slots__ = ("fragment", "flags", "index", "x", "y", "z", "w", "color", "string", "int", "float", "filter", "noXRF")
|
||||||
_hx_fields = ["fragment", "flags", "x", "y", "z", "w", "color", "string", "int", "float", "query", "noXRF"]
|
_hx_fields = ["fragment", "flags", "index", "x", "y", "z", "w", "color", "string", "int", "float", "filter", "noXRF"]
|
||||||
_hx_methods = ["is", "validate", "guessType"]
|
_hx_methods = ["is", "validate", "guessType"]
|
||||||
_hx_statics = ["ASSET", "PROP_BIND", "QUERY_OPERATOR", "PROMPT", "ROUNDROBIN", "NAVIGATOR", "METADATA", "PV_OVERRIDE", "PV_EXECUTE", "T_COLOR", "T_INT", "T_FLOAT", "T_VECTOR2", "T_VECTOR3", "T_URL", "T_PREDEFINED_VIEW", "T_STRING", "T_STRING_OBJ", "T_STRING_OBJ_PROP", "isColor", "isInt", "isFloat", "isVector", "isUrl", "isUrlOrPretypedView", "isString", "set", "unset"]
|
_hx_statics = ["ASSET", "PROP_BIND", "QUERY_OPERATOR", "PROMPT", "ROUNDROBIN", "NAVIGATOR", "METADATA", "PV_OVERRIDE", "PV_EXECUTE", "T_COLOR", "T_INT", "T_FLOAT", "T_VECTOR2", "T_VECTOR3", "T_URL", "T_PREDEFINED_VIEW", "T_STRING", "T_STRING_OBJ", "T_STRING_OBJ_PROP", "isColor", "isInt", "isFloat", "isVector", "isUrl", "isUrlOrPretypedView", "isString", "operators", "isProp", "isExclude", "isDeep", "isNumber", "set", "unset"]
|
||||||
|
|
||||||
def __init__(self,_fragment,_flags):
|
def __init__(self,_fragment,_flags,_index = None):
|
||||||
self.noXRF = None
|
self.noXRF = None
|
||||||
self.query = None
|
self.filter = None
|
||||||
self.float = None
|
self.float = None
|
||||||
self.int = None
|
self.int = None
|
||||||
self.string = None
|
self.string = None
|
||||||
|
|
@ -1671,6 +1670,7 @@ class xrfragment_XRF:
|
||||||
self.x = None
|
self.x = None
|
||||||
self.fragment = _fragment
|
self.fragment = _fragment
|
||||||
self.flags = _flags
|
self.flags = _flags
|
||||||
|
self.index = _index
|
||||||
|
|
||||||
def _hx_is(self,flag):
|
def _hx_is(self,flag):
|
||||||
if (not Std.isOfType(self.flags,Int)):
|
if (not Std.isOfType(self.flags,Int)):
|
||||||
|
|
@ -1679,41 +1679,45 @@ class xrfragment_XRF:
|
||||||
|
|
||||||
def validate(self,value):
|
def validate(self,value):
|
||||||
self.guessType(self,value)
|
self.guessType(self,value)
|
||||||
if (self.fragment == "q"):
|
|
||||||
self.query = xrfragment_Query(value).get()
|
|
||||||
ok = True
|
ok = True
|
||||||
if (((not self._hx_is(xrfragment_XRF.T_FLOAT)) and self._hx_is(xrfragment_XRF.T_VECTOR2)) and (not ((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float))))):
|
if (((not self._hx_is(xrfragment_XRF.T_FLOAT)) and self._hx_is(xrfragment_XRF.T_VECTOR2)) and (not ((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float))))):
|
||||||
ok = False
|
ok = False
|
||||||
if (((not self._hx_is(xrfragment_XRF.T_VECTOR2)) and self._hx_is(xrfragment_XRF.T_VECTOR3)) and (not (((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float)) and Std.isOfType(self.z,Float))))):
|
if (((not ((self._hx_is(xrfragment_XRF.T_VECTOR2) or self._hx_is(xrfragment_XRF.T_STRING)))) and self._hx_is(xrfragment_XRF.T_VECTOR3)) and (not (((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float)) and Std.isOfType(self.z,Float))))):
|
||||||
ok = False
|
ok = False
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def guessType(self,v,_hx_str):
|
def guessType(self,v,_hx_str):
|
||||||
v.string = _hx_str
|
v.string = _hx_str
|
||||||
if (len(_hx_str.split(",")) > 1):
|
if (not Std.isOfType(_hx_str,str)):
|
||||||
xyzw = _hx_str.split(",")
|
return
|
||||||
if (len(xyzw) > 0):
|
if (len(_hx_str) > 0):
|
||||||
v.x = Std.parseFloat((xyzw[0] if 0 < len(xyzw) else None))
|
if (len(_hx_str.split(",")) > 1):
|
||||||
if (len(xyzw) > 1):
|
xyzw = _hx_str.split(",")
|
||||||
v.y = Std.parseFloat((xyzw[1] if 1 < len(xyzw) else None))
|
if (len(xyzw) > 0):
|
||||||
if (len(xyzw) > 2):
|
v.x = Std.parseFloat((xyzw[0] if 0 < len(xyzw) else None))
|
||||||
v.z = Std.parseFloat((xyzw[2] if 2 < len(xyzw) else None))
|
if (len(xyzw) > 1):
|
||||||
if (len(xyzw) > 3):
|
v.y = Std.parseFloat((xyzw[1] if 1 < len(xyzw) else None))
|
||||||
v.w = Std.parseFloat((xyzw[3] if 3 < len(xyzw) else None))
|
if (len(xyzw) > 2):
|
||||||
_this = xrfragment_XRF.isColor
|
v.z = Std.parseFloat((xyzw[2] if 2 < len(xyzw) else None))
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
if (len(xyzw) > 3):
|
||||||
if (_this.matchObj is not None):
|
v.w = Std.parseFloat((xyzw[3] if 3 < len(xyzw) else None))
|
||||||
v.color = _hx_str
|
_this = xrfragment_XRF.isColor
|
||||||
_this = xrfragment_XRF.isFloat
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
if (_this.matchObj is not None):
|
||||||
if (_this.matchObj is not None):
|
v.color = _hx_str
|
||||||
v.x = Std.parseFloat(_hx_str)
|
_this = xrfragment_XRF.isFloat
|
||||||
v.float = v.x
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
_this = xrfragment_XRF.isInt
|
if (_this.matchObj is not None):
|
||||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
v.x = Std.parseFloat(_hx_str)
|
||||||
if (_this.matchObj is not None):
|
v.float = v.x
|
||||||
v.int = Std.parseInt(_hx_str)
|
_this = xrfragment_XRF.isInt
|
||||||
v.x = v.int
|
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||||
|
if (_this.matchObj is not None):
|
||||||
|
v.int = Std.parseInt(_hx_str)
|
||||||
|
v.x = v.int
|
||||||
|
v.filter = xrfragment_Filter(((HxOverrides.stringOrNull(v.fragment) + "=") + HxOverrides.stringOrNull(v.string)))
|
||||||
|
else:
|
||||||
|
v.filter = xrfragment_Filter(v.fragment)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set(flag,flags):
|
def set(flag,flags):
|
||||||
|
|
@ -1760,5 +1764,10 @@ xrfragment_XRF.isVector = EReg("([,]+|\\w)","")
|
||||||
xrfragment_XRF.isUrl = EReg("(://)?\\..*","")
|
xrfragment_XRF.isUrl = EReg("(://)?\\..*","")
|
||||||
xrfragment_XRF.isUrlOrPretypedView = EReg("(^#|://)?\\..*","")
|
xrfragment_XRF.isUrlOrPretypedView = EReg("(^#|://)?\\..*","")
|
||||||
xrfragment_XRF.isString = EReg(".*","")
|
xrfragment_XRF.isString = EReg(".*","")
|
||||||
|
xrfragment_XRF.operators = EReg("(^-|[\\*]+)","")
|
||||||
|
xrfragment_XRF.isProp = EReg("^.*=[><=]?","")
|
||||||
|
xrfragment_XRF.isExclude = EReg("^-","")
|
||||||
|
xrfragment_XRF.isDeep = EReg("\\*","")
|
||||||
|
xrfragment_XRF.isNumber = EReg("^[0-9\\.]+$","")
|
||||||
|
|
||||||
Test.main()
|
Test.main()
|
||||||
|
|
|
||||||
21
test/test.js
21
test/test.js
|
|
@ -1,21 +0,0 @@
|
||||||
|
|
||||||
// in the browser use this instead of require():
|
|
||||||
//
|
|
||||||
// <script src="dist/xrfragment.js"></script>
|
|
||||||
// <script>
|
|
||||||
// var XR = xrfragment;
|
|
||||||
// </script>
|
|
||||||
|
|
||||||
var XF = require('../dist/xrfragment').xrfragment
|
|
||||||
|
|
||||||
let print = (e) => console.log( JSON.stringify(e, null, 1) + "\n" )
|
|
||||||
|
|
||||||
print( XF.URI.parse('://foo.com/1.gltf#pos=1.0,2.0,3.0&q=-.foo&t=1,100',true) );
|
|
||||||
|
|
||||||
// query
|
|
||||||
let q = new XF.Query();
|
|
||||||
print( q.parse("-.foo -plane") )
|
|
||||||
print( q.parse("price:>2") )
|
|
||||||
|
|
||||||
frags = XF.URI.parse('#my_view&t=1,2')
|
|
||||||
console.dir(XF)
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#XR = require("../dist/xrfragment")
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# PYTHONPATH=./dist python test/test.py
|
|
||||||
|
|
||||||
from xrfragment import xrfragment_Query
|
|
||||||
|
|
||||||
q = xrfragment_Query(".foo")
|
|
||||||
|
|
||||||
print( q.toObject() )
|
|
||||||
Loading…
Add table
Reference in a new issue