Skip to content

Commit

Permalink
add gearvr-controls
Browse files Browse the repository at this point in the history
  • Loading branch information
machenmusik committed Apr 7, 2017
1 parent 8b64682 commit 061854b
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 0 deletions.
48 changes: 48 additions & 0 deletions docs/components/gearvr-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: gearvr-controls
type: components
layout: docs
parent_section: components
---

[trackedcontrols]: ./tracked-controls.md

The gearvr-controls component interfaces with the Samsung/Oculus Gear VR controllers.
It wraps the [tracked-controls component][trackedcontrols] while adding button
mappings, events, and a Gear VR controller model that highlights the touched
and/or pressed buttons (trackpad, trigger).

## Example

```html
<a-entity gearvr-controls="hand: left"></a-entity>
<a-entity gearvr-controls="hand: right"></a-entity>
```

## Value

| Property | Description | Default |
|----------------------|----------------------------------------------------|---------|
| buttonColor | Button colors when not pressed. | #000000 |
| buttonTouchedColor | Button colors when touched. | #777777 |
| buttonHighlightColor | Button colors when pressed and active. | #FFFFFF |
| hand | The hand that will be tracked (i.e., right, left). | right |
| model | Whether the Daydream controller model is loaded. | true |
| rotationOffset | Offset to apply to model rotation. | 0 |

## Events

| Event Name | Description |
| ---------- | ----------- |
| trackpaddown | Trackpad pressed. |
| trackpadup | Trackpad released. |
| trackpadtouchstart | Trackpad touched. |
| trackpadtouchend | Trackpad not touched. |
| triggerdown | Trigger pressed. |
| triggerup | Trigger released. |

## Assets

- [Controller OBJ](https://cdn.aframe.io/controllers/google/vr_controller_daydream.obj)
- [Controller MTL](https://cdn.aframe.io/controllers/google/vr_controller_daydream.mtl)

203 changes: 203 additions & 0 deletions src/components/gearvr-controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
var registerComponent = require('../core/component').registerComponent;
var bind = require('../utils/bind');
var isControllerPresent = require('../utils/tracked-controls').isControllerPresent;

var DEFAULT_HANDEDNESS = require('../constants').DEFAULT_HANDEDNESS;

var GEARVR_CONTROLLER_MODEL_BASE_URL = 'https://cdn.aframe.io/controllers/google/';
var GEARVR_CONTROLLER_MODEL_OBJ_URL = GEARVR_CONTROLLER_MODEL_BASE_URL + 'vr_controller_daydream.obj';
var GEARVR_CONTROLLER_MODEL_OBJ_MTL = GEARVR_CONTROLLER_MODEL_BASE_URL + 'vr_controller_daydream.mtl';

var GAMEPAD_ID_PREFIX = 'Gear VR';

/**
* Vive Controls Component
* Interfaces with vive controllers and maps Gamepad events to
* common controller buttons: trackpad, trigger, grip, menu and system
* It loads a controller model and highlights the pressed buttons
*/
module.exports.Component = registerComponent('gearvr-controls', {
schema: {
hand: {default: DEFAULT_HANDEDNESS}, // This informs the degenerate arm model.
buttonColor: {type: 'color', default: '#000000'},
buttonTouchedColor: {type: 'color', default: '#777777'},
buttonHighlightColor: {type: 'color', default: '#FFFFFF'},
model: {default: true},
rotationOffset: {default: 0} // use -999 as sentinel value to auto-determine based on hand
},

// buttonId
// 0 - trackpad
// 1 - triggeri
mapping: {
axis0: 'trackpad',
axis1: 'trackpad',
button0: 'trackpad',
button1: 'trigger'
},

bindMethods: function () {
this.onModelLoaded = bind(this.onModelLoaded, this);
this.onControllersUpdate = bind(this.onControllersUpdate, this);
this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);
this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);
this.onGamepadConnected = bind(this.onGamepadConnected, this);
this.onGamepadDisconnected = bind(this.onGamepadDisconnected, this);
},

init: function () {
var self = this;
this.animationActive = 'pointing';
this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };
this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };
this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };
this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };
this.onAxisMoved = bind(this.onAxisMoved, this);
this.controllerPresent = false;
this.everGotGamepadEvent = false;
this.lastControllerCheck = 0;
this.bindMethods();
this.isControllerPresent = isControllerPresent; // to allow mock
},

addEventListeners: function () {
var el = this.el;
el.addEventListener('buttondown', this.onButtonDown);
el.addEventListener('buttonup', this.onButtonUp);
el.addEventListener('touchstart', this.onButtonTouchStart);
el.addEventListener('touchend', this.onButtonTouchEnd);
el.addEventListener('model-loaded', this.onModelLoaded);
el.addEventListener('axismove', this.onAxisMoved);
},

removeEventListeners: function () {
var el = this.el;
el.removeEventListener('buttondown', this.onButtonDown);
el.removeEventListener('buttonup', this.onButtonUp);
el.removeEventListener('touchstart', this.onButtonTouchStart);
el.removeEventListener('touchend', this.onButtonTouchEnd);
el.removeEventListener('model-loaded', this.onModelLoaded);
el.removeEventListener('axismove', this.onAxisMoved);
},

checkIfControllerPresent: function () {
var isPresent = this.isControllerPresent(this.el.sceneEl, GAMEPAD_ID_PREFIX, {hand: this.data.hand});
if (isPresent === this.controllerPresent) { return; }
this.controllerPresent = isPresent;
if (isPresent) { this.injectTrackedControls(); } // inject track-controls
},

onGamepadConnected: function (evt) {
// for now, don't disable controller update listening, due to
// apparent issue with FF Nightly only sending one event and seeing one controller;
// this.everGotGamepadEvent = true;
// this.removeControllersUpdateListener();
this.checkIfControllerPresent();
},

onGamepadDisconnected: function (evt) {
// for now, don't disable controller update listening, due to
// apparent issue with FF Nightly only sending one event and seeing one controller;
// this.everGotGamepadEvent = true;
// this.removeControllersUpdateListener();
this.checkIfControllerPresent();
},

play: function () {
this.checkIfControllerPresent();
window.addEventListener('gamepadconnected', this.onGamepadConnected, false);
window.addEventListener('gamepaddisconnected', this.onGamepadDisconnected, false);
this.addControllersUpdateListener();
this.addEventListeners();
},

pause: function () {
window.removeEventListener('gamepadconnected', this.onGamepadConnected, false);
window.removeEventListener('gamepaddisconnected', this.onGamepadDisconnected, false);
this.removeControllersUpdateListener();
this.removeEventListeners();
},

injectTrackedControls: function () {
var el = this.el;
var data = this.data;
el.setAttribute('tracked-controls', {idPrefix: GAMEPAD_ID_PREFIX, hand: data.hand, rotationOffset: data.rotationOffset});
if (!this.data.model) { return; }
this.el.setAttribute('obj-model', {
obj: GEARVR_CONTROLLER_MODEL_OBJ_URL,
mtl: GEARVR_CONTROLLER_MODEL_OBJ_MTL
});
},

addControllersUpdateListener: function () {
this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);
},

removeControllersUpdateListener: function () {
this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);
},

onControllersUpdate: function () {
if (!this.everGotGamepadEvent) { this.checkIfControllerPresent(); }
},

// No need for onButtonChanged, since Daydream controller has no analog buttons.

onModelLoaded: function (evt) {
var controllerObject3D = evt.detail.model;
var buttonMeshes;
if (!this.data.model) { return; }
buttonMeshes = this.buttonMeshes = {};
buttonMeshes.trigger = controllerObject3D.getObjectByName('AppButton_AppButton_Cylinder.004');
buttonMeshes.trackpad = controllerObject3D.getObjectByName('TouchPad_TouchPad_Cylinder.003');
// Offset pivot point
controllerObject3D.position.set(0, 0, -0.04);
},

onAxisMoved: function (evt) {
if (evt.detail.axis[0] === 0 && evt.detail.axis[1] === 0) { return; }
this.el.emit('trackpadmoved', { x: evt.detail.axis[0], y: evt.detail.axis[1] });
},

onButtonEvent: function (id, evtName) {
var buttonName = this.mapping['button' + id];
var i;
if (Array.isArray(buttonName)) {
for (i = 0; i < buttonName.length; i++) {
this.el.emit(buttonName[i] + evtName);
}
} else {
this.el.emit(buttonName + evtName);
}
this.updateModel(buttonName, evtName);
},

updateModel: function (buttonName, evtName) {
var i;
if (!this.data.model) { return; }
if (Array.isArray(buttonName)) {
for (i = 0; i < buttonName.length; i++) {
this.updateButtonModel(buttonName[i], evtName);
}
} else {
this.updateButtonModel(buttonName, evtName);
}
},

updateButtonModel: function (buttonName, state) {
var buttonMeshes = this.buttonMeshes;
if (!buttonMeshes || !buttonMeshes[buttonName]) { return; }
var color;
switch (state) {
case 'down':
color = this.data.buttonHighlightColor;
break;
case 'touchstart':
color = this.data.buttonTouchedColor;
break;
default:
color = this.data.buttonColor;
}
buttonMeshes[buttonName].material.color.set(color);
}
});
1 change: 1 addition & 0 deletions src/components/hand-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ module.exports.Component = registerComponent('hand-controls', {
el.setAttribute('vive-controls', controlConfiguration);
el.setAttribute('oculus-touch-controls', controlConfiguration);
el.setAttribute('daydream-controls', controlConfiguration);
el.setAttribute('gearvr-controls', controlConfiguration);
el.setAttribute('blend-character-model', modelUrl);
},

Expand Down
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ require('./camera');
require('./collada-model');
require('./cursor');
require('./daydream-controls');
require('./gearvr-controls');
require('./geometry');
require('./gltf-model');
require('./hand-controls');
Expand Down

0 comments on commit 061854b

Please sign in to comment.