Added VR libraries

This commit is contained in:
Chris Midkiff
2018-10-08 23:54:11 -04:00
parent d9eb2a9763
commit 7ce1036e39
1037 changed files with 195630 additions and 348 deletions

View File

@@ -0,0 +1,459 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This provider is only available on an Android device.
#if UNITY_ANDROID && !UNITY_EDITOR
using UnityEngine;
using System;
using System.Runtime.InteropServices;
/// @cond
namespace Gvr.Internal {
/// Controller Provider that uses the native GVR C API to communicate with controllers
/// via Google VR Services on Android.
class AndroidNativeControllerProvider : IControllerProvider {
// Note: keep structs and function signatures in sync with the C header file (gvr_controller.h).
// GVR controller option flags.
private const int GVR_CONTROLLER_ENABLE_ORIENTATION = 1 << 0;
private const int GVR_CONTROLLER_ENABLE_TOUCH = 1 << 1;
private const int GVR_CONTROLLER_ENABLE_GYRO = 1 << 2;
private const int GVR_CONTROLLER_ENABLE_ACCEL = 1 << 3;
private const int GVR_CONTROLLER_ENABLE_GESTURES = 1 << 4;
private const int GVR_CONTROLLER_ENABLE_POSE_PREDICTION = 1 << 5;
private const int GVR_CONTROLLER_ENABLE_POSITION = 1 << 6;
private const int GVR_CONTROLLER_ENABLE_BATTERY = 1 << 7;
private const int GVR_CONTROLLER_ENABLE_ARM_MODEL = 1 << 8;
// enum gvr_controller_button:
private const int GVR_CONTROLLER_BUTTON_NONE = 0;
private const int GVR_CONTROLLER_BUTTON_CLICK = 1;
private const int GVR_CONTROLLER_BUTTON_HOME = 2;
private const int GVR_CONTROLLER_BUTTON_APP = 3;
private const int GVR_CONTROLLER_BUTTON_VOLUME_UP = 4;
private const int GVR_CONTROLLER_BUTTON_VOLUME_DOWN = 5;
private const int GVR_CONTROLLER_BUTTON_RESERVED0 = 6;
private const int GVR_CONTROLLER_BUTTON_RESERVED1 = 7;
private const int GVR_CONTROLLER_BUTTON_RESERVED2 = 8;
private const int GVR_CONTROLLER_BUTTON_COUNT = 9;
// enum gvr_controller_connection_state:
private const int GVR_CONTROLLER_DISCONNECTED = 0;
private const int GVR_CONTROLLER_SCANNING = 1;
private const int GVR_CONTROLLER_CONNECTING = 2;
private const int GVR_CONTROLLER_CONNECTED = 3;
// enum gvr_controller_api_status
private const int GVR_CONTROLLER_API_OK = 0;
private const int GVR_CONTROLLER_API_UNSUPPORTED = 1;
private const int GVR_CONTROLLER_API_NOT_AUTHORIZED = 2;
private const int GVR_CONTROLLER_API_UNAVAILABLE = 3;
private const int GVR_CONTROLLER_API_SERVICE_OBSOLETE = 4;
private const int GVR_CONTROLLER_API_CLIENT_OBSOLETE = 5;
private const int GVR_CONTROLLER_API_MALFUNCTION = 6;
// The serialization of button-state used to determine which buttons are being pressed.
private readonly GvrControllerButton[] GVR_UNITY_BUTTONS = new GvrControllerButton[] {
GvrControllerButton.App,
GvrControllerButton.System,
GvrControllerButton.TouchPadButton,
GvrControllerButton.Reserved0,
GvrControllerButton.Reserved1,
GvrControllerButton.Reserved2
};
private readonly int[] GVR_BUTTONS = new int[] {
GVR_CONTROLLER_BUTTON_APP,
GVR_CONTROLLER_BUTTON_HOME,
GVR_CONTROLLER_BUTTON_CLICK,
GVR_CONTROLLER_BUTTON_RESERVED0,
GVR_CONTROLLER_BUTTON_RESERVED1,
GVR_CONTROLLER_BUTTON_RESERVED2
};
[StructLayout(LayoutKind.Sequential)]
private struct gvr_quat {
internal float x;
internal float y;
internal float z;
internal float w;
}
[StructLayout(LayoutKind.Sequential)]
private struct gvr_vec3 {
internal float x;
internal float y;
internal float z;
}
[StructLayout(LayoutKind.Sequential)]
private struct gvr_vec2 {
internal float x;
internal float y;
}
private const string dllName = GvrActivityHelper.GVR_DLL_NAME;
[DllImport(dllName)]
private static extern int gvr_controller_get_default_options();
[DllImport(dllName)]
private static extern IntPtr gvr_controller_create_and_init_android(
IntPtr jniEnv, IntPtr androidContext, IntPtr classLoader,
int options, IntPtr context);
[DllImport(dllName)]
private static extern void gvr_controller_destroy(ref IntPtr api);
[DllImport(dllName)]
private static extern void gvr_controller_pause(IntPtr api);
[DllImport(dllName)]
private static extern void gvr_controller_resume(IntPtr api);
[DllImport(dllName)]
private static extern IntPtr gvr_controller_state_create();
[DllImport(dllName)]
private static extern void gvr_controller_state_destroy(ref IntPtr state);
[DllImport(dllName)]
private static extern void gvr_controller_state_update(IntPtr api, int flags, IntPtr out_state);
[DllImport(dllName)]
private static extern int gvr_controller_state_get_api_status(IntPtr state);
[DllImport(dllName)]
private static extern int gvr_controller_state_get_connection_state(IntPtr state);
[DllImport(dllName)]
private static extern gvr_quat gvr_controller_state_get_orientation(IntPtr state);
[DllImport(dllName)]
private static extern gvr_vec3 gvr_controller_state_get_position(IntPtr state);
[DllImport(dllName)]
private static extern gvr_vec3 gvr_controller_state_get_gyro(IntPtr state);
[DllImport(dllName)]
private static extern gvr_vec3 gvr_controller_state_get_accel(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_is_touching(IntPtr state);
[DllImport(dllName)]
private static extern gvr_vec2 gvr_controller_state_get_touch_pos(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_touch_down(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_touch_up(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_recentered(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_button_state(IntPtr state, int button);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_button_down(IntPtr state, int button);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_button_up(IntPtr state, int button);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_orientation_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_gyro_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_accel_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_touch_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_button_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern byte gvr_controller_state_get_battery_charging(IntPtr state);
[DllImport(dllName)]
private static extern int gvr_controller_state_get_battery_level(IntPtr state);
[DllImport(dllName)]
private static extern long gvr_controller_state_get_last_battery_timestamp(IntPtr state);
[DllImport(dllName)]
private static extern int gvr_controller_get_count(IntPtr api);
private const string VRCORE_UTILS_CLASS = "com.google.vr.vrcore.base.api.VrCoreUtils";
private IntPtr api;
private bool hasBatteryMethods = false;
private AndroidJavaObject androidContext;
private AndroidJavaObject classLoader;
private bool error = false;
private string errorDetails = string.Empty;
private IntPtr statePtr;
private MutablePose3D pose3d = new MutablePose3D();
private GvrControllerButton[] lastButtonsState = new GvrControllerButton[2];
public bool SupportsBatteryStatus {
get { return hasBatteryMethods; }
}
public int MaxControllerCount {
get {
if (api == IntPtr.Zero) {
return 0;
}
return gvr_controller_get_count(api);
}
}
internal AndroidNativeControllerProvider() {
// Debug.Log("Initializing Daydream controller API.");
int options = gvr_controller_get_default_options();
options |= GVR_CONTROLLER_ENABLE_ACCEL;
options |= GVR_CONTROLLER_ENABLE_GYRO;
options |= GVR_CONTROLLER_ENABLE_POSITION;
statePtr = gvr_controller_state_create();
// Get a hold of the activity, context and class loader.
AndroidJavaObject activity = GvrActivityHelper.GetActivity();
if (activity == null) {
error = true;
errorDetails = "Failed to get Activity from Unity Player.";
return;
}
androidContext = GvrActivityHelper.GetApplicationContext(activity);
if (androidContext == null) {
error = true;
errorDetails = "Failed to get Android application context from Activity.";
return;
}
classLoader = GetClassLoaderFromActivity(activity);
if (classLoader == null) {
error = true;
errorDetails = "Failed to get class loader from Activity.";
return;
}
// Use IntPtr instead of GetRawObject() so that Unity can shut down gracefully on
// Application.Quit(). Note that GetRawObject() is not pinned by the receiver so it's not
// cleaned up appropriately on shutdown, which is a known bug in Unity.
IntPtr androidContextPtr = AndroidJNI.NewLocalRef(androidContext.GetRawObject());
IntPtr classLoaderPtr = AndroidJNI.NewLocalRef(classLoader.GetRawObject());
Debug.Log ("Creating and initializing GVR API controller object.");
api = gvr_controller_create_and_init_android (IntPtr.Zero, androidContextPtr, classLoaderPtr,
options, IntPtr.Zero);
AndroidJNI.DeleteLocalRef(androidContextPtr);
AndroidJNI.DeleteLocalRef(classLoaderPtr);
if (IntPtr.Zero == api) {
Debug.LogError("Error creating/initializing Daydream controller API.");
error = true;
errorDetails = "Failed to initialize Daydream controller API.";
return;
}
try {
gvr_controller_state_get_battery_charging(statePtr);
gvr_controller_state_get_battery_level(statePtr);
hasBatteryMethods = true;
} catch (EntryPointNotFoundException) {
// Older VrCore version. Does not support battery indicator.
// Note that controller API is not dynamically loaded as of June 2017 (b/35662043),
// so we'll need to support this case indefinitely...
}
// Debug.Log("GVR API successfully initialized. Now resuming it.");
gvr_controller_resume(api);
// Debug.Log("GVR API resumed.");
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
// Debug.Log("Destroying GVR API structures.");
gvr_controller_state_destroy(ref statePtr);
gvr_controller_destroy(ref api);
if (statePtr != IntPtr.Zero) {
Debug.LogError("gvr_controller_state not zeroed after destroy");
}
if (api != IntPtr.Zero) {
Debug.LogError("gvr_controller_api not zeroed after destroy");
}
// Debug.Log("AndroidNativeControllerProvider destroyed.");
}
}
public void ReadState(ControllerState outState, int controller_id) {
if (error) {
outState.connectionState = GvrConnectionState.Error;
outState.apiStatus = GvrControllerApiStatus.Error;
outState.errorDetails = errorDetails;
return;
}
if (api == IntPtr.Zero || statePtr == IntPtr.Zero) {
Debug.LogError("AndroidNativeControllerProvider used after dispose.");
return;
}
gvr_controller_state_update(api, controller_id, statePtr);
outState.connectionState = ConvertConnectionState(
gvr_controller_state_get_connection_state(statePtr));
outState.apiStatus = ConvertControllerApiStatus(
gvr_controller_state_get_api_status(statePtr));
gvr_quat rawOri = gvr_controller_state_get_orientation(statePtr);
gvr_vec3 rawAccel = gvr_controller_state_get_accel(statePtr);
gvr_vec3 rawGyro = gvr_controller_state_get_gyro(statePtr);
gvr_vec3 rawPos = gvr_controller_state_get_position(statePtr);
// Convert GVR API orientation (right-handed) into Unity axis system (left-handed).
pose3d.Set(new Vector3(rawPos.x,rawPos.y,rawPos.z), new Quaternion(rawOri.x, rawOri.y, rawOri.z, rawOri.w));
pose3d.SetRightHanded(pose3d.Matrix);
outState.orientation = pose3d.Orientation;
outState.position = pose3d.Position;
// For accelerometer, we have to flip Z because the GVR API has Z pointing backwards
// and Unity has Z pointing forward.
outState.accel = new Vector3(rawAccel.x, rawAccel.y, -rawAccel.z);
// Gyro in GVR represents a right-handed angular velocity about each axis (positive means
// clockwise when sighting along axis). Since Unity uses a left-handed system, we flip the
// signs to adjust the sign of the rotational velocity (so that positive means
// counter-clockwise). In addition, since in Unity the Z axis points forward while GVR
// has Z pointing backwards, we flip the Z axis sign again. So the result is that
// we should use -X, -Y, +Z:
outState.gyro = new Vector3(-rawGyro.x, -rawGyro.y, rawGyro.z);
gvr_vec2 touchPos = gvr_controller_state_get_touch_pos(statePtr);
outState.touchPos = new Vector2(touchPos.x, touchPos.y);
outState.buttonsState = 0;
for (int i=0; i<GVR_BUTTONS.Length; i++) {
if (0 != gvr_controller_state_get_button_state(statePtr, GVR_BUTTONS[i])) {
outState.buttonsState |= GVR_UNITY_BUTTONS[i];
}
}
if (0 != gvr_controller_state_is_touching(statePtr)) {
outState.buttonsState |= GvrControllerButton.TouchPadTouch;
}
outState.SetButtonsUpDownFromPrevious(lastButtonsState[controller_id]);
lastButtonsState[controller_id] = outState.buttonsState;
outState.recentered = 0 != gvr_controller_state_get_recentered(statePtr);
outState.gvrPtr = statePtr;
if (hasBatteryMethods) {
outState.isCharging = 0 != gvr_controller_state_get_battery_charging(statePtr);
outState.batteryLevel = (GvrControllerBatteryLevel)gvr_controller_state_get_battery_level(statePtr);
}
}
public void OnPause() {
if (IntPtr.Zero != api) {
gvr_controller_pause(api);
}
}
public void OnResume() {
if (IntPtr.Zero != api) {
gvr_controller_resume(api);
}
}
private GvrConnectionState ConvertConnectionState(int connectionState) {
switch (connectionState) {
case GVR_CONTROLLER_CONNECTED:
return GvrConnectionState.Connected;
case GVR_CONTROLLER_CONNECTING:
return GvrConnectionState.Connecting;
case GVR_CONTROLLER_SCANNING:
return GvrConnectionState.Scanning;
default:
return GvrConnectionState.Disconnected;
}
}
private GvrControllerApiStatus ConvertControllerApiStatus(int gvrControllerApiStatus) {
switch (gvrControllerApiStatus) {
case GVR_CONTROLLER_API_OK:
return GvrControllerApiStatus.Ok;
case GVR_CONTROLLER_API_UNSUPPORTED:
return GvrControllerApiStatus.Unsupported;
case GVR_CONTROLLER_API_NOT_AUTHORIZED:
return GvrControllerApiStatus.NotAuthorized;
case GVR_CONTROLLER_API_SERVICE_OBSOLETE:
return GvrControllerApiStatus.ApiServiceObsolete;
case GVR_CONTROLLER_API_CLIENT_OBSOLETE:
return GvrControllerApiStatus.ApiClientObsolete;
case GVR_CONTROLLER_API_MALFUNCTION:
return GvrControllerApiStatus.ApiMalfunction;
case GVR_CONTROLLER_API_UNAVAILABLE:
default: // Fall through.
return GvrControllerApiStatus.Unavailable;
}
}
private static void UpdateInputEvents(bool currentState, ref bool previousState, ref bool up, ref bool down) {
down = !previousState && currentState;
up = previousState && !currentState;
previousState = currentState;
}
private static AndroidJavaObject GetClassLoaderFromActivity(AndroidJavaObject activity) {
AndroidJavaObject result = activity.Call<AndroidJavaObject>("getClassLoader");
if (result == null) {
Debug.LogErrorFormat("Failed to get class loader from Activity.");
return null;
}
return result;
}
private static int GetVrCoreClientApiVersion(AndroidJavaObject activity) {
try {
AndroidJavaClass utilsClass = new AndroidJavaClass(VRCORE_UTILS_CLASS);
int apiVersion = utilsClass.CallStatic<int>("getVrCoreClientApiVersion", activity);
// Debug.LogFormat("VrCore client API version: " + apiVersion);
return apiVersion;
} catch (Exception exc) {
// Even though a catch-all block is normally frowned upon, in this case we really
// need it because this method has to be robust to unpredictable circumstances:
// VrCore might not exist in the device, the Java layer might be broken, etc, etc.
// None of those should abort the app.
Debug.LogError("Error obtaining VrCore client API version: " + exc);
return 0;
}
}
}
}
/// @endcond
#endif // UNITY_ANDROID && !UNITY_EDITOR

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3fda152dc25154b4a9cccb75fd77f018
timeCreated: 1462060442
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Gvr;
/// @cond
namespace Gvr.Internal {
/// Dummy controller provider.
/// Used in platforms that do not support controllers.
class DummyControllerProvider : IControllerProvider {
private ControllerState dummyState = new ControllerState();
public bool SupportsBatteryStatus {
get { return false; }
}
public int MaxControllerCount {
get { return 1; }
}
internal DummyControllerProvider() {}
public void Dispose() {}
public void ReadState(ControllerState outState,int controller_id) {
outState.CopyFrom(dummyState);
}
public void OnPause() {}
public void OnResume() {}
}
}
/// @endcond

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0f791be37caef48c79f72011276ab16a
timeCreated: 1462043669
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This provider is only available in the editor.
#if UNITY_EDITOR
using Gvr;
namespace Gvr.Internal {
/// Controller provider used when playing in the Unity Editor.
/// Supports the Controller Emulator and Mouse input to mock the controller.
class EditorControllerProvider : IControllerProvider {
private EmulatorControllerProvider emulatorControllerProvider;
private MouseControllerProvider mouseControllerProvider;
#if UNITY_HAS_GOOGLEVR
/// Helper class to get Instant Preview controller events if connected.
private InstantPreviewControllerProvider instantPreviewControllerProvider =
new InstantPreviewControllerProvider();
#endif // UNITY_HAS_GOOGLEVR
ControllerState emulatorState = new ControllerState();
ControllerState mouseState = new ControllerState();
public bool SupportsBatteryStatus {
get { return emulatorControllerProvider.SupportsBatteryStatus; }
}
public int MaxControllerCount {
get { return 1; }
}
internal EditorControllerProvider(GvrControllerInput.EmulatorConnectionMode connectionMode) {
emulatorControllerProvider = new EmulatorControllerProvider(connectionMode);
mouseControllerProvider = new MouseControllerProvider();
}
public void Dispose() {}
public void ReadState(ControllerState outState, int controller_id) {
if (controller_id != 0) {
return;
}
#if UNITY_HAS_GOOGLEVR
if (InstantPreview.Instance != null
&& InstantPreview.Instance.IsCurrentlyConnected
&& !EmulatorManager.Instance.Connected) {
// Uses Instant Preview to get controller state if connected.
instantPreviewControllerProvider.ReadState(outState);
return;
}
#endif // UNITY_HAS_GOOGLEVR
// If Instant Preview is not connected, tries to use the emulator or
// mouse.
emulatorControllerProvider.ReadState(emulatorState, controller_id);
mouseControllerProvider.ReadState(mouseState, controller_id);
// Defaults to mouse state if the emulator isn't available.
if (emulatorState.connectionState != GvrConnectionState.Connected
&& mouseState.connectionState == GvrConnectionState.Connected) {
outState.CopyFrom(mouseState);
} else {
outState.CopyFrom(emulatorState);
}
}
public void OnPause() {
emulatorControllerProvider.OnPause();
mouseControllerProvider.OnPause();
}
public void OnResume() {
emulatorControllerProvider.OnResume();
mouseControllerProvider.OnResume();
}
}
}
#endif // UNITY_EDITOR

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e0a32f2191dec4e1b8e05acab6002be6
timeCreated: 1496354837
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,191 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This class is only used in the Editor, so make sure to only compile it on that platform.
// Additionally, it depends on EmulatorManager which is only compiled in the editor.
#if UNITY_EDITOR
using UnityEngine;
/// @cond
namespace Gvr.Internal {
/// Controller provider that connects to the controller emulator to obtain controller events.
class EmulatorControllerProvider : IControllerProvider {
private ControllerState state = new ControllerState();
/// Yaw correction due to recentering.
private Quaternion yawCorrection = Quaternion.identity;
/// True if we performed the initial recenter.
private bool initialRecenterDone = false;
/// The last (uncorrected) orientation received from the emulator.
private Quaternion lastRawOrientation = Quaternion.identity;
private GvrControllerButton lastButtonsState;
public bool SupportsBatteryStatus {
get { return true; }
}
public int MaxControllerCount {
get { return 1; }
}
/// Creates a new EmulatorControllerProvider with the specified settings.
internal EmulatorControllerProvider(GvrControllerInput.EmulatorConnectionMode connectionMode) {
if (connectionMode == GvrControllerInput.EmulatorConnectionMode.USB) {
EmulatorConfig.Instance.PHONE_EVENT_MODE = EmulatorConfig.Mode.USB;
} else if (connectionMode == GvrControllerInput.EmulatorConnectionMode.WIFI) {
EmulatorConfig.Instance.PHONE_EVENT_MODE = EmulatorConfig.Mode.WIFI;
} else {
EmulatorConfig.Instance.PHONE_EVENT_MODE = EmulatorConfig.Mode.OFF;
}
EmulatorManager.Instance.touchEventListeners += HandleTouchEvent;
EmulatorManager.Instance.orientationEventListeners += HandleOrientationEvent;
EmulatorManager.Instance.buttonEventListeners += HandleButtonEvent;
EmulatorManager.Instance.gyroEventListeners += HandleGyroEvent;
EmulatorManager.Instance.accelEventListeners += HandleAccelEvent;
}
public void Dispose() {}
public void ReadState(ControllerState outState, int controller_id) {
if (controller_id != 0) {
return;
}
lock (state) {
state.connectionState = GvrConnectionState.Connected;
if (!EmulatorManager.Instance.Connected) {
state.connectionState = EmulatorManager.Instance.Connecting ?
GvrConnectionState.Connecting : GvrConnectionState.Disconnected;
}
state.apiStatus = EmulatorManager.Instance.Connected ? GvrControllerApiStatus.Ok :
GvrControllerApiStatus.Unavailable;
// During emulation, just assume the controller is fully charged
state.isCharging = false;
state.batteryLevel = GvrControllerBatteryLevel.Full;
state.SetButtonsUpDownFromPrevious(lastButtonsState);
lastButtonsState = state.buttonsState;
outState.CopyFrom(state);
}
state.ClearTransientState();
}
public void OnPause() {}
public void OnResume() {}
private void HandleTouchEvent(EmulatorTouchEvent touchEvent) {
if (touchEvent.pointers.Count < 1) return;
EmulatorTouchEvent.Pointer pointer = touchEvent.pointers[0];
lock (state) {
state.touchPos = new Vector2(pointer.normalizedX, pointer.normalizedY);
switch (touchEvent.getActionMasked()) {
case EmulatorTouchEvent.Action.kActionDown:
state.buttonsState |= GvrControllerButton.TouchPadTouch;
break;
case EmulatorTouchEvent.Action.kActionMove:
state.buttonsState |= GvrControllerButton.TouchPadTouch;
break;
case EmulatorTouchEvent.Action.kActionUp:
state.buttonsState &= ~GvrControllerButton.TouchPadTouch;
break;
}
}
}
private void HandleOrientationEvent(EmulatorOrientationEvent orientationEvent) {
lastRawOrientation = ConvertEmulatorQuaternion(orientationEvent.orientation);
if (!initialRecenterDone) {
Recenter();
initialRecenterDone = true;
}
lock (state) {
state.orientation = yawCorrection * lastRawOrientation;
}
}
private void HandleButtonEvent(EmulatorButtonEvent buttonEvent) {
GvrControllerButton buttonMask = 0;
switch (buttonEvent.code) {
case EmulatorButtonEvent.ButtonCode.kApp:
buttonMask = GvrControllerButton.App;
break;
case EmulatorButtonEvent.ButtonCode.kHome:
buttonMask = GvrControllerButton.System;
break;
case EmulatorButtonEvent.ButtonCode.kClick:
buttonMask = GvrControllerButton.TouchPadButton;
break;
}
if (buttonMask != 0) {
lock (state) {
state.buttonsState &= ~buttonMask;
if (buttonEvent.down) {
state.buttonsState |= buttonMask;
}
}
if (buttonMask == GvrControllerButton.System) {
if (!buttonEvent.down) {
// Finished the recentering gesture. Recenter controller.
Recenter();
}
}
}
}
private void HandleGyroEvent(EmulatorGyroEvent gyroEvent) {
lock (state) {
state.gyro = ConvertEmulatorGyro(gyroEvent.value);
}
}
private void HandleAccelEvent(EmulatorAccelEvent accelEvent) {
lock (state) {
state.accel = ConvertEmulatorAccel(accelEvent.value);
}
}
private static Quaternion ConvertEmulatorQuaternion(Quaternion emulatorQuat) {
// Convert from the emulator's coordinate space to Unity's standard coordinate space.
return new Quaternion(emulatorQuat.x, -emulatorQuat.z, emulatorQuat.y, emulatorQuat.w);
}
private static Vector3 ConvertEmulatorGyro(Vector3 emulatorGyro) {
// Convert from the emulator's coordinate space to Unity's standard coordinate space.
return new Vector3(-emulatorGyro.x, -emulatorGyro.z, -emulatorGyro.y);
}
private static Vector3 ConvertEmulatorAccel(Vector3 emulatorAccel) {
// Convert from the emulator's coordinate space to Unity's standard coordinate space.
return new Vector3(emulatorAccel.x, emulatorAccel.z, emulatorAccel.y);
}
private void Recenter() {
lock (state) {
// We want the current orientation to be "forward" so, we set the yaw correction
// to undo the current rotation's yaw.
yawCorrection = Quaternion.AngleAxis(-lastRawOrientation.eulerAngles.y, Vector3.up);
state.orientation = Quaternion.identity;
state.recentered = true;
}
}
}
}
/// @endcond
#endif // UNITY_EDITOR

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0ca644865f5f4479fb50471605078cf0
timeCreated: 1462051657
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,198 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Gvr;
using UnityEngine;
namespace Gvr.Internal {
/// Mocks controller input by using the mouse.
/// The controller is connected when holding left shift.
/// Move the mouse to control gyroscope and orientation.
/// The left mouse button is used for the clickButton.
/// The right mouse button is used for the appButton.
/// The middle mouse button is used for the homeButton.
class MouseControllerProvider : IControllerProvider {
private const string AXIS_MOUSE_X = "Mouse X";
private const string AXIS_MOUSE_Y = "Mouse Y";
private ControllerState state = new ControllerState();
private Vector2 mouseDelta = new Vector2();
/// Need to store the state of the buttons from the previous frame.
/// This is because Input.GetMouseButtonDown and Input.GetMouseButtonUp
/// don't work when called after WaitForEndOfFrame, which is when ReadState is called.
private bool wasTouching;
private GvrControllerButton lastButtonsState;
private const float ROTATE_SENSITIVITY = 4.5f;
private const float TOUCH_SENSITIVITY = .12f;
private static readonly Vector3 INVERT_Y = new Vector3(1, -1, 1);
public static bool IsMouseAvailable {
get {
return Input.mousePresent && IsActivateButtonPressed;
}
}
public static bool IsActivateButtonPressed {
get {
return Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
}
}
public static bool IsClickButtonPressed {
get {
return Input.GetMouseButton(0);
}
}
public static bool IsAppButtonPressed {
get {
return Input.GetMouseButton(1);
}
}
public static bool IsHomeButtonPressed {
get {
return Input.GetMouseButton(2);
}
}
public static bool IsTouching {
get {
return Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
}
}
public bool SupportsBatteryStatus {
get { return false; }
}
public int MaxControllerCount {
get { return 1; }
}
internal MouseControllerProvider() {}
public void Dispose() {}
public void ReadState(ControllerState outState, int controller_id) {
if (controller_id != 0) {
return;
}
lock (state) {
UpdateState();
outState.CopyFrom(state);
}
state.ClearTransientState();
}
public void OnPause() {}
public void OnResume() {}
private void UpdateState() {
GvrCursorHelper.ControllerEmulationActive = IsMouseAvailable;
if (!IsMouseAvailable) {
ClearState();
return;
}
state.connectionState = GvrConnectionState.Connected;
state.apiStatus = GvrControllerApiStatus.Ok;
state.isCharging = false;
state.batteryLevel = GvrControllerBatteryLevel.Full;
UpdateButtonStates();
mouseDelta.Set(
Input.GetAxis(AXIS_MOUSE_X),
Input.GetAxis(AXIS_MOUSE_Y)
);
if (0 != (state.buttonsState & GvrControllerButton.TouchPadTouch)) {
UpdateTouchPos();
} else {
UpdateOrientation();
}
}
private void UpdateTouchPos() {
Vector3 currentMousePosition = Input.mousePosition;
Vector2 touchDelta = mouseDelta * TOUCH_SENSITIVITY;
touchDelta.y *= -1.0f;
state.touchPos += touchDelta;
state.touchPos.x = Mathf.Clamp01(state.touchPos.x);
state.touchPos.y = Mathf.Clamp01(state.touchPos.y);
}
private void UpdateOrientation() {
Vector3 deltaDegrees = Vector3.Scale(mouseDelta, INVERT_Y) * ROTATE_SENSITIVITY;
state.gyro = deltaDegrees * (Mathf.Deg2Rad / Time.deltaTime);
Quaternion yaw = Quaternion.AngleAxis(deltaDegrees.x, Vector3.up);
Quaternion pitch = Quaternion.AngleAxis(deltaDegrees.y, Vector3.right);
state.orientation = state.orientation * yaw * pitch;
}
private void UpdateButtonStates() {
state.buttonsState = 0;
if (IsClickButtonPressed) {
state.buttonsState |= GvrControllerButton.TouchPadButton;
}
if (IsAppButtonPressed) {
state.buttonsState |= GvrControllerButton.App;
}
if (IsHomeButtonPressed) {
state.buttonsState |= GvrControllerButton.System;
}
if (IsTouching) {
state.buttonsState |= GvrControllerButton.TouchPadTouch;
}
state.SetButtonsUpDownFromPrevious(lastButtonsState);
lastButtonsState = state.buttonsState;
if (0 != (state.buttonsUp & GvrControllerButton.TouchPadTouch)) {
ClearTouchPos();
}
if (0 != (state.buttonsUp & GvrControllerButton.System)) {
Recenter();
}
}
private void Recenter() {
Quaternion yawCorrection = Quaternion.AngleAxis(-state.orientation.eulerAngles.y, Vector3.up);
state.orientation = state.orientation * yawCorrection;
state.recentered = true;
}
private void ClearTouchPos() {
state.touchPos = new Vector2(0.5f, 0.5f);
}
private void ClearState() {
state.connectionState = GvrConnectionState.Disconnected;
state.buttonsState = 0;
state.buttonsDown = 0;
state.buttonsUp = 0;
ClearTouchPos();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d8b9c789363a44b1e87727b1c4d085f6
timeCreated: 1496352344
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: