|
@@ -66002,6 +66002,7 @@ module.exports.Component = registerComponent('camera', {
|
|
|
far: {default: 10000},
|
|
|
fov: {default: 80, min: 0},
|
|
|
near: {default: 0.005, min: 0},
|
|
|
+ spectator: {default: false},
|
|
|
zoom: {default: 1, min: 0}
|
|
|
},
|
|
|
|
|
@@ -66022,10 +66023,8 @@ module.exports.Component = registerComponent('camera', {
|
|
|
* Update three.js camera.
|
|
|
*/
|
|
|
update: function (oldData) {
|
|
|
- var el = this.el;
|
|
|
var data = this.data;
|
|
|
var camera = this.camera;
|
|
|
- var system = this.system;
|
|
|
|
|
|
// Update properties.
|
|
|
camera.aspect = data.aspect || (window.innerWidth / window.innerHeight);
|
|
@@ -66035,8 +66034,16 @@ module.exports.Component = registerComponent('camera', {
|
|
|
camera.zoom = data.zoom;
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
|
+ this.updateActiveCamera(oldData);
|
|
|
+ this.updateSpectatorCamera(oldData);
|
|
|
+ },
|
|
|
+
|
|
|
+ updateActiveCamera: function (oldData) {
|
|
|
+ var data = this.data;
|
|
|
+ var el = this.el;
|
|
|
+ var system = this.system;
|
|
|
// Active property did not change.
|
|
|
- if (oldData && oldData.active === data.active) { return; }
|
|
|
+ if (oldData && oldData.active === data.active || data.spectator) { return; }
|
|
|
|
|
|
// If `active` property changes, or first update, handle active camera with system.
|
|
|
if (data.active && system.activeCameraEl !== el) {
|
|
@@ -66048,6 +66055,23 @@ module.exports.Component = registerComponent('camera', {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ updateSpectatorCamera: function (oldData) {
|
|
|
+ var data = this.data;
|
|
|
+ var el = this.el;
|
|
|
+ var system = this.system;
|
|
|
+ // spectator property did not change.
|
|
|
+ if (oldData && oldData.spectator === data.spectator) { return; }
|
|
|
+
|
|
|
+ // If `spectator` property changes, or first update, handle spectator camera with system.
|
|
|
+ if (data.spectator && system.spectatorCameraEl !== el) {
|
|
|
+ // Camera enabled. Set camera to this camera.
|
|
|
+ system.setSpectatorCamera(el);
|
|
|
+ } else if (!data.spectator && system.spectatorCameraEl === el) {
|
|
|
+ // Camera disabled. Set camera to another camera.
|
|
|
+ system.disableSpectatorCamera();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
/**
|
|
|
* Remove camera on remove (callback).
|
|
|
*/
|
|
@@ -66349,9 +66373,7 @@ module.exports.Component = registerComponent('cursor', {
|
|
|
* Handle intersection.
|
|
|
*/
|
|
|
onIntersection: function (evt) {
|
|
|
- var self = this;
|
|
|
var cursorEl = this.el;
|
|
|
- var data = this.data;
|
|
|
var index;
|
|
|
var intersectedEl;
|
|
|
var intersection;
|
|
@@ -66373,6 +66395,24 @@ module.exports.Component = registerComponent('cursor', {
|
|
|
// Unset current intersection.
|
|
|
if (this.intersectedEl) { this.clearCurrentIntersection(); }
|
|
|
|
|
|
+ this.setIntersection(intersectedEl, intersection);
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Handle intersection cleared.
|
|
|
+ */
|
|
|
+ onIntersectionCleared: function (evt) {
|
|
|
+ var clearedEls = evt.detail.clearedEls;
|
|
|
+
|
|
|
+ // Check if the current intersection has ended
|
|
|
+ if (clearedEls.indexOf(this.intersectedEl) === -1) { return; }
|
|
|
+ this.clearCurrentIntersection();
|
|
|
+ },
|
|
|
+
|
|
|
+ setIntersection: function (intersectedEl, intersection) {
|
|
|
+ var cursorEl = this.el;
|
|
|
+ var data = this.data;
|
|
|
+ var self = this;
|
|
|
// Set new intersection.
|
|
|
this.intersection = intersection;
|
|
|
this.intersectedEl = intersectedEl;
|
|
@@ -66380,7 +66420,7 @@ module.exports.Component = registerComponent('cursor', {
|
|
|
// Hovering.
|
|
|
cursorEl.addState(STATES.HOVERING);
|
|
|
intersectedEl.addState(STATES.HOVERED);
|
|
|
- self.twoWayEmit(EVENTS.MOUSEENTER);
|
|
|
+ this.twoWayEmit(EVENTS.MOUSEENTER);
|
|
|
|
|
|
// Begin fuse if necessary.
|
|
|
if (data.fuseTimeout === 0 || !data.fuse) { return; }
|
|
@@ -66392,20 +66432,11 @@ module.exports.Component = registerComponent('cursor', {
|
|
|
}, data.fuseTimeout);
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * Handle intersection cleared.
|
|
|
- */
|
|
|
- onIntersectionCleared: function (evt) {
|
|
|
- var clearedEls = evt.detail.clearedEls;
|
|
|
-
|
|
|
- // Check if the current intersection has ended
|
|
|
- if (clearedEls.indexOf(this.intersectedEl) !== -1) {
|
|
|
- this.clearCurrentIntersection();
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
clearCurrentIntersection: function () {
|
|
|
var cursorEl = this.el;
|
|
|
+ var index;
|
|
|
+ var intersection;
|
|
|
+ var intersections;
|
|
|
|
|
|
// No longer hovering (or fusing).
|
|
|
this.intersectedEl.removeState(STATES.HOVERED);
|
|
@@ -66419,6 +66450,15 @@ module.exports.Component = registerComponent('cursor', {
|
|
|
|
|
|
// Clear fuseTimeout.
|
|
|
clearTimeout(this.fuseTimeout);
|
|
|
+
|
|
|
+ // Set intersection to another raycasted element if any.
|
|
|
+ intersections = this.el.components.raycaster.intersections;
|
|
|
+ if (intersections.length === 0) { return; }
|
|
|
+ // exclude the cursor.
|
|
|
+ index = intersections[0].object.el === cursorEl ? 1 : 0;
|
|
|
+ intersection = intersections[index];
|
|
|
+ if (!intersection) { return; }
|
|
|
+ this.setIntersection(intersection.object.el, intersection);
|
|
|
},
|
|
|
|
|
|
/**
|
|
@@ -69275,11 +69315,13 @@ module.exports.Component = registerComponent('raycaster', {
|
|
|
*/
|
|
|
refreshObjects: function () {
|
|
|
var data = this.data;
|
|
|
+ var els;
|
|
|
+
|
|
|
// If objects not defined, intersect with everything.
|
|
|
- var els = data.objects
|
|
|
+ els = data.objects
|
|
|
? this.el.sceneEl.querySelectorAll(data.objects)
|
|
|
: this.el.sceneEl.children;
|
|
|
- this.objects = flattenChildrenShallow(els);
|
|
|
+ this.objects = this.flattenChildrenShallow(els);
|
|
|
this.dirty = false;
|
|
|
},
|
|
|
|
|
@@ -69466,40 +69508,44 @@ module.exports.Component = registerComponent('raycaster', {
|
|
|
this.lineData.start = data.origin;
|
|
|
this.lineData.end = endVec3.copy(this.unitLineEndVec3).multiplyScalar(length);
|
|
|
el.setAttribute('line', this.lineData);
|
|
|
- }
|
|
|
-});
|
|
|
+ },
|
|
|
|
|
|
-/**
|
|
|
- * Returns children of each element's object3D group. Children are flattened
|
|
|
- * by one level, removing the THREE.Group wrapper, so that non-recursive
|
|
|
- * raycasting remains useful.
|
|
|
- *
|
|
|
- * @param {Array<Element>} els
|
|
|
- * @return {Array<THREE.Object3D>}
|
|
|
- */
|
|
|
-function flattenChildrenShallow (els) {
|
|
|
- var groups = [];
|
|
|
- var objects = [];
|
|
|
- var children;
|
|
|
- var i;
|
|
|
+ /**
|
|
|
+ * Return children of each element's object3D group. Children are flattened
|
|
|
+ * by one level, removing the THREE.Group wrapper, so that non-recursive
|
|
|
+ * raycasting remains useful.
|
|
|
+ *
|
|
|
+ * @param {Array<Element>} els
|
|
|
+ * @return {Array<THREE.Object3D>}
|
|
|
+ */
|
|
|
+ flattenChildrenShallow: (function () {
|
|
|
+ var groups = [];
|
|
|
|
|
|
- // Push meshes onto list of objects to intersect.
|
|
|
- for (i = 0; i < els.length; i++) {
|
|
|
- if (els[i].object3D) {
|
|
|
- groups.push(els[i].object3D);
|
|
|
- }
|
|
|
- }
|
|
|
+ return function (els) {
|
|
|
+ var children;
|
|
|
+ var i;
|
|
|
+ var objects = this.objects;
|
|
|
|
|
|
- // Each entity's root is a THREE.Group. Return the group's chilrden.
|
|
|
- for (i = 0; i < groups.length; i++) {
|
|
|
- children = groups[i].children;
|
|
|
- if (children && children.length) {
|
|
|
- objects.push.apply(objects, children);
|
|
|
- }
|
|
|
- }
|
|
|
+ // Push meshes onto list of objects to intersect.
|
|
|
+ groups.length = 0;
|
|
|
+ for (i = 0; i < els.length; i++) {
|
|
|
+ if (els[i].object3D) {
|
|
|
+ groups.push(els[i].object3D);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return objects;
|
|
|
-}
|
|
|
+ // Each entity's root is a THREE.Group. Return the group's chilrden.
|
|
|
+ objects.length = 0;
|
|
|
+ for (i = 0; i < groups.length; i++) {
|
|
|
+ children = groups[i].children;
|
|
|
+ if (children && children.length) {
|
|
|
+ objects.push.apply(objects, children);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return objects;
|
|
|
+ };
|
|
|
+ })()
|
|
|
+});
|
|
|
|
|
|
/**
|
|
|
* Copy contents of one array to another without allocating new array.
|
|
@@ -78218,7 +78264,7 @@ _dereq_('./core/a-mixin');
|
|
|
_dereq_('./extras/components/');
|
|
|
_dereq_('./extras/primitives/');
|
|
|
|
|
|
-console.log('A-Frame Version: 0.7.0 (Date 2017-12-22, Commit #1ca6130)');
|
|
|
+console.log('A-Frame Version: 0.7.0 (Date 2017-12-27, Commit #ee1e41e)');
|
|
|
console.log('three Version:', pkg.dependencies['three']);
|
|
|
console.log('WebVR Polyfill Version:', pkg.dependencies['webvr-polyfill']);
|
|
|
|
|
@@ -78838,8 +78884,8 @@ module.exports.System = registerSystem('camera', {
|
|
|
var sceneEl = this.sceneEl;
|
|
|
var defaultCameraEl;
|
|
|
|
|
|
- // Camera already defined.
|
|
|
- if (sceneEl.camera) {
|
|
|
+ // Camera already defined or the one defined it is an spectator one.
|
|
|
+ if (sceneEl.camera && !sceneEl.camera.el.getAttribute('camera').spectator) {
|
|
|
sceneEl.emit('camera-ready', {cameraEl: sceneEl.camera.el});
|
|
|
return;
|
|
|
}
|
|
@@ -78911,11 +78957,58 @@ module.exports.System = registerSystem('camera', {
|
|
|
cameraEls = sceneEl.querySelectorAll('[camera]');
|
|
|
for (i = 0; i < cameraEls.length; i++) {
|
|
|
cameraEl = cameraEls[i];
|
|
|
- if (!cameraEl.isEntity || newCameraEl === cameraEl) { continue; }
|
|
|
+ if (!cameraEl.isEntity ||
|
|
|
+ newCameraEl === cameraEl ||
|
|
|
+ cameraEl.getAttribute('camera').spectator) { continue; }
|
|
|
cameraEl.setAttribute('camera', 'active', false);
|
|
|
cameraEl.pause();
|
|
|
}
|
|
|
sceneEl.emit('camera-set-active', {cameraEl: newCameraEl});
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set spectator camera to render the scene on a 2D display.
|
|
|
+ *
|
|
|
+ * @param {Element} newCameraEl - Entity with camera component.
|
|
|
+ */
|
|
|
+ setSpectatorCamera: function (newCameraEl) {
|
|
|
+ var newCamera;
|
|
|
+ var previousCamera = this.spectatorCameraEl;
|
|
|
+ var sceneEl = this.sceneEl;
|
|
|
+ var spectatorCameraEl;
|
|
|
+
|
|
|
+ // Same camera.
|
|
|
+ newCamera = newCameraEl.getObject3D('camera');
|
|
|
+ if (!newCamera || newCameraEl === this.spectatorCameraEl) { return; }
|
|
|
+
|
|
|
+ // Disable current camera
|
|
|
+ if (previousCamera) {
|
|
|
+ previousCamera.setAttribute('camera', 'spectator', false);
|
|
|
+ }
|
|
|
+
|
|
|
+ spectatorCameraEl = this.spectatorCameraEl = newCameraEl;
|
|
|
+ spectatorCameraEl.setAttribute('camera', 'active', false);
|
|
|
+ spectatorCameraEl.play();
|
|
|
+
|
|
|
+ sceneEl.emit('camera-set-spectator', {cameraEl: newCameraEl});
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Disables current spectator camera.
|
|
|
+ */
|
|
|
+ disableSpectatorCamera: function () {
|
|
|
+ this.spectatorCameraEl = undefined;
|
|
|
+ },
|
|
|
+
|
|
|
+ tock: function () {
|
|
|
+ var spectatorCamera;
|
|
|
+ var sceneEl = this.sceneEl;
|
|
|
+ var isVREnabled = sceneEl.renderer.vr.enabled;
|
|
|
+ if (!this.spectatorCameraEl || sceneEl.isMobile) { return; }
|
|
|
+ spectatorCamera = this.spectatorCameraEl.components.camera.camera;
|
|
|
+ sceneEl.renderer.vr.enabled = false;
|
|
|
+ sceneEl.renderer.render(sceneEl.object3D, spectatorCamera);
|
|
|
+ sceneEl.renderer.vr.enabled = isVREnabled;
|
|
|
}
|
|
|
});
|
|
|
|