build
This commit is contained in:
parent
29744defef
commit
9e1ea98b96
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
|||
delete opts.promise
|
||||
})
|
||||
}
|
||||
|
||||
xrf.addEventListener('reset', () => {
|
||||
// *TODO* do this nicely
|
||||
// xrf._listeners['renderPost'] = []
|
||||
// xrf._listeners['render'] = []
|
||||
})
|
||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
|||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||
xrf.add( xrf.interactive )
|
||||
xrf.layers = 0
|
||||
|
||||
// reset certain events
|
||||
xrf.emit('reset',{})
|
||||
// remove mixers
|
||||
xrf.mixers.map( (m) => m.stop())
|
||||
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
|||
xrf
|
||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||
.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
|
||||
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)
|
||||
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
|||
let url = v.string
|
||||
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
||||
opts.isLocal = v.string[0] == '#'
|
||||
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
||||
|
||||
if( opts.isLocal ){
|
||||
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) => {
|
||||
let {mesh} = opts
|
||||
let scene = model.scene
|
||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
||||
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||
//enableSourcePortation(scene)
|
||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||
// only add remote objects, because
|
||||
// local scene-objects are already added to scene
|
||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
||||
return
|
||||
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||
}else{
|
||||
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
||||
mesh.add(scene)
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
// flag everything isSRC & isXRF
|
||||
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
|
||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||
let {model,scene} = opts
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone()
|
||||
}
|
||||
_model.scenes = [_model.scene]
|
||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||
let {model,mesh,scene} = opts
|
||||
setTimeout( () => {
|
||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||
}
|
||||
_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
|
||||
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
|||
xrf.frag.src.filterScene = (scene,opts) => {
|
||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
xrf.filter.scene({scene,frag,reparent:true})
|
||||
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||
|
||||
if( !opts.isLocal ){
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
|||
xrf.filter.scene = function(opts){
|
||||
let {scene,frag} = opts
|
||||
|
||||
xrf.filter
|
||||
scene = xrf.filter
|
||||
.sort(frag) // get (sorted) filters from XR Fragments
|
||||
.process(frag,scene,opts) // show/hide things
|
||||
|
||||
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
|||
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){
|
||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||
const hasName = (m,name,filter) => m.name == name
|
||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||
|
||||
// utility functions
|
||||
const getOrCloneMaterial = (o) => {
|
||||
if( o.material ){
|
||||
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
|||
let obj
|
||||
frag.target = firstFilter
|
||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||
if(obj){
|
||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||
if(obj ){
|
||||
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
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
|
||||
return xrf.filter
|
||||
return scene
|
||||
}
|
||||
|
||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
let frag = xrf.URI.parse( url )
|
||||
|
||||
return
|
||||
|
||||
/* WebAudio: setup context via THREEjs */
|
||||
if( !camera.listener ){
|
||||
camera.listener = new THREE.AudioListener();
|
||||
// *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)
|
||||
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
}
|
||||
|
||||
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()
|
||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||
let hardcodedLoop = frag.t != undefined
|
||||
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
|
||||
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)
|
||||
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
}catch(e){ console.warn(e) }
|
||||
}
|
||||
mesh.add(sound)
|
||||
mesh.audio = sound
|
||||
});
|
||||
|
||||
mesh.audio = sound
|
||||
}
|
||||
|
||||
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/jpg
|
||||
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
|||
let {mesh,THREE} = opts
|
||||
let restrictTo3DBoundingBox = mesh.geometry
|
||||
|
||||
let renderEquirect = (texture) => {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
texture.needsUpdate = true
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.magFilter = THREE.NearestFilter
|
||||
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
|
||||
}
|
||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||
map: null,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
|
||||
let renderImage = (texture) => {
|
||||
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 = new xrf.THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
mesh.material.map = texture
|
||||
mesh.needsUpdate = true
|
||||
}
|
||||
|
||||
let onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
// detect equirectangular image
|
||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
||||
renderEquirect(texture)
|
||||
}else{
|
||||
renderImage(texture)
|
||||
}
|
||||
renderImage(texture)
|
||||
}
|
||||
|
||||
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){
|
||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||
|
||||
|
||||
mesh.portal = {
|
||||
pos: mesh.position.clone(),
|
||||
posWorld: new xrf.THREE.Vector3(),
|
||||
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
|||
cameraPosition: new THREE.Vector3(),
|
||||
raycaster: new THREE.Raycaster(),
|
||||
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)
|
||||
const addStencilFeature = (n) => {
|
||||
if( n.stencil ) return n // run once
|
||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
||||
if( !mesh.portal.isLens ){
|
||||
n.position.copy( sRef == 0 ? pos : newPos )
|
||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
||||
else n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
}
|
||||
)( n.position.clone(), n.scale.clone() )
|
||||
|
||||
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||
n.position.copy( newPos || pos )
|
||||
n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
// curry function
|
||||
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||
.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
|
||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||
mesh.portal.stencilObjects.children = stencilObjects
|
||||
|
||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||
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
|
||||
}
|
||||
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
|||
xrf.addEventListener('renderPost', (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 newPos = mesh.portal.posWorld
|
||||
let stencilObject = mesh.portal.stencilObject
|
||||
let newScale = mesh.scale
|
||||
let cameraDirection = mesh.portal.cameraDirection
|
||||
let cameraPosition = mesh.portal.cameraPosition
|
||||
let raycaster = mesh.portal.raycaster
|
||||
|
||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||
cam.getWorldPosition(cameraPosition)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
cam.getWorldDirection(cameraDirection)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
|
||||
// init
|
||||
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.autoClearDepth = false
|
||||
renderer.autoClearColor = false
|
||||
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
|||
renderer.autoClearDepth = true
|
||||
renderer.autoClearColor = 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
|
||||
|
||||
|
||||
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
|||
}
|
||||
mesh.portal.needUpdate = false
|
||||
})
|
||||
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.setupListeners()
|
||||
.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) => {
|
||||
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
|||
|
||||
xrf.addEventListener('parseModel',(opts) => {
|
||||
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
|
||||
|
||||
let loadVideo = (mimetype) => function(url,opts){
|
||||
|
@ -2335,9 +2337,20 @@ window.AFRAME.registerComponent('xrf', {
|
|||
// *TODO* this does not really belong here perhaps
|
||||
let blinkControls = document.querySelector('[blink-controls]')
|
||||
if( blinkControls ){
|
||||
blinkControls = blinkControls.components['blink-controls']
|
||||
blinkControls.defaultCollisionMeshes = xrf.getCollisionMeshes()
|
||||
blinkControls.update()
|
||||
let els = xrf.getCollisionMeshes()
|
||||
let invisible = false
|
||||
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) )
|
||||
})
|
||||
|
||||
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)
|
||||
.then( (model) => {
|
||||
let gets = [ ...document.querySelectorAll('[xrf-get]') ]
|
||||
|
@ -2657,9 +2663,10 @@ window.AFRAME.registerComponent('xrf-get', {
|
|||
|
||||
setTimeout( () => {
|
||||
|
||||
if( !this.mesh && this.el.className == "ray" ){
|
||||
if( !this.mesh ){
|
||||
let scene = AFRAME.XRF.scene
|
||||
let mesh = this.mesh = scene.getObjectByName(meshname);
|
||||
if( !this.el.className.match(/ray/) ) this.el.className += " ray"
|
||||
if (!mesh){
|
||||
console.error("mesh with name '"+meshname+"' not found in model")
|
||||
return;
|
||||
|
@ -2684,12 +2691,12 @@ window.AFRAME.registerComponent('xrf-get', {
|
|||
}
|
||||
this.el.setObject3D('mesh',mesh)
|
||||
if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
|
||||
}
|
||||
},500)
|
||||
}else console.warn("xrf-get ignore: "+JSON.stringify(this.data))
|
||||
}, evt && evt.timeout ? evt.timeout: 500)
|
||||
|
||||
})
|
||||
|
||||
this.el.emit("update")
|
||||
this.el.emit("update",{timeout:0})
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
|||
delete opts.promise
|
||||
})
|
||||
}
|
||||
|
||||
xrf.addEventListener('reset', () => {
|
||||
// *TODO* do this nicely
|
||||
// xrf._listeners['renderPost'] = []
|
||||
// xrf._listeners['render'] = []
|
||||
})
|
||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
|||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||
xrf.add( xrf.interactive )
|
||||
xrf.layers = 0
|
||||
|
||||
// reset certain events
|
||||
xrf.emit('reset',{})
|
||||
// remove mixers
|
||||
xrf.mixers.map( (m) => m.stop())
|
||||
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
|||
xrf
|
||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||
.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
|
||||
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)
|
||||
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
|||
let url = v.string
|
||||
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
||||
opts.isLocal = v.string[0] == '#'
|
||||
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
||||
|
||||
if( opts.isLocal ){
|
||||
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) => {
|
||||
let {mesh} = opts
|
||||
let scene = model.scene
|
||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
||||
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||
//enableSourcePortation(scene)
|
||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||
// only add remote objects, because
|
||||
// local scene-objects are already added to scene
|
||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
||||
return
|
||||
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||
}else{
|
||||
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
||||
mesh.add(scene)
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
// flag everything isSRC & isXRF
|
||||
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
|
||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||
let {model,scene} = opts
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone()
|
||||
}
|
||||
_model.scenes = [_model.scene]
|
||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||
let {model,mesh,scene} = opts
|
||||
setTimeout( () => {
|
||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||
}
|
||||
_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
|
||||
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
|||
xrf.frag.src.filterScene = (scene,opts) => {
|
||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
xrf.filter.scene({scene,frag,reparent:true})
|
||||
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||
|
||||
if( !opts.isLocal ){
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
|||
xrf.filter.scene = function(opts){
|
||||
let {scene,frag} = opts
|
||||
|
||||
xrf.filter
|
||||
scene = xrf.filter
|
||||
.sort(frag) // get (sorted) filters from XR Fragments
|
||||
.process(frag,scene,opts) // show/hide things
|
||||
|
||||
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
|||
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){
|
||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||
const hasName = (m,name,filter) => m.name == name
|
||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||
|
||||
// utility functions
|
||||
const getOrCloneMaterial = (o) => {
|
||||
if( o.material ){
|
||||
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
|||
let obj
|
||||
frag.target = firstFilter
|
||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||
if(obj){
|
||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||
if(obj ){
|
||||
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
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
|
||||
return xrf.filter
|
||||
return scene
|
||||
}
|
||||
|
||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
let frag = xrf.URI.parse( url )
|
||||
|
||||
return
|
||||
|
||||
/* WebAudio: setup context via THREEjs */
|
||||
if( !camera.listener ){
|
||||
camera.listener = new THREE.AudioListener();
|
||||
// *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)
|
||||
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
}
|
||||
|
||||
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()
|
||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||
let hardcodedLoop = frag.t != undefined
|
||||
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
|
||||
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)
|
||||
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
}catch(e){ console.warn(e) }
|
||||
}
|
||||
mesh.add(sound)
|
||||
mesh.audio = sound
|
||||
});
|
||||
|
||||
mesh.audio = sound
|
||||
}
|
||||
|
||||
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/jpg
|
||||
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
|||
let {mesh,THREE} = opts
|
||||
let restrictTo3DBoundingBox = mesh.geometry
|
||||
|
||||
let renderEquirect = (texture) => {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
texture.needsUpdate = true
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.magFilter = THREE.NearestFilter
|
||||
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
|
||||
}
|
||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||
map: null,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
|
||||
let renderImage = (texture) => {
|
||||
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 = new xrf.THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
mesh.material.map = texture
|
||||
mesh.needsUpdate = true
|
||||
}
|
||||
|
||||
let onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
// detect equirectangular image
|
||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
||||
renderEquirect(texture)
|
||||
}else{
|
||||
renderImage(texture)
|
||||
}
|
||||
renderImage(texture)
|
||||
}
|
||||
|
||||
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){
|
||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||
|
||||
|
||||
mesh.portal = {
|
||||
pos: mesh.position.clone(),
|
||||
posWorld: new xrf.THREE.Vector3(),
|
||||
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
|||
cameraPosition: new THREE.Vector3(),
|
||||
raycaster: new THREE.Raycaster(),
|
||||
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)
|
||||
const addStencilFeature = (n) => {
|
||||
if( n.stencil ) return n // run once
|
||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
||||
if( !mesh.portal.isLens ){
|
||||
n.position.copy( sRef == 0 ? pos : newPos )
|
||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
||||
else n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
}
|
||||
)( n.position.clone(), n.scale.clone() )
|
||||
|
||||
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||
n.position.copy( newPos || pos )
|
||||
n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
// curry function
|
||||
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||
.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
|
||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||
mesh.portal.stencilObjects.children = stencilObjects
|
||||
|
||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||
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
|
||||
}
|
||||
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
|||
xrf.addEventListener('renderPost', (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 newPos = mesh.portal.posWorld
|
||||
let stencilObject = mesh.portal.stencilObject
|
||||
let newScale = mesh.scale
|
||||
let cameraDirection = mesh.portal.cameraDirection
|
||||
let cameraPosition = mesh.portal.cameraPosition
|
||||
let raycaster = mesh.portal.raycaster
|
||||
|
||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||
cam.getWorldPosition(cameraPosition)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
cam.getWorldDirection(cameraDirection)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
|
||||
// init
|
||||
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.autoClearDepth = false
|
||||
renderer.autoClearColor = false
|
||||
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
|||
renderer.autoClearDepth = true
|
||||
renderer.autoClearColor = 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
|
||||
|
||||
|
||||
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
|||
}
|
||||
mesh.portal.needUpdate = false
|
||||
})
|
||||
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.setupListeners()
|
||||
.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) => {
|
||||
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
|||
|
||||
xrf.addEventListener('parseModel',(opts) => {
|
||||
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
|
||||
|
||||
let loadVideo = (mimetype) => function(url,opts){
|
||||
|
|
|
@ -677,6 +677,12 @@ xrf.emit.promise = function(e, opts){
|
|||
delete opts.promise
|
||||
})
|
||||
}
|
||||
|
||||
xrf.addEventListener('reset', () => {
|
||||
// *TODO* do this nicely
|
||||
// xrf._listeners['renderPost'] = []
|
||||
// xrf._listeners['render'] = []
|
||||
})
|
||||
/*! rasterizeHTML.js - v1.3.1 - 2023-07-06
|
||||
* http://www.github.com/cburgmer/rasterizeHTML.js
|
||||
* Copyright (c) 2023 Christoph Burgmer; Licensed MIT */
|
||||
|
@ -914,6 +920,8 @@ xrf.reset = () => {
|
|||
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
||||
xrf.add( xrf.interactive )
|
||||
xrf.layers = 0
|
||||
|
||||
// reset certain events
|
||||
xrf.emit('reset',{})
|
||||
// remove mixers
|
||||
xrf.mixers.map( (m) => m.stop())
|
||||
|
@ -1083,6 +1091,13 @@ xrf.frag.href = function(v, opts){
|
|||
xrf
|
||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||
.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
|
||||
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)
|
||||
|
@ -1178,6 +1193,7 @@ xrf.frag.src = function(v, opts){
|
|||
let url = v.string
|
||||
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
||||
opts.isLocal = v.string[0] == '#'
|
||||
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
||||
|
||||
if( opts.isLocal ){
|
||||
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) => {
|
||||
let {mesh} = opts
|
||||
let scene = model.scene
|
||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
||||
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||
//enableSourcePortation(scene)
|
||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||
// only add remote objects, because
|
||||
// local scene-objects are already added to scene
|
||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
||||
return
|
||||
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||
}else{
|
||||
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
||||
mesh.add(scene)
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
// flag everything isSRC & isXRF
|
||||
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
||||
xrf.emit('parseModel', {...opts, scene, model})
|
||||
}
|
||||
|
||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||
|
@ -1248,13 +1263,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||
let {model,scene} = opts
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone()
|
||||
}
|
||||
_model.scenes = [_model.scene]
|
||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||
let {model,mesh,scene} = opts
|
||||
setTimeout( () => {
|
||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||
let _model = {
|
||||
animations: model.animations,
|
||||
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||
}
|
||||
_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
|
||||
|
@ -1292,12 +1310,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
|||
xrf.frag.src.filterScene = (scene,opts) => {
|
||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
xrf.filter.scene({scene,frag,reparent:true})
|
||||
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||
|
||||
if( !opts.isLocal ){
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1656,7 +1676,7 @@ xrf.filter = function(query, cb){
|
|||
xrf.filter.scene = function(opts){
|
||||
let {scene,frag} = opts
|
||||
|
||||
xrf.filter
|
||||
scene = xrf.filter
|
||||
.sort(frag) // get (sorted) filters from XR Fragments
|
||||
.process(frag,scene,opts) // show/hide things
|
||||
|
||||
|
@ -1673,12 +1693,14 @@ xrf.filter.sort = function(frag){
|
|||
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){
|
||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||
const hasName = (m,name,filter) => m.name == name
|
||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||
|
||||
// utility functions
|
||||
const getOrCloneMaterial = (o) => {
|
||||
if( o.material ){
|
||||
|
@ -1702,10 +1724,18 @@ xrf.filter.process = function(frag,scene,opts){
|
|||
let obj
|
||||
frag.target = firstFilter
|
||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||
if(obj){
|
||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||
if(obj ){
|
||||
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
|
||||
scene.traverse( (m) => {
|
||||
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
|
||||
})
|
||||
|
||||
return xrf.filter
|
||||
return scene
|
||||
}
|
||||
|
||||
xrf.frag.defaultPredefinedViews = (opts) => {
|
||||
|
@ -1873,13 +1903,11 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||
let frag = xrf.URI.parse( url )
|
||||
|
||||
return
|
||||
|
||||
/* WebAudio: setup context via THREEjs */
|
||||
if( !camera.listener ){
|
||||
camera.listener = new THREE.AudioListener();
|
||||
// *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)
|
||||
|
@ -1899,35 +1927,35 @@ let loadAudio = (mimetype) => function(url,opts){
|
|||
}
|
||||
|
||||
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()
|
||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||
let hardcodedLoop = frag.t != undefined
|
||||
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
|
||||
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)
|
||||
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
|
||||
if( t.y != undefined ){
|
||||
sound.setLoopStart( loopStart )
|
||||
sound.offset = loopStart
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
sound.play()
|
||||
}
|
||||
}catch(e){ console.warn(e) }
|
||||
}
|
||||
mesh.add(sound)
|
||||
mesh.audio = sound
|
||||
});
|
||||
|
||||
mesh.audio = sound
|
||||
}
|
||||
|
||||
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/jpg
|
||||
|
@ -1978,55 +2018,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
|||
let {mesh,THREE} = opts
|
||||
let restrictTo3DBoundingBox = mesh.geometry
|
||||
|
||||
let renderEquirect = (texture) => {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
texture.needsUpdate = true
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.magFilter = THREE.NearestFilter
|
||||
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
|
||||
}
|
||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||
map: null,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
|
||||
let renderImage = (texture) => {
|
||||
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 = new xrf.THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: url.match(/(png|gif)/) ? true : false,
|
||||
side: THREE.DoubleSide,
|
||||
color: 0xFFFFFF,
|
||||
opacity:1
|
||||
});
|
||||
mesh.material.map = texture
|
||||
mesh.needsUpdate = true
|
||||
}
|
||||
|
||||
let onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.wrapS = THREE.RepeatWrapping;
|
||||
texture.wrapT = THREE.RepeatWrapping;
|
||||
// detect equirectangular image
|
||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
||||
renderEquirect(texture)
|
||||
}else{
|
||||
renderImage(texture)
|
||||
}
|
||||
renderImage(texture)
|
||||
}
|
||||
|
||||
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){
|
||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||
|
||||
|
||||
mesh.portal = {
|
||||
pos: mesh.position.clone(),
|
||||
posWorld: new xrf.THREE.Vector3(),
|
||||
|
@ -2087,22 +2075,24 @@ xrf.portalNonEuclidian = function(opts){
|
|||
cameraPosition: new THREE.Vector3(),
|
||||
raycaster: new THREE.Raycaster(),
|
||||
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)
|
||||
const addStencilFeature = (n) => {
|
||||
if( n.stencil ) return n // run once
|
||||
n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => {
|
||||
if( !mesh.portal.isLens ){
|
||||
n.position.copy( sRef == 0 ? pos : newPos )
|
||||
if( sRef > 0 ) n.scale.multiply( newScale )
|
||||
else n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
}
|
||||
)( n.position.clone(), n.scale.clone() )
|
||||
|
||||
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
|
||||
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
|
||||
n.position.copy( newPos || pos )
|
||||
n.scale.copy( scale )
|
||||
n.updateMatrixWorld(true)
|
||||
}
|
||||
// curry function
|
||||
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -2126,23 +2116,12 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||
.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
|
||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||
mesh.portal.stencilObjects.children = stencilObjects
|
||||
|
||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||
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
|
||||
}
|
||||
|
@ -2162,22 +2141,23 @@ xrf.portalNonEuclidian = function(opts){
|
|||
xrf.addEventListener('renderPost', (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 newPos = mesh.portal.posWorld
|
||||
let stencilObject = mesh.portal.stencilObject
|
||||
let newScale = mesh.scale
|
||||
let cameraDirection = mesh.portal.cameraDirection
|
||||
let cameraPosition = mesh.portal.cameraPosition
|
||||
let raycaster = mesh.portal.raycaster
|
||||
|
||||
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
|
||||
cam.getWorldPosition(cameraPosition)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
cam.getWorldDirection(cameraDirection)
|
||||
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
|
||||
|
||||
// init
|
||||
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.autoClearDepth = false
|
||||
renderer.autoClearColor = false
|
||||
|
@ -2189,7 +2169,7 @@ xrf.portalNonEuclidian = function(opts){
|
|||
renderer.autoClearDepth = true
|
||||
renderer.autoClearColor = 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
|
||||
|
||||
|
||||
|
@ -2207,6 +2187,9 @@ xrf.portalNonEuclidian = function(opts){
|
|||
}
|
||||
mesh.portal.needUpdate = false
|
||||
})
|
||||
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -2220,6 +2203,8 @@ xrf.portalNonEuclidian = function(opts){
|
|||
.setupListeners()
|
||||
.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) => {
|
||||
|
@ -2248,10 +2233,27 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
|||
|
||||
xrf.addEventListener('parseModel',(opts) => {
|
||||
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
|
||||
|
||||
let loadVideo = (mimetype) => function(url,opts){
|
||||
|
|
|
@ -49,6 +49,13 @@
|
|||
window.$ = (s) => document.querySelector(s)
|
||||
if( document.location.search.length > 2 )
|
||||
$('#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', () => {
|
||||
|
@ -58,7 +65,7 @@
|
|||
|
||||
// reroute console messages to snackbar notifications
|
||||
console.log = ( (log) => function(str){
|
||||
if( String(str).match(/:.*#/) ) window.notify(str)
|
||||
if( String(str).match(/(:.*#|note:)/) ) window.notify(str)
|
||||
log(str)
|
||||
})(console.log)
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ input[type="submit"] {
|
|||
}
|
||||
|
||||
#overlay{
|
||||
background: #FFF;
|
||||
background: #FFFb;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -72,6 +72,20 @@ Reflect.deleteField = function(o,field) {
|
|||
delete(o[field]);
|
||||
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() { };
|
||||
Std.__name__ = true;
|
||||
Std.string = function(s) {
|
||||
|
@ -133,40 +147,38 @@ StringTools.trim = function(s) {
|
|||
var Test = function() { };
|
||||
Test.__name__ = true;
|
||||
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("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("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"}]);
|
||||
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**"}]);
|
||||
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) {
|
||||
console.log("src/Test.hx:28:","\n[.] running " + topic);
|
||||
var Query = xrfragment_Query;
|
||||
console.log("src/Test.hx:27:","\n[.] running " + topic);
|
||||
var Filter = xrfragment_Filter;
|
||||
var _g = 0;
|
||||
var _g1 = spec.length;
|
||||
while(_g < _g1) {
|
||||
var i = _g++;
|
||||
var q = null;
|
||||
var f = null;
|
||||
var res = null;
|
||||
var valid = false;
|
||||
var item = spec[i];
|
||||
if(item.fn == "query") {
|
||||
q = new xrfragment_Query(item.data);
|
||||
}
|
||||
if(item.fn == "url") {
|
||||
res = xrfragment_URI.parse(item.data,0);
|
||||
}
|
||||
f = new xrfragment_Filter(item.data);
|
||||
res = xrfragment_URI.parse(item.data,null);
|
||||
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") {
|
||||
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") {
|
||||
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") {
|
||||
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") {
|
||||
valid = Test.equalXYZ(res,item);
|
||||
}
|
||||
if(item.expect.fn == "testQueryRoot") {
|
||||
valid = item.expect.out == q.get()[item.expect.input[0]].root;
|
||||
if(item.expect.fn == "testFilterRoot") {
|
||||
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 ? "[ ✔ ] " : "[ ❌] ";
|
||||
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) {
|
||||
Test.errors += 1;
|
||||
}
|
||||
|
@ -315,83 +330,22 @@ js_Boot.__string_rec = function(o,s) {
|
|||
return String(o);
|
||||
}
|
||||
};
|
||||
var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { };
|
||||
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("^.*:[><=!]?","");
|
||||
var xrfragment_Filter = $hx_exports["xrfragment"]["Filter"] = function(str) {
|
||||
this.q = { };
|
||||
this.str = "";
|
||||
if(str != null) {
|
||||
this.parse(str);
|
||||
}
|
||||
};
|
||||
xrfragment_Query.__name__ = true;
|
||||
xrfragment_Query.prototype = {
|
||||
xrfragment_Filter.__name__ = true;
|
||||
xrfragment_Filter.prototype = {
|
||||
toObject: function() {
|
||||
return this.q;
|
||||
return Reflect.copy(this.q);
|
||||
}
|
||||
,get: function() {
|
||||
return this.q;
|
||||
return Reflect.copy(this.q);
|
||||
}
|
||||
,parse: function(str) {
|
||||
var _gthis = this;
|
||||
var token = str.split(" ");
|
||||
var q = { };
|
||||
var process = function(str,prefix) {
|
||||
|
@ -399,59 +353,42 @@ xrfragment_Query.prototype = {
|
|||
prefix = "";
|
||||
}
|
||||
str = StringTools.trim(str);
|
||||
var k = str.split(":")[0];
|
||||
var v = str.split(":")[1];
|
||||
var k = str.split("=")[0];
|
||||
var v = str.split("=")[1];
|
||||
var filter = { };
|
||||
if(q[prefix + k]) {
|
||||
filter = q[prefix + k];
|
||||
}
|
||||
filter["rules"] = filter["rules"] != null ? filter["rules"] : [];
|
||||
if(_gthis.isProp.match(str)) {
|
||||
if(xrfragment_XRF.isProp.match(str)) {
|
||||
var oper = "";
|
||||
if(str.indexOf("*") != -1) {
|
||||
oper = "*";
|
||||
}
|
||||
if(str.indexOf(">") != -1) {
|
||||
oper = ">";
|
||||
}
|
||||
if(str.indexOf("<") != -1) {
|
||||
oper = "<";
|
||||
}
|
||||
if(str.indexOf(">=") != -1) {
|
||||
oper = ">=";
|
||||
}
|
||||
if(str.indexOf("<=") != -1) {
|
||||
oper = "<=";
|
||||
}
|
||||
if(_gthis.isExclude.match(k)) {
|
||||
oper = "!=";
|
||||
if(xrfragment_XRF.isExclude.match(k)) {
|
||||
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) {
|
||||
oper = "=";
|
||||
}
|
||||
var rule = { };
|
||||
if(_gthis.isNumber.match(v)) {
|
||||
if(xrfragment_XRF.isNumber.match(v)) {
|
||||
rule[oper] = parseFloat(v);
|
||||
} else {
|
||||
rule[oper] = v;
|
||||
}
|
||||
filter["rules"].push(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;
|
||||
q["expr"] = rule;
|
||||
}
|
||||
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 _g1 = token.length;
|
||||
|
@ -500,49 +437,75 @@ xrfragment_Query.prototype = {
|
|||
return v[property];
|
||||
}
|
||||
}
|
||||
var _g = 0;
|
||||
var _g1 = Reflect.fields(this.q);
|
||||
while(_g < _g1.length) {
|
||||
var k = _g1[_g];
|
||||
++_g;
|
||||
var filter = Reflect.field(this.q,k);
|
||||
if(filter.rules == null) {
|
||||
continue;
|
||||
}
|
||||
var rules = filter.rules;
|
||||
var _g2 = 0;
|
||||
while(_g2 < rules.length) {
|
||||
var rule = rules[_g2];
|
||||
++_g2;
|
||||
if(exclude) {
|
||||
if(Reflect.field(rule,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(rule,"!="))) && exclude) {
|
||||
++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;
|
||||
}
|
||||
if(Reflect.field(this.q,"expr")) {
|
||||
var f = Reflect.field(this.q,"expr");
|
||||
if(!Reflect.field(this.q,"show")) {
|
||||
if(Reflect.field(f,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(f,"!="))) && exclude) {
|
||||
++qualify;
|
||||
}
|
||||
} else {
|
||||
if(Reflect.field(f,"*") != null && testprop(parseFloat(value) != null)) {
|
||||
++qualify;
|
||||
}
|
||||
if(Reflect.field(f,">") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(f,">")))) {
|
||||
++qualify;
|
||||
}
|
||||
if(Reflect.field(f,"<") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(f,"<")))) {
|
||||
++qualify;
|
||||
}
|
||||
if(Reflect.field(f,"=") != null && (testprop(value == Reflect.field(f,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(f,"="))))) {
|
||||
++qualify;
|
||||
}
|
||||
}
|
||||
}
|
||||
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() { };
|
||||
xrfragment_URI.__name__ = true;
|
||||
xrfragment_URI.parse = function(url,filter) {
|
||||
|
@ -564,7 +527,7 @@ xrfragment_URI.parse = function(url,filter) {
|
|||
var s = regexPlus.split(splitByEqual[1]).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) {
|
||||
var _g = 0;
|
||||
|
@ -580,9 +543,10 @@ xrfragment_URI.parse = function(url,filter) {
|
|||
}
|
||||
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.flags = _flags;
|
||||
this.index = _index;
|
||||
};
|
||||
xrfragment_XRF.__name__ = true;
|
||||
xrfragment_XRF.set = function(flag,flags) {
|
||||
|
@ -601,45 +565,50 @@ xrfragment_XRF.prototype = {
|
|||
}
|
||||
,validate: function(value) {
|
||||
this.guessType(this,value);
|
||||
if(this.fragment == "q") {
|
||||
this.query = new xrfragment_Query(value).get();
|
||||
}
|
||||
var ok = true;
|
||||
if(!this.is(xrfragment_XRF.T_FLOAT) && this.is(xrfragment_XRF.T_VECTOR2) && !(typeof(this.x) == "number" && typeof(this.y) == "number")) {
|
||||
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;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
,guessType: function(v,str) {
|
||||
v.string = str;
|
||||
if(str.split(",").length > 1) {
|
||||
var xyzw = str.split(",");
|
||||
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(typeof(str) != "string") {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
if(str.length > 0) {
|
||||
if(str.split(",").length > 1) {
|
||||
var xyzw = str.split(",");
|
||||
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)) {
|
||||
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.isUrlOrPretypedView = 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();
|
||||
})({});
|
||||
var xrfragment = $hx_exports["xrfragment"];
|
||||
|
|
|
@ -63,7 +63,7 @@ class EReg:
|
|||
_hx_class_name = "EReg"
|
||||
__slots__ = ("pattern", "matchObj", "_hx_global")
|
||||
_hx_fields = ["pattern", "matchObj", "global"]
|
||||
_hx_methods = ["split"]
|
||||
_hx_methods = ["split", "replace"]
|
||||
|
||||
def __init__(self,r,opt):
|
||||
self.matchObj = None
|
||||
|
@ -107,12 +107,35 @@ class EReg:
|
|||
else:
|
||||
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:
|
||||
_hx_class_name = "Reflect"
|
||||
__slots__ = ()
|
||||
_hx_statics = ["field", "deleteField"]
|
||||
_hx_statics = ["field", "deleteField", "copy"]
|
||||
|
||||
@staticmethod
|
||||
def field(o,field):
|
||||
|
@ -129,6 +152,20 @@ class Reflect:
|
|||
o.__delattr__(field)
|
||||
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:
|
||||
_hx_class_name = "Std"
|
||||
|
@ -385,37 +422,36 @@ class Test:
|
|||
|
||||
@staticmethod
|
||||
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("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("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"})])
|
||||
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**"})])
|
||||
if (Test.errors > 1):
|
||||
print(str((("\n-----\n[ ❌] " + Std.string(Test.errors)) + " errors :/")))
|
||||
|
||||
@staticmethod
|
||||
def test(topic,spec):
|
||||
print(str(("\n[.] running " + ("null" if topic is None else topic))))
|
||||
Query = xrfragment_Query
|
||||
Filter = xrfragment_Filter
|
||||
_g = 0
|
||||
_g1 = len(spec)
|
||||
while (_g < _g1):
|
||||
i = _g
|
||||
_g = (_g + 1)
|
||||
q = None
|
||||
f = None
|
||||
res = None
|
||||
valid = False
|
||||
item = (spec[i] if i >= 0 and i < len(spec) else None)
|
||||
if (Reflect.field(item,"fn") == "query"):
|
||||
q = xrfragment_Query(Reflect.field(item,"data"))
|
||||
if (Reflect.field(item,"fn") == "url"):
|
||||
res = xrfragment_URI.parse(Reflect.field(item,"data"),0)
|
||||
f = xrfragment_Filter(Reflect.field(item,"data"))
|
||||
res = xrfragment_URI.parse(Reflect.field(item,"data"),None)
|
||||
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"):
|
||||
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"):
|
||||
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"):
|
||||
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"):
|
||||
|
@ -434,8 +470,10 @@ class Test:
|
|||
valid = Test.equalXY(res,item)
|
||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "equal.xyz"):
|
||||
valid = Test.equalXYZ(res,item)
|
||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testQueryRoot"):
|
||||
valid = (Reflect.field(Reflect.field(item,"expect"),"out") == HxOverrides.arrayGet(q.get(), HxOverrides.arrayGet(Reflect.field(Reflect.field(item,"expect"),"input"), 0)).root)
|
||||
if (Reflect.field(Reflect.field(item,"expect"),"fn") == "testFilterRoot"):
|
||||
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 "[ ❌] ")
|
||||
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):
|
||||
|
@ -1078,7 +1116,11 @@ class python_HaxeIterator:
|
|||
class python_internal_ArrayImpl:
|
||||
_hx_class_name = "python.internal.ArrayImpl"
|
||||
__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
|
||||
def concat(a1,a2):
|
||||
|
@ -1214,7 +1256,7 @@ class python_internal_ArrayImpl:
|
|||
class HxOverrides:
|
||||
_hx_class_name = "HxOverrides"
|
||||
__slots__ = ()
|
||||
_hx_statics = ["eq", "stringOrNull", "push", "arrayGet"]
|
||||
_hx_statics = ["eq", "stringOrNull", "filter", "length", "arrayGet"]
|
||||
|
||||
@staticmethod
|
||||
def eq(a,b):
|
||||
|
@ -1230,12 +1272,18 @@ class HxOverrides:
|
|||
return s
|
||||
|
||||
@staticmethod
|
||||
def push(x,e):
|
||||
def filter(x,f):
|
||||
if isinstance(x,list):
|
||||
_this = x
|
||||
_this.append(e)
|
||||
return len(_this)
|
||||
return x.push(e)
|
||||
return list(filter(f,x))
|
||||
return x.filter(f)
|
||||
|
||||
@staticmethod
|
||||
def length(x):
|
||||
if isinstance(x,str):
|
||||
return len(x)
|
||||
elif isinstance(x,list):
|
||||
return len(x)
|
||||
return x.length
|
||||
|
||||
@staticmethod
|
||||
def arrayGet(a,i):
|
||||
|
@ -1267,7 +1315,7 @@ class python_internal_MethodClosure:
|
|||
class HxString:
|
||||
_hx_class_name = "HxString"
|
||||
__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
|
||||
def split(s,d):
|
||||
|
@ -1346,6 +1394,10 @@ class HxString:
|
|||
def toString(s):
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def get_length(s):
|
||||
return len(s)
|
||||
|
||||
@staticmethod
|
||||
def substring(s,startIndex,endIndex = None):
|
||||
if (startIndex < 0):
|
||||
|
@ -1374,156 +1426,73 @@ class HxString:
|
|||
return s[startIndex:(startIndex + _hx_len)]
|
||||
|
||||
|
||||
class xrfragment_Parser:
|
||||
_hx_class_name = "xrfragment.Parser"
|
||||
__slots__ = ()
|
||||
_hx_statics = ["error", "debug", "parse"]
|
||||
|
||||
@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"]
|
||||
class xrfragment_Filter:
|
||||
_hx_class_name = "xrfragment.Filter"
|
||||
__slots__ = ("str", "q")
|
||||
_hx_fields = ["str", "q"]
|
||||
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
|
||||
|
||||
def __init__(self,_hx_str):
|
||||
self.isNumber = EReg("^[0-9\\.]+$","")
|
||||
self.isRoot = EReg("^[-]?/","")
|
||||
self.isExclude = EReg("^-","")
|
||||
self.isProp = EReg("^.*:[><=!]?","")
|
||||
self.q = _hx_AnonObject({})
|
||||
self.str = ""
|
||||
if (_hx_str is not None):
|
||||
self.parse(_hx_str)
|
||||
|
||||
def toObject(self):
|
||||
return self.q
|
||||
return Reflect.copy(self.q)
|
||||
|
||||
def get(self):
|
||||
return self.q
|
||||
return Reflect.copy(self.q)
|
||||
|
||||
def parse(self,_hx_str):
|
||||
_gthis = self
|
||||
token = _hx_str.split(" ")
|
||||
q = _hx_AnonObject({})
|
||||
def _hx_local_0(_hx_str,prefix = None):
|
||||
if (prefix is None):
|
||||
prefix = ""
|
||||
_hx_str = StringTools.trim(_hx_str)
|
||||
k = HxOverrides.arrayGet(_hx_str.split(":"), 0)
|
||||
v = HxOverrides.arrayGet(_hx_str.split(":"), 1)
|
||||
k = HxOverrides.arrayGet(_hx_str.split("="), 0)
|
||||
v = HxOverrides.arrayGet(_hx_str.split("="), 1)
|
||||
_hx_filter = _hx_AnonObject({})
|
||||
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)))
|
||||
value = (Reflect.field(_hx_filter,"rules") if ((Reflect.field(_hx_filter,"rules") is not None)) else list())
|
||||
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 = xrfragment_XRF.isProp
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
if (_this.matchObj is not None):
|
||||
oper = ""
|
||||
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):
|
||||
oper = ">"
|
||||
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):
|
||||
oper = ">="
|
||||
startIndex = None
|
||||
if (((_hx_str.find("<=") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<=",startIndex))) != -1):
|
||||
oper = "<="
|
||||
_this = _gthis.isExclude
|
||||
_this = xrfragment_XRF.isExclude
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,k)
|
||||
if (_this.matchObj is not None):
|
||||
oper = "!="
|
||||
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):
|
||||
oper = "="
|
||||
rule = _hx_AnonObject({})
|
||||
_this = _gthis.isNumber
|
||||
_this = xrfragment_XRF.isNumber
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,v)
|
||||
if (_this.matchObj is not None):
|
||||
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)
|
||||
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)
|
||||
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(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)
|
||||
return
|
||||
else:
|
||||
_this = _gthis.isExclude
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
value = (False if ((_this.matchObj is not None)) else True)
|
||||
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)
|
||||
_this = _gthis.isRoot
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
value = (_this.matchObj is not None)
|
||||
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)
|
||||
_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)
|
||||
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)
|
||||
_this = xrfragment_XRF.isDeep
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
value = ((Reflect.field(k.split("*"),"length") - 1) if ((_this.matchObj is not None)) else 0)
|
||||
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 = xrfragment_XRF.isExclude
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
value = (False if ((_this.matchObj is not None)) else True)
|
||||
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)
|
||||
value = xrfragment_XRF.operators.replace(k,"")
|
||||
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(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)
|
||||
process = _hx_local_0
|
||||
_g = 0
|
||||
_g1 = len(token)
|
||||
|
@ -1563,8 +1532,8 @@ class xrfragment_Query:
|
|||
fails = 0
|
||||
qualify = 0
|
||||
def _hx_local_2(expr):
|
||||
nonlocal fails
|
||||
nonlocal conds
|
||||
nonlocal fails
|
||||
conds = (conds + 1)
|
||||
fails = (fails + (0 if expr else 1))
|
||||
return expr
|
||||
|
@ -1573,39 +1542,69 @@ class xrfragment_Query:
|
|||
v = Reflect.field(self.q,value)
|
||||
if (Reflect.field(v,property) is not None):
|
||||
return Reflect.field(v,property)
|
||||
_g = 0
|
||||
_g1 = python_Boot.fields(self.q)
|
||||
while (_g < len(_g1)):
|
||||
k = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
|
||||
_g = (_g + 1)
|
||||
_hx_filter = Reflect.field(self.q,k)
|
||||
if (Reflect.field(_hx_filter,"rules") is None):
|
||||
continue
|
||||
rules = Reflect.field(_hx_filter,"rules")
|
||||
_g2 = 0
|
||||
while (_g2 < len(rules)):
|
||||
rule = (rules[_g2] if _g2 >= 0 and _g2 < len(rules) else None)
|
||||
_g2 = (_g2 + 1)
|
||||
if exclude:
|
||||
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)
|
||||
if Reflect.field(self.q,"expr"):
|
||||
f = Reflect.field(self.q,"expr")
|
||||
if (not Reflect.field(self.q,"show")):
|
||||
if (((Reflect.field(f,"!=") is not None) and testprop((Std.string(value) == Std.string(Reflect.field(f,"!="))))) and exclude):
|
||||
qualify = (qualify + 1)
|
||||
else:
|
||||
if ((Reflect.field(f,"*") is not None) and testprop((Std.parseFloat(value) is not None))):
|
||||
qualify = (qualify + 1)
|
||||
if ((Reflect.field(f,">") is not None) and testprop((Std.parseFloat(value) >= Std.parseFloat(Reflect.field(f,">"))))):
|
||||
qualify = (qualify + 1)
|
||||
if ((Reflect.field(f,"<") is not None) and testprop((Std.parseFloat(value) <= Std.parseFloat(Reflect.field(f,"<"))))):
|
||||
qualify = (qualify + 1)
|
||||
if ((Reflect.field(f,"=") is not None) and ((testprop((value == Reflect.field(f,"="))) or testprop((Std.parseFloat(value) == Std.parseFloat(Reflect.field(f,"="))))))):
|
||||
qualify = (qualify + 1)
|
||||
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:
|
||||
_hx_class_name = "xrfragment.URI"
|
||||
__slots__ = ()
|
||||
|
@ -1638,7 +1637,7 @@ class xrfragment_URI:
|
|||
if (len(splitByEqual) > 1):
|
||||
_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]))
|
||||
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))):
|
||||
_g = 0
|
||||
_g1 = python_Boot.fields(store)
|
||||
|
@ -1653,14 +1652,14 @@ class xrfragment_URI:
|
|||
|
||||
class xrfragment_XRF:
|
||||
_hx_class_name = "xrfragment.XRF"
|
||||
__slots__ = ("fragment", "flags", "x", "y", "z", "w", "color", "string", "int", "float", "query", "noXRF")
|
||||
_hx_fields = ["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", "index", "x", "y", "z", "w", "color", "string", "int", "float", "filter", "noXRF"]
|
||||
_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.query = None
|
||||
self.filter = None
|
||||
self.float = None
|
||||
self.int = None
|
||||
self.string = None
|
||||
|
@ -1671,6 +1670,7 @@ class xrfragment_XRF:
|
|||
self.x = None
|
||||
self.fragment = _fragment
|
||||
self.flags = _flags
|
||||
self.index = _index
|
||||
|
||||
def _hx_is(self,flag):
|
||||
if (not Std.isOfType(self.flags,Int)):
|
||||
|
@ -1679,41 +1679,45 @@ class xrfragment_XRF:
|
|||
|
||||
def validate(self,value):
|
||||
self.guessType(self,value)
|
||||
if (self.fragment == "q"):
|
||||
self.query = xrfragment_Query(value).get()
|
||||
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))))):
|
||||
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
|
||||
return ok
|
||||
|
||||
def guessType(self,v,_hx_str):
|
||||
v.string = _hx_str
|
||||
if (len(_hx_str.split(",")) > 1):
|
||||
xyzw = _hx_str.split(",")
|
||||
if (len(xyzw) > 0):
|
||||
v.x = Std.parseFloat((xyzw[0] if 0 < len(xyzw) else None))
|
||||
if (len(xyzw) > 1):
|
||||
v.y = Std.parseFloat((xyzw[1] if 1 < len(xyzw) else None))
|
||||
if (len(xyzw) > 2):
|
||||
v.z = Std.parseFloat((xyzw[2] if 2 < len(xyzw) else None))
|
||||
if (len(xyzw) > 3):
|
||||
v.w = Std.parseFloat((xyzw[3] if 3 < len(xyzw) else None))
|
||||
_this = xrfragment_XRF.isColor
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
if (_this.matchObj is not None):
|
||||
v.color = _hx_str
|
||||
_this = xrfragment_XRF.isFloat
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
if (_this.matchObj is not None):
|
||||
v.x = Std.parseFloat(_hx_str)
|
||||
v.float = v.x
|
||||
_this = xrfragment_XRF.isInt
|
||||
_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
|
||||
if (not Std.isOfType(_hx_str,str)):
|
||||
return
|
||||
if (len(_hx_str) > 0):
|
||||
if (len(_hx_str.split(",")) > 1):
|
||||
xyzw = _hx_str.split(",")
|
||||
if (len(xyzw) > 0):
|
||||
v.x = Std.parseFloat((xyzw[0] if 0 < len(xyzw) else None))
|
||||
if (len(xyzw) > 1):
|
||||
v.y = Std.parseFloat((xyzw[1] if 1 < len(xyzw) else None))
|
||||
if (len(xyzw) > 2):
|
||||
v.z = Std.parseFloat((xyzw[2] if 2 < len(xyzw) else None))
|
||||
if (len(xyzw) > 3):
|
||||
v.w = Std.parseFloat((xyzw[3] if 3 < len(xyzw) else None))
|
||||
_this = xrfragment_XRF.isColor
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
if (_this.matchObj is not None):
|
||||
v.color = _hx_str
|
||||
_this = xrfragment_XRF.isFloat
|
||||
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
|
||||
if (_this.matchObj is not None):
|
||||
v.x = Std.parseFloat(_hx_str)
|
||||
v.float = v.x
|
||||
_this = xrfragment_XRF.isInt
|
||||
_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
|
||||
def set(flag,flags):
|
||||
|
@ -1760,5 +1764,10 @@ xrfragment_XRF.isVector = EReg("([,]+|\\w)","")
|
|||
xrfragment_XRF.isUrl = EReg("(://)?\\..*","")
|
||||
xrfragment_XRF.isUrlOrPretypedView = 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()
|
||||
|
|
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…
Reference in New Issue