Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*********************************************************************************************
- * MaxGameWindowToRift.cs *
- * Version 1.21 *
- * By Justin Scaniglia / WiredEarp 19/04/2015 *
- * Moves an undocked Unity GameView window to the Rift on Play, and makes it full screen *
- * Will restore GameView window to original position on Stop *
- * *
- * Features: *
- * - Toggle GameView position button *
- * - Restore 'normal' layout button *
- * - Save 'normal' layout button *
- * - Automatically maximize to Rift on Play, and restore GameView position on Stop *
- * - GUI adjusts to preferred size (wider or taller) *
- * - Toggle button enables or disables depending on whether Rift is on *
- * New features in V1.21: *
- * - Save 'normal' layout button (and associated resizing code) *
- * Bug fixes in V1.21: *
- * - Fixed bug on dragging the controls window around (reported by p00ky, thanks!) *
- * New features in V1.20: *
- * - Unity 5 compatibility *
- * - State aware toggle button *
- * Bug fixes in V1.21: *
- * - Hopefully fixed failed saving where it saves a truncated layout name *
- * Bug fixes in V1.20: *
- * - Hopefully fixed failed saving where it saves a truncated layout name *
- * New features in V1.15: *
- * - Messagebox notification when 'normal' layout not set *
- * - Improved Rift detection *
- * Bug fixes in V1.15: *
- * - Fixed some issues with being able to toggle state to active when Rift not connected *
- * USE: *
- * In Unity, select Window/Maximise GameWindow To Rift *
- * Dock the Max To Rift window, or keep it floating - but it must be docked or visible, *
- * not just an unselected tab (if you want it to work as an unselected tab, let me know) *
- * Click the 'Maximize On Play' checkbox to maximize/restore. Press 'Toggle' button to *
- * switch the view between the Rift and normal. Press 'Restore Normal Layout' to restore a *
- * layout called 'normal'. Press 'Save Normal Layout' to save a layout called 'normal'. *
- * (handy for any issues) * *
- * *
- * For Feedback/bug reports, message me (WiredEarp) on reddit.com or mtbs3d.com *
- **********************************************************************************************/
- using UnityEditor;
- using UnityEngine;
- using System;
- using System.Runtime.InteropServices;
- using System.IO;
- enum GameViewState { NORMAL, MAXIMIZED };
- /********************************************************************************************
- * MaxGameWindowToRift *
- * Main editor window class *
- * Handles display of the editor window, serialization of important variables, and *
- * detecting and moving GameView to Oculus screen *
- *********************************************************************************************/
- public class MaxGameWindowToRift : EditorWindow
- { //MAIN CLASS
- #region PInvoke Declarations
- //these declarations and structs etc are from www.pinvoke.net
- [DllImport("user32.dll")]
- internal static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
- [DllImport("user32.dll")]
- internal static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
- public static int ENUM_CURRENT_SETTINGS = -1;
- [StructLayout(LayoutKind.Sequential)]
- //public class POINTL
- public struct POINTL
- {
- public Int32 x;
- public Int32 y;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct DEVMODE
- {
- private const int CCHDEVICENAME = 0x20;
- private const int CCHFORMNAME = 0x20;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
- public string dmDeviceName;
- public short dmSpecVersion;
- public short dmDriverVersion;
- public short dmSize;
- public short dmDriverExtra;
- public int dmFields;
- public int dmPositionX;
- public int dmPositionY;
- public Int32 dmDisplayOrientation;
- public int dmDisplayFixedOutput;
- public short dmColor;
- public short dmDuplex;
- public short dmYResolution;
- public short dmTTOption;
- public short dmCollate;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
- public string dmFormName;
- public short dmLogPixels;
- public int dmBitsPerPel;
- public int dmPelsWidth;
- public int dmPelsHeight;
- public int dmDisplayFlags;
- public int dmDisplayFrequency;
- public int dmICMMethod;
- public int dmICMIntent;
- public int dmMediaType;
- public int dmDitherType;
- public int dmReserved1;
- public int dmReserved2;
- public int dmPanningWidth;
- public int dmPanningHeight;
- }
- [Flags()]
- public enum DisplayDeviceStateFlags : int
- {
- /// <summary>The device is part of the desktop.</summary>
- AttachedToDesktop = 0x1,
- MultiDriver = 0x2,
- /// <summary>The device is part of the desktop.</summary>
- PrimaryDevice = 0x4,
- /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
- MirroringDriver = 0x8,
- /// <summary>The device is VGA compatible.</summary>
- VGACompatible = 0x16,
- /// <summary>The device is removable; it cannot be the primary display.</summary>
- Removable = 0x20,
- /// <summary>The device has more display modes than its output devices support.</summary>
- ModesPruned = 0x8000000,
- Remote = 0x4000000,
- Disconnect = 0x2000000
- }
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct DISPLAY_DEVICE
- {
- [MarshalAs(UnmanagedType.U4)]
- public int cb;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
- public string DeviceName;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string DeviceString;
- [MarshalAs(UnmanagedType.U4)]
- public DisplayDeviceStateFlags StateFlags;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string DeviceID;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string DeviceKey;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct WINDOWPOS
- {
- public IntPtr hwnd;
- public IntPtr hwndInsertAfter;
- public int x;
- public int y;
- public int cx;
- public int cy;
- public uint flags;
- }
- #endregion
- #region Global Declarations
- // GLOBAL DECLARATIONS
- //handle to the Editor window
- private static MaxGameWindowToRift _window;
- private static MaxGameWindowToRift _this;
- [NonSerialized]
- private static bool _MaximizeOnPlay = true;
- [NonSerialized]
- public static int _DesiredState;
- [NonSerialized]
- public static int _CurrentState;
- //variables used to store the old window position
- private WINDOWPOS _oldGameWinPos;
- private Vector2 _oldGameWinMinSize; private Vector2 _oldGameWinMaxSize;
- //tabheight and osborderwidth taken from sbNewsom's script
- private const int tabHeight = 22;
- const string LAYOUT_NAME = "rift";
- const string MonitorName = "OVR";
- //const string MonitorName = "DEL"; //my Alienware 1080P monitor, used for testing
- #if UNITY_STANDALONE_WIN
- //Windows settings
- private const int osBorderWidth = 5;
- #endif
- #endregion
- [UnityEditor.MenuItem("Window/Maximize GameWindow to Rift")]
- private static void ShowWindow()
- {
- _window = (MaxGameWindowToRift)EditorWindow.GetWindow(typeof(MaxGameWindowToRift));
- //set the _window title
- _window.title = "Max to Rift";
- _window.minSize = new Vector2(150, 50);
- _window.maxSize = new Vector2(300, 300);
- }
- public static void stateChange(int state)
- {
- if (_MaximizeOnPlay)
- {
- _DesiredState = state;
- SaveState();
- }
- }
- static void SaveState()
- {
- PlayerPrefs.SetInt("_DesiredState", _DesiredState);
- PlayerPrefs.SetInt("_CurrentState", _CurrentState);
- int tint = _MaximizeOnPlay ? tint = 1 : tint = 0;
- PlayerPrefs.SetInt("_MaxOnPlay", tint);
- }
- void RestoreState()
- {
- _DesiredState = PlayerPrefs.GetInt("_DesiredState");
- _CurrentState = PlayerPrefs.GetInt("_CurrentState");
- int tint = PlayerPrefs.GetInt("_MaxOnPlay");
- _MaximizeOnPlay = (tint == 1) ? true : false;
- }
- string strToggle = "Maximize GameView";
- void OnGUI()
- {
- if (_window == null)
- ShowWindow();
- EditorGUILayout.Space();
- GUILayout.BeginHorizontal();
- {
- if (IsMaximized())
- {
- strToggle = "Restore GameView";
- }
- else strToggle = "Maximize GameView";
- }
- if (DetectActiveRift())
- GUI.enabled = true;
- else
- GUI.enabled = false;
- if (GUILayout.Button(new GUIContent(strToggle, "Press to toggle GameView to/from full screen on Rift"), GUILayout.Width(145), GUILayout.Height(20)))
- {
- GUI.enabled = true;
- //use this opportunity to reset the _actual_ state of the Game window, just in case its gotten buggered up
- if (IsMaximized())
- {
- _CurrentState = (int)GameViewState.MAXIMIZED;
- strToggle = "Restore GameView";
- }
- else
- {
- _CurrentState = (int)GameViewState.NORMAL;
- strToggle = "Maximize GameView";
- }
- if (DetectActiveRift())
- {
- _DesiredState = (_DesiredState == (int)GameViewState.MAXIMIZED ? _DesiredState = (int)GameViewState.NORMAL : _DesiredState = (int)GameViewState.MAXIMIZED);
- SaveState();
- }
- }
- GUI.enabled = true;
- if (position.width < 250)
- {
- GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal();
- }
- if (GUILayout.Button(new GUIContent("Save normal Layout", "Press to save a window layout called 'normal'"), GUILayout.Width(145), GUILayout.Height(20)))
- {
- SaveWindowLayout("normal");
- }
- GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal();
- EditorGUIUtility.labelWidth = 140;
- _MaximizeOnPlay = EditorGUILayout.ToggleLeft("Maximize On Play", _MaximizeOnPlay,GUILayout.Width(145));
- if (position.width < 250)
- {
- GUILayout.EndHorizontal();
- }
- GUILayout.BeginHorizontal();
- if (GUILayout.Button(new GUIContent("Restore normal Layout", "Press to restore the window layout named 'normal'"), GUILayout.Width(145), GUILayout.Height(20)))
- {
- if (!RestoreWindowLayout("normal"))
- {
- EditorUtility.DisplayDialog("Layout Not Found", "Could not find a window layout called 'normal'. Please create one with this name before using this button.", "Ok");
- };
- }
- GUILayout.EndHorizontal();
- }
- void OnEnable()
- {
- RestoreState();
- }
- private void Update()
- {
- if (_CurrentState != _DesiredState)
- {
- if (_DesiredState == (int)GameViewState.MAXIMIZED)
- { // MAXIMIZED TO RIFT GAMEVIEW WINDOW
- if (IsMaximized()) return;
- _CurrentState = (int)GameViewState.MAXIMIZED;
- SaveState();
- //save the window pos
- SaveWindowLayout(LAYOUT_NAME);
- MaximizeToRift();
- }
- else //playState==GameViewState.NORMAL
- { // NORMAL GAMEVIEW WINDOW
- //move the window back to the old position
- _CurrentState = (int)GameViewState.NORMAL;
- SaveState();
- RestoreGameWindow();
- RestoreWindowLayout(LAYOUT_NAME);
- }
- return;
- }
- }
- private void SaveOldPos()
- {
- EditorWindow tGameWindow = GetGameView();
- if (!tGameWindow)
- {
- Debug.Log("Failed to get GameView");
- return;
- }
- _oldGameWinPos.x = (int)tGameWindow.position.x;
- _oldGameWinPos.y = (int)tGameWindow.position.y;
- _oldGameWinPos.cx = (int)tGameWindow.position.width;
- _oldGameWinPos.cy = (int)tGameWindow.position.height;
- }
- private void SaveWindowLayout(string layoutName)
- {
- //save the current _window layout
- EditorApplication.ExecuteMenuItem("Window/Layouts/Save Layout...");
- EditorApplication.ExecuteMenuItem("Window/Layouts/Save Layout...");
- foreach (char tch in layoutName)
- {
- EditorWindow.focusedWindow.SendEvent(Event.KeyboardEvent(tch.ToString()));
- }
- EditorWindow.focusedWindow.SendEvent(Event.KeyboardEvent("[enter]"));
- }
- private bool RestoreWindowLayout(string layoutName)
- {
- //restore the saved layout
- return EditorApplication.ExecuteMenuItem("Window/Layouts/" + layoutName);
- }
- private void MaximizeToRift()
- {
- SaveOldPos();
- //get a handle to the game view
- EditorWindow tGameWindow = GetGameView();
- if (!tGameWindow)
- {
- Debug.Log("Failed to get GameView");
- return;
- }
- //Get the Rift window position
- WINDOWPOS winPos = new WINDOWPOS();
- if (!GetRiftMonitorWindowPos(ref winPos))
- {
- Debug.Log("No Rift Detected");
- return;
- }
- // When minSize and maxSize are the same, no OS border is applied to the window (this and tabheights etc taken from sbNewsom's script),
- // although I use them a bit differently (seem to be more accurate on my 1080P monitor while testing)
- // First, save the existing window size (we will need it when restoring the window later)
- _oldGameWinMinSize = tGameWindow.minSize;
- _oldGameWinMaxSize = tGameWindow.maxSize;
- //modify the window min/max size before maximizing to width (to remove borders)
- winPos.y += tabHeight - osBorderWidth;
- winPos.cy += tabHeight;// -osBorderWidth;
- //Finally, call the MoveGameViewNatively routine, twice, since the first time will potentially just undock it if docked (another way would be to check .docked)
- MoveGameViewNatively(tGameWindow, winPos); //this one to simply move or undock it
- //now, set the gameWindow min and max size to remove the borders
- tGameWindow.minSize = new Vector2(winPos.cx, winPos.cy);
- tGameWindow.maxSize = tGameWindow.minSize;
- MoveGameViewNatively(tGameWindow, winPos);
- }
- private bool IsMaximized()
- {
- //get a handle to the game view
- EditorWindow tGameWindow = GetGameView();
- if (!tGameWindow)
- {
- Debug.Log("Failed to get GameView");
- //return true here to restore to window, not rift by default
- return true;
- }
- //Get the Rift window position
- WINDOWPOS winPos = new WINDOWPOS();
- if (!GetRiftMonitorWindowPos(ref winPos))
- {
- Debug.Log("No Rift Detected");
- return false;
- }
- //CALCULATE THE MAXIMIZED SIZE
- if (tGameWindow.position.width == winPos.cx)
- {
- return true;
- }
- else
- return false;
- }
- private void RestoreGameWindow()
- {
- //get a handle to the game view
- EditorWindow tGameWindow = GetGameView();
- if (!tGameWindow)
- {
- Debug.Log("Failed to get GameView");
- return;
- }
- //reset the gameWindow min and max size to remove the borders
- tGameWindow.minSize = _oldGameWinMinSize;
- tGameWindow.maxSize = _oldGameWinMaxSize;
- //Finally, call the MoveGameViewNatively routine to return the gameWindow to the old position
- MoveGameViewNatively(tGameWindow, _oldGameWinPos);
- }
- private void MoveGameViewNatively(EditorWindow gameWindow, WINDOWPOS winPos)
- {
- Rect tPos = new Rect();
- tPos.x = winPos.x;
- tPos.y = winPos.y;
- tPos.width = winPos.cx;
- tPos.height = winPos.cy;
- gameWindow.position = tPos;
- }
- private EditorWindow GetGameView()
- { //thanks to bunny83 for this routine to get the GameView (not sure if theres a better way, but at least this doesn't require reflection)
- Type ttype = Type.GetType("UnityEditor.GameView,UnityEditor");
- object[] foundView = Resources.FindObjectsOfTypeAll(ttype);
- if (foundView.Length > 0)
- {
- EditorWindow tGameView = (EditorWindow)foundView[0];
- return tGameView;
- }
- return null;
- }
- public static bool DetectActiveRift()
- { //Detects a DK2 (or hopefully other Rift) by monitor
- uint deviceIndex = 0;
- bool foundMon = false;
- do
- {
- var device = new DISPLAY_DEVICE();
- device.cb = Marshal.SizeOf(device);
- //First, enumerate through all the display devices
- DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
- displayDevice.cb = Marshal.SizeOf(displayDevice);
- foundMon = EnumDisplayDevices(null, deviceIndex++, ref displayDevice, 0);
- //We only care about active display devices
- if ((displayDevice.StateFlags & DisplayDeviceStateFlags.AttachedToDesktop) == DisplayDeviceStateFlags.AttachedToDesktop)
- {
- DISPLAY_DEVICE monitor = new DISPLAY_DEVICE();
- monitor.cb = Marshal.SizeOf(monitor);
- //now call EnumDisplayDevices again to get the device id
- EnumDisplayDevices(displayDevice.DeviceName, 0, ref monitor, 0);
- //If the display deviceID contains OVR then hopefully this is the Rift
- if (monitor.DeviceID.ToUpper().Contains(MonitorName))
- return true;
- }
- } while (foundMon);
- return false;
- }
- private bool GetRiftMonitorWindowPos(ref WINDOWPOS winPos)
- { //Finds a DK2 (or hopefully other Rifts?) monitor and gets its location, width and height.
- uint deviceIndex = 0;
- bool foundMon = false;
- do
- {
- var device = new DISPLAY_DEVICE();
- device.cb = Marshal.SizeOf(device);
- //First, enumerate through all the display devices
- DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
- displayDevice.cb = Marshal.SizeOf(displayDevice);
- foundMon = EnumDisplayDevices(null, deviceIndex++, ref displayDevice, 0);
- //We only care about active display devices
- if ((displayDevice.StateFlags & DisplayDeviceStateFlags.AttachedToDesktop) == DisplayDeviceStateFlags.AttachedToDesktop)
- {
- DISPLAY_DEVICE monitor = new DISPLAY_DEVICE();
- monitor.cb = Marshal.SizeOf(monitor);
- //now call EnumDisplayDevices again to get the device id
- EnumDisplayDevices(displayDevice.DeviceName, 0, ref monitor, 0);
- //If the display deviceID contains OVR then hopefully this is the Rift
- if (monitor.DeviceID.ToUpper().Contains(MonitorName))
- {
- DEVMODE devModeInfo = new DEVMODE();
- //Now try to get the info we need about the display and its location etc using EnumDisplaySettings
- if (EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, ref devModeInfo))
- {
- winPos.x = devModeInfo.dmPositionX;
- winPos.y = devModeInfo.dmPositionY;
- winPos.cx = devModeInfo.dmPelsWidth;
- winPos.cy = devModeInfo.dmPelsHeight;
- }
- return true;
- }
- }
- } while (foundMon);
- return false;
- }
- /********************************************************************************************
- * UnityPlayState *
- * Static class that detects Play/Stop events and calls the main class when they occur *
- *********************************************************************************************/
- [InitializeOnLoad]
- public static class UnityPlayState
- { //CLASS TO SUPPORT GETTING THE UNITY PLAY STATE
- static int _State;
- static bool wasPaused;
- static UnityPlayState()
- {
- //EditorApplication.update += Update;
- #if UNITY_EDITOR
- EditorApplication.playmodeStateChanged = HandleOnPlayModeChanged;
- #endif
- }
- public static int GetPlayState()
- { //DEPRECATED
- return _State;
- }
- static void HandleOnPlayModeChanged()
- {
- if (!DetectActiveRift()) return; //we are not interested in state changes if the Rift cannot be found
- if (EditorApplication.isPaused)
- {
- if (!wasPaused)
- {
- wasPaused = true;
- }
- else //was stopped or stop pressed
- {
- Stop();
- }
- }
- else if ((EditorApplication.isPlayingOrWillChangePlaymode))
- {
- if (!EditorApplication.isPlaying)
- {
- Play();
- }
- if (wasPaused)
- {
- Play();
- wasPaused = false;
- }
- }
- else if ((!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying))
- {
- Stop();
- }
- }
- static void Play()
- {
- _State = (int)GameViewState.MAXIMIZED;
- stateChange(_State);
- }
- static void Stop()
- {
- _State = (int)GameViewState.NORMAL;
- stateChange(_State);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement