context: // Copyright 2014 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 UnityEngine;
  using System;
  using System.Collections.Generic;
  
  using Gvr.Internal;
  
  /// The GvrViewer object communicates with the head-mounted display.
  /// Is is repsonsible for:
  /// -  Querying the device for viewing parameters
  /// -  Retrieving the latest head tracking data
  /// -  Providing the rendered scene to the device for distortion correction (optional)
  ///
  /// There should only be one of these in a scene.  An instance will be generated automatically
  /// by this script at runtime, or you can add one via the Editor if you wish to customize
  /// its starting properties.
  [AddComponentMenu("GoogleVR/GvrViewer")]
  public class GvrViewer : MonoBehaviour {
    public const string GVR_SDK_VERSION = "0.9.1";
  
    /// The singleton instance of the GvrViewer class.
    public static GvrViewer Instance {
      get {
  #if UNITY_EDITOR
        if (instance == null && !Application.isPlaying) {
          instance = UnityEngine.Object.FindObjectOfType<GvrViewer>();
        }
  #endif
        if (instance == null) {
          Debug.LogError("No GvrViewer instance found.  Ensure one exists in the scene, or call "
              + "GvrViewer.Create() at startup to generate one.\n"
              + "If one does exist but hasn't called Awake() yet, "
              + "then this error is due to order-of-initialization.\n"
              + "In that case, consider moving "
              + "your first reference to GvrViewer.Instance to a later point in time.\n"
              + "If exiting the scene, this indicates that the GvrViewer object has already "
              + "been destroyed.");
        }
        return instance;
      }
    }
    private static GvrViewer instance = null;
  
    /// Generate a GvrViewer instance.  Takes no action if one already exists.
    public static void Create() {
      if (instance == null && UnityEngine.Object.FindObjectOfType<GvrViewer>() == null) {
        Debug.Log("Creating GvrViewer object");
        var go = new GameObject("GvrViewer", typeof(GvrViewer));
        go.transform.localPosition = Vector3.zero;
        // sdk will be set by Awake().
      }
    }
  
    /// The StereoController instance attached to the main camera, or null if there is none.
    /// @note Cached for performance.
    public static StereoController Controller {
      get {
        Camera camera = Camera.main;
        // Cache for performance, if possible.
        if (camera != currentMainCamera || currentController == null) {
          currentMainCamera = camera;
          currentController = camera.GetComponent<StereoController>();
        }
        return currentController;
      }
    }
    private static Camera currentMainCamera;
    private static StereoController currentController;
  
    /// Determine whether the scene renders in stereo or mono.
    /// _True_ means to render in stereo, and _false_ means to render in mono.
    public bool VRModeEnabled {
      get {
        return vrModeEnabled;
      }
      set {
        if (value != vrModeEnabled && device != null) {
          device.SetVRModeEnabled(value);
        }
        vrModeEnabled = value;
      }
    }
    [SerializeField]
    private bool vrModeEnabled = true;
  
    /// Methods for performing lens distortion correction.
    public enum DistortionCorrectionMethod {
        None,    /// No distortion correction
        Native,  /// Use the native C++ plugin
        Unity,   /// Perform distortion correction in Unity (recommended)
    }
  
    /// Determines the distortion correction method used by the SDK to render the
    /// #StereoScreen texture on the phone.  If _Native_ is selected but not supported
    /// by the device, the _Unity_ method will be used instead.
    public DistortionCorrectionMethod DistortionCorrection {
      get {
        return distortionCorrection;
      }
      set {
        if (device != null && device.RequiresNativeDistortionCorrection()) {
          value = DistortionCorrectionMethod.Native;
        }
        if (value != distortionCorrection && device != null) {
          device.SetDistortionCorrectionEnabled(value == DistortionCorrectionMethod.Native
              && NativeDistortionCorrectionSupported);
          device.UpdateScreenData();
        }
        distortionCorrection = value;
      }
    }
    [SerializeField]
    private DistortionCorrectionMethod distortionCorrection = DistortionCorrectionMethod.Unity;
  
    /// The native SDK will apply a neck offset to the head tracking, resulting in
    /// a more realistic model of a person's head position.  This control determines
    /// the scale factor of the offset.  To turn off the neck model, set it to 0, and
    /// to turn it all on, set to 1.  Intermediate values can be used to animate from
    /// on to off or vice versa.
    public float NeckModelScale {
      get {
        return neckModelScale;
      }
      set {
        value = Mathf.Clamp01(value);
        if (!Mathf.Approximately(value, neckModelScale) && device != null) {
          device.SetNeckModelScale(value);
        }
        neckModelScale = value;
      }
    }
    [SerializeField]
    private float neckModelScale = 0.0f;
  
  #if UNITY_EDITOR
    /// Restores level head tilt in when playing in the Unity Editor after you
    /// release the Ctrl key.
    public bool autoUntiltHead = true;
  
    /// @cond
    /// Use unity remote as the input source.
    public bool UseUnityRemoteInput = false;
    /// @endcond
  
    /// The screen size to emulate when testing in the Unity Editor.
    public GvrProfile.ScreenSizes ScreenSize {
      get {
        return screenSize;
      }
      set {
        if (value != screenSize) {
          screenSize = value;
          if (device != null) {
            device.UpdateScreenData();
          }
        }
      }
    }
    [SerializeField]
    private GvrProfile.ScreenSizes screenSize = GvrProfile.ScreenSizes.Nexus5;
  
    /// The viewer type to emulate when testing in the Unity Editor.
    public GvrProfile.ViewerTypes ViewerType {
      get {
        return viewerType;
      }
      set {
        if (value != viewerType) {
          viewerType = value;
          if (device != null) {
            device.UpdateScreenData();
          }
        }
      }
    }
    [SerializeField]
    private GvrProfile.ViewerTypes viewerType = GvrProfile.ViewerTypes.CardboardMay2015;
  #endif
  
    // The VR device that will be providing input data.
    private static BaseVRDevice device;
  
    /// Whether native distortion correction functionality is supported by the VR device.
    public bool NativeDistortionCorrectionSupported { get; private set; }
  
    /// Whether the VR device supports showing a native UI layer, for example for settings.
    public bool NativeUILayerSupported { get; private set; }
  
    /// Scales the resolution of the #StereoScreen.  Set to less than 1.0 to increase
    /// rendering speed while decreasing sharpness, or greater than 1.0 to do the
    /// opposite.
    public float StereoScreenScale {
      get {
        return stereoScreenScale;
      }
      set {
        value = Mathf.Clamp(value, 0.1f, 10.0f);  // Sanity.
        if (stereoScreenScale != value) {
          stereoScreenScale = value;
          StereoScreen = null;
        }
      }
    }
    [SerializeField]
    private float stereoScreenScale = 1;
  
    /// The texture that Unity renders the scene to.  After the frame has been rendered,
    /// this texture is drawn to the screen with a lens distortion correction effect.
    /// The texture size is based on the size of the screen, the lens distortion
    /// parameters, and the #StereoScreenScale factor.
    public RenderTexture StereoScreen {
      get {
        // Don't need it except for distortion correction.
        if (distortionCorrection == DistortionCorrectionMethod.None || !vrModeEnabled) {
          return null;
        }
        if (stereoScreen == null) {
          // Create on demand.
          StereoScreen = device.CreateStereoScreen();  // Note: uses set{}
        }
        return stereoScreen;
      }
      set {
        if (value == stereoScreen) {
          return;
        }
        if (stereoScreen != null) {
          stereoScreen.Release();
        }
        stereoScreen = value;
        if (OnStereoScreenChanged != null) {
          OnStereoScreenChanged(stereoScreen);
        }
      }
    }
    private static RenderTexture stereoScreen = null;
  
    /// A callback for notifications that the StereoScreen property has changed.
    public delegate void StereoScreenChangeDelegate(RenderTexture newStereoScreen);
  
    /// Emitted when the StereoScreen property has changed.
    public event StereoScreenChangeDelegate OnStereoScreenChanged;
  
    /// Describes the current device, including phone screen.
    public GvrProfile Profile {
      get {
        return device.Profile;
      }
    }
  
    /// Distinguish the stereo eyes.
    public enum Eye {
      Left,   /// The left eye
      Right,  /// The right eye
  
gt:     Center  /// The "center" eye (unused)