Mercurial > hg > Game > Games
diff Orchestland/Assets/OVR/Scripts/OVRManager.cs @ 1:f7675884f2a1
Add Orchestland project
author | Daiki OYAKAWA <e135764@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2015 23:09:20 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Orchestland/Assets/OVR/Scripts/OVRManager.cs Fri Jul 17 23:09:20 2015 +0900 @@ -0,0 +1,711 @@ +/************************************************************************************ + +Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +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 System; +using System.Collections; +using System.Runtime.InteropServices; +using System.Linq; +using System.Text.RegularExpressions; +using UnityEngine; +using Ovr; + +/// <summary> +/// Configuration data for Oculus virtual reality. +/// </summary> +public class OVRManager : MonoBehaviour +{ + /// <summary> + /// Contains information about the user's preferences and body dimensions. + /// </summary> + public struct Profile + { + public float ipd; + public float eyeHeight; + public float eyeDepth; + public float neckHeight; + } + + /// <summary> + /// Gets the singleton instance. + /// </summary> + public static OVRManager instance { get; private set; } + + /// <summary> + /// Gets a reference to the low-level C API Hmd Wrapper + /// </summary> + private static Hmd _capiHmd; + public static Hmd capiHmd + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + if (_capiHmd == null) + { + IntPtr hmdPtr = IntPtr.Zero; + OVR_GetHMD(ref hmdPtr); + _capiHmd = (hmdPtr != IntPtr.Zero) ? new Hmd(hmdPtr) : null; + } +#else + _capiHmd = null; +#endif + return _capiHmd; + } + } + + /// <summary> + /// Gets a reference to the active OVRDisplay + /// </summary> + public static OVRDisplay display { get; private set; } + + /// <summary> + /// Gets a reference to the active OVRTracker + /// </summary> + public static OVRTracker tracker { get; private set; } + + /// <summary> + /// Gets the current profile, which contains information about the user's settings and body dimensions. + /// </summary> + private static bool _profileIsCached = false; + private static Profile _profile; + public static Profile profile + { + get { + if (!_profileIsCached) + { +#if !UNITY_ANDROID || UNITY_EDITOR + float ipd = capiHmd.GetFloat(Hmd.OVR_KEY_IPD, Hmd.OVR_DEFAULT_IPD); + float eyeHeight = capiHmd.GetFloat(Hmd.OVR_KEY_EYE_HEIGHT, Hmd.OVR_DEFAULT_EYE_HEIGHT); + float[] defaultOffset = new float[] { Hmd.OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, Hmd.OVR_DEFAULT_NECK_TO_EYE_VERTICAL }; + float[] neckToEyeOffset = capiHmd.GetFloatArray(Hmd.OVR_KEY_NECK_TO_EYE_DISTANCE, defaultOffset); + float neckHeight = eyeHeight - neckToEyeOffset[1]; + + _profile = new Profile + { + ipd = ipd, + eyeHeight = eyeHeight, + eyeDepth = neckToEyeOffset[0], + neckHeight = neckHeight, + }; +#else + float ipd = 0.0f; + OVR_GetInterpupillaryDistance(ref ipd); + + float eyeHeight = 0.0f; + OVR_GetPlayerEyeHeight(ref eyeHeight); + + _profile = new Profile + { + ipd = ipd, + eyeHeight = eyeHeight, + eyeDepth = 0f, //TODO + neckHeight = 0.0f, // TODO + }; +#endif + _profileIsCached = true; + } + + return _profile; + } + } + + /// <summary> + /// Occurs when an HMD attached. + /// </summary> + public static event Action HMDAcquired; + + /// <summary> + /// Occurs when an HMD detached. + /// </summary> + public static event Action HMDLost; + + /// <summary> + /// Occurs when the tracker gained tracking. + /// </summary> + public static event Action TrackingAcquired; + + /// <summary> + /// Occurs when the tracker lost tracking. + /// </summary> + public static event Action TrackingLost; + + /// <summary> + /// Occurs when HSW dismissed. + /// </summary> + public static event Action HSWDismissed; + + /// <summary> + /// If true, then the Oculus health and safety warning (HSW) is currently visible. + /// </summary> + public static bool isHSWDisplayed + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return capiHmd.GetHSWDisplayState().Displayed; +#else + return false; +#endif + } + } + + /// <summary> + /// If the HSW has been visible for the necessary amount of time, this will make it disappear. + /// </summary> + public static void DismissHSWDisplay() + { +#if !UNITY_ANDROID || UNITY_EDITOR + capiHmd.DismissHSWDisplay(); +#endif + } + + /// <summary> + /// Gets the current battery level. + /// </summary> + /// <returns><c>battery level in the range [0.0,1.0]</c> + /// <param name="batteryLevel">Battery level.</param> + public static float batteryLevel + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return 1.0f; +#else + return OVR_GetBatteryLevel(); +#endif + } + } + + /// <summary> + /// Gets the current battery temperature. + /// </summary> + /// <returns><c>battery temperature in Celsius</c> + /// <param name="batteryTemperature">Battery temperature.</param> + public static float batteryTemperature + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return 0.0f; +#else + return OVR_GetBatteryTemperature(); +#endif + } + } + + /// <summary> + /// Gets the current battery status. + /// </summary> + /// <returns><c>battery status</c> + /// <param name="batteryStatus">Battery status.</param> + public static int batteryStatus + { + get { +#if !UNITY_ANDROID || UNITY_EDITOR + return 0; +#else + return OVR_GetBatteryStatus(); +#endif + } + } + + /// <summary> + /// Controls the size of the eye textures. + /// Values must be above 0. + /// Values below 1 permit sub-sampling for improved performance. + /// Values above 1 permit super-sampling for improved sharpness. + /// </summary> + public float nativeTextureScale = 1.0f; + + /// <summary> + /// Controls the size of the rendering viewport. + /// Values must be between 0 and 1. + /// Values below 1 permit dynamic sub-sampling for improved performance. + /// </summary> + public float virtualTextureScale = 1.0f; + + /// <summary> + /// If true, head tracking will affect the orientation of each OVRCameraRig's cameras. + /// </summary> + public bool usePositionTracking = true; + + /// <summary> + /// The format of each eye texture. + /// </summary> + public RenderTextureFormat eyeTextureFormat = RenderTextureFormat.Default; + + /// <summary> + /// The depth of each eye texture in bits. + /// </summary> + public int eyeTextureDepth = 24; + + /// <summary> + /// If true, TimeWarp will be used to correct the output of each OVRCameraRig for rotational latency. + /// </summary> + public bool timeWarp = true; + + /// <summary> + /// If this is true and TimeWarp is true, each OVRCameraRig will stop tracking and only TimeWarp will respond to head motion. + /// </summary> + public bool freezeTimeWarp = false; + + /// <summary> + /// If true, each scene load will cause the head pose to reset. + /// </summary> + public bool resetTrackerOnLoad = true; + + /// <summary> + /// If true, the eyes see the same image, which is rendered only by the left camera. + /// </summary> + public bool monoscopic = false; + + /// <summary> + /// True if the current platform supports virtual reality. + /// </summary> + public bool isSupportedPlatform { get; private set; } + + private static bool usingPositionTracking = false; + private static bool wasHmdPresent = false; + private static bool wasPositionTracked = false; + private static WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame(); + +#if UNITY_ANDROID && !UNITY_EDITOR + // Get this from Unity on startup so we can call Activity java functions + private static bool androidJavaInit = false; + private static AndroidJavaObject activity; + private static AndroidJavaClass javaVrActivityClass; + internal static int timeWarpViewNumber = 0; + public static event Action OnCustomPostRender; +#else + private static bool ovrIsInitialized; + private static bool isQuitting; +#endif + + public static bool isPaused + { + get { return _isPaused; } + set + { +#if UNITY_ANDROID && !UNITY_EDITOR + RenderEventType eventType = (value) ? RenderEventType.Pause : RenderEventType.Resume; + OVRPluginEvent.Issue(eventType); +#endif + _isPaused = value; + } + } + private static bool _isPaused; + +#region Unity Messages + + private void Awake() + { + // Only allow one instance at runtime. + if (instance != null) + { + enabled = false; + DestroyImmediate(this); + return; + } + + instance = this; + +#if !UNITY_ANDROID || UNITY_EDITOR + if (!ovrIsInitialized) + { + OVR_Initialize(); + OVRPluginEvent.Issue(RenderEventType.Initialize); + + ovrIsInitialized = true; + } + + var netVersion = new System.Version(Ovr.Hmd.OVR_VERSION_STRING); + var ovrVersion = new System.Version(Ovr.Hmd.GetVersionString()); + if (netVersion > ovrVersion) + Debug.LogWarning("Using an older version of LibOVR."); +#endif + + // Detect whether this platform is a supported platform + RuntimePlatform currPlatform = Application.platform; + isSupportedPlatform |= currPlatform == RuntimePlatform.Android; + isSupportedPlatform |= currPlatform == RuntimePlatform.LinuxPlayer; + isSupportedPlatform |= currPlatform == RuntimePlatform.OSXEditor; + isSupportedPlatform |= currPlatform == RuntimePlatform.OSXPlayer; + isSupportedPlatform |= currPlatform == RuntimePlatform.WindowsEditor; + isSupportedPlatform |= currPlatform == RuntimePlatform.WindowsPlayer; + if (!isSupportedPlatform) + { + Debug.LogWarning("This platform is unsupported"); + return; + } + +#if UNITY_ANDROID && !UNITY_EDITOR + Application.targetFrameRate = 60; + // don't allow the app to run in the background + Application.runInBackground = false; + // Disable screen dimming + Screen.sleepTimeout = SleepTimeout.NeverSleep; + + if (!androidJavaInit) + { + AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); + javaVrActivityClass = new AndroidJavaClass("com.oculusvr.vrlib.VrActivity"); + // Prepare for the RenderThreadInit() + SetInitVariables(activity.GetRawObject(), javaVrActivityClass.GetRawClass()); + + androidJavaInit = true; + } + + // We want to set up our touchpad messaging system + OVRTouchpad.Create(); + // This will trigger the init on the render thread + InitRenderThread(); +#else + SetEditorPlay(Application.isEditor); +#endif + + if (display == null) + display = new OVRDisplay(); + if (tracker == null) + tracker = new OVRTracker(); + + if (resetTrackerOnLoad) + display.RecenterPose(); + + // Except for D3D9, SDK rendering forces vsync unless you pass ovrHmdCap_NoVSync to Hmd.SetEnabledCaps(). + if (timeWarp) + { + bool useUnityVSync = SystemInfo.graphicsDeviceVersion.Contains("Direct3D 9"); + QualitySettings.vSyncCount = useUnityVSync ? 1 : 0; + } + +#if (UNITY_STANDALONE_WIN && (UNITY_4_6 || UNITY_4_5)) + bool unity_4_6 = false; + bool unity_4_5_2 = false; + bool unity_4_5_3 = false; + bool unity_4_5_4 = false; + bool unity_4_5_5 = false; + +#if (UNITY_4_6) + unity_4_6 = true; +#elif (UNITY_4_5_2) + unity_4_5_2 = true; +#elif (UNITY_4_5_3) + unity_4_5_3 = true; +#elif (UNITY_4_5_4) + unity_4_5_4 = true; +#elif (UNITY_4_5_5) + unity_4_5_5 = true; +#endif + + // Detect correct Unity releases which contain the fix for D3D11 exclusive mode. + string version = Application.unityVersion; + int releaseNumber; + bool releaseNumberFound = Int32.TryParse(Regex.Match(version, @"\d+$").Value, out releaseNumber); + + // Exclusive mode was broken for D3D9 in Unity 4.5.2p2 - 4.5.4 and 4.6 builds prior to beta 21 + bool unsupportedExclusiveModeD3D9 = (unity_4_6 && version.Last(char.IsLetter) == 'b' && releaseNumberFound && releaseNumber < 21) + || (unity_4_5_2 && version.Last(char.IsLetter) == 'p' && releaseNumberFound && releaseNumber >= 2) + || (unity_4_5_3) + || (unity_4_5_4); + + // Exclusive mode was broken for D3D11 in Unity 4.5.2p2 - 4.5.5p2 and 4.6 builds prior to f1 + bool unsupportedExclusiveModeD3D11 = (unity_4_6 && version.Last(char.IsLetter) == 'b') + || (unity_4_5_2 && version.Last(char.IsLetter) == 'p' && releaseNumberFound && releaseNumber >= 2) + || (unity_4_5_3) + || (unity_4_5_4) + || (unity_4_5_5 && version.Last(char.IsLetter) == 'f') + || (unity_4_5_5 && version.Last(char.IsLetter) == 'p' && releaseNumberFound && releaseNumber < 3); + + if (unsupportedExclusiveModeD3D9 && !display.isDirectMode && SystemInfo.graphicsDeviceVersion.Contains("Direct3D 9")) + { + MessageBox(0, "Direct3D 9 extended mode is not supported in this configuration. " + + "Please use direct display mode, a different graphics API, or rebuild the application with a newer Unity version." + , "VR Configuration Warning", 0); + } + + if (unsupportedExclusiveModeD3D11 && !display.isDirectMode && SystemInfo.graphicsDeviceVersion.Contains("Direct3D 11")) + { + MessageBox(0, "Direct3D 11 extended mode is not supported in this configuration. " + + "Please use direct display mode, a different graphics API, or rebuild the application with a newer Unity version." + , "VR Configuration Warning", 0); + } +#endif + } + +#if !UNITY_ANDROID || UNITY_EDITOR + private void OnApplicationQuit() + { + isQuitting = true; + } + + private void OnDisable() + { + if (!isQuitting) + return; + + if (ovrIsInitialized) + { + OVR_Destroy(); + OVRPluginEvent.Issue(RenderEventType.Destroy); + _capiHmd = null; + + ovrIsInitialized = false; + } + } +#endif + + private void Start() + { +#if !UNITY_ANDROID || UNITY_EDITOR + Camera cam = GetComponent<Camera>(); + if (cam == null) + { + // Ensure there is a non-RT camera in the scene to force rendering of the left and right eyes. + cam = gameObject.AddComponent<Camera>(); + cam.cullingMask = 0; + cam.clearFlags = CameraClearFlags.SolidColor; + cam.backgroundColor = new Color(0.0f, 0.0f, 0.0f); + cam.renderingPath = RenderingPath.Forward; + cam.orthographic = true; + cam.useOcclusionCulling = false; + } +#endif + + bool isD3d = SystemInfo.graphicsDeviceVersion.Contains("Direct3D") || + Application.platform == RuntimePlatform.WindowsEditor && + SystemInfo.graphicsDeviceVersion.Contains("emulated"); + display.flipInput = isD3d; + + StartCoroutine(CallbackCoroutine()); + } + + private void Update() + { + if (usePositionTracking != usingPositionTracking) + { + tracker.isEnabled = usePositionTracking; + usingPositionTracking = usePositionTracking; + } + + // Dispatch any events. + if (HMDLost != null && wasHmdPresent && !display.isPresent) + HMDLost(); + + if (HMDAcquired != null && !wasHmdPresent && display.isPresent) + HMDAcquired(); + + wasHmdPresent = display.isPresent; + + if (TrackingLost != null && wasPositionTracked && !tracker.isPositionTracked) + TrackingLost(); + + if (TrackingAcquired != null && !wasPositionTracked && tracker.isPositionTracked) + TrackingAcquired(); + + wasPositionTracked = tracker.isPositionTracked; + + if (isHSWDisplayed && Input.anyKeyDown) + { + DismissHSWDisplay(); + + if (HSWDismissed != null) + HSWDismissed(); + } + + display.timeWarp = timeWarp; + +#if (!UNITY_ANDROID || UNITY_EDITOR) + display.Update(); +#endif + } + +#if (UNITY_EDITOR_OSX) + private void OnPreCull() // TODO: Fix Mac Unity Editor memory corruption issue requiring OnPreCull workaround. +#else + private void LateUpdate() +#endif + { +#if (!UNITY_ANDROID || UNITY_EDITOR) + display.BeginFrame(); +#endif + } + + private IEnumerator CallbackCoroutine() + { + while (true) + { + yield return waitForEndOfFrame; + +#if UNITY_ANDROID && !UNITY_EDITOR + OVRManager.DoTimeWarp(timeWarpViewNumber); +#else + display.EndFrame(); +#endif + } + } + +#if UNITY_ANDROID && !UNITY_EDITOR + private void OnPause() + { + isPaused = true; + } + + private void OnApplicationPause(bool pause) + { + Debug.Log("OnApplicationPause() " + pause); + if (pause) + { + OnPause(); + } + else + { + StartCoroutine(OnResume()); + } + } + + void OnDisable() + { + StopAllCoroutines(); + } + + private IEnumerator OnResume() + { + yield return null; // delay 1 frame to allow Unity enough time to create the windowSurface + + isPaused = false; + } + + /// <summary> + /// Leaves the application/game and returns to the launcher/dashboard + /// </summary> + public void ReturnToLauncher() + { + // show the platform UI quit prompt + OVRManager.PlatformUIConfirmQuit(); + } + + private void OnPostRender() + { + // Allow custom code to render before we kick off the plugin + if (OnCustomPostRender != null) + { + OnCustomPostRender(); + } + + EndEye(OVREye.Left, display.GetEyeTextureId(OVREye.Left)); + EndEye(OVREye.Right, display.GetEyeTextureId(OVREye.Right)); + } +#endif +#endregion + + public static void SetEditorPlay(bool isEditor) + { +#if !UNITY_ANDROID || UNITY_EDITOR + OVR_SetEditorPlay(isEditor); +#endif + } + + public static void SetDistortionCaps(uint distortionCaps) + { +#if !UNITY_ANDROID || UNITY_EDITOR + OVR_SetDistortionCaps(distortionCaps); +#endif + } + + public static void SetInitVariables(IntPtr activity, IntPtr vrActivityClass) + { +#if UNITY_ANDROID && !UNITY_EDITOR + OVR_SetInitVariables(activity, vrActivityClass); +#endif + } + + public static void PlatformUIConfirmQuit() + { +#if UNITY_ANDROID && !UNITY_EDITOR + OVRPluginEvent.Issue(RenderEventType.PlatformUIConfirmQuit); +#endif + } + + public static void PlatformUIGlobalMenu() + { +#if UNITY_ANDROID && !UNITY_EDITOR + OVRPluginEvent.Issue(RenderEventType.PlatformUI); +#endif + } + + public static void DoTimeWarp(int timeWarpViewNumber) + { +#if UNITY_ANDROID && !UNITY_EDITOR + OVRPluginEvent.IssueWithData(RenderEventType.TimeWarp, timeWarpViewNumber); +#endif + } + + public static void EndEye(OVREye eye, int eyeTextureId) + { +#if UNITY_ANDROID && !UNITY_EDITOR + RenderEventType eventType = (eye == OVREye.Left) ? + RenderEventType.LeftEyeEndFrame : + RenderEventType.RightEyeEndFrame; + + OVRPluginEvent.IssueWithData(eventType, eyeTextureId); +#endif + } + + public static void InitRenderThread() + { +#if UNITY_ANDROID && !UNITY_EDITOR + OVRPluginEvent.Issue(RenderEventType.InitRenderThread); +#endif + } + + private const string LibOVR = "OculusPlugin"; + +#if !UNITY_ANDROID || UNITY_EDITOR + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_GetHMD(ref IntPtr hmdPtr); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_SetEditorPlay(bool isEditorPlay); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_SetDistortionCaps(uint distortionCaps); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_Initialize(); + [DllImport(LibOVR, CallingConvention = CallingConvention.Cdecl)] + private static extern void OVR_Destroy(); + +#if UNITY_STANDALONE_WIN + [DllImport("user32", EntryPoint = "MessageBoxA", CharSet = CharSet.Ansi)] + public static extern bool MessageBox(int hWnd, + [MarshalAs(UnmanagedType.LPStr)]string text, + [MarshalAs(UnmanagedType.LPStr)]string caption, uint type); +#endif + +#else + [DllImport(LibOVR)] + private static extern void OVR_SetInitVariables(IntPtr activity, IntPtr vrActivityClass); + [DllImport(LibOVR)] + private static extern float OVR_GetBatteryLevel(); + [DllImport(LibOVR)] + private static extern int OVR_GetBatteryStatus(); + [DllImport(LibOVR)] + private static extern float OVR_GetBatteryTemperature(); + + [DllImport(LibOVR)] + private static extern bool OVR_GetPlayerEyeHeight(ref float eyeHeight); + [DllImport(LibOVR)] + private static extern bool OVR_GetInterpupillaryDistance(ref float interpupillaryDistance); +#endif +}