Merge branch 'main' into feat/src

This commit is contained in:
Leon van Kammen 2023-07-04 18:03:31 +02:00
commit 11edb4e963
13 changed files with 2932 additions and 65 deletions

View file

@ -851,6 +851,7 @@ xrf.patchRenderer = function(renderer){
}
xrf.patchLoader = function(loader){
if( loader.prototype.load.xrf_patched ) return // prevent patching aliased loaders twice
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this,
url,
@ -861,6 +862,7 @@ xrf.patchLoader = function(loader){
onProgress,
onError)
})(loader.prototype.load)
loader.prototype.load.xrf_patched = true
}
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
@ -951,7 +953,7 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,flags) => {
xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
@ -963,13 +965,17 @@ xrf.navigator.to = (url,flags) => {
}
if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false
if( !loader ){
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
xrf.reset() // clear xrf objects from scene
loader = loader || new Loader().setPath( dir )
}
// force relative path
if( dir ) dir = dir[0] == '.' ? dir : `.${dir}`
const loader = new Loader().setPath( dir )
loader.load( file, function(model){
loader = loader || new Loader().setPath( dir )
const onLoad = (model) => {
xrf.reset() // clear xrf objects from scene
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
@ -980,7 +986,10 @@ xrf.navigator.to = (url,flags) => {
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
}
if( data ) loader.parse(data, "", onLoad )
else loader.load(url, onLoad )
})
}
@ -1269,6 +1278,8 @@ xrf.frag.q = function(v, opts){
if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`)
if( i == '*' ){
let cloneScene = scene.clone()
// add interactive elements (href's e.g.)
v.scene.add( xrf.interactive.clone() )
cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) )
target.mesh = v.scene
}else{
@ -1344,12 +1355,10 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
m.isSRC = true
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )
@ -1392,7 +1401,10 @@ window.AFRAME.registerComponent('xrf', {
scene: aScene.object3D,
renderer: aScene.renderer,
debug: true,
loaders: { gltf: THREE.GLTFLoader } // which 3D assets (exts) to check for XR fragments?
loaders: {
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
glb: THREE.GLTFLoader
}
})
if( !XRF.camera ) throw 'xrfragment: no camera detected, please declare <a-entity camera..> ABOVE entities with xrf-attributes'

View file

@ -851,6 +851,7 @@ xrf.patchRenderer = function(renderer){
}
xrf.patchLoader = function(loader){
if( loader.prototype.load.xrf_patched ) return // prevent patching aliased loaders twice
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this,
url,
@ -861,6 +862,7 @@ xrf.patchLoader = function(loader){
onProgress,
onError)
})(loader.prototype.load)
loader.prototype.load.xrf_patched = true
}
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
@ -951,7 +953,7 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,flags) => {
xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
@ -963,13 +965,17 @@ xrf.navigator.to = (url,flags) => {
}
if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false
if( !loader ){
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
xrf.reset() // clear xrf objects from scene
loader = loader || new Loader().setPath( dir )
}
// force relative path
if( dir ) dir = dir[0] == '.' ? dir : `.${dir}`
const loader = new Loader().setPath( dir )
loader.load( file, function(model){
loader = loader || new Loader().setPath( dir )
const onLoad = (model) => {
xrf.reset() // clear xrf objects from scene
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
@ -980,7 +986,10 @@ xrf.navigator.to = (url,flags) => {
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
}
if( data ) loader.parse(data, "", onLoad )
else loader.load(url, onLoad )
})
}
@ -1269,6 +1278,8 @@ xrf.frag.q = function(v, opts){
if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`)
if( i == '*' ){
let cloneScene = scene.clone()
// add interactive elements (href's e.g.)
v.scene.add( xrf.interactive.clone() )
cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) )
target.mesh = v.scene
}else{
@ -1344,12 +1355,10 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
m.isSRC = true
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )

View file

@ -851,6 +851,7 @@ xrf.patchRenderer = function(renderer){
}
xrf.patchLoader = function(loader){
if( loader.prototype.load.xrf_patched ) return // prevent patching aliased loaders twice
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this,
url,
@ -861,6 +862,7 @@ xrf.patchLoader = function(loader){
onProgress,
onError)
})(loader.prototype.load)
loader.prototype.load.xrf_patched = true
}
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
@ -951,7 +953,7 @@ xrf.add = (object) => {
xrf.navigator = {}
xrf.navigator.to = (url,flags) => {
xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
@ -963,13 +965,17 @@ xrf.navigator.to = (url,flags) => {
}
if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false
if( !loader ){
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
xrf.reset() // clear xrf objects from scene
loader = loader || new Loader().setPath( dir )
}
// force relative path
if( dir ) dir = dir[0] == '.' ? dir : `.${dir}`
const loader = new Loader().setPath( dir )
loader.load( file, function(model){
loader = loader || new Loader().setPath( dir )
const onLoad = (model) => {
xrf.reset() // clear xrf objects from scene
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
@ -980,7 +986,10 @@ xrf.navigator.to = (url,flags) => {
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
}
if( data ) loader.parse(data, "", onLoad )
else loader.load(url, onLoad )
})
}
@ -1269,6 +1278,8 @@ xrf.frag.q = function(v, opts){
if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`)
if( i == '*' ){
let cloneScene = scene.clone()
// add interactive elements (href's e.g.)
v.scene.add( xrf.interactive.clone() )
cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) )
target.mesh = v.scene
}else{
@ -1344,12 +1355,10 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
m.isSRC = true
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )

View file

@ -19,8 +19,9 @@
<input type="submit" value="load 3D asset"></input>
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )"/>
</div>
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-aframe-helloworld">clone project</a>
<a class="btn-foot" id="model" target="_blank" href="">⬇️ model</a>
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-helloworld"> clone project</a>
<a class="btn-foot" id="embed" target="_blank" onclick="embed()">📺 embed</a>
<a class="btn-foot" id="model" target="_blank" href="example.gltf">⬇️ model</a>
<textarea style="display:none"></textarea>
<a-scene light="defaultLightsEnabled: false">
<a-entity id="player" wasd-controls look-controls>
@ -39,9 +40,10 @@
</a-scene>
<script type="module">
import { loadFile, setupConsole, setupUrlBar, notify } from './../../assets/js/utils.js';
import { loadFile, setupConsole, setupUrlBar, notify, embed } from './../../assets/js/utils.js';
window.$ = (s) => document.querySelector(s)
window.notify = notify(window)
window.embed = embed
console.log = ( (log) => function(str){
if( String(str).match(/:.*#/) ) window.notify(str)
log(str)
@ -64,6 +66,7 @@
const isExtern = url[0] != '#'
const notIsHome = url != $('#home').getAttribute("xrf")
const promise = e.promise() // promisify event
document.querySelector('#model').setAttribute('href',url.replace(/.*\?/,'') )
if( !renderer.xr.isPresenting ){
if( isExtern && notIsHome ){
if( !confirm("teleport to "+url+" ?") ) return promise.reject('teleport rejected')
@ -81,6 +84,13 @@
window.AFRAME.XRF.addEventListener('href', (data) => data.selected ? window.notify(`href: ${data.xrf.string}`) : false )
// enable user-uploaded asset files
let fileLoaders = loadFile({
".gltf": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null, (new xrf.loaders.gltf()), data) ),
".glb": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null, (new xrf.loaders.gltf()), data) )
})
$("#overlay > input[type=submit]").addEventListener("click", fileLoaders )
})
</script>
</body>

View file

@ -91,30 +91,29 @@ input[type="submit"] {
border-radius: 10px;
border: 5px solid #1c1c3299;
padding: 0px 6px;
bottom:73px;
position: absolute;
}
a.btn-foot#source{
right: 10px;
color: #888;
font-weight: bold;
font-family: sans-serif;
color: #7c7c7c;
z-index:2000;
cursor:pointer;
right: 10px;
}
a.btn-foot#embed{
color: #888;
bottom: 126px;
}
a.btn-foot#model{
position: absolute;
right: 10px;
color: #7c7c7c;
font-weight: bold;
font-family: sans-serif;
z-index:2000;
bottom:73px;
}
html.a-fullscreen a#model,
html.a-fullscreen a#source{
a.btn-foot#source{
bottom:179px;
}
html.a-fullscreen a.btn-foot {
margin-right:10px;
}

View file

@ -3,6 +3,7 @@
export function loadFile(contentLoaders, multiple){
return () => {
window.notify("if you're on Meta browser, file-uploads might be disabled")
let input = document.createElement('input');
input.type = 'file';
input.multiple = multiple;
@ -126,7 +127,7 @@ function SnackBar(userOptions) {
_Message = document.createElement("span");
_Message.classList.add("js-snackbar__message");
_Message.textContent = _Options.message;
_Message.innerHTML = _Options.message;
innerSnack.appendChild(_Message);
@ -265,3 +266,7 @@ export function notify(scope){
SnackBar( opts )
}
}
export function embed(){
window.notify(`copy/paste the following into your HTML:<br><br>&lt;iframe src='${document.location.href}'&gt;<br>&lt;/iframe&gt;<br>`,{timeout:null})
}

2798
example/assets/src.gltf Normal file

File diff suppressed because one or more lines are too long

View file

@ -13,8 +13,9 @@
<input type="submit" value="load 3D asset"></input>
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )"/>
</div>
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-three-helloworld">clone project</a>
<a class="btn-foot" id="model" target="_blank" href="">⬇️ model</a>
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-helloworld"> clone project</a>
<a class="btn-foot" id="embed" target="_blank" onclick="embed()">📺 embed</a>
<a class="btn-foot" id="model" target="_blank" href="example.gltf">⬇️ model</a>
<textarea style="display:none"></textarea>
<script async src="./../../assets/js/alpine.min.js"></script>
@ -125,7 +126,19 @@
window.XRF = XRF // expose to form
let file = document.location.search.length > 2 ? document.location.search.substr(1) + document.location.hash : 'example.gltf#pos=1,0,4&rot=0,-30,0'
$('#model').setAttribute("href","./../../asset/"+file)
// optional decoration of href event
XRF.addEventListener('href',(e) => {
if( e.click ){
const { mesh, model, camera, scene, renderer, THREE} = e.XRF
const url = e.xrf.string
const isExtern = url[0] != '#'
const promise = e.promise() // promisify event
document.querySelector('#model').setAttribute('href',url.replace(/.*\?/,'') )
promise.resolve()
}
})
XRF.navigator.to( file )
@ -208,8 +221,8 @@
})
let fileLoaders = loadFile({
".gltf": (file) => file.arrayBuffer().then( (data) => loader.parse( data, '', loadGLTF, console.error ) ),
".glb": (file) => file.arrayBuffer().then( (data) => loader.parse( data, '', loadGLTF, console.error ) )
".gltf": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null,xrf.loaders.gltf,data) ),
".glb": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null,xrf.loaders.gltf,data) )
})
$("#overlay > input[type=submit]").addEventListener("click", fileLoaders )

View file

@ -28,7 +28,10 @@ window.AFRAME.registerComponent('xrf', {
scene: aScene.object3D,
renderer: aScene.renderer,
debug: true,
loaders: { gltf: THREE.GLTFLoader } // which 3D assets (exts) to check for XR fragments?
loaders: {
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
glb: THREE.GLTFLoader
}
})
if( !XRF.camera ) throw 'xrfragment: no camera detected, please declare <a-entity camera..> ABOVE entities with xrf-attributes'

View file

@ -23,6 +23,7 @@ xrf.patchRenderer = function(renderer){
}
xrf.patchLoader = function(loader){
if( loader.prototype.load.xrf_patched ) return // prevent patching aliased loaders twice
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this,
url,
@ -33,6 +34,7 @@ xrf.patchLoader = function(loader){
onProgress,
onError)
})(loader.prototype.load)
loader.prototype.load.xrf_patched = true
}
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')

View file

@ -1,6 +1,6 @@
xrf.navigator = {}
xrf.navigator.to = (url,flags) => {
xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
return new Promise( (resolve,reject) => {
@ -12,13 +12,17 @@ xrf.navigator.to = (url,flags) => {
}
if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false
if( !loader ){
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
xrf.reset() // clear xrf objects from scene
loader = loader || new Loader().setPath( dir )
}
// force relative path
if( dir ) dir = dir[0] == '.' ? dir : `.${dir}`
const loader = new Loader().setPath( dir )
loader.load( file, function(model){
loader = loader || new Loader().setPath( dir )
const onLoad = (model) => {
xrf.reset() // clear xrf objects from scene
model.file = file
xrf.add( model.scene )
// only change url when loading *another* file
@ -29,7 +33,10 @@ xrf.navigator.to = (url,flags) => {
if( !hash.match(/pos=/) )
xrf.eval( '#pos=0,0,0' ) // set default position if not specified
resolve(model)
})
}
if( data ) loader.parse(data, "", onLoad )
else loader.load(url, onLoad )
})
}

View file

@ -13,6 +13,8 @@ xrf.frag.q = function(v, opts){
if( !scene.getObjectByName(i) && i != '*' ) return console.log(` └ mesh not found: ${i}`)
if( i == '*' ){
let cloneScene = scene.clone()
// add interactive elements (href's e.g.)
v.scene.add( xrf.interactive.clone() )
cloneScene.children.forEach( (child) => v.scene.getObjectByName(child.name) ? null : v.scene.add(child) )
target.mesh = v.scene
}else{

View file

@ -22,12 +22,10 @@ xrf.frag.src = function(v, opts){
console.log(" └ inserting "+i+" (srcScene)")
srcScene.position.set(0,0,0)
srcScene.rotation.set(0,0,0)
// add interactive elements (href's e.g.)
srcScene.add( xrf.interactive.clone() )
srcScene.traverse( (m) => {
m.isSRC = true
if( m.userData && (m.userData.src || m.userData.href) ) return ;//delete m.userData.src // prevent infinite recursion
xrf.eval.mesh(m,{scene,recursive:true})
m.isSRC = true
})
console.dir(xrf)
if( srcScene.visible ) src.add( srcScene )