From 228fcc85282cfe79caf8655f3223ce6864943568 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20de=20la=20Puente=20Gonz=C3=A1lez?=
 <salva@unoyunodiez.com>
Date: Fri, 23 Mar 2018 08:42:30 +0100
Subject: [PATCH 1/5] Free-flight mode script enables scene navigation.

You can use WASD or the arrow keys to move forward/backwards, to the
left/right. You can also configure all these keys. Click and drag
the mouse to rotate the views.

The fallback mode is enabled according to the capabilities of the VR
device.

In desktop environments with VR, movement and rotation are available
while not presenting.

In mobile environments, movement and rotation are enabled or disabled
according to the capabilities of the device.
---
 Assets/WebGLTemplates/WebVR/styles/webvr.css  |   2 +
 Assets/WebGLTemplates/WebVR/webvr.js          | 111 ++++++-----
 Assets/WebVR/Plugins/WebGL/webvr.jslib        |   4 +
 Assets/WebVR/Prefabs/WebVRCameraSet.prefab    |  16 ++
 Assets/WebVR/Scenes/WebVR.unity               |  18 +-
 Assets/WebVR/Scripts/Input.meta               |  10 +
 .../Scripts/Input/FreeFlightController.cs     | 188 ++++++++++++++++++
 .../Input/FreeFlightController.cs.meta        |  13 ++
 Assets/WebVR/Scripts/UI.meta                  |  10 +
 Assets/WebVR/Scripts/UI/WebUI.cs              |   9 +
 Assets/WebVR/Scripts/UI/WebUI.cs.meta         |  13 ++
 Assets/WebVR/Scripts/VRDisplayCapabilities.cs |  10 +
 .../Scripts/VRDisplayCapabilities.cs.meta     |  13 ++
 Assets/WebVR/Scripts/WebVRCamera.cs           |  37 ++--
 ProjectSettings/ProjectVersion.txt            |   2 +-
 15 files changed, 385 insertions(+), 71 deletions(-)
 create mode 100644 Assets/WebVR/Scripts/Input.meta
 create mode 100644 Assets/WebVR/Scripts/Input/FreeFlightController.cs
 create mode 100644 Assets/WebVR/Scripts/Input/FreeFlightController.cs.meta
 create mode 100644 Assets/WebVR/Scripts/UI.meta
 create mode 100644 Assets/WebVR/Scripts/UI/WebUI.cs
 create mode 100644 Assets/WebVR/Scripts/UI/WebUI.cs.meta
 create mode 100644 Assets/WebVR/Scripts/VRDisplayCapabilities.cs
 create mode 100644 Assets/WebVR/Scripts/VRDisplayCapabilities.cs.meta

diff --git a/Assets/WebGLTemplates/WebVR/styles/webvr.css b/Assets/WebGLTemplates/WebVR/styles/webvr.css
index c3be537..a8c0b36 100755
--- a/Assets/WebGLTemplates/WebVR/styles/webvr.css
+++ b/Assets/WebGLTemplates/WebVR/styles/webvr.css
@@ -130,6 +130,7 @@ a:link, a:visited {
   position: absolute;
   top: 0;
   width: 100%;
+  pointer-events: none;
 }
 
 #instruction button {
@@ -148,6 +149,7 @@ a:link, a:visited {
   display: none;
   max-width: 50%;
   padding: 10px 30px;
+  pointer-events: all;
 }
 
 .panel[data-enabled='true'] {
diff --git a/Assets/WebGLTemplates/WebVR/webvr.js b/Assets/WebGLTemplates/WebVR/webvr.js
index 0248efa..7b51665 100644
--- a/Assets/WebGLTemplates/WebVR/webvr.js
+++ b/Assets/WebGLTemplates/WebVR/webvr.js
@@ -2,11 +2,14 @@
   'use strict';
 
   var defaultHeight = 1.5;
-  var entervrButton = document.querySelector('#entervr');
-  var container = document.querySelector('#game');
-  var status = document.querySelector('#status');
-  var icons = document.querySelector('#icons');
-  var controller = document.querySelector('#motion-controller');
+
+  var enterVRButton = document.getElementById('entervr');
+  var gameContainer = document.getElementById('game');
+  var vrHardwareStatus = document.getElementById('status');
+  var statusIcons = document.getElementById('icons');
+  var controllerIconTemplate = document.getElementById('motion-controller');
+  var noVRInstructions = document.getElementById('novr');
+
   var windowRaf = window.requestAnimationFrame;
   var vrDisplay = null;
   var canvas = null;
@@ -46,25 +49,34 @@
   }
 
   function onUnity (msg) {
-    // Measure Round-Trip Time from Unity.
-    if (msg.detail === 'Timer') {
-      var delta = window.performance.now() - testTimeStart;
-      console.log('return time (ms): ',delta);
-      testTimeStart = null;
-      return;
-    }
+    // This way of passing messages is deprecated. Use rich objects instead.
+    if (typeof msg.detail === 'string') {
+      // Measure Round-Trip Time from Unity.
+      if (msg.detail === 'Timer') {
+        var delta = window.performance.now() - testTimeStart;
+        console.log('return time (ms): ',delta);
+        testTimeStart = null;
+        return;
+      }
 
-    // Wait for Unity to render the frame; then submit the frame to the VR display.
-    if (msg.detail === 'PostRender') {
-      submitNextFrame = vrDisplay && vrDisplay.isPresenting;
-      if (submitNextFrame) {
-        vrDisplay.requestAnimationFrame(onAnimate);
+      // Wait for Unity to render the frame; then submit the frame to the VR display.
+      if (msg.detail === 'PostRender') {
+        submitNextFrame = vrDisplay && vrDisplay.isPresenting;
+        if (submitNextFrame) {
+          vrDisplay.requestAnimationFrame(onAnimate);
+        }
+      }
+
+      // Handle quick VR/normal toggling.
+      if (msg.detail.indexOf('ConfigureToggleVRKeyName') === 0) {
+        toggleVRKeyName = msg.detail.split(':')[1];
       }
     }
 
-    // Handle quick VR/normal toggling.
-    if (msg.detail.indexOf('ConfigureToggleVRKeyName') === 0) {
-      toggleVRKeyName = msg.detail.split(':')[1];
+    // Handle an UI command
+    if (msg.detail.type === 'ShowPanel') {
+      var panelId = document.getElementById(msg.detail.panelId);
+      showInstruction(panelId);
     }
   }
 
@@ -88,7 +100,7 @@
     return vrDisplay.requestPresent([{source: canvas}]).then(function () {
       // Start stereo rendering in Unity.
       console.log('Entered VR mode');
-      gameInstance.SendMessage('WebVRCameraSet', 'Begin');
+      gameInstance.SendMessage('WebVRCameraSet', 'OnStartVR');
     }).catch(function (err) {
       console.error('Unable to enter VR mode:', err);
     });
@@ -101,7 +113,7 @@
     }
     function done () {
       // End stereo rendering in Unity.
-      gameInstance.SendMessage('WebVRCameraSet', 'End');
+      gameInstance.SendMessage('WebVRCameraSet', 'OnEndVR');
       onResize();
     }
     return vrDisplay.exitPresent().then(function () {
@@ -223,11 +235,11 @@
       // scale game container so we get a proper sized mirror of VR content to desktop.
       var scaleX = window.innerWidth / renderWidth;
       var scaleY = window.innerHeight / renderHeight;
-      container.setAttribute('style', `transform: scale(${scaleX}, ${scaleY}); transform-origin: top left;`);
+      gameContainer.setAttribute('style', `transform: scale(${scaleX}, ${scaleY}); transform-origin: top left;`);
     } else {
       canvas.width = window.innerWidth;
       canvas.height = window.innerHeight;
-      container.style.transform = '';
+      gameContainer.style.transform = '';
     }
   }
 
@@ -242,6 +254,7 @@
   }
 
   function showInstruction (el) {
+    if (el.dataset.enabled) { return; }
     var confirmButton = el.querySelector('button');
     el.dataset.enabled = true;
     confirmButton.addEventListener('click', onConfirm);
@@ -252,19 +265,19 @@
   }
 
   function updateStatus () {
-    if (parseInt(status.dataset.gamepads) !== vrGamepads.length) {
+    if (parseInt(vrHardwareStatus.dataset.gamepads) !== vrGamepads.length) {
       var controllerClassName = 'controller-icon';
-      var controlIcons = icons.getElementsByClassName(controllerClassName);
+      var controlIcons = statusIcons.getElementsByClassName(controllerClassName);
       while (controlIcons.length > 0) {
         controlIcons[0].parentNode.removeChild(controlIcons[0]);
       }
 
       vrGamepads.forEach(function (gamepad) {
-        var controllerIcon = document.importNode(controller.content, true);
+        var controllerIcon = document.importNode(controllerIconTemplate.content, true);
         controllerIcon.querySelector('img').className = controllerClassName;
-        icons.appendChild(controllerIcon);
+        statusIcons.appendChild(controllerIcon);
       });
-      status.dataset.gamepads = vrGamepads.length;
+      vrHardwareStatus.dataset.gamepads = vrGamepads.length;
     }
   }
 
@@ -287,26 +300,30 @@
     frameData = new VRFrameData();
 
     return navigator.getVRDisplays().then(function(displays) {
-      if (!displays.length) {
-        return null;
+      var canPresent = false;
+      var hasPosition = false;
+      var hasOrientation = false;
+      var hasExternalDisplay = false;
+
+      if (displays.length) {
+        vrDisplay = displays[displays.length - 1];
+        canPresent = vrDisplay.capabilities.canPresent;
+        hasPosition = vrDisplay.capabilities.hasPosition;
+        hasOrientation = vrDisplay.capabilities.hasOrientation;
+        hasExternalDisplay = vrDisplay.capabilities.hasExternalDisplay;
       }
 
-      vrDisplay = displays[displays.length - 1];
-
-      if (!vrDisplay) {
-        return null;
-      }
+      enterVRButton.dataset.enabled = canPresent;
 
-      if (isPolyfilled(vrDisplay)) {
-        showInstruction(document.querySelector('#novr'));
-      } else {
-        status.dataset.enabled = 'true';
-      }
-
-      if (vrDisplay.capabilities && vrDisplay.capabilities.canPresent) {
-        // Enable button to toggle entering/exiting VR.
-        entervrButton.dataset.enabled = 'true';
-      }
+      gameInstance.SendMessage(
+        'WebVRCameraSet', 'OnVRCapabilities',
+        JSON.stringify({
+          canPresent: canPresent,
+          hasPosition: hasPosition,
+          hasOrientation: hasOrientation,
+          hasExternalDisplay: hasExternalDisplay
+        })
+      );
 
       return vrDisplay;
     }).catch(function (err) {
@@ -335,7 +352,7 @@
   window.addEventListener('keyup', onKeyUp, false);
   document.addEventListener('UnityLoaded', onUnityLoaded, false);
   document.addEventListener('Unity', onUnity);
-  entervrButton.addEventListener('click', onToggleVR, false);
+  enterVRButton.addEventListener('click', onToggleVR, false);
 
   onResize();
 
diff --git a/Assets/WebVR/Plugins/WebGL/webvr.jslib b/Assets/WebVR/Plugins/WebGL/webvr.jslib
index 6eefc61..db15b1d 100755
--- a/Assets/WebVR/Plugins/WebGL/webvr.jslib
+++ b/Assets/WebVR/Plugins/WebGL/webvr.jslib
@@ -14,5 +14,9 @@ mergeInto(LibraryManager.library, {
 
   ConfigureToggleVRKeyName: function (keyName) {
     document.dispatchEvent(new CustomEvent('Unity', {detail: 'ConfigureToggleVRKeyName:' + Pointer_stringify(keyName)}));
+  },
+
+  ShowPanel: function (panelId) {
+    document.dispatchEvent(new CustomEvent('Unity', {detail: {type:'ShowPanel', panelId: Pointer_stringify(panelId)}}));
   }
 });
diff --git a/Assets/WebVR/Prefabs/WebVRCameraSet.prefab b/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
index 826c613..ee552b0 100644
--- a/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
+++ b/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
@@ -57,6 +57,7 @@ GameObject:
   - component: {fileID: 4620614974547310}
   - component: {fileID: 114951743782495552}
   - component: {fileID: 81381995457807688}
+  - component: {fileID: 114848038275145070}
   m_Layer: 0
   m_Name: WebVRCameraSet
   m_TagString: Untagged
@@ -273,6 +274,21 @@ Behaviour:
   m_PrefabInternal: {fileID: 100100000}
   m_GameObject: {fileID: 1147971983220084}
   m_Enabled: 1
+--- !u!114 &114848038275145070
+MonoBehaviour:
+  m_ObjectHideFlags: 1
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 100100000}
+  m_GameObject: {fileID: 1514700693580046}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 683f145ef879be447ba25c1080ac1984, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  translationSpeed: 7
+  rotationSpeed: 90
+  rotationEnabled: 1
+  translationEnabled: 1
 --- !u!114 &114951743782495552
 MonoBehaviour:
   m_ObjectHideFlags: 1
diff --git a/Assets/WebVR/Scenes/WebVR.unity b/Assets/WebVR/Scenes/WebVR.unity
index f525ba0..bdbe649 100644
--- a/Assets/WebVR/Scenes/WebVR.unity
+++ b/Assets/WebVR/Scenes/WebVR.unity
@@ -889,6 +889,11 @@ MeshFilter:
   m_PrefabInternal: {fileID: 0}
   m_GameObject: {fileID: 705953490}
   m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!1 &757088923 stripped
+GameObject:
+  m_PrefabParentObject: {fileID: 1147971983220084, guid: 78df02845d4b54181b4ca9188aba0671,
+    type: 2}
+  m_PrefabInternal: {fileID: 1315843485}
 --- !u!1 &821505835 stripped
 GameObject:
   m_PrefabParentObject: {fileID: 100030, guid: 013217fcf4bba4f3380d9159876fa8ea, type: 3}
@@ -1603,14 +1608,14 @@ Prefab:
       objectReference: {fileID: 0}
     - target: {fileID: 114951743782495552, guid: 78df02845d4b54181b4ca9188aba0671,
         type: 2}
-      propertyPath: rightHandObject
+      propertyPath: leftHandObject
       value: 
-      objectReference: {fileID: 1269233424}
+      objectReference: {fileID: 757088923}
     - target: {fileID: 114951743782495552, guid: 78df02845d4b54181b4ca9188aba0671,
         type: 2}
-      propertyPath: leftHandObject
+      propertyPath: rightHandObject
       value: 
-      objectReference: {fileID: 821505835}
+      objectReference: {fileID: 2040219167}
     m_RemovedComponents: []
   m_ParentPrefab: {fileID: 100100000, guid: 78df02845d4b54181b4ca9188aba0671, type: 2}
   m_IsPrefabParent: 0
@@ -2189,6 +2194,11 @@ Transform:
   m_Father: {fileID: 2005427646}
   m_RootOrder: 0
   m_LocalEulerAnglesHint: {x: -16.601002, y: -7.7430005, z: 25.449001}
+--- !u!1 &2040219167 stripped
+GameObject:
+  m_PrefabParentObject: {fileID: 1118756453539842, guid: 78df02845d4b54181b4ca9188aba0671,
+    type: 2}
+  m_PrefabInternal: {fileID: 1315843485}
 --- !u!4 &2066780126 stripped
 Transform:
   m_PrefabParentObject: {fileID: 400000, guid: 7e57e26a714804d3c9f1baa605131856, type: 3}
diff --git a/Assets/WebVR/Scripts/Input.meta b/Assets/WebVR/Scripts/Input.meta
new file mode 100644
index 0000000..af10670
--- /dev/null
+++ b/Assets/WebVR/Scripts/Input.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: c7d3e8ee975b05b4aa3b84ed9fe51878
+folderAsset: yes
+timeCreated: 1521741256
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/WebVR/Scripts/Input/FreeFlightController.cs b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
new file mode 100644
index 0000000..dd40f79
--- /dev/null
+++ b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
@@ -0,0 +1,188 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine.EventSystems;
+using UnityEngine;
+
+public class FreeFlightController : MonoBehaviour {
+
+	[Tooltip("Enable/disable rotation control.")]
+	public bool rotationEnabled = true;
+
+	[Tooltip("Enable/disable translation control.")]
+	public bool translationEnabled = true;
+
+	[Tooltip("Speed of rotation in degrees/seconds.")]
+	public float rotationSpeed = 90;
+
+	[Tooltip("Speed of translation in meters/seconds.")]
+	public float translationSpeed = 7;
+
+	[Tooltip("Keys to move forward.")]
+	public List<KeyCode> moveForwardKeys =
+		new List<KeyCode> { KeyCode.W, KeyCode.UpArrow };
+
+	[Tooltip("Keys to move backwards.")]
+	public List<KeyCode> moveBackwardsKeys =
+		new List<KeyCode> { KeyCode.S, KeyCode.DownArrow };
+
+	[Tooltip("Keys to stride-right.")]
+	public List<KeyCode> strideRightKeys =
+		new List<KeyCode> { KeyCode.D, KeyCode.RightArrow };
+
+	[Tooltip("Keys to stride-left.")]
+	public List<KeyCode> strideLeftKeys =
+		new List<KeyCode> { KeyCode.A, KeyCode.LeftArrow };
+
+	[Tooltip("Keys to move upward.")]
+	public List<KeyCode> moveUpwardKeys = new List<KeyCode> { KeyCode.R };
+
+	[Tooltip("Keys to move downward.")]
+	public List<KeyCode> moveDownwardKeys = new List<KeyCode> { KeyCode.F };
+
+	VRDisplayCapabilities capabilities;
+
+	bool inDesktopLike {
+		get {
+			return capabilities.hasExternalDisplay;
+		}
+	}
+
+	Vector3 mouseMovement = Vector3.zero;
+
+	Vector3 lastMousePosition;
+
+	public void OnStartVR() {
+		DisableEverything();
+	}
+
+	public void OnEndVR() {
+		EnableAccordingToPlatform();
+	}
+
+	public void OnVRCapabilities(string json) {
+		OnVRCapabilities(JsonUtility.FromJson<VRDisplayCapabilities>(json));
+	}
+
+	public void OnVRCapabilities(VRDisplayCapabilities vrCapabilities) {
+		capabilities = vrCapabilities;
+
+		#if !UNITY_EDITOR && UNITY_WEBGL
+		if (!capabilities.hasOrientation) {
+			WebUI.ShowPanel("novr");
+		}
+		#endif
+
+		EnableAccordingToPlatform();
+	}
+
+	void Update() {
+		if (translationEnabled) {
+			Translate();
+		}
+		if (rotationEnabled) {
+			Rotate();
+		}
+	}
+
+	void DisableEverything() {
+		rotationEnabled = false;
+		translationEnabled = false;
+	}
+
+	/// Enables rotation and translation control for desktop environments.
+	/// For mobile environments, it enables rotation or translation according to
+	/// the device capabilities.
+	void EnableAccordingToPlatform() {
+		rotationEnabled = inDesktopLike || !capabilities.hasOrientation;
+		translationEnabled = inDesktopLike || !capabilities.hasPosition;
+	}
+
+	void Translate() {
+		transform.Translate(
+			SideMovement(),
+			ElevationMovement(),
+			ForwardMovement()
+		);
+	}
+
+	void Rotate() {
+		RegisterMouseMovement();
+		transform.Rotate(Vector3.up, YawMovement(), Space.World);
+		transform.Rotate(Vector3.right, -PitchMovement(), Space.Self);
+	}
+
+	float SideMovement() {
+		return TranslationPerFrame(DirectionFromKeys(
+			strideRightKeys,
+			strideLeftKeys
+		));
+	}
+
+	float ElevationMovement() {
+		return TranslationPerFrame(DirectionFromKeys(
+			moveUpwardKeys,
+			moveDownwardKeys
+		));
+	}
+
+	float ForwardMovement() {
+		return TranslationPerFrame(DirectionFromKeys(
+			moveForwardKeys,
+			moveBackwardsKeys
+		));
+	}
+
+	float TranslationPerFrame(float direction) {
+		return direction * translationSpeed * Time.deltaTime;
+	}
+
+	float DirectionFromKeys(List<KeyCode> positive, List<KeyCode> negative) {
+		if (SomeIsPressed(positive)) {
+			return 1;
+		}
+		if (SomeIsPressed(negative)) {
+			return -1;
+		}
+		return 0;
+	}
+
+	bool SomeIsPressed(List<KeyCode> keys) {
+		return keys.FindAll(k => Input.GetKey(k)).Count > 0;
+	}
+
+	void RegisterMouseMovement() {
+		bool stoppedTracking = Input.GetMouseButtonUp(0);
+		bool isTracking = Input.GetMouseButton(0);
+
+		if (stoppedTracking) {
+			mouseMovement.Set(0, 0, 0);
+		}
+		else if (isTracking) {
+			mouseMovement = Input.mousePosition - lastMousePosition;
+		}
+
+		lastMousePosition = Input.mousePosition;
+	}
+
+	float YawMovement() {
+		return RotationPerFrame(DirectionFromMovement(mouseMovement.x));
+	}
+
+	float PitchMovement() {
+		return RotationPerFrame(DirectionFromMovement(mouseMovement.y));
+	}
+
+	float RotationPerFrame(float direction) {
+		return direction * rotationSpeed * Time.deltaTime;
+	}
+
+	float DirectionFromMovement(float number, float threshold=0.001f) {
+		if (number > threshold) {
+			return 1;
+		}
+		if (number < -threshold) {
+			return -1;
+		}
+		return 0;
+	}
+}
diff --git a/Assets/WebVR/Scripts/Input/FreeFlightController.cs.meta b/Assets/WebVR/Scripts/Input/FreeFlightController.cs.meta
new file mode 100644
index 0000000..25756d9
--- /dev/null
+++ b/Assets/WebVR/Scripts/Input/FreeFlightController.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 683f145ef879be447ba25c1080ac1984
+timeCreated: 1521741240
+licenseType: Free
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/WebVR/Scripts/UI.meta b/Assets/WebVR/Scripts/UI.meta
new file mode 100644
index 0000000..3da951a
--- /dev/null
+++ b/Assets/WebVR/Scripts/UI.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: a2dab90430c8adb4ea32cdb6433d5125
+folderAsset: yes
+timeCreated: 1522148380
+licenseType: Free
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/WebVR/Scripts/UI/WebUI.cs b/Assets/WebVR/Scripts/UI/WebUI.cs
new file mode 100644
index 0000000..c4dfca5
--- /dev/null
+++ b/Assets/WebVR/Scripts/UI/WebUI.cs
@@ -0,0 +1,9 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Runtime.InteropServices;
+public class WebUI {
+
+	[DllImport("__Internal")]
+	public static extern void ShowPanel(string panelId);
+}
diff --git a/Assets/WebVR/Scripts/UI/WebUI.cs.meta b/Assets/WebVR/Scripts/UI/WebUI.cs.meta
new file mode 100644
index 0000000..24c67c5
--- /dev/null
+++ b/Assets/WebVR/Scripts/UI/WebUI.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: c994eddbe9991024395a45fc26ddff3f
+timeCreated: 1522148390
+licenseType: Free
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/WebVR/Scripts/VRDisplayCapabilities.cs b/Assets/WebVR/Scripts/VRDisplayCapabilities.cs
new file mode 100644
index 0000000..4bbea92
--- /dev/null
+++ b/Assets/WebVR/Scripts/VRDisplayCapabilities.cs
@@ -0,0 +1,10 @@
+using UnityEngine;
+
+[System.Serializable]
+public class VRDisplayCapabilities
+{
+	public bool canPresent;
+	public bool hasOrientation;
+	public bool hasPosition;
+	public bool hasExternalDisplay;
+}
diff --git a/Assets/WebVR/Scripts/VRDisplayCapabilities.cs.meta b/Assets/WebVR/Scripts/VRDisplayCapabilities.cs.meta
new file mode 100644
index 0000000..07fb210
--- /dev/null
+++ b/Assets/WebVR/Scripts/VRDisplayCapabilities.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: e5b808a3fa694d143ad05bb10081d67a
+timeCreated: 1522145545
+licenseType: Free
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/WebVR/Scripts/WebVRCamera.cs b/Assets/WebVR/Scripts/WebVRCamera.cs
index 8c4a4be..66eec3c 100755
--- a/Assets/WebVR/Scripts/WebVRCamera.cs
+++ b/Assets/WebVR/Scripts/WebVRCamera.cs
@@ -5,8 +5,8 @@
 
 public class WebVRCamera : MonoBehaviour
 {
-    [DllImport("__Internal")]
-    private static extern void FinishLoading();
+	[DllImport("__Internal")]
+	private static extern void FinishLoading();
 
 	[DllImport("__Internal")]
 	private static extern void TestTimeReturn();
@@ -18,11 +18,10 @@ public class WebVRCamera : MonoBehaviour
 	private static extern void ConfigureToggleVRKeyName(string keyName);
 
 	Camera cameraMain, cameraL, cameraR;
-
-    Quaternion cq;
-    Quaternion lhq;
-    Quaternion rhq;
-    Vector3 cp;
+	Quaternion cq;
+	Quaternion lhq;
+	Quaternion rhq;
+	Vector3 cp;
 
 	// left and right hand position and rotation
 	Vector3 lhp;
@@ -40,11 +39,11 @@ public class WebVRCamera : MonoBehaviour
 	//Matrix4x4 sitStand = Matrix4x4.Translate (new Vector3 (0, 1.2f, 0));
 	Matrix4x4 sitStand = Matrix4x4.identity;
 
-    bool active = false; // vr mode
-    
+	bool active = false; // vr mode
+
 	[Tooltip("GameObject to be controlled by the left hand controller.")]
 	public GameObject leftHandObject;
-    
+
 	[Tooltip("GameObject to be controlled by the right hand controller.")]
 	public GameObject rightHandObject;
 
@@ -83,13 +82,13 @@ public static VRData CreateFromJSON(string jsonString)
 	}
 
 	// received enter VR from WebVR browser
-	public void Begin()
+	public void OnStartVR()
 	{
 		changeMode("vr");
 	}
 
 	// receive exit VR from WebVR browser
-	public void End()
+	public void OnEndVR()
 	{
 		changeMode("normal");
 	}
@@ -100,7 +99,7 @@ public void WebVRData (string jsonString) {
 
 		// left projection matrix
 		clp = numbersToMatrix (data.leftProjectionMatrix);
-	
+
 		// left view matrix
 		clv = numbersToMatrix (data.leftViewMatrix);
 
@@ -227,10 +226,10 @@ void Update()
 			cameraR.projectionMatrix = crp;
 			SetHeadTransform ();
 		} else {
-			// apply left 
+			// apply left
 			cameraMain.worldToCameraMatrix = clv * sitStand.inverse * transform.worldToLocalMatrix;
 		}
-		
+
 		#if UNITY_EDITOR
 		if (leftHandObject) {
 			leftHandObject.transform.localRotation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.LeftHand);
@@ -273,14 +272,14 @@ private Matrix4x4 TransformViewMatrixToTRS(Matrix4x4 openGLViewMatrix) {
 		openGLViewMatrix.m20 *= -1;
 		openGLViewMatrix.m21 *= -1;
 		openGLViewMatrix.m22 *= -1;
-		openGLViewMatrix.m23 *= -1;  
+		openGLViewMatrix.m23 *= -1;
 		return openGLViewMatrix.inverse;
 	}
 
 	private void SetHeadTransform() {
 		Transform leftTransform = cameraL.transform;
 		Transform rightTransform = cameraR.transform;
-		cameraMain.transform.localPosition = 
+		cameraMain.transform.localPosition =
 			(rightTransform.localPosition - leftTransform.localPosition) / 2f + leftTransform.localPosition;
 		cameraMain.transform.localRotation = leftTransform.localRotation;
 		cameraMain.transform.localScale = leftTransform.localScale;
@@ -289,7 +288,7 @@ void OnGUI()
 	{
 		if (!showPerf)
 			return;
-		
+
 		int w = Screen.width, h = Screen.height;
 
 		GUIStyle style = new GUIStyle();
@@ -303,7 +302,7 @@ void OnGUI()
 		string text = string.Format("{0:0.0} ms ({1:0.} fps)", msec, fps);
 		GUI.Label(rect, text, style);
 	}
-		
+
 	// Utility functions
 	private Matrix4x4 numbersToMatrix(float[] array) {
 		var mat = new Matrix4x4 ();
diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt
index e6cd1f9..27997c5 100644
--- a/ProjectSettings/ProjectVersion.txt
+++ b/ProjectSettings/ProjectVersion.txt
@@ -1 +1 @@
-m_EditorVersion: 2017.3.0f3
+m_EditorVersion: 2017.3.1f1

From 72e79dc945ae34440f9392a9ae94e6590c0a7e33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20de=20la=20Puente=20Gonz=C3=A1lez?=
 <salva@unoyunodiez.com>
Date: Wed, 28 Mar 2018 08:20:19 +0200
Subject: [PATCH 2/5] Addressed naming issues

---
 .../Scripts/Input/FreeFlightController.cs     | 35 +++++++++++--------
 ProjectSettings/ProjectVersion.txt            |  2 +-
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/Assets/WebVR/Scripts/Input/FreeFlightController.cs b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
index dd40f79..a82523d 100644
--- a/Assets/WebVR/Scripts/Input/FreeFlightController.cs
+++ b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
@@ -17,19 +17,22 @@ public class FreeFlightController : MonoBehaviour {
 	[Tooltip("Speed of translation in meters/seconds.")]
 	public float translationSpeed = 7;
 
+	[Tooltip("Minimum distance the mouse must move to start registering movement.")]
+	public float rotationDeadDistance = 0.001f;
+
 	[Tooltip("Keys to move forward.")]
 	public List<KeyCode> moveForwardKeys =
 		new List<KeyCode> { KeyCode.W, KeyCode.UpArrow };
 
-	[Tooltip("Keys to move backwards.")]
-	public List<KeyCode> moveBackwardsKeys =
+	[Tooltip("Keys to move backward.")]
+	public List<KeyCode> moveBackwardKeys =
 		new List<KeyCode> { KeyCode.S, KeyCode.DownArrow };
 
-	[Tooltip("Keys to stride-right.")]
+	[Tooltip("Keys to stride to the right.")]
 	public List<KeyCode> strideRightKeys =
 		new List<KeyCode> { KeyCode.D, KeyCode.RightArrow };
 
-	[Tooltip("Keys to stride-left.")]
+	[Tooltip("Keys to stride to the left.")]
 	public List<KeyCode> strideLeftKeys =
 		new List<KeyCode> { KeyCode.A, KeyCode.LeftArrow };
 
@@ -85,8 +88,8 @@ void Update() {
 	}
 
 	void DisableEverything() {
-		rotationEnabled = false;
 		translationEnabled = false;
+		rotationEnabled = false;
 	}
 
 	/// Enables rotation and translation control for desktop environments.
@@ -128,7 +131,7 @@ float ElevationMovement() {
 	float ForwardMovement() {
 		return TranslationPerFrame(DirectionFromKeys(
 			moveForwardKeys,
-			moveBackwardsKeys
+			moveBackwardKeys
 		));
 	}
 
@@ -137,27 +140,27 @@ float TranslationPerFrame(float direction) {
 	}
 
 	float DirectionFromKeys(List<KeyCode> positive, List<KeyCode> negative) {
-		if (SomeIsPressed(positive)) {
+		if (AnyKeyIsPressed(positive)) {
 			return 1;
 		}
-		if (SomeIsPressed(negative)) {
+		if (AnyKeyIsPressed(negative)) {
 			return -1;
 		}
 		return 0;
 	}
 
-	bool SomeIsPressed(List<KeyCode> keys) {
+	bool AnyKeyIsPressed(List<KeyCode> keys) {
 		return keys.FindAll(k => Input.GetKey(k)).Count > 0;
 	}
 
 	void RegisterMouseMovement() {
-		bool stoppedTracking = Input.GetMouseButtonUp(0);
-		bool isTracking = Input.GetMouseButton(0);
+		bool mouseStoppedDragging = Input.GetMouseButtonUp(0);
+		bool mouseIsDragging = Input.GetMouseButton(0);
 
-		if (stoppedTracking) {
+		if (mouseStoppedDragging) {
 			mouseMovement.Set(0, 0, 0);
 		}
-		else if (isTracking) {
+		else if (mouseIsDragging) {
 			mouseMovement = Input.mousePosition - lastMousePosition;
 		}
 
@@ -165,11 +168,13 @@ void RegisterMouseMovement() {
 	}
 
 	float YawMovement() {
-		return RotationPerFrame(DirectionFromMovement(mouseMovement.x));
+		return RotationPerFrame(
+			DirectionFromMovement(mouseMovement.x, rotationDeadDistance));
 	}
 
 	float PitchMovement() {
-		return RotationPerFrame(DirectionFromMovement(mouseMovement.y));
+		return RotationPerFrame(
+			DirectionFromMovement(mouseMovement.y, rotationDeadDistance));
 	}
 
 	float RotationPerFrame(float direction) {
diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt
index 27997c5..e6cd1f9 100644
--- a/ProjectSettings/ProjectVersion.txt
+++ b/ProjectSettings/ProjectVersion.txt
@@ -1 +1 @@
-m_EditorVersion: 2017.3.1f1
+m_EditorVersion: 2017.3.0f3

From cb7d0b376219f29810a3f061a3e649dec465cd3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20de=20la=20Puente=20Gonz=C3=A1lez?=
 <salva@unoyunodiez.com>
Date: Wed, 28 Mar 2018 09:25:37 +0200
Subject: [PATCH 3/5] Clarifying rotation and translation switches

---
 Assets/WebVR/Scripts/Input/FreeFlightController.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Assets/WebVR/Scripts/Input/FreeFlightController.cs b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
index a82523d..5ba7fa6 100644
--- a/Assets/WebVR/Scripts/Input/FreeFlightController.cs
+++ b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
@@ -5,10 +5,10 @@
 
 public class FreeFlightController : MonoBehaviour {
 
-	[Tooltip("Enable/disable rotation control.")]
+	[Tooltip("Enable/disable rotation control. For use in Unity editor only.")]
 	public bool rotationEnabled = true;
 
-	[Tooltip("Enable/disable translation control.")]
+	[Tooltip("Enable/disable translation control. For use in Unity editor only.")]
 	public bool translationEnabled = true;
 
 	[Tooltip("Speed of rotation in degrees/seconds.")]

From 735f97e3d17c5ec228d7246a213218e5c67d9575 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salvador=20de=20la=20Puente=20Gonz=C3=A1lez?=
 <salva@unoyunodiez.com>
Date: Wed, 28 Mar 2018 18:26:44 +0200
Subject: [PATCH 4/5] Fixing initial position

---
 Assets/WebVR/Prefabs/WebVRCameraSet.prefab    | 18 ++++++++++----
 Assets/WebVR/Scenes/WebVR.unity               | 24 ++-----------------
 .../Scripts/Input/FreeFlightController.cs     |  7 ++++++
 Assets/WebVR/Scripts/WebVRCamera.cs           | 12 ++++++----
 ProjectSettings/ProjectSettings.asset         |  2 +-
 5 files changed, 30 insertions(+), 33 deletions(-)

diff --git a/Assets/WebVR/Prefabs/WebVRCameraSet.prefab b/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
index ee552b0..917fc6f 100644
--- a/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
+++ b/Assets/WebVR/Prefabs/WebVRCameraSet.prefab
@@ -57,7 +57,6 @@ GameObject:
   - component: {fileID: 4620614974547310}
   - component: {fileID: 114951743782495552}
   - component: {fileID: 81381995457807688}
-  - component: {fileID: 114848038275145070}
   m_Layer: 0
   m_Name: WebVRCameraSet
   m_TagString: Untagged
@@ -76,6 +75,7 @@ GameObject:
   - component: {fileID: 20329244052411564}
   - component: {fileID: 124144808855090856}
   - component: {fileID: 92017933162973034}
+  - component: {fileID: 114089120386618070}
   m_Layer: 0
   m_Name: CameraMain
   m_TagString: Untagged
@@ -274,21 +274,29 @@ Behaviour:
   m_PrefabInternal: {fileID: 100100000}
   m_GameObject: {fileID: 1147971983220084}
   m_Enabled: 1
---- !u!114 &114848038275145070
+--- !u!114 &114089120386618070
 MonoBehaviour:
   m_ObjectHideFlags: 1
   m_PrefabParentObject: {fileID: 0}
   m_PrefabInternal: {fileID: 100100000}
-  m_GameObject: {fileID: 1514700693580046}
+  m_GameObject: {fileID: 1614126958852788}
   m_Enabled: 1
   m_EditorHideFlags: 0
   m_Script: {fileID: 11500000, guid: 683f145ef879be447ba25c1080ac1984, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  translationSpeed: 7
-  rotationSpeed: 90
   rotationEnabled: 1
   translationEnabled: 1
+  noVROffset: {x: 0, y: 1.2, z: 0}
+  rotationSpeed: 90
+  translationSpeed: 7
+  rotationDeadDistance: 0.001
+  moveForwardKeys: 7700000011010000
+  moveBackwardKeys: 7300000012010000
+  strideRightKeys: 6400000013010000
+  strideLeftKeys: 6100000014010000
+  moveUpwardKeys: 72000000
+  moveDownwardKeys: 66000000
 --- !u!114 &114951743782495552
 MonoBehaviour:
   m_ObjectHideFlags: 1
diff --git a/Assets/WebVR/Scenes/WebVR.unity b/Assets/WebVR/Scenes/WebVR.unity
index bdbe649..57920de 100644
--- a/Assets/WebVR/Scenes/WebVR.unity
+++ b/Assets/WebVR/Scenes/WebVR.unity
@@ -788,7 +788,7 @@ Prefab:
       objectReference: {fileID: 0}
     - target: {fileID: 400030, guid: 013217fcf4bba4f3380d9159876fa8ea, type: 3}
       propertyPath: m_RootOrder
-      value: 2
+      value: 1
       objectReference: {fileID: 0}
     - target: {fileID: 9500000, guid: 013217fcf4bba4f3380d9159876fa8ea, type: 3}
       propertyPath: m_Enabled
@@ -889,11 +889,6 @@ MeshFilter:
   m_PrefabInternal: {fileID: 0}
   m_GameObject: {fileID: 705953490}
   m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
---- !u!1 &757088923 stripped
-GameObject:
-  m_PrefabParentObject: {fileID: 1147971983220084, guid: 78df02845d4b54181b4ca9188aba0671,
-    type: 2}
-  m_PrefabInternal: {fileID: 1315843485}
 --- !u!1 &821505835 stripped
 GameObject:
   m_PrefabParentObject: {fileID: 100030, guid: 013217fcf4bba4f3380d9159876fa8ea, type: 3}
@@ -975,7 +970,7 @@ Prefab:
       objectReference: {fileID: 0}
     - target: {fileID: 400030, guid: c99aacc3accab4fdaadab5e3ea13b9c7, type: 3}
       propertyPath: m_RootOrder
-      value: 1
+      value: 2
       objectReference: {fileID: 0}
     - target: {fileID: 9500000, guid: c99aacc3accab4fdaadab5e3ea13b9c7, type: 3}
       propertyPath: m_Enabled
@@ -1606,16 +1601,6 @@ Prefab:
       propertyPath: m_RootOrder
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 114951743782495552, guid: 78df02845d4b54181b4ca9188aba0671,
-        type: 2}
-      propertyPath: leftHandObject
-      value: 
-      objectReference: {fileID: 757088923}
-    - target: {fileID: 114951743782495552, guid: 78df02845d4b54181b4ca9188aba0671,
-        type: 2}
-      propertyPath: rightHandObject
-      value: 
-      objectReference: {fileID: 2040219167}
     m_RemovedComponents: []
   m_ParentPrefab: {fileID: 100100000, guid: 78df02845d4b54181b4ca9188aba0671, type: 2}
   m_IsPrefabParent: 0
@@ -2194,11 +2179,6 @@ Transform:
   m_Father: {fileID: 2005427646}
   m_RootOrder: 0
   m_LocalEulerAnglesHint: {x: -16.601002, y: -7.7430005, z: 25.449001}
---- !u!1 &2040219167 stripped
-GameObject:
-  m_PrefabParentObject: {fileID: 1118756453539842, guid: 78df02845d4b54181b4ca9188aba0671,
-    type: 2}
-  m_PrefabInternal: {fileID: 1315843485}
 --- !u!4 &2066780126 stripped
 Transform:
   m_PrefabParentObject: {fileID: 400000, guid: 7e57e26a714804d3c9f1baa605131856, type: 3}
diff --git a/Assets/WebVR/Scripts/Input/FreeFlightController.cs b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
index 5ba7fa6..ab679fb 100644
--- a/Assets/WebVR/Scripts/Input/FreeFlightController.cs
+++ b/Assets/WebVR/Scripts/Input/FreeFlightController.cs
@@ -11,6 +11,9 @@ public class FreeFlightController : MonoBehaviour {
 	[Tooltip("Enable/disable translation control. For use in Unity editor only.")]
 	public bool translationEnabled = true;
 
+	[Tooltip("Offset position to apply when VR is not available.")]
+	public Vector3 noVROffset = new Vector3(0, 1.2f, 0);
+
 	[Tooltip("Speed of rotation in degrees/seconds.")]
 	public float rotationSpeed = 90;
 
@@ -75,6 +78,10 @@ public void OnVRCapabilities(VRDisplayCapabilities vrCapabilities) {
 		}
 		#endif
 
+		if (inDesktopLike || !capabilities.hasPosition) {
+			transform.Translate(noVROffset);
+		}
+
 		EnableAccordingToPlatform();
 	}
 
diff --git a/Assets/WebVR/Scripts/WebVRCamera.cs b/Assets/WebVR/Scripts/WebVRCamera.cs
index 66eec3c..bcce65c 100755
--- a/Assets/WebVR/Scripts/WebVRCamera.cs
+++ b/Assets/WebVR/Scripts/WebVRCamera.cs
@@ -84,15 +84,21 @@ public static VRData CreateFromJSON(string jsonString)
 	// received enter VR from WebVR browser
 	public void OnStartVR()
 	{
+		GameObject.Find("CameraMain").SendMessage("OnStartVR");
 		changeMode("vr");
 	}
 
 	// receive exit VR from WebVR browser
 	public void OnEndVR()
 	{
+		GameObject.Find("CameraMain").SendMessage("OnEndVR");
 		changeMode("normal");
 	}
 
+	public void OnVRCapabilities(string json) {
+		GameObject.Find("CameraMain").SendMessage("OnVRCapabilities", json);
+	}
+
 	// receive WebVR data from browser.
 	public void WebVRData (string jsonString) {
 		VRData data = VRData.CreateFromJSON (jsonString);
@@ -165,9 +171,9 @@ private void changeMode(string mode)
 		switch (mode)
 		{
 		case "normal":
-			cameraMain.enabled = true;
 			cameraL.enabled = false;
 			cameraR.enabled = false;
+			cameraMain.enabled = true;
 			active = false;
 			break;
 		case "vr":
@@ -218,16 +224,12 @@ void Update()
 		#endif
 
 		deltaTime += (Time.deltaTime - deltaTime) * 0.1f;
-
 		if (active) {
 			SetTransformFromViewMatrix (cameraL.transform, clv * sitStand.inverse * transform.worldToLocalMatrix);
 			cameraL.projectionMatrix = clp;
 			SetTransformFromViewMatrix (cameraR.transform, crv * sitStand.inverse * transform.worldToLocalMatrix);
 			cameraR.projectionMatrix = crp;
 			SetHeadTransform ();
-		} else {
-			// apply left
-			cameraMain.worldToCameraMatrix = clv * sitStand.inverse * transform.worldToLocalMatrix;
 		}
 
 		#if UNITY_EDITOR
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 030cfe2..28c15c2 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -260,7 +260,7 @@ PlayerSettings:
   m_BuildTargetGraphicsAPIs: []
   m_BuildTargetVRSettings:
   - m_BuildTarget: Standalone
-    m_Enabled: 1
+    m_Enabled: 0
     m_Devices:
     - OpenVR
     - Oculus

From f1c2e903a3fd7602aae847ca98d30b96fc1ddc6a Mon Sep 17 00:00:00 2001
From: "C. Van Wiemeersch" <cvan@users.noreply.github.com>
Date: Mon, 2 Apr 2018 23:27:58 -0700
Subject: [PATCH 5/5] fix nit: add whitespace

---
 Assets/WebVR/Plugins/WebGL/webvr.jslib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Assets/WebVR/Plugins/WebGL/webvr.jslib b/Assets/WebVR/Plugins/WebGL/webvr.jslib
index db15b1d..15b812a 100755
--- a/Assets/WebVR/Plugins/WebGL/webvr.jslib
+++ b/Assets/WebVR/Plugins/WebGL/webvr.jslib
@@ -17,6 +17,6 @@ mergeInto(LibraryManager.library, {
   },
 
   ShowPanel: function (panelId) {
-    document.dispatchEvent(new CustomEvent('Unity', {detail: {type:'ShowPanel', panelId: Pointer_stringify(panelId)}}));
+    document.dispatchEvent(new CustomEvent('Unity', {detail: {type: 'ShowPanel', panelId: Pointer_stringify(panelId)}}));
   }
 });