Jean-Yves Didier

merge

import ARCS from '../build/arcs.js';
import ARCS from '../engine/arcs.js';
let Filter;
......@@ -30,13 +30,12 @@ Filter = ARCS.Component.create(
function(config) {
let self = this;
let _config = config || {};
self.signals = self.signals || {};
let _config = config ?? {};
//self.signal(self.signals);
if (_config.signals) {
_config.signals.forEach(e => {
self.signals[e] = [];
self.signal(e);
});
}
......@@ -44,9 +43,10 @@ Filter = ARCS.Component.create(
_config.slots.forEach(e => {
if (!e.slot || !e.func) return;
let slotName = e.slot;
let slotFunc = new Function('self',`return ${e.func}`)(self);
self.slots.push(slotName);
self[slotName] = slotFunc;
let slotFunc = Array.isArray(e.func)?
new Function('self',`return ${e.func.join(' ')}`)(self):
new Function('self',`return ${e.func}`)(self);
self.slot(slotName, slotFunc);
});
}
},
......
import ARCS from '../build/arcs.js';
var Logger;
let Logger;
var indexedDB = window.indexedDB;
const indexedDB = window.indexedDB;
// two modes: websockets or indexeddb
// the idea is to add a timestamp as well as a timestamp for the start of
......@@ -50,7 +50,18 @@ var toStructuredData = function( obj) {
return obj;
};
/**
* @class Logger
* @classdesc Logging system for ARCS.js
* @param [config] {object} configuration object for the logger
* @param [config.dbconfig] {object} use of indexedDB browser facility to record data
* @param [config.dbconfig.name="ARCS"] {string} database name
* @param [config.dbconfig.table="logtable"] {string} table name
* @param [config.dbconfig.clear] {boolean} if set to true, resets the table
* @param [config.server] {string} URL for websocket receiver. Can be used instead of database
* @param [config.slots] {Array.string} List of slots that need to be created.
* Each slot is then considered as an event to record when called.
*/
Logger = ARCS.Component.create(
function(obj) {
var i;
......
import ARCS from '../build/arcs.js';
import ARCS from '../engine/arcs.js';
let UIMapper ;
......@@ -6,17 +6,12 @@ let UIMapper ;
* UIMapperSlot
* An item describing a slot for an UIMapper component
* @typedef {Object} UIMapperSlot
* @property param {string} a string representing a parameter. It can reach
* subcomponents of an object by using the notation X.subcomp1.subcomp2 ...
* where X value is the position index of the parameter
* @property field {string} a string representing a reference to an HTML element
* and its subcomponents in the same way as the param property. However, the X
* component relates to a CSS selector (without CSS classes)
* @property format {string} a string representing code for a callback function.
* The callback should only expect one parameter, which is the value given by
* the parameter param
* @property value a value that should be injected by the slot to the HTML field.
* It can be used instead of param.
* @property index {number} the index of the slot parameter to use for the
* callback function
* @property selector {string} a CSS selector to target a DOM element
* @property func {string} a string representing code for a callback function.
* The callback function should expect two parameters, which are the
* DOM element and the parameter value
*/
/**
......@@ -45,54 +40,32 @@ UIMapper = ARCS.Component.create(
let self = this;
// returns a map function
const mapFunction = function(param, field, format, val) {
let params = param.split('.');
let func = null;
if (format !== undefined) {
func = new Function('self', `return ${format}`)(self);
}
let fields = field.split('.');
let eltField = document.querySelector(fields[0]);
for(let i=1; i < fields.length-1; i++) {
eltField = eltField[fields[i]];
}
return function() {
let value ;
if (val === undefined) {
value = arguments[params[0]];
for (let i=1; i < params.length; i++) {
value = value[params[i]];
}
} else {
value = val;
}
eltField[fields[fields.length-1]] = (func)?((typeof func === 'function')?func(value):func):value;
}
const mapFunction = function(index, selector, func) {
let elt = document.querySelector(selector);
let actualFunc = Array.isArray(func)?
new Function('self',`return ${func.join(' ')}`)(self):
new Function('self',`return ${func}`)(self);
return function() { actualFunc(elt,arguments[index]); };
};
obj = obj || {};
obj = obj ?? {};
if (obj.slots) {
for(let p in obj.slots) {
let slotName = p;
let slotFunction = function(pobj) {
let functions = pobj.map( elt => { return mapFunction(elt.index, elt.selector, elt.func) });
return function() {
pobj.map( elt => {
mapFunction(elt.param, elt.field,elt.format, elt.value).apply(null, arguments);
});
functions.forEach(f => { f.apply(null, arguments) });
};
}
if (self.slots.indexOf(slotName) < 0) {
self.slots.push(slotName);
self[slotName] = slotFunction(obj.slots[p]);
}
self.slot(slotName, slotFunction(obj.slots[p]));
};
}
self.signals = self.signals || {};
/*** SIGNALS PART **/
self.signals = self.signals ?? {};
let osignals = obj.signals;
......@@ -115,11 +88,12 @@ UIMapper = ARCS.Component.create(
}
if (domElt) {
domElt.addEventListener(signalDescr.event, self => {
domElt.addEventListener('beforexrselect', e => { e.preventDefault(); });
domElt.addEventListener(signalDescr.event, (() => {
return e => self.emit(s, e)
});
})());
}
self.signals[s] = [];
self.signal(s);
}
}
......
import ARCS from '../build/arcs.js';
import ARCS from '../engine/arcs.js';
import * as THREE from '../deps/three.js/index.js';
import {ARButton} from '../deps/three.js/ARButton.js';
......@@ -16,11 +16,14 @@ var XRViewer;
XRViewer = ARCS.Component.create(
/** @lends XRViewer.prototype */
function (config) {
let renderer, scene, camera;
let renderer, root, scene, camera;
let sceneId;
let container;
let self = this;
let defaultStyle;
let controller;
let button;
let binding;
let _config = config || {};
......@@ -39,16 +42,19 @@ XRViewer = ARCS.Component.create(
let firstFrame = true;
// scenegraph initializations
scene = new THREE.Scene();
root = new THREE.Scene();
scene = new THREE.Group();
root.add(scene);
renderer = new THREE.WebGLRenderer();
renderer = new THREE.WebGLRenderer({ alpha: true});
//renderer.setClearColor(0x000000, 1);
renderer.setSize(container.width, container.height);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.xr.enabled = true;
renderer.xr.cameraAutoUpdate = false;
//renderer.xr.cameraAutoUpdate = false;
container.appendChild(renderer.domElement);
rootOverlay.appendChild(ARButton.createButton(renderer,_config.sessionConfig));
button = ARButton.createButton(renderer,_config.sessionConfig);
rootOverlay.appendChild(button);
var theta = 45;
camera = new THREE.PerspectiveCamera(theta, container.width / container.height, 0.01, 10);
......@@ -57,6 +63,17 @@ XRViewer = ARCS.Component.create(
_light.position.set(0,5,5);
scene.add(_light);
scene.add(camera);
let origin = new THREE.Mesh(new THREE.SphereGeometry(0.02,32,32), new THREE.MeshBasicMaterial({color: 'red', wireframe: true, side: THREE.DoubleSide}));
root.add(origin);
let sOrigin = new THREE.Mesh(new THREE.SphereGeometry(0.02,32,32), new THREE.MeshBasicMaterial({color: 'green', wireframe: true, side: THREE.DoubleSide}));
scene.add(sOrigin);
controller = renderer.xr.getController(0);
controller.addEventListener('select', () => {
console.log('xr select');
this.emit('onSelect',controller);
});
/*renderer.domElement.addEventListener('webglcontextlost', (event) => {
console.log(event);
......@@ -69,9 +86,16 @@ XRViewer = ARCS.Component.create(
* @slot
* @function XRViewer#addScene
*/
this.addScene = function (subScene) {
this.addXRScene = function (subScene) {
scene.add(subScene);
};
this.addXRCameraScene = function(subScene) {
camera.add(subScene);
};
this.addScene = function(subScene) {
root.add(subScene);
};
/**
* Removes an object from the current 3D scene
......@@ -79,94 +103,98 @@ XRViewer = ARCS.Component.create(
* @slot
* @function XRViewer#removeScene
*/
this.removeScene = function (subScene) {
this.removeXRScene = function (subScene) {
scene.remove(subScene);
};
/**
* Sets the pose
* @param pos {object} a position with x, y and z coordinates
* @param rot {object} unused so far
* @slot
* @function XRViewer#setPose
*/
this.setPose = function(pos, rot) {
let session = renderer.xr.getSession();
let p = camera.position;
let q = new THREE.Quaternion();
q.setFromRotationMatrix(camera.matrixWorld);
session.requestReferenceSpace(renderer.xr.getReferenceSpace()).then(
(space) => {
let xrSpace = space;
xrSpace = xrSpace.getOffsetReferenceSpace(
new XRRigidTransform(
{ x: p.x, y: p.y, z: p.z, w: 1 },
{ x: q.x, y: q.y, z: q.z, w: q.w}
)
);
// we will also have to modify the orientation
// because offset position is not enough
xrSpace = xrSpace.getOffsetReferenceSpace(
new XRRigidTransform(
{ x: pos.x, y: pos.y, z:pos.z, w:1},
{ x: 0, y:0, z:0, w:1}
)
);
}
);
this.removeScene = function(subScene) {
root.remove(subScene);
};
this.setMatrixRotation = function(mat) {
let m = new THREE.Matrix4();
m.copy(mat);
m.invert();
scene.position.setFromMatrixRotation(m);
};
this.setMatrixPosition = function(mat) {
let m = new THREE.Matrix4();
m.copy(mat);
m.invert();
scene.position.setFromMatrixPosition(m);
};
this.setMatrixPose = function(mat) {
scene.rotation.setFromRotationMatrix(mat);
scene.position.setFromMatrixPosition(mat);
};
/**
* Starts the animation loop.
* Each time an animation frame is obtained, preRender and postRender
* signals are triggered
* @slot
* @function XRViewer#start
* @triggers preRender
* @triggers postRender
* @emits onRender
* @emits onStarted
* @emits onEnded
*/
this.start = function() {
renderer.setAnimationLoop(render);
};
/* not a good idea, webxr MUST BE manually activated ! */
/*this.activate = function() {
button.click();
this.start();
};*/
let render = function (time, frame) {
if (frame) {
renderer.xr.updateCamera(camera);
if (firstFrame) {
binding = new XRWebGLBinding(frame.session,renderer.getContext());
renderer.xr.getSession().addEventListener('end',() => {
firstFrame = true;
rootOverlay.style.display = defaultDisplay;
self.setMatrixPose(new THREE.Matrix4());
self.emit('onEnded');
});
firstFrame = false;
self.emit('onStarted');
}
//console.log(JSON.stringify(renderer.xr.getCamera().position));
let pose = frame.getViewerPose(renderer.xr.getReferenceSpace());
//console.log(pose);
/*for (let xrView of pose.views) {
if (xrView.camera) {
console.log("I can see a camera");
} */
/*if (pose) {
console.log(pose.views[0].projectionMatrix);
}*/
// if this works, then we simplify the thing
frame.manager = renderer.xr;
frame.renderer = renderer;
frame.binding = binding;
self.emit("onRender",time,renderer.xr.getCamera(),frame);
}
renderer.render(scene, camera);
renderer.render(root, camera);
}
},
/** @lends XRViewer.slots */
['addScene','removeScene','start','setPose'],
['onRender','onEnded', 'onStarted']
[
'addScene','removeScene','addXRScene', 'addXRCameraScene', 'removeXRScene',
'start','setPose', 'setMatrixPose', 'setMatrixPosition', 'setMatrixRotation'
],
['onRender','onEnded', 'onStarted','onSelect']
);
/**
* emitted when a webXR session is operational
* @function XRViewer#onStarted
* @signal
*/
/**
* emitted when a frame is obtained after rendering of the scene.
* @function XRViewer#onRender
......
......@@ -25,11 +25,11 @@
"author": "Jean-Yves Didier",
"license": "GPL-3.0-or-later",
"dependencies": {
"arcsjs": "^0.9.1",
"arcsjs": "^0.9.2",
"js-aruco": ">=0.1",
"jsqr": "^1.4.0",
"three": ">=0.131",
"webpack": "^5.51.1",
"jsqr": "^1.4.0"
"webpack": "^5.66.0"
},
"private": true,
"devDependencies": {
......