2023-05-12 22:06:21 +02:00
|
|
|
let xrf = xrfragment
|
|
|
|
|
xrf.frag = {}
|
2023-05-17 21:31:28 +02:00
|
|
|
xrf.model = {}
|
2023-05-04 16:24:54 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.init = function(opts){
|
2023-05-04 16:24:54 +02:00
|
|
|
opts = opts || {}
|
2023-05-05 13:26:17 +02:00
|
|
|
let XRF = function(){
|
2023-05-08 14:21:28 +02:00
|
|
|
alert("queries are not implemented (yet)")
|
2023-05-05 13:26:17 +02:00
|
|
|
}
|
2023-05-12 22:06:21 +02:00
|
|
|
for ( let i in opts ) xrf[i] = opts[i]
|
|
|
|
|
for ( let i in xrf.XRF ) xrf.XRF[i] // shortcuts to constants (NAVIGATOR e.g.)
|
|
|
|
|
xrf.Parser.debug = xrf.debug
|
|
|
|
|
if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader )
|
2023-05-17 21:31:28 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchRenderer(opts.renderer)
|
2023-05-18 12:32:57 +02:00
|
|
|
xrf.navigator.init()
|
2023-05-12 22:06:21 +02:00
|
|
|
return xrf
|
2023-05-04 16:24:54 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchRenderer = function(renderer){
|
|
|
|
|
renderer.xr.addEventListener( 'sessionstart', () => xrf.baseReferenceSpace = renderer.xr.getReferenceSpace() );
|
|
|
|
|
renderer.xr.enabled = true;
|
2023-05-10 19:12:15 +02:00
|
|
|
renderer.render = ((render) => function(scene,camera){
|
2023-05-12 22:06:21 +02:00
|
|
|
if( xrf.model && xrf.model.render )
|
|
|
|
|
xrf.model.render(scene,camera)
|
2023-05-10 19:12:15 +02:00
|
|
|
render(scene,camera)
|
|
|
|
|
})(renderer.render.bind(renderer))
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchLoader = function(loader){
|
2023-05-04 16:24:54 +02:00
|
|
|
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
|
|
|
|
|
load.call( this,
|
|
|
|
|
url,
|
2023-05-12 22:06:21 +02:00
|
|
|
(model) => { onLoad(model); xrf.parseModel(model,url) },
|
2023-05-04 16:24:54 +02:00
|
|
|
onProgress,
|
|
|
|
|
onError)
|
|
|
|
|
})(loader.prototype.load)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
|
2023-05-05 18:53:42 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.parseModel = function(model,url){
|
|
|
|
|
let file = xrf.getFile(url)
|
2023-05-05 18:53:42 +02:00
|
|
|
model.file = file
|
|
|
|
|
model.render = function(){}
|
2023-05-18 17:11:11 +02:00
|
|
|
// eval embedded XR fragments
|
2023-05-17 21:31:28 +02:00
|
|
|
model.scene.traverse( (mesh) => xrf.eval.mesh(mesh,model) )
|
2023-05-04 16:24:54 +02:00
|
|
|
}
|
2023-05-09 17:42:29 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.getLastModel = () => xrf.model.last
|
2023-05-05 13:26:17 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.eval = function( url, model ){
|
2023-05-08 14:21:28 +02:00
|
|
|
let notice = false
|
2023-05-12 22:06:21 +02:00
|
|
|
model = model || xrf.model
|
|
|
|
|
let { THREE, camera } = xrf
|
|
|
|
|
let frag = xrf.URI.parse( url, xrf.XRF.NAVIGATOR )
|
2023-05-09 17:42:29 +02:00
|
|
|
let meshes = frag.q ? [] : [camera]
|
2023-05-08 14:21:28 +02:00
|
|
|
|
2023-05-09 17:42:29 +02:00
|
|
|
for ( let i in meshes ) {
|
|
|
|
|
for ( let k in frag ){
|
|
|
|
|
let mesh = meshes[i]
|
|
|
|
|
if( !String(k).match(/(pos|rot)/) ) notice = true
|
2023-05-12 22:06:21 +02:00
|
|
|
let opts = {frag, mesh, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
|
|
|
|
|
xrf.eval.fragment(k,opts)
|
2023-05-08 14:21:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( notice ) alert("only 'pos' and 'rot' XRF.NAVIGATOR-flagged XR fragments are supported (for now)")
|
2023-05-05 13:26:17 +02:00
|
|
|
}
|
2023-05-12 22:06:21 +02:00
|
|
|
|
|
|
|
|
xrf.eval.mesh = (mesh,model) => {
|
|
|
|
|
if( mesh.userData ){
|
|
|
|
|
let frag = {}
|
|
|
|
|
for( let k in mesh.userData ) xrf.Parser.parse( k, mesh.userData[k], frag )
|
|
|
|
|
for( let k in frag ){
|
|
|
|
|
let opts = {frag, mesh, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
|
2023-05-17 21:31:28 +02:00
|
|
|
mesh.userData.XRF = frag // allow fragment impl to access XRF obj already
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.eval.fragment(k,opts)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xrf.eval.fragment = (k, opts ) => {
|
|
|
|
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
|
|
|
|
let func = xrf.frag[k] || function(){}
|
|
|
|
|
if( xrf[k] ) xrf[k]( func, opts.frag[k], opts)
|
|
|
|
|
else func( opts.frag[k], opts)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xrf.reset = () => {
|
2023-05-17 21:31:28 +02:00
|
|
|
const disposeObject = (obj) => {
|
|
|
|
|
if (obj.children.length > 0) obj.children.forEach((child) => disposeObject(child));
|
|
|
|
|
if (obj.geometry) obj.geometry.dispose();
|
|
|
|
|
if (obj.material) {
|
|
|
|
|
if (obj.material.map) obj.material.map.dispose();
|
|
|
|
|
obj.material.dispose();
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
2023-05-18 12:32:57 +02:00
|
|
|
obj.parent.remove(obj)
|
|
|
|
|
console.log("removing "+(obj.type))
|
2023-05-17 21:31:28 +02:00
|
|
|
return true
|
|
|
|
|
};
|
2023-05-18 12:32:57 +02:00
|
|
|
let nodes = xrf.scene.children
|
|
|
|
|
for ( let i in nodes ) {
|
|
|
|
|
const child = nodes[i];
|
|
|
|
|
if( child.isXRF ){
|
|
|
|
|
disposeObject(child) // dont affect user objects
|
2023-05-17 21:31:28 +02:00
|
|
|
}
|
2023-05-18 12:32:57 +02:00
|
|
|
|
2023-05-17 21:31:28 +02:00
|
|
|
}
|
2023-05-18 12:32:57 +02:00
|
|
|
xrf.scene.remove(xrf.interactive) // why is this needed (again?)
|
|
|
|
|
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
|
|
|
|
xrf.add( xrf.interactive)
|
|
|
|
|
console.dir(xrf.scene)
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-17 21:31:28 +02:00
|
|
|
xrf.parseUrl = (url) => {
|
|
|
|
|
const urlObj = new URL( url.match(/:\/\//) ? url : String(`https://fake.com/${url}`).replace(/\/\//,'/') )
|
|
|
|
|
let dir = url.substring(0, url.lastIndexOf('/') + 1)
|
|
|
|
|
const file = urlObj.pathname.substring(urlObj.pathname.lastIndexOf('/') + 1);
|
|
|
|
|
const hash = url.match(/#/) ? url.replace(/.*#/,'') : ''
|
|
|
|
|
const ext = file.split('.').pop()
|
|
|
|
|
return {urlObj,dir,file,hash,ext}
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
2023-05-18 12:32:57 +02:00
|
|
|
|
|
|
|
|
xrf.add = (object) => {
|
|
|
|
|
object.isXRF = true // mark for easy deletion when replacing scene
|
|
|
|
|
xrf.scene.add(object)
|
|
|
|
|
}
|
2023-05-22 14:10:44 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* EVENTS
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
xrf.addEventListener = function(eventName, callback) {
|
|
|
|
|
if( !this._listeners ) this._listeners = []
|
|
|
|
|
if (!this._listeners[eventName]) {
|
|
|
|
|
// create a new array for this event name if it doesn't exist yet
|
|
|
|
|
this._listeners[eventName] = [];
|
|
|
|
|
}
|
|
|
|
|
// add the callback to the listeners array for this event name
|
|
|
|
|
this._listeners[eventName].push(callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
xrf.emit = function(eventName, data) {
|
|
|
|
|
if( !this._listeners ) this._listeners = []
|
|
|
|
|
var callbacks = this._listeners[eventName]
|
|
|
|
|
if (callbacks) {
|
|
|
|
|
for (var i = 0; i < callbacks.length; i++) {
|
|
|
|
|
callbacks[i](data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|