diff --git a/Menus/MainMenu/MainMenu.cs b/Menus/MainMenu/MainMenu.cs index bcf59f65e..86aa8d44a 100644 --- a/Menus/MainMenu/MainMenu.cs +++ b/Menus/MainMenu/MainMenu.cs @@ -1,396 +1,395 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEditor.Experimental.EditorVR.Workspaces; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Menus -{ - sealed class MainMenu : MonoBehaviour, IMainMenu, IConnectInterfaces, IInstantiateUI, ICreateWorkspace, - ICustomActionMap, IUsesMenuOrigins, IUsesDeviceType, IControlHaptics, IUsesNode, IRayToNode, IUsesRayOrigin, - IRequestFeedback - { - const string k_SettingsMenuSectionName = "Settings"; - - [SerializeField] - ActionMap m_ActionMap; - - [SerializeField] - HapticPulse m_FaceRotationPulse; - - [SerializeField] - HapticPulse m_ShowPulse; - - [SerializeField] - HapticPulse m_HidePulse; - - [SerializeField] - MainMenuUI m_MainMenuPrefab; - - [SerializeField] - HapticPulse m_ButtonClickPulse; - - [SerializeField] - HapticPulse m_ButtonHoverPulse; - - Transform m_AlternateMenuOrigin; - Transform m_MenuOrigin; - MainMenuUI m_MainMenuUI; - float m_LastRotationInput; - MenuHideFlags m_MenuHideFlags = MenuHideFlags.Hidden; - readonly Dictionary m_ToolButtons = new Dictionary(); - readonly Dictionary m_SettingsMenus = new Dictionary(); - readonly Dictionary m_SettingsMenuItems = new Dictionary(); - - readonly BindingDictionary m_Controls = new BindingDictionary(); - - public List menuTools { private get; set; } - public List menuWorkspaces { private get; set; } - public Dictionary, ISettingsMenuProvider> settingsMenuProviders { get; set; } - public Dictionary, ISettingsMenuItemProvider> settingsMenuItemProviders { get; set; } - public List menuActions { get; set; } - public Transform targetRayOrigin { private get; set; } - public Node node { get; set; } - - public GameObject menuContent { get { return m_MainMenuUI.gameObject; } } - - public Transform rayOrigin { private get; set; } - - public Bounds localBounds { get { return m_MainMenuUI.localBounds; } } - - public bool focus { get { return m_MainMenuUI.hovering; } } - - public ActionMap actionMap { get { return m_ActionMap; } } - public bool ignoreLocking { get { return false; } } - - public Transform menuOrigin - { - get { return m_MenuOrigin; } - set - { - m_MenuOrigin = value; - if (m_MainMenuUI) - m_MainMenuUI.menuOrigin = value; - } - } - - public Transform alternateMenuOrigin - { - get { return m_AlternateMenuOrigin; } - set - { - m_AlternateMenuOrigin = value; - if (m_MainMenuUI) - m_MainMenuUI.alternateMenuOrigin = value; - } - } - - public MenuHideFlags menuHideFlags - { - get { return m_MenuHideFlags; } - set - { - var wasVisible = m_MenuHideFlags == 0; - var wasPermanent = (m_MenuHideFlags & MenuHideFlags.Hidden) != 0; - if (m_MenuHideFlags != value) - { - m_MenuHideFlags = value; - var visible = value == 0; - if (m_MainMenuUI) - { - var isPermanent = (value & MenuHideFlags.Hidden) != 0; - m_MainMenuUI.visible = visible; - if (wasPermanent && visible || wasVisible && isPermanent) - SendVisibilityPulse(); - } - - if (visible) - ShowFeedback(); - else - this.ClearFeedbackRequests(); - } - } - } - - void Awake() - { - m_MainMenuUI = this.InstantiateUI(m_MainMenuPrefab.gameObject).GetComponent(); - this.ConnectInterfaces(m_MainMenuUI); - m_MainMenuUI.alternateMenuOrigin = alternateMenuOrigin; - m_MainMenuUI.menuOrigin = menuOrigin; - m_MainMenuUI.Setup(); - - InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); - } - - void Start() - { - CreateFaceButtons(); - UpdateToolButtons(); - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - if (!m_MainMenuUI.visible) - return; - - var mainMenuInput = (MainMenuInput)input; - var rotationInput = -mainMenuInput.rotate.rawValue; - - consumeControl(mainMenuInput.rotate); - consumeControl(mainMenuInput.blockY); - - const float kFlickDeltaThreshold = 0.5f; - if ((this.GetDeviceType() != DeviceType.Vive && Mathf.Abs(rotationInput) >= kFlickDeltaThreshold - && Mathf.Abs(m_LastRotationInput) < kFlickDeltaThreshold) || mainMenuInput.flickFace.wasJustReleased) - { - m_MainMenuUI.targetFaceIndex += (int)Mathf.Sign(rotationInput); - this.Pulse(node, m_FaceRotationPulse); - } - - if (m_MenuHideFlags == 0) - consumeControl(mainMenuInput.flickFace); - - m_LastRotationInput = rotationInput; - } - - void OnDestroy() - { - if (m_MainMenuUI) - ObjectUtils.Destroy(m_MainMenuUI.gameObject); - } - - void CreateFaceButtons() - { - var types = new HashSet(); - types.UnionWith(menuTools); - types.UnionWith(menuWorkspaces); - types.UnionWith(settingsMenuProviders.Keys.Select(provider => provider.Key)); - types.UnionWith(settingsMenuItemProviders.Keys.Select(provider => provider.Key)); - - foreach (var type in types) - { - var customMenuAttribute = (MainMenuItemAttribute)type.GetCustomAttributes(typeof(MainMenuItemAttribute), false).FirstOrDefault(); - if (customMenuAttribute != null && !customMenuAttribute.shown) - continue; - - var isTool = typeof(ITool).IsAssignableFrom(type) && menuTools.Contains(type); - var isWorkspace = typeof(Workspace).IsAssignableFrom(type); - var isSettingsProvider = typeof(ISettingsMenuProvider).IsAssignableFrom(type); - var isSettingsItemProvider = typeof(ISettingsMenuItemProvider).IsAssignableFrom(type); - - ITooltip tooltip = null; - MainMenuUI.ButtonData buttonData = null; - - var selectedType = type; // Local variable for closure - if (customMenuAttribute != null && customMenuAttribute.shown) - { - tooltip = customMenuAttribute.tooltip; - - buttonData = new MainMenuUI.ButtonData(customMenuAttribute.name) - { - sectionName = customMenuAttribute.sectionName, - description = customMenuAttribute.description - }; - } - - if (isTool) - { - if (buttonData == null) - buttonData = new MainMenuUI.ButtonData(type.Name); - - var mainMenuButton = CreateFaceButton(buttonData, tooltip, () => - { - if (targetRayOrigin) - { - this.SelectTool(targetRayOrigin, selectedType, - hideMenu: typeof(IInstantiateMenuUI).IsAssignableFrom(selectedType)); - UpdateToolButtons(); - } - }); - - m_ToolButtons[type] = mainMenuButton; - - // Assign Tools Menu button preview properties - if (mainMenuButton != null) - mainMenuButton.toolType = selectedType; - } - - if (isWorkspace) - { - // For workspaces that haven't specified a custom attribute, do some menu categorization automatically - if (buttonData == null) - buttonData = new MainMenuUI.ButtonData(type.Name) { sectionName = "Workspaces" }; - - CreateFaceButton(buttonData, tooltip, () => { this.CreateWorkspace(selectedType); }); - } - - if (isSettingsProvider) - { - foreach (var providerPair in settingsMenuProviders) - { - var kvp = providerPair.Key; - if (kvp.Key == type && (kvp.Value == null || kvp.Value == rayOrigin)) - AddSettingsMenu(providerPair.Value, buttonData, tooltip); - } - } - - if (isSettingsItemProvider) - { - foreach (var providerPair in settingsMenuItemProviders) - { - var kvp = providerPair.Key; - if (kvp.Key == type && (kvp.Value == null || kvp.Value == rayOrigin)) - AddSettingsMenuItem(providerPair.Value); - } - } - } - } - - MainMenuButton CreateFaceButton(MainMenuUI.ButtonData buttonData, ITooltip tooltip, Action buttonClickCallback) - { - var mainMenuButton = m_MainMenuUI.CreateFaceButton(buttonData); - if (mainMenuButton == null) - return null; - - var button = mainMenuButton.button; - button.onClick.RemoveAllListeners(); - button.onClick.AddListener(() => - { - if (m_MenuHideFlags == 0) - buttonClickCallback(); - }); - - mainMenuButton.hovered += OnButtonHovered; - mainMenuButton.clicked += OnButtonClicked; - mainMenuButton.tooltip = tooltip; - - return mainMenuButton; - } - - void UpdateToolButtons() - { - foreach (var kvp in m_ToolButtons) - { - kvp.Value.selected = this.IsToolActive(targetRayOrigin, kvp.Key); - } - } - - void OnButtonClicked(Transform rayOrigin) - { - this.Pulse(this.RequestNodeFromRayOrigin(rayOrigin), m_ButtonClickPulse); - } - - void OnButtonHovered(Transform rayOrigin, Type buttonType, string buttonDescription) - { - this.Pulse(this.RequestNodeFromRayOrigin(rayOrigin), m_ButtonHoverPulse); - - // Pass the pointer which is over us, so this information can supply context (e.g. selecting a tool for a different hand) - // Enable preview-mode on a Tools Menu button; Display on the opposite proxy device by evaluating the entering RayOrigin - // Disable any existing previews being displayed in ToolsMenus - this.ClearToolMenuButtonPreview(); - - if (buttonType != null && rayOrigin != null) - this.PreviewInToolMenuButton(rayOrigin, buttonType, buttonDescription); - } - - void SendVisibilityPulse() - { - this.Pulse(node, m_MenuHideFlags == 0 ? m_HidePulse : m_ShowPulse); - } - - public void AddSettingsMenu(ISettingsMenuProvider provider) - { - var type = provider.GetType(); - var customMenuAttribute = (MainMenuItemAttribute)type.GetCustomAttributes(typeof(MainMenuItemAttribute), false).FirstOrDefault(); - - ITooltip tooltip = null; - MainMenuUI.ButtonData buttonData; - if (customMenuAttribute != null && customMenuAttribute.shown) - { - tooltip = customMenuAttribute.tooltip; - - buttonData = new MainMenuUI.ButtonData(customMenuAttribute.name) - { - sectionName = customMenuAttribute.sectionName, - description = customMenuAttribute.description - }; - } - else - { - buttonData = new MainMenuUI.ButtonData(type.Name); - } - - AddSettingsMenu(provider, buttonData, tooltip); - } - - void AddSettingsMenu(ISettingsMenuProvider provider, MainMenuUI.ButtonData buttonData, ITooltip tooltip) - { - buttonData.sectionName = k_SettingsMenuSectionName; - - CreateFaceButton(buttonData, tooltip, () => - { - var instance = m_MainMenuUI.AddSubmenu(k_SettingsMenuSectionName, provider.settingsMenuPrefab); - m_SettingsMenus[provider] = instance; - provider.settingsMenuInstance = instance; - }); - } - - public void RemoveSettingsMenu(ISettingsMenuProvider provider) - { - GameObject instance; - if (m_SettingsMenus.TryGetValue(provider, out instance)) - { - if (instance) - ObjectUtils.Destroy(instance); - - m_SettingsMenus.Remove(provider); - } - provider.settingsMenuInstance = null; - } - - public void AddSettingsMenuItem(ISettingsMenuItemProvider provider) - { - var instance = m_MainMenuUI.CreateCustomButton(provider.settingsMenuItemPrefab, k_SettingsMenuSectionName); - m_SettingsMenuItems[provider] = instance; - provider.settingsMenuItemInstance = instance; - } - - public void RemoveSettingsMenuItem(ISettingsMenuItemProvider provider) - { - GameObject instance; - if (m_SettingsMenuItems.TryGetValue(provider, out instance)) - { - if (instance) - ObjectUtils.Destroy(instance); - - m_SettingsMenuItems.Remove(provider); - } - provider.settingsMenuItemInstance = null; - } - - void ShowFeedback() - { - var tooltipText = this.GetDeviceType() == DeviceType.Vive ? "Press to Rotate Menu" : "Rotate Menu"; - List controls; - if (m_Controls.TryGetValue("FlickFace", out controls)) - { - foreach (var id in controls) - { - this.AddFeedbackRequest(new ProxyFeedbackRequest - { - control = id, - node = node, - tooltipText = tooltipText - }); - } - } - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEditor.Experimental.EditorVR.Workspaces; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Menus +{ + sealed class MainMenu : MonoBehaviour, IMainMenu, IConnectInterfaces, IInstantiateUI, ICreateWorkspace, + ICustomActionMap, IUsesMenuOrigins, IUsesDeviceType, IControlHaptics, IUsesNode, IRayToNode, IUsesRayOrigin, + IRequestFeedback + { + const string k_SettingsMenuSectionName = "Settings"; + + [SerializeField] + ActionMap m_ActionMap; + + [SerializeField] + HapticPulse m_FaceRotationPulse; + + [SerializeField] + HapticPulse m_ShowPulse; + + [SerializeField] + HapticPulse m_HidePulse; + + [SerializeField] + MainMenuUI m_MainMenuPrefab; + + [SerializeField] + HapticPulse m_ButtonClickPulse; + + [SerializeField] + HapticPulse m_ButtonHoverPulse; + + Transform m_AlternateMenuOrigin; + Transform m_MenuOrigin; + MainMenuUI m_MainMenuUI; + float m_LastRotationInput; + MenuHideFlags m_MenuHideFlags = MenuHideFlags.Hidden; + readonly Dictionary m_ToolButtons = new Dictionary(); + readonly Dictionary m_SettingsMenus = new Dictionary(); + readonly Dictionary m_SettingsMenuItems = new Dictionary(); + + readonly BindingDictionary m_Controls = new BindingDictionary(); + + public List menuTools { private get; set; } + public List menuWorkspaces { private get; set; } + public Dictionary, ISettingsMenuProvider> settingsMenuProviders { get; set; } + public Dictionary, ISettingsMenuItemProvider> settingsMenuItemProviders { get; set; } + public List menuActions { get; set; } + public Transform targetRayOrigin { private get; set; } + public Node node { get; set; } + + public GameObject menuContent { get { return m_MainMenuUI.gameObject; } } + + public Transform rayOrigin { private get; set; } + + public Bounds localBounds { get { return m_MainMenuUI.localBounds; } } + + public bool focus { get { return m_MainMenuUI.hovering; } } + + public ActionMap actionMap { get { return m_ActionMap; } } + public bool ignoreLocking { get { return false; } } + + public Transform menuOrigin + { + get { return m_MenuOrigin; } + set + { + m_MenuOrigin = value; + if (m_MainMenuUI) + m_MainMenuUI.menuOrigin = value; + } + } + + public Transform alternateMenuOrigin + { + get { return m_AlternateMenuOrigin; } + set + { + m_AlternateMenuOrigin = value; + if (m_MainMenuUI) + m_MainMenuUI.alternateMenuOrigin = value; + } + } + + public MenuHideFlags menuHideFlags + { + get { return m_MenuHideFlags; } + set + { + var wasVisible = m_MenuHideFlags == 0; + var wasPermanent = (m_MenuHideFlags & MenuHideFlags.Hidden) != 0; + if (m_MenuHideFlags != value) + { + m_MenuHideFlags = value; + var visible = value == 0; + if (m_MainMenuUI) + { + var isPermanent = (value & MenuHideFlags.Hidden) != 0; + m_MainMenuUI.visible = visible; + if (wasPermanent && visible || wasVisible && isPermanent) + SendVisibilityPulse(); + } + + if (visible) + ShowFeedback(); + else + this.ClearFeedbackRequests(); + } + } + } + + void Awake() + { + m_MainMenuUI = this.InstantiateUI(m_MainMenuPrefab.gameObject).GetComponent(); + this.ConnectInterfaces(m_MainMenuUI); + m_MainMenuUI.alternateMenuOrigin = alternateMenuOrigin; + m_MainMenuUI.menuOrigin = menuOrigin; + m_MainMenuUI.Setup(); + + InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); + } + + void Start() + { + CreateFaceButtons(); + UpdateToolButtons(); + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + if (!m_MainMenuUI.visible) + return; + + var mainMenuInput = (MainMenuInput)input; + var rotationInput = -mainMenuInput.rotate.rawValue; + + consumeControl(mainMenuInput.rotate); + consumeControl(mainMenuInput.blockY); + + const float kFlickDeltaThreshold = 0.5f; + if ((this.GetDeviceType() != DeviceType.Vive && Mathf.Abs(rotationInput) >= kFlickDeltaThreshold + && Mathf.Abs(m_LastRotationInput) < kFlickDeltaThreshold) || mainMenuInput.flickFace.wasJustReleased) + { + m_MainMenuUI.targetFaceIndex += (int)Mathf.Sign(rotationInput); + this.Pulse(node, m_FaceRotationPulse); + } + + if (m_MenuHideFlags == 0) + consumeControl(mainMenuInput.flickFace); + + m_LastRotationInput = rotationInput; + } + + void OnDestroy() + { + if (m_MainMenuUI) + ObjectUtils.Destroy(m_MainMenuUI.gameObject); + } + + void CreateFaceButtons() + { + var types = new HashSet(); + types.UnionWith(menuTools); + types.UnionWith(menuWorkspaces); + types.UnionWith(settingsMenuProviders.Keys.Select(provider => provider.Key)); + types.UnionWith(settingsMenuItemProviders.Keys.Select(provider => provider.Key)); + + foreach (var type in types) + { + var customMenuAttribute = (MainMenuItemAttribute)type.GetCustomAttributes(typeof(MainMenuItemAttribute), false).FirstOrDefault(); + if (customMenuAttribute != null && !customMenuAttribute.shown) + continue; + + var isTool = typeof(ITool).IsAssignableFrom(type) && menuTools.Contains(type); + var isWorkspace = typeof(Workspace).IsAssignableFrom(type); + var isSettingsProvider = typeof(ISettingsMenuProvider).IsAssignableFrom(type); + var isSettingsItemProvider = typeof(ISettingsMenuItemProvider).IsAssignableFrom(type); + + ITooltip tooltip = null; + MainMenuUI.ButtonData buttonData = null; + + var selectedType = type; // Local variable for closure + if (customMenuAttribute != null && customMenuAttribute.shown) + { + tooltip = customMenuAttribute.tooltip; + + buttonData = new MainMenuUI.ButtonData(customMenuAttribute.name) + { + sectionName = customMenuAttribute.sectionName, + description = customMenuAttribute.description + }; + } + + if (isTool) + { + if (buttonData == null) + buttonData = new MainMenuUI.ButtonData(type.Name); + + var mainMenuButton = CreateFaceButton(buttonData, tooltip, () => + { + if (targetRayOrigin) + { + this.SelectTool(targetRayOrigin, selectedType, + hideMenu: typeof(IInstantiateMenuUI).IsAssignableFrom(selectedType)); + UpdateToolButtons(); + } + }); + + m_ToolButtons[type] = mainMenuButton; + + // Assign Tools Menu button preview properties + if (mainMenuButton != null) + mainMenuButton.toolType = selectedType; + } + + if (isWorkspace) + { + // For workspaces that haven't specified a custom attribute, do some menu categorization automatically + if (buttonData == null) + buttonData = new MainMenuUI.ButtonData(type.Name) { sectionName = "Workspaces" }; + + CreateFaceButton(buttonData, tooltip, () => { this.CreateWorkspace(selectedType); }); + } + + if (isSettingsProvider) + { + foreach (var providerPair in settingsMenuProviders) + { + var kvp = providerPair.Key; + if (kvp.Key == type && (kvp.Value == null || kvp.Value == rayOrigin)) + AddSettingsMenu(providerPair.Value, buttonData, tooltip); + } + } + + if (isSettingsItemProvider) + { + foreach (var providerPair in settingsMenuItemProviders) + { + var kvp = providerPair.Key; + if (kvp.Key == type && (kvp.Value == null || kvp.Value == rayOrigin)) + AddSettingsMenuItem(providerPair.Value); + } + } + } + } + + MainMenuButton CreateFaceButton(MainMenuUI.ButtonData buttonData, ITooltip tooltip, Action buttonClickCallback) + { + var mainMenuButton = m_MainMenuUI.CreateFaceButton(buttonData); + if (mainMenuButton == null) + return null; + + var button = mainMenuButton.button; + button.onClick.RemoveAllListeners(); + button.onClick.AddListener(() => + { + if (m_MenuHideFlags == 0) + buttonClickCallback(); + }); + + mainMenuButton.hovered += OnButtonHovered; + mainMenuButton.clicked += OnButtonClicked; + mainMenuButton.tooltip = tooltip; + + return mainMenuButton; + } + + void UpdateToolButtons() + { + foreach (var kvp in m_ToolButtons) + { + kvp.Value.selected = this.IsToolActive(targetRayOrigin, kvp.Key); + } + } + + void OnButtonClicked(Transform rayOrigin) + { + this.Pulse(this.RequestNodeFromRayOrigin(rayOrigin), m_ButtonClickPulse); + } + + void OnButtonHovered(Transform rayOrigin, Type buttonType, string buttonDescription) + { + this.Pulse(this.RequestNodeFromRayOrigin(rayOrigin), m_ButtonHoverPulse); + + // Pass the pointer which is over us, so this information can supply context (e.g. selecting a tool for a different hand) + // Enable preview-mode on a Tools Menu button; Display on the opposite proxy device by evaluating the entering RayOrigin + // Disable any existing previews being displayed in ToolsMenus + this.ClearToolMenuButtonPreview(); + + if (buttonType != null && rayOrigin != null) + this.PreviewInToolMenuButton(rayOrigin, buttonType, buttonDescription); + } + + void SendVisibilityPulse() + { + this.Pulse(node, m_MenuHideFlags == 0 ? m_HidePulse : m_ShowPulse); + } + + public void AddSettingsMenu(ISettingsMenuProvider provider) + { + var type = provider.GetType(); + var customMenuAttribute = (MainMenuItemAttribute)type.GetCustomAttributes(typeof(MainMenuItemAttribute), false).FirstOrDefault(); + + ITooltip tooltip = null; + MainMenuUI.ButtonData buttonData; + if (customMenuAttribute != null && customMenuAttribute.shown) + { + tooltip = customMenuAttribute.tooltip; + + buttonData = new MainMenuUI.ButtonData(customMenuAttribute.name) + { + sectionName = customMenuAttribute.sectionName, + description = customMenuAttribute.description + }; + } + else + { + buttonData = new MainMenuUI.ButtonData(type.Name); + } + + AddSettingsMenu(provider, buttonData, tooltip); + } + + void AddSettingsMenu(ISettingsMenuProvider provider, MainMenuUI.ButtonData buttonData, ITooltip tooltip) + { + buttonData.sectionName = k_SettingsMenuSectionName; + + CreateFaceButton(buttonData, tooltip, () => + { + var instance = m_MainMenuUI.AddSubmenu(k_SettingsMenuSectionName, provider.settingsMenuPrefab); + m_SettingsMenus[provider] = instance; + provider.settingsMenuInstance = instance; + }); + } + + public void RemoveSettingsMenu(ISettingsMenuProvider provider) + { + GameObject instance; + if (m_SettingsMenus.TryGetValue(provider, out instance)) + { + if (instance) + ObjectUtils.Destroy(instance); + + m_SettingsMenus.Remove(provider); + } + provider.settingsMenuInstance = null; + } + + public void AddSettingsMenuItem(ISettingsMenuItemProvider provider) + { + var instance = m_MainMenuUI.CreateCustomButton(provider.settingsMenuItemPrefab, k_SettingsMenuSectionName); + m_SettingsMenuItems[provider] = instance; + provider.settingsMenuItemInstance = instance; + } + + public void RemoveSettingsMenuItem(ISettingsMenuItemProvider provider) + { + GameObject instance; + if (m_SettingsMenuItems.TryGetValue(provider, out instance)) + { + if (instance) + ObjectUtils.Destroy(instance); + + m_SettingsMenuItems.Remove(provider); + } + provider.settingsMenuItemInstance = null; + } + + void ShowFeedback() + { + var tooltipText = this.GetDeviceType() == DeviceType.Vive ? "Press to Rotate Menu" : "Rotate Menu"; + List controls; + if (m_Controls.TryGetValue("FlickFace", out controls)) + { + foreach (var id in controls) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = id; + request.node = node; + request.tooltipText = tooltipText; + this.AddFeedbackRequest(request); + } + } + } + } +} +#endif diff --git a/Menus/MainMenu/Scripts/MainMenuUI.cs b/Menus/MainMenu/Scripts/MainMenuUI.cs index e22e75311..9bc9cf45b 100644 --- a/Menus/MainMenu/Scripts/MainMenuUI.cs +++ b/Menus/MainMenu/Scripts/MainMenuUI.cs @@ -481,7 +481,7 @@ IEnumerator AnimateFrameReveal(VisibilityState visibilityState) currentBlendShapeWeight = currentBlendShapeWeight > 0 ? currentBlendShapeWeight : zeroStartBlendShapePadding; var currentDuration = 0f; - while (m_VisibilityState != VisibilityState.Hidden && currentDuration < smoothTime) + while (m_VisibilityState != VisibilityState.Hidden && currentDuration - Time.deltaTime < smoothTime) { currentBlendShapeWeight = MathUtilsExt.SmoothDamp(currentBlendShapeWeight, targetWeight, ref smoothVelocity, smoothTime, Mathf.Infinity, Time.deltaTime); currentDuration += Time.deltaTime; @@ -490,14 +490,13 @@ IEnumerator AnimateFrameReveal(VisibilityState visibilityState) yield return null; } - if (m_VisibilityState == visibilityState) - { - m_MenuFrameRenderer.SetBlendShapeWeight(1, targetWeight); - m_MenuFacesMaterial.color = targetWeight > 0 ? m_MenuFacesColor : k_MenuFacesHiddenColor; - } + m_MenuFrameRenderer.SetBlendShapeWeight(1, targetWeight); + m_MenuFacesMaterial.color = targetWeight > 0 ? m_MenuFacesColor : k_MenuFacesHiddenColor; if (m_VisibilityState == VisibilityState.Hidden) + { m_MenuFrameRenderer.SetBlendShapeWeight(0, 0); + } } public void OnRayEnter(RayEventData eventData) diff --git a/Menus/RadialMenu/RadialMenu.cs b/Menus/RadialMenu/RadialMenu.cs index 5d52e66ae..ee5a70c3d 100644 --- a/Menus/RadialMenu/RadialMenu.cs +++ b/Menus/RadialMenu/RadialMenu.cs @@ -1,180 +1,179 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Menus -{ - sealed class RadialMenu : MonoBehaviour, IInstantiateUI, IAlternateMenu, IUsesMenuOrigins, ICustomActionMap, - IControlHaptics, IUsesNode, IConnectInterfaces, IRequestFeedback - { - const float k_ActivationThreshold = 0.5f; // Do not consume thumbstick or activate menu if the control vector's magnitude is below this threshold - - [SerializeField] - ActionMap m_ActionMap; - - [SerializeField] - RadialMenuUI m_RadialMenuPrefab; - - [SerializeField] - HapticPulse m_ReleasePulse; - - [SerializeField] - HapticPulse m_ButtonHoverPulse; - - [SerializeField] - HapticPulse m_ButtonClickedPulse; - - RadialMenuUI m_RadialMenuUI; - List m_MenuActions; - Transform m_AlternateMenuOrigin; - MenuHideFlags m_MenuHideFlags = MenuHideFlags.Hidden; - - readonly BindingDictionary m_Controls = new BindingDictionary(); - - public event Action itemWasSelected; - - public Transform rayOrigin { private get; set; } - - public Transform menuOrigin { get; set; } - - public GameObject menuContent { get { return m_RadialMenuUI.gameObject; } } - - public Node node { get; set; } - - public Bounds localBounds { get { return default(Bounds); } } - - public ActionMap actionMap { get { return m_ActionMap; } } - public bool ignoreLocking { get { return false; } } - - public List menuActions - { - get { return m_MenuActions; } - set - { - m_MenuActions = value; - - if (m_RadialMenuUI) - m_RadialMenuUI.actions = value; - } - } - - public Transform alternateMenuOrigin - { - get { return m_AlternateMenuOrigin; } - set - { - m_AlternateMenuOrigin = value; - - if (m_RadialMenuUI != null) - m_RadialMenuUI.alternateMenuOrigin = value; - } - } - - public MenuHideFlags menuHideFlags - { - get { return m_MenuHideFlags; } - set - { - if (m_MenuHideFlags != value) - { - m_MenuHideFlags = value; - var visible = value == 0; - if (m_RadialMenuUI) - m_RadialMenuUI.visible = visible; - - if (visible) - ShowFeedback(); - else - this.ClearFeedbackRequests(); - } - } - } - - void Start() - { - m_RadialMenuUI = this.InstantiateUI(m_RadialMenuPrefab.gameObject).GetComponent(); - m_RadialMenuUI.alternateMenuOrigin = alternateMenuOrigin; - m_RadialMenuUI.actions = menuActions; - this.ConnectInterfaces(m_RadialMenuUI); // Connect interfaces before performing setup on the UI - m_RadialMenuUI.Setup(); - m_RadialMenuUI.buttonHovered += OnButtonHovered; - m_RadialMenuUI.buttonClicked += OnButtonClicked; - - InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - var radialMenuInput = (RadialMenuInput)input; - if (radialMenuInput == null || m_MenuHideFlags != 0) - { - this.ClearFeedbackRequests(); - return; - } - - var inputDirection = radialMenuInput.navigate.vector2; - - if (inputDirection.magnitude > k_ActivationThreshold) - { - // Composite controls need to be consumed separately - consumeControl(radialMenuInput.navigateX); - consumeControl(radialMenuInput.navigateY); - m_RadialMenuUI.buttonInputDirection = inputDirection; - } - else - { - m_RadialMenuUI.buttonInputDirection = Vector2.zero; - } - - var selectControl = radialMenuInput.selectItem; - m_RadialMenuUI.pressedDown = selectControl.wasJustPressed; - if (m_RadialMenuUI.pressedDown) - consumeControl(selectControl); - - if (selectControl.wasJustReleased) - { - this.Pulse(node, m_ReleasePulse); - - m_RadialMenuUI.SelectionOccurred(); - - if (itemWasSelected != null) - itemWasSelected(rayOrigin); - - consumeControl(selectControl); - } - } - - void OnButtonClicked() - { - this.Pulse(node, m_ButtonClickedPulse); - } - - void OnButtonHovered() - { - this.Pulse(node, m_ButtonHoverPulse); - } - - void ShowFeedback() - { - List controls; - if (m_Controls.TryGetValue("SelectItem", out controls)) - { - foreach (var id in controls) - { - this.AddFeedbackRequest(new ProxyFeedbackRequest - { - control = id, - node = node, - tooltipText = "Select Action (Press to Execute)" - }); - } - } - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Menus +{ + sealed class RadialMenu : MonoBehaviour, IInstantiateUI, IAlternateMenu, IUsesMenuOrigins, ICustomActionMap, + IControlHaptics, IUsesNode, IConnectInterfaces, IRequestFeedback + { + const float k_ActivationThreshold = 0.5f; // Do not consume thumbstick or activate menu if the control vector's magnitude is below this threshold + + [SerializeField] + ActionMap m_ActionMap; + + [SerializeField] + RadialMenuUI m_RadialMenuPrefab; + + [SerializeField] + HapticPulse m_ReleasePulse; + + [SerializeField] + HapticPulse m_ButtonHoverPulse; + + [SerializeField] + HapticPulse m_ButtonClickedPulse; + + RadialMenuUI m_RadialMenuUI; + List m_MenuActions; + Transform m_AlternateMenuOrigin; + MenuHideFlags m_MenuHideFlags = MenuHideFlags.Hidden; + + readonly BindingDictionary m_Controls = new BindingDictionary(); + + public event Action itemWasSelected; + + public Transform rayOrigin { private get; set; } + + public Transform menuOrigin { get; set; } + + public GameObject menuContent { get { return m_RadialMenuUI.gameObject; } } + + public Node node { get; set; } + + public Bounds localBounds { get { return default(Bounds); } } + + public ActionMap actionMap { get { return m_ActionMap; } } + public bool ignoreLocking { get { return false; } } + + public List menuActions + { + get { return m_MenuActions; } + set + { + m_MenuActions = value; + + if (m_RadialMenuUI) + m_RadialMenuUI.actions = value; + } + } + + public Transform alternateMenuOrigin + { + get { return m_AlternateMenuOrigin; } + set + { + m_AlternateMenuOrigin = value; + + if (m_RadialMenuUI != null) + m_RadialMenuUI.alternateMenuOrigin = value; + } + } + + public MenuHideFlags menuHideFlags + { + get { return m_MenuHideFlags; } + set + { + if (m_MenuHideFlags != value) + { + m_MenuHideFlags = value; + var visible = value == 0; + if (m_RadialMenuUI) + m_RadialMenuUI.visible = visible; + + if (visible) + ShowFeedback(); + else + this.ClearFeedbackRequests(); + } + } + } + + void Start() + { + m_RadialMenuUI = this.InstantiateUI(m_RadialMenuPrefab.gameObject).GetComponent(); + m_RadialMenuUI.alternateMenuOrigin = alternateMenuOrigin; + m_RadialMenuUI.actions = menuActions; + this.ConnectInterfaces(m_RadialMenuUI); // Connect interfaces before performing setup on the UI + m_RadialMenuUI.Setup(); + m_RadialMenuUI.buttonHovered += OnButtonHovered; + m_RadialMenuUI.buttonClicked += OnButtonClicked; + + InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + var radialMenuInput = (RadialMenuInput)input; + if (radialMenuInput == null || m_MenuHideFlags != 0) + { + this.ClearFeedbackRequests(); + return; + } + + var inputDirection = radialMenuInput.navigate.vector2; + + if (inputDirection.magnitude > k_ActivationThreshold) + { + // Composite controls need to be consumed separately + consumeControl(radialMenuInput.navigateX); + consumeControl(radialMenuInput.navigateY); + m_RadialMenuUI.buttonInputDirection = inputDirection; + } + else + { + m_RadialMenuUI.buttonInputDirection = Vector2.zero; + } + + var selectControl = radialMenuInput.selectItem; + m_RadialMenuUI.pressedDown = selectControl.wasJustPressed; + if (m_RadialMenuUI.pressedDown) + consumeControl(selectControl); + + if (selectControl.wasJustReleased) + { + this.Pulse(node, m_ReleasePulse); + + m_RadialMenuUI.SelectionOccurred(); + + if (itemWasSelected != null) + itemWasSelected(rayOrigin); + + consumeControl(selectControl); + } + } + + void OnButtonClicked() + { + this.Pulse(node, m_ButtonClickedPulse); + } + + void OnButtonHovered() + { + this.Pulse(node, m_ButtonHoverPulse); + } + + void ShowFeedback() + { + List controls; + if (m_Controls.TryGetValue("SelectItem", out controls)) + { + foreach (var id in controls) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = id; + request.node = node; + request.tooltipText = "Select Action (Press to Execute)"; + this.AddFeedbackRequest(request); + } + } + } + } +} +#endif diff --git a/Menus/ToolsMenu/ToolsMenu.cs b/Menus/ToolsMenu/ToolsMenu.cs index 6735d783e..cba516231 100644 --- a/Menus/ToolsMenu/ToolsMenu.cs +++ b/Menus/ToolsMenu/ToolsMenu.cs @@ -1,320 +1,317 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Menus -{ - sealed class ToolsMenu : MonoBehaviour, IToolsMenu, IConnectInterfaces, IInstantiateUI, IControlHaptics, - IUsesViewerScale, IControlSpatialScrolling, IControlSpatialHinting, IRayVisibilitySettings, IUsesRayOrigin, - IRequestFeedback - { - const int k_ActiveToolOrderPosition = 1; // A active-tool button position used in this particular ToolButton implementation - const int k_MaxButtonCount = 16; - - [SerializeField] - Sprite m_MainMenuIcon; - - [SerializeField] - ActionMap m_ActionMap; - - [SerializeField] - ToolsMenuUI m_ToolsMenuPrefab; - - [SerializeField] - ToolsMenuButton _mToolsMenuButtonTemplate; - - [SerializeField] - HapticPulse m_ButtonClickPulse; - - [SerializeField] - HapticPulse m_ButtonHoverPulse; - - [SerializeField] - HapticPulse m_HidingPulse; // The pulse performed when ending a spatial selection - - float m_AllowToolToggleBeforeThisTime; - Vector3 m_SpatialScrollStartPosition; - ToolsMenuUI m_ToolsMenuUI; - - readonly BindingDictionary m_Controls = new BindingDictionary(); - readonly List m_ScrollFeedback = new List(); - readonly List m_MenuFeedback = new List(); - - public Transform menuOrigin { get; set; } - - List buttons { get { return m_ToolsMenuUI.buttons; } } - - public bool alternateMenuVisible { set { m_ToolsMenuUI.moveToAlternatePosition = value; } } - - public Action highlightSingleButton { get; set; } - public Action selectHighlightedButton { get; set; } - public Action setButtonForType { get; set; } - public Action deleteToolsMenuButton { get; set; } - public Node node { get; set; } - public IToolsMenuButton PreviewToolsMenuButton { get; private set; } - public Transform alternateMenuOrigin { get; set; } - public SpatialScrollModule.SpatialScrollData spatialScrollData { get; set; } - - public ActionMap actionMap { get { return m_ActionMap; } } - public bool ignoreLocking { get { return false; } } - - public Transform rayOrigin { get; set; } - - public bool mainMenuActivatorInteractable - { - set { PreviewToolsMenuButton.interactable = value; } - } - - void Awake() - { - setButtonForType = CreateToolsMenuButton; - deleteToolsMenuButton = DeleteToolsMenuButton; - InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); - } - - void OnDestroy() - { - this.RemoveRayVisibilitySettings(rayOrigin, this); - } - - void CreateToolsMenuUI() - { - m_ToolsMenuUI = this.InstantiateUI(m_ToolsMenuPrefab.gameObject, rayOrigin, true, rayOrigin).GetComponent(); - m_ToolsMenuUI.maxButtonCount = k_MaxButtonCount; - m_ToolsMenuUI.mainMenuActivatorSelected = this.MainMenuActivatorSelected; - m_ToolsMenuUI.buttonHovered += OnButtonHover; - m_ToolsMenuUI.buttonClicked += OnButtonClick; - m_ToolsMenuUI.buttonSelected += OnButtonSelected; - m_ToolsMenuUI.closeMenu += CloseMenu; - - // Alternate menu origin isn't set when awake or start run - var toolsMenuUITransform = m_ToolsMenuUI.transform; - toolsMenuUITransform.SetParent(alternateMenuOrigin); - toolsMenuUITransform.localPosition = Vector3.zero; - toolsMenuUITransform.localRotation = Quaternion.identity; - } - - void CreateToolsMenuButton(Type toolType, Sprite buttonIcon) - { - // Verify first that the ToolsMenuUI exists - // This is called in EditorVR.Tools before the UI can be created herein in Awake - // The SelectionTool & MainMenu buttons are created immediately after instantiating the ToolsMenu - if (m_ToolsMenuUI == null) - CreateToolsMenuUI(); - - // Select an existing ToolButton if the type is already present in a button - if (buttons.Any(x => x.toolType == toolType)) - { - m_ToolsMenuUI.SelectExistingToolType(toolType); - return; - } - - if (buttons.Count >= k_MaxButtonCount) // Return if tool type already occupies a tool button - return; - - var buttonTransform = ObjectUtils.Instantiate(_mToolsMenuButtonTemplate.gameObject, m_ToolsMenuUI.buttonContainer, false).transform; - var button = buttonTransform.GetComponent(); - this.ConnectInterfaces(button); - - button.rayOrigin = rayOrigin; - button.toolType = toolType; // Assign Tool Type before assigning order - button.icon = toolType != typeof(IMainMenu) ? buttonIcon : m_MainMenuIcon; - button.highlightSingleButton = highlightSingleButton; - button.selectHighlightedButton = selectHighlightedButton; - button.rayOrigin = rayOrigin; - - if (toolType == typeof(IMainMenu)) - PreviewToolsMenuButton = button; - - m_ToolsMenuUI.AddButton(button, buttonTransform); - } - - void DeleteToolsMenuButton(Type toolTypeToDelete, Type toolTypeToSelectAfterDelete) - { - if (m_ToolsMenuUI.DeleteButtonOfType(toolTypeToDelete)) - m_ToolsMenuUI.SelectNextExistingToolButton(); - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - var buttonCount = buttons.Count; - if (buttonCount <= k_ActiveToolOrderPosition + 1) - return; - - const float kAllowToggleDuration = 0.25f; - - var toolslMenuInput = (ToolsMenuInput)input; - - if (spatialScrollData != null && toolslMenuInput.cancel.wasJustPressed) - { - consumeControl(toolslMenuInput.cancel); - consumeControl(toolslMenuInput.show); - consumeControl(toolslMenuInput.select); - OnButtonClick(); - CloseMenu(); // Also ends spatial scroll - m_ToolsMenuUI.allButtonsVisible = false; - } - - if (toolslMenuInput.show.wasJustPressed) - ShowScrollFeedback(); - - if (toolslMenuInput.show.wasJustReleased) - HideScrollFeedback(); - - if (spatialScrollData == null && (toolslMenuInput.show.wasJustPressed || toolslMenuInput.show.isHeld) && toolslMenuInput.select.wasJustPressed) - { - m_SpatialScrollStartPosition = alternateMenuOrigin.position; - m_AllowToolToggleBeforeThisTime = Time.realtimeSinceStartup + kAllowToggleDuration; - this.SetSpatialHintControlNode(node); - m_ToolsMenuUI.spatiallyScrolling = true; // Triggers the display of the directional hint arrows - consumeControl(toolslMenuInput.show); - consumeControl(toolslMenuInput.select); - - // Assign initial SpatialScrollData; begin scroll - spatialScrollData = this.PerformSpatialScroll(node, m_SpatialScrollStartPosition, alternateMenuOrigin.position, 0.325f, m_ToolsMenuUI.buttons.Count, m_ToolsMenuUI.maxButtonCount); - - HideScrollFeedback(); - ShowMenuFeedback(); - } - else if (spatialScrollData != null && toolslMenuInput.show.isHeld) - { - consumeControl(toolslMenuInput.show); - consumeControl(toolslMenuInput.select); - - // Attempt to close a button, if a scroll has passed the trigger threshold - if (spatialScrollData != null && toolslMenuInput.select.wasJustPressed) - { - if (m_ToolsMenuUI.DeleteHighlightedButton()) - buttonCount = buttons.Count; // The MainMenu button will be hidden, subtract 1 from the activeButtonCount - - if (buttonCount <= k_ActiveToolOrderPosition + 1) - { - if (spatialScrollData != null) - this.EndSpatialScroll(); - - return; - } - } - - // normalized input should loop after reaching the 0.15f length - buttonCount -= 1; // Decrement to disallow cycling through the main menu button - spatialScrollData = this.PerformSpatialScroll(node, m_SpatialScrollStartPosition, alternateMenuOrigin.position, 0.325f, m_ToolsMenuUI.buttons.Count, m_ToolsMenuUI.maxButtonCount); - var normalizedRepeatingPosition = spatialScrollData.normalizedLoopingPosition; - if (!Mathf.Approximately(normalizedRepeatingPosition, 0f)) - { - if (!m_ToolsMenuUI.allButtonsVisible) - { - m_ToolsMenuUI.spatialDragDistance = spatialScrollData.dragDistance; - this.SetSpatialHintState(SpatialHintModule.SpatialHintStateFlags.CenteredScrolling); - m_ToolsMenuUI.allButtonsVisible = true; - } - else if (spatialScrollData.spatialDirection != null) - { - m_ToolsMenuUI.startingDragOrigin = spatialScrollData.spatialDirection; - } - - m_ToolsMenuUI.HighlightSingleButtonWithoutMenu((int)(buttonCount * normalizedRepeatingPosition) + 1); - } - } - else if (spatialScrollData != null && !toolslMenuInput.show.isHeld && !toolslMenuInput.select.isHeld) - { - consumeControl(toolslMenuInput.show); - consumeControl(toolslMenuInput.select); - - if (spatialScrollData != null && spatialScrollData.passedMinDragActivationThreshold) - { - m_ToolsMenuUI.SelectHighlightedButton(); - } - else if (Time.realtimeSinceStartup < m_AllowToolToggleBeforeThisTime) - { - // Allow for single press+release to cycle through tools - m_ToolsMenuUI.SelectNextExistingToolButton(); - OnButtonClick(); - } - - CloseMenu(); - } - } - - void OnButtonClick() - { - this.Pulse(node, m_ButtonClickPulse); - this.SetSpatialHintState(SpatialHintModule.SpatialHintStateFlags.Hidden); - } - - void OnButtonHover() - { - this.Pulse(node, m_ButtonHoverPulse); - } - - void OnButtonSelected(Transform rayOrigin, Type buttonType) - { - this.SelectTool(rayOrigin, buttonType, false); - } - - void CloseMenu() - { - this.ClearFeedbackRequests(); - this.Pulse(node, m_HidingPulse); - this.EndSpatialScroll(); // Free the spatial scroll data owned by this object - } - - void ShowFeedback(List requests, string controlName, string tooltipText = null) - { - if (tooltipText == null) - tooltipText = controlName; - - List ids; - if (m_Controls.TryGetValue(controlName, out ids)) - { - foreach (var id in ids) - { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - priority = 1, - tooltipText = tooltipText - }; - - this.AddFeedbackRequest(request); - requests.Add(request); - } - } - } - - void ShowScrollFeedback() - { - ShowFeedback(m_ScrollFeedback, "select", "Scroll to Change Tool"); - } - - void ShowMenuFeedback() - { - ShowFeedback(m_MenuFeedback, "select", "Remove Tool"); - ShowFeedback(m_MenuFeedback, "cancel", "Cancel Scrolling"); - ShowFeedback(m_MenuFeedback, "show", "Release to Select Tool"); - } - - void HideFeedback(List requests) - { - foreach (var request in requests) - { - this.RemoveFeedbackRequest(request); - } - requests.Clear(); - } - - void HideScrollFeedback() - { - HideFeedback(m_ScrollFeedback); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Menus +{ + sealed class ToolsMenu : MonoBehaviour, IToolsMenu, IConnectInterfaces, IInstantiateUI, IControlHaptics, + IUsesViewerScale, IControlSpatialScrolling, IControlSpatialHinting, IRayVisibilitySettings, IUsesRayOrigin, + IRequestFeedback + { + const int k_ActiveToolOrderPosition = 1; // A active-tool button position used in this particular ToolButton implementation + const int k_MaxButtonCount = 16; + + [SerializeField] + Sprite m_MainMenuIcon; + + [SerializeField] + ActionMap m_ActionMap; + + [SerializeField] + ToolsMenuUI m_ToolsMenuPrefab; + + [SerializeField] + ToolsMenuButton _mToolsMenuButtonTemplate; + + [SerializeField] + HapticPulse m_ButtonClickPulse; + + [SerializeField] + HapticPulse m_ButtonHoverPulse; + + [SerializeField] + HapticPulse m_HidingPulse; // The pulse performed when ending a spatial selection + + float m_AllowToolToggleBeforeThisTime; + Vector3 m_SpatialScrollStartPosition; + ToolsMenuUI m_ToolsMenuUI; + + readonly BindingDictionary m_Controls = new BindingDictionary(); + readonly List m_ScrollFeedback = new List(); + readonly List m_MenuFeedback = new List(); + + public Transform menuOrigin { get; set; } + + List buttons { get { return m_ToolsMenuUI.buttons; } } + + public bool alternateMenuVisible { set { m_ToolsMenuUI.moveToAlternatePosition = value; } } + + public Action highlightSingleButton { get; set; } + public Action selectHighlightedButton { get; set; } + public Action setButtonForType { get; set; } + public Action deleteToolsMenuButton { get; set; } + public Node node { get; set; } + public IToolsMenuButton PreviewToolsMenuButton { get; private set; } + public Transform alternateMenuOrigin { get; set; } + public SpatialScrollModule.SpatialScrollData spatialScrollData { get; set; } + + public ActionMap actionMap { get { return m_ActionMap; } } + public bool ignoreLocking { get { return false; } } + + public Transform rayOrigin { get; set; } + + public bool mainMenuActivatorInteractable + { + set { PreviewToolsMenuButton.interactable = value; } + } + + void Awake() + { + setButtonForType = CreateToolsMenuButton; + deleteToolsMenuButton = DeleteToolsMenuButton; + InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); + } + + void OnDestroy() + { + this.RemoveRayVisibilitySettings(rayOrigin, this); + } + + void CreateToolsMenuUI() + { + m_ToolsMenuUI = this.InstantiateUI(m_ToolsMenuPrefab.gameObject, rayOrigin, true, rayOrigin).GetComponent(); + m_ToolsMenuUI.maxButtonCount = k_MaxButtonCount; + m_ToolsMenuUI.mainMenuActivatorSelected = this.MainMenuActivatorSelected; + m_ToolsMenuUI.buttonHovered += OnButtonHover; + m_ToolsMenuUI.buttonClicked += OnButtonClick; + m_ToolsMenuUI.buttonSelected += OnButtonSelected; + m_ToolsMenuUI.closeMenu += CloseMenu; + + // Alternate menu origin isn't set when awake or start run + var toolsMenuUITransform = m_ToolsMenuUI.transform; + toolsMenuUITransform.SetParent(alternateMenuOrigin); + toolsMenuUITransform.localPosition = Vector3.zero; + toolsMenuUITransform.localRotation = Quaternion.identity; + } + + void CreateToolsMenuButton(Type toolType, Sprite buttonIcon) + { + // Verify first that the ToolsMenuUI exists + // This is called in EditorVR.Tools before the UI can be created herein in Awake + // The SelectionTool & MainMenu buttons are created immediately after instantiating the ToolsMenu + if (m_ToolsMenuUI == null) + CreateToolsMenuUI(); + + // Select an existing ToolButton if the type is already present in a button + if (buttons.Any(x => x.toolType == toolType)) + { + m_ToolsMenuUI.SelectExistingToolType(toolType); + return; + } + + if (buttons.Count >= k_MaxButtonCount) // Return if tool type already occupies a tool button + return; + + var buttonTransform = ObjectUtils.Instantiate(_mToolsMenuButtonTemplate.gameObject, m_ToolsMenuUI.buttonContainer, false).transform; + var button = buttonTransform.GetComponent(); + this.ConnectInterfaces(button); + + button.rayOrigin = rayOrigin; + button.toolType = toolType; // Assign Tool Type before assigning order + button.icon = toolType != typeof(IMainMenu) ? buttonIcon : m_MainMenuIcon; + button.highlightSingleButton = highlightSingleButton; + button.selectHighlightedButton = selectHighlightedButton; + button.rayOrigin = rayOrigin; + + if (toolType == typeof(IMainMenu)) + PreviewToolsMenuButton = button; + + m_ToolsMenuUI.AddButton(button, buttonTransform); + } + + void DeleteToolsMenuButton(Type toolTypeToDelete, Type toolTypeToSelectAfterDelete) + { + if (m_ToolsMenuUI.DeleteButtonOfType(toolTypeToDelete)) + m_ToolsMenuUI.SelectNextExistingToolButton(); + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + var buttonCount = buttons.Count; + if (buttonCount <= k_ActiveToolOrderPosition + 1) + return; + + const float kAllowToggleDuration = 0.25f; + + var toolslMenuInput = (ToolsMenuInput)input; + + if (spatialScrollData != null && toolslMenuInput.cancel.wasJustPressed) + { + consumeControl(toolslMenuInput.cancel); + consumeControl(toolslMenuInput.show); + consumeControl(toolslMenuInput.select); + OnButtonClick(); + CloseMenu(); // Also ends spatial scroll + m_ToolsMenuUI.allButtonsVisible = false; + } + + if (toolslMenuInput.show.wasJustPressed) + ShowScrollFeedback(); + + if (toolslMenuInput.show.wasJustReleased) + HideScrollFeedback(); + + if (spatialScrollData == null && (toolslMenuInput.show.wasJustPressed || toolslMenuInput.show.isHeld) && toolslMenuInput.select.wasJustPressed) + { + m_SpatialScrollStartPosition = alternateMenuOrigin.position; + m_AllowToolToggleBeforeThisTime = Time.realtimeSinceStartup + kAllowToggleDuration; + this.SetSpatialHintControlNode(node); + m_ToolsMenuUI.spatiallyScrolling = true; // Triggers the display of the directional hint arrows + consumeControl(toolslMenuInput.show); + consumeControl(toolslMenuInput.select); + + // Assign initial SpatialScrollData; begin scroll + spatialScrollData = this.PerformSpatialScroll(node, m_SpatialScrollStartPosition, alternateMenuOrigin.position, 0.325f, m_ToolsMenuUI.buttons.Count, m_ToolsMenuUI.maxButtonCount); + + HideScrollFeedback(); + ShowMenuFeedback(); + } + else if (spatialScrollData != null && toolslMenuInput.show.isHeld) + { + consumeControl(toolslMenuInput.show); + consumeControl(toolslMenuInput.select); + + // Attempt to close a button, if a scroll has passed the trigger threshold + if (spatialScrollData != null && toolslMenuInput.select.wasJustPressed) + { + if (m_ToolsMenuUI.DeleteHighlightedButton()) + buttonCount = buttons.Count; // The MainMenu button will be hidden, subtract 1 from the activeButtonCount + + if (buttonCount <= k_ActiveToolOrderPosition + 1) + { + if (spatialScrollData != null) + this.EndSpatialScroll(); + + return; + } + } + + // normalized input should loop after reaching the 0.15f length + buttonCount -= 1; // Decrement to disallow cycling through the main menu button + spatialScrollData = this.PerformSpatialScroll(node, m_SpatialScrollStartPosition, alternateMenuOrigin.position, 0.325f, m_ToolsMenuUI.buttons.Count, m_ToolsMenuUI.maxButtonCount); + var normalizedRepeatingPosition = spatialScrollData.normalizedLoopingPosition; + if (!Mathf.Approximately(normalizedRepeatingPosition, 0f)) + { + if (!m_ToolsMenuUI.allButtonsVisible) + { + m_ToolsMenuUI.spatialDragDistance = spatialScrollData.dragDistance; + this.SetSpatialHintState(SpatialHintModule.SpatialHintStateFlags.CenteredScrolling); + m_ToolsMenuUI.allButtonsVisible = true; + } + else if (spatialScrollData.spatialDirection != null) + { + m_ToolsMenuUI.startingDragOrigin = spatialScrollData.spatialDirection; + } + + m_ToolsMenuUI.HighlightSingleButtonWithoutMenu((int)(buttonCount * normalizedRepeatingPosition) + 1); + } + } + else if (spatialScrollData != null && !toolslMenuInput.show.isHeld && !toolslMenuInput.select.isHeld) + { + consumeControl(toolslMenuInput.show); + consumeControl(toolslMenuInput.select); + + if (spatialScrollData != null && spatialScrollData.passedMinDragActivationThreshold) + { + m_ToolsMenuUI.SelectHighlightedButton(); + } + else if (Time.realtimeSinceStartup < m_AllowToolToggleBeforeThisTime) + { + // Allow for single press+release to cycle through tools + m_ToolsMenuUI.SelectNextExistingToolButton(); + OnButtonClick(); + } + + CloseMenu(); + } + } + + void OnButtonClick() + { + this.Pulse(node, m_ButtonClickPulse); + this.SetSpatialHintState(SpatialHintModule.SpatialHintStateFlags.Hidden); + } + + void OnButtonHover() + { + this.Pulse(node, m_ButtonHoverPulse); + } + + void OnButtonSelected(Transform rayOrigin, Type buttonType) + { + this.SelectTool(rayOrigin, buttonType, false); + } + + void CloseMenu() + { + this.ClearFeedbackRequests(); + this.Pulse(node, m_HidingPulse); + this.EndSpatialScroll(); // Free the spatial scroll data owned by this object + } + + void ShowFeedback(List requests, string controlName, string tooltipText = null) + { + if (tooltipText == null) + tooltipText = controlName; + + List ids; + if (m_Controls.TryGetValue(controlName, out ids)) + { + foreach (var id in ids) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.priority = 1; + request.tooltipText = tooltipText; + requests.Add(request); + this.AddFeedbackRequest(request); + } + } + } + + void ShowScrollFeedback() + { + ShowFeedback(m_ScrollFeedback, "select", "Scroll to Change Tool"); + } + + void ShowMenuFeedback() + { + ShowFeedback(m_MenuFeedback, "select", "Remove Tool"); + ShowFeedback(m_MenuFeedback, "cancel", "Cancel Scrolling"); + ShowFeedback(m_MenuFeedback, "show", "Release to Select Tool"); + } + + void HideFeedback(List requests) + { + foreach (var request in requests) + { + this.RemoveFeedbackRequest(request); + } + requests.Clear(); + } + + void HideScrollFeedback() + { + HideFeedback(m_ScrollFeedback); + } + } +} +#endif diff --git a/Models/Vive/Materials/ViveController.mat b/Models/Vive/Materials/ViveController.mat index df8727dc9..d1e045a5a 100644 --- a/Models/Vive/Materials/ViveController.mat +++ b/Models/Vive/Materials/ViveController.mat @@ -12,7 +12,7 @@ Material: m_LightmapFlags: 4 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 + m_CustomRenderQueue: 3000 stringTagMap: RenderType: Transparent disabledShaderPasses: [] @@ -75,7 +75,7 @@ Material: - _SpecularHighlights: 1 - _SrcBlend: 5 - _UVSec: 0 - - _ZWrite: 1 + - _ZWrite: 0 m_Colors: - _Color: {r: 1, g: 1, b: 1, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Models/Vive/Models/body.mtl b/Models/Vive/Models/body.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/body.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/body.obj.meta b/Models/Vive/Models/body.obj.meta index 9a58639ef..d3d2b2288 100644 --- a/Models/Vive/Models/body.obj.meta +++ b/Models/Vive/Models/body.obj.meta @@ -3,7 +3,7 @@ guid: 91923fcf53844be47a1ad1b01dc5b4d5 timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: body_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: body_group1 3300000: body_group1 4300000: body_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/button.mtl b/Models/Vive/Models/button.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/button.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/button.obj.meta b/Models/Vive/Models/button.obj.meta index f34aa26f3..77c391987 100644 --- a/Models/Vive/Models/button.obj.meta +++ b/Models/Vive/Models/button.obj.meta @@ -3,7 +3,7 @@ guid: cbd31b89c0bde684db82ff8056d3cc8e timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: menu_but_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: menu_but_group1 3300000: menu_but_group1 4300000: menu_but_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/l_grip.mtl b/Models/Vive/Models/l_grip.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/l_grip.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/l_grip.obj.meta b/Models/Vive/Models/l_grip.obj.meta index 577b7c1d5..924fe0a05 100644 --- a/Models/Vive/Models/l_grip.obj.meta +++ b/Models/Vive/Models/l_grip.obj.meta @@ -3,7 +3,7 @@ guid: b32f6f3f786b1b8449a3494a98f2b6b2 timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: l_gripper_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: l_gripper_group1 3300000: l_gripper_group1 4300000: l_gripper_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/led.mtl b/Models/Vive/Models/led.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/led.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/led.obj.meta b/Models/Vive/Models/led.obj.meta index e134296c1..1c93949a5 100644 --- a/Models/Vive/Models/led.obj.meta +++ b/Models/Vive/Models/led.obj.meta @@ -3,7 +3,7 @@ guid: 76a8658f8856237409616e713d02cd80 timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: LED_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: LED_group1 3300000: LED_group1 4300000: LED_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/r_grip.mtl b/Models/Vive/Models/r_grip.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/r_grip.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/r_grip.mtl.meta b/Models/Vive/Models/r_grip.mtl.meta deleted file mode 100644 index ae8bf5114..000000000 --- a/Models/Vive/Models/r_grip.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a0f36f63db2126d408275047b6da8d3c -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/r_grip.obj.meta b/Models/Vive/Models/r_grip.obj.meta index a5b63bc36..3b855c8c0 100644 --- a/Models/Vive/Models/r_grip.obj.meta +++ b/Models/Vive/Models/r_grip.obj.meta @@ -3,7 +3,7 @@ guid: 56f79c509c890b74e906e8a5caee40ae timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: r_gripper_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: r_gripper_group1 3300000: r_gripper_group1 4300000: r_gripper_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/scroll_wheel.mtl b/Models/Vive/Models/scroll_wheel.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/scroll_wheel.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/scroll_wheel.mtl.meta b/Models/Vive/Models/scroll_wheel.mtl.meta deleted file mode 100644 index 25a6657d1..000000000 --- a/Models/Vive/Models/scroll_wheel.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0c32eae4586d18f4f967987138bee9fe -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/scroll_wheel.obj.meta b/Models/Vive/Models/scroll_wheel.obj.meta index 3a3b59ac3..7bd1d2a0c 100644 --- a/Models/Vive/Models/scroll_wheel.obj.meta +++ b/Models/Vive/Models/scroll_wheel.obj.meta @@ -3,7 +3,7 @@ guid: 0470cc75e5d4adc4ea095278a47a03b4 timeCreated: 1507075389 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: scroll_wheel_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: scroll_wheel_group1 3300000: scroll_wheel_group1 4300000: scroll_wheel_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/status.mtl b/Models/Vive/Models/status.mtl deleted file mode 100644 index a4ff1f153..000000000 --- a/Models/Vive/Models/status.mtl +++ /dev/null @@ -1,9 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd status.png -Ni 1.00 -newmtl lambert4SG - diff --git a/Models/Vive/Models/status.mtl.meta b/Models/Vive/Models/status.mtl.meta deleted file mode 100644 index aea121834..000000000 --- a/Models/Vive/Models/status.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: df66281bcb5dc5048b756f26b3497de1 -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/status.obj.meta b/Models/Vive/Models/status.obj.meta index fea8bd553..6d50ba778 100644 --- a/Models/Vive/Models/status.obj.meta +++ b/Models/Vive/Models/status.obj.meta @@ -3,7 +3,7 @@ guid: 4be9d36f561eb7c4baf693cb4a3afac0 timeCreated: 1507075389 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: status_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: status_group1 3300000: status_group1 4300000: status_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: initialShadingGroup + second: {fileID: 2100000, guid: 382a130523b88ba4fb85bf066031e25c, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/sys_button.mtl b/Models/Vive/Models/sys_button.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/sys_button.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/sys_button.mtl.meta b/Models/Vive/Models/sys_button.mtl.meta deleted file mode 100644 index 5f64fe41c..000000000 --- a/Models/Vive/Models/sys_button.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9ceb230d2af4588408c5af49aa715713 -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/sys_button.obj.meta b/Models/Vive/Models/sys_button.obj.meta index 5e3be2e4d..2f7dc2ba7 100644 --- a/Models/Vive/Models/sys_button.obj.meta +++ b/Models/Vive/Models/sys_button.obj.meta @@ -3,7 +3,7 @@ guid: a522de35d424c4547bce18694eac5aea timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: sys_but_group1 100002: //RootNode @@ -12,10 +12,17 @@ ModelImporter: 2300000: sys_but_group1 3300000: sys_but_group1 4300000: sys_but_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/trackpad.mtl b/Models/Vive/Models/trackpad.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/trackpad.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/trackpad.mtl.meta b/Models/Vive/Models/trackpad.mtl.meta deleted file mode 100644 index f00b5a19e..000000000 --- a/Models/Vive/Models/trackpad.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: db4994de10138db49bd9d2b21a814120 -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/trackpad.obj.meta b/Models/Vive/Models/trackpad.obj.meta index 4701e9c6c..f589b767a 100644 --- a/Models/Vive/Models/trackpad.obj.meta +++ b/Models/Vive/Models/trackpad.obj.meta @@ -3,7 +3,7 @@ guid: 1eb55c31fec770a4d97118edb282d8c8 timeCreated: 1507075389 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: trackpad_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: trackpad_group1 3300000: trackpad_group1 4300000: trackpad_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/trackpad_scroll_cut.mtl b/Models/Vive/Models/trackpad_scroll_cut.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/trackpad_scroll_cut.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/trackpad_scroll_cut.mtl.meta b/Models/Vive/Models/trackpad_scroll_cut.mtl.meta deleted file mode 100644 index 68eb4de82..000000000 --- a/Models/Vive/Models/trackpad_scroll_cut.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ba1f24fecc5ff924da77dc464c5a1fbb -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/trackpad_scroll_cut.obj.meta b/Models/Vive/Models/trackpad_scroll_cut.obj.meta index f2a85f0f0..85221cc3d 100644 --- a/Models/Vive/Models/trackpad_scroll_cut.obj.meta +++ b/Models/Vive/Models/trackpad_scroll_cut.obj.meta @@ -3,7 +3,7 @@ guid: 918f5dcc9e64cfa47ad3a7aa35fb70f2 timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: track_pad_scrollcut_group1 100002: //RootNode @@ -12,10 +12,17 @@ ModelImporter: 2300000: track_pad_scrollcut_group1 3300000: track_pad_scrollcut_group1 4300000: track_pad_scrollcut_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/trackpad_touch.mtl b/Models/Vive/Models/trackpad_touch.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/trackpad_touch.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/trackpad_touch.mtl.meta b/Models/Vive/Models/trackpad_touch.mtl.meta deleted file mode 100644 index bbf8f926a..000000000 --- a/Models/Vive/Models/trackpad_touch.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bb8fc38bd9541d24794cdaebcf96ac4b -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/trackpad_touch.obj.meta b/Models/Vive/Models/trackpad_touch.obj.meta index 94ab2097b..4f35780f5 100644 --- a/Models/Vive/Models/trackpad_touch.obj.meta +++ b/Models/Vive/Models/trackpad_touch.obj.meta @@ -3,7 +3,7 @@ guid: 8fca69da58fb5a44ba6d838685744c73 timeCreated: 1507075390 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: track_pip_group1 100002: //RootNode @@ -12,10 +12,17 @@ ModelImporter: 2300000: track_pip_group1 3300000: track_pip_group1 4300000: track_pip_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Models/Vive/Models/trigger.mtl b/Models/Vive/Models/trigger.mtl deleted file mode 100644 index 5a6f15abf..000000000 --- a/Models/Vive/Models/trigger.mtl +++ /dev/null @@ -1,15 +0,0 @@ -newmtl initialShadingGroup -illum 4 -Kd 0.50 0.50 0.50 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -Ni 1.00 -newmtl lambert4SG -illum 4 -Kd 0.00 0.00 0.00 -Ka 0.00 0.00 0.00 -Tf 1.00 1.00 1.00 -map_Kd onepointfive_texture.png -Ni 1.00 -Ks 0.00 0.00 0.00 -map_Ks onepointfive_spec.png diff --git a/Models/Vive/Models/trigger.mtl.meta b/Models/Vive/Models/trigger.mtl.meta deleted file mode 100644 index 31025628e..000000000 --- a/Models/Vive/Models/trigger.mtl.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4112f44848fa1544d84b5465857ce524 -timeCreated: 1507075387 -licenseType: Pro -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Models/Vive/Models/trigger.obj.meta b/Models/Vive/Models/trigger.obj.meta index 39a45e475..2f99f592c 100644 --- a/Models/Vive/Models/trigger.obj.meta +++ b/Models/Vive/Models/trigger.obj.meta @@ -3,7 +3,7 @@ guid: 11be60732cf8ba74ab65779a6c6d62f2 timeCreated: 1507075389 licenseType: Pro ModelImporter: - serializedVersion: 19 + serializedVersion: 22 fileIDToRecycleName: 100000: //RootNode 100002: trigger_group1 @@ -12,10 +12,17 @@ ModelImporter: 2300000: trigger_group1 3300000: trigger_group1 4300000: trigger_group1 + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: lambert4SG + second: {fileID: 2100000, guid: 4a51798d5e95de54488eac1b012f2607, type: 2} materials: - importMaterials: 1 + importMaterials: 0 materialName: 0 materialSearch: 1 + materialLocation: 0 animations: legacyGenerateAnimations: 4 bakeSimulation: 0 @@ -28,12 +35,14 @@ ModelImporter: animationImportWarnings: animationRetargetingWarnings: animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 animationCompression: 1 animationRotationError: 0.5 animationPositionError: 0.5 animationScaleError: 0.5 animationWrapMode: 0 extraExposedTransformPaths: [] + extraUserProperties: [] clipAnimations: [] isReadable: 1 meshes: @@ -41,7 +50,10 @@ ModelImporter: globalScale: 1 meshCompression: 0 addColliders: 0 + importVisibility: 0 importBlendShapes: 1 + importCameras: 0 + importLights: 0 swapUVChannels: 0 generateSecondaryUV: 0 useFileUnits: 1 @@ -57,6 +69,7 @@ ModelImporter: normalSmoothAngle: 60 normalImportMode: 0 tangentImportMode: 3 + normalCalculationMode: 0 importAnimation: 1 copyAvatar: 0 humanDescription: diff --git a/Prefabs/Proxies/LeftTouch.prefab b/Prefabs/Proxies/LeftTouch.prefab index 6e1aa7d69..3fff78e70 100644 --- a/Prefabs/Proxies/LeftTouch.prefab +++ b/Prefabs/Proxies/LeftTouch.prefab @@ -1566,7 +1566,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1352081654243216} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.0396, y: -0.0292, z: -0.0289} + m_LocalPosition: {x: -0.0772, y: -0.0437, z: -0.0289} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4301915322387644} @@ -1579,7 +1579,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1109432372925108} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0339, y: 0.0007, z: 0.0285} + m_LocalPosition: {x: -0.0339, y: 0.00069999904, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4168974876719622} @@ -1592,7 +1592,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1575236754355180} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.04, y: 0.0143, z: 0} + m_LocalPosition: {x: -0.0876, y: -0.0065, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4301915322387644} @@ -1623,7 +1623,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1026636374437032} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0292, y: 0.0047, z: 0.0285} + m_LocalPosition: {x: 0.0292, y: 0.004699999, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4168974876719622} @@ -1636,7 +1636,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1800859972846318} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0301, y: -0.0124, z: 0.0147} + m_LocalPosition: {x: -0.0339, y: -0.0124, z: 0.005} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4168974876719622} @@ -1649,7 +1649,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1106541392480628} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0088, z: 0.0359} + m_LocalPosition: {x: -9.552226e-19, y: 0.008799999, z: 0.06359998} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4220023546949684} @@ -1662,7 +1662,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1618643921889922} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: 0, y: 0.06, z: 0.015} + m_LocalPosition: {x: -0.005, y: 0.0944, z: 0.015} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4301915322387644} @@ -1675,7 +1675,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1559818264756724} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0, y: 0.0301, z: 0.05} + m_LocalPosition: {x: -0, y: 0.0301, z: 0.0595} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4168974876719622} @@ -1688,7 +1688,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1347184759783470} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: -0, y: -0.0225, z: 0.02} + m_LocalPosition: {x: -0, y: -0.0225, z: 0.0382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4220023546949684} @@ -1701,7 +1701,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1865368733839716} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: 0.0367, y: 0.0048, z: 0.0203} + m_LocalPosition: {x: 0.0867, y: 0.0204, z: 0.0286} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4301915322387644} @@ -1714,7 +1714,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1853512583863796} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.04, y: -0.0074, z: 0} + m_LocalPosition: {x: -0.0841, y: -0.025, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4301915322387644} @@ -1740,7 +1740,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1103856973924540} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0209, z: 0.02} + m_LocalPosition: {x: 0, y: 0.020899996, z: 0.038199976} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4220023546949684} diff --git a/Prefabs/Proxies/LeftTouchOpenVR.prefab b/Prefabs/Proxies/LeftTouchOpenVR.prefab index 1de4a76ed..0cfd0fee5 100644 --- a/Prefabs/Proxies/LeftTouchOpenVR.prefab +++ b/Prefabs/Proxies/LeftTouchOpenVR.prefab @@ -767,7 +767,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1687655920288898} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.0396, y: -0.0292, z: -0.0289} + m_LocalPosition: {x: -0.0772, y: -0.0437, z: -0.0289} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4287670221377860} @@ -845,7 +845,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1137710370616554} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0301, y: -0.0124, z: 0.0147} + m_LocalPosition: {x: -0.0339, y: -0.0124, z: 0.005} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4378134475513972} @@ -858,7 +858,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1614691614439212} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0292, y: 0.0047, z: 0.0285} + m_LocalPosition: {x: 0.0292, y: 0.004699999, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4378134475513972} @@ -1000,7 +1000,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1231199047469498} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0, y: 0.0301, z: 0.05} + m_LocalPosition: {x: -0, y: 0.0301, z: 0.0595} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4378134475513972} @@ -1027,7 +1027,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1455514600189430} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0088, z: 0.0359} + m_LocalPosition: {x: -9.552226e-19, y: 0.008799999, z: 0.06359998} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4534451313242526} @@ -1066,7 +1066,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1607563885409028} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.04, y: -0.0074, z: 0} + m_LocalPosition: {x: -0.0841, y: -0.025, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4287670221377860} @@ -1178,7 +1178,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1405430302077892} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0339, y: 0.0007, z: 0.0285} + m_LocalPosition: {x: -0.0339, y: 0.00069999904, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4378134475513972} @@ -1204,7 +1204,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1495733347613644} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0209, z: 0.02} + m_LocalPosition: {x: 0, y: 0.020899996, z: 0.038199976} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4534451313242526} @@ -1259,7 +1259,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1221307289850582} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: 0.0367, y: 0.0048, z: 0.0203} + m_LocalPosition: {x: 0.0867, y: 0.0204, z: 0.0286} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4287670221377860} @@ -1272,7 +1272,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1974733396555132} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: -0, y: -0.0225, z: 0.02} + m_LocalPosition: {x: -0, y: -0.0225, z: 0.0382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4534451313242526} @@ -1311,7 +1311,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1529948422914310} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: 0, y: 0.06, z: 0.015} + m_LocalPosition: {x: -0.005, y: 0.0944, z: 0.015} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4287670221377860} @@ -1358,7 +1358,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1371879058933120} m_LocalRotation: {x: -0.06975647, y: 0.9975641, z: -0, w: 0} - m_LocalPosition: {x: -0.04, y: 0.0143, z: 0} + m_LocalPosition: {x: -0.0876, y: -0.0065, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4287670221377860} diff --git a/Prefabs/Proxies/RightTouch.prefab b/Prefabs/Proxies/RightTouch.prefab index b62e5e916..e2e81a56a 100644 --- a/Prefabs/Proxies/RightTouch.prefab +++ b/Prefabs/Proxies/RightTouch.prefab @@ -334,7 +334,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 141214} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: -0.775, z: 0} + m_LocalPosition: {x: 0.1301, y: -0.775, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - {fileID: 484770} @@ -1474,7 +1474,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1119280824263610} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0088, z: 0.0359} + m_LocalPosition: {x: -0, y: 0.0088, z: 0.0636} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4565487885698820} @@ -1500,7 +1500,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1247061116493002} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.04, y: -0.0074, z: 0} + m_LocalPosition: {x: 0.0841, y: -0.0254, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4770157981233164} @@ -1512,13 +1512,13 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1370272309804156} - m_LocalRotation: {x: 0.5, y: -0.5, z: -0.5, w: 0.5} - m_LocalPosition: {x: -0, y: -0.0225, z: 0.02} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} + m_LocalPosition: {x: -0, y: -0.0225, z: 0.0382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4565487885698820} m_RootOrder: 5 - m_LocalEulerAnglesHint: {x: 0, y: -90, z: -90} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 90} --- !u!4 &4452259222587156 Transform: m_ObjectHideFlags: 1 @@ -1526,7 +1526,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1379410660592782} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0301, y: -0.0124, z: 0.0147} + m_LocalPosition: {x: 0.0339, y: -0.0124, z: 0.005} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4626264276201916} @@ -1538,13 +1538,13 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1527866904692174} - m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0, y: 0.06, z: 0.015} + m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: -0.000000013062143, w: -0.00000018679738} + m_LocalPosition: {x: 0.0077, y: 0.0941, z: 0.015} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4770157981233164} m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 180, z: 8} + m_LocalEulerAnglesHint: {x: 0, y: 180.00002, z: 8} --- !u!4 &4496493134172762 Transform: m_ObjectHideFlags: 1 @@ -1552,7 +1552,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1922651742282288} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.0396, y: -0.0292, z: -0.0289} + m_LocalPosition: {x: 0.0767, y: -0.0451, z: -0.0289} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4770157981233164} @@ -1565,7 +1565,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1051482740643952} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.04, y: 0.0143, z: 0} + m_LocalPosition: {x: 0.0879, y: -0.0067, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4770157981233164} @@ -1578,7 +1578,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1529540797198496} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0, y: 0.0301, z: 0.05} + m_LocalPosition: {x: -0, y: 0.0301, z: 0.0595} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4626264276201916} @@ -1641,13 +1641,13 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1021843426612402} - m_LocalRotation: {x: 0.5, y: -0.5, z: -0.5, w: 0.5} - m_LocalPosition: {x: -4.9785933e-23, y: 0.0209, z: 0.01999998} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.020899996, z: 0.038199976} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4565487885698820} m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 0, y: -90, z: -90} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 90} --- !u!4 &4703955814576790 Transform: m_ObjectHideFlags: 1 @@ -1655,7 +1655,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1736852069742372} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0339, y: 0.0007, z: 0.0285} + m_LocalPosition: {x: 0.0339, y: 0.00069999904, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4626264276201916} @@ -1681,7 +1681,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1929895129918990} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: -0.0367, y: 0.0048, z: 0.0203} + m_LocalPosition: {x: -0.0856, y: 0.0183, z: 0.0203} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4770157981233164} @@ -1738,7 +1738,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1352703442349410} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0292, y: 0.0047, z: 0.0285} + m_LocalPosition: {x: -0.0292, y: 0.004699999, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4626264276201916} @@ -1944,7 +1944,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_TooltipTarget: {fileID: 0} m_TooltipSource: {fileID: 437054} - m_TooltipAlignment: 2 + m_TooltipAlignment: 0 m_FacingDirection: 12 --- !u!114 &114382005819407472 MonoBehaviour: @@ -2046,7 +2046,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_TooltipTarget: {fileID: 0} m_TooltipSource: {fileID: 412818} - m_TooltipAlignment: 0 + m_TooltipAlignment: 2 m_FacingDirection: 12 --- !u!114 &114526162600788140 MonoBehaviour: diff --git a/Prefabs/Proxies/RightTouchOpenVR.prefab b/Prefabs/Proxies/RightTouchOpenVR.prefab index 8d20efa5e..2f0031234 100644 --- a/Prefabs/Proxies/RightTouchOpenVR.prefab +++ b/Prefabs/Proxies/RightTouchOpenVR.prefab @@ -765,7 +765,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1544585890443730} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: -0.0367, y: 0.0048, z: 0.0203} + m_LocalPosition: {x: -0.0856, y: 0.0183, z: 0.0203} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4024085169846182} @@ -808,8 +808,8 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1544558391918520} - m_LocalRotation: {x: 0.5, y: -0.5, z: -0.5, w: 0.5} - m_LocalPosition: {x: -0, y: -0.0225, z: 0.02} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} + m_LocalPosition: {x: -0, y: -0.0225, z: 0.0382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4820048965396724} @@ -834,8 +834,8 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1859334382155604} - m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0, y: 0.06, z: 0.015} + m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: -0.000000013062143, w: -0.00000018679738} + m_LocalPosition: {x: 0.0077, y: 0.0941, z: 0.015} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4024085169846182} @@ -860,8 +860,8 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1236516356898100} - m_LocalRotation: {x: 0.5, y: -0.5, z: -0.5, w: 0.5} - m_LocalPosition: {x: -4.9785933e-23, y: 0.0209, z: 0.01999998} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} + m_LocalPosition: {x: 0, y: 0.020899996, z: 0.038199976} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4820048965396724} @@ -887,7 +887,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1186264849566554} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.04, y: -0.0074, z: 0} + m_LocalPosition: {x: 0.0841, y: -0.0254, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4024085169846182} @@ -913,7 +913,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1747390268308380} m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0.0088, z: 0.0359} + m_LocalPosition: {x: -0, y: 0.0088, z: 0.0636} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4820048965396724} @@ -1023,7 +1023,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1431128304040176} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.0396, y: -0.0292, z: -0.0289} + m_LocalPosition: {x: 0.0767, y: -0.0451, z: -0.0289} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4024085169846182} @@ -1070,7 +1070,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1056099179106798} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0, y: 0.0301, z: 0.05} + m_LocalPosition: {x: -0, y: 0.0301, z: 0.0595} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4488417919114820} @@ -1127,7 +1127,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1700608085783986} m_LocalRotation: {x: 0.06975647, y: 0.9975641, z: 0, w: 0} - m_LocalPosition: {x: 0.04, y: 0.0143, z: 0} + m_LocalPosition: {x: 0.0879, y: -0.0067, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4024085169846182} @@ -1168,7 +1168,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1609220482806210} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0339, y: 0.0007, z: 0.0285} + m_LocalPosition: {x: 0.0339, y: 0.00069999904, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4488417919114820} @@ -1228,7 +1228,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1049085034074666} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: -0.0292, y: 0.0047, z: 0.0285} + m_LocalPosition: {x: -0.0292, y: 0.004699999, z: 0.03799997} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4488417919114820} @@ -1254,7 +1254,7 @@ Transform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1264255518176884} - m_LocalRotation: {x: -0, y: -0, z: -2.3283064e-10, w: 1} + m_LocalRotation: {x: -0, y: -0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: @@ -1305,7 +1305,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1885192281175252} m_LocalRotation: {x: 0, y: 0.7071068, z: 0.7071068, w: 0} - m_LocalPosition: {x: 0.0301, y: -0.0124, z: 0.0147} + m_LocalPosition: {x: 0.0339, y: -0.0124, z: 0.005} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4488417919114820} @@ -1740,7 +1740,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_TooltipTarget: {fileID: 0} m_TooltipSource: {fileID: 4221126147080902} - m_TooltipAlignment: 0 + m_TooltipAlignment: 2 m_FacingDirection: 12 --- !u!114 &114496970830405662 MonoBehaviour: @@ -1943,7 +1943,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_TooltipTarget: {fileID: 0} m_TooltipSource: {fileID: 4022345611153456} - m_TooltipAlignment: 2 + m_TooltipAlignment: 0 m_FacingDirection: 12 --- !u!136 &136497482760722588 CapsuleCollider: diff --git a/Prefabs/Proxies/ViveController.prefab b/Prefabs/Proxies/ViveController.prefab index 52425e762..29eab1de4 100644 --- a/Prefabs/Proxies/ViveController.prefab +++ b/Prefabs/Proxies/ViveController.prefab @@ -928,7 +928,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1225174784619462} m_LocalRotation: {x: 0, y: 0.8762647, z: -0.4818301, w: 0} - m_LocalPosition: {x: 0.0425, y: 0.0026, z: 0.0999} + m_LocalPosition: {x: 0.0778, y: 0.0026, z: 0.0999} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -941,7 +941,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1547906465118038} m_LocalRotation: {x: -0, y: 0.2789073, z: -0.960318, w: 0} - m_LocalPosition: {x: 0.0495, y: 0.0187, z: 0.0012} + m_LocalPosition: {x: 0.0738, y: 0.0187, z: 0.0012} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -980,7 +980,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1690274936479956} m_LocalRotation: {x: -0, y: 0.8762647, z: -0.48183012, w: 0} - m_LocalPosition: {x: -0.04879999, y: 0.010199993, z: 0.0063000116} + m_LocalPosition: {x: -0.0793, y: 0.010199993, z: 0.0063000116} m_LocalScale: {x: 1, y: 1, z: 1.0000001} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1020,7 +1020,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1975974212585692} m_LocalRotation: {x: 0, y: 0.8762647, z: -0.4818301, w: 0} - m_LocalPosition: {x: 0.0488, y: 0.0102, z: 0.0062999995} + m_LocalPosition: {x: 0.0791, y: 0.0102, z: 0.0062999995} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1046,7 +1046,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1299922452772042} m_LocalRotation: {x: -0, y: 0.27890733, z: -0.9603181, w: 0} - m_LocalPosition: {x: 0.042499993, y: 0.011599995, z: 0.10210002} + m_LocalPosition: {x: 0.0718, y: 0.011599995, z: 0.10210002} m_LocalScale: {x: 1, y: 1.0000005, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1059,7 +1059,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1684975939010892} m_LocalRotation: {x: 0, y: 0.8762647, z: -0.4818301, w: 0} - m_LocalPosition: {x: 0.0449, y: 0.0059, z: 0.0657} + m_LocalPosition: {x: 0.0877, y: 0.0059, z: 0.0657} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1072,7 +1072,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1057360148245394} m_LocalRotation: {x: 0, y: 0.2789073, z: -0.9603181, w: 0} - m_LocalPosition: {x: -0.047, y: -0.0125, z: 0.0503} + m_LocalPosition: {x: -0.0872, y: -0.0125, z: 0.0503} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1211,7 +1211,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1112519066469124} m_LocalRotation: {x: -0, y: 0.8762647, z: -0.48183012, w: 0} - m_LocalPosition: {x: -0.04699999, y: 0.007299993, z: 0.03500002} + m_LocalPosition: {x: -0.0876, y: 0.007299993, z: 0.03500002} m_LocalScale: {x: 1, y: 1, z: 1.0000001} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1238,7 +1238,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1947939447631840} m_LocalRotation: {x: -0, y: 0.27890733, z: -0.9603181, w: 0} - m_LocalPosition: {x: -0.04950001, y: 0.018699987, z: 0.0012000217} + m_LocalPosition: {x: -0.0727, y: 0.018699987, z: 0.0012000217} m_LocalScale: {x: 1, y: 1.0000005, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1251,7 +1251,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1782288131876036} m_LocalRotation: {x: -0, y: 0.8762647, z: -0.48183012, w: 0} - m_LocalPosition: {x: -0.04249999, y: 0.0025999844, z: 0.09990003} + m_LocalPosition: {x: -0.0763, y: 0.0025999844, z: 0.09990003} m_LocalScale: {x: 1, y: 1, z: 1.0000001} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1277,7 +1277,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1537308548188052} m_LocalRotation: {x: -0, y: 0.2789073, z: -0.960318, w: 0} - m_LocalPosition: {x: -0.042500004, y: 0.011600018, z: 0.102110185} + m_LocalPosition: {x: -0.0735, y: 0.011600018, z: 0.102110185} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1290,7 +1290,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1185558813916894} m_LocalRotation: {x: -0, y: 0.27890733, z: -0.9603181, w: 0} - m_LocalPosition: {x: -0.0449, y: 0.04039999, z: 0.056800015} + m_LocalPosition: {x: -0.0875, y: 0.04039999, z: 0.056800015} m_LocalScale: {x: 1, y: 1.0000005, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1303,7 +1303,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1639276185918900} m_LocalRotation: {x: -0, y: 0.8762647, z: -0.48183012, w: 0} - m_LocalPosition: {x: -0.0449, y: 0.0058999956, z: 0.06570001} + m_LocalPosition: {x: -0.088, y: 0.0058999956, z: 0.06570001} m_LocalScale: {x: 1, y: 1, z: 1.0000001} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1329,7 +1329,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1605934862968814} m_LocalRotation: {x: -0, y: 0.27890733, z: -0.9603181, w: 0} - m_LocalPosition: {x: 0.04699999, y: -0.012500018, z: 0.050300024} + m_LocalPosition: {x: 0.0878, y: -0.012500018, z: 0.050300024} m_LocalScale: {x: 1, y: 1.0000005, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} @@ -1355,7 +1355,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1727178761897516} m_LocalRotation: {x: 0, y: 0.8762647, z: -0.4818301, w: 0} - m_LocalPosition: {x: 0.047, y: 0.0073, z: 0.035} + m_LocalPosition: {x: 0.0877, y: 0.0073, z: 0.035} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4035010716147694} @@ -1368,7 +1368,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1238159370474176} m_LocalRotation: {x: 0, y: 0.2789073, z: -0.9603181, w: 0} - m_LocalPosition: {x: 0.0449, y: 0.0404, z: 0.0568} + m_LocalPosition: {x: 0.0885, y: 0.0404, z: 0.0568} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4449357101051952} diff --git a/Scripts/Core/EditorVR.Menus.cs b/Scripts/Core/EditorVR.Menus.cs index a20671723..664302b5b 100644 --- a/Scripts/Core/EditorVR.Menus.cs +++ b/Scripts/Core/EditorVR.Menus.cs @@ -179,6 +179,14 @@ internal void UpdateMenuVisibilities() k_ActiveDeviceData.Clear(); Rays.ForEachProxyDevice(deviceData => { k_ActiveDeviceData.Add(deviceData); }); + foreach (var deviceData in k_ActiveDeviceData) + { + foreach (var kvp in deviceData.menuHideData) + { + kvp.Value.hideFlags &= ~MenuHideFlags.Temporary; + } + } + foreach (var deviceData in k_ActiveDeviceData) { var alternateMenu = deviceData.alternateMenu; @@ -287,15 +295,6 @@ internal void UpdateMenuVisibilities() Rays.UpdateRayForDevice(deviceData, deviceData.rayOrigin); } - // Reset Temporary states and set lastHideFlags - foreach (var deviceData in k_ActiveDeviceData) - { - foreach (var kvp in deviceData.menuHideData) - { - kvp.Value.hideFlags &= ~MenuHideFlags.Temporary; - } - } - evr.GetModule().UpdatePlayerHandleMaps(); } @@ -421,7 +420,7 @@ internal static bool IsValidHover(MultipleRayInputModule.RaycastSource source) return true; } - return (menuHideFlags[openMenu].hideFlags & MenuHideFlags.Hidden) != 0; + return menuHideFlags[openMenu].hideFlags != 0; } return true; diff --git a/Scripts/Core/EditorVR.MiniWorlds.cs b/Scripts/Core/EditorVR.MiniWorlds.cs index 0059f8ea3..4d53efbcd 100644 --- a/Scripts/Core/EditorVR.MiniWorlds.cs +++ b/Scripts/Core/EditorVR.MiniWorlds.cs @@ -1,647 +1,648 @@ -#if UNITY_EDITOR && UNITY_2017_2_OR_NEWER -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEditor.Experimental.EditorVR.Workspaces; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Core -{ - partial class EditorVR - { - class MiniWorlds : Nested, ILateBindInterfaceMethods, IPlaceSceneObjects, IUsesViewerScale, - IUsesSpatialHash - { - internal class MiniWorldRay - { - readonly List m_GrabData = new List(); - - public Transform originalRayOrigin { get; private set; } - public IMiniWorld miniWorld { get; private set; } - public IProxy proxy { get; private set; } - public Node node { get; private set; } - public IntersectionTester tester { get; private set; } - - public bool hasPreview { get; private set; } - - public bool hasObjects - { - get { return m_GrabData.Count > 0; } - } - - public bool dragStartedOutside { get; set; } - public bool isContained { get; set; } - - class GrabData - { - Vector3 m_OriginalLocalPositionOffset; - Vector3 m_LocalPositionOffset; - Quaternion m_RotationOffset; - - public Vector3 centerPositionOffset { get; private set; } - public Quaternion originalRotation { get; private set; } - public Vector3 originalScale { get; private set; } - - public Transform transform { get; private set; } - - public GrabData(Transform transform, Transform parent, Vector3 center) - { - this.transform = transform; - centerPositionOffset = transform.position - center; - originalRotation = transform.rotation; - originalScale = transform.localScale; - GetCurrentOffsets(parent); - } - - public void GetCurrentOffsets(Transform parent) - { - MathUtilsExt.GetTransformOffset(parent, transform, out m_LocalPositionOffset, out m_RotationOffset); - m_OriginalLocalPositionOffset = m_LocalPositionOffset; - } - - public void SetScale(float scaleFactor) - { - transform.localScale *= scaleFactor; - m_LocalPositionOffset = m_OriginalLocalPositionOffset * scaleFactor; - } - - public void ResetScale() - { - transform.localScale = originalScale; - m_LocalPositionOffset = m_OriginalLocalPositionOffset; - } - - public void Update(Transform parent) - { - MathUtilsExt.SetTransformOffset(parent, transform, m_LocalPositionOffset, m_RotationOffset); - } - } - - public MiniWorldRay(Transform originalRayOrigin, IMiniWorld miniWorld, IProxy proxy, Node node, IntersectionTester tester) - { - this.originalRayOrigin = originalRayOrigin; - this.miniWorld = miniWorld; - this.proxy = proxy; - this.node = node; - this.tester = tester; - } - - public void OnObjectsGrabbed(HashSet heldObjects, Transform rayOrigin) - { - var center = ObjectUtils.GetBounds(heldObjects.ToArray()).center; - - m_GrabData.Clear(); - foreach (var heldObject in heldObjects) - { - m_GrabData.Add(new GrabData(heldObject, rayOrigin, center)); - } - } - - public void TransferObjects(MiniWorldRay destinationRay, Transform rayOrigin = null) - { - var destinationGrabData = destinationRay.m_GrabData; - destinationGrabData.AddRange(m_GrabData); - m_GrabData.Clear(); - destinationRay.dragStartedOutside = dragStartedOutside; - - if (rayOrigin) - { - foreach (var grabData in destinationGrabData) - { - grabData.GetCurrentOffsets(rayOrigin); - } - } - } - - public void EnterPreviewMode(IUsesSpatialHash hash, float scaleFactor) - { - hasPreview = true; - foreach (var grabData in m_GrabData) - { - hash.RemoveFromSpatialHash(grabData.transform.gameObject); - grabData.SetScale(scaleFactor); - grabData.Update(originalRayOrigin); - } - } - - public void ExitPreviewMode(IUsesSpatialHash hash) - { - foreach (var grabData in m_GrabData) - { - hash.AddToSpatialHash(grabData.transform.gameObject); - grabData.ResetScale(); - } - hasPreview = false; - } - - public void DropPreviewObjects(IPlaceSceneObjects placer) - { - var count = m_GrabData.Count; - var transforms = new Transform[count]; - var targetPositionOffsets = new Vector3[count]; - var targetRotations = new Quaternion[count]; - var targetScales = new Vector3[count]; - - for (var i = 0; i < count; i++) - { - var grabData = m_GrabData[i]; - transforms[i] = grabData.transform; - targetPositionOffsets[i] = grabData.centerPositionOffset; - targetRotations[i] = grabData.originalRotation; - targetScales[i] = grabData.originalScale; - } - - if (hasPreview) - placer.PlaceSceneObjects(transforms, targetPositionOffsets, targetRotations, targetScales); - - m_GrabData.Clear(); - hasPreview = false; - } - - public void UpdatePreview() - { - foreach (var grabData in m_GrabData) - { - grabData.Update(originalRayOrigin); - } - } - } - - readonly Dictionary m_Rays = new Dictionary(); - readonly Dictionary m_RayWasContained = new Dictionary(); - - readonly List m_Worlds = new List(); - - bool m_MiniWorldIgnoreListDirty = true; - - // Local method use only -- created here to reduce garbage collection - static readonly List k_IgnoreList = new List(); - static readonly List k_Renderers = new List(); - - public Dictionary rays { get { return m_Rays; } } - - public List worlds { get { return m_Worlds; } } - - public MiniWorlds() - { - EditorApplication.hierarchyWindowChanged += OnHierarchyChanged; - IIsInMiniWorldMethods.isInMiniWorld = IsInMiniWorld; - } - - bool IsInMiniWorld(Transform rayOrigin) - { - foreach (var miniWorld in m_Worlds) - { - var rayOriginPosition = rayOrigin.position; - var pointerPosition = rayOriginPosition + rayOrigin.forward * DirectSelection.GetPointerLength(rayOrigin); - if (miniWorld.Contains(rayOriginPosition) || miniWorld.Contains(pointerPosition)) - return true; - } - return false; - } - - internal override void OnDestroy() - { - base.OnDestroy(); - EditorApplication.hierarchyWindowChanged -= OnHierarchyChanged; - } - - public void LateBindInterfaceMethods(DirectSelection provider) - { - provider.objectsGrabbed += OnObjectsGrabbed; - provider.objectsDropped += OnObjectsDropped; - provider.objectsTransferred += OnObjectsTransferred; - } - - void OnHierarchyChanged() - { - m_MiniWorldIgnoreListDirty = true; - } - - /// - /// Re-use DefaultProxyRay and strip off objects and components not needed for MiniWorldRays - /// - static Transform InstantiateMiniWorldRay() - { - var miniWorldRay = ObjectUtils.Instantiate(evr.m_ProxyRayPrefab.gameObject).transform; - ObjectUtils.Destroy(miniWorldRay.GetComponent()); - - var renderers = miniWorldRay.GetComponentsInChildren(); - foreach (var renderer in renderers) - { - if (!renderer.GetComponentInParent()) - ObjectUtils.Destroy(renderer.gameObject); - else - renderer.enabled = false; - } - - return miniWorldRay; - } - - void UpdateMiniWorldIgnoreList() - { - evr.GetComponentsInChildren(true, k_Renderers); - k_IgnoreList.Clear(); - - foreach (var r in k_Renderers) - { - if (r.CompareTag(k_VRPlayerTag)) - continue; - - if (r.gameObject.layer != LayerMask.NameToLayer("UI") && r.CompareTag(MiniWorldRenderer.ShowInMiniWorldTag)) - continue; - - k_IgnoreList.Add(r); - } - - foreach (var miniWorld in m_Worlds) - { - miniWorld.ignoreList = k_IgnoreList; - } - } - - internal void UpdateMiniWorlds() - { - if (m_MiniWorldIgnoreListDirty) - { - UpdateMiniWorldIgnoreList(); - m_MiniWorldIgnoreListDirty = false; - } - - var directSelection = evr.GetNestedModule(); - - // Update MiniWorldRays - foreach (var ray in m_Rays) - { - var miniWorldRayOrigin = ray.Key; - var miniWorldRay = ray.Value; - - if (!miniWorldRay.proxy.active) - { - miniWorldRay.tester.active = false; - continue; - } - - var miniWorld = miniWorldRay.miniWorld; - var inverseScale = miniWorld.miniWorldTransform.lossyScale.Inverse(); - - if (float.IsInfinity(inverseScale.x) || float.IsNaN(inverseScale.x)) // Extreme scales cause transform errors - continue; - - // Transform into reference space - var originalRayOrigin = miniWorldRay.originalRayOrigin; - var referenceTransform = miniWorld.referenceTransform; - var miniWorldTransform = miniWorld.miniWorldTransform; - miniWorldRayOrigin.position = referenceTransform.TransformPoint(miniWorldTransform.InverseTransformPoint(originalRayOrigin.position)); - miniWorldRayOrigin.rotation = referenceTransform.rotation * Quaternion.Inverse(miniWorldTransform.rotation) * originalRayOrigin.rotation; - miniWorldRayOrigin.localScale = Vector3.Scale(inverseScale, referenceTransform.localScale); - - // Set miniWorldRayOrigin active state based on whether controller is inside corresponding MiniWorld - var originalPointerPosition = originalRayOrigin.position + originalRayOrigin.forward * DirectSelection.GetPointerLength(originalRayOrigin); - var isContained = miniWorld.Contains(originalPointerPosition); - miniWorldRay.tester.active = isContained; - miniWorldRayOrigin.gameObject.SetActive(isContained); - - var miniWorldRayObjects = directSelection.GetHeldObjects(miniWorldRayOrigin); - var originalRayObjects = directSelection.GetHeldObjects(originalRayOrigin); - - var hasPreview = miniWorldRay.hasPreview; - if (miniWorldRayObjects == null && originalRayObjects == null && !hasPreview) - { - miniWorldRay.isContained = isContained; - continue; - } - - var wasContained = miniWorldRay.isContained; - var dragStartedOutside = miniWorldRay.dragStartedOutside; - if (isContained != wasContained) - { - // Early out if we grabbed a real-world object that started inside a mini world - if (!isContained && miniWorldRayObjects == null) - { - miniWorldRay.isContained = false; - continue; - } - - // Transfer objects to and from original ray and MiniWorld ray (e.g. outside to inside mini world) - var from = isContained ? originalRayOrigin : miniWorldRayOrigin; - var to = isContained ? miniWorldRayOrigin : originalRayOrigin; - - KeyValuePair? overlapPair = null; - MiniWorldRay incomingPreview = null; - - // Try to transfer objects between MiniWorlds - if (miniWorldRayObjects != null && !isContained) - { - foreach (var kvp in m_Rays) - { - var otherRayOrigin = kvp.Key; - var otherRay = kvp.Value; - if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.isContained) - { - overlapPair = kvp; - from = miniWorldRayOrigin; - to = otherRayOrigin; - break; - } - } - } - - if (originalRayObjects != null && isContained && !dragStartedOutside) - { - //Check for other miniworlds' previews entering this ray's miniworld - foreach (var kvp in m_Rays) - { - var otherRay = kvp.Value; - if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.hasObjects) - { - incomingPreview = otherRay; - from = originalRayOrigin; - to = miniWorldRayOrigin; - break; - } - } - } - - var pointerLengthDiff = DirectSelection.GetPointerLength(to) - DirectSelection.GetPointerLength(from); - directSelection.TransferHeldObjects(from, to, Vector3.forward * pointerLengthDiff); - - if (overlapPair.HasValue) - { - var kvp = overlapPair.Value; - miniWorldRay.TransferObjects(kvp.Value, kvp.Key); - } - - if (incomingPreview != null) - { - incomingPreview.ExitPreviewMode(this); - incomingPreview.TransferObjects(miniWorldRay); - directSelection.ResumeGrabbers(incomingPreview.node); - } - - miniWorldRay.UpdatePreview(); // Otherwise the object is in the wrong position for a frame - - if (!isContained) - m_RayWasContained[originalRayOrigin] = false; //Prevent ray from showing - } - - if (dragStartedOutside) - { - miniWorldRay.isContained = isContained; - continue; - } - - var node = miniWorldRay.node; - - if (miniWorldRayObjects != null && !isContained && wasContained) - { - var containedInOtherMiniWorld = false; - foreach (var world in m_Worlds) - { - if (miniWorld != world && world.Contains(originalPointerPosition)) - containedInOtherMiniWorld = true; - } - - // Transfer objects from miniworld to preview state - // Don't switch to previewing the objects we are dragging if we are still in another mini world - if (!containedInOtherMiniWorld) - { - // Check for player head - var playerHead = false; - foreach (var obj in miniWorldRayObjects) - { - if (obj.CompareTag(k_VRPlayerTag)) - { - playerHead = true; - directSelection.DropHeldObjects(node); - break; - } - } - - if (!playerHead) - { - var scaleFactor = this.GetViewerScale() / miniWorld.referenceTransform.localScale.x; - miniWorldRay.EnterPreviewMode(this, scaleFactor); - directSelection.SuspendGrabbers(node); - } - } - } - - if (hasPreview) - { - // Check if we have just entered another miniworld - var enterOther = false; - foreach (var kvp in m_Rays) - { - var otherRay = kvp.Value; - var otherMiniWorld = otherRay.miniWorld; - if (otherMiniWorld != miniWorld && otherRay.node == node && otherMiniWorld.Contains(originalPointerPosition)) - { - miniWorldRay.ExitPreviewMode(this); - directSelection.ResumeGrabbers(node); - enterOther = true; - break; - } - } - - if (!enterOther) - { - if (!isContained) - { - miniWorldRay.UpdatePreview(); - } - else if (!wasContained) - { - miniWorldRay.ExitPreviewMode(this); - directSelection.ResumeGrabbers(node); - } - } - } - - miniWorldRay.isContained = isContained; - } - - // Update ray visibilities - foreach (var deviceData in evr.m_DeviceData) - { - var proxy = deviceData.proxy; - if (!proxy.active) - continue; - - UpdateRayContaimnent(deviceData); - } - } - - void UpdateRayContaimnent(DeviceData data) - { - bool wasContained; - var rayOrigin = data.rayOrigin; - m_RayWasContained.TryGetValue(rayOrigin, out wasContained); - - var isContained = false; - foreach (var miniWorld in m_Worlds) - { - isContained |= miniWorld.Contains(rayOrigin.position + rayOrigin.forward * DirectSelection.GetPointerLength(rayOrigin)); - } - - if (isContained && !wasContained) - Rays.AddVisibilitySettings(rayOrigin, this, false, true); - - if (!isContained && wasContained) - Rays.RemoveVisibilitySettings(rayOrigin, this); - - m_RayWasContained[rayOrigin] = isContained; - } - - internal void OnWorkspaceCreated(IWorkspace workspace) - { - var miniWorldWorkspace = workspace as MiniWorldWorkspace; - if (!miniWorldWorkspace) - return; - - miniWorldWorkspace.zoomSliderMax = evr.GetModule().GetMaxBounds().size.MaxComponent() - / miniWorldWorkspace.contentBounds.size.MaxComponent(); - - var miniWorld = miniWorldWorkspace.miniWorld; - var worldID = m_Worlds.Count; - miniWorld.miniWorldTransform.name = string.Format("Miniworld {0}", worldID); - m_Worlds.Add(miniWorld); - - var intersectionModule = evr.GetModule(); - Rays.ForEachProxyDevice(deviceData => - { - var node = deviceData.node; - var rayOrigin = deviceData.rayOrigin; - var proxy = deviceData.proxy; - - var miniWorldRayOrigin = InstantiateMiniWorldRay(); - miniWorldRayOrigin.name = string.Format("{0} Miniworld {1} Ray", node, worldID); - miniWorldRayOrigin.parent = workspace.transform; - - var tester = miniWorldRayOrigin.GetComponentInChildren(); - tester.active = false; - - m_Rays[miniWorldRayOrigin] = new MiniWorldRay(rayOrigin, miniWorld, proxy, node, tester); - - intersectionModule.AddTester(tester); - - evr.GetModule().AddRayOriginForNode(node, miniWorldRayOrigin); - - if (proxy.active) - { - if (node == Node.LeftHand) - miniWorldWorkspace.leftRayOrigin = rayOrigin; - - if (node == Node.RightHand) - miniWorldWorkspace.rightRayOrigin = rayOrigin; - } - }, false); - } - - internal void OnWorkspaceDestroyed(IWorkspace workspace) - { - var miniWorldWorkspace = workspace as MiniWorldWorkspace; - if (!miniWorldWorkspace) - return; - - var miniWorld = miniWorldWorkspace.miniWorld; - - // Clean up MiniWorldRays - m_Worlds.Remove(miniWorld); - var miniWorldRaysCopy = new Dictionary(m_Rays); - foreach (var ray in miniWorldRaysCopy) - { - var miniWorldRay = ray.Value; - if (miniWorldRay.miniWorld == miniWorld) - m_Rays.Remove(ray.Key); - } - } - - void OnObjectsGrabbed(Transform rayOrigin, HashSet grabbedObjects) - { - foreach (var kvp in m_Rays) - { - var miniWorldRayOrigin = kvp.Key; - var ray = kvp.Value; - var isOriginalRayOrigin = rayOrigin == ray.originalRayOrigin; - if (isOriginalRayOrigin) - ray.dragStartedOutside = true; - - var isMiniWorldRayOrigin = rayOrigin == miniWorldRayOrigin; - if (isOriginalRayOrigin || isMiniWorldRayOrigin) - ray.OnObjectsGrabbed(grabbedObjects, rayOrigin); - } - } - - void OnObjectsDropped(Transform rayOrigin, Transform[] grabbedObjects) - { - var node = Node.None; - foreach (var ray in m_Rays) - { - var miniWorldRay = ray.Value; - if (ray.Key == rayOrigin || miniWorldRay.originalRayOrigin == rayOrigin) - { - node = miniWorldRay.node; - break; - } - } - - foreach (var ray in m_Rays) - { - var miniWorldRay = ray.Value; - if (miniWorldRay.node == node) - { - miniWorldRay.DropPreviewObjects(this); - miniWorldRay.dragStartedOutside = false; - - if (!miniWorldRay.isContained) - Rays.RemoveVisibilitySettings(rayOrigin, this); - } - } - } - - void OnObjectsTransferred(Transform sourceRayOrigin, Transform destinationRayOrigin) - { - // Handle hand-to-hand transfers from two-handed scaling - foreach (var src in m_Rays) - { - var srcRayOrigin = src.Key; - var srcRay = src.Value; - var srcRayHasObjects = srcRay.hasObjects; - if (srcRayOrigin == sourceRayOrigin) - { - if (srcRayHasObjects) - { - foreach (var dest in m_Rays) - { - if (dest.Key == destinationRayOrigin) - { - srcRay.TransferObjects(dest.Value, destinationRayOrigin); - break; - } - } - } - } - - var srcRayOriginalRayOrigin = srcRay.originalRayOrigin; - if (srcRayOriginalRayOrigin == sourceRayOrigin) - { - if (srcRayHasObjects) - { - foreach (var dest in m_Rays) - { - var destRay = dest.Value; - if (destRay.originalRayOrigin == destinationRayOrigin && destRay.miniWorld == srcRay.miniWorld) - srcRay.TransferObjects(destRay, destinationRayOrigin); - } - } - } - } - } - } - } -} -#endif +#if UNITY_EDITOR && UNITY_2017_2_OR_NEWER +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEditor.Experimental.EditorVR.Workspaces; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Core +{ + partial class EditorVR + { + class MiniWorlds : Nested, ILateBindInterfaceMethods, IPlaceSceneObjects, IUsesViewerScale, + IUsesSpatialHash + { + internal class MiniWorldRay + { + readonly List m_GrabData = new List(); + + public Transform originalRayOrigin { get; private set; } + public IMiniWorld miniWorld { get; private set; } + public IProxy proxy { get; private set; } + public Node node { get; private set; } + public IntersectionTester tester { get; private set; } + + public bool hasPreview { get; private set; } + + public bool hasObjects + { + get { return m_GrabData.Count > 0; } + } + + public bool dragStartedOutside { get; set; } + public bool isContained { get; set; } + + class GrabData + { + Vector3 m_OriginalLocalPositionOffset; + Vector3 m_LocalPositionOffset; + Quaternion m_RotationOffset; + + public Vector3 centerPositionOffset { get; private set; } + public Quaternion originalRotation { get; private set; } + public Vector3 originalScale { get; private set; } + + public Transform transform { get; private set; } + + public GrabData(Transform transform, Transform parent, Vector3 center) + { + this.transform = transform; + centerPositionOffset = transform.position - center; + originalRotation = transform.rotation; + originalScale = transform.localScale; + GetCurrentOffsets(parent); + } + + public void GetCurrentOffsets(Transform parent) + { + MathUtilsExt.GetTransformOffset(parent, transform, out m_LocalPositionOffset, out m_RotationOffset); + m_OriginalLocalPositionOffset = m_LocalPositionOffset; + } + + public void SetScale(float scaleFactor) + { + transform.localScale *= scaleFactor; + m_LocalPositionOffset = m_OriginalLocalPositionOffset * scaleFactor; + } + + public void ResetScale() + { + transform.localScale = originalScale; + m_LocalPositionOffset = m_OriginalLocalPositionOffset; + } + + public void Update(Transform parent) + { + MathUtilsExt.SetTransformOffset(parent, transform, m_LocalPositionOffset, m_RotationOffset); + } + } + + public MiniWorldRay(Transform originalRayOrigin, IMiniWorld miniWorld, IProxy proxy, Node node, IntersectionTester tester) + { + this.originalRayOrigin = originalRayOrigin; + this.miniWorld = miniWorld; + this.proxy = proxy; + this.node = node; + this.tester = tester; + } + + public void OnObjectsGrabbed(HashSet heldObjects, Transform rayOrigin) + { + var center = ObjectUtils.GetBounds(heldObjects.ToArray()).center; + + m_GrabData.Clear(); + foreach (var heldObject in heldObjects) + { + m_GrabData.Add(new GrabData(heldObject, rayOrigin, center)); + } + } + + public void TransferObjects(MiniWorldRay destinationRay, Transform rayOrigin = null) + { + var destinationGrabData = destinationRay.m_GrabData; + destinationGrabData.AddRange(m_GrabData); + m_GrabData.Clear(); + destinationRay.dragStartedOutside = dragStartedOutside; + + if (rayOrigin) + { + foreach (var grabData in destinationGrabData) + { + grabData.GetCurrentOffsets(rayOrigin); + } + } + } + + public void EnterPreviewMode(IUsesSpatialHash hash, float scaleFactor) + { + hasPreview = true; + foreach (var grabData in m_GrabData) + { + hash.RemoveFromSpatialHash(grabData.transform.gameObject); + grabData.SetScale(scaleFactor); + grabData.Update(originalRayOrigin); + } + } + + public void ExitPreviewMode(IUsesSpatialHash hash) + { + foreach (var grabData in m_GrabData) + { + hash.AddToSpatialHash(grabData.transform.gameObject); + grabData.ResetScale(); + } + + hasPreview = false; + } + + public void DropPreviewObjects(IPlaceSceneObjects placer) + { + var count = m_GrabData.Count; + var transforms = new Transform[count]; + var targetPositionOffsets = new Vector3[count]; + var targetRotations = new Quaternion[count]; + var targetScales = new Vector3[count]; + + for (var i = 0; i < count; i++) + { + var grabData = m_GrabData[i]; + transforms[i] = grabData.transform; + targetPositionOffsets[i] = grabData.centerPositionOffset; + targetRotations[i] = grabData.originalRotation; + targetScales[i] = grabData.originalScale; + } + + if (hasPreview) + placer.PlaceSceneObjects(transforms, targetPositionOffsets, targetRotations, targetScales); + + m_GrabData.Clear(); + hasPreview = false; + } + + public void UpdatePreview() + { + foreach (var grabData in m_GrabData) + { + grabData.Update(originalRayOrigin); + } + } + } + + readonly Dictionary m_Rays = new Dictionary(); + readonly Dictionary m_RayWasContained = new Dictionary(); + + readonly List m_Worlds = new List(); + + bool m_MiniWorldIgnoreListDirty = true; + + // Local method use only -- created here to reduce garbage collection + static readonly List k_IgnoreList = new List(); + static readonly List k_Renderers = new List(); + + public Dictionary rays { get { return m_Rays; } } + + public List worlds { get { return m_Worlds; } } + + public MiniWorlds() + { + EditorApplication.hierarchyWindowChanged += OnHierarchyChanged; + IIsInMiniWorldMethods.isInMiniWorld = IsInMiniWorld; + } + + bool IsInMiniWorld(Transform rayOrigin) + { + foreach (var miniWorld in m_Worlds) + { + var rayOriginPosition = rayOrigin.position; + var pointerPosition = rayOriginPosition + rayOrigin.forward * DirectSelection.GetPointerLength(rayOrigin); + if (miniWorld.Contains(rayOriginPosition) || miniWorld.Contains(pointerPosition)) + return true; + } + return false; + } + + internal override void OnDestroy() + { + base.OnDestroy(); + EditorApplication.hierarchyWindowChanged -= OnHierarchyChanged; + } + + public void LateBindInterfaceMethods(DirectSelection provider) + { + provider.objectsGrabbed += OnObjectsGrabbed; + provider.objectsDropped += OnObjectsDropped; + provider.objectsTransferred += OnObjectsTransferred; + } + + void OnHierarchyChanged() + { + m_MiniWorldIgnoreListDirty = true; + } + + /// + /// Re-use DefaultProxyRay and strip off objects and components not needed for MiniWorldRays + /// + static Transform InstantiateMiniWorldRay() + { + var miniWorldRay = ObjectUtils.Instantiate(evr.m_ProxyRayPrefab.gameObject).transform; + ObjectUtils.Destroy(miniWorldRay.GetComponent()); + + var renderers = miniWorldRay.GetComponentsInChildren(); + foreach (var renderer in renderers) + { + if (!renderer.GetComponentInParent()) + ObjectUtils.Destroy(renderer.gameObject); + else + renderer.enabled = false; + } + + return miniWorldRay; + } + + void UpdateMiniWorldIgnoreList() + { + evr.GetComponentsInChildren(true, k_Renderers); + k_IgnoreList.Clear(); + + foreach (var r in k_Renderers) + { + if (r.CompareTag(k_VRPlayerTag)) + continue; + + if (r.gameObject.layer != LayerMask.NameToLayer("UI") && r.CompareTag(MiniWorldRenderer.ShowInMiniWorldTag)) + continue; + + k_IgnoreList.Add(r); + } + + foreach (var miniWorld in m_Worlds) + { + miniWorld.ignoreList = k_IgnoreList; + } + } + + internal void UpdateMiniWorlds() + { + if (m_MiniWorldIgnoreListDirty) + { + UpdateMiniWorldIgnoreList(); + m_MiniWorldIgnoreListDirty = false; + } + + var directSelection = evr.GetNestedModule(); + + // Update MiniWorldRays + foreach (var ray in m_Rays) + { + var miniWorldRayOrigin = ray.Key; + var miniWorldRay = ray.Value; + + if (!miniWorldRay.proxy.active) + { + miniWorldRay.tester.active = false; + continue; + } + + var miniWorld = miniWorldRay.miniWorld; + var inverseScale = miniWorld.miniWorldTransform.lossyScale.Inverse(); + + if (float.IsInfinity(inverseScale.x) || float.IsNaN(inverseScale.x)) // Extreme scales cause transform errors + continue; + + // Transform into reference space + var originalRayOrigin = miniWorldRay.originalRayOrigin; + var referenceTransform = miniWorld.referenceTransform; + var miniWorldTransform = miniWorld.miniWorldTransform; + miniWorldRayOrigin.position = referenceTransform.TransformPoint(miniWorldTransform.InverseTransformPoint(originalRayOrigin.position)); + miniWorldRayOrigin.rotation = referenceTransform.rotation * Quaternion.Inverse(miniWorldTransform.rotation) * originalRayOrigin.rotation; + miniWorldRayOrigin.localScale = Vector3.Scale(inverseScale, referenceTransform.localScale); + + // Set miniWorldRayOrigin active state based on whether controller is inside corresponding MiniWorld + var originalPointerPosition = originalRayOrigin.position + originalRayOrigin.forward * DirectSelection.GetPointerLength(originalRayOrigin); + var isContained = miniWorld.Contains(originalPointerPosition); + miniWorldRay.tester.active = isContained; + miniWorldRayOrigin.gameObject.SetActive(isContained); + + var miniWorldRayObjects = directSelection.GetHeldObjects(miniWorldRayOrigin); + var originalRayObjects = directSelection.GetHeldObjects(originalRayOrigin); + + var hasPreview = miniWorldRay.hasPreview; + if (miniWorldRayObjects == null && originalRayObjects == null && !hasPreview) + { + miniWorldRay.isContained = isContained; + continue; + } + + var wasContained = miniWorldRay.isContained; + var dragStartedOutside = miniWorldRay.dragStartedOutside; + if (isContained != wasContained) + { + // Early out if we grabbed a real-world object that started inside a mini world + if (!isContained && miniWorldRayObjects == null) + { + miniWorldRay.isContained = false; + continue; + } + + // Transfer objects to and from original ray and MiniWorld ray (e.g. outside to inside mini world) + var from = isContained ? originalRayOrigin : miniWorldRayOrigin; + var to = isContained ? miniWorldRayOrigin : originalRayOrigin; + + KeyValuePair? overlapPair = null; + MiniWorldRay incomingPreview = null; + + // Try to transfer objects between MiniWorlds + if (miniWorldRayObjects != null && !isContained) + { + foreach (var kvp in m_Rays) + { + var otherRayOrigin = kvp.Key; + var otherRay = kvp.Value; + if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.isContained) + { + overlapPair = kvp; + from = miniWorldRayOrigin; + to = otherRayOrigin; + break; + } + } + } + + if (originalRayObjects != null && isContained && !dragStartedOutside) + { + //Check for other miniworlds' previews entering this ray's miniworld + foreach (var kvp in m_Rays) + { + var otherRay = kvp.Value; + if (originalRayOrigin == otherRay.originalRayOrigin && otherRay != miniWorldRay && otherRay.hasObjects) + { + incomingPreview = otherRay; + from = originalRayOrigin; + to = miniWorldRayOrigin; + break; + } + } + } + + var pointerLengthDiff = DirectSelection.GetPointerLength(to) - DirectSelection.GetPointerLength(from); + directSelection.TransferHeldObjects(from, to, Vector3.forward * pointerLengthDiff); + + if (overlapPair.HasValue) + { + var kvp = overlapPair.Value; + miniWorldRay.TransferObjects(kvp.Value, kvp.Key); + } + + if (incomingPreview != null) + { + incomingPreview.ExitPreviewMode(this); + incomingPreview.TransferObjects(miniWorldRay); + directSelection.ResumeGrabbers(incomingPreview.node); + } + + miniWorldRay.UpdatePreview(); // Otherwise the object is in the wrong position for a frame + + if (!isContained) + m_RayWasContained[originalRayOrigin] = false; //Prevent ray from showing + } + + if (dragStartedOutside) + { + miniWorldRay.isContained = isContained; + continue; + } + + var node = miniWorldRay.node; + + if (miniWorldRayObjects != null && !isContained && wasContained) + { + var containedInOtherMiniWorld = false; + foreach (var world in m_Worlds) + { + if (miniWorld != world && world.Contains(originalPointerPosition)) + containedInOtherMiniWorld = true; + } + + // Transfer objects from miniworld to preview state + // Don't switch to previewing the objects we are dragging if we are still in another mini world + if (!containedInOtherMiniWorld) + { + // Check for player head + var playerHead = false; + foreach (var obj in miniWorldRayObjects) + { + if (obj.CompareTag(k_VRPlayerTag)) + { + playerHead = true; + directSelection.DropHeldObjects(node); + break; + } + } + + if (!playerHead) + { + var scaleFactor = this.GetViewerScale() / miniWorld.referenceTransform.localScale.x; + miniWorldRay.EnterPreviewMode(this, scaleFactor); + directSelection.SuspendGrabbers(node); + } + } + } + + if (hasPreview) + { + // Check if we have just entered another miniworld + var enterOther = false; + foreach (var kvp in m_Rays) + { + var otherRay = kvp.Value; + var otherMiniWorld = otherRay.miniWorld; + if (otherMiniWorld != miniWorld && otherRay.node == node && otherMiniWorld.Contains(originalPointerPosition)) + { + miniWorldRay.ExitPreviewMode(this); + directSelection.ResumeGrabbers(node); + enterOther = true; + break; + } + } + + if (!enterOther) + { + if (!isContained) + { + miniWorldRay.UpdatePreview(); + } + else if (!wasContained) + { + miniWorldRay.ExitPreviewMode(this); + directSelection.ResumeGrabbers(node); + } + } + } + + miniWorldRay.isContained = isContained; + } + + // Update ray visibilities + foreach (var deviceData in evr.m_DeviceData) + { + var proxy = deviceData.proxy; + if (!proxy.active) + continue; + + UpdateRayContaimnent(deviceData); + } + } + + void UpdateRayContaimnent(DeviceData data) + { + bool wasContained; + var rayOrigin = data.rayOrigin; + m_RayWasContained.TryGetValue(rayOrigin, out wasContained); + + var isContained = false; + foreach (var miniWorld in m_Worlds) + { + isContained |= miniWorld.Contains(rayOrigin.position + rayOrigin.forward * DirectSelection.GetPointerLength(rayOrigin)); + } + + if (isContained && !wasContained) + Rays.AddVisibilitySettings(rayOrigin, this, false, true); + + if (!isContained && wasContained) + Rays.RemoveVisibilitySettings(rayOrigin, this); + + m_RayWasContained[rayOrigin] = isContained; + } + + internal void OnWorkspaceCreated(IWorkspace workspace) + { + var miniWorldWorkspace = workspace as MiniWorldWorkspace; + if (!miniWorldWorkspace) + return; + + miniWorldWorkspace.zoomSliderMax = evr.GetModule().GetMaxBounds().size.MaxComponent() + / miniWorldWorkspace.contentBounds.size.MaxComponent(); + + var miniWorld = miniWorldWorkspace.miniWorld; + var worldID = m_Worlds.Count; + miniWorld.miniWorldTransform.name = string.Format("Miniworld {0}", worldID); + m_Worlds.Add(miniWorld); + + var intersectionModule = evr.GetModule(); + Rays.ForEachProxyDevice(deviceData => + { + var node = deviceData.node; + var rayOrigin = deviceData.rayOrigin; + var proxy = deviceData.proxy; + + var miniWorldRayOrigin = InstantiateMiniWorldRay(); + miniWorldRayOrigin.name = string.Format("{0} Miniworld {1} Ray", node, worldID); + miniWorldRayOrigin.parent = workspace.transform; + + var tester = miniWorldRayOrigin.GetComponentInChildren(); + tester.active = false; + + m_Rays[miniWorldRayOrigin] = new MiniWorldRay(rayOrigin, miniWorld, proxy, node, tester); + + intersectionModule.AddTester(tester); + + evr.GetModule().AddRayOriginForNode(node, miniWorldRayOrigin); + + if (proxy.active) + { + if (node == Node.LeftHand) + miniWorldWorkspace.leftRayOrigin = rayOrigin; + + if (node == Node.RightHand) + miniWorldWorkspace.rightRayOrigin = rayOrigin; + } + }, false); + } + + internal void OnWorkspaceDestroyed(IWorkspace workspace) + { + var miniWorldWorkspace = workspace as MiniWorldWorkspace; + if (!miniWorldWorkspace) + return; + + var miniWorld = miniWorldWorkspace.miniWorld; + + // Clean up MiniWorldRays + m_Worlds.Remove(miniWorld); + var miniWorldRaysCopy = new Dictionary(m_Rays); + foreach (var ray in miniWorldRaysCopy) + { + var miniWorldRay = ray.Value; + if (miniWorldRay.miniWorld == miniWorld) + m_Rays.Remove(ray.Key); + } + } + + void OnObjectsGrabbed(Transform rayOrigin, HashSet grabbedObjects) + { + foreach (var kvp in m_Rays) + { + var miniWorldRayOrigin = kvp.Key; + var ray = kvp.Value; + var isOriginalRayOrigin = rayOrigin == ray.originalRayOrigin; + if (isOriginalRayOrigin) + ray.dragStartedOutside = true; + + var isMiniWorldRayOrigin = rayOrigin == miniWorldRayOrigin; + if (isOriginalRayOrigin || isMiniWorldRayOrigin) + ray.OnObjectsGrabbed(grabbedObjects, rayOrigin); + } + } + + void OnObjectsDropped(Transform rayOrigin, Transform[] grabbedObjects) + { + var node = Node.None; + foreach (var ray in m_Rays) + { + var miniWorldRay = ray.Value; + if (ray.Key == rayOrigin || miniWorldRay.originalRayOrigin == rayOrigin) + { + node = miniWorldRay.node; + break; + } + } + + foreach (var ray in m_Rays) + { + var miniWorldRay = ray.Value; + if (miniWorldRay.node == node) + { + miniWorldRay.DropPreviewObjects(this); + miniWorldRay.dragStartedOutside = false; + + if (!miniWorldRay.isContained) + Rays.RemoveVisibilitySettings(rayOrigin, this); + } + } + } + + void OnObjectsTransferred(Transform sourceRayOrigin, Transform destinationRayOrigin) + { + // Handle hand-to-hand transfers from two-handed scaling + foreach (var src in m_Rays) + { + var srcRayOrigin = src.Key; + var srcRay = src.Value; + var srcRayHasObjects = srcRay.hasObjects; + if (srcRayOrigin == sourceRayOrigin) + { + if (srcRayHasObjects) + { + foreach (var dest in m_Rays) + { + if (dest.Key == destinationRayOrigin) + { + srcRay.TransferObjects(dest.Value, destinationRayOrigin); + break; + } + } + } + } + + var srcRayOriginalRayOrigin = srcRay.originalRayOrigin; + if (srcRayOriginalRayOrigin == sourceRayOrigin) + { + if (srcRayHasObjects) + { + foreach (var dest in m_Rays) + { + var destRay = dest.Value; + if (destRay.originalRayOrigin == destinationRayOrigin && destRay.miniWorld == srcRay.miniWorld) + srcRay.TransferObjects(destRay, destinationRayOrigin); + } + } + } + } + } + } + } +} +#endif diff --git a/Scripts/Core/EditorVR.Viewer.cs b/Scripts/Core/EditorVR.Viewer.cs index bb6900d41..47d60cad9 100644 --- a/Scripts/Core/EditorVR.Viewer.cs +++ b/Scripts/Core/EditorVR.Viewer.cs @@ -51,6 +51,8 @@ public float cameraRigScale const float k_CameraRigTransitionTime = 0.25f; + const string k_WorldScaleProperty = "_WorldScale"; + // Local method use only -- created here to reduce garbage collection const int k_MaxCollisionCheck = 32; static Collider[] s_CachedColliders = new Collider[k_MaxCollisionCheck]; @@ -80,6 +82,8 @@ public Viewer() VRView.hmdStatusChange += OnHMDStatusChange; preserveCameraRig = true; + + Shader.SetGlobalFloat(k_WorldScaleProperty, 1); } internal override void OnDestroy() @@ -317,6 +321,7 @@ void SetViewerScale(float scale) CameraUtils.GetCameraRig().localScale = Vector3.one * scale; camera.nearClipPlane = m_OriginalNearClipPlane * scale; camera.farClipPlane = m_OriginalFarClipPlane * scale; + Shader.SetGlobalFloat(k_WorldScaleProperty, 1f / scale); } } } diff --git a/Scripts/Core/EditorVR.cs b/Scripts/Core/EditorVR.cs index 82efbb882..2714e7d7e 100644 --- a/Scripts/Core/EditorVR.cs +++ b/Scripts/Core/EditorVR.cs @@ -4,12 +4,15 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using UnityEditor.Experimental.EditorVR; using UnityEditor.Experimental.EditorVR.Extensions; using UnityEditor.Experimental.EditorVR.Modules; using UnityEditor.Experimental.EditorVR.Utilities; using UnityEngine; using UnityEngine.InputNew; +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + namespace UnityEditor.Experimental.EditorVR.Core { #if UNITY_2017_2_OR_NEWER @@ -235,6 +238,13 @@ void Awake() AddModule(); + AddModule(); + + //TODO: External module support (removes need for CCU in this instance) +#if INCLUDE_POLY_TOOLKIT + AddModule(); +#endif + viewer.AddPlayerModel(); GetNestedModule().CreateAllProxies(); diff --git a/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs b/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs new file mode 100644 index 000000000..08bb8b66b --- /dev/null +++ b/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs @@ -0,0 +1,22 @@ +#if UNITY_EDITOR && UNITY_2017_2_OR_NEWER +using UnityEditor.Experimental.EditorVR; +using UnityEditor.Experimental.EditorVR.Modules; + +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + +#if INCLUDE_POLY_TOOLKIT +namespace UnityEditor.Experimental.EditorVR.Core +{ + partial class EditorVR + { + class PolyModuleConnector : Nested, ILateBindInterfaceMethods + { + public void LateBindInterfaceMethods(PolyModule provider) + { + IPolyMethods.getAssetList = provider.GetAssetList; + } + } + } +} +#endif +#endif diff --git a/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs.meta b/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs.meta new file mode 100644 index 000000000..db55087be --- /dev/null +++ b/Scripts/Core/InterfaceConnectors/PolyModuleConnector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 631d0bca4660f5c4593cae69ae9ed5b8 +timeCreated: 1505163769 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs b/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs new file mode 100644 index 000000000..8afdc6cd7 --- /dev/null +++ b/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs @@ -0,0 +1,19 @@ +#if UNITY_EDITOR && UNITY_2017_2_OR_NEWER +using UnityEditor.Experimental.EditorVR.Modules; + +namespace UnityEditor.Experimental.EditorVR.Core +{ + partial class EditorVR + { + class WebModuleConnector : Nested, ILateBindInterfaceMethods + { + public void LateBindInterfaceMethods(WebModule provider) + { + IWebMethods.download = provider.Download; + IWebMethods.downloadTexture = provider.DownloadTexture; + IWebMethods.downloadToDisk = provider.Download; + } + } + } +} +#endif diff --git a/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs.meta b/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs.meta new file mode 100644 index 000000000..88f19212e --- /dev/null +++ b/Scripts/Core/InterfaceConnectors/WebModuleConnector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39bcf8a3be05ffc4fa410705506ec04d +timeCreated: 1505163769 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Core/Interfaces/IUsesPointer.cs.meta b/Scripts/Core/Interfaces/IUsesPointer.cs.meta index 3863692df..5ee678184 100644 --- a/Scripts/Core/Interfaces/IUsesPointer.cs.meta +++ b/Scripts/Core/Interfaces/IUsesPointer.cs.meta @@ -1,12 +1,12 @@ -fileFormatVersion: 2 -guid: 56f696da02705f34fafa462bc2a18b30 -timeCreated: 1491521343 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 56f696da02705f34fafa462bc2a18b30 +timeCreated: 1491521343 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/HandleEventData.cs b/Scripts/Data/HandleEventData.cs index 67694be7c..49786d73d 100644 --- a/Scripts/Data/HandleEventData.cs +++ b/Scripts/Data/HandleEventData.cs @@ -1,40 +1,40 @@ -#if UNITY_EDITOR -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - /// - /// Event data for BaseHandle.DragEventCallback - /// - class HandleEventData - { - /// - /// The source transform from where the ray is cast - /// - public Transform rayOrigin; - - /// - /// Whether this pointer was within range to be considered "direct" - /// - public bool direct; - - /// - /// Change in position between last frame and this frame - /// - public Vector3 deltaPosition; - - /// - /// Change in rotation between last frame and this frame - /// - public Quaternion deltaRotation; - - public HandleEventData(Transform rayOrigin, bool direct) - { - this.rayOrigin = rayOrigin; - this.direct = direct; - this.deltaPosition = Vector3.zero; - this.deltaRotation = Quaternion.identity; - } - } -} -#endif +#if UNITY_EDITOR +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + /// + /// Event data for BaseHandle.DragEventCallback + /// + class HandleEventData + { + /// + /// The source transform from where the ray is cast + /// + public Transform rayOrigin; + + /// + /// Whether this pointer was within range to be considered "direct" + /// + public bool direct; + + /// + /// Change in position between last frame and this frame + /// + public Vector3 deltaPosition; + + /// + /// Change in rotation between last frame and this frame + /// + public Quaternion deltaRotation; + + public HandleEventData(Transform rayOrigin, bool direct) + { + this.rayOrigin = rayOrigin; + this.direct = direct; + this.deltaPosition = Vector3.zero; + this.deltaRotation = Quaternion.identity; + } + } +} +#endif diff --git a/Scripts/Handles/BaseHandle.cs b/Scripts/Handles/BaseHandle.cs index 66ddfb1a5..197fb96c2 100644 --- a/Scripts/Handles/BaseHandle.cs +++ b/Scripts/Handles/BaseHandle.cs @@ -1,285 +1,290 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.UI; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.EventSystems; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - /// - /// Base class for providing draggable handles in 3D (requires PhysicsRaycaster) - /// - class BaseHandle : MonoBehaviour, ISelectionFlags, IRayBeginDragHandler, IRayDragHandler, IRayEndDragHandler, - IRayEnterHandler, IRayExitHandler, IRayHoverHandler, IPointerClickHandler, IDropReceiver, IDroppable - { - protected const int k_DefaultCapacity = 2; // i.e. 2 controllers - - public SelectionFlags selectionFlags - { - get { return m_SelectionFlags; } - set { m_SelectionFlags = value; } - } - - [SerializeField] - [FlagsProperty] - SelectionFlags m_SelectionFlags = SelectionFlags.Ray | SelectionFlags.Direct; - - protected readonly List m_HoverSources = new List(k_DefaultCapacity); - protected readonly List m_DragSources = new List(k_DefaultCapacity); - protected readonly Dictionary m_StartDragPositions = new Dictionary(k_DefaultCapacity); - protected readonly Dictionary m_LastClickTimes = new Dictionary(k_DefaultCapacity); - - public bool hasHoverSource { get { return m_HoverSources.Count > 0; } } - public bool hasDragSource { get { return m_DragSources.Count > 0; } } - public Dictionary startDragPositions { get { return m_StartDragPositions; } } - - public Func canDrop { private get; set; } - public Action receiveDrop { private get; set; } - public Func getDropObject { private get; set; } - - public event Action dropHoverStarted; - public event Action dropHoverEnded; - - public event Action dragStarted; - public event Action dragging; - public event Action dragEnded; - - public event Action click; - public event Action doubleClick; - - public event Action hoverStarted; - public event Action hovering; - public event Action hoverEnded; - - void Awake() - { - // Put this object in the UI layer so that it is hit by UI raycasts - gameObject.layer = LayerMask.NameToLayer("UI"); - } - - void OnDisable() - { - if (m_HoverSources.Count > 0 || m_DragSources.Count > 0) - { - var eventData = GetHandleEventData(new RayEventData(EventSystem.current)); - var sources = new List(m_HoverSources); - m_HoverSources.Clear(); - foreach (var rayOrigin in sources) - { - eventData.rayOrigin = rayOrigin; - OnHandleHoverEnded(eventData); - } - - sources.Clear(); - sources.AddRange(m_DragSources); - m_DragSources.Clear(); - foreach (var rayOrigin in sources) - { - eventData.rayOrigin = rayOrigin; - OnHandleDragEnded(eventData); - } - } - } - - protected virtual HandleEventData GetHandleEventData(RayEventData eventData) - { - return new HandleEventData(eventData.rayOrigin, UIUtils.IsDirectEvent(eventData)); - } - - public int IndexOfHoverSource(Transform rayOrigin) - { - return m_HoverSources.IndexOf(rayOrigin); - } - - public int IndexOfDragSource(Transform rayOrigin) - { - return m_DragSources.IndexOf(rayOrigin); - } - - public void OnBeginDrag(RayEventData eventData) - { - if (!UIUtils.IsValidEvent(eventData, selectionFlags)) - return; - - var rayOrigin = eventData.rayOrigin; - m_DragSources.Add(rayOrigin); - startDragPositions[rayOrigin] = eventData.pointerCurrentRaycast.worldPosition; - - var handleEventData = GetHandleEventData(eventData); - - //Double-click logic - DateTime lastClickTime; - if (!m_LastClickTimes.TryGetValue(rayOrigin, out lastClickTime)) - m_LastClickTimes[rayOrigin] = new DateTime(); - - var timeSinceLastClick = (float)(DateTime.Now - lastClickTime).TotalSeconds; - m_LastClickTimes[rayOrigin] = DateTime.Now; - if (UIUtils.IsDoubleClick(timeSinceLastClick)) - OnDoubleClick(handleEventData); - - OnHandleDragStarted(handleEventData); - } - - public void OnDrag(RayEventData eventData) - { - if (m_DragSources.Count > 0) - OnHandleDragging(GetHandleEventData(eventData)); - } - - public void OnEndDrag(RayEventData eventData) - { - if (m_DragSources.Remove(eventData.rayOrigin)) - OnHandleDragEnded(GetHandleEventData(eventData)); - } - - public void OnRayEnter(RayEventData eventData) - { - if (!UIUtils.IsValidEvent(eventData, selectionFlags)) - return; - - m_HoverSources.Add(eventData.rayOrigin); - OnHandleHoverStarted(GetHandleEventData(eventData)); - } - - public void OnRayHover(RayEventData eventData) - { - var handleEventData = GetHandleEventData(eventData); - - // Direct selection has special handling for enter/exit since those events may not have been called - // because the pointer wasn't close enough to the handle - if (selectionFlags == SelectionFlags.Direct) - { - if (!handleEventData.direct && m_HoverSources.Remove(eventData.rayOrigin)) - { - OnHandleHoverEnded(handleEventData); - return; - } - - if (handleEventData.direct && !m_HoverSources.Contains(eventData.rayOrigin)) - { - m_HoverSources.Add(eventData.rayOrigin); - OnHandleHoverStarted(handleEventData); - } - } - - if (m_HoverSources.Count > 0) - OnHandleHovering(GetHandleEventData(eventData)); - } - - public void OnRayExit(RayEventData eventData) - { - if (m_HoverSources.Remove(eventData.rayOrigin)) - OnHandleHoverEnded(GetHandleEventData(eventData)); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleHoverStarted(HandleEventData eventData) - { - if (hoverStarted != null) - hoverStarted(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleHovering(HandleEventData eventData) - { - if (hovering != null) - hovering(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleHoverEnded(HandleEventData eventData) - { - if (hoverEnded != null) - hoverEnded(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleDragStarted(HandleEventData eventData) - { - if (dragStarted != null) - dragStarted(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleDragging(HandleEventData eventData) - { - if (dragging != null) - dragging(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnHandleDragEnded(HandleEventData eventData) - { - if (dragEnded != null) - dragEnded(this, eventData); - } - - /// - /// Override to modify event data prior to raising event (requires calling base method at the end) - /// - protected virtual void OnDoubleClick(HandleEventData eventData) - { - if (doubleClick != null) - doubleClick(this, eventData); - } - - public void OnPointerClick(PointerEventData eventData) - { - if (click != null) - click(this, eventData); - } - - public virtual bool CanDrop(object dropObject) - { - if (canDrop != null) - return canDrop(this, dropObject); - - return false; - } - - public virtual void ReceiveDrop(object dropObject) - { - if (receiveDrop != null) - receiveDrop(this, dropObject); - } - - public virtual object GetDropObject() - { - if (!this) // If this handle has ben destroyed, return null; - return null; - - if (getDropObject != null) - return getDropObject(this); - - return null; - } - - public void OnDropHoverStarted() - { - if (dropHoverStarted != null) - dropHoverStarted(this); - } - - public void OnDropHoverEnded() - { - if (dropHoverEnded != null) - dropHoverEnded(this); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + /// + /// Base class for providing draggable handles in 3D (requires PhysicsRaycaster) + /// + class BaseHandle : MonoBehaviour, ISelectionFlags, IRayBeginDragHandler, IRayDragHandler, IRayEndDragHandler, + IRayEnterHandler, IRayExitHandler, IRayHoverHandler, IPointerClickHandler, IDropReceiver, IDroppable + { + protected const int k_DefaultCapacity = 2; // i.e. 2 controllers + + public SelectionFlags selectionFlags + { + get { return m_SelectionFlags; } + set { m_SelectionFlags = value; } + } + + [SerializeField] + [FlagsProperty] + SelectionFlags m_SelectionFlags = SelectionFlags.Ray | SelectionFlags.Direct; + + protected readonly List m_HoverSources = new List(k_DefaultCapacity); + protected readonly List m_DragSources = new List(k_DefaultCapacity); + protected readonly Dictionary m_StartDragPositions = new Dictionary(k_DefaultCapacity); + protected readonly Dictionary m_LastClickTimes = new Dictionary(k_DefaultCapacity); + + public bool hasHoverSource { get { return m_HoverSources.Count > 0; } } + public bool hasDragSource { get { return m_DragSources.Count > 0; } } + public Dictionary startDragPositions { get { return m_StartDragPositions; } } + + public Func canDrop { private get; set; } + public Action receiveDrop { private get; set; } + public Func getDropObject { private get; set; } + + public event Action dropHoverStarted; + public event Action dropHoverEnded; + + public event Action dragStarted; + public event Action dragging; + public event Action dragEnded; + + public event Action click; + public event Action doubleClick; + + public event Action hoverStarted; + public event Action hovering; + public event Action hoverEnded; + + // Local method use only -- created here to reduce garbage collection + static readonly HandleEventData k_HandleEventData = new HandleEventData(null, false); + + void Awake() + { + // Put this object in the UI layer so that it is hit by UI raycasts + gameObject.layer = LayerMask.NameToLayer("UI"); + } + + void OnDisable() + { + if (m_HoverSources.Count > 0 || m_DragSources.Count > 0) + { + var eventData = GetHandleEventData(new RayEventData(EventSystem.current)); + var sources = new List(m_HoverSources); + m_HoverSources.Clear(); + foreach (var rayOrigin in sources) + { + eventData.rayOrigin = rayOrigin; + OnHandleHoverEnded(eventData); + } + + sources.Clear(); + sources.AddRange(m_DragSources); + m_DragSources.Clear(); + foreach (var rayOrigin in sources) + { + eventData.rayOrigin = rayOrigin; + OnHandleDragEnded(eventData); + } + } + } + + protected virtual HandleEventData GetHandleEventData(RayEventData eventData) + { + k_HandleEventData.rayOrigin = eventData.rayOrigin; + k_HandleEventData.direct = UIUtils.IsDirectEvent(eventData); + return k_HandleEventData; + } + + public int IndexOfHoverSource(Transform rayOrigin) + { + return m_HoverSources.IndexOf(rayOrigin); + } + + public int IndexOfDragSource(Transform rayOrigin) + { + return m_DragSources.IndexOf(rayOrigin); + } + + public void OnBeginDrag(RayEventData eventData) + { + if (!UIUtils.IsValidEvent(eventData, selectionFlags)) + return; + + var rayOrigin = eventData.rayOrigin; + m_DragSources.Add(rayOrigin); + startDragPositions[rayOrigin] = eventData.pointerCurrentRaycast.worldPosition; + + var handleEventData = GetHandleEventData(eventData); + + //Double-click logic + DateTime lastClickTime; + if (!m_LastClickTimes.TryGetValue(rayOrigin, out lastClickTime)) + m_LastClickTimes[rayOrigin] = new DateTime(); + + var timeSinceLastClick = (float)(DateTime.Now - lastClickTime).TotalSeconds; + m_LastClickTimes[rayOrigin] = DateTime.Now; + if (UIUtils.IsDoubleClick(timeSinceLastClick)) + OnDoubleClick(handleEventData); + + OnHandleDragStarted(handleEventData); + } + + public void OnDrag(RayEventData eventData) + { + if (m_DragSources.Count > 0) + OnHandleDragging(GetHandleEventData(eventData)); + } + + public void OnEndDrag(RayEventData eventData) + { + if (m_DragSources.Remove(eventData.rayOrigin)) + OnHandleDragEnded(GetHandleEventData(eventData)); + } + + public void OnRayEnter(RayEventData eventData) + { + if (!UIUtils.IsValidEvent(eventData, selectionFlags)) + return; + + m_HoverSources.Add(eventData.rayOrigin); + OnHandleHoverStarted(GetHandleEventData(eventData)); + } + + public void OnRayHover(RayEventData eventData) + { + var handleEventData = GetHandleEventData(eventData); + + // Direct selection has special handling for enter/exit since those events may not have been called + // because the pointer wasn't close enough to the handle + if (selectionFlags == SelectionFlags.Direct) + { + if (!handleEventData.direct && m_HoverSources.Remove(eventData.rayOrigin)) + { + OnHandleHoverEnded(handleEventData); + return; + } + + if (handleEventData.direct && !m_HoverSources.Contains(eventData.rayOrigin)) + { + m_HoverSources.Add(eventData.rayOrigin); + OnHandleHoverStarted(handleEventData); + } + } + + if (m_HoverSources.Count > 0) + OnHandleHovering(GetHandleEventData(eventData)); + } + + public void OnRayExit(RayEventData eventData) + { + if (m_HoverSources.Remove(eventData.rayOrigin)) + OnHandleHoverEnded(GetHandleEventData(eventData)); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleHoverStarted(HandleEventData eventData) + { + if (hoverStarted != null) + hoverStarted(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleHovering(HandleEventData eventData) + { + if (hovering != null) + hovering(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleHoverEnded(HandleEventData eventData) + { + if (hoverEnded != null) + hoverEnded(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleDragStarted(HandleEventData eventData) + { + if (dragStarted != null) + dragStarted(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleDragging(HandleEventData eventData) + { + if (dragging != null) + dragging(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnHandleDragEnded(HandleEventData eventData) + { + if (dragEnded != null) + dragEnded(this, eventData); + } + + /// + /// Override to modify event data prior to raising event (requires calling base method at the end) + /// + protected virtual void OnDoubleClick(HandleEventData eventData) + { + if (doubleClick != null) + doubleClick(this, eventData); + } + + public void OnPointerClick(PointerEventData eventData) + { + if (click != null) + click(this, eventData); + } + + public virtual bool CanDrop(object dropObject) + { + if (canDrop != null) + return canDrop(this, dropObject); + + return false; + } + + public virtual void ReceiveDrop(object dropObject) + { + if (receiveDrop != null) + receiveDrop(this, dropObject); + } + + public virtual object GetDropObject() + { + if (!this) // If this handle has ben destroyed, return null; + return null; + + if (getDropObject != null) + return getDropObject(this); + + return null; + } + + public void OnDropHoverStarted() + { + if (dropHoverStarted != null) + dropHoverStarted(this); + } + + public void OnDropHoverEnded() + { + if (dropHoverEnded != null) + dropHoverEnded(this); + } + } +} +#endif diff --git a/Scripts/Handles/LinearHandle.cs b/Scripts/Handles/LinearHandle.cs index 6a9a1b668..d23cc86ab 100644 --- a/Scripts/Handles/LinearHandle.cs +++ b/Scripts/Handles/LinearHandle.cs @@ -1,108 +1,115 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.UI; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - sealed class LinearHandle : BaseHandle, IAxisConstraints, IUsesViewerScale - { - const float k_MaxDragDistance = 1000f; - - internal class LinearHandleEventData : HandleEventData - { - public Vector3 raycastHitWorldPosition; - - public LinearHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} - } - - [SerializeField] - bool m_OrientDragPlaneToRay = true; - - [FlagsProperty] - [SerializeField] - AxisFlags m_Constraints; - - readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); - - Plane m_Plane; - - public AxisFlags constraints { get { return m_Constraints; } } - - protected override HandleEventData GetHandleEventData(RayEventData eventData) - { - return new LinearHandleEventData(eventData.rayOrigin, UIUtils.IsDirectEvent(eventData)) { raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition }; - } - - void UpdateEventData(LinearHandleEventData eventData, bool setLastPosition = true) - { - var rayOrigin = eventData.rayOrigin; - var lastPosition = m_LastPositions[rayOrigin]; - var worldPosition = lastPosition; - - if (m_OrientDragPlaneToRay) - { - // Orient a plane for dragging purposes through the axis that rotates to avoid being parallel to the ray, - // so that you can prevent intersections at infinity - var forward = Quaternion.Inverse(transform.rotation) * (rayOrigin.position - transform.position); - forward.z = 0; - m_Plane.SetNormalAndPosition(transform.rotation * forward.normalized, transform.position); - } - else - { - m_Plane.SetNormalAndPosition(transform.up, transform.position); - } - - float distance; - var ray = new Ray(rayOrigin.position, rayOrigin.forward); - if (m_Plane.Raycast(ray, out distance)) - worldPosition = ray.GetPoint(Mathf.Min(distance, k_MaxDragDistance * this.GetViewerScale())); - - eventData.raycastHitWorldPosition = worldPosition; - - eventData.deltaPosition = Vector3.Project(worldPosition - lastPosition, transform.forward); - - if (setLastPosition) - m_LastPositions[rayOrigin] = worldPosition; - } - - protected override void OnHandleHoverStarted(HandleEventData eventData) - { - var linearEventData = (LinearHandleEventData)eventData; - - m_LastPositions[eventData.rayOrigin] = linearEventData.raycastHitWorldPosition; - - if (m_DragSources.Count == 0) - UpdateEventData(linearEventData); - - base.OnHandleHoverStarted(eventData); - } - - protected override void OnHandleHovering(HandleEventData eventData) - { - if (m_DragSources.Count == 0) - UpdateEventData((LinearHandleEventData)eventData); - - base.OnHandleHovering(eventData); - } - - protected override void OnHandleDragStarted(HandleEventData eventData) - { - var linearEventData = (LinearHandleEventData)eventData; - m_LastPositions[eventData.rayOrigin] = linearEventData.raycastHitWorldPosition; - UpdateEventData(linearEventData); - - base.OnHandleDragStarted(eventData); - } - - protected override void OnHandleDragging(HandleEventData eventData) - { - UpdateEventData((LinearHandleEventData)eventData); - - base.OnHandleDragging(eventData); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + sealed class LinearHandle : BaseHandle, IAxisConstraints, IUsesViewerScale + { + const float k_MaxDragDistance = 1000f; + + internal class LinearHandleEventData : HandleEventData + { + public Vector3 raycastHitWorldPosition; + + public LinearHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} + } + + [SerializeField] + bool m_OrientDragPlaneToRay = true; + + [FlagsProperty] + [SerializeField] + AxisFlags m_Constraints; + + readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); + + Plane m_Plane; + + public AxisFlags constraints { get { return m_Constraints; } } + + // Local method use only -- created here to reduce garbage collection + static readonly LinearHandleEventData k_LinearHandleEventData = new LinearHandleEventData(null, false); + + protected override HandleEventData GetHandleEventData(RayEventData eventData) + { + k_LinearHandleEventData.rayOrigin = eventData.rayOrigin; + k_LinearHandleEventData.direct = UIUtils.IsDirectEvent(eventData); + k_LinearHandleEventData.raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition; + + return k_LinearHandleEventData; + } + + void UpdateEventData(LinearHandleEventData eventData, bool setLastPosition = true) + { + var rayOrigin = eventData.rayOrigin; + var lastPosition = m_LastPositions[rayOrigin]; + var worldPosition = lastPosition; + + if (m_OrientDragPlaneToRay) + { + // Orient a plane for dragging purposes through the axis that rotates to avoid being parallel to the ray, + // so that you can prevent intersections at infinity + var forward = Quaternion.Inverse(transform.rotation) * (rayOrigin.position - transform.position); + forward.z = 0; + m_Plane.SetNormalAndPosition(transform.rotation * forward.normalized, transform.position); + } + else + { + m_Plane.SetNormalAndPosition(transform.up, transform.position); + } + + float distance; + var ray = new Ray(rayOrigin.position, rayOrigin.forward); + if (m_Plane.Raycast(ray, out distance)) + worldPosition = ray.GetPoint(Mathf.Min(distance, k_MaxDragDistance * this.GetViewerScale())); + + eventData.raycastHitWorldPosition = worldPosition; + + eventData.deltaPosition = Vector3.Project(worldPosition - lastPosition, transform.forward); + + if (setLastPosition) + m_LastPositions[rayOrigin] = worldPosition; + } + + protected override void OnHandleHoverStarted(HandleEventData eventData) + { + var linearEventData = (LinearHandleEventData)eventData; + + m_LastPositions[eventData.rayOrigin] = linearEventData.raycastHitWorldPosition; + + if (m_DragSources.Count == 0) + UpdateEventData(linearEventData); + + base.OnHandleHoverStarted(eventData); + } + + protected override void OnHandleHovering(HandleEventData eventData) + { + if (m_DragSources.Count == 0) + UpdateEventData((LinearHandleEventData)eventData); + + base.OnHandleHovering(eventData); + } + + protected override void OnHandleDragStarted(HandleEventData eventData) + { + var linearEventData = (LinearHandleEventData)eventData; + m_LastPositions[eventData.rayOrigin] = linearEventData.raycastHitWorldPosition; + UpdateEventData(linearEventData); + + base.OnHandleDragStarted(eventData); + } + + protected override void OnHandleDragging(HandleEventData eventData) + { + UpdateEventData((LinearHandleEventData)eventData); + + base.OnHandleDragging(eventData); + } + } +} +#endif diff --git a/Scripts/Handles/PlaneHandle.cs b/Scripts/Handles/PlaneHandle.cs index 3d26822e4..7930b3091 100644 --- a/Scripts/Handles/PlaneHandle.cs +++ b/Scripts/Handles/PlaneHandle.cs @@ -1,69 +1,76 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.UI; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - sealed class PlaneHandle : BaseHandle, IAxisConstraints, IUsesViewerScale - { - const float k_MaxDragDistance = 1000f; - - class PlaneHandleEventData : HandleEventData - { - public Vector3 raycastHitWorldPosition; - - public PlaneHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} - } - - [FlagsProperty] - [SerializeField] - AxisFlags m_Constraints; - - Plane m_Plane; - readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); - - public AxisFlags constraints { get { return m_Constraints; } } - - protected override HandleEventData GetHandleEventData(RayEventData eventData) - { - return new PlaneHandleEventData(eventData.rayOrigin, UIUtils.IsDirectEvent(eventData)) { raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition }; - } - - protected override void OnHandleDragStarted(HandleEventData eventData) - { - var planeEventData = eventData as PlaneHandleEventData; - m_LastPositions[eventData.rayOrigin] = planeEventData.raycastHitWorldPosition; - - m_Plane.SetNormalAndPosition(transform.forward, transform.position); - - base.OnHandleDragStarted(eventData); - } - - protected override void OnHandleDragging(HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - - var lastPosition = m_LastPositions[eventData.rayOrigin]; - var worldPosition = lastPosition; - - float distance; - var ray = new Ray(rayOrigin.position, rayOrigin.forward); - if (m_Plane.Raycast(ray, out distance)) - worldPosition = ray.GetPoint(Mathf.Min(Mathf.Abs(distance), k_MaxDragDistance * this.GetViewerScale())); - - var deltaPosition = worldPosition - lastPosition; - m_LastPositions[eventData.rayOrigin] = worldPosition; - - deltaPosition = transform.InverseTransformVector(deltaPosition); - deltaPosition.z = 0; - deltaPosition = transform.TransformVector(deltaPosition); - eventData.deltaPosition = deltaPosition; - - base.OnHandleDragging(eventData); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + sealed class PlaneHandle : BaseHandle, IAxisConstraints, IUsesViewerScale + { + const float k_MaxDragDistance = 1000f; + + class PlaneHandleEventData : HandleEventData + { + public Vector3 raycastHitWorldPosition; + + public PlaneHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} + } + + [FlagsProperty] + [SerializeField] + AxisFlags m_Constraints; + + Plane m_Plane; + readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); + + public AxisFlags constraints { get { return m_Constraints; } } + + // Local method use only -- created here to reduce garbage collection + static readonly PlaneHandleEventData k_LinearHandleEventData = new PlaneHandleEventData(null, false); + + protected override HandleEventData GetHandleEventData(RayEventData eventData) + { + k_LinearHandleEventData.rayOrigin = eventData.rayOrigin; + k_LinearHandleEventData.direct = UIUtils.IsDirectEvent(eventData); + k_LinearHandleEventData.raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition; + + return k_LinearHandleEventData; + } + + protected override void OnHandleDragStarted(HandleEventData eventData) + { + var planeEventData = eventData as PlaneHandleEventData; + m_LastPositions[eventData.rayOrigin] = planeEventData.raycastHitWorldPosition; + + m_Plane.SetNormalAndPosition(transform.forward, transform.position); + + base.OnHandleDragStarted(eventData); + } + + protected override void OnHandleDragging(HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + + var lastPosition = m_LastPositions[eventData.rayOrigin]; + var worldPosition = lastPosition; + + float distance; + var ray = new Ray(rayOrigin.position, rayOrigin.forward); + if (m_Plane.Raycast(ray, out distance)) + worldPosition = ray.GetPoint(Mathf.Min(Mathf.Abs(distance), k_MaxDragDistance * this.GetViewerScale())); + + var deltaPosition = worldPosition - lastPosition; + m_LastPositions[eventData.rayOrigin] = worldPosition; + + deltaPosition = transform.InverseTransformVector(deltaPosition); + deltaPosition.z = 0; + deltaPosition = transform.TransformVector(deltaPosition); + eventData.deltaPosition = deltaPosition; + + base.OnHandleDragging(eventData); + } + } +} +#endif diff --git a/Scripts/Handles/RadialHandle.cs b/Scripts/Handles/RadialHandle.cs index 7dd692fd5..ca18349b3 100644 --- a/Scripts/Handles/RadialHandle.cs +++ b/Scripts/Handles/RadialHandle.cs @@ -1,68 +1,75 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - sealed class RadialHandle : BaseHandle - { - internal class RadialHandleEventData : HandleEventData - { - public Vector3 raycastHitWorldPosition; - - public RadialHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} - } - - [SerializeField] - float m_TurnSpeed; - - Plane m_Plane; - readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); - readonly Dictionary m_LastDragForwards = new Dictionary(k_DefaultCapacity); - - protected override HandleEventData GetHandleEventData(RayEventData eventData) - { - return new RadialHandleEventData(eventData.rayOrigin, UIUtils.IsDirectEvent(eventData)) { raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition }; - } - - protected override void OnHandleDragStarted(HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - - var radialEventData = (RadialHandleEventData)eventData; - m_LastPositions[rayOrigin] = radialEventData.raycastHitWorldPosition; - m_LastDragForwards[rayOrigin] = rayOrigin.forward; - - m_Plane.SetNormalAndPosition(rayOrigin.forward, transform.position); - - base.OnHandleDragStarted(eventData); - } - - protected override void OnHandleDragging(HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - - var lastPosition = m_LastPositions[rayOrigin]; - var lastDragForward = m_LastDragForwards[rayOrigin]; - var worldPosition = lastPosition; - - float distance; - var ray = new Ray(rayOrigin.position, rayOrigin.forward); - if (m_Plane.Raycast(ray, out distance)) - worldPosition = ray.GetPoint(Mathf.Abs(distance)); - - var dragTangent = Vector3.Cross(transform.up, (startDragPositions[rayOrigin] - transform.position).normalized); - var angle = m_TurnSpeed * Vector3.Angle(rayOrigin.forward, lastDragForward) * - Vector3.Dot((worldPosition - lastPosition).normalized, dragTangent); - eventData.deltaRotation = Quaternion.AngleAxis(angle, transform.up); - - m_LastPositions[rayOrigin] = worldPosition; - m_LastDragForwards[rayOrigin] = rayOrigin.forward; - - base.OnHandleDragging(eventData); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + sealed class RadialHandle : BaseHandle + { + internal class RadialHandleEventData : HandleEventData + { + public Vector3 raycastHitWorldPosition; + + public RadialHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} + } + + [SerializeField] + float m_TurnSpeed; + + Plane m_Plane; + readonly Dictionary m_LastPositions = new Dictionary(k_DefaultCapacity); + readonly Dictionary m_LastDragForwards = new Dictionary(k_DefaultCapacity); + + // Local method use only -- created here to reduce garbage collection + static readonly RadialHandleEventData k_RadialHandleEventData = new RadialHandleEventData(null, false); + + protected override HandleEventData GetHandleEventData(RayEventData eventData) + { + k_RadialHandleEventData.rayOrigin = eventData.rayOrigin; + k_RadialHandleEventData.direct = UIUtils.IsDirectEvent(eventData); + k_RadialHandleEventData.raycastHitWorldPosition = eventData.pointerCurrentRaycast.worldPosition; + + return k_RadialHandleEventData; + } + + protected override void OnHandleDragStarted(HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + + var radialEventData = (RadialHandleEventData)eventData; + m_LastPositions[rayOrigin] = radialEventData.raycastHitWorldPosition; + m_LastDragForwards[rayOrigin] = rayOrigin.forward; + + m_Plane.SetNormalAndPosition(rayOrigin.forward, transform.position); + + base.OnHandleDragStarted(eventData); + } + + protected override void OnHandleDragging(HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + + var lastPosition = m_LastPositions[rayOrigin]; + var lastDragForward = m_LastDragForwards[rayOrigin]; + var worldPosition = lastPosition; + + float distance; + var ray = new Ray(rayOrigin.position, rayOrigin.forward); + if (m_Plane.Raycast(ray, out distance)) + worldPosition = ray.GetPoint(Mathf.Abs(distance)); + + var dragTangent = Vector3.Cross(transform.up, (startDragPositions[rayOrigin] - transform.position).normalized); + var angle = m_TurnSpeed * Vector3.Angle(rayOrigin.forward, lastDragForward) * + Vector3.Dot((worldPosition - lastPosition).normalized, dragTangent); + eventData.deltaRotation = Quaternion.AngleAxis(angle, transform.up); + + m_LastPositions[rayOrigin] = worldPosition; + m_LastDragForwards[rayOrigin] = rayOrigin.forward; + + base.OnHandleDragging(eventData); + } + } +} +#endif diff --git a/Scripts/Handles/SphereHandle.cs b/Scripts/Handles/SphereHandle.cs index 2e1bf2c5b..4c9c90bf2 100644 --- a/Scripts/Handles/SphereHandle.cs +++ b/Scripts/Handles/SphereHandle.cs @@ -1,96 +1,103 @@ -#if UNITY_EDITOR -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.EventSystems; - -namespace UnityEditor.Experimental.EditorVR.Handles -{ - sealed class SphereHandle : BaseHandle, IScrollHandler, IUsesViewerScale - { - const float k_MaxSphereRadius = 1000f; - - class SphereHandleEventData : HandleEventData - { - public float raycastHitDistance; - - public SphereHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} - } - - const float k_InitialScrollRate = 2f; - const float k_ScrollAcceleration = 14f; - - const float k_DistanceScale = 0.1f; - - float m_ScrollRate; - Vector3 m_LastPosition; - float m_CurrentRadius; - - protected override HandleEventData GetHandleEventData(RayEventData eventData) - { - return new SphereHandleEventData(eventData.rayOrigin, UIUtils.IsDirectEvent(eventData)) { raycastHitDistance = eventData.pointerCurrentRaycast.distance }; - } - - protected override void OnHandleDragStarted(HandleEventData eventData) - { - var sphereEventData = (SphereHandleEventData)eventData; - - var rayOrigin = eventData.rayOrigin; - if (IndexOfDragSource(rayOrigin) == 0) - { - m_CurrentRadius = sphereEventData.raycastHitDistance; - m_ScrollRate = k_InitialScrollRate; - m_LastPosition = GetRayPoint(eventData); - - base.OnHandleDragStarted(eventData); - } - } - - protected override void OnHandleDragging(HandleEventData eventData) - { - if (IndexOfDragSource(eventData.rayOrigin) == 0) - { - var worldPosition = GetRayPoint(eventData); - eventData.deltaPosition = worldPosition - m_LastPosition; - m_LastPosition = worldPosition; - - base.OnHandleDragging(eventData); - } - } - - protected override void OnHandleDragEnded(HandleEventData eventData) - { - if (!hasDragSource) - base.OnHandleDragEnded(eventData); - } - - public void ChangeRadius(float delta) - { - var distance = Vector3.Distance(CameraUtils.GetMainCamera().transform.position, transform.position); - m_CurrentRadius += delta * distance * k_DistanceScale; - m_CurrentRadius = Mathf.Clamp(m_CurrentRadius, 0f, k_MaxSphereRadius * this.GetViewerScale()); - } - - public void OnScroll(PointerEventData eventData) - { - if (m_DragSources.Count == 0) - return; - - // Scrolling changes the radius of the sphere while dragging, and accelerates - if (Mathf.Abs(eventData.scrollDelta.y) > 0.5f) - m_ScrollRate += Mathf.Abs(eventData.scrollDelta.y) * k_ScrollAcceleration * Time.deltaTime; - else - m_ScrollRate = k_InitialScrollRate; - - ChangeRadius(m_ScrollRate * eventData.scrollDelta.y * Time.deltaTime); - } - - Vector3 GetRayPoint(HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - var ray = new Ray(rayOrigin.position, rayOrigin.forward); - return ray.GetPoint(m_CurrentRadius); - } - } -} -#endif +#if UNITY_EDITOR +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UnityEditor.Experimental.EditorVR.Handles +{ + sealed class SphereHandle : BaseHandle, IScrollHandler, IUsesViewerScale + { + const float k_MaxSphereRadius = 1000f; + + class SphereHandleEventData : HandleEventData + { + public float raycastHitDistance; + + public SphereHandleEventData(Transform rayOrigin, bool direct) : base(rayOrigin, direct) {} + } + + const float k_InitialScrollRate = 2f; + const float k_ScrollAcceleration = 14f; + + const float k_DistanceScale = 0.1f; + + float m_ScrollRate; + Vector3 m_LastPosition; + float m_CurrentRadius; + + // Local method use only -- created here to reduce garbage collection + static readonly SphereHandleEventData k_SphereHandleEventData = new SphereHandleEventData(null, false); + + protected override HandleEventData GetHandleEventData(RayEventData eventData) + { + k_SphereHandleEventData.rayOrigin = eventData.rayOrigin; + k_SphereHandleEventData.direct = UIUtils.IsDirectEvent(eventData); + k_SphereHandleEventData.raycastHitDistance = eventData.pointerCurrentRaycast.distance; + + return k_SphereHandleEventData; + } + + protected override void OnHandleDragStarted(HandleEventData eventData) + { + var sphereEventData = (SphereHandleEventData)eventData; + + var rayOrigin = eventData.rayOrigin; + if (IndexOfDragSource(rayOrigin) == 0) + { + m_CurrentRadius = sphereEventData.raycastHitDistance; + m_ScrollRate = k_InitialScrollRate; + m_LastPosition = GetRayPoint(eventData); + + base.OnHandleDragStarted(eventData); + } + } + + protected override void OnHandleDragging(HandleEventData eventData) + { + if (IndexOfDragSource(eventData.rayOrigin) == 0) + { + var worldPosition = GetRayPoint(eventData); + eventData.deltaPosition = worldPosition - m_LastPosition; + m_LastPosition = worldPosition; + + base.OnHandleDragging(eventData); + } + } + + protected override void OnHandleDragEnded(HandleEventData eventData) + { + if (!hasDragSource) + base.OnHandleDragEnded(eventData); + } + + public void ChangeRadius(float delta) + { + var distance = Vector3.Distance(CameraUtils.GetMainCamera().transform.position, transform.position); + m_CurrentRadius += delta * distance * k_DistanceScale; + m_CurrentRadius = Mathf.Clamp(m_CurrentRadius, 0f, k_MaxSphereRadius * this.GetViewerScale()); + } + + public void OnScroll(PointerEventData eventData) + { + if (m_DragSources.Count == 0) + return; + + // Scrolling changes the radius of the sphere while dragging, and accelerates + if (Mathf.Abs(eventData.scrollDelta.y) > 0.5f) + m_ScrollRate += Mathf.Abs(eventData.scrollDelta.y) * k_ScrollAcceleration * Time.deltaTime; + else + m_ScrollRate = k_InitialScrollRate; + + ChangeRadius(m_ScrollRate * eventData.scrollDelta.y * Time.deltaTime); + } + + Vector3 GetRayPoint(HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + var ray = new Ray(rayOrigin.position, rayOrigin.forward); + return ray.GetPoint(m_CurrentRadius); + } + } +} +#endif diff --git a/Scripts/Interfaces/Capability/IFeedbackReceiver.cs b/Scripts/Interfaces/Capability/IFeedbackReceiver.cs index 06d7c9e1d..abe6c0871 100644 --- a/Scripts/Interfaces/Capability/IFeedbackReceiver.cs +++ b/Scripts/Interfaces/Capability/IFeedbackReceiver.cs @@ -1,29 +1,30 @@ -#if UNITY_EDITOR -namespace UnityEditor.Experimental.EditorVR -{ - /// - /// Implementors can receive Feedback Requests - /// - public interface IFeedbackReceiver - { - /// - /// Add a feedback request to be presented by this receiver - /// - /// Information about the request, usually cast to a custom type defined by the receiver - void AddFeedbackRequest(FeedbackRequest request); - - /// - /// Remove a feedback request and stop presenting it - /// - /// The request object used in AddFeedbackRequest - void RemoveFeedbackRequest(FeedbackRequest request); - - /// - /// Clear feedback requests that were added by this caller. - /// The FeedbackModule can also call this with a null argument, signaling the intent to clear all requests from all callers. - /// - /// The IRequestFeedback whose requests will be cleared - void ClearFeedbackRequests(IRequestFeedback caller); - } -} -#endif +#if UNITY_EDITOR + +namespace UnityEditor.Experimental.EditorVR +{ + /// + /// Implementors can receive Feedback Requests + /// + public interface IFeedbackReceiver + { + /// + /// Add a feedback request to be presented by this receiver + /// + /// Information about the request, usually cast to a custom type defined by the receiver + void AddFeedbackRequest(FeedbackRequest request); + + /// + /// Remove a feedback request and stop presenting it + /// + /// The request object used in AddFeedbackRequest + void RemoveFeedbackRequest(FeedbackRequest request); + + /// + /// Clear feedback requests that were added by this caller. + /// The FeedbackModule can also call this with a null argument, signaling the intent to clear all requests from all callers. + /// + /// The IRequestFeedback whose requests will be cleared + void ClearFeedbackRequests(IRequestFeedback caller); + } +} +#endif diff --git a/Scripts/Interfaces/FunctionalityInjection/IPoly.cs b/Scripts/Interfaces/FunctionalityInjection/IPoly.cs new file mode 100644 index 000000000..29a21bc49 --- /dev/null +++ b/Scripts/Interfaces/FunctionalityInjection/IPoly.cs @@ -0,0 +1,51 @@ +#if UNITY_EDITOR +using System; +using UnityEditor.Experimental.EditorVR; + +#if INCLUDE_POLY_TOOLKIT +using System.Collections.Generic; +using PolyToolkit; +using UnityEditor.Experimental.EditorVR.Workspaces; +#endif + +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + +namespace UnityEditor.Experimental.EditorVR +{ + /// + /// Provides access to the Poly Module + /// + public interface IPoly + { + } + +#if INCLUDE_POLY_TOOLKIT + public static class IPolyMethods + { + internal delegate void GetFeaturedModelsDelegate(PolyOrderBy orderBy, PolyMaxComplexityFilter complexity, + PolyFormatFilter? format, PolyCategory category, int requestSize, List assets, + Action listCallback, string nextPageToken = null); + + internal static GetFeaturedModelsDelegate getAssetList; + + /// + /// Get a list of assets + /// + /// The sorting order of the results + /// The max complexity of assets to request + /// The format of assets to request + /// The category of assets to request + /// The number of assets to request + /// The list of poly assets to add the results to + /// A method which is called when the list is returned + /// (optional) The next page token to pick up on an existing list + public static void GetAssetList(this IPoly obj, PolyOrderBy orderBy, PolyMaxComplexityFilter complexity, + PolyFormatFilter? format, PolyCategory category, int requestSize, List + assets, Action listCallback, string nextPageToken = null) + { + getAssetList(orderBy, complexity, format, category, requestSize, assets, listCallback, nextPageToken); + } + } +#endif +} +#endif diff --git a/Scripts/Interfaces/FunctionalityInjection/IPoly.cs.meta b/Scripts/Interfaces/FunctionalityInjection/IPoly.cs.meta new file mode 100644 index 000000000..de3855ead --- /dev/null +++ b/Scripts/Interfaces/FunctionalityInjection/IPoly.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: c94c2010ae9b3d8498815e718ebb232f +timeCreated: 1510616351 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Interfaces/FunctionalityInjection/IRequestFeedback.cs b/Scripts/Interfaces/FunctionalityInjection/IRequestFeedback.cs index d6e57d28c..73163487f 100644 --- a/Scripts/Interfaces/FunctionalityInjection/IRequestFeedback.cs +++ b/Scripts/Interfaces/FunctionalityInjection/IRequestFeedback.cs @@ -1,48 +1,57 @@ -#if UNITY_EDITOR -using System; - -namespace UnityEditor.Experimental.EditorVR -{ - public interface IRequestFeedback - { - } - - public static class IRequestFeedbackMethods - { - public static Action addFeedbackRequest { private get; set; } - public static Action removeFeedbackRequest { private get; set; } - public static Action clearFeedbackRequests { private get; set; } - - /// - /// Add a feedback request to the system - /// - /// The caller object - /// The feedback request - public static void AddFeedbackRequest(this IRequestFeedback obj, FeedbackRequest request) - { - request.caller = obj; - addFeedbackRequest(request); - } - - /// - /// Remove a feedback request from the system - /// - /// The caller object - /// The feedback request - public static void RemoveFeedbackRequest(this IRequestFeedback obj, FeedbackRequest request) - { - request.caller = obj; - removeFeedbackRequest(request); - } - - /// - /// Clear all feedback requests submitted by this caller from the system - /// - /// The caller object - public static void ClearFeedbackRequests(this IRequestFeedback obj) - { - clearFeedbackRequests(obj); - } - } -} -#endif +#if UNITY_EDITOR +using System; + +namespace UnityEditor.Experimental.EditorVR +{ + public interface IRequestFeedback + { + } + + public static class IRequestFeedbackMethods + { + public static Action addFeedbackRequest { private get; set; } + public static Action removeFeedbackRequest { private get; set; } + public static Action clearFeedbackRequests { private get; set; } + public static Func getFeedbackRequestObject { private get; set; } + + /// + /// Add a feedback request to the system + /// + /// The caller object + /// The feedback request + public static void AddFeedbackRequest(this IRequestFeedback obj, FeedbackRequest request) + { + request.caller = obj; + addFeedbackRequest(request); + } + + /// + /// Remove a feedback request from the system + /// + /// The caller object + /// The feedback request + public static void RemoveFeedbackRequest(this IRequestFeedback obj, FeedbackRequest request) + { + request.caller = obj; + removeFeedbackRequest(request); + } + + /// + /// Clear all feedback requests submitted by this caller from the system + /// + /// The caller object + public static void ClearFeedbackRequests(this IRequestFeedback obj) + { + clearFeedbackRequests(obj); + } + + /// + /// Get a pooled FeedbackRequest object from the system + /// + public static FeedbackRequest GetFeedbackRequestObject(this IRequestFeedback obj, Type type) + { + return getFeedbackRequestObject(type); + } + } +} +#endif diff --git a/Scripts/Interfaces/FunctionalityInjection/IUsesDeviceType.cs b/Scripts/Interfaces/FunctionalityInjection/IUsesDeviceType.cs index 8783d579a..25ed4dd4d 100644 --- a/Scripts/Interfaces/FunctionalityInjection/IUsesDeviceType.cs +++ b/Scripts/Interfaces/FunctionalityInjection/IUsesDeviceType.cs @@ -1,33 +1,38 @@ -#if UNITY_EDITOR -using System; -using UnityEngine.XR; - -namespace UnityEditor.Experimental.EditorVR -{ - public enum DeviceType - { - Oculus, - Vive - } - - /// - /// In cases where you must have different input logic (e.g. button press + axis input) you can get the device type - /// - public interface IUsesDeviceType - { - } - - public static class IUsesDeviceTypeMethods - { - /// - /// Returns the type of device currently in use - /// - /// The device type - public static DeviceType GetDeviceType(this IUsesDeviceType @this) - { - return XRDevice.model.IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0 - ? DeviceType.Oculus : DeviceType.Vive; - } - } -} -#endif +#if UNITY_EDITOR +using System; +using UnityEngine.XR; + +namespace UnityEditor.Experimental.EditorVR +{ + public enum DeviceType + { + Oculus, + Vive + } + + /// + /// In cases where you must have different input logic (e.g. button press + axis input) you can get the device type + /// + public interface IUsesDeviceType + { + } + + public static class IUsesDeviceTypeMethods + { + static string s_XRDeviceModel; + + /// + /// Returns the type of device currently in use + /// + /// The device type + public static DeviceType GetDeviceType(this IUsesDeviceType @this) + { + if (string.IsNullOrEmpty(s_XRDeviceModel)) + s_XRDeviceModel = XRDevice.model; + + return s_XRDeviceModel.IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0 + ? DeviceType.Oculus : DeviceType.Vive; + } + } +} +#endif diff --git a/Scripts/Interfaces/FunctionalityInjection/IWeb.cs b/Scripts/Interfaces/FunctionalityInjection/IWeb.cs new file mode 100644 index 000000000..58e4708a5 --- /dev/null +++ b/Scripts/Interfaces/FunctionalityInjection/IWeb.cs @@ -0,0 +1,53 @@ +#if UNITY_EDITOR +using System; +using UnityEngine.Networking; + +namespace UnityEditor.Experimental.EditorVR +{ + /// + /// Provides access to the Web Module + /// + public interface IWeb + { + } + + public static class IWebMethods + { + // TODO: Template support for Functionality Injection + internal static Action> download; + internal static Action> downloadTexture; + internal static Action downloadToDisk; + + /// + /// Download the given URL + /// + /// The URL to request + /// A method to be called on completion + public static void Download(this IWeb obj, string url, Action completed) + { + download(url, completed); + } + + /// + /// Download the given URL using a DownloadTextureHandler + /// + /// The URL to request + /// A method to be called on completion + public static void DownloadTexture(this IWeb obj, string url, Action completed) + { + downloadTexture(url, completed); + } + + /// + /// Download the given URL to a file on disk + /// + /// The URL to request + /// The file in which to store the results + /// A method to be called on completion + public static void Download(this IWeb obj, string url, string destination, Action completed) + { + downloadToDisk(url, destination, completed); + } + } +} +#endif diff --git a/Scripts/Interfaces/FunctionalityInjection/IWeb.cs.meta b/Scripts/Interfaces/FunctionalityInjection/IWeb.cs.meta new file mode 100644 index 000000000..6bd65359b --- /dev/null +++ b/Scripts/Interfaces/FunctionalityInjection/IWeb.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d753cad90c7d5b146b12fa6dd6e8fb86 +timeCreated: 1505157406 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset b/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset new file mode 100644 index 000000000..65936fc3f --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1efd705dfe960584581b3390e04777f1, type: 3} + m_Name: ListViewItemClickPulse + m_EditorClassIdentifier: + m_Duration: 0.5 + m_Intensity: 0.4 + m_FadeIn: 1 + m_FadeOut: 1 diff --git a/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset.meta b/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset.meta new file mode 100644 index 000000000..c7fa99137 --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemClickPulse.asset.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 72c68844f1d53f549976daae6a207100 +timeCreated: 1496975270 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset b/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset new file mode 100644 index 000000000..75d43a42f --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1efd705dfe960584581b3390e04777f1, type: 3} + m_Name: ListViewItemDragStartPulse + m_EditorClassIdentifier: + m_Duration: 0.5 + m_Intensity: 0.3 + m_FadeIn: 1 + m_FadeOut: 1 diff --git a/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset.meta b/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset.meta new file mode 100644 index 000000000..16de0e90b --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemDragStartPulse.asset.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0df1c3251269d8a41a11a33faf676222 +timeCreated: 1496968525 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset b/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset new file mode 100644 index 000000000..85be83f98 --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1efd705dfe960584581b3390e04777f1, type: 3} + m_Name: ListViewItemDraggingPulse + m_EditorClassIdentifier: + m_Duration: 0.25 + m_Intensity: 0.15 + m_FadeIn: 0 + m_FadeOut: 1 diff --git a/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset.meta b/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset.meta new file mode 100644 index 000000000..38dd70a24 --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemDraggingPulse.asset.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ccd598d3356a834e87a36e7111cb173 +timeCreated: 1497398097 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset b/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset new file mode 100644 index 000000000..6b840752b --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1efd705dfe960584581b3390e04777f1, type: 3} + m_Name: ListViewItemHoverStartPulse + m_EditorClassIdentifier: + m_Duration: 0.005 + m_Intensity: 0.6 + m_FadeIn: 0 + m_FadeOut: 0 diff --git a/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset.meta b/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset.meta new file mode 100644 index 000000000..9a0e0d6fa --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListViewItemHoverStartPulse.asset.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d71c4adadeb37984aa5f37d8c0096997 +timeCreated: 1496973884 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset b/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset new file mode 100644 index 000000000..5c4b9e527 --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1efd705dfe960584581b3390e04777f1, type: 3} + m_Name: ListviewItemDragEndPulse + m_EditorClassIdentifier: + m_Duration: 0.75 + m_Intensity: 0.2 + m_FadeIn: 0 + m_FadeOut: 1 diff --git a/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset.meta b/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset.meta new file mode 100644 index 000000000..6d762e8f2 --- /dev/null +++ b/Scripts/ListView/HapticPulses/ListviewItemDragEndPulse.asset.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 64a535853bdb5b24f8d196dedeea8cba +timeCreated: 1496968454 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListView/ListViewController.cs b/Scripts/ListView/ListViewController.cs index 0096a9b4e..8bafc8383 100644 --- a/Scripts/ListView/ListViewController.cs +++ b/Scripts/ListView/ListViewController.cs @@ -1,11 +1,14 @@ #if UNITY_EDITOR +using System; using System.Collections.Generic; using UnityEditor.Experimental.EditorVR; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Workspaces; using UnityEngine; namespace ListView { - public abstract class ListViewController : ListViewControllerBase, IInstantiateUI, IConnectInterfaces + public abstract class ListViewController : ListViewControllerBase, IInstantiateUI, IConnectInterfaces, IControlHaptics, IRayToNode where TData : ListViewItemData where TItem : ListViewItem { @@ -29,6 +32,25 @@ public virtual List data } } + [Header("Unassigned haptic pulses will not be performed")] + [SerializeField] + HapticPulse m_ItemClickPulse; + + [SerializeField] + HapticPulse m_ItemHoverStartPulse; + + [SerializeField] + HapticPulse m_ItemHoverEndPulse; + + [SerializeField] + HapticPulse m_ItemDragStartPulse; + + [SerializeField] + HapticPulse m_ItemDraggingPulse; + + [SerializeField] + HapticPulse m_ItemDragEndPulse; + protected List m_Data; protected readonly Dictionary> m_TemplateDictionary = new Dictionary>(); @@ -43,10 +65,12 @@ protected override void Setup() { Debug.LogError("No templates!"); } + foreach (var template in m_Templates) { if (m_TemplateDictionary.ContainsKey(template.name)) Debug.LogError("Two templates cannot have the same name"); + m_TemplateDictionary[template.name] = new ListViewItemTemplate(template); } } @@ -159,6 +183,14 @@ protected virtual TItem GetItem(TData data) item = this.InstantiateUI(m_TemplateDictionary[data.template].prefab, transform, false).GetComponent(); this.ConnectInterfaces(item); item.Setup(data); + + // Hookup input events for new items. + item.hoverStart += OnItemHoverStart; + item.hoverEnd += OnItemHoverEnd; + item.dragStart += OnItemDragStart; + item.dragging += OnItemDragging; + item.dragEnd += OnItemDragEnd; + item.click += OnItemClicked; } m_ListItems[data.index] = item; @@ -169,6 +201,42 @@ protected virtual TItem GetItem(TData data) return item; } + + public void OnItemHoverStart(Node node) + { + if (m_ItemHoverStartPulse) + this.Pulse(node, m_ItemHoverStartPulse); + } + + public void OnItemHoverEnd(Node node) + { + if (m_ItemHoverEndPulse) + this.Pulse(node, m_ItemHoverEndPulse); + } + + public void OnItemDragStart(Node node) + { + if (m_ItemDragStartPulse) + this.Pulse(node, m_ItemDragStartPulse); + } + + public void OnItemDragging(Node node) + { + if (m_ItemDraggingPulse) + this.Pulse(node, m_ItemDraggingPulse); + } + + public void OnItemDragEnd(Node node) + { + if (m_ItemDragEndPulse) + this.Pulse(node, m_ItemDragEndPulse); + } + + public void OnItemClicked(Node node) + { + if (m_ItemClickPulse) + this.Pulse(node, m_ItemClickPulse); + } } } #endif diff --git a/Scripts/ListView/ListViewItem.cs b/Scripts/ListView/ListViewItem.cs index bc40f34d2..94e3b10b9 100644 --- a/Scripts/ListView/ListViewItem.cs +++ b/Scripts/ListView/ListViewItem.cs @@ -1,5 +1,6 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; +using UnityEditor.Experimental.EditorVR; using UnityEngine; namespace ListView @@ -11,6 +12,13 @@ public class ListViewItem : MonoBehaviour where TData : ListViewI public Action endSettling { protected get; set; } public Func> getListItem { protected get; set; } + public Action click { get; set; } + public Action hoverStart { get; set; } + public Action hoverEnd { get; set; } + public Action dragStart { get; set; } + public Action dragging { get; set; } + public Action dragEnd { get; set; } + public virtual void Setup(TData data) { this.data = data; diff --git a/Scripts/Modules/FeedbackModule/FeedbackModule.cs b/Scripts/Modules/FeedbackModule/FeedbackModule.cs index 58c34b9c0..e98ef4c69 100644 --- a/Scripts/Modules/FeedbackModule/FeedbackModule.cs +++ b/Scripts/Modules/FeedbackModule/FeedbackModule.cs @@ -1,158 +1,197 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Handles; -using UnityEngine; -using UnityEngine.UI; - -namespace UnityEditor.Experimental.EditorVR -{ - public abstract class FeedbackRequest - { - public IRequestFeedback caller; - } - - public class FeedbackModule : MonoBehaviour, ISettingsMenuItemProvider, ISerializePreferences - { - [Serializable] - class Preferences - { - [SerializeField] - bool m_Enabled = true; - - public bool enabled - { - get { return m_Enabled; } - set { m_Enabled = value; } - } - } - - [SerializeField] - GameObject m_SettingsMenuItemPrefab; - - readonly List m_Toggles = new List(); - - Preferences m_Preferences; - - readonly List m_FeedbackReceivers = new List(); - - public GameObject settingsMenuItemPrefab { get { return m_SettingsMenuItemPrefab; } } - - public GameObject settingsMenuItemInstance - { - set - { - var toggle = value.GetComponent(); - if (m_Preferences != null) - toggle.isOn = m_Preferences.enabled; - - m_Toggles.Add(toggle); - var label = value.GetComponentInChildren(); - - const string feedbackEnabled = "Feedback enabled"; - const string feedbackDisabled = "Feedback disabled"; - const string enableFeedback = "Enable feedback"; - const string disableFeedback = "Disable feedback"; - - toggle.onValueChanged.AddListener(isOn => - { - label.text = isOn ? feedbackEnabled : feedbackDisabled; - SetEnabled(isOn); - }); - - var handle = value.GetComponent(); - handle.hoverStarted += (baseHandle, data) => { label.text = m_Preferences.enabled ? disableFeedback : enableFeedback; }; - handle.hoverEnded += (baseHandle, data) => { label.text = m_Preferences.enabled ? feedbackEnabled : feedbackDisabled; }; - } - } - - public Transform rayOrigin { get { return null; } } - - void Awake() - { - IRequestFeedbackMethods.addFeedbackRequest = AddFeedbackRequest; - IRequestFeedbackMethods.removeFeedbackRequest = RemoveFeedbackRequest; - IRequestFeedbackMethods.clearFeedbackRequests = ClearFeedbackRequests; - } - - void Start() - { - if (m_Preferences == null) - m_Preferences = new Preferences(); - } - - public void AddReceiver(IFeedbackReceiver feedbackReceiver) - { - m_FeedbackReceivers.Add(feedbackReceiver); - } - - public void RemoveReceiver(IFeedbackReceiver feedbackReceiver) - { - m_FeedbackReceivers.Remove(feedbackReceiver); - } - - void SetEnabled(bool enabled) - { - if (m_Preferences.enabled != enabled) - { - m_Preferences.enabled = enabled; - if (!enabled) - { - foreach (var receiver in m_FeedbackReceivers) - { - receiver.ClearFeedbackRequests(null); - } - } - } - } - - void AddFeedbackRequest(FeedbackRequest request) - { - if (!m_Preferences.enabled) - return; - - foreach (var receiver in m_FeedbackReceivers) - { - receiver.AddFeedbackRequest(request); - } - } - - void RemoveFeedbackRequest(FeedbackRequest request) - { - foreach (var receiver in m_FeedbackReceivers) - { - receiver.RemoveFeedbackRequest(request); - } - } - - void ClearFeedbackRequests(IRequestFeedback caller) - { - if (caller == null) // Requesters are not allowed to clear all requests - return; - - foreach (var receiver in m_FeedbackReceivers) - { - receiver.ClearFeedbackRequests(caller); - } - } - - public object OnSerializePreferences() - { - return m_Preferences; - } - - public void OnDeserializePreferences(object obj) - { - var preferences = obj as Preferences; - if (preferences != null) - m_Preferences = preferences; - - foreach (var toggle in m_Toggles) - { - toggle.isOn = m_Preferences.enabled; - } - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.Experimental.EditorVR +{ + public abstract class FeedbackRequest + { + public IRequestFeedback caller; + + public abstract void Reset(); + } + + public class FeedbackModule : MonoBehaviour, ISettingsMenuItemProvider, ISerializePreferences + { + [Serializable] + class Preferences + { + [SerializeField] + bool m_Enabled = true; + + public bool enabled + { + get { return m_Enabled; } + set { m_Enabled = value; } + } + } + + [SerializeField] + GameObject m_SettingsMenuItemPrefab; + + readonly List m_Toggles = new List(); + + Preferences m_Preferences; + + readonly List m_FeedbackReceivers = new List(); + + public GameObject settingsMenuItemPrefab { get { return m_SettingsMenuItemPrefab; } } + + public GameObject settingsMenuItemInstance + { + set + { + var toggle = value.GetComponent(); + if (m_Preferences != null) + toggle.isOn = m_Preferences.enabled; + + m_Toggles.Add(toggle); + var label = value.GetComponentInChildren(); + + const string feedbackEnabled = "Feedback enabled"; + const string feedbackDisabled = "Feedback disabled"; + const string enableFeedback = "Enable feedback"; + const string disableFeedback = "Disable feedback"; + + toggle.onValueChanged.AddListener(isOn => + { + label.text = isOn ? feedbackEnabled : feedbackDisabled; + SetEnabled(isOn); + }); + + var handle = value.GetComponent(); + handle.hoverStarted += (baseHandle, data) => { label.text = m_Preferences.enabled ? disableFeedback : enableFeedback; }; + handle.hoverEnded += (baseHandle, data) => { label.text = m_Preferences.enabled ? feedbackEnabled : feedbackDisabled; }; + } + } + + public Transform rayOrigin { get { return null; } } + + readonly Dictionary> m_FeedbackRequestPool = new Dictionary>(); + + void Awake() + { + IRequestFeedbackMethods.addFeedbackRequest = AddFeedbackRequest; + IRequestFeedbackMethods.removeFeedbackRequest = RemoveFeedbackRequest; + IRequestFeedbackMethods.clearFeedbackRequests = ClearFeedbackRequests; + IRequestFeedbackMethods.getFeedbackRequestObject = GetFeedbackRequestObject; + } + + void Start() + { + if (m_Preferences == null) + m_Preferences = new Preferences(); + } + + public void AddReceiver(IFeedbackReceiver feedbackReceiver) + { + m_FeedbackReceivers.Add(feedbackReceiver); + } + + public void RemoveReceiver(IFeedbackReceiver feedbackReceiver) + { + m_FeedbackReceivers.Remove(feedbackReceiver); + } + + void SetEnabled(bool enabled) + { + if (m_Preferences.enabled != enabled) + { + m_Preferences.enabled = enabled; + if (!enabled) + { + foreach (var receiver in m_FeedbackReceivers) + { + receiver.ClearFeedbackRequests(null); + } + } + } + } + + void AddFeedbackRequest(FeedbackRequest request) + { + if (!m_Preferences.enabled) + return; + + foreach (var receiver in m_FeedbackReceivers) + { + receiver.AddFeedbackRequest(request); + } + } + + void RemoveFeedbackRequest(FeedbackRequest request) + { + foreach (var receiver in m_FeedbackReceivers) + { + receiver.RemoveFeedbackRequest(request); + } + + RecycleFeedbackRequestObject(request); + } + + void ClearFeedbackRequests(IRequestFeedback caller) + { + if (caller == null) // Requesters are not allowed to clear all requests + return; + + foreach (var receiver in m_FeedbackReceivers) + { + receiver.ClearFeedbackRequests(caller); + } + } + + FeedbackRequest GetFeedbackRequestObject(Type type) + { + Queue pool; + if (!m_FeedbackRequestPool.TryGetValue(type, out pool)) + { + pool = new Queue(); + m_FeedbackRequestPool[type] = pool; + } + + if (pool.Count > 0) + { + var request = pool.Dequeue(); + request.Reset(); + return request; + } + + return (FeedbackRequest)Activator.CreateInstance(type); + } + + void RecycleFeedbackRequestObject(FeedbackRequest request) + { + var type = request.GetType(); + Queue pool; + if (!m_FeedbackRequestPool.TryGetValue(type, out pool)) + { + pool = new Queue(); + m_FeedbackRequestPool[type] = pool; + } + + pool.Enqueue(request); + } + + public object OnSerializePreferences() + { + return m_Preferences; + } + + public void OnDeserializePreferences(object obj) + { + var preferences = obj as Preferences; + if (preferences != null) + m_Preferences = preferences; + + foreach (var toggle in m_Toggles) + { + toggle.isOn = m_Preferences.enabled; + } + } + } +} +#endif diff --git a/Scripts/Modules/MultipleRayInputModule/MultipleRayInputModule.cs b/Scripts/Modules/MultipleRayInputModule/MultipleRayInputModule.cs index 958632640..555e02271 100644 --- a/Scripts/Modules/MultipleRayInputModule/MultipleRayInputModule.cs +++ b/Scripts/Modules/MultipleRayInputModule/MultipleRayInputModule.cs @@ -1,525 +1,522 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.UI; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Modules -{ - // Based in part on code provided by VREAL at https://github.com/VREALITY/ViveUGUIModule/, which is licensed under the MIT License - sealed class MultipleRayInputModule : BaseInputModule, IUsesPointer, IConnectInterfaces - { - public class RaycastSource : ICustomActionMap, IRequestFeedback - { - public IProxy proxy; // Needed for checking if proxy is active - public Transform rayOrigin; - public Node node; - public RayEventData eventData; - public GameObject hoveredObject; - public GameObject draggedObject; - public bool blocked; - public Func isValid; - - MultipleRayInputModule m_Owner; - readonly List m_ScrollFeedback = new List(); - - public GameObject currentObject { get { return hoveredObject ? hoveredObject : draggedObject; } } - - public bool hasObject { get { return currentObject != null && (s_LayerMask & (1 << currentObject.layer)) != 0; } } - - public ActionMap actionMap { get { return m_Owner.m_UIActionMap; } } - public bool ignoreLocking { get { return false; } } - - public RaycastSource(IProxy proxy, Transform rayOrigin, Node node, MultipleRayInputModule owner, Func validationCallback) - { - this.proxy = proxy; - this.rayOrigin = rayOrigin; - this.node = node; - m_Owner = owner; - isValid = validationCallback; - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - if (!(rayOrigin.gameObject.activeSelf || draggedObject) || !proxy.active) - return; - - var preProcessRaycastSource = m_Owner.preProcessRaycastSource; - if (preProcessRaycastSource != null) - preProcessRaycastSource(rayOrigin); - - if (eventData == null) - eventData = new RayEventData(m_Owner.eventSystem); - - hoveredObject = m_Owner.GetRayIntersection(this); // Check all currently running raycasters - - eventData.node = node; - eventData.rayOrigin = rayOrigin; - eventData.pointerLength = m_Owner.GetPointerLength(eventData.rayOrigin); - - var uiActions = (UIActions)input; - var select = uiActions.select; - - if (isValid != null && !isValid(this)) - { - var currentRaycast = eventData.pointerCurrentRaycast; - currentRaycast.gameObject = null; - eventData.pointerCurrentRaycast = currentRaycast; - hoveredObject = null; - m_Owner.HandlePointerExitAndEnter(eventData, null, true); // Send only exit events - - if (select.wasJustReleased) - m_Owner.OnSelectReleased(this); - - HideScrollFeedback(); - - return; - } - - m_Owner.HandlePointerExitAndEnter(eventData, hoveredObject); // Send enter and exit events - - var hasScrollHandler = false; - var hasInteractable = hasObject && HoveringInteractable(eventData, currentObject, out hasScrollHandler); - - // Proceed only if pointer is interacting with something - if (!hasInteractable) - { - // If we have an object, the ray is blocked--input should not bleed through - if (hasObject && select.wasJustPressed) - consumeControl(select); - - HideScrollFeedback(); - - if (select.wasJustReleased) - m_Owner.OnSelectReleased(this); - - return; - } - - // Send select pressed and released events - if (select.wasJustPressed) - { - m_Owner.OnSelectPressed(this); - consumeControl(select); - } - - if (select.wasJustReleased) - m_Owner.OnSelectReleased(this); - - // Send Drag Events - if (draggedObject != null) - { - ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.dragHandler); - ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.dragHandler); - } - - // Send scroll events - if (currentObject && hasScrollHandler) - { - var verticalScroll = uiActions.verticalScroll; - var horizontalScroll = uiActions.horizontalScroll; - var verticalScrollValue = verticalScroll.value; - var horizontalScrollValue = horizontalScroll.value; - if (!Mathf.Approximately(verticalScrollValue, 0f) || !Mathf.Approximately(horizontalScrollValue, 0f)) - { - consumeControl(verticalScroll); - consumeControl(horizontalScroll); - eventData.scrollDelta = new Vector2(horizontalScrollValue, verticalScrollValue); - ExecuteEvents.ExecuteHierarchy(currentObject, eventData, ExecuteEvents.scrollHandler); - } - - if (m_ScrollFeedback.Count == 0) - ShowScrollFeedback(); - } - } - - void ShowFeedback(List requests, string controlName, string tooltipText = null) - { - if (tooltipText == null) - tooltipText = controlName; - - List ids; - if (m_Owner.m_Controls.TryGetValue(controlName, out ids)) - { - foreach (var id in ids) - { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - tooltipText = tooltipText - }; - - this.AddFeedbackRequest(request); - requests.Add(request); - } - } - } - - void ShowScrollFeedback() - { - ShowFeedback(m_ScrollFeedback, "VerticalScroll", "Scroll"); - } - - void HideFeedback(List requests) - { - foreach (var request in requests) - { - this.RemoveFeedbackRequest(request); - } - requests.Clear(); - } - - void HideScrollFeedback() - { - HideFeedback(m_ScrollFeedback); - } - } - - static LayerMask s_LayerMask; - - readonly Dictionary m_RaycastSources = new Dictionary(); - - Camera m_EventCamera; - - [SerializeField] - ActionMap m_UIActionMap; - - public Camera eventCamera - { - get { return m_EventCamera; } - set { m_EventCamera = value; } - } - - public LayerMask layerMask - { - get { return s_LayerMask; } - set { s_LayerMask = value; } - } - - public event Action rayEntered; - public event Action rayHovering; - public event Action rayExited; - public event Action dragStarted; - public event Action dragEnded; - - public Action preProcessRaycastSource { private get; set; } - - readonly BindingDictionary m_Controls = new BindingDictionary(); - - // Local method use only -- created here to reduce garbage collection - RayEventData m_TempRayEvent; - - protected override void Awake() - { - base.Awake(); - - s_LayerMask = LayerMask.GetMask("UI"); - m_TempRayEvent = new RayEventData(eventSystem); - InputUtils.GetBindingDictionaryFromActionMap(m_UIActionMap, m_Controls); - } - - protected override void OnDestroy() - { - foreach (var source in m_RaycastSources) - { - this.DisconnectInterfaces(source); - } - } - - public void AddRaycastSource(IProxy proxy, Node node, Transform rayOrigin, Func validationCallback = null) - { - var source = new RaycastSource(proxy, rayOrigin, node, this, validationCallback); - this.ConnectInterfaces(source, rayOrigin); - m_RaycastSources.Add(rayOrigin, source); - } - - public RayEventData GetPointerEventData(Transform rayOrigin) - { - RaycastSource source; - if (m_RaycastSources.TryGetValue(rayOrigin, out source)) - return source.eventData; - - return null; - } - - public override void Process() - { - ExecuteUpdateOnSelectedObject(); - - if (m_EventCamera == null) - return; - - // World scaling also scales clipping planes - var camera = CameraUtils.GetMainCamera(); - m_EventCamera.nearClipPlane = camera.nearClipPlane; - m_EventCamera.farClipPlane = camera.farClipPlane; - } - - static bool HoveringInteractable(RayEventData eventData, GameObject currentObject, out bool hasScrollHandler) - { - hasScrollHandler = false; - - var selectionFlags = ComponentUtils.GetComponent(currentObject); - if (selectionFlags != null && selectionFlags.selectionFlags == SelectionFlags.Direct && !UIUtils.IsDirectEvent(eventData)) - return false; - - hasScrollHandler = ExecuteEvents.GetEventHandler(currentObject); - - return ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || ExecuteEvents.GetEventHandler(currentObject) - || hasScrollHandler; - } - - RayEventData GetTempEventDataClone(RayEventData eventData) - { - var clone = m_TempRayEvent; - clone.rayOrigin = eventData.rayOrigin; - clone.node = eventData.node; - clone.hovered.Clear(); - clone.hovered.AddRange(eventData.hovered); - clone.pointerEnter = eventData.pointerEnter; - clone.pointerCurrentRaycast = eventData.pointerCurrentRaycast; - clone.pointerLength = eventData.pointerLength; - - return clone; - } - - void HandlePointerExitAndEnter(RayEventData eventData, GameObject newEnterTarget, bool exitOnly = false) - { - // Cache properties before executing base method, so we can complete additional ray events later - var cachedEventData = GetTempEventDataClone(eventData); - - // This will modify the event data (new target will be set) - base.HandlePointerExitAndEnter(eventData, newEnterTarget); - - var pointerEnter = cachedEventData.pointerEnter; - if (newEnterTarget == null || pointerEnter == null) - { - for (var i = 0; i < cachedEventData.hovered.Count; ++i) - { - var hovered = cachedEventData.hovered[i]; - - ExecuteEvents.Execute(hovered, eventData, ExecuteRayEvents.rayExitHandler); - if (rayExited != null) - rayExited(hovered, eventData); - } - - if (newEnterTarget == null) - return; - } - - if (!exitOnly) - { - // if we have not changed hover target - if (newEnterTarget && pointerEnter == newEnterTarget) - { - var transform = newEnterTarget.transform; - while (transform != null) - { - ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayHoverHandler); - if (rayHovering != null) - rayHovering(transform.gameObject, cachedEventData); - - transform = transform.parent; - } - return; - } - } - - var commonRoot = FindCommonRoot(pointerEnter, newEnterTarget); - - // and we already an entered object from last time - if (pointerEnter != null) - { - // send exit handler call to all elements in the chain - // until we reach the new target, or null! - var transform = pointerEnter.transform; - - while (transform != null) - { - // if we reach the common root break out! - if (commonRoot != null && commonRoot.transform == transform) - break; - - ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayExitHandler); - if (rayExited != null) - rayExited(transform.gameObject, cachedEventData); - - transform = transform.parent; - } - } - - if (!exitOnly) - { - // now issue the enter call up to but not including the common root - cachedEventData.pointerEnter = newEnterTarget; - var transform = newEnterTarget.transform; - while (transform != null && transform.gameObject != commonRoot) - { - ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayEnterHandler); - if (rayEntered != null) - rayEntered(transform.gameObject, cachedEventData); - - transform = transform.parent; - } - } - } - - void OnSelectPressed(RaycastSource source) - { - Deselect(); - - var eventData = source.eventData; - var hoveredObject = source.hoveredObject; - eventData.pressPosition = eventData.position; - eventData.pointerPressRaycast = eventData.pointerCurrentRaycast; - eventData.pointerPress = hoveredObject; - - if (hoveredObject != null) // Pressed when pointer is over something - { - var draggedObject = hoveredObject; - var newPressed = ExecuteEvents.ExecuteHierarchy(draggedObject, eventData, ExecuteEvents.pointerDownHandler); - - if (newPressed == null) // Gameobject does not have pointerDownHandler in hierarchy, but may still have click handler - newPressed = ExecuteEvents.GetEventHandler(draggedObject); - - if (newPressed != null) - { - draggedObject = newPressed; // Set current pressed to gameObject that handles the pointerDown event, not the root object - Select(draggedObject); - eventData.eligibleForClick = true; - - // Track clicks for double-clicking, triple-clicking, etc. - float time = Time.realtimeSinceStartup; - if (newPressed == eventData.lastPress) - { - var diffTime = time - eventData.clickTime; - if (UIUtils.IsDoubleClick(diffTime)) - ++eventData.clickCount; - else - eventData.clickCount = 1; - } - else - { - eventData.clickCount = 1; - } - eventData.clickTime = time; - } - - ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.beginDragHandler); - ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.beginDragHandler); - eventData.dragging = true; - if (dragStarted != null) - dragStarted(draggedObject, eventData); - - eventData.pointerDrag = draggedObject; - source.draggedObject = draggedObject; - } - } - - void OnSelectReleased(RaycastSource source) - { - var eventData = source.eventData; - var hoveredObject = source.hoveredObject; - - if (source.draggedObject) - ExecuteEvents.Execute(source.draggedObject, eventData, ExecuteEvents.pointerUpHandler); - - if (source.draggedObject) - { - var draggedObject = source.draggedObject; - if (dragEnded != null) - dragEnded(draggedObject, eventData); - - ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.endDragHandler); - ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.endDragHandler); - - if (hoveredObject != null) - ExecuteEvents.ExecuteHierarchy(hoveredObject, eventData, ExecuteEvents.dropHandler); - - eventData.pointerDrag = null; - } - - var clickHandler = ExecuteEvents.GetEventHandler(hoveredObject); - if (source.draggedObject == clickHandler && eventData.eligibleForClick) - ExecuteEvents.Execute(clickHandler, eventData, ExecuteEvents.pointerClickHandler); - - eventData.dragging = false; - eventData.rawPointerPress = null; - eventData.pointerPress = null; - eventData.eligibleForClick = false; - source.draggedObject = null; - } - - public void Deselect() - { - if (eventSystem.currentSelectedGameObject) - eventSystem.SetSelectedGameObject(null); - } - - void Select(GameObject go) - { - Deselect(); - - if (ExecuteEvents.GetEventHandler(go)) - eventSystem.SetSelectedGameObject(go); - } - - GameObject GetRayIntersection(RaycastSource source) - { - // Move camera to position and rotation for the ray origin - m_EventCamera.transform.position = source.rayOrigin.position; - m_EventCamera.transform.rotation = source.rayOrigin.rotation; - - var eventData = source.eventData; - eventData.Reset(); - eventData.delta = Vector2.zero; - eventData.position = m_EventCamera.pixelRect.center; - eventData.scrollDelta = Vector2.zero; - - eventSystem.RaycastAll(eventData, m_RaycastResultCache); - eventData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache); - var hit = eventData.pointerCurrentRaycast.gameObject; - - m_RaycastResultCache.Clear(); - return hit; - } - - bool ExecuteUpdateOnSelectedObject() - { - if (eventSystem.currentSelectedGameObject == null) - return false; - - var eventData = GetBaseEventData(); - ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, eventData, ExecuteEvents.updateSelectedHandler); - return eventData.used; - } - - public bool IsHoveringOverUI(Transform rayOrigin) - { - RaycastSource source; - return m_RaycastSources.TryGetValue(rayOrigin, out source) && source.hasObject; - } - - public void SetUIBlockedForRayOrigin(Transform rayOrigin, bool blocked) - { - RaycastSource source; - if (m_RaycastSources.TryGetValue(rayOrigin, out source)) - source.blocked = blocked; - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Modules +{ + // Based in part on code provided by VREAL at https://github.com/VREALITY/ViveUGUIModule/, which is licensed under the MIT License + sealed class MultipleRayInputModule : BaseInputModule, IUsesPointer, IConnectInterfaces + { + public class RaycastSource : ICustomActionMap, IRequestFeedback + { + public IProxy proxy; // Needed for checking if proxy is active + public Transform rayOrigin; + public Node node; + public RayEventData eventData; + public GameObject hoveredObject; + public GameObject draggedObject; + public bool blocked; + public Func isValid; + + MultipleRayInputModule m_Owner; + readonly List m_ScrollFeedback = new List(); + + public GameObject currentObject { get { return hoveredObject ? hoveredObject : draggedObject; } } + + public bool hasObject { get { return currentObject != null && (s_LayerMask & (1 << currentObject.layer)) != 0; } } + + public ActionMap actionMap { get { return m_Owner.m_UIActionMap; } } + public bool ignoreLocking { get { return false; } } + + public RaycastSource(IProxy proxy, Transform rayOrigin, Node node, MultipleRayInputModule owner, Func validationCallback) + { + this.proxy = proxy; + this.rayOrigin = rayOrigin; + this.node = node; + m_Owner = owner; + isValid = validationCallback; + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + if (!(rayOrigin.gameObject.activeSelf || draggedObject) || !proxy.active) + return; + + var preProcessRaycastSource = m_Owner.preProcessRaycastSource; + if (preProcessRaycastSource != null) + preProcessRaycastSource(rayOrigin); + + if (eventData == null) + eventData = new RayEventData(m_Owner.eventSystem); + + hoveredObject = m_Owner.GetRayIntersection(this); // Check all currently running raycasters + + eventData.node = node; + eventData.rayOrigin = rayOrigin; + eventData.pointerLength = m_Owner.GetPointerLength(eventData.rayOrigin); + + var uiActions = (UIActions)input; + var select = uiActions.select; + + if (isValid != null && !isValid(this)) + { + var currentRaycast = eventData.pointerCurrentRaycast; + currentRaycast.gameObject = null; + eventData.pointerCurrentRaycast = currentRaycast; + hoveredObject = null; + m_Owner.HandlePointerExitAndEnter(eventData, null, true); // Send only exit events + + if (select.wasJustReleased) + m_Owner.OnSelectReleased(this); + + HideScrollFeedback(); + + return; + } + + m_Owner.HandlePointerExitAndEnter(eventData, hoveredObject); // Send enter and exit events + + var hasScrollHandler = false; + var hasInteractable = hasObject && HoveringInteractable(eventData, currentObject, out hasScrollHandler); + + // Proceed only if pointer is interacting with something + if (!hasInteractable) + { + // If we have an object, the ray is blocked--input should not bleed through + if (hasObject && select.wasJustPressed) + consumeControl(select); + + HideScrollFeedback(); + + if (select.wasJustReleased) + m_Owner.OnSelectReleased(this); + + return; + } + + // Send select pressed and released events + if (select.wasJustPressed) + { + m_Owner.OnSelectPressed(this); + consumeControl(select); + } + + if (select.wasJustReleased) + m_Owner.OnSelectReleased(this); + + // Send Drag Events + if (draggedObject != null) + { + ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.dragHandler); + ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.dragHandler); + } + + // Send scroll events + if (currentObject && hasScrollHandler) + { + var verticalScroll = uiActions.verticalScroll; + var horizontalScroll = uiActions.horizontalScroll; + var verticalScrollValue = verticalScroll.value; + var horizontalScrollValue = horizontalScroll.value; + if (!Mathf.Approximately(verticalScrollValue, 0f) || !Mathf.Approximately(horizontalScrollValue, 0f)) + { + consumeControl(verticalScroll); + consumeControl(horizontalScroll); + eventData.scrollDelta = new Vector2(horizontalScrollValue, verticalScrollValue); + ExecuteEvents.ExecuteHierarchy(currentObject, eventData, ExecuteEvents.scrollHandler); + } + + if (m_ScrollFeedback.Count == 0) + ShowScrollFeedback(); + } + } + + void ShowFeedback(List requests, string controlName, string tooltipText = null) + { + if (tooltipText == null) + tooltipText = controlName; + + List ids; + if (m_Owner.m_Controls.TryGetValue(controlName, out ids)) + { + foreach (var id in ids) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.tooltipText = tooltipText; + requests.Add(request); + this.AddFeedbackRequest(request); + } + } + } + + void ShowScrollFeedback() + { + ShowFeedback(m_ScrollFeedback, "VerticalScroll", "Scroll"); + } + + void HideFeedback(List requests) + { + foreach (var request in requests) + { + this.RemoveFeedbackRequest(request); + } + requests.Clear(); + } + + void HideScrollFeedback() + { + HideFeedback(m_ScrollFeedback); + } + } + + static LayerMask s_LayerMask; + + readonly Dictionary m_RaycastSources = new Dictionary(); + + Camera m_EventCamera; + + [SerializeField] + ActionMap m_UIActionMap; + + public Camera eventCamera + { + get { return m_EventCamera; } + set { m_EventCamera = value; } + } + + public LayerMask layerMask + { + get { return s_LayerMask; } + set { s_LayerMask = value; } + } + + public event Action rayEntered; + public event Action rayHovering; + public event Action rayExited; + public event Action dragStarted; + public event Action dragEnded; + + public Action preProcessRaycastSource { private get; set; } + + readonly BindingDictionary m_Controls = new BindingDictionary(); + + // Local method use only -- created here to reduce garbage collection + RayEventData m_TempRayEvent; + + protected override void Awake() + { + base.Awake(); + + s_LayerMask = LayerMask.GetMask("UI"); + m_TempRayEvent = new RayEventData(eventSystem); + InputUtils.GetBindingDictionaryFromActionMap(m_UIActionMap, m_Controls); + } + + protected override void OnDestroy() + { + foreach (var source in m_RaycastSources) + { + this.DisconnectInterfaces(source); + } + } + + public void AddRaycastSource(IProxy proxy, Node node, Transform rayOrigin, Func validationCallback = null) + { + var source = new RaycastSource(proxy, rayOrigin, node, this, validationCallback); + this.ConnectInterfaces(source, rayOrigin); + m_RaycastSources.Add(rayOrigin, source); + } + + public RayEventData GetPointerEventData(Transform rayOrigin) + { + RaycastSource source; + if (m_RaycastSources.TryGetValue(rayOrigin, out source)) + return source.eventData; + + return null; + } + + public override void Process() + { + ExecuteUpdateOnSelectedObject(); + + if (m_EventCamera == null) + return; + + // World scaling also scales clipping planes + var camera = CameraUtils.GetMainCamera(); + m_EventCamera.nearClipPlane = camera.nearClipPlane; + m_EventCamera.farClipPlane = camera.farClipPlane; + } + + static bool HoveringInteractable(RayEventData eventData, GameObject currentObject, out bool hasScrollHandler) + { + hasScrollHandler = false; + + var selectionFlags = ComponentUtils.GetComponent(currentObject); + if (selectionFlags != null && selectionFlags.selectionFlags == SelectionFlags.Direct && !UIUtils.IsDirectEvent(eventData)) + return false; + + hasScrollHandler = ExecuteEvents.GetEventHandler(currentObject); + + return ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || ExecuteEvents.GetEventHandler(currentObject) + || hasScrollHandler; + } + + RayEventData GetTempEventDataClone(RayEventData eventData) + { + var clone = m_TempRayEvent; + clone.rayOrigin = eventData.rayOrigin; + clone.node = eventData.node; + clone.hovered.Clear(); + clone.hovered.AddRange(eventData.hovered); + clone.pointerEnter = eventData.pointerEnter; + clone.pointerCurrentRaycast = eventData.pointerCurrentRaycast; + clone.pointerLength = eventData.pointerLength; + + return clone; + } + + void HandlePointerExitAndEnter(RayEventData eventData, GameObject newEnterTarget, bool exitOnly = false) + { + // Cache properties before executing base method, so we can complete additional ray events later + var cachedEventData = GetTempEventDataClone(eventData); + + // This will modify the event data (new target will be set) + base.HandlePointerExitAndEnter(eventData, newEnterTarget); + + var pointerEnter = cachedEventData.pointerEnter; + if (newEnterTarget == null || pointerEnter == null) + { + for (var i = 0; i < cachedEventData.hovered.Count; ++i) + { + var hovered = cachedEventData.hovered[i]; + + ExecuteEvents.Execute(hovered, eventData, ExecuteRayEvents.rayExitHandler); + if (rayExited != null) + rayExited(hovered, eventData); + } + + if (newEnterTarget == null) + return; + } + + if (!exitOnly) + { + // if we have not changed hover target + if (newEnterTarget && pointerEnter == newEnterTarget) + { + var transform = newEnterTarget.transform; + while (transform != null) + { + ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayHoverHandler); + if (rayHovering != null) + rayHovering(transform.gameObject, cachedEventData); + + transform = transform.parent; + } + return; + } + } + + var commonRoot = FindCommonRoot(pointerEnter, newEnterTarget); + + // and we already an entered object from last time + if (pointerEnter != null) + { + // send exit handler call to all elements in the chain + // until we reach the new target, or null! + var transform = pointerEnter.transform; + + while (transform != null) + { + // if we reach the common root break out! + if (commonRoot != null && commonRoot.transform == transform) + break; + + ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayExitHandler); + if (rayExited != null) + rayExited(transform.gameObject, cachedEventData); + + transform = transform.parent; + } + } + + if (!exitOnly) + { + // now issue the enter call up to but not including the common root + cachedEventData.pointerEnter = newEnterTarget; + var transform = newEnterTarget.transform; + while (transform != null && transform.gameObject != commonRoot) + { + ExecuteEvents.Execute(transform.gameObject, cachedEventData, ExecuteRayEvents.rayEnterHandler); + if (rayEntered != null) + rayEntered(transform.gameObject, cachedEventData); + + transform = transform.parent; + } + } + } + + void OnSelectPressed(RaycastSource source) + { + Deselect(); + + var eventData = source.eventData; + var hoveredObject = source.hoveredObject; + eventData.pressPosition = eventData.position; + eventData.pointerPressRaycast = eventData.pointerCurrentRaycast; + eventData.pointerPress = hoveredObject; + + if (hoveredObject != null) // Pressed when pointer is over something + { + var draggedObject = hoveredObject; + var newPressed = ExecuteEvents.ExecuteHierarchy(draggedObject, eventData, ExecuteEvents.pointerDownHandler); + + if (newPressed == null) // Gameobject does not have pointerDownHandler in hierarchy, but may still have click handler + newPressed = ExecuteEvents.GetEventHandler(draggedObject); + + if (newPressed != null) + { + draggedObject = newPressed; // Set current pressed to gameObject that handles the pointerDown event, not the root object + Select(draggedObject); + eventData.eligibleForClick = true; + + // Track clicks for double-clicking, triple-clicking, etc. + float time = Time.realtimeSinceStartup; + if (newPressed == eventData.lastPress) + { + var diffTime = time - eventData.clickTime; + if (UIUtils.IsDoubleClick(diffTime)) + ++eventData.clickCount; + else + eventData.clickCount = 1; + } + else + { + eventData.clickCount = 1; + } + eventData.clickTime = time; + } + + ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.beginDragHandler); + ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.beginDragHandler); + eventData.dragging = true; + if (dragStarted != null) + dragStarted(draggedObject, eventData); + + eventData.pointerDrag = draggedObject; + source.draggedObject = draggedObject; + } + } + + void OnSelectReleased(RaycastSource source) + { + var eventData = source.eventData; + var hoveredObject = source.hoveredObject; + + if (source.draggedObject) + ExecuteEvents.Execute(source.draggedObject, eventData, ExecuteEvents.pointerUpHandler); + + if (source.draggedObject) + { + var draggedObject = source.draggedObject; + if (dragEnded != null) + dragEnded(draggedObject, eventData); + + ExecuteEvents.Execute(draggedObject, eventData, ExecuteEvents.endDragHandler); + ExecuteEvents.Execute(draggedObject, eventData, ExecuteRayEvents.endDragHandler); + + if (hoveredObject != null) + ExecuteEvents.ExecuteHierarchy(hoveredObject, eventData, ExecuteEvents.dropHandler); + + eventData.pointerDrag = null; + } + + var clickHandler = ExecuteEvents.GetEventHandler(hoveredObject); + if (source.draggedObject == clickHandler && eventData.eligibleForClick) + ExecuteEvents.Execute(clickHandler, eventData, ExecuteEvents.pointerClickHandler); + + eventData.dragging = false; + eventData.rawPointerPress = null; + eventData.pointerPress = null; + eventData.eligibleForClick = false; + source.draggedObject = null; + } + + public void Deselect() + { + if (eventSystem.currentSelectedGameObject) + eventSystem.SetSelectedGameObject(null); + } + + void Select(GameObject go) + { + Deselect(); + + if (ExecuteEvents.GetEventHandler(go)) + eventSystem.SetSelectedGameObject(go); + } + + GameObject GetRayIntersection(RaycastSource source) + { + // Move camera to position and rotation for the ray origin + m_EventCamera.transform.position = source.rayOrigin.position; + m_EventCamera.transform.rotation = source.rayOrigin.rotation; + + var eventData = source.eventData; + eventData.Reset(); + eventData.delta = Vector2.zero; + eventData.position = m_EventCamera.pixelRect.center; + eventData.scrollDelta = Vector2.zero; + + eventSystem.RaycastAll(eventData, m_RaycastResultCache); + eventData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache); + var hit = eventData.pointerCurrentRaycast.gameObject; + + m_RaycastResultCache.Clear(); + return hit; + } + + bool ExecuteUpdateOnSelectedObject() + { + if (eventSystem.currentSelectedGameObject == null) + return false; + + var eventData = GetBaseEventData(); + ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, eventData, ExecuteEvents.updateSelectedHandler); + return eventData.used; + } + + public bool IsHoveringOverUI(Transform rayOrigin) + { + RaycastSource source; + return m_RaycastSources.TryGetValue(rayOrigin, out source) && source.hasObject; + } + + public void SetUIBlockedForRayOrigin(Transform rayOrigin, bool blocked) + { + RaycastSource source; + if (m_RaycastSources.TryGetValue(rayOrigin, out source)) + source.blocked = blocked; + } + } +} +#endif diff --git a/Scripts/Modules/SerializedPreferencesModule.cs b/Scripts/Modules/SerializedPreferencesModule.cs index 71b114d55..08d341585 100644 --- a/Scripts/Modules/SerializedPreferencesModule.cs +++ b/Scripts/Modules/SerializedPreferencesModule.cs @@ -1,145 +1,145 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Modules -{ - sealed class SerializedPreferencesModule : MonoBehaviour - { - List m_Serializers = new List(); - SerializedPreferences m_Preferences; - - [Serializable] - class SerializedPreferences : ISerializationCallbackReceiver - { - [SerializeField] - SerializedPreferenceItem[] m_Items; - - readonly Dictionary m_ItemDictionary = new Dictionary(); - - public Dictionary items { get { return m_ItemDictionary; } } - - public void OnBeforeSerialize() - { - m_Items = m_ItemDictionary.Values.ToArray(); - } - - public void OnAfterDeserialize() - { - foreach (var item in m_Items) - { - var type = Type.GetType(item.name); - if (type != null) - { - if (m_ItemDictionary.ContainsKey(type)) - Debug.LogWarning("Multiple payloads of the same type on deserialization"); - - m_ItemDictionary[type] = item; - } - } - } - } - - [Serializable] - class SerializedPreferenceItem - { - [SerializeField] - string m_Name; - [SerializeField] - string m_PayloadType; - [SerializeField] - string m_Payload; - - public string name - { - get { return m_Name; } - set { m_Name = value; } - } - - public string payloadType - { - get { return m_PayloadType; } - set { m_PayloadType = value; } - } - - public string payload - { - get { return m_Payload; } - set { m_Payload = value; } - } - } - - public void AddSerializer(ISerializePreferences serializer) - { - if (m_Preferences != null) - Deserialize(serializer); - - m_Serializers.Add(serializer); - } - - public void RemoveSerializer(ISerializePreferences serializer) - { - // TODO: Support serializing one type at a time - SerializePreferences(); - m_Serializers.Remove(serializer); - } - - internal void DeserializePreferences(string serializedPreferences) - { - var preferences = JsonUtility.FromJson(serializedPreferences); - if (preferences != null) - { - m_Preferences = preferences; - - foreach (var serializer in m_Serializers) - { - Deserialize(serializer); - } - } - } - - internal string SerializePreferences() - { - if (m_Preferences == null) - m_Preferences = new SerializedPreferences(); - - var serializerTypes = new HashSet(); - - foreach (var serializer in m_Serializers) - { - var payload = serializer.OnSerializePreferences(); - - if (payload == null) - continue; - - var type = serializer.GetType(); - - if (!serializerTypes.Add(type)) - Debug.LogWarning(string.Format("Multiple payloads of type {0} on serialization", type)); - - m_Preferences.items[type] = new SerializedPreferenceItem - { - name = type.FullName, - payloadType = payload.GetType().FullName, - payload = JsonUtility.ToJson(payload) - }; - } - - return JsonUtility.ToJson(m_Preferences); - } - - void Deserialize(ISerializePreferences serializer) - { - SerializedPreferenceItem item; - if (m_Preferences.items.TryGetValue(serializer.GetType(), out item)) - { - var payload = JsonUtility.FromJson(item.payload, Type.GetType(item.payloadType)); - serializer.OnDeserializePreferences(payload); - } - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Modules +{ + sealed class SerializedPreferencesModule : MonoBehaviour + { + List m_Serializers = new List(); + SerializedPreferences m_Preferences; + + [Serializable] + class SerializedPreferences : ISerializationCallbackReceiver + { + [SerializeField] + SerializedPreferenceItem[] m_Items; + + readonly Dictionary m_ItemDictionary = new Dictionary(); + + public Dictionary items { get { return m_ItemDictionary; } } + + public void OnBeforeSerialize() + { + m_Items = m_ItemDictionary.Values.ToArray(); + } + + public void OnAfterDeserialize() + { + foreach (var item in m_Items) + { + var type = Type.GetType(item.name); + if (type != null) + { + if (m_ItemDictionary.ContainsKey(type)) + Debug.LogWarning("Multiple payloads of the same type on deserialization"); + + m_ItemDictionary[type] = item; + } + } + } + } + + [Serializable] + class SerializedPreferenceItem + { + [SerializeField] + string m_Name; + [SerializeField] + string m_PayloadType; + [SerializeField] + string m_Payload; + + public string name + { + get { return m_Name; } + set { m_Name = value; } + } + + public string payloadType + { + get { return m_PayloadType; } + set { m_PayloadType = value; } + } + + public string payload + { + get { return m_Payload; } + set { m_Payload = value; } + } + } + + public void AddSerializer(ISerializePreferences serializer) + { + if (m_Preferences != null) + Deserialize(serializer); + + m_Serializers.Add(serializer); + } + + public void RemoveSerializer(ISerializePreferences serializer) + { + // TODO: Support serializing one type at a time + SerializePreferences(); + m_Serializers.Remove(serializer); + } + + internal void DeserializePreferences(string serializedPreferences) + { + var preferences = JsonUtility.FromJson(serializedPreferences); + if (preferences != null) + { + m_Preferences = preferences; + + foreach (var serializer in m_Serializers) + { + Deserialize(serializer); + } + } + } + + internal string SerializePreferences() + { + if (m_Preferences == null) + m_Preferences = new SerializedPreferences(); + + var serializerTypes = new HashSet(); + + foreach (var serializer in m_Serializers) + { + var payload = serializer.OnSerializePreferences(); + + if (payload == null) + continue; + + var type = serializer.GetType(); + + if (!serializerTypes.Add(type)) + Debug.LogWarning(string.Format("Multiple payloads of type {0} on serialization", type)); + + m_Preferences.items[type] = new SerializedPreferenceItem + { + name = type.FullName, + payloadType = payload.GetType().FullName, + payload = JsonUtility.ToJson(payload) + }; + } + + return JsonUtility.ToJson(m_Preferences); + } + + void Deserialize(ISerializePreferences serializer) + { + SerializedPreferenceItem item; + if (m_Preferences.items.TryGetValue(serializer.GetType(), out item)) + { + var payload = JsonUtility.FromJson(item.payload, Type.GetType(item.payloadType)); + serializer.OnDeserializePreferences(payload); + } + } + } +} +#endif diff --git a/Scripts/Modules/TooltipModule/TooltipModule.cs b/Scripts/Modules/TooltipModule/TooltipModule.cs index 4f59a8377..7545d6fb9 100644 --- a/Scripts/Modules/TooltipModule/TooltipModule.cs +++ b/Scripts/Modules/TooltipModule/TooltipModule.cs @@ -22,6 +22,8 @@ sealed class TooltipModule : MonoBehaviour, IUsesViewerScale static readonly Quaternion k_FlipYRotation = Quaternion.AngleAxis(180f, Vector3.up); static readonly Quaternion k_FlipZRotation = Quaternion.AngleAxis(180f, Vector3.forward); + static readonly Vector3[] k_Corners = new Vector3[4]; + [SerializeField] GameObject m_TooltipPrefab; @@ -48,10 +50,25 @@ public Transform GetTooltipTarget(ITooltip tooltip) return ((MonoBehaviour)tooltip).transform; } + + public void Reset() + { + startTime = default(float); + lastModifiedTime = default(float); + tooltipUI = default(TooltipUI); + persistent = default(bool); + duration = default(float); + becameVisible = default(Action); + placement = default(ITooltipPlacement); + orientationWeight = default(float); + transitionOffset = default(Vector3); + transitionTime = default(float); + } } readonly Dictionary m_Tooltips = new Dictionary(); readonly Queue m_TooltipPool = new Queue(k_PoolInitialCapacity); + readonly Queue m_TooltipDataPool = new Queue(k_PoolInitialCapacity); Transform m_TooltipCanvas; Vector3 m_TooltipScale; @@ -173,10 +190,11 @@ void UpdateVisuals(ITooltip tooltip, TooltipData tooltipData, float lerp) if (placement != null) { - var rectTransform = tooltipUI.rectTransform; - var rect = rectTransform.rect; - var halfWidth = rect.width * 0.5f; - var halfHeight = rect.height * 0.5f; + //TODO: Figure out why rect gives us different height/width than GetWorldCorners + tooltipUI.rectTransform.GetWorldCorners(k_Corners); + var bottomLeft = k_Corners[0]; + var halfWidth = (bottomLeft - k_Corners[2]).magnitude * 0.5f; + var halfHeight = (bottomLeft - k_Corners[1]).magnitude * 0.5f; var source = placement.tooltipSource; var toSource = tooltipTransform.InverseTransformPoint(source.position); @@ -189,8 +207,9 @@ void UpdateVisuals(ITooltip tooltip, TooltipData tooltipData, float lerp) var boxSlope = halfHeight / halfWidth; var toSourceSlope = Mathf.Abs(toSource.y / toSource.x); - halfHeight *= Mathf.Sign(toSource.y); - halfWidth *= Mathf.Sign(toSource.x); + var parentScale = attachedSphere.parent.lossyScale; + halfHeight *= Mathf.Sign(toSource.y) / parentScale.x; + halfWidth *= Mathf.Sign(toSource.x) / parentScale.y; attachedSphere.localPosition = toSourceSlope > boxSlope ? new Vector3(0, halfHeight) : new Vector3(halfWidth, 0); @@ -301,18 +320,31 @@ public void ShowTooltip(ITooltip tooltip, bool persistent = false, float duratio if (duration < 0) return; - m_Tooltips[tooltip] = new TooltipData + var tooltipData = GetTooltipData(); + + tooltipData.startTime = Time.time; + tooltipData.lastModifiedTime = Time.time; + tooltipData.persistent = persistent; + tooltipData.duration = duration; + tooltipData.becameVisible = becameVisible; + tooltipData.placement = placement ?? tooltip as ITooltipPlacement; + tooltipData.orientationWeight = 0.0f; + tooltipData.transitionOffset = Vector3.zero; + tooltipData.transitionTime = 0.0f; + + m_Tooltips[tooltip] = tooltipData; + } + + TooltipData GetTooltipData() + { + if (m_TooltipDataPool.Count > 0) { - startTime = Time.time, - lastModifiedTime = Time.time, - persistent = persistent, - duration = duration, - becameVisible = becameVisible, - placement = placement ?? tooltip as ITooltipPlacement, - orientationWeight = 0.0f, - transitionOffset = Vector3.zero, - transitionTime = 0.0f, - }; + var tooltipData = m_TooltipDataPool.Dequeue(); + tooltipData.Reset(); + return tooltipData; + } + + return new TooltipData(); } static bool IsValidTooltip(ITooltip tooltip) @@ -372,15 +404,16 @@ Vector3 GetTooltipOffset(TooltipUI tooltipUI, ITooltipPlacement placement, Vecto } } - // The rectTransform expansion is handled in the Tooltip dynamically, based on alignment & text length - var rectTransform = tooltipUI.rectTransform; - var rect = rectTransform.rect; - var halfWidth = rect.width * 0.5f; - if (placement != null) - offset *= halfWidth * rectTransform.lossyScale.x; + { + tooltipUI.rectTransform.GetWorldCorners(k_Corners); + var halfWidth = (k_Corners[0] - k_Corners[2]).magnitude * 0.5f; + offset *= halfWidth; + } else + { offset = Vector3.back * k_Offset * this.GetViewerScale(); + } offset += transitionOffset; @@ -396,6 +429,7 @@ void RecycleTooltip(TooltipData tooltipData) tooltipUI.removeSelf(tooltipUI); m_TooltipPool.Enqueue(tooltipUI); + m_TooltipDataPool.Enqueue(tooltipData); } } } diff --git a/Scripts/Modules/TooltipModule/TooltipUI.cs b/Scripts/Modules/TooltipModule/TooltipUI.cs index e40bad6a9..e797859d2 100644 --- a/Scripts/Modules/TooltipModule/TooltipUI.cs +++ b/Scripts/Modules/TooltipModule/TooltipUI.cs @@ -24,7 +24,7 @@ sealed class TooltipUI : MonoBehaviour, IWillRender Transform[] m_Spheres; [SerializeField] - Image m_Background; + RectTransform m_Background; [SerializeField] Image m_Icon; @@ -66,8 +66,7 @@ sealed class TooltipUI : MonoBehaviour, IWillRender public RawImage dottedLine { get { return m_DottedLine; } } public Transform[] spheres { get { return m_Spheres; } } - public Image background { get { return m_Background; } } - public RectTransform rectTransform { get { return m_Background.rectTransform; } } + public RectTransform rectTransform { get { return m_Background; } } public event Action becameVisible; diff --git a/Scripts/Modules/TooltipModule/Tooltips/Tooltip.prefab b/Scripts/Modules/TooltipModule/Tooltips/Tooltip.prefab index 8ff5e7079..175501018 100644 --- a/Scripts/Modules/TooltipModule/Tooltips/Tooltip.prefab +++ b/Scripts/Modules/TooltipModule/Tooltips/Tooltip.prefab @@ -11,23 +11,6 @@ Prefab: m_ParentPrefab: {fileID: 0} m_RootGameObject: {fileID: 1000013663370456} m_IsPrefabParent: 1 ---- !u!1 &1000011269692594 -GameObject: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - serializedVersion: 5 - m_Component: - - component: {fileID: 4000010243013896} - - component: {fileID: 33000011797969314} - - component: {fileID: 23000013531814294} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 --- !u!1 &1000012744295348 GameObject: m_ObjectHideFlags: 1 @@ -112,23 +95,6 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!1 &1074182860545018 -GameObject: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - serializedVersion: 5 - m_Component: - - component: {fileID: 4620116345127136} - - component: {fileID: 33355909907356680} - - component: {fileID: 23252392897680406} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 --- !u!1 &1085556213955996 GameObject: m_ObjectHideFlags: 0 @@ -474,19 +440,6 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!4 &4000010243013896 -Transform: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011269692594} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.38505355, y: 0, z: 0} - m_LocalScale: {x: 0.18902051, y: 0.1890209, z: 63.006966} - m_Children: [] - m_Father: {fileID: 224812264159558962} - m_RootOrder: 8 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!4 &4054281684252946 Transform: m_ObjectHideFlags: 1 @@ -551,7 +504,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1275968570622872} m_LocalRotation: {x: 0.50000006, y: 0.49999997, z: 0.49999997, w: -0.50000006} - m_LocalPosition: {x: 0.10450004, y: 0, z: 0} + m_LocalPosition: {x: 0.09073241, y: -0.000033139382, z: 0.0000000021746382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4650979388391932} @@ -564,7 +517,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1146718103621422} m_LocalRotation: {x: -0.7071067, y: 0.7071068, z: -0.00000008940697, w: -0.000000029802322} - m_LocalPosition: {x: -0.10400001, y: 0.0000000023818574, z: 2.842171e-16} + m_LocalPosition: {x: -0.09073239, y: -0.000033139382, z: 0.0000000021746382} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4650979388391932} @@ -598,19 +551,6 @@ Transform: m_Father: {fileID: 224000013761003670} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!4 &4620116345127136 -Transform: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1074182860545018} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.38505355, y: 0, z: 0} - m_LocalScale: {x: 0.18884532, y: 0.18884572, z: 62.948574} - m_Children: [] - m_Father: {fileID: 224812264159558962} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!4 &4632352749217536 Transform: m_ObjectHideFlags: 1 @@ -631,7 +571,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1499802188371770} m_LocalRotation: {x: -0.70710677, y: 0.7071068, z: -0.000000053385076, w: -0.00000005338508} - m_LocalPosition: {x: -0.11460056, y: 0.0000000023841857, z: 0} + m_LocalPosition: {x: -0.09998032, y: 0.000010736565, z: 0.0000000024912878} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4054281684252946} @@ -644,8 +584,8 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1300164825752618} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 333.33334, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 5, y: 5, z: 5} m_Children: [] m_Father: {fileID: 224000013761003670} m_RootOrder: 4 @@ -673,7 +613,7 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1907346415385320} m_LocalRotation: {x: 0.50000006, y: 0.49999997, z: 0.5, w: -0.5} - m_LocalPosition: {x: 0.1141607, y: -3.4372283e-11, z: 2.842171e-16} + m_LocalPosition: {x: 0.09998033, y: 0.000010736565, z: 0.0000000024912878} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4054281684252946} @@ -686,8 +626,8 @@ Transform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1634802432663298} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 333.33334, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 5, y: 5, z: 5} m_Children: [] m_Father: {fileID: 224000013761003670} m_RootOrder: 3 @@ -707,40 +647,6 @@ Transform: m_Father: {fileID: 4480985723262476} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!23 &23000013531814294 -MeshRenderer: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011269692594} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 0 - m_ReflectionProbeUsage: 0 - m_Materials: - - {fileID: 2100000, guid: fd8559955928a5b45bf39973c09cc269, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_PreserveUVs: 1 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 0 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 --- !u!23 &23099930443996418 MeshRenderer: m_ObjectHideFlags: 1 @@ -775,40 +681,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 ---- !u!23 &23252392897680406 -MeshRenderer: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1074182860545018} - m_Enabled: 1 - m_CastShadows: 0 - m_ReceiveShadows: 0 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 0 - m_ReflectionProbeUsage: 0 - m_Materials: - - {fileID: 2100000, guid: fd8559955928a5b45bf39973c09cc269, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_PreserveUVs: 1 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 0 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 --- !u!23 &23651303856265792 MeshRenderer: m_ObjectHideFlags: 1 @@ -843,20 +715,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 ---- !u!33 &33000011797969314 -MeshFilter: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011269692594} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!33 &33355909907356680 -MeshFilter: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1074182860545018} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} --- !u!33 &33629107108381318 MeshFilter: m_ObjectHideFlags: 1 @@ -931,7 +789,7 @@ MonoBehaviour: m_Spheres: - {fileID: 4885394691244456} - {fileID: 4645832757573646} - m_Background: {fileID: 114793349690410468} + m_Background: {fileID: 224812264159558962} m_Icon: {fileID: 114615058684537526} m_TextLeft: {fileID: 114655812428771694} m_TextRight: {fileID: 114184815761203624} @@ -1054,7 +912,7 @@ MonoBehaviour: m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 - m_firstOverflowCharacterIndex: -1 + m_firstOverflowCharacterIndex: 0 m_linkedTextComponent: {fileID: 0} m_isLinkedTextComponent: 0 m_enableKerning: 1 @@ -1133,10 +991,10 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Padding: - m_Left: 0 - m_Right: 0 - m_Top: 0 - m_Bottom: 0 + m_Left: 10 + m_Right: 10 + m_Top: 12 + m_Bottom: 12 m_ChildAlignment: 4 m_Spacing: -2.55 m_ChildForceExpandWidth: 1 @@ -1306,7 +1164,7 @@ MonoBehaviour: m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 - m_firstOverflowCharacterIndex: -1 + m_firstOverflowCharacterIndex: 0 m_linkedTextComponent: {fileID: 0} m_isLinkedTextComponent: 0 m_enableKerning: 1 @@ -1819,8 +1677,6 @@ RectTransform: - {fileID: 224669117280002088} - {fileID: 224674761347856788} - {fileID: 224580360882846154} - - {fileID: 4620116345127136} - - {fileID: 4000010243013896} m_Father: {fileID: 224000013761003670} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Scripts/Modules/WebModule.cs b/Scripts/Modules/WebModule.cs new file mode 100644 index 000000000..c1c850779 --- /dev/null +++ b/Scripts/Modules/WebModule.cs @@ -0,0 +1,220 @@ +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using UnityEngine; +using UnityEngine.Networking; + +namespace UnityEditor.Experimental.EditorVR.Modules +{ + public class WebModule : MonoBehaviour + { + class DownloadRequest + { + public string key; // For queuing + public UnityWebRequest request; + public event Action completed; + + public void Complete() + { + var handler = request.downloadHandler; + if (completed != null) + completed(handler); + } + } + + class TextureRequest + { + public string key; // For queuing + public UnityWebRequest request; + public event Action completed; + + public void Complete() + { + var handler = (DownloadHandlerTexture)request.downloadHandler; + if (completed != null) + completed(handler); + } + } + + class FileTransfer + { + public bool isDone; + public event Action completed; + + public void Complete() + { + if (completed != null) + completed(); + } + } + + // Assume all requests to the same url are the same. If this changes, use entire header as the key + const int k_MaxSimultaneousRequests = 8; + const int k_MaxSimultaneousTransfers = 8; + readonly Dictionary m_Requests = new Dictionary(); + readonly Queue m_QueuedRequests = new Queue(); + readonly Dictionary m_TextureRequests = new Dictionary(); + readonly Queue m_QueuedTextureRequests = new Queue(); + + readonly List m_Transfers = new List(); + readonly Queue m_QueuedTransfers = new Queue(); + + List m_CompletedRequests = new List(20); + List m_CompletedTransfers = new List(20); + + /// + /// Download a resource at the given URL and call a method on completion, providing the DownloadHandler + /// + /// The URL of the resource + /// The completion callback + public void Download(string url, Action completed) + { + DownloadRequest request; + if (!m_Requests.TryGetValue(url, out request)) + { + var webRequest = UnityWebRequest.Get(url); + webRequest.SendWebRequest(); + request = new DownloadRequest { key = url, request = webRequest }; + if (m_Requests.Count < k_MaxSimultaneousRequests) + m_Requests.Add(url, request); + else + m_QueuedRequests.Enqueue(request); + } + + request.completed += completed; + } + + /// + /// Download a texture at a given URL and call a method on completion, providing the DownloadTextureHandler + /// + /// The URL of the resource + /// The completion callback + public void DownloadTexture(string url, Action completed) + { + TextureRequest request; + if (!m_TextureRequests.TryGetValue(url, out request)) + { + var webRequest = UnityWebRequest.Get(url); + webRequest.downloadHandler = new DownloadHandlerTexture(); + webRequest.SendWebRequest(); + request = new TextureRequest { key = url, request = webRequest }; + if (m_Requests.Count < k_MaxSimultaneousRequests) + m_TextureRequests.Add(url, request); + else + m_QueuedTextureRequests.Enqueue(request); + } + + request.completed += completed; + } + + /// + /// Download a resource at the given URL to the given destination file and call a method on completion + /// + /// The URL of the resource + /// The destination file path + /// The completion callback + public void Download(string url, string destination, Action completed) + { + Download(url, handler => + { + var transfer = new FileTransfer(); + transfer.completed += completed; + m_Transfers.Add(transfer); + var data = handler.data; + new Thread(() => + { + File.WriteAllBytes(destination, data); + transfer.isDone = true; + }).Start(); + }); + } + + void Update() + { + foreach (var kvp in m_Requests) + { + var request = kvp.Value; + var webRequest = request.request; + + if (webRequest.isDone && webRequest.downloadHandler.isDone) + { + var error = webRequest.error; + if (!string.IsNullOrEmpty(error)) + Debug.LogWarning(error); + + request.Complete(); + + m_CompletedRequests.Add(kvp.Key); + } + } + + foreach (var request in m_CompletedRequests) + { + m_Requests.Remove(request); + } + + while (m_Requests.Count < k_MaxSimultaneousRequests && m_QueuedRequests.Count > 0) + { + var first = m_QueuedRequests.Dequeue(); + m_Requests.Add(first.key, first); + } + + //TODO: Generalize Request class + m_CompletedRequests.Clear(); + + foreach (var kvp in m_TextureRequests) + { + var request = kvp.Value; + var webRequest = request.request; + + if (webRequest.isDone && webRequest.downloadHandler.isDone) + { + var error = webRequest.error; + if (!string.IsNullOrEmpty(error)) + Debug.LogWarning(error); + + request.Complete(); + + m_CompletedRequests.Add(kvp.Key); + } + } + + foreach (var request in m_CompletedRequests) + { + m_TextureRequests.Remove(request); + } + + while (m_TextureRequests.Count < k_MaxSimultaneousRequests && m_QueuedTextureRequests.Count > 0) + { + var first = m_QueuedTextureRequests.Dequeue(); + m_TextureRequests.Add(first.key, first); + } + + foreach (var transfer in m_Transfers) + { + if (transfer.isDone) + { + transfer.Complete(); + m_CompletedTransfers.Add(transfer); + } + } + + foreach (var transfer in m_CompletedTransfers) + { + m_Transfers.Remove(transfer); + } + + while (m_Transfers.Count < k_MaxSimultaneousTransfers && m_QueuedTransfers.Count > 0) + { + var first = m_QueuedTransfers.Dequeue(); + m_Transfers.Add(first); + } + + m_CompletedRequests.Clear(); + m_CompletedTransfers.Clear(); + } + } +} +#endif diff --git a/Scripts/Modules/WebModule.cs.meta b/Scripts/Modules/WebModule.cs.meta new file mode 100644 index 000000000..085cbc649 --- /dev/null +++ b/Scripts/Modules/WebModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2365462634aabd84897372b8b287eb1b +timeCreated: 1505157257 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Proxies/Data/ProxyFeedbackRequest.cs b/Scripts/Proxies/Data/ProxyFeedbackRequest.cs index 45ba33b11..e1b2d07d0 100644 --- a/Scripts/Proxies/Data/ProxyFeedbackRequest.cs +++ b/Scripts/Proxies/Data/ProxyFeedbackRequest.cs @@ -1,5 +1,6 @@ #if UNITY_EDITOR using System; +using UnityEngine; using UnityEngine.InputNew; namespace UnityEditor.Experimental.EditorVR.Proxies @@ -12,6 +13,9 @@ namespace UnityEditor.Experimental.EditorVR.Proxies /// public class ProxyFeedbackRequest : FeedbackRequest { + const float k_DefaultDuration = 5f; + const int k_DefaultMaxPresentations = 20; + /// /// The priority level for this request. Default is 0. /// If there are multiple requests for one control, the one with the highest priority is presented @@ -47,18 +51,30 @@ public class ProxyFeedbackRequest : FeedbackRequest /// /// The duration of the presentation /// - public float duration = 5f; + public float duration = k_DefaultDuration; /// /// The maximum number times to present this feedback /// - public int maxPresentations = 20; + public int maxPresentations = k_DefaultMaxPresentations; /// /// (Optional) A delegate which returns true if presentation should be suppressed /// If the delegate is not null, feedback will be suppressed after it becomes visible a number of times (specified by maxPresentations) /// public Func suppressPresentation; + + public override void Reset() + { + priority = default(int); + control = default(VRControl); + node = default(Node); + tooltipText = default(string); + suppressExisting = default(bool); + showBody = default(bool); + duration = k_DefaultDuration; + maxPresentations = k_DefaultMaxPresentations; + } } } #endif diff --git a/Scripts/Proxies/DefaultProxyRay.cs b/Scripts/Proxies/DefaultProxyRay.cs index fdc691c07..91d1a1552 100644 --- a/Scripts/Proxies/DefaultProxyRay.cs +++ b/Scripts/Proxies/DefaultProxyRay.cs @@ -1,247 +1,254 @@ -#if UNITY_EDITOR -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Proxies -{ - sealed class DefaultProxyRay : MonoBehaviour, IUsesViewerScale - { - struct DefaultRayVisibilitySettings - { - public int priority; - public bool rayVisible; - public bool coneVisible; - } - - [SerializeField] - VRLineRenderer m_LineRenderer; - - [SerializeField] - GameObject m_Tip; - - [SerializeField] - float m_LineWidth; - - [SerializeField] - MeshFilter m_Cone; - - Vector3 m_TipStartScale; - Transform m_ConeTransform; - Vector3 m_OriginalConeLocalScale; - Coroutine m_RayVisibilityCoroutine; - Coroutine m_ConeVisibilityCoroutine; - Material m_RayMaterial; - float m_LastPointerLength; - - readonly Dictionary m_VisibilitySettings = new Dictionary(); - - /// - /// The length of the direct selection pointer - /// - public float pointerLength - { - get - { - if (!coneVisible || m_ConeVisibilityCoroutine != null) - return m_LastPointerLength; - - m_LastPointerLength = (m_Cone.transform.TransformPoint(m_Cone.sharedMesh.bounds.size.z * Vector3.forward) - m_Cone.transform.position).magnitude; - return m_LastPointerLength; - } - } - - public bool rayVisible { get; private set; } - public bool coneVisible { get; private set; } - - void OnDisable() - { - this.StopCoroutine(ref m_RayVisibilityCoroutine); - this.StopCoroutine(ref m_ConeVisibilityCoroutine); - } - - public void AddVisibilitySettings(object caller, bool rayVisible, bool coneVisible, int priority = 0) - { - m_VisibilitySettings[caller] = new DefaultRayVisibilitySettings { rayVisible = rayVisible, coneVisible = coneVisible, priority = priority }; - } - - public void RemoveVisibilitySettings(object caller) - { - m_VisibilitySettings.Remove(caller); - } - - public void SetLength(float length) - { - if (!rayVisible) - return; - - var viewerScale = this.GetViewerScale(); - var scaledWidth = m_LineWidth * viewerScale; - var scaledLength = length / viewerScale; - - var lineRendererTransform = m_LineRenderer.transform; - lineRendererTransform.localScale = Vector3.one * scaledLength; - m_LineRenderer.SetWidth(scaledWidth, scaledWidth * scaledLength); - m_Tip.transform.position = transform.position + transform.forward * length; - m_Tip.transform.localScale = scaledLength * m_TipStartScale; - } - - public void SetColor(Color c) - { - m_RayMaterial.color = c; - } - - void Awake() - { - m_RayMaterial = MaterialUtils.GetMaterialClone(m_LineRenderer.GetComponent()); - m_ConeTransform = m_Cone.transform; - m_OriginalConeLocalScale = m_ConeTransform.localScale; - - rayVisible = true; - coneVisible = true; - } - - void Start() - { - m_TipStartScale = m_Tip.transform.localScale; - rayVisible = true; - } - - void Update() - { - UpdateVisibility(); - } - - void UpdateVisibility() - { - var coneVisible = true; - var rayVisible = true; - - if (m_VisibilitySettings.Count > 0) - { - var maxPriority = m_VisibilitySettings.Select(setting => setting.Value.priority).Max(); - foreach (var kvp in m_VisibilitySettings) - { - var settings = kvp.Value; - if (settings.priority == maxPriority) - { - rayVisible &= settings.rayVisible; - coneVisible &= settings.coneVisible; - } - } - } - - if (this.rayVisible != rayVisible) - { - this.rayVisible = rayVisible; - this.StopCoroutine(ref m_RayVisibilityCoroutine); - m_RayVisibilityCoroutine = StartCoroutine(rayVisible ? ShowRay() : HideRay()); - } - - if (this.coneVisible != coneVisible) - { - this.coneVisible = coneVisible; - this.StopCoroutine(ref m_ConeVisibilityCoroutine); - m_ConeVisibilityCoroutine = StartCoroutine(coneVisible ? ShowCone() : HideCone()); - } - } - - IEnumerator HideRay() - { - m_Tip.transform.localScale = Vector3.zero; - - // cache current width for smooth animation to target value without snapping - var currentWidth = m_LineRenderer.widthStart; - const float kTargetWidth = 0f; - const float kSmoothTime = 0.1875f; - var smoothVelocity = 0f; - var currentDuration = 0f; - while (currentDuration < kSmoothTime) - { - currentDuration += Time.deltaTime; - currentWidth = MathUtilsExt.SmoothDamp(currentWidth, kTargetWidth, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); - m_LineRenderer.SetWidth(currentWidth, currentWidth); - yield return null; - } - - m_LineRenderer.SetWidth(kTargetWidth, kTargetWidth); - m_RayVisibilityCoroutine = null; - } - - IEnumerator ShowRay() - { - m_Tip.transform.localScale = m_TipStartScale; - - var viewerScale = this.GetViewerScale(); - float scaledWidth; - var currentWidth = m_LineRenderer.widthStart / viewerScale; - var smoothVelocity = 0f; - const float kSmoothTime = 0.3125f; - var currentDuration = 0f; - while (currentDuration < kSmoothTime) - { - viewerScale = this.GetViewerScale(); - currentDuration += Time.deltaTime; - currentWidth = MathUtilsExt.SmoothDamp(currentWidth, m_LineWidth, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); - scaledWidth = currentWidth * viewerScale; - m_LineRenderer.SetWidth(scaledWidth, scaledWidth); - yield return null; - } - - viewerScale = this.GetViewerScale(); - scaledWidth = m_LineWidth * viewerScale; - m_LineRenderer.SetWidth(scaledWidth, scaledWidth); - m_RayVisibilityCoroutine = null; - } - - IEnumerator HideCone() - { - var currentScale = m_ConeTransform.localScale; - var smoothVelocity = Vector3.one; - const float kSmoothTime = 0.1875f; - var currentDuration = 0f; - while (currentDuration < kSmoothTime) - { - currentDuration += Time.deltaTime; - currentScale = MathUtilsExt.SmoothDamp(currentScale, Vector3.zero, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); - m_ConeTransform.localScale = currentScale; - yield return null; - } - - m_ConeTransform.localScale = Vector3.zero; - m_ConeVisibilityCoroutine = null; - } - - IEnumerator ShowCone() - { - var currentScale = m_ConeTransform.localScale; - var smoothVelocity = Vector3.zero; - const float kSmoothTime = 0.3125f; - var currentDuration = 0f; - while (currentDuration < kSmoothTime) - { - currentDuration += Time.deltaTime; - currentScale = MathUtilsExt.SmoothDamp(currentScale, m_OriginalConeLocalScale, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); - m_ConeTransform.localScale = currentScale; - yield return null; - } - - m_ConeTransform.localScale = m_OriginalConeLocalScale; - m_ConeVisibilityCoroutine = null; - } - - public Color GetColor() - { - return m_RayMaterial.color; - } - - void OnDestroy() - { - ObjectUtils.Destroy(m_RayMaterial); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Proxies +{ + sealed class DefaultProxyRay : MonoBehaviour, IUsesViewerScale + { + struct DefaultRayVisibilitySettings + { + public int priority; + public bool rayVisible; + public bool coneVisible; + } + + [SerializeField] + VRLineRenderer m_LineRenderer; + + [SerializeField] + GameObject m_Tip; + + [SerializeField] + float m_LineWidth; + + [SerializeField] + MeshFilter m_Cone; + + Vector3 m_TipStartScale; + Transform m_ConeTransform; + Vector3 m_OriginalConeLocalScale; + Coroutine m_RayVisibilityCoroutine; + Coroutine m_ConeVisibilityCoroutine; + Material m_RayMaterial; + float m_LastPointerLength; + + readonly Dictionary m_VisibilitySettings = new Dictionary(); + + /// + /// The length of the direct selection pointer + /// + public float pointerLength + { + get + { + if (!coneVisible || m_ConeVisibilityCoroutine != null) + return m_LastPointerLength; + + m_LastPointerLength = (m_Cone.transform.TransformPoint(m_Cone.sharedMesh.bounds.size.z * Vector3.forward) - m_Cone.transform.position).magnitude; + return m_LastPointerLength; + } + } + + public bool rayVisible { get; private set; } + public bool coneVisible { get; private set; } + + void OnDisable() + { + this.StopCoroutine(ref m_RayVisibilityCoroutine); + this.StopCoroutine(ref m_ConeVisibilityCoroutine); + } + + public void AddVisibilitySettings(object caller, bool rayVisible, bool coneVisible, int priority = 0) + { + m_VisibilitySettings[caller] = new DefaultRayVisibilitySettings { rayVisible = rayVisible, coneVisible = coneVisible, priority = priority }; + } + + public void RemoveVisibilitySettings(object caller) + { + m_VisibilitySettings.Remove(caller); + } + + public void SetLength(float length) + { + if (!rayVisible) + return; + + var viewerScale = this.GetViewerScale(); + var scaledWidth = m_LineWidth * viewerScale; + var scaledLength = length / viewerScale; + + var lineRendererTransform = m_LineRenderer.transform; + lineRendererTransform.localScale = Vector3.one * scaledLength; + m_LineRenderer.SetWidth(scaledWidth, scaledWidth * scaledLength); + m_Tip.transform.position = transform.position + transform.forward * length; + m_Tip.transform.localScale = scaledLength * m_TipStartScale; + } + + public void SetColor(Color c) + { + m_RayMaterial.color = c; + } + + void Awake() + { + m_RayMaterial = MaterialUtils.GetMaterialClone(m_LineRenderer.GetComponent()); + m_ConeTransform = m_Cone.transform; + m_OriginalConeLocalScale = m_ConeTransform.localScale; + + rayVisible = true; + coneVisible = true; + } + + void Start() + { + m_TipStartScale = m_Tip.transform.localScale; + rayVisible = true; + } + + void Update() + { + UpdateVisibility(); + } + + void UpdateVisibility() + { + var coneVisible = true; + var rayVisible = true; + + if (m_VisibilitySettings.Count > 0) + { + var maxPriority = 0; + foreach (var kvp in m_VisibilitySettings) + { + var priority = kvp.Value.priority; + if (priority > maxPriority) + maxPriority = priority; + } + + foreach (var kvp in m_VisibilitySettings) + { + var settings = kvp.Value; + if (settings.priority == maxPriority) + { + rayVisible &= settings.rayVisible; + coneVisible &= settings.coneVisible; + } + } + } + + if (this.rayVisible != rayVisible) + { + this.rayVisible = rayVisible; + this.StopCoroutine(ref m_RayVisibilityCoroutine); + m_RayVisibilityCoroutine = StartCoroutine(rayVisible ? ShowRay() : HideRay()); + } + + if (this.coneVisible != coneVisible) + { + this.coneVisible = coneVisible; + this.StopCoroutine(ref m_ConeVisibilityCoroutine); + m_ConeVisibilityCoroutine = StartCoroutine(coneVisible ? ShowCone() : HideCone()); + } + } + + IEnumerator HideRay() + { + m_Tip.transform.localScale = Vector3.zero; + + // cache current width for smooth animation to target value without snapping + var currentWidth = m_LineRenderer.widthStart; + const float kTargetWidth = 0f; + const float kSmoothTime = 0.1875f; + var smoothVelocity = 0f; + var currentDuration = 0f; + while (currentDuration < kSmoothTime) + { + currentDuration += Time.deltaTime; + currentWidth = MathUtilsExt.SmoothDamp(currentWidth, kTargetWidth, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); + m_LineRenderer.SetWidth(currentWidth, currentWidth); + yield return null; + } + + m_LineRenderer.SetWidth(kTargetWidth, kTargetWidth); + m_RayVisibilityCoroutine = null; + } + + IEnumerator ShowRay() + { + m_Tip.transform.localScale = m_TipStartScale; + + var viewerScale = this.GetViewerScale(); + float scaledWidth; + var currentWidth = m_LineRenderer.widthStart / viewerScale; + var smoothVelocity = 0f; + const float kSmoothTime = 0.3125f; + var currentDuration = 0f; + while (currentDuration < kSmoothTime) + { + viewerScale = this.GetViewerScale(); + currentDuration += Time.deltaTime; + currentWidth = MathUtilsExt.SmoothDamp(currentWidth, m_LineWidth, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); + scaledWidth = currentWidth * viewerScale; + m_LineRenderer.SetWidth(scaledWidth, scaledWidth); + yield return null; + } + + viewerScale = this.GetViewerScale(); + scaledWidth = m_LineWidth * viewerScale; + m_LineRenderer.SetWidth(scaledWidth, scaledWidth); + m_RayVisibilityCoroutine = null; + } + + IEnumerator HideCone() + { + var currentScale = m_ConeTransform.localScale; + var smoothVelocity = Vector3.one; + const float kSmoothTime = 0.1875f; + var currentDuration = 0f; + while (currentDuration < kSmoothTime) + { + currentDuration += Time.deltaTime; + currentScale = MathUtilsExt.SmoothDamp(currentScale, Vector3.zero, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); + m_ConeTransform.localScale = currentScale; + yield return null; + } + + m_ConeTransform.localScale = Vector3.zero; + m_ConeVisibilityCoroutine = null; + } + + IEnumerator ShowCone() + { + var currentScale = m_ConeTransform.localScale; + var smoothVelocity = Vector3.zero; + const float kSmoothTime = 0.3125f; + var currentDuration = 0f; + while (currentDuration < kSmoothTime) + { + currentDuration += Time.deltaTime; + currentScale = MathUtilsExt.SmoothDamp(currentScale, m_OriginalConeLocalScale, ref smoothVelocity, kSmoothTime, Mathf.Infinity, Time.deltaTime); + m_ConeTransform.localScale = currentScale; + yield return null; + } + + m_ConeTransform.localScale = m_OriginalConeLocalScale; + m_ConeVisibilityCoroutine = null; + } + + public Color GetColor() + { + return m_RayMaterial.color; + } + + void OnDestroy() + { + ObjectUtils.Destroy(m_RayMaterial); + } + } +} +#endif diff --git a/Scripts/Proxies/ProxyAnimator.cs b/Scripts/Proxies/ProxyAnimator.cs index c0b0d1797..f05ee37f2 100644 --- a/Scripts/Proxies/ProxyAnimator.cs +++ b/Scripts/Proxies/ProxyAnimator.cs @@ -1,178 +1,178 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Proxies -{ - using FeedbackDictionary = Dictionary; - - [ProcessInput(1)] - [RequireComponent(typeof(ProxyNode))] - class ProxyAnimator : MonoBehaviour, ICustomActionMap, IUsesNode, IRequestFeedback - { - public class TransformInfo - { - public Vector3 initialPosition; - public Vector3 initialRotation; - public Vector3 positionOffset; - public Vector3 rotationOffset; - - public void Apply(Transform transform) - { - transform.localPosition = initialPosition + positionOffset; - transform.localRotation = Quaternion.Euler(initialRotation + rotationOffset); - } - } - - [SerializeField] - ActionMap m_ProxyActionMap; - - Affordance[] m_Affordances; - AffordanceDefinition[] m_AffordanceDefinitions; - InputControl[] m_Controls; - - readonly Dictionary m_TransformInfos = new Dictionary(); - - readonly FeedbackDictionary m_FeedbackRequests = new FeedbackDictionary(); - - public ActionMap actionMap { get { return m_ProxyActionMap; } } - public bool ignoreLocking { get { return true; } } - - public Node node { private get; set; } - - internal event Action, ActionMapInput> postAnimate; - - public void Setup(AffordanceDefinition[] affordanceDefinitions, Affordance[] affordances) - { - m_Affordances = affordances; - m_AffordanceDefinitions = affordanceDefinitions; - } - - void OnDestroy() - { - this.ClearFeedbackRequests(); - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - var length = m_Affordances.Length; - if (m_Controls == null) - { - m_Controls = new InputControl[length]; - - var bindings = input.actionMap.controlSchemes[0].bindings; - for (var i = 0; i < input.controlCount; i++) - { - var control = input[i]; - var binding = bindings[i]; - for (var j = 0; j < length; j++) - { - var affordance = m_Affordances[j]; - foreach (var index in binding.sources) - { - if (index.controlIndex == (int)affordance.control) - { - m_Controls[j] = control; - break; - } - } - } - } - - foreach (var affordance in m_Affordances) - { - var affordanceTransform = affordance.transform; - TransformInfo info; - if (!m_TransformInfos.TryGetValue(affordanceTransform, out info)) - { - info = new TransformInfo(); - m_TransformInfos[affordanceTransform] = info; - } - - info.initialPosition = affordanceTransform.localPosition; - info.initialRotation = affordanceTransform.localRotation.eulerAngles; - } - } - - foreach (var kvp in m_TransformInfos) - { - var transformInfo = kvp.Value; - transformInfo.positionOffset = Vector3.zero; - transformInfo.rotationOffset = Vector3.zero; - } - - for (var i = 0; i < length; i++) - { - var affordance = m_Affordances[i]; - var inputControl = m_Controls[i]; - var controlIndex = affordance.control; - foreach (var definition in m_AffordanceDefinitions) - { - if (definition.control == controlIndex) - { - var animationDefinition = definition.animationDefinition; - - // Animate any values defined in the ProxyAffordanceMap's Affordance Definition - //Assume control values are [-1, 1] - if (animationDefinition != null) - { - var info = m_TransformInfos[affordance.transform]; - var handednessScalar = node == Node.RightHand && animationDefinition.reverseForRightHand ? -1 : 1; - var min = animationDefinition.min * handednessScalar; - var max = animationDefinition.max * handednessScalar; - var offset = min + (inputControl.rawValue + 1) * (max - min) * 0.5f; - - info.positionOffset += animationDefinition.translateAxes.GetAxis() * offset; - info.rotationOffset += animationDefinition.rotateAxes.GetAxis() * offset; - } - - break; - } - } - - if (Mathf.Approximately(inputControl.rawValue, 0)) - HideFeedback(controlIndex); - else - ShowFeedback(controlIndex); - } - - foreach (var kvp in m_TransformInfos) - { - kvp.Value.Apply(kvp.Key); - } - - if (postAnimate != null) - postAnimate(m_Affordances, m_AffordanceDefinitions, m_TransformInfos, input); - } - - void ShowFeedback(VRInputDevice.VRControl control) - { - if (m_FeedbackRequests.ContainsKey(control)) - return; - - var request = new ProxyFeedbackRequest - { - control = control, - node = node, - duration = -1 - }; - m_FeedbackRequests[control] = request; - this.AddFeedbackRequest(request); - } - - void HideFeedback(VRInputDevice.VRControl control) - { - ProxyFeedbackRequest request; - if (m_FeedbackRequests.TryGetValue(control, out request)) - { - m_FeedbackRequests.Remove(control); - this.RemoveFeedbackRequest(request); - } - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Proxies +{ + using FeedbackDictionary = Dictionary; + + [ProcessInput(1)] + [RequireComponent(typeof(ProxyNode))] + class ProxyAnimator : MonoBehaviour, ICustomActionMap, IUsesNode, IRequestFeedback + { + public class TransformInfo + { + public Vector3 initialPosition; + public Vector3 initialRotation; + public Vector3 positionOffset; + public Vector3 rotationOffset; + + public void Apply(Transform transform) + { + transform.localPosition = initialPosition + positionOffset; + transform.localRotation = Quaternion.Euler(initialRotation + rotationOffset); + } + } + + [SerializeField] + ActionMap m_ProxyActionMap; + + Affordance[] m_Affordances; + AffordanceDefinition[] m_AffordanceDefinitions; + InputControl[] m_Controls; + + readonly Dictionary m_TransformInfos = new Dictionary(); + + readonly FeedbackDictionary m_FeedbackRequests = new FeedbackDictionary(); + + public ActionMap actionMap { get { return m_ProxyActionMap; } } + public bool ignoreLocking { get { return true; } } + + public Node node { private get; set; } + + internal event Action, ActionMapInput> postAnimate; + + public void Setup(AffordanceDefinition[] affordanceDefinitions, Affordance[] affordances) + { + m_Affordances = affordances; + m_AffordanceDefinitions = affordanceDefinitions; + } + + void OnDestroy() + { + this.ClearFeedbackRequests(); + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + var length = m_Affordances.Length; + if (m_Controls == null) + { + m_Controls = new InputControl[length]; + + var bindings = input.actionMap.controlSchemes[0].bindings; + for (var i = 0; i < input.controlCount; i++) + { + var control = input[i]; + var binding = bindings[i]; + for (var j = 0; j < length; j++) + { + var affordance = m_Affordances[j]; + foreach (var index in binding.sources) + { + if (index.controlIndex == (int)affordance.control) + { + m_Controls[j] = control; + break; + } + } + } + } + + foreach (var affordance in m_Affordances) + { + var affordanceTransform = affordance.transform; + TransformInfo info; + if (!m_TransformInfos.TryGetValue(affordanceTransform, out info)) + { + info = new TransformInfo(); + m_TransformInfos[affordanceTransform] = info; + } + + info.initialPosition = affordanceTransform.localPosition; + info.initialRotation = affordanceTransform.localRotation.eulerAngles; + } + } + + foreach (var kvp in m_TransformInfos) + { + var transformInfo = kvp.Value; + transformInfo.positionOffset = Vector3.zero; + transformInfo.rotationOffset = Vector3.zero; + } + + for (var i = 0; i < length; i++) + { + var affordance = m_Affordances[i]; + var inputControl = m_Controls[i]; + var controlIndex = affordance.control; + foreach (var definition in m_AffordanceDefinitions) + { + if (definition.control == controlIndex) + { + var animationDefinition = definition.animationDefinition; + + // Animate any values defined in the ProxyAffordanceMap's Affordance Definition + //Assume control values are [-1, 1] + if (animationDefinition != null) + { + var info = m_TransformInfos[affordance.transform]; + var handednessScalar = node == Node.RightHand && animationDefinition.reverseForRightHand ? -1 : 1; + var min = animationDefinition.min * handednessScalar; + var max = animationDefinition.max * handednessScalar; + var offset = min + (inputControl.rawValue + 1) * (max - min) * 0.5f; + + info.positionOffset += animationDefinition.translateAxes.GetAxis() * offset; + info.rotationOffset += animationDefinition.rotateAxes.GetAxis() * offset; + } + + break; + } + } + + if (Mathf.Approximately(inputControl.rawValue, 0)) + HideFeedback(controlIndex); + else + ShowFeedback(controlIndex); + } + + foreach (var kvp in m_TransformInfos) + { + kvp.Value.Apply(kvp.Key); + } + + if (postAnimate != null) + postAnimate(m_Affordances, m_AffordanceDefinitions, m_TransformInfos, input); + } + + void ShowFeedback(VRInputDevice.VRControl control) + { + var key = (int)control; + if (m_FeedbackRequests.ContainsKey(key)) + return; + + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = control; + request.node = node; + request.duration = -1; + m_FeedbackRequests[key] = request; + this.AddFeedbackRequest(request); + } + + void HideFeedback(VRInputDevice.VRControl control) + { + var key = (int)control; + ProxyFeedbackRequest request; + if (m_FeedbackRequests.TryGetValue(key, out request)) + { + m_FeedbackRequests.Remove(key); + this.RemoveFeedbackRequest(request); + } + } + } +} +#endif diff --git a/Scripts/Proxies/ProxyNode.cs b/Scripts/Proxies/ProxyNode.cs index 4357c23bf..8a41add78 100644 --- a/Scripts/Proxies/ProxyNode.cs +++ b/Scripts/Proxies/ProxyNode.cs @@ -25,6 +25,9 @@ class VisibilityState readonly AffordanceTooltip[] m_Tooltips; readonly AffordanceVisibilityDefinition m_Definition; + readonly Action m_SetFloat; + readonly Action m_SetColor; + bool m_Visibile; float m_VisibilityChangeTime; @@ -35,6 +38,9 @@ class VisibilityState public float visibleDuration { get; set; } public float hideTime { get { return m_VisibilityChangeTime + visibleDuration; } } + public Action setFloat { get { return m_SetFloat; } } + public Action setColor { get { return m_SetColor; } } + public bool visible { get { return m_Visibile; } @@ -51,14 +57,18 @@ public VisibilityState(Renderer renderer, AffordanceTooltip[] tooltips, Affordan m_Definition = definition; m_Material = material; m_MaterialIndex = Array.IndexOf(renderer.sharedMaterials, material); + + // Cache delegate versions of SetFloat and SetColor to avoid GC when used in AnimateProperty + m_SetFloat = SetFloat; + m_SetColor = SetColor; } - public void SetFloat(float value) + void SetFloat(float value) { m_Material.SetFloat(m_Definition.alphaProperty, value); } - public void SetColor(Color value) + void SetColor(Color value) { m_Material.SetColor(m_Definition.colorProperty, value); } @@ -70,16 +80,18 @@ public void SetColor(Color value) Color m_StartColor; Color m_CurrentColor; - readonly Dictionary m_AffordanceVisibilityStates = new Dictionary(); + readonly Dictionary m_AffordanceVisibilityStates = new Dictionary(); readonly Dictionary, VisibilityState> m_VisibilityStates = new Dictionary, VisibilityState>(); public void AddAffordance(Material material, VRControl control, Renderer renderer, AffordanceTooltip[] tooltips, AffordanceVisibilityDefinition definition) { - if (m_AffordanceVisibilityStates.ContainsKey(control)) + var key = (int)control; + + if (m_AffordanceVisibilityStates.ContainsKey(key)) Debug.LogWarning("Multiple affordaces added to " + this + " for " + control); - m_AffordanceVisibilityStates[control] = new VisibilityState(renderer, tooltips, definition, material); + m_AffordanceVisibilityStates[key] = new VisibilityState(renderer, tooltips, definition, material); switch (definition.visibilityType) { @@ -146,7 +158,7 @@ public void Update(Renderer renderer, Material material, float time, float fadeI TransitionUtils.AnimateProperty(time, visible, ref m_WasVisible, ref m_VisibleChangeTime, ref m_CurrentColor.a, ref m_StartColor.a, definition.hiddenColor.a, m_OriginalColor.a, fadeDuration, Mathf.Approximately, TransitionUtils.GetPercentage, Mathf.Lerp, - visibilityState.SetFloat, false); + visibilityState.setFloat, false); break; case VisibilityControlType.ColorProperty: if (visibilityState == null) @@ -162,7 +174,7 @@ public void Update(Renderer renderer, Material material, float time, float fadeI TransitionUtils.AnimateProperty(time, visible, ref m_WasVisible, ref m_VisibleChangeTime, ref m_CurrentColor, ref m_StartColor, definition.hiddenColor, m_OriginalColor, fadeDuration, TransitionUtils.Approximately, TransitionUtils.GetPercentage, Color.Lerp, - visibilityState.SetColor, false); + visibilityState.setColor, false); break; } @@ -205,7 +217,7 @@ public bool GetVisibility(VRControl control) { foreach (var kvp in m_AffordanceVisibilityStates) { - if (kvp.Key != control) + if (kvp.Key != (int)control) continue; if (kvp.Value.visible) @@ -218,7 +230,7 @@ public bool GetVisibility(VRControl control) public void SetVisibility(bool visible, float duration, VRControl control) { VisibilityState visibilityState; - if (m_AffordanceVisibilityStates.TryGetValue(control, out visibilityState)) + if (m_AffordanceVisibilityStates.TryGetValue((int)control, out visibilityState)) { visibilityState.visible = visible; visibilityState.visibleDuration = duration; @@ -310,7 +322,7 @@ public void OnDestroy() /// They are used to relate feedback requests to the persistent count of visible presentations used to suppress feedback /// [Serializable] - internal struct RequestKey + internal class RequestKey { /// /// The control index used to identify the related affordance @@ -324,7 +336,7 @@ internal struct RequestKey [SerializeField] string m_TooltipText; - public RequestKey(ProxyFeedbackRequest request) + public void UpdateValues(ProxyFeedbackRequest request) { m_Control = request.control; m_TooltipText = request.tooltipText; @@ -339,6 +351,18 @@ public override int GetHashCode() return hashCode; } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + + if (!(obj is RequestKey)) + return false; + + var key = (RequestKey)obj; + return m_Control == key.m_Control && string.Equals(m_TooltipText, key.m_TooltipText); + } } /// @@ -347,6 +371,8 @@ public override int GetHashCode() [Serializable] internal class RequestData { + readonly Action m_OnBecameVisible; + [SerializeField] int m_Presentations; @@ -360,6 +386,21 @@ public int presentations } public bool visibleThisPresentation { get; set; } + + public Action onBecameVisible { get { return m_OnBecameVisible; } } + + public RequestData() + { + m_OnBecameVisible = OnBecameVisible; + } + + void OnBecameVisible() + { + if (!visibleThisPresentation) + presentations++; + + visibleThisPresentation = true; + } } /// @@ -428,6 +469,7 @@ internal class SerializedFeedback // Local method use only -- created here to reduce garbage collection static readonly List k_FeedbackRequestsCopy = new List(); + readonly Queue m_RequestKeyPool = new Queue(); /// /// The transform that the device's ray contents (default ray, custom ray, etc) will be parented under @@ -453,7 +495,6 @@ internal class SerializedFeedback /// The transform that the display/preview objects will be parented under /// public Transform fieldGrabOrigin { get { return m_FieldGrabOrigin; } } - void Awake() { // Don't allow setup if affordances are invalid @@ -699,12 +740,17 @@ void ExecuteFeedback(ProxyFeedbackRequest changedRequest) if (request == null) return; - var feedbackKey = new RequestKey(request); + var requestKey = GetRequestKey(); + requestKey.UpdateValues(request); RequestData data; - if (!m_RequestData.TryGetValue(feedbackKey, out data)) + if (!m_RequestData.TryGetValue(requestKey, out data)) { data = new RequestData(); - m_RequestData[feedbackKey] = data; + m_RequestData[requestKey] = data; + } + else + { + m_RequestKeyPool.Enqueue(requestKey); } var suppress = data.presentations > request.maxPresentations - 1; @@ -734,19 +780,21 @@ void ExecuteFeedback(ProxyFeedbackRequest changedRequest) data.visibleThisPresentation = false; tooltip.tooltipText = tooltipText; this.ShowTooltip(tooltip, true, placement: tooltip.GetPlacement(m_FacingDirection), - becameVisible: () => - { - if (!data.visibleThisPresentation) - data.presentations++; - - data.visibleThisPresentation = true; - }); + becameVisible: data.onBecameVisible); } } } } } + RequestKey GetRequestKey() + { + if (m_RequestKeyPool.Count > 0) + return m_RequestKeyPool.Dequeue(); + + return new RequestKey(); + } + public void RemoveFeedbackRequest(ProxyFeedbackRequest request) { foreach (var affordance in m_Affordances) @@ -776,6 +824,7 @@ public void RemoveFeedbackRequest(ProxyFeedbackRequest request) if (feedbackRequest == request) { m_FeedbackRequests.Remove(feedbackRequest); + if (!request.showBody) ExecuteFeedback(request); diff --git a/Scripts/Proxies/TwoHandedProxyBase.cs b/Scripts/Proxies/TwoHandedProxyBase.cs index c34a8276a..ec0bdbca6 100644 --- a/Scripts/Proxies/TwoHandedProxyBase.cs +++ b/Scripts/Proxies/TwoHandedProxyBase.cs @@ -1,233 +1,233 @@ -#if UNITY_EDITOR -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Helpers; -using UnityEditor.Experimental.EditorVR.Input; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Proxies -{ - /// - /// Which cardinal direction a proxy node is facing - /// - [Flags] - public enum FacingDirection - { - Front = 1 << 0, - Back = 1 << 1, - Left = 1 << 2, - Right = 1 << 3, - Top = 1 << 4, - Bottom = 1 << 5 - } - - abstract class TwoHandedProxyBase : MonoBehaviour, IProxy, IFeedbackReceiver, ISetTooltipVisibility, ISetHighlight, ISerializePreferences - { - [Serializable] - class SerializedFeedback - { - public ProxyNode.SerializedFeedback leftNode; - public ProxyNode.SerializedFeedback rightNode; - } - - [SerializeField] - protected GameObject m_LeftHandProxyPrefab; - - [SerializeField] - protected GameObject m_RightHandProxyPrefab; - - [SerializeField] - protected PlayerInput m_PlayerInput; - - [SerializeField] - [Tooltip("How much strength the controllers must be shaken with before fading in")] - protected float m_ShakeThreshhold = 0.5f; - - [SerializeField] - [Tooltip("Controls the smoothing and how long of a history detection of left controller shake has")] - protected ShakeVelocityTracker m_LeftShakeTracker = new ShakeVelocityTracker(); - - [SerializeField] - [Tooltip("Controls the smoothing and how long of a history detection of right controller shake has")] - protected ShakeVelocityTracker m_RightShakeTracker = new ShakeVelocityTracker(); - - protected IInputToEvents m_InputToEvents; - - protected Transform m_LeftHand; - protected Transform m_RightHand; - - protected Dictionary m_RayOrigins; - - bool m_Hidden; - ProxyNode m_LeftProxyNode; - ProxyNode m_RightProxyNode; - - public Transform leftHand { get { return m_LeftHand; } } - public Transform rightHand { get { return m_RightHand; } } - - public virtual Dictionary rayOrigins { get { return m_RayOrigins; } } - - public virtual TrackedObject trackedObjectInput { protected get; set; } - - public bool active { get { return m_InputToEvents.active; } } - - public event Action activeChanged - { - add { m_InputToEvents.activeChanged += value; } - remove { m_InputToEvents.activeChanged -= value; } - } - - public virtual bool hidden - { - set - { - if (value != m_Hidden) - { - m_Hidden = value; - m_LeftHand.gameObject.SetActive(!value); - m_RightHand.gameObject.SetActive(!value); - } - } - } - - public Dictionary menuOrigins { get; set; } - public Dictionary alternateMenuOrigins { get; set; } - public Dictionary previewOrigins { get; set; } - public Dictionary fieldGrabOrigins { get; set; } - - protected virtual void Awake() - { - m_LeftHand = ObjectUtils.Instantiate(m_LeftHandProxyPrefab, transform).transform; - m_RightHand = ObjectUtils.Instantiate(m_RightHandProxyPrefab, transform).transform; - - m_LeftProxyNode = m_LeftHand.GetComponent(); - m_RightProxyNode = m_RightHand.GetComponent(); - - m_RayOrigins = new Dictionary - { - { Node.LeftHand, m_LeftProxyNode.rayOrigin }, - { Node.RightHand, m_RightProxyNode.rayOrigin } - }; - - menuOrigins = new Dictionary() - { - { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.menuOrigin }, - { m_RightProxyNode.rayOrigin, m_RightProxyNode.menuOrigin }, - }; - - alternateMenuOrigins = new Dictionary() - { - { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.alternateMenuOrigin }, - { m_RightProxyNode.rayOrigin, m_RightProxyNode.alternateMenuOrigin }, - }; - - previewOrigins = new Dictionary - { - { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.previewOrigin }, - { m_RightProxyNode.rayOrigin, m_RightProxyNode.previewOrigin } - }; - - fieldGrabOrigins = new Dictionary - { - { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.fieldGrabOrigin }, - { m_RightProxyNode.rayOrigin, m_RightProxyNode.fieldGrabOrigin } - }; - } - - protected virtual IEnumerator Start() - { - hidden = true; - while (!active) - yield return null; - - // In standalone play-mode usage, attempt to get the TrackedObjectInput - if (trackedObjectInput == null && m_PlayerInput) - trackedObjectInput = m_PlayerInput.GetActions(); - - m_LeftShakeTracker.Initialize(trackedObjectInput.leftPosition.vector3); - m_RightShakeTracker.Initialize(trackedObjectInput.rightPosition.vector3); - } - - protected virtual void Update() - { - if (active) - { - var leftLocalPosition = trackedObjectInput.leftPosition.vector3; - m_LeftHand.localPosition = leftLocalPosition; - m_LeftHand.localRotation = trackedObjectInput.leftRotation.quaternion; - - var rightLocalPosition = trackedObjectInput.rightPosition.vector3; - m_RightHand.localPosition = rightLocalPosition; - m_RightHand.localRotation = trackedObjectInput.rightRotation.quaternion; - - m_LeftShakeTracker.Update(leftLocalPosition, Time.deltaTime); - m_RightShakeTracker.Update(rightLocalPosition, Time.deltaTime); - - if (Mathf.Max(m_LeftShakeTracker.shakeStrength, m_RightShakeTracker.shakeStrength) > m_ShakeThreshhold) - { - m_LeftProxyNode.AddShakeRequest(); - m_RightProxyNode.AddShakeRequest(); - } - } - } - - public void AddFeedbackRequest(FeedbackRequest request) - { - var proxyRequest = request as ProxyFeedbackRequest; - if (proxyRequest != null) - { - if (proxyRequest.node == Node.LeftHand) - m_LeftProxyNode.AddFeedbackRequest(proxyRequest); - else if (proxyRequest.node == Node.RightHand) - m_RightProxyNode.AddFeedbackRequest(proxyRequest); - } - } - - public void RemoveFeedbackRequest(FeedbackRequest request) - { - var proxyRequest = request as ProxyFeedbackRequest; - if (proxyRequest != null) - { - if (proxyRequest.node == Node.LeftHand) - m_LeftProxyNode.RemoveFeedbackRequest(proxyRequest); - else if (proxyRequest.node == Node.RightHand) - m_RightProxyNode.RemoveFeedbackRequest(proxyRequest); - } - } - - public void ClearFeedbackRequests(IRequestFeedback caller) - { - // Check for null in order to prevent MissingReferenceException when exiting EXR - if (m_LeftProxyNode && m_RightProxyNode) - { - m_LeftProxyNode.ClearFeedbackRequests(caller); - m_RightProxyNode.ClearFeedbackRequests(caller); - } - } - - public object OnSerializePreferences() - { - if (!active) - return null; - - return new SerializedFeedback - { - leftNode = m_LeftProxyNode.OnSerializePreferences(), - rightNode = m_RightProxyNode.OnSerializePreferences() - }; - } - - public void OnDeserializePreferences(object obj) - { - var serializedFeedback = (SerializedFeedback)obj; - - m_LeftProxyNode.OnDeserializePreferences(serializedFeedback.leftNode); - m_RightProxyNode.OnDeserializePreferences(serializedFeedback.rightNode); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Helpers; +using UnityEditor.Experimental.EditorVR.Input; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Proxies +{ + /// + /// Which cardinal direction a proxy node is facing + /// + [Flags] + public enum FacingDirection + { + Front = 1 << 0, + Back = 1 << 1, + Left = 1 << 2, + Right = 1 << 3, + Top = 1 << 4, + Bottom = 1 << 5 + } + + abstract class TwoHandedProxyBase : MonoBehaviour, IProxy, IFeedbackReceiver, ISetTooltipVisibility, ISetHighlight, ISerializePreferences + { + [Serializable] + class SerializedFeedback + { + public ProxyNode.SerializedFeedback leftNode; + public ProxyNode.SerializedFeedback rightNode; + } + + [SerializeField] + protected GameObject m_LeftHandProxyPrefab; + + [SerializeField] + protected GameObject m_RightHandProxyPrefab; + + [SerializeField] + protected PlayerInput m_PlayerInput; + + [SerializeField] + [Tooltip("How much strength the controllers must be shaken with before fading in")] + protected float m_ShakeThreshhold = 0.5f; + + [SerializeField] + [Tooltip("Controls the smoothing and how long of a history detection of left controller shake has")] + protected ShakeVelocityTracker m_LeftShakeTracker = new ShakeVelocityTracker(); + + [SerializeField] + [Tooltip("Controls the smoothing and how long of a history detection of right controller shake has")] + protected ShakeVelocityTracker m_RightShakeTracker = new ShakeVelocityTracker(); + + protected IInputToEvents m_InputToEvents; + + protected Transform m_LeftHand; + protected Transform m_RightHand; + + protected Dictionary m_RayOrigins; + + bool m_Hidden; + ProxyNode m_LeftProxyNode; + ProxyNode m_RightProxyNode; + + public Transform leftHand { get { return m_LeftHand; } } + public Transform rightHand { get { return m_RightHand; } } + + public virtual Dictionary rayOrigins { get { return m_RayOrigins; } } + + public virtual TrackedObject trackedObjectInput { protected get; set; } + + public bool active { get { return m_InputToEvents.active; } } + + public event Action activeChanged + { + add { m_InputToEvents.activeChanged += value; } + remove { m_InputToEvents.activeChanged -= value; } + } + + public virtual bool hidden + { + set + { + if (value != m_Hidden) + { + m_Hidden = value; + m_LeftHand.gameObject.SetActive(!value); + m_RightHand.gameObject.SetActive(!value); + } + } + } + + public Dictionary menuOrigins { get; set; } + public Dictionary alternateMenuOrigins { get; set; } + public Dictionary previewOrigins { get; set; } + public Dictionary fieldGrabOrigins { get; set; } + + protected virtual void Awake() + { + m_LeftHand = ObjectUtils.Instantiate(m_LeftHandProxyPrefab, transform).transform; + m_RightHand = ObjectUtils.Instantiate(m_RightHandProxyPrefab, transform).transform; + + m_LeftProxyNode = m_LeftHand.GetComponent(); + m_RightProxyNode = m_RightHand.GetComponent(); + + m_RayOrigins = new Dictionary + { + { Node.LeftHand, m_LeftProxyNode.rayOrigin }, + { Node.RightHand, m_RightProxyNode.rayOrigin } + }; + + menuOrigins = new Dictionary() + { + { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.menuOrigin }, + { m_RightProxyNode.rayOrigin, m_RightProxyNode.menuOrigin }, + }; + + alternateMenuOrigins = new Dictionary() + { + { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.alternateMenuOrigin }, + { m_RightProxyNode.rayOrigin, m_RightProxyNode.alternateMenuOrigin }, + }; + + previewOrigins = new Dictionary + { + { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.previewOrigin }, + { m_RightProxyNode.rayOrigin, m_RightProxyNode.previewOrigin } + }; + + fieldGrabOrigins = new Dictionary + { + { m_LeftProxyNode.rayOrigin, m_LeftProxyNode.fieldGrabOrigin }, + { m_RightProxyNode.rayOrigin, m_RightProxyNode.fieldGrabOrigin } + }; + } + + protected virtual IEnumerator Start() + { + hidden = true; + while (!active) + yield return null; + + // In standalone play-mode usage, attempt to get the TrackedObjectInput + if (trackedObjectInput == null && m_PlayerInput) + trackedObjectInput = m_PlayerInput.GetActions(); + + m_LeftShakeTracker.Initialize(trackedObjectInput.leftPosition.vector3); + m_RightShakeTracker.Initialize(trackedObjectInput.rightPosition.vector3); + } + + protected virtual void Update() + { + if (active) + { + var leftLocalPosition = trackedObjectInput.leftPosition.vector3; + m_LeftHand.localPosition = leftLocalPosition; + m_LeftHand.localRotation = trackedObjectInput.leftRotation.quaternion; + + var rightLocalPosition = trackedObjectInput.rightPosition.vector3; + m_RightHand.localPosition = rightLocalPosition; + m_RightHand.localRotation = trackedObjectInput.rightRotation.quaternion; + + m_LeftShakeTracker.Update(leftLocalPosition, Time.deltaTime); + m_RightShakeTracker.Update(rightLocalPosition, Time.deltaTime); + + if (Mathf.Max(m_LeftShakeTracker.shakeStrength, m_RightShakeTracker.shakeStrength) > m_ShakeThreshhold) + { + m_LeftProxyNode.AddShakeRequest(); + m_RightProxyNode.AddShakeRequest(); + } + } + } + + public void AddFeedbackRequest(FeedbackRequest request) + { + var proxyRequest = request as ProxyFeedbackRequest; + if (proxyRequest != null) + { + if (proxyRequest.node == Node.LeftHand) + m_LeftProxyNode.AddFeedbackRequest(proxyRequest); + else if (proxyRequest.node == Node.RightHand) + m_RightProxyNode.AddFeedbackRequest(proxyRequest); + } + } + + public void RemoveFeedbackRequest(FeedbackRequest request) + { + var proxyRequest = request as ProxyFeedbackRequest; + if (proxyRequest != null) + { + if (proxyRequest.node == Node.LeftHand) + m_LeftProxyNode.RemoveFeedbackRequest(proxyRequest); + else if (proxyRequest.node == Node.RightHand) + m_RightProxyNode.RemoveFeedbackRequest(proxyRequest); + } + } + + public void ClearFeedbackRequests(IRequestFeedback caller) + { + // Check for null in order to prevent MissingReferenceException when exiting EXR + if (m_LeftProxyNode && m_RightProxyNode) + { + m_LeftProxyNode.ClearFeedbackRequests(caller); + m_RightProxyNode.ClearFeedbackRequests(caller); + } + } + + public object OnSerializePreferences() + { + if (!active) + return null; + + return new SerializedFeedback + { + leftNode = m_LeftProxyNode.OnSerializePreferences(), + rightNode = m_RightProxyNode.OnSerializePreferences() + }; + } + + public void OnDeserializePreferences(object obj) + { + var serializedFeedback = (SerializedFeedback)obj; + + m_LeftProxyNode.OnDeserializePreferences(serializedFeedback.leftNode); + m_RightProxyNode.OnDeserializePreferences(serializedFeedback.rightNode); + } + } +} +#endif diff --git a/Scripts/UI/InputField.cs b/Scripts/UI/InputField.cs index 33e73d0b9..65f413fc0 100644 --- a/Scripts/UI/InputField.cs +++ b/Scripts/UI/InputField.cs @@ -5,8 +5,10 @@ using System; using System.Collections; +using System.Collections.Generic; using UnityEditor.Experimental.EditorVR.Extensions; using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEditor.Experimental.EditorVR.Workspaces; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; @@ -14,43 +16,48 @@ namespace UnityEditor.Experimental.EditorVR.UI { - abstract class InputField : Selectable, ISelectionFlags, IUsesViewerScale + abstract class InputField : Selectable, ISelectionFlags, IUsesViewerScale, IAllWorkspaces { - const float k_MoveKeyboardTime = 0.2f; - public SelectionFlags selectionFlags { get { return m_SelectionFlags; } set { m_SelectionFlags = value; } } - [SerializeField] - [FlagsProperty] - protected SelectionFlags m_SelectionFlags = SelectionFlags.Ray | SelectionFlags.Direct; - - public Func spawnKeyboard; - protected KeyboardUI m_Keyboard; - [Serializable] public class OnChangeEvent : UnityEvent { } - public OnChangeEvent onValueChanged { get { return m_OnValueChanged; } } + const float k_MoveKeyboardTime = 0.2f; + + [SerializeField] + [FlagsProperty] + SelectionFlags m_SelectionFlags = SelectionFlags.Ray | SelectionFlags.Direct; [SerializeField] - private OnChangeEvent m_OnValueChanged = new OnChangeEvent(); + OnChangeEvent m_OnValueChanged = new OnChangeEvent(); [SerializeField] - protected Text m_TextComponent; + Text m_TextComponent; [SerializeField] - private int m_CharacterLimit = 10; + int m_CharacterLimit = 10; + + [HideInInspector] + [SerializeField] // Serialized so that this remains set after cloning + protected string m_Text = string.Empty; - private bool m_KeyboardOpen; + bool m_KeyboardOpen; Coroutine m_MoveKeyboardCoroutine; + protected KeyboardUI m_Keyboard; + + public Func spawnKeyboard { private get; set; } + + public OnChangeEvent onValueChanged { get { return m_OnValueChanged; } } + public virtual string text { get { return m_Text; } @@ -66,9 +73,7 @@ public virtual string text } } - [HideInInspector] - [SerializeField] // Serialized so that this remains set after cloning - protected string m_Text = string.Empty; + public List allWorkspaces { private get; set; } protected override void OnEnable() { @@ -102,6 +107,13 @@ public override void OnSelect(BaseEventData eventData) // Don't do base functionality } + protected override void OnDisable() + { + // hide the keyboard if there are 0 open inspectors or the selection is null + if (m_KeyboardOpen && (Selection.activeObject == null || !FindAnyOpenInspector())) + CloseKeyboard(true); + } + protected void SendOnValueChangedAndUpdateLabel() { SendOnValueChanged(); @@ -120,6 +132,27 @@ protected virtual void UpdateLabel() m_TextComponent.text = m_Text; } + /// + /// Check if any Inspector workspaces are still open + /// + protected bool FindAnyOpenInspector() + { + if (allWorkspaces == null || allWorkspaces.Count == 0) + return false; + + var found = false; + foreach (var w in allWorkspaces) + { + if (w is InspectorWorkspace) + { + found = true; + break; + } + } + + return found; + } + /// /// Open a keyboard for this input field /// diff --git a/Scripts/Utilities/ObjectUtils.cs b/Scripts/Utilities/ObjectUtils.cs index c681d7b4e..e22160361 100644 --- a/Scripts/Utilities/ObjectUtils.cs +++ b/Scripts/Utilities/ObjectUtils.cs @@ -25,6 +25,7 @@ public static HideFlags hideFlags // Local method use only -- created here to reduce garbage collection static readonly List k_Renderers = new List(); + static readonly List k_Transforms = new List(); public static GameObject Instantiate(GameObject prefab, Transform parent = null, bool worldPositionStays = true, bool runInEditMode = true, bool active = true) @@ -141,12 +142,13 @@ public static Bounds GetBounds(Transform transform) // As a fallback when there are no bounds, collect all transform positions if (b.size == Vector3.zero) { - var transforms = transform.GetComponentsInChildren(); + k_Transforms.Clear(); + transform.GetComponentsInChildren(k_Transforms); - if (transforms.Length > 0) - b.center = transforms[0].position; + if (k_Transforms.Count > 0) + b.center = k_Transforms[0].position; - foreach (var t in transforms) + foreach (var t in k_Transforms) b.Encapsulate(t.position); } diff --git a/Shaders/StandardFogDisabled.shader b/Shaders/StandardFogDisabled.shader index 16e85f194..920e5e964 100644 --- a/Shaders/StandardFogDisabled.shader +++ b/Shaders/StandardFogDisabled.shader @@ -63,7 +63,7 @@ Shader "EditorVR/Standard Fog Disabled" Blend [_SrcBlend] [_DstBlend] ZWrite [_ZWrite] - ZTest Off + ZTest On Offset 0, -1 CGPROGRAM diff --git a/Tools/AnnotationTool/AnnotationTool.cs b/Tools/AnnotationTool/AnnotationTool.cs index b7e723f56..e25297e7e 100644 --- a/Tools/AnnotationTool/AnnotationTool.cs +++ b/Tools/AnnotationTool/AnnotationTool.cs @@ -1,875 +1,874 @@ -#if UNITY_EDITOR -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Experimental.EditorVR.Core; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.UI; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; -using UnityEngine.UI; - -namespace UnityEditor.Experimental.EditorVR.Tools -{ - [MainMenuItem("Annotation", "Create", "Draw in 3D")] - public class AnnotationTool : MonoBehaviour, ITool, ICustomActionMap, IUsesRayOrigin, IRayVisibilitySettings, - IUsesRayOrigins, IInstantiateUI, IUsesMenuOrigins, IUsesCustomMenuOrigins, IUsesViewerScale, IUsesSpatialHash, - IIsHoveringOverUI, IMultiDeviceTool, IUsesDeviceType, ISettingsMenuItemProvider, ISerializePreferences, ILinkedObject, - IUsesNode, IRequestFeedback - { - [Serializable] - class Preferences - { - [SerializeField] - bool m_MeshGroupingMode; - - [SerializeField] - Color m_AnnotationColor = Color.white; - - [SerializeField] - float m_BrushSize = MinBrushSize; - - public bool meshGroupingMode - { - get { return m_MeshGroupingMode; } - set { m_MeshGroupingMode = value; } - } - - public Color annotationColor - { - get { return m_AnnotationColor; } - set { m_AnnotationColor = value; } - } - - public float brushSize - { - get { return m_BrushSize; } - set { m_BrushSize = value; } - } - } - - const float k_MinDistance = 0.003f; - const int k_InitialListSize = 1024; // Pre-allocate lists to avoid GC - - const string k_GroupFormatString = "Group {0}"; - const string k_AnnotationFormatStrig = "Annotation {0}"; - const string k_MainHolderName = "Annotations"; - const string k_MeshName = "Annotation"; - - public const float TipDistance = 0.05f; - public const float MinBrushSize = 0.0025f; - public const float MaxBrushSize = 0.05f; - - public delegate void AnnotationUpdatedCallback(MeshFilter meshFilter); - public static AnnotationUpdatedCallback AnnotationUpdated; - public delegate void AnnotationFinishedCallback(MeshFilter meshFilter); - public static AnnotationFinishedCallback AnnotationFinished; - - [SerializeField] - ActionMap m_ActionMap; - - [SerializeField] - Material m_AnnotationMaterial; - - [SerializeField] - GameObject m_BrushSizePrefab; - - [SerializeField] - GameObject m_ColorPickerActivatorPrefab; - - [SerializeField] - GameObject m_SettingsMenuItemPrefab; - - Action m_BrushSizeChanged; - - Preferences m_Preferences; - - readonly List m_Points = new List(k_InitialListSize); - readonly List m_UpVectors = new List(k_InitialListSize); - readonly List m_Widths = new List(k_InitialListSize); - readonly List m_Groups = new List(); - float m_Length; - - MeshFilter m_CurrentMeshFilter; - Mesh m_CurrentMesh; - Matrix4x4 m_WorldToLocalMesh; - - ColorPickerUI m_ColorPicker; - BrushSizeUI m_BrushSizeUI; - - Transform m_AnnotationRoot; - Transform m_AnnotationHolder; - - AnnotationPointer m_AnnotationPointer; - Vector3 m_OriginalAnnotationPointerLocalScale; - Coroutine m_AnnotationPointerVisibilityCoroutine; - bool m_WasOverUI; - bool m_WasDoingUndoRedo; - - GameObject m_ColorPickerActivator; - - Toggle m_TransformToggle; - Toggle m_MeshToggle; - bool m_BlockValueChangedListener; - - public bool primary { private get; set; } - public Transform rayOrigin { get; set; } - public List otherRayOrigins { private get; set; } - - public Transform menuOrigin { private get; set; } - public Transform alternateMenuOrigin { private get; set; } - - public ActionMap actionMap { get { return m_ActionMap; } } - public bool ignoreLocking { get { return false; } } - - public List linkedObjects { private get; set; } - public Node node { private get; set; } - - public GameObject settingsMenuItemPrefab { get { return m_SettingsMenuItemPrefab; } } - - public GameObject settingsMenuItemInstance - { - set - { - if (value == null) - { - m_TransformToggle = null; - m_MeshToggle = null; - return; - } - - var defaultToggleGroup = value.GetComponentInChildren(); - foreach (var toggle in value.GetComponentsInChildren()) - { - if (toggle == defaultToggleGroup.defaultToggle) - { - m_TransformToggle = toggle; - toggle.onValueChanged.AddListener(isOn => - { - if (m_BlockValueChangedListener) - return; - - // m_Preferences on all instances refer to a single preferences object - m_Preferences.meshGroupingMode = !isOn; - foreach (var linkedObject in linkedObjects) - { - var annotationTool = (AnnotationTool)linkedObject; - if (annotationTool != this) - { - annotationTool.m_BlockValueChangedListener = true; - - //linkedObject.m_ToggleGroup.NotifyToggleOn(isOn ? m_FlyToggle : m_BlinkToggle); - // HACK: Toggle Group claims these toggles are not a part of the group - annotationTool.m_TransformToggle.isOn = isOn; - annotationTool.m_MeshToggle.isOn = !isOn; - annotationTool.m_BlockValueChangedListener = false; - } - } - }); - } - else - { - m_MeshToggle = toggle; - } - } - } - } - - void OnDestroy() - { - if (m_Preferences != null && m_Preferences.meshGroupingMode) - CombineGroups(); - - CleanUpNames(); - - if (rayOrigin) - this.RemoveRayVisibilitySettings(rayOrigin, this); - - if (m_ColorPicker) - ObjectUtils.Destroy(m_ColorPicker.gameObject); - - if (m_BrushSizeUI) - ObjectUtils.Destroy(m_BrushSizeUI.gameObject); - - if (m_ColorPickerActivator) - ObjectUtils.Destroy(m_ColorPickerActivator); - - if (m_AnnotationPointer) - ObjectUtils.Destroy(m_AnnotationPointer.gameObject); - - this.ClearFeedbackRequests(); - } - - void CleanUpNames() - { - if (m_AnnotationRoot == null) - return; - - var groupCount = 0; - var annotationCount = 0; - foreach (Transform child in m_AnnotationRoot) - { - if (child.childCount > 0) - child.name = string.Format(k_GroupFormatString, groupCount++); - else - child.name = string.Format(k_AnnotationFormatStrig, annotationCount++); - } - } - - void Start() - { - // Clear selection so we can't manipulate things - Selection.activeGameObject = null; - - SetupPreferences(); - - if (primary) - { - this.AddRayVisibilitySettings(rayOrigin, this, false, false); - SetupBrushUI(); - HandleBrushSize(m_Preferences.brushSize); - - m_ColorPickerActivator = this.InstantiateUI(m_ColorPickerActivatorPrefab); - var otherRayOrigin = otherRayOrigins.First(); - var otherAltMenu = this.GetCustomAlternateMenuOrigin(otherRayOrigin); - - const float UIOffset = 0.1f; - var colorPickerActivatorTransform = m_ColorPickerActivator.transform; - colorPickerActivatorTransform.SetParent(otherAltMenu); - colorPickerActivatorTransform.localRotation = Quaternion.identity; - colorPickerActivatorTransform.localPosition = (node == Node.LeftHand ? Vector3.left : Vector3.right) * UIOffset; - colorPickerActivatorTransform.localScale = Vector3.one; - - var activator = m_ColorPickerActivator.GetComponentInChildren(); - - m_ColorPicker = activator.GetComponentInChildren(true); - m_ColorPicker.onHideCalled = HideColorPicker; - m_ColorPicker.toolRayOrigin = rayOrigin; - m_ColorPicker.onColorPicked = OnColorPickerValueChanged; - OnColorPickerValueChanged(m_Preferences.annotationColor); - - activator.node = node; - activator.rayOrigin = otherRayOrigin; - activator.showColorPicker = ShowColorPicker; - activator.hideColorPicker = HideColorPicker; - - activator.undoButtonClick += Undo.PerformUndo; - activator.redoButtonClick += Undo.PerformRedo; - - var controls = new BindingDictionary(); - InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, controls); - - foreach (var control in controls) - { - var tooltipText = control.Key; - var suppressExisting = control.Key == "Vertical" || control.Key == "StickButton"; - if (suppressExisting) - tooltipText = null; - - foreach (var id in control.Value) - { - this.AddFeedbackRequest(new ProxyFeedbackRequest - { - node = node, - control = id, - priority = 1, - tooltipText = tooltipText, - suppressExisting = suppressExisting - }); - } - } - } - } - - void SetupPreferences() - { - if (this.IsSharedUpdater(this)) - { - // Share one preferences object across all instances - foreach (var linkedObject in linkedObjects) - { - ((AnnotationTool)linkedObject).m_Preferences = m_Preferences; - } - - if (m_Preferences != null) - { - //Setting toggles on this tool's menu will set them on other tool menus - m_MeshToggle.isOn = m_Preferences.meshGroupingMode; - m_TransformToggle.isOn = !m_Preferences.meshGroupingMode; - } - } - - if (m_Preferences == null) - m_Preferences = new Preferences(); - } - - void SetupBrushUI() - { - m_AnnotationPointer = ObjectUtils.CreateGameObjectWithComponent(rayOrigin, false); - m_OriginalAnnotationPointerLocalScale = m_AnnotationPointer.transform.localScale; - var brushSize = m_Preferences.brushSize; - m_AnnotationPointer.Resize(brushSize); - - var brushSizeUi = this.InstantiateUI(m_BrushSizePrefab); - m_BrushSizeUI = brushSizeUi.GetComponent(); - - var transform = brushSizeUi.transform; - var scale = transform.localScale; - transform.SetParent(alternateMenuOrigin, false); - transform.localPosition = Vector3.zero; - transform.localRotation = Quaternion.Euler(-90, 0, 0); - transform.localScale = scale; - - m_BrushSizeUI.onValueChanged = value => - { - var sliderValue = Mathf.Lerp(MinBrushSize, MaxBrushSize, value); - m_Preferences.brushSize = sliderValue; - m_AnnotationPointer.Resize(sliderValue); - }; - m_BrushSizeChanged = m_BrushSizeUI.ChangeSliderValue; - } - - void ShowColorPicker(Transform otherRayOrigin) - { - if (!m_ColorPicker.enabled) - m_ColorPicker.Show(); - - m_AnnotationPointer.gameObject.SetActive(false); - } - - void HideColorPicker() - { - if (m_ColorPicker && m_ColorPicker.enabled) - { - m_ColorPicker.Hide(); - m_AnnotationPointer.gameObject.SetActive(true); - } - } - - void OnColorPickerValueChanged(Color color) - { - m_Preferences.annotationColor = color; - - const float annotationPointerAlpha = 0.75f; - color.a = annotationPointerAlpha; - m_AnnotationPointer.SetColor(color); - - m_BrushSizeUI.OnBrushColorChanged(color); - } - - void HandleBrushSize(float value) - { - if (m_AnnotationPointer != null) - { - var brushSize = m_Preferences.brushSize; - if (this.GetDeviceType() == DeviceType.Vive) // For vive controllers, use 1:1 touchpad setting. - { - brushSize = Mathf.Lerp(MinBrushSize, MaxBrushSize, (value + 1) / 2f); - } - else // For touch and hydra, let the thumbstick gradually modify the width. - { - brushSize += value * Time.unscaledDeltaTime * .1f; - brushSize = Mathf.Clamp(brushSize, MinBrushSize, MaxBrushSize); - } - - if (m_BrushSizeUI && m_BrushSizeChanged != null) - { - var ratio = Mathf.InverseLerp(MinBrushSize, MaxBrushSize, brushSize); - m_BrushSizeChanged(ratio); - } - - m_AnnotationPointer.Resize(brushSize); - m_Preferences.brushSize = brushSize; - } - } - - void SetupAnnotation() - { - SetupHolder(); - - m_Points.Clear(); - m_UpVectors.Clear(); - m_Widths.Clear(); - m_Length = 0; - - var go = new GameObject(string.Format(k_AnnotationFormatStrig,+ m_AnnotationHolder.childCount)); - - var goTrans = go.transform; - goTrans.SetParent(m_AnnotationHolder); - goTrans.position = rayOrigin.position; - - m_CurrentMeshFilter = go.AddComponent(); - var mRenderer = go.AddComponent(); - - var matToUse = Instantiate(m_AnnotationMaterial); - matToUse.SetColor("_EmissionColor", m_Preferences.annotationColor); - mRenderer.sharedMaterial = matToUse; - - m_WorldToLocalMesh = goTrans.worldToLocalMatrix; - - m_CurrentMesh = new Mesh(); - m_CurrentMesh.name = k_MeshName; - } - - void SetupHolder() - { - var mainHolder = GameObject.Find(k_MainHolderName) ?? new GameObject(k_MainHolderName); - m_AnnotationRoot = mainHolder.transform; - - var newSession = GetNewSessionHolder(); - if (!newSession) - { - newSession = new GameObject(string.Format(k_GroupFormatString, m_AnnotationRoot.childCount)); - newSession.transform.position = GetPointerPosition(); - m_Groups.Add(newSession); - } - - m_AnnotationHolder = newSession.transform; - m_AnnotationHolder.SetParent(m_AnnotationRoot); - } - - GameObject GetNewSessionHolder() - { - const float groupingDistance = 0.3f; - var position = rayOrigin.position; - for (var i = 0; i < m_Groups.Count; i++) - { - var child = m_Groups[i]; - child.name = "Group " + i; - - var renderers = child.GetComponentsInChildren(); - if (renderers.Length > 0) - { - var bound = renderers[0].bounds; - for (var r = 1; r < renderers.Length; r++) - { - bound.Encapsulate(renderers[r].bounds); - } - - if (bound.Contains(position) || bound.SqrDistance(position) < groupingDistance) - return child.gameObject; - } - } - - return null; - } - - void UpdateAnnotation() - { - var upVector = rayOrigin.up; - var viewerScale = this.GetViewerScale(); - var worldPoint = GetPointerPosition(); - var localPoint = m_WorldToLocalMesh.MultiplyPoint3x4(worldPoint); - - if (m_Points.Count > 0) - { - var lastPoint = m_Points.Last(); - localPoint = Vector3.Lerp(lastPoint, localPoint, 0.5f); - var distance = (localPoint - lastPoint).magnitude; - if (distance < k_MinDistance * viewerScale) - return; - - m_Length += distance; - } - - var brushSize = m_Preferences.brushSize * viewerScale; - InterpolatePointsIfNeeded(localPoint, upVector, brushSize); - - m_Points.Add(localPoint); - m_UpVectors.Add(upVector); - m_Widths.Add(brushSize); - - PointsToMesh(); - - if (AnnotationUpdated != null) - { - AnnotationUpdated(m_CurrentMeshFilter); - } - } - - void InterpolatePointsIfNeeded(Vector3 localPoint, Vector3 upVector, float brushSize) - { - if (m_Points.Count > 1) - { - var lastPoint = m_Points.Last(); - var distance = Vector3.Distance(lastPoint, localPoint); - - if (distance > brushSize * .5f) - { - var halfPoint = (lastPoint + localPoint) / 2f; - m_Points.Add(halfPoint); - - var halfUp = (m_UpVectors.Last() + upVector) / 2f; - m_UpVectors.Add(halfUp); - - var halfRadius = (m_Widths.Last() + brushSize) / 2f; - m_Widths.Add(halfRadius); - } - } - } - - void PointsToMesh() - { - if (m_Points.Count < 4) - return; - - if (m_CurrentMesh == null) - m_CurrentMesh = new Mesh(); - - var newVertices = new List(); - var newTriangles = new List(); - var newUvs = new List(); - - LineToPlane(newVertices); - - TriangulatePlane(newTriangles, newVertices.Count); - CalculateUvs(newUvs, newVertices); - - m_CurrentMesh.Clear(); - - m_CurrentMesh.vertices = newVertices.ToArray(); - m_CurrentMesh.triangles = newTriangles.ToArray(); - m_CurrentMesh.uv = newUvs.ToArray(); - - m_CurrentMesh.UploadMeshData(false); - - m_CurrentMeshFilter.sharedMesh = m_CurrentMesh; - } - - void LineToPlane(List newVertices) - { - var distance = 0f; - var lastPoint = m_Points[0]; - for (var i = 1; i < m_Points.Count; i++) - { - var point = m_Points[i]; - var segment = point - lastPoint; - - var width = m_Widths[i]; - - width *= Math.Min(Mathf.Sqrt(distance / width), 1); - var endDistance = m_Length - distance; - width *= Math.Min(Mathf.Sqrt(endDistance / width), 1); - - var upVector = m_UpVectors[i]; - var top = point - upVector * width; - var bottom = point + upVector * width; - - newVertices.Add(top); - newVertices.Add(bottom); - - distance += segment.magnitude; - lastPoint = point; - } - } - - static void TriangulatePlane(List newTriangles, int vertexCount) - { - for (var i = 3; i < vertexCount; i += 2) - { - var upperLeft = i - 1; - var upperRight = i; - var lowerLeft = i - 3; - var lowerRight = i - 2; - - var triangles = VerticesToPolygon(upperLeft, upperRight, lowerLeft, lowerRight); - newTriangles.AddRange(triangles); - } - } - - static void CalculateUvs(List newUvs, List newVertices) - { - for (var i = 0; i < newVertices.Count; i += 2) - { - newUvs.Add(new Vector2(0, i * 0.5f)); - newUvs.Add(new Vector2(1, i * 0.5f)); - } - } - - void FinalizeMesh() - { - CenterMesh(); - - m_CurrentMesh.RecalculateBounds(); - m_CurrentMesh.RecalculateNormals(); - - m_CurrentMesh.UploadMeshData(false); - - CenterHolder(); - - var go = m_CurrentMeshFilter.gameObject; - - this.AddToSpatialHash(go); - - Undo.IncrementCurrentGroup(); - Undo.RegisterCreatedObjectUndo(go, "Create Annotation"); - - if (AnnotationFinished != null) - { - AnnotationFinished(m_CurrentMeshFilter); - } - } - - void CenterMesh() - { - if (m_CurrentMesh == null || m_CurrentMesh.vertexCount == 0) - return; - - var center = Vector3.zero; - - var vertices = m_CurrentMesh.vertices; - - for (var i = 0; i < m_CurrentMesh.vertexCount; i++) - { - center += vertices[i]; - } - - center /= m_CurrentMesh.vertexCount; - - for (var i = 0; i < m_CurrentMesh.vertexCount; i++) - { - vertices[i] -= center; - } - - m_CurrentMesh.vertices = vertices; - m_CurrentMeshFilter.transform.localPosition += center; - } - - void CenterHolder() - { - if (m_AnnotationHolder == null || m_AnnotationHolder.childCount == 0) - return; - - var childWorldPositions = new List(); - var center = Vector3.zero; - - for (var i = 0; i < m_AnnotationHolder.childCount; i++) - { - var worldPos = m_AnnotationHolder.GetChild(i).position; - childWorldPositions.Add(worldPos); - center += worldPos; - } - - center /= m_AnnotationHolder.childCount; - - m_AnnotationHolder.localPosition += center; - for (var i = 0; i < m_AnnotationHolder.childCount; i++) - { - m_AnnotationHolder.GetChild(i).position = childWorldPositions[i]; - } - } - - public static int[] VerticesToPolygon(int upperLeft, int upperRight, int lowerLeft, int lowerRight, bool doubleSided = true) - { - var triangleCount = doubleSided ? 12 : 6; - var triangles = new int[triangleCount]; - var index = 0; - - triangles[index++] = upperLeft; - triangles[index++] = lowerRight; - triangles[index++] = lowerLeft; - - triangles[index++] = lowerRight; - triangles[index++] = upperLeft; - triangles[index++] = upperRight; - - if (doubleSided) - { - triangles[index++] = lowerLeft; - triangles[index++] = lowerRight; - triangles[index++] = upperLeft; - - triangles[index++] = upperRight; - triangles[index++] = upperLeft; - triangles[index] = lowerRight; - } - - return triangles; - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - var annotationInput = (AnnotationInput)input; - - var draw = annotationInput.draw; - var isHeld = draw.isHeld; - if (primary) - { - if (!Mathf.Approximately(annotationInput.changeBrushSize.value, 0)) - { - HandleBrushSize(annotationInput.changeBrushSize.value); - consumeControl(annotationInput.changeBrushSize); - consumeControl(annotationInput.vertical); - } - - if (draw.wasJustPressed) - { - SetupAnnotation(); - consumeControl(draw); - } - - if (isHeld) - { - UpdateAnnotation(); - consumeControl(draw); - } - - if (draw.wasJustReleased) - { - FinalizeMesh(); - consumeControl(draw); - } - } - else - { - // Secondary hand uses brush size input to do undo/redo - var value = annotationInput.changeBrushSize.value; - if (this.GetDeviceType() == DeviceType.Vive) - { - if (annotationInput.stickButton.wasJustPressed) - { - if (value > 0) - Undo.PerformRedo(); - else - Undo.PerformUndo(); - } - } - else - { - var doUndoRedo = Math.Abs(value) > 0.5f; - if (doUndoRedo != m_WasDoingUndoRedo) - { - m_WasDoingUndoRedo = doUndoRedo; - if (doUndoRedo) - { - if (value > 0) - Undo.PerformRedo(); - else - Undo.PerformUndo(); - } - } - - consumeControl(annotationInput.changeBrushSize); - consumeControl(annotationInput.vertical); - } - } - - if (isHeld) - return; - - var isOverUI = this.IsHoveringOverUI(rayOrigin); - if (isOverUI != m_WasOverUI) - { - m_WasOverUI = isOverUI; - this.RestartCoroutine(ref m_AnnotationPointerVisibilityCoroutine, SetAnnotationPointerVisibility(!isOverUI)); - if (isOverUI) - this.RemoveRayVisibilitySettings(rayOrigin, this); - else - this.AddRayVisibilitySettings(rayOrigin, this, false, false); - } - } - - IEnumerator SetAnnotationPointerVisibility(bool visible) - { - if (!m_AnnotationPointer) - yield break; - - const float transitionTime = 0.1875f; - var annotationPointerTransform = m_AnnotationPointer.transform; - var startTime = Time.time; - var timeDiff = 0f; - var currentScale = annotationPointerTransform.localScale; - var targetScale = visible ? m_OriginalAnnotationPointerLocalScale : Vector3.zero; - while (timeDiff < transitionTime) - { - annotationPointerTransform.localScale = Vector3.Lerp(currentScale, targetScale, timeDiff / transitionTime); - timeDiff = Time.time - startTime; - yield return null; - } - - annotationPointerTransform.localScale = targetScale; - } - - void CombineGroups() - { - foreach (var group in m_Groups) - { - var meshFilters = group.GetComponentsInChildren(); - var renderers = group.GetComponentsInChildren(); - - if (meshFilters.Length == 0) - { - ObjectUtils.Destroy(group); - continue; - } - - var length = meshFilters.Length; - var combines = new List(length); - var materials = new List(length); - for (var i = 0; i < length; i++) - { - var meshFilter = meshFilters[i]; - var sharedMesh = meshFilter.sharedMesh; - if (sharedMesh && sharedMesh.vertexCount > 0) - { - var combine = new CombineInstance - { - mesh = sharedMesh, - transform = group.transform.worldToLocalMatrix * meshFilter.transform.localToWorldMatrix - }; - - sharedMesh.UploadMeshData(false); - combines.Add(combine); - materials.Add(renderers[i].sharedMaterial); - } - } - - var mesh = new Mesh(); - mesh.CombineMeshes(combines.ToArray(), false, true); - group.AddComponent().sharedMesh = mesh; - - group.AddComponent().sharedMaterials = materials.ToArray(); - - this.AddToSpatialHash(group); - - foreach (var meshFilter in meshFilters) - { - var go = meshFilter.gameObject; - this.RemoveFromSpatialHash(go); - ObjectUtils.Destroy(go); - } - } - } - - Vector3 GetPointerPosition() - { - return rayOrigin.position + rayOrigin.forward * TipDistance * this.GetViewerScale(); - } - - public object OnSerializePreferences() - { - if (this.IsSharedUpdater(this)) - { - // Share one preferences object across all instances - foreach (var linkedObject in linkedObjects) - { - ((AnnotationTool)linkedObject).m_Preferences = m_Preferences; - } - - return m_Preferences; - } - - return null; - } - - public void OnDeserializePreferences(object obj) - { - if (m_Preferences == null) - m_Preferences = (Preferences)obj; - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; +using UnityEngine.UI; + +namespace UnityEditor.Experimental.EditorVR.Tools +{ + [MainMenuItem("Annotation", "Create", "Draw in 3D")] + public class AnnotationTool : MonoBehaviour, ITool, ICustomActionMap, IUsesRayOrigin, IRayVisibilitySettings, + IUsesRayOrigins, IInstantiateUI, IUsesMenuOrigins, IUsesCustomMenuOrigins, IUsesViewerScale, IUsesSpatialHash, + IIsHoveringOverUI, IMultiDeviceTool, IUsesDeviceType, ISettingsMenuItemProvider, ISerializePreferences, ILinkedObject, + IUsesNode, IRequestFeedback + { + [Serializable] + class Preferences + { + [SerializeField] + bool m_MeshGroupingMode; + + [SerializeField] + Color m_AnnotationColor = Color.white; + + [SerializeField] + float m_BrushSize = MinBrushSize; + + public bool meshGroupingMode + { + get { return m_MeshGroupingMode; } + set { m_MeshGroupingMode = value; } + } + + public Color annotationColor + { + get { return m_AnnotationColor; } + set { m_AnnotationColor = value; } + } + + public float brushSize + { + get { return m_BrushSize; } + set { m_BrushSize = value; } + } + } + + const float k_MinDistance = 0.003f; + const int k_InitialListSize = 1024; // Pre-allocate lists to avoid GC + + const string k_GroupFormatString = "Group {0}"; + const string k_AnnotationFormatStrig = "Annotation {0}"; + const string k_MainHolderName = "Annotations"; + const string k_MeshName = "Annotation"; + + public const float TipDistance = 0.05f; + public const float MinBrushSize = 0.0025f; + public const float MaxBrushSize = 0.05f; + + public delegate void AnnotationUpdatedCallback(MeshFilter meshFilter); + public static AnnotationUpdatedCallback AnnotationUpdated; + public delegate void AnnotationFinishedCallback(MeshFilter meshFilter); + public static AnnotationFinishedCallback AnnotationFinished; + + [SerializeField] + ActionMap m_ActionMap; + + [SerializeField] + Material m_AnnotationMaterial; + + [SerializeField] + GameObject m_BrushSizePrefab; + + [SerializeField] + GameObject m_ColorPickerActivatorPrefab; + + [SerializeField] + GameObject m_SettingsMenuItemPrefab; + + Action m_BrushSizeChanged; + + Preferences m_Preferences; + + readonly List m_Points = new List(k_InitialListSize); + readonly List m_UpVectors = new List(k_InitialListSize); + readonly List m_Widths = new List(k_InitialListSize); + readonly List m_Groups = new List(); + float m_Length; + + MeshFilter m_CurrentMeshFilter; + Mesh m_CurrentMesh; + Matrix4x4 m_WorldToLocalMesh; + + ColorPickerUI m_ColorPicker; + BrushSizeUI m_BrushSizeUI; + + Transform m_AnnotationRoot; + Transform m_AnnotationHolder; + + AnnotationPointer m_AnnotationPointer; + Vector3 m_OriginalAnnotationPointerLocalScale; + Coroutine m_AnnotationPointerVisibilityCoroutine; + bool m_WasOverUI; + bool m_WasDoingUndoRedo; + + GameObject m_ColorPickerActivator; + + Toggle m_TransformToggle; + Toggle m_MeshToggle; + bool m_BlockValueChangedListener; + + public bool primary { private get; set; } + public Transform rayOrigin { get; set; } + public List otherRayOrigins { private get; set; } + + public Transform menuOrigin { private get; set; } + public Transform alternateMenuOrigin { private get; set; } + + public ActionMap actionMap { get { return m_ActionMap; } } + public bool ignoreLocking { get { return false; } } + + public List linkedObjects { private get; set; } + public Node node { private get; set; } + + public GameObject settingsMenuItemPrefab { get { return m_SettingsMenuItemPrefab; } } + + public GameObject settingsMenuItemInstance + { + set + { + if (value == null) + { + m_TransformToggle = null; + m_MeshToggle = null; + return; + } + + var defaultToggleGroup = value.GetComponentInChildren(); + foreach (var toggle in value.GetComponentsInChildren()) + { + if (toggle == defaultToggleGroup.defaultToggle) + { + m_TransformToggle = toggle; + toggle.onValueChanged.AddListener(isOn => + { + if (m_BlockValueChangedListener) + return; + + // m_Preferences on all instances refer to a single preferences object + m_Preferences.meshGroupingMode = !isOn; + foreach (var linkedObject in linkedObjects) + { + var annotationTool = (AnnotationTool)linkedObject; + if (annotationTool != this) + { + annotationTool.m_BlockValueChangedListener = true; + + //linkedObject.m_ToggleGroup.NotifyToggleOn(isOn ? m_FlyToggle : m_BlinkToggle); + // HACK: Toggle Group claims these toggles are not a part of the group + annotationTool.m_TransformToggle.isOn = isOn; + annotationTool.m_MeshToggle.isOn = !isOn; + annotationTool.m_BlockValueChangedListener = false; + } + } + }); + } + else + { + m_MeshToggle = toggle; + } + } + } + } + + void OnDestroy() + { + if (m_Preferences != null && m_Preferences.meshGroupingMode) + CombineGroups(); + + CleanUpNames(); + + if (rayOrigin) + this.RemoveRayVisibilitySettings(rayOrigin, this); + + if (m_ColorPicker) + ObjectUtils.Destroy(m_ColorPicker.gameObject); + + if (m_BrushSizeUI) + ObjectUtils.Destroy(m_BrushSizeUI.gameObject); + + if (m_ColorPickerActivator) + ObjectUtils.Destroy(m_ColorPickerActivator); + + if (m_AnnotationPointer) + ObjectUtils.Destroy(m_AnnotationPointer.gameObject); + + this.ClearFeedbackRequests(); + } + + void CleanUpNames() + { + if (m_AnnotationRoot == null) + return; + + var groupCount = 0; + var annotationCount = 0; + foreach (Transform child in m_AnnotationRoot) + { + if (child.childCount > 0) + child.name = string.Format(k_GroupFormatString, groupCount++); + else + child.name = string.Format(k_AnnotationFormatStrig, annotationCount++); + } + } + + void Start() + { + // Clear selection so we can't manipulate things + Selection.activeGameObject = null; + + SetupPreferences(); + + if (primary) + { + this.AddRayVisibilitySettings(rayOrigin, this, false, false); + SetupBrushUI(); + HandleBrushSize(m_Preferences.brushSize); + + m_ColorPickerActivator = this.InstantiateUI(m_ColorPickerActivatorPrefab); + var otherRayOrigin = otherRayOrigins.First(); + var otherAltMenu = this.GetCustomAlternateMenuOrigin(otherRayOrigin); + + const float UIOffset = 0.1f; + var colorPickerActivatorTransform = m_ColorPickerActivator.transform; + colorPickerActivatorTransform.SetParent(otherAltMenu); + colorPickerActivatorTransform.localRotation = Quaternion.identity; + colorPickerActivatorTransform.localPosition = (node == Node.LeftHand ? Vector3.left : Vector3.right) * UIOffset; + colorPickerActivatorTransform.localScale = Vector3.one; + + var activator = m_ColorPickerActivator.GetComponentInChildren(); + + m_ColorPicker = activator.GetComponentInChildren(true); + m_ColorPicker.onHideCalled = HideColorPicker; + m_ColorPicker.toolRayOrigin = rayOrigin; + m_ColorPicker.onColorPicked = OnColorPickerValueChanged; + OnColorPickerValueChanged(m_Preferences.annotationColor); + + activator.node = node; + activator.rayOrigin = otherRayOrigin; + activator.showColorPicker = ShowColorPicker; + activator.hideColorPicker = HideColorPicker; + + activator.undoButtonClick += Undo.PerformUndo; + activator.redoButtonClick += Undo.PerformRedo; + + var controls = new BindingDictionary(); + InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, controls); + + foreach (var control in controls) + { + var tooltipText = control.Key; + var suppressExisting = control.Key == "Vertical" || control.Key == "StickButton"; + if (suppressExisting) + tooltipText = null; + + foreach (var id in control.Value) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.priority = 1; + request.tooltipText = tooltipText; + request.suppressExisting = suppressExisting; + this.AddFeedbackRequest(request); + } + } + } + } + + void SetupPreferences() + { + if (this.IsSharedUpdater(this)) + { + // Share one preferences object across all instances + foreach (var linkedObject in linkedObjects) + { + ((AnnotationTool)linkedObject).m_Preferences = m_Preferences; + } + + if (m_Preferences != null) + { + //Setting toggles on this tool's menu will set them on other tool menus + m_MeshToggle.isOn = m_Preferences.meshGroupingMode; + m_TransformToggle.isOn = !m_Preferences.meshGroupingMode; + } + } + + if (m_Preferences == null) + m_Preferences = new Preferences(); + } + + void SetupBrushUI() + { + m_AnnotationPointer = ObjectUtils.CreateGameObjectWithComponent(rayOrigin, false); + m_OriginalAnnotationPointerLocalScale = m_AnnotationPointer.transform.localScale; + var brushSize = m_Preferences.brushSize; + m_AnnotationPointer.Resize(brushSize); + + var brushSizeUi = this.InstantiateUI(m_BrushSizePrefab); + m_BrushSizeUI = brushSizeUi.GetComponent(); + + var transform = brushSizeUi.transform; + var scale = transform.localScale; + transform.SetParent(alternateMenuOrigin, false); + transform.localPosition = Vector3.zero; + transform.localRotation = Quaternion.Euler(-90, 0, 0); + transform.localScale = scale; + + m_BrushSizeUI.onValueChanged = value => + { + var sliderValue = Mathf.Lerp(MinBrushSize, MaxBrushSize, value); + m_Preferences.brushSize = sliderValue; + m_AnnotationPointer.Resize(sliderValue); + }; + m_BrushSizeChanged = m_BrushSizeUI.ChangeSliderValue; + } + + void ShowColorPicker(Transform otherRayOrigin) + { + if (!m_ColorPicker.enabled) + m_ColorPicker.Show(); + + m_AnnotationPointer.gameObject.SetActive(false); + } + + void HideColorPicker() + { + if (m_ColorPicker && m_ColorPicker.enabled) + { + m_ColorPicker.Hide(); + m_AnnotationPointer.gameObject.SetActive(true); + } + } + + void OnColorPickerValueChanged(Color color) + { + m_Preferences.annotationColor = color; + + const float annotationPointerAlpha = 0.75f; + color.a = annotationPointerAlpha; + m_AnnotationPointer.SetColor(color); + + m_BrushSizeUI.OnBrushColorChanged(color); + } + + void HandleBrushSize(float value) + { + if (m_AnnotationPointer != null) + { + var brushSize = m_Preferences.brushSize; + if (this.GetDeviceType() == DeviceType.Vive) // For vive controllers, use 1:1 touchpad setting. + { + brushSize = Mathf.Lerp(MinBrushSize, MaxBrushSize, (value + 1) / 2f); + } + else // For touch and hydra, let the thumbstick gradually modify the width. + { + brushSize += value * Time.unscaledDeltaTime * .1f; + brushSize = Mathf.Clamp(brushSize, MinBrushSize, MaxBrushSize); + } + + if (m_BrushSizeUI && m_BrushSizeChanged != null) + { + var ratio = Mathf.InverseLerp(MinBrushSize, MaxBrushSize, brushSize); + m_BrushSizeChanged(ratio); + } + + m_AnnotationPointer.Resize(brushSize); + m_Preferences.brushSize = brushSize; + } + } + + void SetupAnnotation() + { + SetupHolder(); + + m_Points.Clear(); + m_UpVectors.Clear(); + m_Widths.Clear(); + m_Length = 0; + + var go = new GameObject(string.Format(k_AnnotationFormatStrig,+ m_AnnotationHolder.childCount)); + + var goTrans = go.transform; + goTrans.SetParent(m_AnnotationHolder); + goTrans.position = rayOrigin.position; + + m_CurrentMeshFilter = go.AddComponent(); + var mRenderer = go.AddComponent(); + + var matToUse = Instantiate(m_AnnotationMaterial); + matToUse.SetColor("_EmissionColor", m_Preferences.annotationColor); + mRenderer.sharedMaterial = matToUse; + + m_WorldToLocalMesh = goTrans.worldToLocalMatrix; + + m_CurrentMesh = new Mesh(); + m_CurrentMesh.name = k_MeshName; + } + + void SetupHolder() + { + var mainHolder = GameObject.Find(k_MainHolderName) ?? new GameObject(k_MainHolderName); + m_AnnotationRoot = mainHolder.transform; + + var newSession = GetNewSessionHolder(); + if (!newSession) + { + newSession = new GameObject(string.Format(k_GroupFormatString, m_AnnotationRoot.childCount)); + newSession.transform.position = GetPointerPosition(); + m_Groups.Add(newSession); + } + + m_AnnotationHolder = newSession.transform; + m_AnnotationHolder.SetParent(m_AnnotationRoot); + } + + GameObject GetNewSessionHolder() + { + const float groupingDistance = 0.3f; + var position = rayOrigin.position; + for (var i = 0; i < m_Groups.Count; i++) + { + var child = m_Groups[i]; + child.name = "Group " + i; + + var renderers = child.GetComponentsInChildren(); + if (renderers.Length > 0) + { + var bound = renderers[0].bounds; + for (var r = 1; r < renderers.Length; r++) + { + bound.Encapsulate(renderers[r].bounds); + } + + if (bound.Contains(position) || bound.SqrDistance(position) < groupingDistance) + return child.gameObject; + } + } + + return null; + } + + void UpdateAnnotation() + { + var upVector = rayOrigin.up; + var viewerScale = this.GetViewerScale(); + var worldPoint = GetPointerPosition(); + var localPoint = m_WorldToLocalMesh.MultiplyPoint3x4(worldPoint); + + if (m_Points.Count > 0) + { + var lastPoint = m_Points.Last(); + localPoint = Vector3.Lerp(lastPoint, localPoint, 0.5f); + var distance = (localPoint - lastPoint).magnitude; + if (distance < k_MinDistance * viewerScale) + return; + + m_Length += distance; + } + + var brushSize = m_Preferences.brushSize * viewerScale; + InterpolatePointsIfNeeded(localPoint, upVector, brushSize); + + m_Points.Add(localPoint); + m_UpVectors.Add(upVector); + m_Widths.Add(brushSize); + + PointsToMesh(); + + if (AnnotationUpdated != null) + { + AnnotationUpdated(m_CurrentMeshFilter); + } + } + + void InterpolatePointsIfNeeded(Vector3 localPoint, Vector3 upVector, float brushSize) + { + if (m_Points.Count > 1) + { + var lastPoint = m_Points.Last(); + var distance = Vector3.Distance(lastPoint, localPoint); + + if (distance > brushSize * .5f) + { + var halfPoint = (lastPoint + localPoint) / 2f; + m_Points.Add(halfPoint); + + var halfUp = (m_UpVectors.Last() + upVector) / 2f; + m_UpVectors.Add(halfUp); + + var halfRadius = (m_Widths.Last() + brushSize) / 2f; + m_Widths.Add(halfRadius); + } + } + } + + void PointsToMesh() + { + if (m_Points.Count < 4) + return; + + if (m_CurrentMesh == null) + m_CurrentMesh = new Mesh(); + + var newVertices = new List(); + var newTriangles = new List(); + var newUvs = new List(); + + LineToPlane(newVertices); + + TriangulatePlane(newTriangles, newVertices.Count); + CalculateUvs(newUvs, newVertices); + + m_CurrentMesh.Clear(); + + m_CurrentMesh.vertices = newVertices.ToArray(); + m_CurrentMesh.triangles = newTriangles.ToArray(); + m_CurrentMesh.uv = newUvs.ToArray(); + + m_CurrentMesh.UploadMeshData(false); + + m_CurrentMeshFilter.sharedMesh = m_CurrentMesh; + } + + void LineToPlane(List newVertices) + { + var distance = 0f; + var lastPoint = m_Points[0]; + for (var i = 1; i < m_Points.Count; i++) + { + var point = m_Points[i]; + var segment = point - lastPoint; + + var width = m_Widths[i]; + + width *= Math.Min(Mathf.Sqrt(distance / width), 1); + var endDistance = m_Length - distance; + width *= Math.Min(Mathf.Sqrt(endDistance / width), 1); + + var upVector = m_UpVectors[i]; + var top = point - upVector * width; + var bottom = point + upVector * width; + + newVertices.Add(top); + newVertices.Add(bottom); + + distance += segment.magnitude; + lastPoint = point; + } + } + + static void TriangulatePlane(List newTriangles, int vertexCount) + { + for (var i = 3; i < vertexCount; i += 2) + { + var upperLeft = i - 1; + var upperRight = i; + var lowerLeft = i - 3; + var lowerRight = i - 2; + + var triangles = VerticesToPolygon(upperLeft, upperRight, lowerLeft, lowerRight); + newTriangles.AddRange(triangles); + } + } + + static void CalculateUvs(List newUvs, List newVertices) + { + for (var i = 0; i < newVertices.Count; i += 2) + { + newUvs.Add(new Vector2(0, i * 0.5f)); + newUvs.Add(new Vector2(1, i * 0.5f)); + } + } + + void FinalizeMesh() + { + CenterMesh(); + + m_CurrentMesh.RecalculateBounds(); + m_CurrentMesh.RecalculateNormals(); + + m_CurrentMesh.UploadMeshData(false); + + CenterHolder(); + + var go = m_CurrentMeshFilter.gameObject; + + this.AddToSpatialHash(go); + + Undo.IncrementCurrentGroup(); + Undo.RegisterCreatedObjectUndo(go, "Create Annotation"); + + if (AnnotationFinished != null) + { + AnnotationFinished(m_CurrentMeshFilter); + } + } + + void CenterMesh() + { + if (m_CurrentMesh == null || m_CurrentMesh.vertexCount == 0) + return; + + var center = Vector3.zero; + + var vertices = m_CurrentMesh.vertices; + + for (var i = 0; i < m_CurrentMesh.vertexCount; i++) + { + center += vertices[i]; + } + + center /= m_CurrentMesh.vertexCount; + + for (var i = 0; i < m_CurrentMesh.vertexCount; i++) + { + vertices[i] -= center; + } + + m_CurrentMesh.vertices = vertices; + m_CurrentMeshFilter.transform.localPosition += center; + } + + void CenterHolder() + { + if (m_AnnotationHolder == null || m_AnnotationHolder.childCount == 0) + return; + + var childWorldPositions = new List(); + var center = Vector3.zero; + + for (var i = 0; i < m_AnnotationHolder.childCount; i++) + { + var worldPos = m_AnnotationHolder.GetChild(i).position; + childWorldPositions.Add(worldPos); + center += worldPos; + } + + center /= m_AnnotationHolder.childCount; + + m_AnnotationHolder.localPosition += center; + for (var i = 0; i < m_AnnotationHolder.childCount; i++) + { + m_AnnotationHolder.GetChild(i).position = childWorldPositions[i]; + } + } + + public static int[] VerticesToPolygon(int upperLeft, int upperRight, int lowerLeft, int lowerRight, bool doubleSided = true) + { + var triangleCount = doubleSided ? 12 : 6; + var triangles = new int[triangleCount]; + var index = 0; + + triangles[index++] = upperLeft; + triangles[index++] = lowerRight; + triangles[index++] = lowerLeft; + + triangles[index++] = lowerRight; + triangles[index++] = upperLeft; + triangles[index++] = upperRight; + + if (doubleSided) + { + triangles[index++] = lowerLeft; + triangles[index++] = lowerRight; + triangles[index++] = upperLeft; + + triangles[index++] = upperRight; + triangles[index++] = upperLeft; + triangles[index] = lowerRight; + } + + return triangles; + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + var annotationInput = (AnnotationInput)input; + + var draw = annotationInput.draw; + var isHeld = draw.isHeld; + if (primary) + { + if (!Mathf.Approximately(annotationInput.changeBrushSize.value, 0)) + { + HandleBrushSize(annotationInput.changeBrushSize.value); + consumeControl(annotationInput.changeBrushSize); + consumeControl(annotationInput.vertical); + } + + if (draw.wasJustPressed) + { + SetupAnnotation(); + consumeControl(draw); + } + + if (isHeld) + { + UpdateAnnotation(); + consumeControl(draw); + } + + if (draw.wasJustReleased) + { + FinalizeMesh(); + consumeControl(draw); + } + } + else + { + // Secondary hand uses brush size input to do undo/redo + var value = annotationInput.changeBrushSize.value; + if (this.GetDeviceType() == DeviceType.Vive) + { + if (annotationInput.stickButton.wasJustPressed) + { + if (value > 0) + Undo.PerformRedo(); + else + Undo.PerformUndo(); + } + } + else + { + var doUndoRedo = Math.Abs(value) > 0.5f; + if (doUndoRedo != m_WasDoingUndoRedo) + { + m_WasDoingUndoRedo = doUndoRedo; + if (doUndoRedo) + { + if (value > 0) + Undo.PerformRedo(); + else + Undo.PerformUndo(); + } + } + + consumeControl(annotationInput.changeBrushSize); + consumeControl(annotationInput.vertical); + } + } + + if (isHeld) + return; + + var isOverUI = this.IsHoveringOverUI(rayOrigin); + if (isOverUI != m_WasOverUI) + { + m_WasOverUI = isOverUI; + this.RestartCoroutine(ref m_AnnotationPointerVisibilityCoroutine, SetAnnotationPointerVisibility(!isOverUI)); + if (isOverUI) + this.RemoveRayVisibilitySettings(rayOrigin, this); + else + this.AddRayVisibilitySettings(rayOrigin, this, false, false); + } + } + + IEnumerator SetAnnotationPointerVisibility(bool visible) + { + if (!m_AnnotationPointer) + yield break; + + const float transitionTime = 0.1875f; + var annotationPointerTransform = m_AnnotationPointer.transform; + var startTime = Time.time; + var timeDiff = 0f; + var currentScale = annotationPointerTransform.localScale; + var targetScale = visible ? m_OriginalAnnotationPointerLocalScale : Vector3.zero; + while (timeDiff < transitionTime) + { + annotationPointerTransform.localScale = Vector3.Lerp(currentScale, targetScale, timeDiff / transitionTime); + timeDiff = Time.time - startTime; + yield return null; + } + + annotationPointerTransform.localScale = targetScale; + } + + void CombineGroups() + { + foreach (var group in m_Groups) + { + var meshFilters = group.GetComponentsInChildren(); + var renderers = group.GetComponentsInChildren(); + + if (meshFilters.Length == 0) + { + ObjectUtils.Destroy(group); + continue; + } + + var length = meshFilters.Length; + var combines = new List(length); + var materials = new List(length); + for (var i = 0; i < length; i++) + { + var meshFilter = meshFilters[i]; + var sharedMesh = meshFilter.sharedMesh; + if (sharedMesh && sharedMesh.vertexCount > 0) + { + var combine = new CombineInstance + { + mesh = sharedMesh, + transform = group.transform.worldToLocalMatrix * meshFilter.transform.localToWorldMatrix + }; + + sharedMesh.UploadMeshData(false); + combines.Add(combine); + materials.Add(renderers[i].sharedMaterial); + } + } + + var mesh = new Mesh(); + mesh.CombineMeshes(combines.ToArray(), false, true); + group.AddComponent().sharedMesh = mesh; + + group.AddComponent().sharedMaterials = materials.ToArray(); + + this.AddToSpatialHash(group); + + foreach (var meshFilter in meshFilters) + { + var go = meshFilter.gameObject; + this.RemoveFromSpatialHash(go); + ObjectUtils.Destroy(go); + } + } + } + + Vector3 GetPointerPosition() + { + return rayOrigin.position + rayOrigin.forward * TipDistance * this.GetViewerScale(); + } + + public object OnSerializePreferences() + { + if (this.IsSharedUpdater(this)) + { + // Share one preferences object across all instances + foreach (var linkedObject in linkedObjects) + { + ((AnnotationTool)linkedObject).m_Preferences = m_Preferences; + } + + return m_Preferences; + } + + return null; + } + + public void OnDeserializePreferences(object obj) + { + if (m_Preferences == null) + m_Preferences = (Preferences)obj; + } + } +} +#endif diff --git a/Tools/CreatePrimitiveTool/CreatePrimitiveTool.cs b/Tools/CreatePrimitiveTool/CreatePrimitiveTool.cs index ecfc51572..86400d51a 100644 --- a/Tools/CreatePrimitiveTool/CreatePrimitiveTool.cs +++ b/Tools/CreatePrimitiveTool/CreatePrimitiveTool.cs @@ -1,198 +1,197 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Tools -{ - [MainMenuItem("Primitive", "Create", "Create primitives in the scene")] - sealed class CreatePrimitiveTool : MonoBehaviour, ITool, IStandardActionMap, IConnectInterfaces, IInstantiateMenuUI, - IUsesRayOrigin, IUsesSpatialHash, IUsesViewerScale, ISelectTool, IIsHoveringOverUI, IIsMainMenuVisible, - IRayVisibilitySettings, IMenuIcon, IRequestFeedback, IUsesNode - { - [SerializeField] - CreatePrimitiveMenu m_MenuPrefab; - - [SerializeField] - Sprite m_Icon; - - const float k_DrawDistance = 0.075f; - - GameObject m_ToolMenu; - - PrimitiveType m_SelectedPrimitiveType = PrimitiveType.Cube; - bool m_Freeform; - - GameObject m_CurrentGameObject; - - Vector3 m_StartPoint = Vector3.zero; - Vector3 m_EndPoint = Vector3.zero; - - PrimitiveCreationStates m_State = PrimitiveCreationStates.StartPoint; - - public Transform rayOrigin { get; set; } - public Node node { get; set; } - - public Sprite icon { get { return m_Icon; } } - - enum PrimitiveCreationStates - { - StartPoint, - EndPoint, - Freeform - } - - void Start() - { - // Clear selection so we can't manipulate things - Selection.activeGameObject = null; - - m_ToolMenu = this.InstantiateMenuUI(rayOrigin, m_MenuPrefab); - var createPrimitiveMenu = m_ToolMenu.GetComponent(); - this.ConnectInterfaces(createPrimitiveMenu, rayOrigin); - createPrimitiveMenu.selectPrimitive = SetSelectedPrimitive; - createPrimitiveMenu.close = Close; - - var controls = new BindingDictionary(); - InputUtils.GetBindingDictionaryFromActionMap(standardActionMap, controls); - - foreach (var control in controls) - { - foreach (var id in control.Value) - { - this.AddFeedbackRequest(new ProxyFeedbackRequest - { - node = node, - control = id, - tooltipText = "Draw" - }); - } - } - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - if (!IsActive()) - return; - - var standardInput = (Standard)input; - - switch (m_State) - { - case PrimitiveCreationStates.StartPoint: - { - HandleStartPoint(standardInput, consumeControl); - break; - } - case PrimitiveCreationStates.EndPoint: - { - UpdatePositions(); - SetScalingForObjectType(); - CheckForTriggerRelease(standardInput, consumeControl); - break; - } - case PrimitiveCreationStates.Freeform: - { - UpdatePositions(); - UpdateFreeformScale(); - CheckForTriggerRelease(standardInput, consumeControl); - break; - } - } - - if (m_State == PrimitiveCreationStates.StartPoint && this.IsHoveringOverUI(rayOrigin)) - this.RemoveRayVisibilitySettings(rayOrigin, this); - else - this.AddRayVisibilitySettings(rayOrigin, this, false, true); - } - - void SetSelectedPrimitive(PrimitiveType type, bool isFreeform) - { - m_SelectedPrimitiveType = type; - m_Freeform = isFreeform; - } - - void HandleStartPoint(Standard standardInput, ConsumeControlDelegate consumeControl) - { - if (standardInput.action.wasJustPressed) - { - m_CurrentGameObject = GameObject.CreatePrimitive(m_SelectedPrimitiveType); - - // Set starting minimum scale (don't allow zero scale object to be created) - const float kMinScale = 0.0025f; - var viewerScale = this.GetViewerScale(); - m_CurrentGameObject.transform.localScale = Vector3.one * kMinScale * viewerScale; - m_StartPoint = rayOrigin.position + rayOrigin.forward * k_DrawDistance * viewerScale; - m_CurrentGameObject.transform.position = m_StartPoint; - - m_State = m_Freeform ? PrimitiveCreationStates.Freeform : PrimitiveCreationStates.EndPoint; - - this.AddToSpatialHash(m_CurrentGameObject); - - consumeControl(standardInput.action); - Selection.activeGameObject = m_CurrentGameObject; - } - } - - void SetScalingForObjectType() - { - var corner = (m_EndPoint - m_StartPoint).magnitude; - - // it feels better to scale these primitives vertically with the draw point - if (m_SelectedPrimitiveType == PrimitiveType.Capsule || m_SelectedPrimitiveType == PrimitiveType.Cylinder || m_SelectedPrimitiveType == PrimitiveType.Cube) - m_CurrentGameObject.transform.localScale = Vector3.one * corner * 0.5f; - else - m_CurrentGameObject.transform.localScale = Vector3.one * corner; - } - - void UpdatePositions() - { - m_EndPoint = rayOrigin.position + rayOrigin.forward * k_DrawDistance * this.GetViewerScale(); - m_CurrentGameObject.transform.position = (m_StartPoint + m_EndPoint) * 0.5f; - } - - void UpdateFreeformScale() - { - var maxCorner = Vector3.Max(m_StartPoint, m_EndPoint); - var minCorner = Vector3.Min(m_StartPoint, m_EndPoint); - m_CurrentGameObject.transform.localScale = maxCorner - minCorner; - } - - void CheckForTriggerRelease(Standard standardInput, ConsumeControlDelegate consumeControl) - { - // Ready for next object to be created - if (standardInput.action.wasJustReleased) - { - m_State = PrimitiveCreationStates.StartPoint; - - consumeControl(standardInput.action); - } - } - - bool IsActive() - { - return !this.IsMainMenuVisible(rayOrigin); - } - - void Close() - { - this.SelectTool(rayOrigin, GetType()); - } - - void OnDestroy() - { - ObjectUtils.Destroy(m_ToolMenu); - - if (rayOrigin == null) - return; - - this.RemoveRayVisibilitySettings(rayOrigin, this); - this.ClearFeedbackRequests(); - } - - public ActionMap standardActionMap { private get; set; } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Tools +{ + [MainMenuItem("Primitive", "Create", "Create primitives in the scene")] + sealed class CreatePrimitiveTool : MonoBehaviour, ITool, IStandardActionMap, IConnectInterfaces, IInstantiateMenuUI, + IUsesRayOrigin, IUsesSpatialHash, IUsesViewerScale, ISelectTool, IIsHoveringOverUI, IIsMainMenuVisible, + IRayVisibilitySettings, IMenuIcon, IRequestFeedback, IUsesNode + { + [SerializeField] + CreatePrimitiveMenu m_MenuPrefab; + + [SerializeField] + Sprite m_Icon; + + const float k_DrawDistance = 0.075f; + + GameObject m_ToolMenu; + + PrimitiveType m_SelectedPrimitiveType = PrimitiveType.Cube; + bool m_Freeform; + + GameObject m_CurrentGameObject; + + Vector3 m_StartPoint = Vector3.zero; + Vector3 m_EndPoint = Vector3.zero; + + PrimitiveCreationStates m_State = PrimitiveCreationStates.StartPoint; + + public Transform rayOrigin { get; set; } + public Node node { get; set; } + + public Sprite icon { get { return m_Icon; } } + + enum PrimitiveCreationStates + { + StartPoint, + EndPoint, + Freeform + } + + void Start() + { + // Clear selection so we can't manipulate things + Selection.activeGameObject = null; + + m_ToolMenu = this.InstantiateMenuUI(rayOrigin, m_MenuPrefab); + var createPrimitiveMenu = m_ToolMenu.GetComponent(); + this.ConnectInterfaces(createPrimitiveMenu, rayOrigin); + createPrimitiveMenu.selectPrimitive = SetSelectedPrimitive; + createPrimitiveMenu.close = Close; + + var controls = new BindingDictionary(); + InputUtils.GetBindingDictionaryFromActionMap(standardActionMap, controls); + + foreach (var control in controls) + { + foreach (var id in control.Value) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.tooltipText = "Draw"; + this.AddFeedbackRequest(request); + } + } + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + if (!IsActive()) + return; + + var standardInput = (Standard)input; + + switch (m_State) + { + case PrimitiveCreationStates.StartPoint: + { + HandleStartPoint(standardInput, consumeControl); + break; + } + case PrimitiveCreationStates.EndPoint: + { + UpdatePositions(); + SetScalingForObjectType(); + CheckForTriggerRelease(standardInput, consumeControl); + break; + } + case PrimitiveCreationStates.Freeform: + { + UpdatePositions(); + UpdateFreeformScale(); + CheckForTriggerRelease(standardInput, consumeControl); + break; + } + } + + if (m_State == PrimitiveCreationStates.StartPoint && this.IsHoveringOverUI(rayOrigin)) + this.RemoveRayVisibilitySettings(rayOrigin, this); + else + this.AddRayVisibilitySettings(rayOrigin, this, false, true); + } + + void SetSelectedPrimitive(PrimitiveType type, bool isFreeform) + { + m_SelectedPrimitiveType = type; + m_Freeform = isFreeform; + } + + void HandleStartPoint(Standard standardInput, ConsumeControlDelegate consumeControl) + { + if (standardInput.action.wasJustPressed) + { + m_CurrentGameObject = GameObject.CreatePrimitive(m_SelectedPrimitiveType); + + // Set starting minimum scale (don't allow zero scale object to be created) + const float kMinScale = 0.0025f; + var viewerScale = this.GetViewerScale(); + m_CurrentGameObject.transform.localScale = Vector3.one * kMinScale * viewerScale; + m_StartPoint = rayOrigin.position + rayOrigin.forward * k_DrawDistance * viewerScale; + m_CurrentGameObject.transform.position = m_StartPoint; + + m_State = m_Freeform ? PrimitiveCreationStates.Freeform : PrimitiveCreationStates.EndPoint; + + this.AddToSpatialHash(m_CurrentGameObject); + + consumeControl(standardInput.action); + Selection.activeGameObject = m_CurrentGameObject; + } + } + + void SetScalingForObjectType() + { + var corner = (m_EndPoint - m_StartPoint).magnitude; + + // it feels better to scale these primitives vertically with the draw point + if (m_SelectedPrimitiveType == PrimitiveType.Capsule || m_SelectedPrimitiveType == PrimitiveType.Cylinder || m_SelectedPrimitiveType == PrimitiveType.Cube) + m_CurrentGameObject.transform.localScale = Vector3.one * corner * 0.5f; + else + m_CurrentGameObject.transform.localScale = Vector3.one * corner; + } + + void UpdatePositions() + { + m_EndPoint = rayOrigin.position + rayOrigin.forward * k_DrawDistance * this.GetViewerScale(); + m_CurrentGameObject.transform.position = (m_StartPoint + m_EndPoint) * 0.5f; + } + + void UpdateFreeformScale() + { + var maxCorner = Vector3.Max(m_StartPoint, m_EndPoint); + var minCorner = Vector3.Min(m_StartPoint, m_EndPoint); + m_CurrentGameObject.transform.localScale = maxCorner - minCorner; + } + + void CheckForTriggerRelease(Standard standardInput, ConsumeControlDelegate consumeControl) + { + // Ready for next object to be created + if (standardInput.action.wasJustReleased) + { + m_State = PrimitiveCreationStates.StartPoint; + + consumeControl(standardInput.action); + } + } + + bool IsActive() + { + return !this.IsMainMenuVisible(rayOrigin); + } + + void Close() + { + this.SelectTool(rayOrigin, GetType()); + } + + void OnDestroy() + { + ObjectUtils.Destroy(m_ToolMenu); + + if (rayOrigin == null) + return; + + this.RemoveRayVisibilitySettings(rayOrigin, this); + this.ClearFeedbackRequests(); + } + + public ActionMap standardActionMap { private get; set; } + } +} +#endif diff --git a/Tools/LocomotionTool/LocomotionTool.cs b/Tools/LocomotionTool/LocomotionTool.cs index 5018ccbb1..2f77c83af 100644 --- a/Tools/LocomotionTool/LocomotionTool.cs +++ b/Tools/LocomotionTool/LocomotionTool.cs @@ -26,8 +26,6 @@ sealed class LocomotionTool : MonoBehaviour, ITool, ILocomotor, IUsesRayOrigin, const float k_MinScale = 0.1f; const float k_MaxScale = 1000f; - const string k_WorldScaleProperty = "_WorldScale"; - const string k_Crawl = "Crawl"; const string k_Rotate = "Rotate"; const string k_Blink = "Blink"; @@ -95,10 +93,6 @@ public bool blinkMode // Allow shared updater to check input values and consume controls LocomotionInput m_LocomotionInput; - Camera m_MainCamera; - float m_OriginalNearClipPlane; - float m_OriginalFarClipPlane; - Toggle m_FlyToggle; Toggle m_BlinkToggle; bool m_BlockValueChangedListener; @@ -192,12 +186,6 @@ void Start() m_BlinkVisualsGO.transform.localPosition = Vector3.zero; m_BlinkVisualsGO.transform.localRotation = Quaternion.identity; - m_MainCamera = CameraUtils.GetMainCamera(); - m_OriginalNearClipPlane = m_MainCamera.nearClipPlane; - m_OriginalFarClipPlane = m_MainCamera.farClipPlane; - - Shader.SetGlobalFloat(k_WorldScaleProperty, 1); - var viewerScaleObject = ObjectUtils.Instantiate(m_ViewerScaleVisualsPrefab, cameraRig, false); m_ViewerScaleVisuals = viewerScaleObject.GetComponent(); viewerScaleObject.SetActive(false); @@ -710,13 +698,9 @@ bool DoTwoHandedScaling(ConsumeControlDelegate consumeControl) midPoint = currentRotation * midPoint * currentScale; cameraRig.position = m_StartPosition + m_StartMidPoint - midPoint; - cameraRig.localScale = Vector3.one * currentScale; cameraRig.rotation = currentRotation; - m_MainCamera.nearClipPlane = m_OriginalNearClipPlane * currentScale; - m_MainCamera.farClipPlane = m_OriginalFarClipPlane * currentScale; - - Shader.SetGlobalFloat(k_WorldScaleProperty, 1f / currentScale); + this.SetViewerScale(currentScale); } break; } @@ -737,9 +721,7 @@ bool DoTwoHandedScaling(ConsumeControlDelegate consumeControl) void ResetViewerScale() { - cameraRig.localScale = Vector3.one; - m_MainCamera.nearClipPlane = m_OriginalNearClipPlane; - m_MainCamera.farClipPlane = m_OriginalFarClipPlane; + this.SetViewerScale(1f); m_ViewerScaleVisuals.gameObject.SetActive(false); } @@ -799,15 +781,12 @@ void ShowFeedback(List requests, string controlName, strin { foreach (var id in ids) { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - tooltipText = tooltipText - }; - - this.AddFeedbackRequest(request); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.tooltipText = tooltipText; requests.Add(request); + this.AddFeedbackRequest(request); } } } @@ -839,15 +818,12 @@ void ShowScaleFeedback() { foreach (var id in ids) { - var request = new ProxyFeedbackRequest - { - control = id, - node = node == Node.LeftHand ? Node.RightHand : Node.LeftHand, - tooltipText = "Scale" - }; - - this.AddFeedbackRequest(request); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = id; + request.node = node == Node.LeftHand ? Node.RightHand : Node.LeftHand; + request.tooltipText = "Scale"; m_ScaleFeedback.Add(request); + this.AddFeedbackRequest(request); } } } diff --git a/Tools/LocomotionTool/Prefabs/ViewerScaleVisuals.prefab b/Tools/LocomotionTool/Prefabs/ViewerScaleVisuals.prefab index 44d97d6b1..fa16dcd64 100644 --- a/Tools/LocomotionTool/Prefabs/ViewerScaleVisuals.prefab +++ b/Tools/LocomotionTool/Prefabs/ViewerScaleVisuals.prefab @@ -377,7 +377,7 @@ MonoBehaviour: m_text: 'Viewer Scale: 0.5' m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: ea721564999c75441b5b3aa01ae88f76, type: 2} - m_sharedMaterial: {fileID: 2100000, guid: db4a373a15bcdcc42af5fd55a87bdd2b, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 5be343b145ab9dd42821b06c75f9a60c, type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] diff --git a/Tools/SelectionTool/SelectionTool.cs b/Tools/SelectionTool/SelectionTool.cs index 1e56c235f..88779434e 100644 --- a/Tools/SelectionTool/SelectionTool.cs +++ b/Tools/SelectionTool/SelectionTool.cs @@ -34,7 +34,8 @@ public bool sphereMode } const float k_MultiselectHueShift = 0.5f; - static readonly Vector3 k_TooltipPosition = new Vector3(0, -0.15f, -0.13f); + static readonly Vector3 k_TouchTooltipPosition = new Vector3(0, -0.08f, -0.13f); + static readonly Vector3 k_ViveTooltipPosition = new Vector3(0, 0.05f, -0.18f); const float k_BLockSelectDragThreshold = 0.01f; static readonly Quaternion k_TooltipRotation = Quaternion.AngleAxis(90, Vector3.right); @@ -163,7 +164,7 @@ void Start() m_MultiselectRayColor = MaterialUtils.HueShift(m_MultiselectRayColor, k_MultiselectHueShift); tooltipTarget = ObjectUtils.CreateEmptyGameObject("SelectionTool Tooltip Target", rayOrigin).transform; - tooltipTarget.localPosition = k_TooltipPosition; + tooltipTarget.localPosition = this.GetDeviceType() == DeviceType.Oculus ? k_TouchTooltipPosition : k_ViveTooltipPosition; tooltipTarget.localRotation = k_TooltipRotation; m_BlockSelectCube = ObjectUtils.Instantiate(m_BlockSelectCube, transform); @@ -570,15 +571,12 @@ void ShowFeedback(List requests, string controlName, strin { foreach (var id in ids) { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - tooltipText = tooltipText - }; - - this.AddFeedbackRequest(request); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.tooltipText = tooltipText; requests.Add(request); + this.AddFeedbackRequest(request); } } } diff --git a/Tools/TransformTool/TransformTool.cs b/Tools/TransformTool/TransformTool.cs index 94bf74d24..f88fce69f 100644 --- a/Tools/TransformTool/TransformTool.cs +++ b/Tools/TransformTool/TransformTool.cs @@ -436,6 +436,9 @@ public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeCon if (leftInput.select.wasJustReleased) { + if (rightInput != null && rightInput.select.wasJustReleased) + m_Scaling = false; + DropHeldObjects(Node.LeftHand); hasLeft = false; consumeControl(leftInput.select); @@ -447,7 +450,6 @@ public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeCon consumeControl(rightInput.cancel); if (rightInput.cancel.wasJustPressed) { - if (m_Scaling) { m_Scaling = false; @@ -465,6 +467,9 @@ public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeCon if (rightInput.select.wasJustReleased) { + if (leftInput != null && leftInput.select.wasJustReleased) + m_Scaling = false; + DropHeldObjects(Node.RightHand); hasRight = false; consumeControl(rightInput.select); @@ -817,17 +822,14 @@ void ShowFeedback(List requests, string controlName, strin { foreach (var id in ids) { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - tooltipText = tooltipText, - priority = 1, - suppressExisting = suppressExisting - }; - - this.AddFeedbackRequest(request); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.tooltipText = tooltipText; + request.priority = 1; + request.suppressExisting = suppressExisting; requests.Add(request); + this.AddFeedbackRequest(request); } } } diff --git a/Tools/VacuumTool/VacuumTool.cs b/Tools/VacuumTool/VacuumTool.cs index 54fb15d75..bf6ec2bb0 100644 --- a/Tools/VacuumTool/VacuumTool.cs +++ b/Tools/VacuumTool/VacuumTool.cs @@ -1,137 +1,134 @@ -#if UNITY_EDITOR -using System.Collections; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; - -namespace UnityEditor.Experimental.EditorVR.Tools -{ - sealed class VacuumTool : MonoBehaviour, ITool, ICustomActionMap, IUsesRayOrigin, IUsesViewerScale, - IRequestFeedback, IUsesNode - { - [SerializeField] - ActionMap m_ActionMap; - - float m_LastClickTime; - readonly Dictionary m_VacuumingCoroutines = new Dictionary(); - - readonly BindingDictionary m_Controls = new BindingDictionary(); - readonly List m_Feedback = new List(); - - public ActionMap actionMap { get { return m_ActionMap; } } - public bool ignoreLocking { get { return false; } } - - public List vacuumables { private get; set; } - - public Transform rayOrigin { get; set; } - - public Vector3 defaultOffset { private get; set; } - public Quaternion defaultTilt { private get; set; } - public Node node { private get; set; } - - void Start() - { - InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); - } - - void OnDestroy() - { - this.ClearFeedbackRequests(); - } - - public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) - { - var hit = false; - foreach (var vacuumable in vacuumables) - { - var vacuumableTransform = vacuumable.transform; - var ray = new Ray(rayOrigin.position, rayOrigin.forward); - ray.origin = vacuumableTransform.InverseTransformPoint(ray.origin); - ray.direction = vacuumableTransform.InverseTransformDirection(ray.direction); - if (vacuumable.vacuumBounds.IntersectRay(ray)) - { - hit = true; - var vacuumInput = (VacuumInput)input; - if (vacuumInput.vacuum.wasJustPressed) - { - var realTime = Time.realtimeSinceStartup; - if (UIUtils.IsDoubleClick(realTime - m_LastClickTime)) - { - Coroutine coroutine; - if (m_VacuumingCoroutines.TryGetValue(vacuumableTransform, out coroutine)) - StopCoroutine(coroutine); - - m_VacuumingCoroutines[vacuumableTransform] = StartCoroutine(VacuumToViewer(vacuumable)); - } - - m_LastClickTime = realTime; - } - - if (m_Feedback.Count == 0) - { - foreach (var kvp in m_Controls) - { - foreach (var id in kvp.Value) - { - var request = new ProxyFeedbackRequest - { - control = id, - node = node, - tooltipText = "Double-tap to summon workspace" - }; - - m_Feedback.Add(request); - this.AddFeedbackRequest(request); - } - } - } - - break; - } - } - - if (!hit) - { - foreach (var request in m_Feedback) - { - this.RemoveFeedbackRequest(request); - } - m_Feedback.Clear(); - } - } - - IEnumerator VacuumToViewer(IVacuumable vacuumable) - { - var vacuumTransform = vacuumable.transform; - var startPosition = vacuumTransform.position; - var startRotation = vacuumTransform.rotation; - - var offset = defaultOffset; - offset.z += vacuumable.vacuumBounds.extents.z; - offset *= this.GetViewerScale(); - - var camera = CameraUtils.GetMainCamera().transform; - var destPosition = camera.position + MathUtilsExt.ConstrainYawRotation(camera.rotation) * offset; - var destRotation = Quaternion.LookRotation(camera.forward) * defaultTilt; - - var currentValue = 0f; - var currentVelocity = 0f; - var currentDuration = 0f; - const float kTargetValue = 1f; - const float kTargetDuration = 0.5f; - while (currentDuration < kTargetDuration) - { - currentDuration += Time.deltaTime; - currentValue = MathUtilsExt.SmoothDamp(currentValue, kTargetValue, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - vacuumTransform.position = Vector3.Lerp(startPosition, destPosition, currentValue); - vacuumTransform.rotation = Quaternion.Lerp(startRotation, destRotation, currentValue); - yield return null; - } - - m_VacuumingCoroutines.Remove(vacuumTransform); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; + +namespace UnityEditor.Experimental.EditorVR.Tools +{ + sealed class VacuumTool : MonoBehaviour, ITool, ICustomActionMap, IUsesRayOrigin, IUsesViewerScale, + IRequestFeedback, IUsesNode + { + [SerializeField] + ActionMap m_ActionMap; + + float m_LastClickTime; + readonly Dictionary m_VacuumingCoroutines = new Dictionary(); + + readonly BindingDictionary m_Controls = new BindingDictionary(); + readonly List m_Feedback = new List(); + + public ActionMap actionMap { get { return m_ActionMap; } } + public bool ignoreLocking { get { return false; } } + + public List vacuumables { private get; set; } + + public Transform rayOrigin { get; set; } + + public Vector3 defaultOffset { private get; set; } + public Quaternion defaultTilt { private get; set; } + public Node node { private get; set; } + + void Start() + { + InputUtils.GetBindingDictionaryFromActionMap(m_ActionMap, m_Controls); + } + + void OnDestroy() + { + this.ClearFeedbackRequests(); + } + + public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl) + { + var hit = false; + foreach (var vacuumable in vacuumables) + { + var vacuumableTransform = vacuumable.transform; + var ray = new Ray(rayOrigin.position, rayOrigin.forward); + ray.origin = vacuumableTransform.InverseTransformPoint(ray.origin); + ray.direction = vacuumableTransform.InverseTransformDirection(ray.direction); + if (vacuumable.vacuumBounds.IntersectRay(ray)) + { + hit = true; + var vacuumInput = (VacuumInput)input; + if (vacuumInput.vacuum.wasJustPressed) + { + var realTime = Time.realtimeSinceStartup; + if (UIUtils.IsDoubleClick(realTime - m_LastClickTime)) + { + Coroutine coroutine; + if (m_VacuumingCoroutines.TryGetValue(vacuumableTransform, out coroutine)) + StopCoroutine(coroutine); + + m_VacuumingCoroutines[vacuumableTransform] = StartCoroutine(VacuumToViewer(vacuumable)); + } + + m_LastClickTime = realTime; + } + + if (m_Feedback.Count == 0) + { + foreach (var kvp in m_Controls) + { + foreach (var id in kvp.Value) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = id; + request.node = node; + request.tooltipText = "Double-tap to summon workspace"; + m_Feedback.Add(request); + this.AddFeedbackRequest(request); + } + } + } + + break; + } + } + + if (!hit) + { + foreach (var request in m_Feedback) + { + this.RemoveFeedbackRequest(request); + } + m_Feedback.Clear(); + } + } + + IEnumerator VacuumToViewer(IVacuumable vacuumable) + { + var vacuumTransform = vacuumable.transform; + var startPosition = vacuumTransform.position; + var startRotation = vacuumTransform.rotation; + + var offset = defaultOffset; + offset.z += vacuumable.vacuumBounds.extents.z; + offset *= this.GetViewerScale(); + + var camera = CameraUtils.GetMainCamera().transform; + var destPosition = camera.position + MathUtilsExt.ConstrainYawRotation(camera.rotation) * offset; + var destRotation = Quaternion.LookRotation(camera.forward) * defaultTilt; + + var currentValue = 0f; + var currentVelocity = 0f; + var currentDuration = 0f; + const float kTargetValue = 1f; + const float kTargetDuration = 0.5f; + while (currentDuration < kTargetDuration) + { + currentDuration += Time.deltaTime; + currentValue = MathUtilsExt.SmoothDamp(currentValue, kTargetValue, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); + vacuumTransform.position = Vector3.Lerp(startPosition, destPosition, currentValue); + vacuumTransform.rotation = Quaternion.Lerp(startRotation, destRotation, currentValue); + yield return null; + } + + m_VacuumingCoroutines.Remove(vacuumTransform); + } + } +} +#endif diff --git a/Workspaces/Base/Workspace.cs b/Workspaces/Base/Workspace.cs index 65015ac91..a6674fcb4 100644 --- a/Workspaces/Base/Workspace.cs +++ b/Workspaces/Base/Workspace.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using System.Collections; using UnityEditor.Experimental.EditorVR.Core; @@ -18,6 +18,7 @@ abstract class Workspace : MonoBehaviour, IWorkspace, IInstantiateUI, IUsesStenc public static readonly Vector3 MinBounds = new Vector3(0.677f, 0f, 0.1f); public const float FaceMargin = 0.025f; + protected float DoubleFaceMargin = FaceMargin * 2; public const float HighlightMargin = 0.002f; [SerializeField] diff --git a/Workspaces/Base/WorkspaceUI.cs b/Workspaces/Base/WorkspaceUI.cs index 3e9da7a52..91aeb7eee 100644 --- a/Workspaces/Base/WorkspaceUI.cs +++ b/Workspaces/Base/WorkspaceUI.cs @@ -1,1050 +1,1047 @@ -#if UNITY_EDITOR -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Handles; -using UnityEditor.Experimental.EditorVR.Helpers; -using UnityEditor.Experimental.EditorVR.Proxies; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.InputNew; -using UnityEngine.UI; - -namespace UnityEditor.Experimental.EditorVR.Workspaces -{ - sealed class WorkspaceUI : MonoBehaviour, IUsesStencilRef, IUsesViewerScale, IUsesPointer, IRequestFeedback - { - [Flags] - enum ResizeDirection - { - Front = 1, - Back = 2, - Left = 4, - Right = 8 - } - - class DragState - { - public Transform rayOrigin { get; private set; } - bool m_Resizing; - Vector3 m_PositionOffset; - Quaternion m_RotationOffset; - WorkspaceUI m_WorkspaceUI; - Vector3 m_DragStart; - Vector3 m_PositionStart; - Vector3 m_BoundsSizeStart; - ResizeDirection m_Direction; - - public DragState(WorkspaceUI workspaceUI, Transform rayOrigin, bool resizing) - { - m_WorkspaceUI = workspaceUI; - m_Resizing = resizing; - this.rayOrigin = rayOrigin; - - if (resizing) - { - var pointerPosition = m_WorkspaceUI.GetPointerPosition(rayOrigin); - m_DragStart = pointerPosition; - m_PositionStart = workspaceUI.transform.parent.position; - m_BoundsSizeStart = workspaceUI.bounds.size; - var localPosition = m_WorkspaceUI.transform.InverseTransformPoint(pointerPosition); - m_Direction = m_WorkspaceUI.GetResizeDirectionForLocalPosition(localPosition); - } - else - { - MathUtilsExt.GetTransformOffset(rayOrigin, m_WorkspaceUI.transform.parent, out m_PositionOffset, out m_RotationOffset); - } - } - - public void OnDragging() - { - if (m_Resizing) - { - var viewerScale = m_WorkspaceUI.GetViewerScale(); - var pointerPosition = m_WorkspaceUI.GetPointerPosition(rayOrigin); - var dragVector = (pointerPosition - m_DragStart) / viewerScale; - var bounds = m_WorkspaceUI.bounds; - var transform = m_WorkspaceUI.transform; - - var positionOffsetForward = Vector3.Dot(dragVector, transform.forward) * 0.5f; - var positionOffsetRight = Vector3.Dot(dragVector, transform.right) * 0.5f; - - switch (m_Direction) - { - default: - bounds.size = m_BoundsSizeStart + Vector3.back * Vector3.Dot(dragVector, transform.forward); - positionOffsetRight = 0; - break; - case ResizeDirection.Back: - bounds.size = m_BoundsSizeStart + Vector3.forward * Vector3.Dot(dragVector, transform.forward); - positionOffsetRight = 0; - break; - case ResizeDirection.Left: - bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right); - positionOffsetForward = 0; - break; - case ResizeDirection.Right: - bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right); - positionOffsetForward = 0; - break; - case ResizeDirection.Front | ResizeDirection.Left: - bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) - + Vector3.back * Vector3.Dot(dragVector, transform.forward); - break; - case ResizeDirection.Front | ResizeDirection.Right: - bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) - + Vector3.back * Vector3.Dot(dragVector, transform.forward); - break; - case ResizeDirection.Back | ResizeDirection.Left: - bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) - + Vector3.forward * Vector3.Dot(dragVector, transform.forward); - break; - case ResizeDirection.Back | ResizeDirection.Right: - bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) - + Vector3.forward * Vector3.Dot(dragVector, transform.forward); - break; - } - - if (m_WorkspaceUI.resize != null) - m_WorkspaceUI.resize(bounds); - - var currentExtents = m_WorkspaceUI.bounds.extents; - var extents = bounds.extents; - var absRight = Mathf.Abs(positionOffsetRight); - var absForward = Mathf.Abs(positionOffsetForward); - var positionOffset = transform.right * (absRight - (currentExtents.x - extents.x)) * Mathf.Sign(positionOffsetRight) - + transform.forward * (absForward - (currentExtents.z - extents.z)) * Mathf.Sign(positionOffsetForward); - - m_WorkspaceUI.transform.parent.position = m_PositionStart + positionOffset * viewerScale; - m_WorkspaceUI.OnResizing(rayOrigin); - } - else - { - MathUtilsExt.SetTransformOffset(rayOrigin, m_WorkspaceUI.transform.parent, m_PositionOffset, m_RotationOffset); - m_WorkspaceUI.OnMoving(rayOrigin); - } - } - } - - const int k_AngledFaceBlendShapeIndex = 2; - const int k_ThinFrameBlendShapeIndex = 3; - const string k_MaterialStencilRef = "_StencilRef"; - - const float k_ResizeIconCrossfadeDuration = 0.1f; - const float k_ResizeIconSmoothFollow = 10f; - - const float k_FrontFrameZOffset = 0.088f; - - static readonly Vector3 k_BaseFrontPanelRotation = Vector3.zero; - static readonly Vector3 k_MaxFrontPanelRotation = new Vector3(90f, 0f, 0f); - - [SerializeField] - Transform m_SceneContainer; - - [SerializeField] - RectTransform m_FrontPanel; - - [SerializeField] - BaseHandle[] m_Handles; - - [SerializeField] - Image[] m_ResizeIcons; - - [SerializeField] - Transform m_FrontLeftHandle; - - [SerializeField] - Transform m_FrontLeftCornerHandle; - - [SerializeField] - Transform m_FrontRightHandle; - - [SerializeField] - Transform m_FrontRightCornerHandle; - - [SerializeField] - Transform m_BottomFrontHandle; - - [SerializeField] - Transform m_TopFaceContainer; - - [SerializeField] - WorkspaceHighlight m_TopHighlight; - - [SerializeField] - SkinnedMeshRenderer m_Frame; - - [SerializeField] - Transform m_FrameFrontFaceTransform; - - [SerializeField] - Transform m_FrameFrontFaceHighlightTransform; - - [SerializeField] - Transform m_TopPanelDividerTransform; - - [SerializeField] - RectTransform m_UIContentContainer; - - [SerializeField] - Image m_FrontResizeIcon; - - [SerializeField] - Image m_RightResizeIcon; - - [SerializeField] - Image m_LeftResizeIcon; - - [SerializeField] - Image m_BackResizeIcon; - - [SerializeField] - Image m_FrontLeftResizeIcon; - - [SerializeField] - Image m_FrontRightResizeIcon; - - [SerializeField] - Image m_BackLeftResizeIcon; - - [SerializeField] - Image m_BackRightResizeIcon; - - [SerializeField] - Transform m_TopHighlightContainer; - - [SerializeField] - RectTransform m_HandleRectTransform; - - [SerializeField] - RectTransform m_ResizeIconRectTransform; - - [SerializeField] - WorkspaceHighlight m_FrontHighlight; - - [SerializeField] - float m_FrameHandleSize = 0.03f; - - [SerializeField] - float m_FrontFrameHandleSize = 0.01f; - - [SerializeField] - float m_FrameHeight = 0.09275f; - - [SerializeField] - float m_ResizeHandleMargin = 0.01f; - - [SerializeField] - float m_ResizeCornerSize = 0.05f; - - [SerializeField] - bool m_DynamicFaceAdjustment = true; - - [SerializeField] - WorkspaceButton m_CloseButton; - - [SerializeField] - WorkspaceButton m_ResizeButton; - - BoxCollider m_FrameCollider; - Bounds m_Bounds; - float? m_TopPanelDividerOffset; - - readonly BindingDictionary m_Controls = new BindingDictionary(); - readonly List m_LeftMoveFeedback = new List(); - readonly List m_RightMoveFeedback = new List(); - readonly List m_LeftResizeFeedback = new List(); - readonly List m_RightResizeFeedback = new List(); - - // Cached for optimization - float m_PreviousXRotation; - Coroutine m_FrameThicknessCoroutine; - Coroutine m_TopFaceVisibleCoroutine; - Material m_TopFaceMaterial; - Material m_FrontFaceMaterial; - - float m_LerpAmount; - float m_FrontZOffset; - - DragState m_DragState; - - readonly List m_HovereringRayOrigins = new List(); - readonly Dictionary m_LastResizeIcons = new Dictionary(); - - public bool highlightsVisible - { - set - { - if (m_TopHighlight.visible == value && m_FrontHighlight.visible == value) - return; - - m_TopHighlight.visible = value; - m_FrontHighlight.visible = value; - - if (value) - IncreaseFrameThickness(); - else - ResetFrameThickness(); - } - } - - public bool frontHighlightVisible - { - set - { - if (m_FrontHighlight.visible == value) - return; - - m_FrontHighlight.visible = value; - - if (value) - IncreaseFrameThickness(); - else - ResetFrameThickness(); - } - } - - public bool amplifyTopHighlight - { - set - { - this.StopCoroutine(ref m_TopFaceVisibleCoroutine); - m_TopFaceVisibleCoroutine = value ? StartCoroutine(HideTopFace()) : StartCoroutine(ShowTopFace()); - } - } - - /// - /// (-1 to 1) ranged value that controls the separator mask's X-offset placement - /// A value of zero will leave the mask in the center of the workspace - /// - public float topPanelDividerOffset - { - set - { - m_TopPanelDividerOffset = value; - m_TopPanelDividerTransform.gameObject.SetActive(true); - } - } - - public Transform topFaceContainer - { - get { return m_TopFaceContainer; } - set { m_TopFaceContainer = value; } - } - - public bool dynamicFaceAdjustment - { - get { return m_DynamicFaceAdjustment; } - set { m_DynamicFaceAdjustment = value; } - } - - public bool preventResize - { - set - { - foreach (var handle in m_Handles) - { - handle.gameObject.SetActive(!value); - } - } - } - - public Bounds bounds - { - get { return m_Bounds; } - set - { - m_Bounds = value; - - m_Bounds.center = Vector3.down * m_FrameHeight * 0.5f; - - var extents = m_Bounds.extents; - var size = m_Bounds.size; - size.y = m_FrameHeight + m_FrameHandleSize; - m_Bounds.size = size; - - const float kWidthMultiplier = 0.96154f; - const float kDepthMultiplier = 0.99383f; - const float kWidthOffset = -0.156f; - const float kDepthOffset = -0.0318f; - const float kDepthCompensation = -0.008f; - - var width = size.x; - var depth = size.z; - var faceWidth = width - Workspace.FaceMargin; - var faceDepth = depth - Workspace.FaceMargin; - - m_Frame.SetBlendShapeWeight(0, width * kWidthMultiplier + kWidthOffset); - m_Frame.SetBlendShapeWeight(1, depth * kDepthMultiplier + kDepthOffset + kDepthCompensation * m_LerpAmount); - - // Resize content container - m_UIContentContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, faceWidth); - var localPosition = m_UIContentContainer.localPosition; - localPosition.z = -extents.z; - m_UIContentContainer.localPosition = localPosition; - - // Resize front panel - m_FrameFrontFaceTransform.localScale = new Vector3(faceWidth, 1f, 1f); - const float kFrontFaceHighlightMargin = 0.0008f; - m_FrameFrontFaceHighlightTransform.localScale = new Vector3(faceWidth + kFrontFaceHighlightMargin, 1f, 1f); - - // Position the separator mask if enabled - if (m_TopPanelDividerOffset != null) - { - m_TopPanelDividerTransform.localPosition = new Vector3(faceWidth * (m_TopPanelDividerOffset.Value - 0.5f), 0f, 0f); - m_TopPanelDividerTransform.localScale = new Vector3(1f, 1f, faceDepth + Workspace.HighlightMargin); - } - - // Scale the Top Face and the Top Face Highlight - const float kHighlightMargin = 0.0005f; - m_TopHighlightContainer.localScale = new Vector3(faceWidth + kHighlightMargin, 1f, faceDepth + kHighlightMargin); - m_TopFaceContainer.localScale = new Vector3(faceWidth, 1f, faceDepth); - - var frameBounds = adjustedBounds; - m_FrameCollider.size = frameBounds.size; - m_FrameCollider.center = frameBounds.center; - - AdjustHandlesAndIcons(); - } - } - - public Bounds adjustedBounds - { - get - { - var adjustedBounds = bounds; - adjustedBounds.size += Vector3.forward * m_FrontZOffset; - adjustedBounds.center += Vector3.back * m_FrontZOffset * 0.5f; - return adjustedBounds; - } - } - - public event Action buttonHovered; - public event Action closeClicked; - public event Action resetSizeClicked; - public event Action resizing; - public event Action moving; - public event Action hoveringFrame; - - public Transform sceneContainer { get { return m_SceneContainer; } } - public RectTransform frontPanel { get { return m_FrontPanel; } } - public WorkspaceHighlight topHighlight { get { return m_TopHighlight; } } - - public byte stencilRef { get; set; } - - public Transform leftRayOrigin { private get; set; } - public Transform rightRayOrigin { private get; set; } - - public event Action resize; - - void Awake() - { - foreach (var icon in m_ResizeIcons) - { - icon.CrossFadeAlpha(0f, 0f, true); - } - - m_Frame.SetBlendShapeWeight(k_ThinFrameBlendShapeIndex, 50f); // Set default frame thickness to be in middle for a thinner initial frame - - if (m_TopPanelDividerOffset == null) - m_TopPanelDividerTransform.gameObject.SetActive(false); - - foreach (var handle in m_Handles) - { - handle.hoverStarted += OnHandleHoverStarted; - handle.hoverEnded += OnHandleHoverEnded; - } - - m_CloseButton.clicked += OnCloseClicked; - m_CloseButton.hovered += OnButtonHovered; - m_ResizeButton.clicked += OnResetSizeClicked; - m_ResizeButton.hovered += OnButtonHovered; - - m_FrameCollider = transform.parent.gameObject.AddComponent(); - } - - IEnumerator Start() - { - const string kShaderBlur = "_Blur"; - const string kShaderAlpha = "_Alpha"; - const string kShaderVerticalOffset = "_VerticalOffset"; - const float kTargetDuration = 1.25f; - - m_TopFaceMaterial = MaterialUtils.GetMaterialClone(m_TopFaceContainer.GetComponentInChildren()); - m_TopFaceMaterial.SetFloat("_Alpha", 1f); - m_TopFaceMaterial.SetInt(k_MaterialStencilRef, stencilRef); - - m_FrontFaceMaterial = MaterialUtils.GetMaterialClone(m_FrameFrontFaceTransform.GetComponentInChildren()); - m_FrontFaceMaterial.SetInt(k_MaterialStencilRef, stencilRef); - - var originalBlurAmount = m_TopFaceMaterial.GetFloat("_Blur"); - var currentBlurAmount = 10f; // also the maximum blur amount - var currentDuration = 0f; - var currentVelocity = 0f; - - m_TopFaceMaterial.SetFloat(kShaderBlur, currentBlurAmount); - m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 1f); // increase the blur sample offset to amplify the effect - m_TopFaceMaterial.SetFloat(kShaderAlpha, 0.5f); // set partially transparent - - while (currentDuration < kTargetDuration) - { - currentDuration += Time.deltaTime; - currentBlurAmount = MathUtilsExt.SmoothDamp(currentBlurAmount, originalBlurAmount, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - m_TopFaceMaterial.SetFloat(kShaderBlur, currentBlurAmount); - - var percentageComplete = currentDuration / kTargetDuration; - m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 1 - percentageComplete); // lerp back towards an offset of zero - m_TopFaceMaterial.SetFloat(kShaderAlpha, percentageComplete * 0.5f + 0.5f); // lerp towards fully opaque from 50% transparent - - yield return null; - } - - m_TopFaceMaterial.SetFloat(kShaderBlur, originalBlurAmount); - m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 0f); - m_TopFaceMaterial.SetFloat(kShaderAlpha, 1f); - - yield return null; - } - - void AdjustHandlesAndIcons() - { - var size = m_Bounds.size; - m_HandleRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); - m_HandleRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z); - - var halfFrontZOffset = m_FrontZOffset * 0.5f; - var localPosition = m_ResizeIconRectTransform.localPosition; - localPosition.z = -halfFrontZOffset; - m_ResizeIconRectTransform.localPosition = localPosition; - m_ResizeIconRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); - m_ResizeIconRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z + m_FrontZOffset); - - var extents = m_Bounds.extents; - var halfWidth = extents.x; - var halfDepth = extents.z; - var yOffset = m_FrameHeight * (0.5f - m_LerpAmount); - localPosition = m_BottomFrontHandle.localPosition; - localPosition.z = yOffset; - localPosition.y = -halfDepth - m_FrontZOffset; - m_BottomFrontHandle.localPosition = localPosition; - - yOffset = (1 - m_LerpAmount) * m_FrameHeight; - var angle = Mathf.Atan(m_FrontZOffset / yOffset) * Mathf.Rad2Deg; - - m_FrontLeftHandle.localPosition = new Vector3(-halfWidth, -yOffset * 0.5f, -halfDepth - halfFrontZOffset); - m_FrontLeftHandle.localRotation = Quaternion.AngleAxis(angle, Vector3.right); - m_FrontLeftHandle.localScale = new Vector3(m_FrontFrameHandleSize, m_FrameHeight, m_FrontFrameHandleSize); - localPosition = m_FrontLeftHandle.localPosition; - localPosition.x = halfWidth; - - m_FrontRightHandle.localPosition = localPosition; - m_FrontRightHandle.localRotation = m_FrontLeftHandle.localRotation; - m_FrontRightHandle.localScale = m_FrontLeftHandle.localScale; - - var zOffset = m_FrontZOffset - (k_FrontFrameZOffset + m_FrontFrameHandleSize) * 0.5f; - var zScale = m_FrameHeight * m_LerpAmount; - var yPosition = -m_FrontFrameHandleSize * 0.5f - m_FrameHeight + zScale * 0.5f; - m_FrontLeftCornerHandle.localPosition = new Vector3(-halfWidth, yPosition, -halfDepth - zOffset - m_FrontFrameHandleSize); - m_FrontLeftCornerHandle.localScale = new Vector3(m_FrontFrameHandleSize, k_FrontFrameZOffset, zScale); - - m_FrontRightCornerHandle = m_FrontRightCornerHandle.transform; - localPosition = m_FrontLeftCornerHandle.localPosition; - localPosition.x = halfWidth; - m_FrontRightCornerHandle.localPosition = localPosition; - m_FrontRightCornerHandle.localRotation = m_FrontLeftCornerHandle.localRotation; - m_FrontRightCornerHandle.localScale = m_FrontLeftCornerHandle.localScale; - } - - void OnHandleHoverStarted(BaseHandle handle, HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - if (m_HovereringRayOrigins.Count == 0 && m_DragState == null) - IncreaseFrameThickness(rayOrigin); - - m_HovereringRayOrigins.Add(rayOrigin); - } - - ResizeDirection GetResizeDirectionForLocalPosition(Vector3 localPosition) - { - var direction = localPosition.z > 0 ? ResizeDirection.Back : ResizeDirection.Front; - var xDirection = localPosition.x > 0 ? ResizeDirection.Right : ResizeDirection.Left; - - var zDistance = bounds.extents.z - Mathf.Abs(localPosition.z); - if (localPosition.z < 0) - zDistance += m_FrontZOffset; - - var cornerZ = zDistance < m_ResizeCornerSize; - var cornerX = bounds.extents.x - Mathf.Abs(localPosition.x) < m_ResizeCornerSize; - - if (cornerZ && cornerX) - direction |= xDirection; - else if (cornerX) - direction = xDirection; - - return direction; - } - - Image GetResizeIconForDirection(ResizeDirection direction) - { - switch (direction) - { - default: - return m_FrontResizeIcon; - case ResizeDirection.Back: - return m_BackResizeIcon; - case ResizeDirection.Left: - return m_LeftResizeIcon; - case ResizeDirection.Right: - return m_RightResizeIcon; - case ResizeDirection.Front | ResizeDirection.Left: - return m_FrontLeftResizeIcon; - case ResizeDirection.Front | ResizeDirection.Right: - return m_FrontRightResizeIcon; - case ResizeDirection.Back | ResizeDirection.Left: - return m_BackLeftResizeIcon; - case ResizeDirection.Back | ResizeDirection.Right: - return m_BackRightResizeIcon; - } - } - - void OnHandleHoverEnded(BaseHandle handle, HandleEventData eventData) - { - var rayOrigin = eventData.rayOrigin; - if (m_HovereringRayOrigins.Remove(rayOrigin)) - { - Image lastResizeIcon; - if (m_LastResizeIcons.TryGetValue(rayOrigin, out lastResizeIcon)) - { - lastResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); - m_LastResizeIcons.Remove(rayOrigin); - } - } - - if (m_HovereringRayOrigins.Count == 0) - ResetFrameThickness(); - } - - void Update() - { - if (!m_DynamicFaceAdjustment) - return; - - var currentXRotation = transform.rotation.eulerAngles.x; - if (Mathf.Approximately(currentXRotation, m_PreviousXRotation)) - return; // Exit if no x rotation change occurred for this frame - - m_PreviousXRotation = currentXRotation; - - // a second additional value added to the y offset of the front panel when it is in mid-reveal, - // lerped in at the middle of the rotation/reveal, and lerped out at the beginning & end of the rotation/reveal - const int kRevealCompensationBlendShapeIndex = 5; - const float kLerpPadding = 1.2f; // pad lerp values increasingly as it increases, displaying the "front face reveal" sooner - const float kCorrectiveRevealShapeMultiplier = 1.85f; - var angledAmount = Mathf.Clamp(Mathf.DeltaAngle(currentXRotation, 0f), 0f, 90f); - var midRevealCorrectiveShapeAmount = Mathf.PingPong(angledAmount * kCorrectiveRevealShapeMultiplier, 90); - - // add lerp padding to reach and maintain the target value sooner - m_LerpAmount = angledAmount / 90f; - var paddedLerp = m_LerpAmount * kLerpPadding; - - // offset front panel according to workspace rotation angle - const float kAdditionalFrontPanelLerpPadding = 1.1f; - const float kFrontPanelYOffset = 0.03f; - const float kFrontPanelZStartOffset = 0.0084f; - const float kFrontPanelZEndOffset = -0.05f; - m_FrontPanel.localRotation = Quaternion.Euler(Vector3.Lerp(k_BaseFrontPanelRotation, k_MaxFrontPanelRotation, paddedLerp * kAdditionalFrontPanelLerpPadding)); - m_FrontPanel.localPosition = Vector3.Lerp(Vector3.forward * kFrontPanelZStartOffset, new Vector3(0, kFrontPanelYOffset, kFrontPanelZEndOffset), paddedLerp); - - m_FrontZOffset = (k_FrontFrameZOffset + m_FrontFrameHandleSize) * Mathf.Clamp01(paddedLerp * kAdditionalFrontPanelLerpPadding); - var frameBounds = adjustedBounds; - m_FrameCollider.size = frameBounds.size; - m_FrameCollider.center = frameBounds.center; - - AdjustHandlesAndIcons(); - - // change blendshapes according to workspace rotation angle - m_Frame.SetBlendShapeWeight(k_AngledFaceBlendShapeIndex, angledAmount * kLerpPadding); - m_Frame.SetBlendShapeWeight(kRevealCompensationBlendShapeIndex, midRevealCorrectiveShapeAmount); - } - - public void ProcessInput(WorkspaceInput input, ConsumeControlDelegate consumeControl) - { - if (m_Controls.Count == 0) - InputUtils.GetBindingDictionaryFromActionMap(input.actionMap, m_Controls); - - var moveResizeLeft = input.moveResizeLeft; - var moveResizeRight = input.moveResizeRight; - - if (m_DragState != null) - { - var rayOrigin = m_DragState.rayOrigin; - - if ((rayOrigin == leftRayOrigin && moveResizeLeft.wasJustReleased) - || (rayOrigin == rightRayOrigin && moveResizeRight.wasJustReleased)) - { - m_DragState = null; - m_LastResizeIcons.Clear(); - - foreach (var smoothMotion in GetComponentsInChildren()) - { - smoothMotion.enabled = true; - } - - highlightsVisible = false; - } - else - { - m_DragState.OnDragging(); - } - - return; - } - - Transform dragRayOrigin = null; - Image dragResizeIcon = null; - var resizing = false; - - var hasLeft = false; - var hasRight = false; - for (int i = 0; i < m_HovereringRayOrigins.Count; i++) - { - var rayOrigin = m_HovereringRayOrigins[i]; - Image lastResizeIcon; - m_LastResizeIcons.TryGetValue(rayOrigin, out lastResizeIcon); - if (rayOrigin == leftRayOrigin) - { - if (m_LeftResizeFeedback.Count == 0) - ShowLeftResizeFeedback(); - - if (moveResizeLeft.wasJustPressed) - { - consumeControl(moveResizeLeft); - dragRayOrigin = rayOrigin; - dragResizeIcon = lastResizeIcon; - resizing = true; - } - - hasLeft = true; - } - - if (rayOrigin == rightRayOrigin) - { - if (m_RightResizeFeedback.Count == 0) - ShowRightResizeFeedback(); - - if (moveResizeRight.wasJustPressed) - { - consumeControl(moveResizeRight); - dragRayOrigin = rayOrigin; - dragResizeIcon = lastResizeIcon; - resizing = true; - } - - hasRight = true; - } - - const float kVisibleOpacity = 0.75f; - var localPosition = transform.InverseTransformPoint(this.GetPointerPosition(rayOrigin)); - var direction = GetResizeDirectionForLocalPosition(localPosition); - var resizeIcon = GetResizeIconForDirection(direction); - - if (lastResizeIcon != null) - { - if (resizeIcon != lastResizeIcon) - { - resizeIcon.CrossFadeAlpha(kVisibleOpacity, k_ResizeIconCrossfadeDuration, true); - lastResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); - } - } - else - { - resizeIcon.CrossFadeAlpha(kVisibleOpacity, k_ResizeIconCrossfadeDuration, true); - } - - m_LastResizeIcons[rayOrigin] = resizeIcon; - - var iconTransform = resizeIcon.transform; - var iconPosition = iconTransform.localPosition; - var smoothFollow = lastResizeIcon == null ? 1 : k_ResizeIconSmoothFollow * Time.deltaTime; - var localDirection = localPosition - transform.InverseTransformPoint(rayOrigin.position); - switch (direction) - { - case ResizeDirection.Front: - case ResizeDirection.Back: - var iconPositionX = iconPosition.x; - var positionOffsetX = Mathf.Sign(localDirection.x) * m_ResizeHandleMargin; - var tergetPositionX = localPosition.x + positionOffsetX; - if (Mathf.Abs(tergetPositionX) > bounds.extents.x - m_ResizeCornerSize) - tergetPositionX = localPosition.x - positionOffsetX; - - iconPosition.x = Mathf.Lerp(iconPositionX, tergetPositionX, smoothFollow); - break; - case ResizeDirection.Left: - case ResizeDirection.Right: - var iconPositionY = iconPosition.y; - var positionOffsetY = Mathf.Sign(localDirection.z) * m_ResizeHandleMargin; - var tergetPositionY = localPosition.z + positionOffsetY; - if (Mathf.Abs(tergetPositionY) > bounds.extents.z - m_ResizeCornerSize) - tergetPositionY = localPosition.z - positionOffsetY; - - iconPosition.y = Mathf.Lerp(iconPositionY, tergetPositionY, smoothFollow); - break; - } - - iconTransform.localPosition = iconPosition; - } - - if (!hasRight) - HideRightResizeFeedback(); - - if (!hasLeft) - HideLeftResizeFeedback(); - - var adjustedBounds = this.adjustedBounds; - if (!dragRayOrigin) - { - var leftPosition = transform.InverseTransformPoint(leftRayOrigin.position); - var leftPointerPosition = transform.InverseTransformPoint(this.GetPointerPosition(leftRayOrigin)); - if (adjustedBounds.Contains(leftPosition) || adjustedBounds.Contains(leftPointerPosition)) - { - if (m_LeftMoveFeedback.Count == 0) - ShowLeftMoveFeedback(); - - if (moveResizeLeft.wasJustPressed) - { - dragRayOrigin = leftRayOrigin; - m_LastResizeIcons.TryGetValue(dragRayOrigin, out dragResizeIcon); - consumeControl(moveResizeLeft); - } - } - else - { - HideLeftMoveFeedback(); - } - - var rightPosition = transform.InverseTransformPoint(rightRayOrigin.position); - var rightPointerPosition = transform.InverseTransformPoint(this.GetPointerPosition(rightRayOrigin)); - if (adjustedBounds.Contains(rightPosition) || adjustedBounds.Contains(rightPointerPosition)) - { - if (m_RightMoveFeedback.Count == 0) - ShowRightMoveFeedback(); - - if (moveResizeRight.wasJustPressed) - { - dragRayOrigin = rightRayOrigin; - m_LastResizeIcons.TryGetValue(dragRayOrigin, out dragResizeIcon); - consumeControl(moveResizeRight); - } - } - else - { - HideRightMoveFeedback(); - } - } - - if (dragRayOrigin) - { - m_DragState = new DragState(this, dragRayOrigin, resizing); - if (dragResizeIcon != null) - dragResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); - - ResetFrameThickness(); - - foreach (var smoothMotion in GetComponentsInChildren()) - { - smoothMotion.enabled = false; - } - - highlightsVisible = true; - } - } - void OnDestroy() - { - ObjectUtils.Destroy(m_TopFaceMaterial); - ObjectUtils.Destroy(m_FrontFaceMaterial); - - m_CloseButton.clicked -= OnCloseClicked; - m_CloseButton.hovered -= OnButtonHovered; - m_ResizeButton.clicked -= OnResetSizeClicked; - m_ResizeButton.hovered -= OnButtonHovered; - } - - void OnCloseClicked(Transform rayOrigin) - { - if (closeClicked != null) - closeClicked(rayOrigin); - } - - void OnResetSizeClicked(Transform rayOrigin) - { - if (resetSizeClicked != null) - resetSizeClicked(rayOrigin); - } - - void OnButtonHovered(Transform rayOrigin) - { - if (buttonHovered != null) - buttonHovered(rayOrigin); - } - - void IncreaseFrameThickness(Transform rayOrigin = null) - { - this.StopCoroutine(ref m_FrameThicknessCoroutine); - const float kTargetBlendAmount = 0f; - m_FrameThicknessCoroutine = StartCoroutine(ChangeFrameThickness(kTargetBlendAmount, rayOrigin)); - } - - void ResetFrameThickness() - { - this.StopCoroutine(ref m_FrameThicknessCoroutine); - const float kTargetBlendAmount = 50f; - m_FrameThicknessCoroutine = StartCoroutine(ChangeFrameThickness(kTargetBlendAmount, null)); - } - - IEnumerator ChangeFrameThickness(float targetBlendAmount, Transform rayOrigin) - { - const float kTargetDuration = 0.25f; - var currentDuration = 0f; - var currentBlendAmount = m_Frame.GetBlendShapeWeight(k_ThinFrameBlendShapeIndex); - var currentVelocity = 0f; - while (currentDuration < kTargetDuration) - { - currentDuration += Time.deltaTime; - currentBlendAmount = MathUtilsExt.SmoothDamp(currentBlendAmount, targetBlendAmount, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - m_Frame.SetBlendShapeWeight(k_ThinFrameBlendShapeIndex, currentBlendAmount); - yield return null; - } - - // If hovering the frame, and not moving, perform haptic feedback - if (hoveringFrame != null && m_HovereringRayOrigins.Count > 0 && m_DragState == null && Mathf.Approximately(targetBlendAmount, 0f)) - hoveringFrame(rayOrigin); - - m_FrameThicknessCoroutine = null; - } - - IEnumerator ShowTopFace() - { - const string kMaterialHighlightAlphaProperty = "_Alpha"; - const float kTargetAlpha = 1f; - const float kTargetDuration = 0.35f; - var currentDuration = 0f; - var currentAlpha = m_TopFaceMaterial.GetFloat(kMaterialHighlightAlphaProperty); - var currentVelocity = 0f; - while (currentDuration < kTargetDuration) - { - currentDuration += Time.deltaTime; - currentAlpha = MathUtilsExt.SmoothDamp(currentAlpha, kTargetAlpha, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - m_TopFaceMaterial.SetFloat(kMaterialHighlightAlphaProperty, currentAlpha); - yield return null; - } - - m_TopFaceVisibleCoroutine = null; - } - - IEnumerator HideTopFace() - { - const string kMaterialHighlightAlphaProperty = "_Alpha"; - const float kTargetAlpha = 0f; - const float kTargetDuration = 0.2f; - var currentDuration = 0f; - var currentAlpha = m_TopFaceMaterial.GetFloat(kMaterialHighlightAlphaProperty); - var currentVelocity = 0f; - while (currentDuration < kTargetDuration) - { - currentDuration += Time.deltaTime; - currentAlpha = MathUtilsExt.SmoothDamp(currentAlpha, kTargetAlpha, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - m_TopFaceMaterial.SetFloat(kMaterialHighlightAlphaProperty, currentAlpha); - yield return null; - } - - m_TopFaceVisibleCoroutine = null; - } - - void OnMoving(Transform rayOrigin) - { - if (moving != null) - moving(rayOrigin); - } - - void OnResizing(Transform rayOrigin) - { - if (resizing != null) - resizing(rayOrigin); - } - - void ShowFeedback(List requests, Node node, string controlName, string tooltipText, int priority = 1) - { - if (tooltipText == null) - tooltipText = controlName; - - List ids; - if (m_Controls.TryGetValue(controlName, out ids)) - { - foreach (var id in ids) - { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - priority = priority, - tooltipText = tooltipText - }; - - this.AddFeedbackRequest(request); - requests.Add(request); - } - } - } - - void ShowLeftMoveFeedback() - { - ShowFeedback(m_LeftMoveFeedback, Node.LeftHand, "Move Resize Left", "Move Workspace"); - } - - void ShowLeftResizeFeedback() - { - ShowFeedback(m_LeftResizeFeedback, Node.LeftHand, "Move Resize Left", "Resize Workspace", 2); - } - - void ShowRightMoveFeedback() - { - ShowFeedback(m_RightMoveFeedback, Node.RightHand, "Move Resize Right", "Move Workspace"); - } - - void ShowRightResizeFeedback() - { - ShowFeedback(m_RightResizeFeedback, Node.RightHand, "Move Resize Right", "Resize Workspace", 2); - } - - void HideFeedback(List requests) - { - foreach (var request in requests) - { - this.RemoveFeedbackRequest(request); - } - requests.Clear(); - } - - void HideLeftMoveFeedback() - { - HideFeedback(m_LeftMoveFeedback); - } - - void HideRightMoveFeedback() - { - HideFeedback(m_RightMoveFeedback); - } - - void HideLeftResizeFeedback() - { - HideFeedback(m_LeftResizeFeedback); - } - - void HideRightResizeFeedback() - { - HideFeedback(m_RightResizeFeedback); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEditor.Experimental.EditorVR.Helpers; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; +using UnityEngine.UI; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + sealed class WorkspaceUI : MonoBehaviour, IUsesStencilRef, IUsesViewerScale, IUsesPointer, IRequestFeedback + { + [Flags] + enum ResizeDirection + { + Front = 1, + Back = 2, + Left = 4, + Right = 8 + } + + class DragState + { + public Transform rayOrigin { get; private set; } + bool m_Resizing; + Vector3 m_PositionOffset; + Quaternion m_RotationOffset; + WorkspaceUI m_WorkspaceUI; + Vector3 m_DragStart; + Vector3 m_PositionStart; + Vector3 m_BoundsSizeStart; + ResizeDirection m_Direction; + + public DragState(WorkspaceUI workspaceUI, Transform rayOrigin, bool resizing) + { + m_WorkspaceUI = workspaceUI; + m_Resizing = resizing; + this.rayOrigin = rayOrigin; + + if (resizing) + { + var pointerPosition = m_WorkspaceUI.GetPointerPosition(rayOrigin); + m_DragStart = pointerPosition; + m_PositionStart = workspaceUI.transform.parent.position; + m_BoundsSizeStart = workspaceUI.bounds.size; + var localPosition = m_WorkspaceUI.transform.InverseTransformPoint(pointerPosition); + m_Direction = m_WorkspaceUI.GetResizeDirectionForLocalPosition(localPosition); + } + else + { + MathUtilsExt.GetTransformOffset(rayOrigin, m_WorkspaceUI.transform.parent, out m_PositionOffset, out m_RotationOffset); + } + } + + public void OnDragging() + { + if (m_Resizing) + { + var viewerScale = m_WorkspaceUI.GetViewerScale(); + var pointerPosition = m_WorkspaceUI.GetPointerPosition(rayOrigin); + var dragVector = (pointerPosition - m_DragStart) / viewerScale; + var bounds = m_WorkspaceUI.bounds; + var transform = m_WorkspaceUI.transform; + + var positionOffsetForward = Vector3.Dot(dragVector, transform.forward) * 0.5f; + var positionOffsetRight = Vector3.Dot(dragVector, transform.right) * 0.5f; + + switch (m_Direction) + { + default: + bounds.size = m_BoundsSizeStart + Vector3.back * Vector3.Dot(dragVector, transform.forward); + positionOffsetRight = 0; + break; + case ResizeDirection.Back: + bounds.size = m_BoundsSizeStart + Vector3.forward * Vector3.Dot(dragVector, transform.forward); + positionOffsetRight = 0; + break; + case ResizeDirection.Left: + bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right); + positionOffsetForward = 0; + break; + case ResizeDirection.Right: + bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right); + positionOffsetForward = 0; + break; + case ResizeDirection.Front | ResizeDirection.Left: + bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) + + Vector3.back * Vector3.Dot(dragVector, transform.forward); + break; + case ResizeDirection.Front | ResizeDirection.Right: + bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) + + Vector3.back * Vector3.Dot(dragVector, transform.forward); + break; + case ResizeDirection.Back | ResizeDirection.Left: + bounds.size = m_BoundsSizeStart + Vector3.left * Vector3.Dot(dragVector, transform.right) + + Vector3.forward * Vector3.Dot(dragVector, transform.forward); + break; + case ResizeDirection.Back | ResizeDirection.Right: + bounds.size = m_BoundsSizeStart + Vector3.right * Vector3.Dot(dragVector, transform.right) + + Vector3.forward * Vector3.Dot(dragVector, transform.forward); + break; + } + + if (m_WorkspaceUI.resize != null) + m_WorkspaceUI.resize(bounds); + + var currentExtents = m_WorkspaceUI.bounds.extents; + var extents = bounds.extents; + var absRight = Mathf.Abs(positionOffsetRight); + var absForward = Mathf.Abs(positionOffsetForward); + var positionOffset = transform.right * (absRight - (currentExtents.x - extents.x)) * Mathf.Sign(positionOffsetRight) + + transform.forward * (absForward - (currentExtents.z - extents.z)) * Mathf.Sign(positionOffsetForward); + + m_WorkspaceUI.transform.parent.position = m_PositionStart + positionOffset * viewerScale; + m_WorkspaceUI.OnResizing(rayOrigin); + } + else + { + MathUtilsExt.SetTransformOffset(rayOrigin, m_WorkspaceUI.transform.parent, m_PositionOffset, m_RotationOffset); + m_WorkspaceUI.OnMoving(rayOrigin); + } + } + } + + const int k_AngledFaceBlendShapeIndex = 2; + const int k_ThinFrameBlendShapeIndex = 3; + const string k_MaterialStencilRef = "_StencilRef"; + + const float k_ResizeIconCrossfadeDuration = 0.1f; + const float k_ResizeIconSmoothFollow = 10f; + + const float k_FrontFrameZOffset = 0.088f; + + static readonly Vector3 k_BaseFrontPanelRotation = Vector3.zero; + static readonly Vector3 k_MaxFrontPanelRotation = new Vector3(90f, 0f, 0f); + + [SerializeField] + Transform m_SceneContainer; + + [SerializeField] + RectTransform m_FrontPanel; + + [SerializeField] + BaseHandle[] m_Handles; + + [SerializeField] + Image[] m_ResizeIcons; + + [SerializeField] + Transform m_FrontLeftHandle; + + [SerializeField] + Transform m_FrontLeftCornerHandle; + + [SerializeField] + Transform m_FrontRightHandle; + + [SerializeField] + Transform m_FrontRightCornerHandle; + + [SerializeField] + Transform m_BottomFrontHandle; + + [SerializeField] + Transform m_TopFaceContainer; + + [SerializeField] + WorkspaceHighlight m_TopHighlight; + + [SerializeField] + SkinnedMeshRenderer m_Frame; + + [SerializeField] + Transform m_FrameFrontFaceTransform; + + [SerializeField] + Transform m_FrameFrontFaceHighlightTransform; + + [SerializeField] + Transform m_TopPanelDividerTransform; + + [SerializeField] + RectTransform m_UIContentContainer; + + [SerializeField] + Image m_FrontResizeIcon; + + [SerializeField] + Image m_RightResizeIcon; + + [SerializeField] + Image m_LeftResizeIcon; + + [SerializeField] + Image m_BackResizeIcon; + + [SerializeField] + Image m_FrontLeftResizeIcon; + + [SerializeField] + Image m_FrontRightResizeIcon; + + [SerializeField] + Image m_BackLeftResizeIcon; + + [SerializeField] + Image m_BackRightResizeIcon; + + [SerializeField] + Transform m_TopHighlightContainer; + + [SerializeField] + RectTransform m_HandleRectTransform; + + [SerializeField] + RectTransform m_ResizeIconRectTransform; + + [SerializeField] + WorkspaceHighlight m_FrontHighlight; + + [SerializeField] + float m_FrameHandleSize = 0.03f; + + [SerializeField] + float m_FrontFrameHandleSize = 0.01f; + + [SerializeField] + float m_FrameHeight = 0.09275f; + + [SerializeField] + float m_ResizeHandleMargin = 0.01f; + + [SerializeField] + float m_ResizeCornerSize = 0.05f; + + [SerializeField] + bool m_DynamicFaceAdjustment = true; + + [SerializeField] + WorkspaceButton m_CloseButton; + + [SerializeField] + WorkspaceButton m_ResizeButton; + + BoxCollider m_FrameCollider; + Bounds m_Bounds; + float? m_TopPanelDividerOffset; + + readonly BindingDictionary m_Controls = new BindingDictionary(); + readonly List m_LeftMoveFeedback = new List(); + readonly List m_RightMoveFeedback = new List(); + readonly List m_LeftResizeFeedback = new List(); + readonly List m_RightResizeFeedback = new List(); + + // Cached for optimization + float m_PreviousXRotation; + Coroutine m_FrameThicknessCoroutine; + Coroutine m_TopFaceVisibleCoroutine; + Material m_TopFaceMaterial; + Material m_FrontFaceMaterial; + + float m_LerpAmount; + float m_FrontZOffset; + + DragState m_DragState; + + readonly List m_HovereringRayOrigins = new List(); + readonly Dictionary m_LastResizeIcons = new Dictionary(); + + public bool highlightsVisible + { + set + { + if (m_TopHighlight.visible == value && m_FrontHighlight.visible == value) + return; + + m_TopHighlight.visible = value; + m_FrontHighlight.visible = value; + + if (value) + IncreaseFrameThickness(); + else + ResetFrameThickness(); + } + } + + public bool frontHighlightVisible + { + set + { + if (m_FrontHighlight.visible == value) + return; + + m_FrontHighlight.visible = value; + + if (value) + IncreaseFrameThickness(); + else + ResetFrameThickness(); + } + } + + public bool amplifyTopHighlight + { + set + { + this.StopCoroutine(ref m_TopFaceVisibleCoroutine); + m_TopFaceVisibleCoroutine = value ? StartCoroutine(HideTopFace()) : StartCoroutine(ShowTopFace()); + } + } + + /// + /// (-1 to 1) ranged value that controls the separator mask's X-offset placement + /// A value of zero will leave the mask in the center of the workspace + /// + public float topPanelDividerOffset + { + set + { + m_TopPanelDividerOffset = value; + m_TopPanelDividerTransform.gameObject.SetActive(true); + } + } + + public Transform topFaceContainer + { + get { return m_TopFaceContainer; } + set { m_TopFaceContainer = value; } + } + + public bool dynamicFaceAdjustment + { + get { return m_DynamicFaceAdjustment; } + set { m_DynamicFaceAdjustment = value; } + } + + public bool preventResize + { + set + { + foreach (var handle in m_Handles) + { + handle.gameObject.SetActive(!value); + } + } + } + + public Bounds bounds + { + get { return m_Bounds; } + set + { + m_Bounds = value; + + m_Bounds.center = Vector3.down * m_FrameHeight * 0.5f; + + var extents = m_Bounds.extents; + var size = m_Bounds.size; + size.y = m_FrameHeight + m_FrameHandleSize; + m_Bounds.size = size; + + const float kWidthMultiplier = 0.96154f; + const float kDepthMultiplier = 0.99383f; + const float kWidthOffset = -0.156f; + const float kDepthOffset = -0.0318f; + const float kDepthCompensation = -0.008f; + + var width = size.x; + var depth = size.z; + var faceWidth = width - Workspace.FaceMargin; + var faceDepth = depth - Workspace.FaceMargin; + + m_Frame.SetBlendShapeWeight(0, width * kWidthMultiplier + kWidthOffset); + m_Frame.SetBlendShapeWeight(1, depth * kDepthMultiplier + kDepthOffset + kDepthCompensation * m_LerpAmount); + + // Resize content container + m_UIContentContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, faceWidth); + var localPosition = m_UIContentContainer.localPosition; + localPosition.z = -extents.z; + m_UIContentContainer.localPosition = localPosition; + + // Resize front panel + m_FrameFrontFaceTransform.localScale = new Vector3(faceWidth, 1f, 1f); + const float kFrontFaceHighlightMargin = 0.0008f; + m_FrameFrontFaceHighlightTransform.localScale = new Vector3(faceWidth + kFrontFaceHighlightMargin, 1f, 1f); + + // Position the separator mask if enabled + if (m_TopPanelDividerOffset != null) + { + m_TopPanelDividerTransform.localPosition = new Vector3(faceWidth * (m_TopPanelDividerOffset.Value - 0.5f), 0f, 0f); + m_TopPanelDividerTransform.localScale = new Vector3(1f, 1f, faceDepth + Workspace.HighlightMargin); + } + + // Scale the Top Face and the Top Face Highlight + const float kHighlightMargin = 0.0005f; + m_TopHighlightContainer.localScale = new Vector3(faceWidth + kHighlightMargin, 1f, faceDepth + kHighlightMargin); + m_TopFaceContainer.localScale = new Vector3(faceWidth, 1f, faceDepth); + + var frameBounds = adjustedBounds; + m_FrameCollider.size = frameBounds.size; + m_FrameCollider.center = frameBounds.center; + + AdjustHandlesAndIcons(); + } + } + + public Bounds adjustedBounds + { + get + { + var adjustedBounds = bounds; + adjustedBounds.size += Vector3.forward * m_FrontZOffset; + adjustedBounds.center += Vector3.back * m_FrontZOffset * 0.5f; + return adjustedBounds; + } + } + + public event Action buttonHovered; + public event Action closeClicked; + public event Action resetSizeClicked; + public event Action resizing; + public event Action moving; + public event Action hoveringFrame; + + public Transform sceneContainer { get { return m_SceneContainer; } } + public RectTransform frontPanel { get { return m_FrontPanel; } } + public WorkspaceHighlight topHighlight { get { return m_TopHighlight; } } + + public byte stencilRef { get; set; } + + public Transform leftRayOrigin { private get; set; } + public Transform rightRayOrigin { private get; set; } + + public event Action resize; + + void Awake() + { + foreach (var icon in m_ResizeIcons) + { + icon.CrossFadeAlpha(0f, 0f, true); + } + + m_Frame.SetBlendShapeWeight(k_ThinFrameBlendShapeIndex, 50f); // Set default frame thickness to be in middle for a thinner initial frame + + if (m_TopPanelDividerOffset == null) + m_TopPanelDividerTransform.gameObject.SetActive(false); + + foreach (var handle in m_Handles) + { + handle.hoverStarted += OnHandleHoverStarted; + handle.hoverEnded += OnHandleHoverEnded; + } + + m_CloseButton.clicked += OnCloseClicked; + m_CloseButton.hovered += OnButtonHovered; + m_ResizeButton.clicked += OnResetSizeClicked; + m_ResizeButton.hovered += OnButtonHovered; + + m_FrameCollider = transform.parent.gameObject.AddComponent(); + } + + IEnumerator Start() + { + const string kShaderBlur = "_Blur"; + const string kShaderAlpha = "_Alpha"; + const string kShaderVerticalOffset = "_VerticalOffset"; + const float kTargetDuration = 1.25f; + + m_TopFaceMaterial = MaterialUtils.GetMaterialClone(m_TopFaceContainer.GetComponentInChildren()); + m_TopFaceMaterial.SetFloat("_Alpha", 1f); + m_TopFaceMaterial.SetInt(k_MaterialStencilRef, stencilRef); + + m_FrontFaceMaterial = MaterialUtils.GetMaterialClone(m_FrameFrontFaceTransform.GetComponentInChildren()); + m_FrontFaceMaterial.SetInt(k_MaterialStencilRef, stencilRef); + + var originalBlurAmount = m_TopFaceMaterial.GetFloat("_Blur"); + var currentBlurAmount = 10f; // also the maximum blur amount + var currentDuration = 0f; + var currentVelocity = 0f; + + m_TopFaceMaterial.SetFloat(kShaderBlur, currentBlurAmount); + m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 1f); // increase the blur sample offset to amplify the effect + m_TopFaceMaterial.SetFloat(kShaderAlpha, 0.5f); // set partially transparent + + while (currentDuration < kTargetDuration) + { + currentDuration += Time.deltaTime; + currentBlurAmount = MathUtilsExt.SmoothDamp(currentBlurAmount, originalBlurAmount, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); + m_TopFaceMaterial.SetFloat(kShaderBlur, currentBlurAmount); + + var percentageComplete = currentDuration / kTargetDuration; + m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 1 - percentageComplete); // lerp back towards an offset of zero + m_TopFaceMaterial.SetFloat(kShaderAlpha, percentageComplete * 0.5f + 0.5f); // lerp towards fully opaque from 50% transparent + + yield return null; + } + + m_TopFaceMaterial.SetFloat(kShaderBlur, originalBlurAmount); + m_TopFaceMaterial.SetFloat(kShaderVerticalOffset, 0f); + m_TopFaceMaterial.SetFloat(kShaderAlpha, 1f); + + yield return null; + } + + void AdjustHandlesAndIcons() + { + var size = m_Bounds.size; + m_HandleRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); + m_HandleRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z); + + var halfFrontZOffset = m_FrontZOffset * 0.5f; + var localPosition = m_ResizeIconRectTransform.localPosition; + localPosition.z = -halfFrontZOffset; + m_ResizeIconRectTransform.localPosition = localPosition; + m_ResizeIconRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); + m_ResizeIconRectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z + m_FrontZOffset); + + var extents = m_Bounds.extents; + var halfWidth = extents.x; + var halfDepth = extents.z; + var yOffset = m_FrameHeight * (0.5f - m_LerpAmount); + localPosition = m_BottomFrontHandle.localPosition; + localPosition.z = yOffset; + localPosition.y = -halfDepth - m_FrontZOffset; + m_BottomFrontHandle.localPosition = localPosition; + + yOffset = (1 - m_LerpAmount) * m_FrameHeight; + var angle = Mathf.Atan(m_FrontZOffset / yOffset) * Mathf.Rad2Deg; + + m_FrontLeftHandle.localPosition = new Vector3(-halfWidth, -yOffset * 0.5f, -halfDepth - halfFrontZOffset); + m_FrontLeftHandle.localRotation = Quaternion.AngleAxis(angle, Vector3.right); + m_FrontLeftHandle.localScale = new Vector3(m_FrontFrameHandleSize, m_FrameHeight, m_FrontFrameHandleSize); + localPosition = m_FrontLeftHandle.localPosition; + localPosition.x = halfWidth; + + m_FrontRightHandle.localPosition = localPosition; + m_FrontRightHandle.localRotation = m_FrontLeftHandle.localRotation; + m_FrontRightHandle.localScale = m_FrontLeftHandle.localScale; + + var zOffset = m_FrontZOffset - (k_FrontFrameZOffset + m_FrontFrameHandleSize) * 0.5f; + var zScale = m_FrameHeight * m_LerpAmount; + var yPosition = -m_FrontFrameHandleSize * 0.5f - m_FrameHeight + zScale * 0.5f; + m_FrontLeftCornerHandle.localPosition = new Vector3(-halfWidth, yPosition, -halfDepth - zOffset - m_FrontFrameHandleSize); + m_FrontLeftCornerHandle.localScale = new Vector3(m_FrontFrameHandleSize, k_FrontFrameZOffset, zScale); + + m_FrontRightCornerHandle = m_FrontRightCornerHandle.transform; + localPosition = m_FrontLeftCornerHandle.localPosition; + localPosition.x = halfWidth; + m_FrontRightCornerHandle.localPosition = localPosition; + m_FrontRightCornerHandle.localRotation = m_FrontLeftCornerHandle.localRotation; + m_FrontRightCornerHandle.localScale = m_FrontLeftCornerHandle.localScale; + } + + void OnHandleHoverStarted(BaseHandle handle, HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + if (m_HovereringRayOrigins.Count == 0 && m_DragState == null) + IncreaseFrameThickness(rayOrigin); + + m_HovereringRayOrigins.Add(rayOrigin); + } + + ResizeDirection GetResizeDirectionForLocalPosition(Vector3 localPosition) + { + var direction = localPosition.z > 0 ? ResizeDirection.Back : ResizeDirection.Front; + var xDirection = localPosition.x > 0 ? ResizeDirection.Right : ResizeDirection.Left; + + var zDistance = bounds.extents.z - Mathf.Abs(localPosition.z); + if (localPosition.z < 0) + zDistance += m_FrontZOffset; + + var cornerZ = zDistance < m_ResizeCornerSize; + var cornerX = bounds.extents.x - Mathf.Abs(localPosition.x) < m_ResizeCornerSize; + + if (cornerZ && cornerX) + direction |= xDirection; + else if (cornerX) + direction = xDirection; + + return direction; + } + + Image GetResizeIconForDirection(ResizeDirection direction) + { + switch (direction) + { + default: + return m_FrontResizeIcon; + case ResizeDirection.Back: + return m_BackResizeIcon; + case ResizeDirection.Left: + return m_LeftResizeIcon; + case ResizeDirection.Right: + return m_RightResizeIcon; + case ResizeDirection.Front | ResizeDirection.Left: + return m_FrontLeftResizeIcon; + case ResizeDirection.Front | ResizeDirection.Right: + return m_FrontRightResizeIcon; + case ResizeDirection.Back | ResizeDirection.Left: + return m_BackLeftResizeIcon; + case ResizeDirection.Back | ResizeDirection.Right: + return m_BackRightResizeIcon; + } + } + + void OnHandleHoverEnded(BaseHandle handle, HandleEventData eventData) + { + var rayOrigin = eventData.rayOrigin; + if (m_HovereringRayOrigins.Remove(rayOrigin)) + { + Image lastResizeIcon; + if (m_LastResizeIcons.TryGetValue(rayOrigin, out lastResizeIcon)) + { + lastResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); + m_LastResizeIcons.Remove(rayOrigin); + } + } + + if (m_HovereringRayOrigins.Count == 0) + ResetFrameThickness(); + } + + void Update() + { + if (!m_DynamicFaceAdjustment) + return; + + var currentXRotation = transform.rotation.eulerAngles.x; + if (Mathf.Approximately(currentXRotation, m_PreviousXRotation)) + return; // Exit if no x rotation change occurred for this frame + + m_PreviousXRotation = currentXRotation; + + // a second additional value added to the y offset of the front panel when it is in mid-reveal, + // lerped in at the middle of the rotation/reveal, and lerped out at the beginning & end of the rotation/reveal + const int kRevealCompensationBlendShapeIndex = 5; + const float kLerpPadding = 1.2f; // pad lerp values increasingly as it increases, displaying the "front face reveal" sooner + const float kCorrectiveRevealShapeMultiplier = 1.85f; + var angledAmount = Mathf.Clamp(Mathf.DeltaAngle(currentXRotation, 0f), 0f, 90f); + var midRevealCorrectiveShapeAmount = Mathf.PingPong(angledAmount * kCorrectiveRevealShapeMultiplier, 90); + + // add lerp padding to reach and maintain the target value sooner + m_LerpAmount = angledAmount / 90f; + var paddedLerp = m_LerpAmount * kLerpPadding; + + // offset front panel according to workspace rotation angle + const float kAdditionalFrontPanelLerpPadding = 1.1f; + const float kFrontPanelYOffset = 0.03f; + const float kFrontPanelZStartOffset = 0.0084f; + const float kFrontPanelZEndOffset = -0.05f; + m_FrontPanel.localRotation = Quaternion.Euler(Vector3.Lerp(k_BaseFrontPanelRotation, k_MaxFrontPanelRotation, paddedLerp * kAdditionalFrontPanelLerpPadding)); + m_FrontPanel.localPosition = Vector3.Lerp(Vector3.forward * kFrontPanelZStartOffset, new Vector3(0, kFrontPanelYOffset, kFrontPanelZEndOffset), paddedLerp); + + m_FrontZOffset = (k_FrontFrameZOffset + m_FrontFrameHandleSize) * Mathf.Clamp01(paddedLerp * kAdditionalFrontPanelLerpPadding); + var frameBounds = adjustedBounds; + m_FrameCollider.size = frameBounds.size; + m_FrameCollider.center = frameBounds.center; + + AdjustHandlesAndIcons(); + + // change blendshapes according to workspace rotation angle + m_Frame.SetBlendShapeWeight(k_AngledFaceBlendShapeIndex, angledAmount * kLerpPadding); + m_Frame.SetBlendShapeWeight(kRevealCompensationBlendShapeIndex, midRevealCorrectiveShapeAmount); + } + + public void ProcessInput(WorkspaceInput input, ConsumeControlDelegate consumeControl) + { + if (m_Controls.Count == 0) + InputUtils.GetBindingDictionaryFromActionMap(input.actionMap, m_Controls); + + var moveResizeLeft = input.moveResizeLeft; + var moveResizeRight = input.moveResizeRight; + + if (m_DragState != null) + { + var rayOrigin = m_DragState.rayOrigin; + + if ((rayOrigin == leftRayOrigin && moveResizeLeft.wasJustReleased) + || (rayOrigin == rightRayOrigin && moveResizeRight.wasJustReleased)) + { + m_DragState = null; + m_LastResizeIcons.Clear(); + + foreach (var smoothMotion in GetComponentsInChildren()) + { + smoothMotion.enabled = true; + } + + highlightsVisible = false; + } + else + { + m_DragState.OnDragging(); + } + + return; + } + + Transform dragRayOrigin = null; + Image dragResizeIcon = null; + var resizing = false; + + var hasLeft = false; + var hasRight = false; + for (int i = 0; i < m_HovereringRayOrigins.Count; i++) + { + var rayOrigin = m_HovereringRayOrigins[i]; + Image lastResizeIcon; + m_LastResizeIcons.TryGetValue(rayOrigin, out lastResizeIcon); + if (rayOrigin == leftRayOrigin) + { + if (m_LeftResizeFeedback.Count == 0) + ShowLeftResizeFeedback(); + + if (moveResizeLeft.wasJustPressed) + { + consumeControl(moveResizeLeft); + dragRayOrigin = rayOrigin; + dragResizeIcon = lastResizeIcon; + resizing = true; + } + + hasLeft = true; + } + + if (rayOrigin == rightRayOrigin) + { + if (m_RightResizeFeedback.Count == 0) + ShowRightResizeFeedback(); + + if (moveResizeRight.wasJustPressed) + { + consumeControl(moveResizeRight); + dragRayOrigin = rayOrigin; + dragResizeIcon = lastResizeIcon; + resizing = true; + } + + hasRight = true; + } + + const float kVisibleOpacity = 0.75f; + var localPosition = transform.InverseTransformPoint(this.GetPointerPosition(rayOrigin)); + var direction = GetResizeDirectionForLocalPosition(localPosition); + var resizeIcon = GetResizeIconForDirection(direction); + + if (lastResizeIcon != null) + { + if (resizeIcon != lastResizeIcon) + { + resizeIcon.CrossFadeAlpha(kVisibleOpacity, k_ResizeIconCrossfadeDuration, true); + lastResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); + } + } + else + { + resizeIcon.CrossFadeAlpha(kVisibleOpacity, k_ResizeIconCrossfadeDuration, true); + } + + m_LastResizeIcons[rayOrigin] = resizeIcon; + + var iconTransform = resizeIcon.transform; + var iconPosition = iconTransform.localPosition; + var smoothFollow = lastResizeIcon == null ? 1 : k_ResizeIconSmoothFollow * Time.deltaTime; + var localDirection = localPosition - transform.InverseTransformPoint(rayOrigin.position); + switch (direction) + { + case ResizeDirection.Front: + case ResizeDirection.Back: + var iconPositionX = iconPosition.x; + var positionOffsetX = Mathf.Sign(localDirection.x) * m_ResizeHandleMargin; + var tergetPositionX = localPosition.x + positionOffsetX; + if (Mathf.Abs(tergetPositionX) > bounds.extents.x - m_ResizeCornerSize) + tergetPositionX = localPosition.x - positionOffsetX; + + iconPosition.x = Mathf.Lerp(iconPositionX, tergetPositionX, smoothFollow); + break; + case ResizeDirection.Left: + case ResizeDirection.Right: + var iconPositionY = iconPosition.y; + var positionOffsetY = Mathf.Sign(localDirection.z) * m_ResizeHandleMargin; + var tergetPositionY = localPosition.z + positionOffsetY; + if (Mathf.Abs(tergetPositionY) > bounds.extents.z - m_ResizeCornerSize) + tergetPositionY = localPosition.z - positionOffsetY; + + iconPosition.y = Mathf.Lerp(iconPositionY, tergetPositionY, smoothFollow); + break; + } + + iconTransform.localPosition = iconPosition; + } + + if (!hasRight) + HideRightResizeFeedback(); + + if (!hasLeft) + HideLeftResizeFeedback(); + + var adjustedBounds = this.adjustedBounds; + if (!dragRayOrigin) + { + var leftPosition = transform.InverseTransformPoint(leftRayOrigin.position); + var leftPointerPosition = transform.InverseTransformPoint(this.GetPointerPosition(leftRayOrigin)); + if (adjustedBounds.Contains(leftPosition) || adjustedBounds.Contains(leftPointerPosition)) + { + if (m_LeftMoveFeedback.Count == 0) + ShowLeftMoveFeedback(); + + if (moveResizeLeft.wasJustPressed) + { + dragRayOrigin = leftRayOrigin; + m_LastResizeIcons.TryGetValue(dragRayOrigin, out dragResizeIcon); + consumeControl(moveResizeLeft); + } + } + else + { + HideLeftMoveFeedback(); + } + + var rightPosition = transform.InverseTransformPoint(rightRayOrigin.position); + var rightPointerPosition = transform.InverseTransformPoint(this.GetPointerPosition(rightRayOrigin)); + if (adjustedBounds.Contains(rightPosition) || adjustedBounds.Contains(rightPointerPosition)) + { + if (m_RightMoveFeedback.Count == 0) + ShowRightMoveFeedback(); + + if (moveResizeRight.wasJustPressed) + { + dragRayOrigin = rightRayOrigin; + m_LastResizeIcons.TryGetValue(dragRayOrigin, out dragResizeIcon); + consumeControl(moveResizeRight); + } + } + else + { + HideRightMoveFeedback(); + } + } + + if (dragRayOrigin) + { + m_DragState = new DragState(this, dragRayOrigin, resizing); + if (dragResizeIcon != null) + dragResizeIcon.CrossFadeAlpha(0f, k_ResizeIconCrossfadeDuration, true); + + ResetFrameThickness(); + + foreach (var smoothMotion in GetComponentsInChildren()) + { + smoothMotion.enabled = false; + } + + highlightsVisible = true; + } + } + void OnDestroy() + { + ObjectUtils.Destroy(m_TopFaceMaterial); + ObjectUtils.Destroy(m_FrontFaceMaterial); + + m_CloseButton.clicked -= OnCloseClicked; + m_CloseButton.hovered -= OnButtonHovered; + m_ResizeButton.clicked -= OnResetSizeClicked; + m_ResizeButton.hovered -= OnButtonHovered; + } + + void OnCloseClicked(Transform rayOrigin) + { + if (closeClicked != null) + closeClicked(rayOrigin); + } + + void OnResetSizeClicked(Transform rayOrigin) + { + if (resetSizeClicked != null) + resetSizeClicked(rayOrigin); + } + + void OnButtonHovered(Transform rayOrigin) + { + if (buttonHovered != null) + buttonHovered(rayOrigin); + } + + void IncreaseFrameThickness(Transform rayOrigin = null) + { + this.StopCoroutine(ref m_FrameThicknessCoroutine); + const float kTargetBlendAmount = 0f; + m_FrameThicknessCoroutine = StartCoroutine(ChangeFrameThickness(kTargetBlendAmount, rayOrigin)); + } + + void ResetFrameThickness() + { + this.StopCoroutine(ref m_FrameThicknessCoroutine); + const float kTargetBlendAmount = 50f; + m_FrameThicknessCoroutine = StartCoroutine(ChangeFrameThickness(kTargetBlendAmount, null)); + } + + IEnumerator ChangeFrameThickness(float targetBlendAmount, Transform rayOrigin) + { + const float kTargetDuration = 0.25f; + var currentDuration = 0f; + var currentBlendAmount = m_Frame.GetBlendShapeWeight(k_ThinFrameBlendShapeIndex); + var currentVelocity = 0f; + while (currentDuration < kTargetDuration) + { + currentDuration += Time.deltaTime; + currentBlendAmount = MathUtilsExt.SmoothDamp(currentBlendAmount, targetBlendAmount, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); + m_Frame.SetBlendShapeWeight(k_ThinFrameBlendShapeIndex, currentBlendAmount); + yield return null; + } + + // If hovering the frame, and not moving, perform haptic feedback + if (hoveringFrame != null && m_HovereringRayOrigins.Count > 0 && m_DragState == null && Mathf.Approximately(targetBlendAmount, 0f)) + hoveringFrame(rayOrigin); + + m_FrameThicknessCoroutine = null; + } + + IEnumerator ShowTopFace() + { + const string kMaterialHighlightAlphaProperty = "_Alpha"; + const float kTargetAlpha = 1f; + const float kTargetDuration = 0.35f; + var currentDuration = 0f; + var currentAlpha = m_TopFaceMaterial.GetFloat(kMaterialHighlightAlphaProperty); + var currentVelocity = 0f; + while (currentDuration < kTargetDuration) + { + currentDuration += Time.deltaTime; + currentAlpha = MathUtilsExt.SmoothDamp(currentAlpha, kTargetAlpha, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); + m_TopFaceMaterial.SetFloat(kMaterialHighlightAlphaProperty, currentAlpha); + yield return null; + } + + m_TopFaceVisibleCoroutine = null; + } + + IEnumerator HideTopFace() + { + const string kMaterialHighlightAlphaProperty = "_Alpha"; + const float kTargetAlpha = 0f; + const float kTargetDuration = 0.2f; + var currentDuration = 0f; + var currentAlpha = m_TopFaceMaterial.GetFloat(kMaterialHighlightAlphaProperty); + var currentVelocity = 0f; + while (currentDuration < kTargetDuration) + { + currentDuration += Time.deltaTime; + currentAlpha = MathUtilsExt.SmoothDamp(currentAlpha, kTargetAlpha, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); + m_TopFaceMaterial.SetFloat(kMaterialHighlightAlphaProperty, currentAlpha); + yield return null; + } + + m_TopFaceVisibleCoroutine = null; + } + + void OnMoving(Transform rayOrigin) + { + if (moving != null) + moving(rayOrigin); + } + + void OnResizing(Transform rayOrigin) + { + if (resizing != null) + resizing(rayOrigin); + } + + void ShowFeedback(List requests, Node node, string controlName, string tooltipText, int priority = 1) + { + if (tooltipText == null) + tooltipText = controlName; + + List ids; + if (m_Controls.TryGetValue(controlName, out ids)) + { + foreach (var id in ids) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.priority = priority; + request.tooltipText = tooltipText; + requests.Add(request); + this.AddFeedbackRequest(request); + } + } + } + + void ShowLeftMoveFeedback() + { + ShowFeedback(m_LeftMoveFeedback, Node.LeftHand, "Move Resize Left", "Move Workspace"); + } + + void ShowLeftResizeFeedback() + { + ShowFeedback(m_LeftResizeFeedback, Node.LeftHand, "Move Resize Left", "Resize Workspace", 2); + } + + void ShowRightMoveFeedback() + { + ShowFeedback(m_RightMoveFeedback, Node.RightHand, "Move Resize Right", "Move Workspace"); + } + + void ShowRightResizeFeedback() + { + ShowFeedback(m_RightResizeFeedback, Node.RightHand, "Move Resize Right", "Resize Workspace", 2); + } + + void HideFeedback(List requests) + { + foreach (var request in requests) + { + this.RemoveFeedbackRequest(request); + } + requests.Clear(); + } + + void HideLeftMoveFeedback() + { + HideFeedback(m_LeftMoveFeedback); + } + + void HideRightMoveFeedback() + { + HideFeedback(m_RightMoveFeedback); + } + + void HideLeftResizeFeedback() + { + HideFeedback(m_LeftResizeFeedback); + } + + void HideRightResizeFeedback() + { + HideFeedback(m_RightResizeFeedback); + } + } +} +#endif diff --git a/Workspaces/Common/Prefabs/FilterButton.prefab b/Workspaces/Common/Prefabs/FilterButton.prefab index f2f5a3e6d..de9e5e120 100644 --- a/Workspaces/Common/Prefabs/FilterButton.prefab +++ b/Workspaces/Common/Prefabs/FilterButton.prefab @@ -37,7 +37,7 @@ GameObject: m_Component: - component: {fileID: 224000010255316478} - component: {fileID: 222000012941897208} - - component: {fileID: 114000013065111822} + - component: {fileID: 114580130425258110} m_Layer: 5 m_Name: Text m_TagString: Untagged @@ -152,39 +152,6 @@ MonoBehaviour: m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 ---- !u!114 &114000013065111822 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000010208401484} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} - m_Color: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 1} - m_RaycastTarget: 0 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, - Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - m_FontData: - m_Font: {fileID: 12800000, guid: 013679fd6ee2085428a7f896aa7b50cc, type: 3} - m_FontSize: 14 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 10 - m_MaxSize: 40 - m_Alignment: 3 - m_AlignByGeometry: 0 - m_RichText: 1 - m_HorizontalOverflow: 0 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: All/None --- !u!114 &114000013101132712 MonoBehaviour: m_ObjectHideFlags: 1 @@ -200,7 +167,7 @@ MonoBehaviour: m_EyePanel: {fileID: 114000013532684452} m_Eye: {fileID: 114000011813173376} m_TextPanel: {fileID: 114000013254149160} - m_Text: {fileID: 114000013065111822} + m_Text: {fileID: 114580130425258110} --- !u!114 &114000013254149160 MonoBehaviour: m_ObjectHideFlags: 1 @@ -317,6 +284,118 @@ MonoBehaviour: m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 +--- !u!114 &114580130425258110 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010208401484} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: All/None and stuff with overflow + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.014 + m_fontSizeBase: 0.014 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 513 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_firstOverflowCharacterIndex: -1 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114580130425258110} + characterCount: 23 + spriteCount: 0 + spaceCount: 3 + wordCount: 5 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!222 &222000010522060036 CanvasRenderer: m_ObjectHideFlags: 1 @@ -354,17 +433,17 @@ RectTransform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000010208401484} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -0.0002} - m_LocalScale: {x: 0.001, y: 0.001, z: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 224000013482272966} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 0.06665012, y: -0.00011215723} - m_SizeDelta: {x: 114.5619, y: 29.3607} - m_Pivot: {x: 0.5, y: 0.5} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.07227503, y: -0.00018998975} + m_SizeDelta: {x: 0.14393, y: 0.02} + m_Pivot: {x: 0, y: 0.5} --- !u!224 &224000010389022026 RectTransform: m_ObjectHideFlags: 1 @@ -408,7 +487,7 @@ RectTransform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000011664971740} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: @@ -419,7 +498,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchoredPosition: {x: -0.5, y: 0.55} m_SizeDelta: {x: 0.23, y: 0.03} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000013482272966 diff --git a/Workspaces/Common/Prefabs/FilterUI.prefab b/Workspaces/Common/Prefabs/FilterUI.prefab index 7168c572a..7d1b58175 100644 --- a/Workspaces/Common/Prefabs/FilterUI.prefab +++ b/Workspaces/Common/Prefabs/FilterUI.prefab @@ -191,7 +191,7 @@ GameObject: m_Component: - component: {fileID: 224000013947219512} - component: {fileID: 222000010645976992} - - component: {fileID: 114000013883654872} + - component: {fileID: 114908488939773918} m_Layer: 5 m_Name: Description m_TagString: Untagged @@ -215,23 +215,6 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!1 &1000011955002436 -GameObject: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - serializedVersion: 5 - m_Component: - - component: {fileID: 224000011638138020} - - component: {fileID: 222000012450206526} - - component: {fileID: 114000010570993454} - m_Layer: 5 - m_Name: Icon - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 --- !u!1 &1000012133731784 GameObject: m_ObjectHideFlags: 1 @@ -291,7 +274,7 @@ GameObject: m_Component: - component: {fileID: 224000010366256770} - component: {fileID: 222000011540912930} - - component: {fileID: 114000013668190444} + - component: {fileID: 114969544617510458} m_Layer: 5 m_Name: Summary m_TagString: Untagged @@ -434,11 +417,10 @@ Transform: m_LocalPosition: {x: -0.007400036, y: -0.000000057041493, z: -0.00000008218965} m_LocalScale: {x: 7.5641837, y: 2.503347, z: 1} m_Children: - - {fileID: 224000011194382768} - {fileID: 224000010242275708} - {fileID: 224000013754521624} m_Father: {fileID: 4000011653624854} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!4 &4000010967785486 Transform: @@ -477,6 +459,7 @@ Transform: m_LocalPosition: {x: 0.035397947, y: 0.00000003331204, z: -0.000000077919545} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: + - {fileID: 224000011194382768} - {fileID: 4000010821369492} m_Father: {fileID: 224000010866448056} m_RootOrder: 1 @@ -622,13 +605,13 @@ MonoBehaviour: m_AlternateIconSprite: {fileID: 0} m_ButtonMeshRenderer: {fileID: 23000010227944570} m_CanvasGroup: {fileID: 225000013559454362} - m_Icon: {fileID: 114000010570993454} + m_Icon: {fileID: 0} m_IconContainer: {fileID: 224000011194382768} m_Button: {fileID: 114000010404580652} m_SwapIconsOnClick: 0 m_HighlightItems: - - {fileID: 114000013668190444} - - {fileID: 114000013883654872} + - {fileID: 0} + - {fileID: 0} m_GrayscaleGradient: 0 m_AnimatedReveal: 1 m_DelayBeforeReveal: 0.125 @@ -667,7 +650,7 @@ MonoBehaviour: m_PressedTrigger: Pressed m_DisabledTrigger: Disabled m_Interactable: 1 - m_TargetGraphic: {fileID: 114000013668190444} + m_TargetGraphic: {fileID: 114000011492943456} m_OnClick: m_PersistentCalls: m_Calls: @@ -711,33 +694,6 @@ MonoBehaviour: m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 ---- !u!114 &114000010570993454 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011955002436} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 0 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, - Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - m_Sprite: {fileID: 21300000, guid: 9e99addd065823d4189ba97c2110682e, type: 3} - m_Type: 3 - m_PreserveAspect: 1 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 2 --- !u!114 &114000010697686692 MonoBehaviour: m_ObjectHideFlags: 1 @@ -749,8 +705,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6ce73cffb6071a94e84ff5b160100080, type: 3} m_Name: m_EditorClassIdentifier: - m_SummaryText: {fileID: 114000013668190444} - m_DescriptionText: {fileID: 114000013883654872} + m_SummaryText: {fileID: 114969544617510458} + m_DescriptionText: {fileID: 114908488939773918} m_ButtonList: {fileID: 224000013333582342} m_ButtonPrefab: {fileID: 1000011664971740, guid: 9356373b6af61fb47aef381a65c953dc, type: 2} @@ -998,41 +954,6 @@ MonoBehaviour: m_Spacing: {x: 0, y: 0} m_Constraint: 1 m_ConstraintCount: 1 ---- !u!114 &114000013668190444 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000012583667622} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} - m_Color: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 1} - m_RaycastTarget: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, - Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - m_FontData: - m_Font: {fileID: 12800000, guid: 013679fd6ee2085428a7f896aa7b50cc, type: 3} - m_FontSize: 2 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 1 - m_MaxSize: 2 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 1 - m_HorizontalOverflow: 1 - m_VerticalOverflow: 1 - m_LineSpacing: 1 - m_Text: 'View all - -' --- !u!114 &114000013866040058 MonoBehaviour: m_ObjectHideFlags: 1 @@ -1058,39 +979,6 @@ MonoBehaviour: m_GrayscaleGradient: 0 m_AnimatedReveal: 1 m_DelayBeforeReveal: 0.125 ---- !u!114 &114000013883654872 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011788878884} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} - m_Color: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 1} - m_RaycastTarget: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, - Version=1.0.0.0, Culture=neutral, PublicKeyToken=null - m_FontData: - m_Font: {fileID: 12800000, guid: 013679fd6ee2085428a7f896aa7b50cc, type: 3} - m_FontSize: 1 - m_FontStyle: 0 - m_BestFit: 0 - m_MinSize: 0 - m_MaxSize: 40 - m_Alignment: 0 - m_AlignByGeometry: 0 - m_RichText: 1 - m_HorizontalOverflow: 1 - m_VerticalOverflow: 1 - m_LineSpacing: 1 - m_Text: All types of objects are visible --- !u!114 &114000014158638022 MonoBehaviour: m_ObjectHideFlags: 1 @@ -1170,6 +1058,230 @@ MonoBehaviour: m_CallState: 1 m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null +--- !u!114 &114908488939773918 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011788878884} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: All types of objects are visible + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.01 + m_fontSizeBase: 0.01 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 257 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: -1 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114908488939773918} + characterCount: 32 + spriteCount: 0 + spaceCount: 5 + wordCount: 6 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &114969544617510458 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012583667622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: View all + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.02 + m_fontSizeBase: 0.02 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 257 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: 0 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114969544617510458} + characterCount: 8 + spriteCount: 0 + spaceCount: 1 + wordCount: 2 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!222 &222000010645976992 CanvasRenderer: m_ObjectHideFlags: 1 @@ -1188,12 +1300,6 @@ CanvasRenderer: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000012583667622} ---- !u!222 &222000012450206526 -CanvasRenderer: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011955002436} --- !u!222 &222000012570870192 CanvasRenderer: m_ObjectHideFlags: 1 @@ -1226,15 +1332,15 @@ RectTransform: m_GameObject: {fileID: 1000013772705832} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.13220197, y: 0.3994652, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4000010821369492} - m_RootOrder: 1 + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -4.7672725e-12, y: -0.03} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 0, y: -0.03} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000010366256770 RectTransform: @@ -1242,17 +1348,17 @@ RectTransform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000012583667622} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -0.00035344507} - m_LocalScale: {x: 13.315506, y: 13.315506, z: 13.315506} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 224000011194382768} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.4802881, y: 0.83956707} - m_AnchorMax: {x: 0.5526162, y: 0.83956707} - m_AnchoredPosition: {x: -0.00009393692, y: 0.000022888184} - m_SizeDelta: {x: 0.00000023841858, y: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.00351, y: 0.00538} + m_SizeDelta: {x: 0.14702, y: 0.02277} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000010866448056 RectTransform: @@ -1272,7 +1378,7 @@ RectTransform: m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 100, y: 100} + m_SizeDelta: {x: 0.2244, y: 0.05} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000011121188416 RectTransform: @@ -1298,39 +1404,20 @@ RectTransform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000012137799818} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.00009928422, y: 0.00030000007, z: 0.00030000007} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - {fileID: 224000010366256770} - {fileID: 224000013947219512} - - {fileID: 224000011638138020} - {fileID: 224000012846441888} - m_Father: {fileID: 4000010821369492} + m_Father: {fileID: 4000011653624854} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.00000681878, y: 0.00000012455233} - m_SizeDelta: {x: 200.58318, y: 69.2061} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!224 &224000011638138020 -RectTransform: - m_ObjectHideFlags: 1 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 100100000} - m_GameObject: {fileID: 1000011955002436} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 224000011194382768} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.000030875206, y: 0} - m_SizeDelta: {x: 144.65083, y: 62} + m_AnchoredPosition: {x: -0.007386, y: 0.000016} + m_SizeDelta: {x: 0.151252, y: 0.050072} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000011829119632 RectTransform: @@ -1340,15 +1427,15 @@ RectTransform: m_GameObject: {fileID: 1000010508801244} m_LocalRotation: {x: -0, y: -0, z: -7.251184e-18, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.39946523, y: 0.39946523, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4000010181320156} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.00000067800283, y: -0.01} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 0, y: -0.01} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000011830306076 RectTransform: @@ -1405,7 +1492,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 0.07825945, y: 0} + m_AnchoredPosition: {x: 0.07825947, y: 0} m_SizeDelta: {x: 0.22439998, y: 0.05} m_Pivot: {x: 0, y: 0.5} --- !u!224 &224000012846441888 @@ -1415,16 +1502,16 @@ RectTransform: m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000010336788726} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -0.00020019042} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 224000011194382768} - m_RootOrder: 3 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.000030875206, y: 0} - m_SizeDelta: {x: 200.6, y: 69.206} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0.15125, y: 0.050072} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000013276871106 RectTransform: @@ -1472,15 +1559,15 @@ RectTransform: m_GameObject: {fileID: 1000012601679824} m_LocalRotation: {x: -0, y: -0, z: -7.251184e-18, w: 1} m_LocalPosition: {x: 0, y: 0, z: -0} - m_LocalScale: {x: 0.39946523, y: 0.39946523, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4000010181320156} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -5.5537016e-11, y: -0.03} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 0, y: -0.03} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000013690042288 RectTransform: @@ -1509,15 +1596,15 @@ RectTransform: m_GameObject: {fileID: 1000013563257892} m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.13220197, y: 0.3994652, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 4000010821369492} - m_RootOrder: 2 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -0.0000013560057, y: -0.01} - m_SizeDelta: {x: 100, y: 100} + m_AnchoredPosition: {x: 0, y: -0.01} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!224 &224000013947219512 RectTransform: @@ -1525,17 +1612,17 @@ RectTransform: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 100100000} m_GameObject: {fileID: 1000011788878884} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -0.00023711883} - m_LocalScale: {x: 13.315506, y: 13.315506, z: 13.315506} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 224000011194382768} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.48078653, y: 0.42919698} - m_AnchorMax: {x: 0.5531146, y: 0.42919698} - m_AnchoredPosition: {x: 0.00000023841858, y: 0} - m_SizeDelta: {x: 0.00000047683716, y: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.00235, y: -0.01238} + m_SizeDelta: {x: 0.14425, y: 0.01527} m_Pivot: {x: 0.5, y: 0.5} --- !u!225 &225000010025708586 CanvasGroup: diff --git a/Workspaces/Common/Scripts/DraggableListItem.cs b/Workspaces/Common/Scripts/DraggableListItem.cs index e4fd37558..62abc6b97 100644 --- a/Workspaces/Common/Scripts/DraggableListItem.cs +++ b/Workspaces/Common/Scripts/DraggableListItem.cs @@ -1,15 +1,16 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using ListView; using System; using System.Collections; using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Core; using UnityEditor.Experimental.EditorVR.Handles; using UnityEditor.Experimental.EditorVR.Utilities; using UnityEngine; namespace UnityEditor.Experimental.EditorVR.Workspaces { - class DraggableListItem : ListViewItem, IGetPreviewOrigin, IUsesViewerScale + class DraggableListItem : ListViewItem, IGetPreviewOrigin, IUsesViewerScale, IRayToNode where TData : ListViewItemData { const float k_MagnetizeDuration = 0.5f; @@ -34,6 +35,9 @@ protected virtual void OnDragStarted(BaseHandle handle, HandleEventData eventDat m_DragObject = handle.transform; m_DragLerp = 0; StartCoroutine(Magnetize()); + + if (dragStart != null) + dragStart(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); } else { @@ -55,6 +59,7 @@ protected virtual IEnumerator Magnetize() m_DragLerp = currTime / k_MagnetizeDuration; yield return null; } + m_DragLerp = 1; OnMagnetizeEnded(); } @@ -67,6 +72,9 @@ protected virtual void OnDragging(BaseHandle handle, HandleEventData eventData) { var previewOrigin = this.GetPreviewOriginForRayOrigin(eventData.rayOrigin); MathUtilsExt.LerpTransform(m_DragObject, previewOrigin.position, previewOrigin.rotation, m_DragLerp); + + if (dragging != null) + dragging(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); } } else @@ -83,21 +91,50 @@ protected virtual void OnDragging(BaseHandle handle, HandleEventData eventData) if (m_DragObject == null && distance > k_DragDeadzone * this.GetViewerScale()) { m_DragObject = handle.transform; - OnGrabDragStart(handle, eventData, dragStart); + OnDragStarted(handle, eventData, dragStart); } if (m_DragObject) - OnGrabDragging(handle, eventData, dragStart); + OnDragging(handle, eventData, dragStart); } } - protected virtual void OnGrabDragStart(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) {} + protected virtual void OnDragStarted(BaseHandle handle, HandleEventData eventData, Vector3 dragStartPosition) + { + if (dragStart != null) + dragStart(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } - protected virtual void OnGrabDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) {} + protected virtual void OnDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStartPosition) + { + if (dragging != null) + dragging(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } protected virtual void OnDragEnded(BaseHandle handle, HandleEventData eventData) { m_DragObject = null; + + if (dragEnd != null) + dragEnd(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } + + protected virtual void OnHoverStart(BaseHandle handle, HandleEventData eventData) + { + if (hoverStart != null) + hoverStart(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } + + protected virtual void OnHoverEnd(BaseHandle handle, HandleEventData eventData) + { + if (hoverEnd != null) + hoverEnd(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } + + protected virtual void OnClick(BaseHandle handle, HandleEventData eventData) + { + if (click != null) + click(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); } protected virtual void OnMagnetizeEnded() {} diff --git a/Workspaces/Common/Scripts/FilterButtonUI.cs b/Workspaces/Common/Scripts/FilterButtonUI.cs index 734118f69..18739711a 100644 --- a/Workspaces/Common/Scripts/FilterButtonUI.cs +++ b/Workspaces/Common/Scripts/FilterButtonUI.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using UnityEditor.Experimental.EditorVR.Modules; using UnityEngine; @@ -6,6 +6,10 @@ using UnityEngine.UI; using Button = UnityEditor.Experimental.EditorVR.UI.Button; +#if INCLUDE_TEXT_MESH_PRO +using TMPro; +#endif + namespace UnityEditor.Experimental.EditorVR.Workspaces { sealed class FilterButtonUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IRayEnterHandler @@ -30,22 +34,29 @@ public Button button [SerializeField] Image m_TextPanel; - Transform m_InteractingRayOrigin; - - public Text text - { - get { return m_Text; } - } - +#if INCLUDE_TEXT_MESH_PRO + [SerializeField] + TextMeshProUGUI m_Text; +#else [SerializeField] Text m_Text; +#endif + + Transform m_InteractingRayOrigin; + +#if INCLUDE_TEXT_MESH_PRO + public TextMeshProUGUI text { get { return m_Text; } } +#else + public Text text { get; set; } +#endif public Color color { set { - m_Eye.color = value; m_Text.color = value; + if (m_Eye) + m_Eye.color = value; } } @@ -64,18 +75,21 @@ void OnDestroy() public void OnPointerEnter(PointerEventData eventData) { - var c = m_EyePanel.color; + var c = m_TextPanel.color; c.a = k_HoverAlpha; - m_EyePanel.color = c; m_TextPanel.color = c; + + if (m_EyePanel) + m_EyePanel.color = c; } public void OnPointerExit(PointerEventData eventData) { - var c = m_EyePanel.color; + var c = m_TextPanel.color; c.a = k_NormalAlpha; - m_EyePanel.color = c; m_TextPanel.color = c; + if (m_EyePanel) + m_EyePanel.color = c; } public void OnRayEnter(RayEventData eventData) diff --git a/Workspaces/Common/Scripts/FilterUI.cs b/Workspaces/Common/Scripts/FilterUI.cs index b7a6fbf00..4094de725 100644 --- a/Workspaces/Common/Scripts/FilterUI.cs +++ b/Workspaces/Common/Scripts/FilterUI.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; @@ -7,27 +7,29 @@ using UnityEngine; using UnityEngine.UI; +#if INCLUDE_TEXT_MESH_PRO +using TMPro; +#endif + namespace UnityEditor.Experimental.EditorVR.Workspaces { sealed class FilterUI : MonoBehaviour, IUsesStencilRef { const string k_AllText = "All"; - public Text summaryText - { - get { return m_SummaryText; } - } +#if INCLUDE_TEXT_MESH_PRO + [SerializeField] + TextMeshProUGUI m_SummaryText; + [SerializeField] + TextMeshProUGUI m_DescriptionText; +#else [SerializeField] Text m_SummaryText; - public Text descriptionText - { - get { return m_DescriptionText; } - } - [SerializeField] Text m_DescriptionText; +#endif [SerializeField] RectTransform m_ButtonList; @@ -81,11 +83,17 @@ public List filterList { // Clean up old buttons if (m_VisibilityButtons != null) + { foreach (var button in m_VisibilityButtons) + { ObjectUtils.Destroy(button.gameObject); + } + } m_FilterTypes = value; - m_FilterTypes.Insert(0, k_AllText); + + if (addDefaultOption) + m_FilterTypes.Insert(0, k_AllText); // Generate new button list m_VisibilityButtons = new FilterButtonUI[m_FilterTypes.Count]; @@ -94,8 +102,7 @@ public List filterList var button = ObjectUtils.Instantiate(m_ButtonPrefab, m_ButtonList, false).GetComponent(); m_VisibilityButtons[i] = button; - button.button.onClick.AddListener(() => { OnFilterClick(button); }); - + button.clicked += rayOrigin => { OnFilterClick(button); }; button.clicked += OnClicked; button.hovered += OnHovered; button.text.text = m_FilterTypes[i]; @@ -105,11 +112,23 @@ public List filterList public byte stencilRef { get; set; } +#if INCLUDE_TEXT_MESH_PRO + public TextMeshProUGUI summaryText { get { return m_SummaryText; } } + public TextMeshProUGUI descriptionText { get { return m_DescriptionText; } } +#else + public Text summaryText { get; set; } + public Text descriptionText { get; set; } +#endif + + public bool addDefaultOption { private get; set; } + public event Action buttonHovered; public event Action buttonClicked; + public event Action filterChanged; void Awake() { + addDefaultOption = true; m_HiddenButtonListYSpacing = -m_ButtonListGrid.cellSize.y; } @@ -118,8 +137,12 @@ void Start() m_BackgroundMaterial = MaterialUtils.GetMaterialClone(m_Background); m_BackgroundMaterial.SetInt("_StencilRef", stencilRef); - m_VisibilityButton.clicked += OnVisibilityButtonClicked; - m_VisibilityButton.hovered += OnHovered; + if (m_VisibilityButton) + { + m_VisibilityButton.clicked += OnVisibilityButtonClicked; + m_VisibilityButton.hovered += OnHovered; + } + m_SummaryButton.clicked += OnVisibilityButtonClicked; m_SummaryButton.hovered += OnHovered; } @@ -139,23 +162,21 @@ public void SetListVisibility(bool show) this.StopCoroutine(ref m_ShowButtonListCoroutine); m_ShowButtonListCoroutine = StartCoroutine(ShowButtonList()); } - else + else if (m_ButtonList.gameObject.activeSelf) { this.StopCoroutine(ref m_ShowUICoroutine); m_ShowUICoroutine = StartCoroutine(ShowUIContent()); this.StopCoroutine(ref m_HideButtonListCoroutine); m_HideButtonListCoroutine = StartCoroutine(HideButtonList()); - - OnClicked(null); } } - public void OnFilterClick(FilterButtonUI clickedButton) + void OnFilterClick(FilterButtonUI clickedButton) { for (int i = 0; i < m_VisibilityButtons.Length; i++) if (clickedButton == m_VisibilityButtons[i]) - m_SearchQuery = i == 0 ? string.Empty : m_FilterTypes[i]; + m_SearchQuery = i == 0 && addDefaultOption ? string.Empty : m_FilterTypes[i]; foreach (FilterButtonUI button in m_VisibilityButtons) { @@ -168,6 +189,7 @@ public void OnFilterClick(FilterButtonUI clickedButton) switch (clickedButton.text.text) { case k_AllText: + m_SummaryText.text = clickedButton.text.text; m_DescriptionText.text = "All objects are visible"; break; @@ -177,6 +199,9 @@ public void OnFilterClick(FilterButtonUI clickedButton) m_DescriptionText.text = "Only " + m_SummaryText.text + " are visible"; break; } + + if (filterChanged != null) + filterChanged(); } IEnumerator ShowUIContent() @@ -216,22 +241,23 @@ IEnumerator ShowButtonList() { m_ButtonList.gameObject.SetActive(true); - const float kTargetDuration = 0.5f; + const float targetDuration = 0.5f; + const float targetMinSpacing = 0.0015f; var currentAlpha = m_ButtonListCanvasGroup.alpha; var kTargetAlpha = 1f; var transitionAmount = 0f; var velocity = 0f; var currentDuration = 0f; - while (currentDuration < kTargetDuration) + while (currentDuration < targetDuration) { currentDuration += Time.deltaTime; - transitionAmount = MathUtilsExt.SmoothDamp(transitionAmount, 1f, ref velocity, kTargetDuration, Mathf.Infinity, Time.deltaTime); - m_ButtonListGrid.spacing = new Vector2(0f, Mathf.Lerp(m_HiddenButtonListYSpacing, 0f, transitionAmount)); + transitionAmount = MathUtilsExt.SmoothDamp(transitionAmount, 1f, ref velocity, targetDuration, Mathf.Infinity, Time.deltaTime); + m_ButtonListGrid.spacing = new Vector2(0f, Mathf.Lerp(m_HiddenButtonListYSpacing, targetMinSpacing, transitionAmount)); m_ButtonListCanvasGroup.alpha = Mathf.Lerp(currentAlpha, kTargetAlpha, transitionAmount); yield return null; } - m_ButtonListGrid.spacing = new Vector2(0f, 0f); + m_ButtonListGrid.spacing = Vector2.one * targetMinSpacing; m_ButtonListCanvasGroup.alpha = 1f; m_ShowButtonListCoroutine = null; } diff --git a/Workspaces/Common/Scripts/WorkspaceButton.cs b/Workspaces/Common/Scripts/WorkspaceButton.cs index 7d49ba4e4..cdb54456b 100644 --- a/Workspaces/Common/Scripts/WorkspaceButton.cs +++ b/Workspaces/Common/Scripts/WorkspaceButton.cs @@ -1,491 +1,494 @@ -#if UNITY_EDITOR -using System; -using System.Collections; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Helpers; -using UnityEditor.Experimental.EditorVR.Modules; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; -using UnityEngine.UI; - -namespace UnityEditor.Experimental.EditorVR.Workspaces -{ - sealed class WorkspaceButton : MonoBehaviour, IRayEnterHandler, IRayExitHandler, IUsesStencilRef - { - const float k_IconHighlightedLocalZOffset = -0.0015f; - const string k_MaterialAlphaProperty = "_Alpha"; - const string k_MaterialColorTopProperty = "_ColorTop"; - const string k_MaterialColorBottomProperty = "_ColorBottom"; - - public event Action clicked; - public event Action hovered; - - public bool autoHighlight - { - get { return m_AutoHighlight; } - set { m_AutoHighlight = value; } - } - - [SerializeField] - bool m_AutoHighlight = true; - - public Sprite iconSprite - { - set - { - m_IconSprite = value; - m_Icon.sprite = m_IconSprite; - } - } - - Sprite m_IconSprite; - - public Color customHighlightColor - { - get { return m_CustomHighlightColor; } - set { m_CustomHighlightColor = value; } - } - - [Header("Extras")] - [SerializeField] - Color m_CustomHighlightColor = UnityBrandColorScheme.light; - - public bool pressed - { - get { return m_Pressed; } - set - { - if (m_Highlighted && value != m_Pressed && value) // proceed only if value is true after previously being false - { - m_Pressed = value; - - this.StopCoroutine(ref m_IconHighlightCoroutine); - - m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsBeginHighlight(true)); - } - } - } - - bool m_Pressed; - - public bool highlighted - { - set - { - if (m_Highlighted == value) - return; - else - { - // Stop any existing icon highlight coroutines - this.StopCoroutine(ref m_IconHighlightCoroutine); - - m_Highlighted = value; - - // Stop any existing begin/end highlight coroutine - this.StopCoroutine(ref m_HighlightCoroutine); - - if (!gameObject.activeInHierarchy) - return; - - m_HighlightCoroutine = m_Highlighted ? StartCoroutine(BeginHighlight()) : StartCoroutine(EndHighlight()); - } - } - } - - bool m_Highlighted; - - public bool alternateIconVisible - { - set - { - if (m_AlternateIconSprite) // Only allow sprite swapping if an alternate sprite exists - m_Icon.sprite = value ? m_AlternateIconSprite : m_OriginalIconSprite; // If true, set the icon sprite back to the original sprite - } - get { return m_Icon.sprite == m_AlternateIconSprite; } - } - - [SerializeField] - Sprite m_AlternateIconSprite; - - public MeshRenderer buttonMeshRenderer { get { return m_ButtonMeshRenderer; } } - - [SerializeField] - MeshRenderer m_ButtonMeshRenderer; - - [SerializeField] - CanvasGroup m_CanvasGroup; - - [SerializeField] - Image m_Icon; - - [SerializeField] - Transform m_IconContainer; - - [SerializeField] - Button m_Button; - - [SerializeField] - bool m_SwapIconsOnClick = true; - - [SerializeField] - Graphic[] m_HighlightItems; - - [SerializeField] - bool m_GrayscaleGradient; - - [Header("Animated Reveal Settings")] - [SerializeField] - bool m_AnimatedReveal; - - [Tooltip("Default value is 0.25")] - [SerializeField] - [Range(0f, 2f)] - float m_DelayBeforeReveal = 0.25f; - - GradientPair m_OriginalGradientPair; - GradientPair m_HighlightGradientPair; - Vector3 m_IconDirection; - Material m_ButtonMaterial; - Material m_ButtonMaskMaterial; - Vector3 m_OriginalIconLocalPosition; - Vector3 m_HiddenLocalScale; - Vector3 m_IconHighlightedLocalPosition; - Vector3 m_IconPressedLocalPosition; - Vector3 m_IconLookDirection; - Color m_OriginalColor; - Sprite m_OriginalIconSprite; - float m_VisibleLocalZScale; - Transform m_InteractingRayOrigin; - - // The initial button reveal coroutines, before highlighting - Coroutine m_VisibilityCoroutine; - Coroutine m_ContentVisibilityCoroutine; - - // The already visible, highlight coroutines - Coroutine m_HighlightCoroutine; - Coroutine m_IconHighlightCoroutine; - - public Button button { get { return m_Button; } } - - public byte stencilRef { get; set; } - - public void InstantClearState() - { - this.StopCoroutine(ref m_IconHighlightCoroutine); - this.StopCoroutine(ref m_HighlightCoroutine); - - ResetColors(); - m_InteractingRayOrigin = null; - } - - public void SetMaterialColors(GradientPair gradientPair) - { - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, gradientPair.a); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, gradientPair.b); - } - - public void ResetColors() - { - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, m_OriginalGradientPair.a); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, m_OriginalGradientPair.b); - } - - void Awake() - { - m_OriginalColor = m_Icon.color; - m_ButtonMaterial = Instantiate(m_ButtonMeshRenderer.sharedMaterials[0]); - m_ButtonMaskMaterial = Instantiate(m_ButtonMeshRenderer.sharedMaterials[1]); - m_ButtonMeshRenderer.materials = new Material[] { m_ButtonMaterial, m_ButtonMaskMaterial }; - m_OriginalGradientPair = new GradientPair(m_ButtonMaterial.GetColor(k_MaterialColorTopProperty), m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty)); - m_HiddenLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, 0f); - m_VisibleLocalZScale = transform.localScale.z; - - m_OriginalIconLocalPosition = m_IconContainer.localPosition; - m_IconHighlightedLocalPosition = m_OriginalIconLocalPosition + Vector3.forward * k_IconHighlightedLocalZOffset; - m_IconPressedLocalPosition = m_OriginalIconLocalPosition + Vector3.back * k_IconHighlightedLocalZOffset; - - m_HighlightGradientPair = m_GrayscaleGradient ? UnityBrandColorScheme.grayscaleSessionGradient : UnityBrandColorScheme.sessionGradient; - - m_OriginalIconSprite = m_Icon.sprite; - - if (m_Button) - { - // Hookup button OnClick event if there is an alternate icon sprite set - if (m_SwapIconsOnClick && m_AlternateIconSprite) - m_Button.onClick.AddListener(SwapIconSprite); - - m_Button.onClick.AddListener(OnButtonClicked); - } - } - - void Start() - { - const string kStencilRef = "_StencilRef"; - m_ButtonMaterial.SetInt(kStencilRef, stencilRef); - m_ButtonMaskMaterial.SetInt(kStencilRef, stencilRef); - } - - void OnEnable() - { - if (m_AnimatedReveal) - { - this.StopCoroutine(ref m_VisibilityCoroutine); - m_VisibilityCoroutine = StartCoroutine(AnimateShow()); - } - } - - void OnDestroy() - { - ObjectUtils.Destroy(m_ButtonMaterial); - ObjectUtils.Destroy(m_ButtonMaskMaterial); - - if (m_Button) - m_Button.onClick.RemoveAllListeners(); - } - - void OnDisable() - { - InstantClearState(); - } - - IEnumerator AnimateShow() - { - m_CanvasGroup.interactable = false; - m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, 0f); - - this.StopCoroutine(ref m_ContentVisibilityCoroutine); - m_ContentVisibilityCoroutine = StartCoroutine(ShowContent()); - - const float kInitialRevealDuration = 0.5f; - const float kScaleRevealDuration = 0.25f; - var delay = 0f; - var scale = m_HiddenLocalScale; - var smoothVelocity = Vector3.zero; - var hiddenLocalYScale = new Vector3(m_HiddenLocalScale.x, 0f, 0f); - var currentDuration = 0f; - var totalDuration = m_DelayBeforeReveal + kInitialRevealDuration + kScaleRevealDuration; - var visibleLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale); - while (currentDuration < totalDuration) - { - currentDuration += Time.deltaTime; - transform.localScale = scale; - m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, scale.z); - - // Perform initial delay - while (delay < m_DelayBeforeReveal) - { - delay += Time.deltaTime; - yield return null; - } - - // Perform the button vertical button reveal, after the initial wait - while (delay < kInitialRevealDuration + m_DelayBeforeReveal) - { - delay += Time.deltaTime; - var shapedDelayLerp = delay / m_DelayBeforeReveal; - transform.localScale = Vector3.Lerp(hiddenLocalYScale, m_HiddenLocalScale, shapedDelayLerp * shapedDelayLerp); - yield return null; - } - - // Perform the button depth reveal - scale = MathUtilsExt.SmoothDamp(scale, visibleLocalScale, ref smoothVelocity, kScaleRevealDuration, Mathf.Infinity, Time.deltaTime); - yield return null; - } - - m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, 1); - m_VisibilityCoroutine = null; - } - - IEnumerator ShowContent() - { - m_CanvasGroup.interactable = true; - - const float kTargetAlpha = 1f; - const float kRevealDuration = 0.4f; - const float kInitialDelayLengthenMultipler = 5f; // used to scale up the initial delay based on the m_InitialDelay value - var delay = 0f; - var targetDelay = Mathf.Clamp(m_DelayBeforeReveal * kInitialDelayLengthenMultipler, 0f, 2.5f); // scale the target delay, with a maximum clamp - var alpha = 0f; - var opacitySmoothVelocity = 1f; - var currentDuration = 0f; - var targetDuration = targetDelay + kRevealDuration; - while (currentDuration < targetDuration) - { - currentDuration += Time.deltaTime; - m_CanvasGroup.alpha = alpha; - - while (delay < targetDelay) - { - delay += Time.deltaTime; - yield return null; - } - - alpha = MathUtilsExt.SmoothDamp(alpha, kTargetAlpha, ref opacitySmoothVelocity, targetDuration, Mathf.Infinity, Time.deltaTime); - yield return null; - } - - m_CanvasGroup.alpha = 1; - m_ContentVisibilityCoroutine = null; - } - - IEnumerator BeginHighlight() - { - this.StopCoroutine(ref m_IconHighlightCoroutine); - m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsBeginHighlight()); - - const float kTargetTransitionAmount = 1f; - var transitionAmount = Time.deltaTime; - var topColor = Color.clear; - var bottomColor = Color.clear; - var currentTopColor = m_ButtonMaterial.GetColor(k_MaterialColorTopProperty); - var currentBottomColor = m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty); - var topHighlightColor = m_HighlightGradientPair.a; - var bottomHighlightColor = m_HighlightGradientPair.b; - var currentLocalScale = transform.localScale; - var highlightedLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale * 2); - var transitionAmountMultiplier = 5; - while (transitionAmount < kTargetTransitionAmount) - { - transitionAmount += Time.deltaTime * transitionAmountMultiplier; - var shapedTransitionAmount = Mathf.Pow(transitionAmount, 2); - transform.localScale = Vector3.Lerp(currentLocalScale, highlightedLocalScale, shapedTransitionAmount); - - topColor = Color.Lerp(currentTopColor, topHighlightColor, shapedTransitionAmount); - bottomColor = Color.Lerp(currentBottomColor, bottomHighlightColor, shapedTransitionAmount); - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topColor); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomColor); - yield return null; - } - - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topHighlightColor); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomHighlightColor); - transform.localScale = highlightedLocalScale; - m_HighlightCoroutine = null; - } - - IEnumerator EndHighlight() - { - this.StopCoroutine(ref m_IconHighlightCoroutine); - m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsEndHighlight()); - - const float kTargetTransitionAmount = 1f; - var transitionAmount = Time.deltaTime; - var topColor = Color.clear; - var bottomColor = Color.clear; - var currentTopColor = m_ButtonMaterial.GetColor(k_MaterialColorTopProperty); - var currentBottomColor = m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty); - var topOriginalColor = m_OriginalGradientPair.a; - var bottomOriginalColor = m_OriginalGradientPair.b; - var currentLocalScale = transform.localScale; - var targetScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale); - while (transitionAmount < kTargetTransitionAmount) - { - transitionAmount += Time.deltaTime * 3; - var shapedTransitionAmount = Mathf.Pow(transitionAmount, 2); - topColor = Color.Lerp(currentTopColor, topOriginalColor, shapedTransitionAmount); - bottomColor = Color.Lerp(currentBottomColor, bottomOriginalColor, shapedTransitionAmount); - - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topColor); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomColor); - - transform.localScale = Vector3.Lerp(currentLocalScale, targetScale, shapedTransitionAmount); - yield return null; - } - - m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topOriginalColor); - m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomOriginalColor); - transform.localScale = targetScale; - m_HighlightCoroutine = null; - } - - IEnumerator IconContainerContentsBeginHighlight(bool pressed = false) - { - var currentPosition = m_IconContainer.localPosition; - var targetPosition = pressed == false ? m_IconHighlightedLocalPosition : m_IconPressedLocalPosition; // forward for highlight, backward for press - var transitionAmount = Time.deltaTime; - var transitionAddMultiplier = !pressed ? 4 : 7; // Faster transition in for highlight; slower for pressed highlight - while (transitionAmount < 1) - { - transitionAmount += Time.deltaTime * transitionAddMultiplier; - - foreach (var graphic in m_HighlightItems) - { - if (graphic) - graphic.color = Color.Lerp(m_OriginalColor, customHighlightColor, transitionAmount); - } - - m_IconContainer.localPosition = Vector3.Lerp(currentPosition, targetPosition, transitionAmount); - yield return null; - } - - foreach (var graphic in m_HighlightItems) - { - if (graphic) - graphic.color = m_CustomHighlightColor; - } - - m_IconContainer.localPosition = targetPosition; - m_IconHighlightCoroutine = null; - } - - IEnumerator IconContainerContentsEndHighlight() - { - var currentPosition = m_IconContainer.localPosition; - var transitionAmount = 1f; - const float kTransitionSubtractMultiplier = 5f; - while (transitionAmount > 0) - { - transitionAmount -= Time.deltaTime * kTransitionSubtractMultiplier; - - foreach (var graphic in m_HighlightItems) - { - if (graphic != null) - graphic.color = Color.Lerp(m_OriginalColor, customHighlightColor, transitionAmount); - } - - m_IconContainer.localPosition = Vector3.Lerp(m_OriginalIconLocalPosition, currentPosition, transitionAmount); - yield return null; - } - - foreach (var graphic in m_HighlightItems) - { - if (graphic != null) - graphic.color = m_OriginalColor; - } - - m_IconContainer.localPosition = m_OriginalIconLocalPosition; - m_IconHighlightCoroutine = null; - } - - public void OnRayEnter(RayEventData eventData) - { - m_InteractingRayOrigin = eventData.rayOrigin; - if (hovered != null) - hovered(m_InteractingRayOrigin); - - if (autoHighlight) - highlighted = true; - } - - public void OnRayExit(RayEventData eventData) - { - m_InteractingRayOrigin = null; - - if (autoHighlight) - highlighted = false; - } - - void SwapIconSprite() - { - // Alternate between the main icon and the alternate icon when the button is clicked - alternateIconVisible = !alternateIconVisible; - } - - void OnButtonClicked() - { - if (clicked != null) - clicked(m_InteractingRayOrigin); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Helpers; +using UnityEditor.Experimental.EditorVR.Modules; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + sealed class WorkspaceButton : MonoBehaviour, IRayEnterHandler, IRayExitHandler, IUsesStencilRef + { + const float k_IconHighlightedLocalZOffset = -0.0015f; + const string k_MaterialAlphaProperty = "_Alpha"; + const string k_MaterialColorTopProperty = "_ColorTop"; + const string k_MaterialColorBottomProperty = "_ColorBottom"; + + public event Action clicked; + public event Action hovered; + + public bool autoHighlight + { + get { return m_AutoHighlight; } + set { m_AutoHighlight = value; } + } + + [SerializeField] + bool m_AutoHighlight = true; + + public Sprite iconSprite + { + set + { + m_IconSprite = value; + m_Icon.sprite = m_IconSprite; + } + } + + Sprite m_IconSprite; + + public Color customHighlightColor + { + get { return m_CustomHighlightColor; } + set { m_CustomHighlightColor = value; } + } + + [Header("Extras")] + [SerializeField] + Color m_CustomHighlightColor = UnityBrandColorScheme.light; + + public bool pressed + { + get { return m_Pressed; } + set + { + if (m_Highlighted && value != m_Pressed && value) // proceed only if value is true after previously being false + { + m_Pressed = value; + + this.StopCoroutine(ref m_IconHighlightCoroutine); + + m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsBeginHighlight(true)); + } + } + } + + bool m_Pressed; + + public bool highlighted + { + set + { + if (m_Highlighted == value) + return; + else + { + // Stop any existing icon highlight coroutines + this.StopCoroutine(ref m_IconHighlightCoroutine); + + m_Highlighted = value; + + // Stop any existing begin/end highlight coroutine + this.StopCoroutine(ref m_HighlightCoroutine); + + if (!gameObject.activeInHierarchy) + return; + + m_HighlightCoroutine = m_Highlighted ? StartCoroutine(BeginHighlight()) : StartCoroutine(EndHighlight()); + } + } + } + + bool m_Highlighted; + + public bool alternateIconVisible + { + set + { + if (m_AlternateIconSprite) // Only allow sprite swapping if an alternate sprite exists + m_Icon.sprite = value ? m_AlternateIconSprite : m_OriginalIconSprite; // If true, set the icon sprite back to the original sprite + } + get { return m_Icon.sprite == m_AlternateIconSprite; } + } + + [SerializeField] + Sprite m_AlternateIconSprite; + + public MeshRenderer buttonMeshRenderer { get { return m_ButtonMeshRenderer; } } + + [SerializeField] + MeshRenderer m_ButtonMeshRenderer; + + [SerializeField] + CanvasGroup m_CanvasGroup; + + [SerializeField] + Image m_Icon; + + [SerializeField] + Transform m_IconContainer; + + [SerializeField] + Button m_Button; + + [SerializeField] + bool m_SwapIconsOnClick = true; + + [SerializeField] + Graphic[] m_HighlightItems; + + [SerializeField] + bool m_GrayscaleGradient; + + [Header("Animated Reveal Settings")] + [SerializeField] + bool m_AnimatedReveal; + + [Tooltip("Default value is 0.25")] + [SerializeField] + [Range(0f, 2f)] + float m_DelayBeforeReveal = 0.25f; + + GradientPair m_OriginalGradientPair; + GradientPair m_HighlightGradientPair; + Vector3 m_IconDirection; + Material m_ButtonMaterial; + Material m_ButtonMaskMaterial; + Vector3 m_OriginalIconLocalPosition; + Vector3 m_HiddenLocalScale; + Vector3 m_IconHighlightedLocalPosition; + Vector3 m_IconPressedLocalPosition; + Vector3 m_IconLookDirection; + Color m_OriginalColor; + Sprite m_OriginalIconSprite; + float m_VisibleLocalZScale; + Transform m_InteractingRayOrigin; + + // The initial button reveal coroutines, before highlighting + Coroutine m_VisibilityCoroutine; + Coroutine m_ContentVisibilityCoroutine; + + // The already visible, highlight coroutines + Coroutine m_HighlightCoroutine; + Coroutine m_IconHighlightCoroutine; + + public Button button { get { return m_Button; } } + + public byte stencilRef { get; set; } + + public void InstantClearState() + { + this.StopCoroutine(ref m_IconHighlightCoroutine); + this.StopCoroutine(ref m_HighlightCoroutine); + + ResetColors(); + m_InteractingRayOrigin = null; + } + + public void SetMaterialColors(GradientPair gradientPair) + { + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, gradientPair.a); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, gradientPair.b); + } + + public void ResetColors() + { + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, m_OriginalGradientPair.a); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, m_OriginalGradientPair.b); + } + + void Awake() + { + m_ButtonMaterial = Instantiate(m_ButtonMeshRenderer.sharedMaterials[0]); + m_ButtonMaskMaterial = Instantiate(m_ButtonMeshRenderer.sharedMaterials[1]); + m_ButtonMeshRenderer.materials = new Material[] { m_ButtonMaterial, m_ButtonMaskMaterial }; + m_OriginalGradientPair = new GradientPair(m_ButtonMaterial.GetColor(k_MaterialColorTopProperty), m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty)); + m_HiddenLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, 0f); + m_VisibleLocalZScale = transform.localScale.z; + + if (m_Icon) + { + m_OriginalColor = m_Icon.color; + m_OriginalIconSprite = m_Icon.sprite; + } + + m_OriginalIconLocalPosition = m_IconContainer.localPosition; + m_IconHighlightedLocalPosition = m_OriginalIconLocalPosition + Vector3.forward * k_IconHighlightedLocalZOffset; + m_IconPressedLocalPosition = m_OriginalIconLocalPosition + Vector3.back * k_IconHighlightedLocalZOffset; + + m_HighlightGradientPair = m_GrayscaleGradient ? UnityBrandColorScheme.grayscaleSessionGradient : UnityBrandColorScheme.sessionGradient; + + if (m_Button) + { + // Hookup button OnClick event if there is an alternate icon sprite set + if (m_SwapIconsOnClick && m_AlternateIconSprite) + m_Button.onClick.AddListener(SwapIconSprite); + + m_Button.onClick.AddListener(OnButtonClicked); + } + } + + void Start() + { + const string kStencilRef = "_StencilRef"; + m_ButtonMaterial.SetInt(kStencilRef, stencilRef); + m_ButtonMaskMaterial.SetInt(kStencilRef, stencilRef); + } + + void OnEnable() + { + if (m_AnimatedReveal) + { + this.StopCoroutine(ref m_VisibilityCoroutine); + m_VisibilityCoroutine = StartCoroutine(AnimateShow()); + } + } + + void OnDestroy() + { + ObjectUtils.Destroy(m_ButtonMaterial); + ObjectUtils.Destroy(m_ButtonMaskMaterial); + + if (m_Button) + m_Button.onClick.RemoveAllListeners(); + } + + void OnDisable() + { + InstantClearState(); + } + + IEnumerator AnimateShow() + { + m_CanvasGroup.interactable = false; + m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, 0f); + + this.StopCoroutine(ref m_ContentVisibilityCoroutine); + m_ContentVisibilityCoroutine = StartCoroutine(ShowContent()); + + const float kInitialRevealDuration = 0.5f; + const float kScaleRevealDuration = 0.25f; + var delay = 0f; + var scale = m_HiddenLocalScale; + var smoothVelocity = Vector3.zero; + var hiddenLocalYScale = new Vector3(m_HiddenLocalScale.x, 0f, 0f); + var currentDuration = 0f; + var totalDuration = m_DelayBeforeReveal + kInitialRevealDuration + kScaleRevealDuration; + var visibleLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale); + while (currentDuration < totalDuration) + { + currentDuration += Time.deltaTime; + transform.localScale = scale; + m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, scale.z); + + // Perform initial delay + while (delay < m_DelayBeforeReveal) + { + delay += Time.deltaTime; + yield return null; + } + + // Perform the button vertical button reveal, after the initial wait + while (delay < kInitialRevealDuration + m_DelayBeforeReveal) + { + delay += Time.deltaTime; + var shapedDelayLerp = delay / m_DelayBeforeReveal; + transform.localScale = Vector3.Lerp(hiddenLocalYScale, m_HiddenLocalScale, shapedDelayLerp * shapedDelayLerp); + yield return null; + } + + // Perform the button depth reveal + scale = MathUtilsExt.SmoothDamp(scale, visibleLocalScale, ref smoothVelocity, kScaleRevealDuration, Mathf.Infinity, Time.deltaTime); + yield return null; + } + + m_ButtonMaterial.SetFloat(k_MaterialAlphaProperty, 1); + m_VisibilityCoroutine = null; + } + + IEnumerator ShowContent() + { + m_CanvasGroup.interactable = true; + + const float kTargetAlpha = 1f; + const float kRevealDuration = 0.4f; + const float kInitialDelayLengthenMultipler = 5f; // used to scale up the initial delay based on the m_InitialDelay value + var delay = 0f; + var targetDelay = Mathf.Clamp(m_DelayBeforeReveal * kInitialDelayLengthenMultipler, 0f, 2.5f); // scale the target delay, with a maximum clamp + var alpha = 0f; + var opacitySmoothVelocity = 1f; + var currentDuration = 0f; + var targetDuration = targetDelay + kRevealDuration; + while (currentDuration < targetDuration) + { + currentDuration += Time.deltaTime; + m_CanvasGroup.alpha = alpha; + + while (delay < targetDelay) + { + delay += Time.deltaTime; + yield return null; + } + + alpha = MathUtilsExt.SmoothDamp(alpha, kTargetAlpha, ref opacitySmoothVelocity, targetDuration, Mathf.Infinity, Time.deltaTime); + yield return null; + } + + m_CanvasGroup.alpha = 1; + m_ContentVisibilityCoroutine = null; + } + + IEnumerator BeginHighlight() + { + this.StopCoroutine(ref m_IconHighlightCoroutine); + m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsBeginHighlight()); + + const float kTargetTransitionAmount = 1f; + var transitionAmount = Time.deltaTime; + var topColor = Color.clear; + var bottomColor = Color.clear; + var currentTopColor = m_ButtonMaterial.GetColor(k_MaterialColorTopProperty); + var currentBottomColor = m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty); + var topHighlightColor = m_HighlightGradientPair.a; + var bottomHighlightColor = m_HighlightGradientPair.b; + var currentLocalScale = transform.localScale; + var highlightedLocalScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale * 2); + var transitionAmountMultiplier = 5; + while (transitionAmount < kTargetTransitionAmount) + { + transitionAmount += Time.deltaTime * transitionAmountMultiplier; + var shapedTransitionAmount = Mathf.Pow(transitionAmount, 2); + transform.localScale = Vector3.Lerp(currentLocalScale, highlightedLocalScale, shapedTransitionAmount); + + topColor = Color.Lerp(currentTopColor, topHighlightColor, shapedTransitionAmount); + bottomColor = Color.Lerp(currentBottomColor, bottomHighlightColor, shapedTransitionAmount); + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topColor); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomColor); + yield return null; + } + + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topHighlightColor); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomHighlightColor); + transform.localScale = highlightedLocalScale; + m_HighlightCoroutine = null; + } + + IEnumerator EndHighlight() + { + this.StopCoroutine(ref m_IconHighlightCoroutine); + m_IconHighlightCoroutine = StartCoroutine(IconContainerContentsEndHighlight()); + + const float kTargetTransitionAmount = 1f; + var transitionAmount = Time.deltaTime; + var topColor = Color.clear; + var bottomColor = Color.clear; + var currentTopColor = m_ButtonMaterial.GetColor(k_MaterialColorTopProperty); + var currentBottomColor = m_ButtonMaterial.GetColor(k_MaterialColorBottomProperty); + var topOriginalColor = m_OriginalGradientPair.a; + var bottomOriginalColor = m_OriginalGradientPair.b; + var currentLocalScale = transform.localScale; + var targetScale = new Vector3(transform.localScale.x, transform.localScale.y, m_VisibleLocalZScale); + while (transitionAmount < kTargetTransitionAmount) + { + transitionAmount += Time.deltaTime * 3; + var shapedTransitionAmount = Mathf.Pow(transitionAmount, 2); + topColor = Color.Lerp(currentTopColor, topOriginalColor, shapedTransitionAmount); + bottomColor = Color.Lerp(currentBottomColor, bottomOriginalColor, shapedTransitionAmount); + + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topColor); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomColor); + + transform.localScale = Vector3.Lerp(currentLocalScale, targetScale, shapedTransitionAmount); + yield return null; + } + + m_ButtonMaterial.SetColor(k_MaterialColorTopProperty, topOriginalColor); + m_ButtonMaterial.SetColor(k_MaterialColorBottomProperty, bottomOriginalColor); + transform.localScale = targetScale; + m_HighlightCoroutine = null; + } + + IEnumerator IconContainerContentsBeginHighlight(bool pressed = false) + { + var currentPosition = m_IconContainer.localPosition; + var targetPosition = pressed == false ? m_IconHighlightedLocalPosition : m_IconPressedLocalPosition; // forward for highlight, backward for press + var transitionAmount = Time.deltaTime; + var transitionAddMultiplier = !pressed ? 4 : 7; // Faster transition in for highlight; slower for pressed highlight + while (transitionAmount < 1) + { + transitionAmount += Time.deltaTime * transitionAddMultiplier; + + foreach (var graphic in m_HighlightItems) + { + if (graphic) + graphic.color = Color.Lerp(m_OriginalColor, customHighlightColor, transitionAmount); + } + + m_IconContainer.localPosition = Vector3.Lerp(currentPosition, targetPosition, transitionAmount); + yield return null; + } + + foreach (var graphic in m_HighlightItems) + { + if (graphic) + graphic.color = m_CustomHighlightColor; + } + + m_IconContainer.localPosition = targetPosition; + m_IconHighlightCoroutine = null; + } + + IEnumerator IconContainerContentsEndHighlight() + { + var currentPosition = m_IconContainer.localPosition; + var transitionAmount = 1f; + const float kTransitionSubtractMultiplier = 5f; + while (transitionAmount > 0) + { + transitionAmount -= Time.deltaTime * kTransitionSubtractMultiplier; + + foreach (var graphic in m_HighlightItems) + { + if (graphic != null) + graphic.color = Color.Lerp(m_OriginalColor, customHighlightColor, transitionAmount); + } + + m_IconContainer.localPosition = Vector3.Lerp(m_OriginalIconLocalPosition, currentPosition, transitionAmount); + yield return null; + } + + foreach (var graphic in m_HighlightItems) + { + if (graphic != null) + graphic.color = m_OriginalColor; + } + + m_IconContainer.localPosition = m_OriginalIconLocalPosition; + m_IconHighlightCoroutine = null; + } + + public void OnRayEnter(RayEventData eventData) + { + m_InteractingRayOrigin = eventData.rayOrigin; + if (hovered != null) + hovered(m_InteractingRayOrigin); + + if (autoHighlight) + highlighted = true; + } + + public void OnRayExit(RayEventData eventData) + { + m_InteractingRayOrigin = null; + + if (autoHighlight) + highlighted = false; + } + + void SwapIconSprite() + { + // Alternate between the main icon and the alternate icon when the button is clicked + alternateIconVisible = !alternateIconVisible; + } + + void OnButtonClicked() + { + if (clicked != null) + clicked(m_InteractingRayOrigin); + } + } +} +#endif diff --git a/Workspaces/HierarchyWorkspace/HierarchyWorkspace.cs b/Workspaces/HierarchyWorkspace/HierarchyWorkspace.cs index a300d8c85..2369e3eba 100644 --- a/Workspaces/HierarchyWorkspace/HierarchyWorkspace.cs +++ b/Workspaces/HierarchyWorkspace/HierarchyWorkspace.cs @@ -1,249 +1,249 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Extensions; -using UnityEditor.Experimental.EditorVR.Handles; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Workspaces -{ - [MainMenuItem("Hierarchy", "Workspaces", "View all GameObjects in your scene(s)")] - class HierarchyWorkspace : Workspace, IFilterUI, IUsesHierarchyData, ISelectionChanged, IMoveCameraRig - { - protected const string k_Locked = "Locked"; - - [SerializeField] - GameObject m_ContentPrefab; - - [SerializeField] - GameObject m_FilterPrefab; - - [SerializeField] - GameObject m_FocusPrefab; - - [SerializeField] - GameObject m_CreateEmptyPrefab; - - HierarchyUI m_HierarchyUI; - protected FilterUI m_FilterUI; - - HierarchyData m_SelectedRow; - - bool m_Scrolling; - - public List hierarchyData - { - set - { - m_HierarchyData = value; - - if (m_HierarchyUI) - m_HierarchyUI.listView.data = value; - } - } - - protected List m_HierarchyData; - - public virtual List filterList - { - set - { - m_FilterList = value; - m_FilterList.Sort(); - m_FilterList.Insert(0, k_Locked); - - if (m_FilterUI) - m_FilterUI.filterList = value; - } - } - - protected List m_FilterList; - - public virtual string searchQuery { get { return m_FilterUI.searchQuery; } } - - public override void Setup() - { - // Initial bounds must be set before the base.Setup() is called - minBounds = new Vector3(0.522f, MinBounds.y, 0.5f); - m_CustomStartingBounds = minBounds; - - base.Setup(); - - var contentPrefab = ObjectUtils.Instantiate(m_ContentPrefab, m_WorkspaceUI.sceneContainer, false); - m_HierarchyUI = contentPrefab.GetComponent(); - m_HierarchyUI.listView.lockedQueryString = k_Locked; - hierarchyData = m_HierarchyData; - - if (m_FilterPrefab) - { - m_FilterUI = ObjectUtils.Instantiate(m_FilterPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); - foreach (var mb in m_FilterUI.GetComponentsInChildren()) - { - this.ConnectInterfaces(mb); - } - m_FilterUI.filterList = m_FilterList; - } - - if (m_FocusPrefab) - { - var focusUI = ObjectUtils.Instantiate(m_FocusPrefab, m_WorkspaceUI.frontPanel, false); - foreach (var mb in focusUI.GetComponentsInChildren()) - { - this.ConnectInterfaces(mb); - } - var button = focusUI.GetComponentInChildren(true); - button.clicked += FocusSelection; - button.hovered += OnButtonHovered; - } - - if (m_CreateEmptyPrefab) - { - var createEmptyUI = ObjectUtils.Instantiate(m_CreateEmptyPrefab, m_WorkspaceUI.frontPanel, false); - foreach (var mb in createEmptyUI.GetComponentsInChildren()) - { - this.ConnectInterfaces(mb); - } - var button = createEmptyUI.GetComponentInChildren(true); - button.clicked += CreateEmptyGameObject; - button.clicked += OnButtonClicked; - button.hovered += OnButtonHovered; - } - - var listView = m_HierarchyUI.listView; - listView.selectRow = SelectRow; - listView.matchesFilter = this.MatchesFilter; - listView.getSearchQuery = () => searchQuery; - this.ConnectInterfaces(listView); - - var scrollHandle = m_HierarchyUI.scrollHandle; - scrollHandle.dragStarted += OnScrollDragStarted; - scrollHandle.dragging += OnScrollDragging; - scrollHandle.dragEnded += OnScrollDragEnded; - scrollHandle.hoverStarted += OnScrollHoverStarted; - scrollHandle.hoverEnded += OnScrollHoverEnded; - - contentBounds = new Bounds(Vector3.zero, m_CustomStartingBounds.Value); - - var scrollHandleTransform = m_HierarchyUI.scrollHandle.transform; - scrollHandleTransform.SetParent(m_WorkspaceUI.topFaceContainer); - scrollHandleTransform.localScale = new Vector3(1.03f, 0.02f, 1.02f); // Extra space for scrolling - scrollHandleTransform.localPosition = new Vector3(0f, -0.015f, 0f); // Offset from content for collision purposes - - m_FilterUI.buttonClicked += OnButtonClicked; - m_FilterUI.buttonHovered += OnButtonHovered; - - // Propagate initial bounds - OnBoundsChanged(); - } - - protected override void OnDestroy() - { - m_FilterUI.buttonClicked -= OnButtonClicked; - m_FilterUI.buttonHovered -= OnButtonHovered; - - base.OnDestroy(); - } - - protected override void OnBoundsChanged() - { - var size = contentBounds.size; - var listView = m_HierarchyUI.listView; - size.y = float.MaxValue; // Add height for dropdowns - size.x -= FaceMargin * 2; // Shrink the content width, so that there is space allowed to grab and scroll - size.z -= FaceMargin * 2; // Reduce the height of the inspector contents as to fit within the bounds of the workspace - listView.size = size; - } - - static void SelectRow(int index) - { - var gameObject = EditorUtility.InstanceIDToObject(index) as GameObject; - if (gameObject && Selection.activeGameObject != gameObject) - Selection.activeGameObject = gameObject; - else - Selection.activeGameObject = null; - } - - void OnScrollDragStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_Scrolling = true; - - m_WorkspaceUI.topHighlight.visible = true; - m_WorkspaceUI.amplifyTopHighlight = false; - - m_HierarchyUI.listView.OnBeginScrolling(); - } - - void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_HierarchyUI.listView.scrollOffset -= Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); - } - - void OnScrollDragEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_Scrolling = false; - - m_WorkspaceUI.topHighlight.visible = false; - - m_HierarchyUI.listView.OnScrollEnded(); - } - - void OnScrollHoverStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - if (!m_Scrolling) - { - m_WorkspaceUI.topHighlight.visible = true; - m_WorkspaceUI.amplifyTopHighlight = true; - } - } - - void OnScrollHoverEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - if (!m_Scrolling) - { - m_WorkspaceUI.topHighlight.visible = false; - m_WorkspaceUI.amplifyTopHighlight = false; - } - } - - public void OnSelectionChanged() - { - m_HierarchyUI.listView.SelectRow(Selection.activeInstanceID); - } - - void FocusSelection(Transform rayOrigin) - { - if (Selection.gameObjects.Length == 0) - return; - - var mainCamera = CameraUtils.GetMainCamera().transform; - var bounds = ObjectUtils.GetBounds(Selection.transforms); - - var size = bounds.size; - size.y = 0; - var maxSize = size.MaxComponent(); - - const float kExtraDistance = 0.25f; // Add some extra distance so selection isn't in your face - maxSize += kExtraDistance; - - var viewDirection = mainCamera.transform.forward; - viewDirection.y = 0; - viewDirection.Normalize(); - - var cameraDiff = mainCamera.position - CameraUtils.GetCameraRig().position; - cameraDiff.y = 0; - - this.MoveCameraRig(bounds.center - cameraDiff - viewDirection * maxSize); - - OnButtonClicked(rayOrigin); - } - - static void CreateEmptyGameObject(Transform rayOrigin) - { - var camera = CameraUtils.GetMainCamera().transform; - var go = new GameObject(); - go.transform.position = camera.position + camera.forward; - Selection.activeGameObject = go; - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + [MainMenuItem("Hierarchy", "Workspaces", "View all GameObjects in your scene(s)")] + class HierarchyWorkspace : Workspace, IFilterUI, IUsesHierarchyData, ISelectionChanged, IMoveCameraRig + { + protected const string k_Locked = "Locked"; + + [SerializeField] + GameObject m_ContentPrefab; + + [SerializeField] + GameObject m_FilterPrefab; + + [SerializeField] + GameObject m_FocusPrefab; + + [SerializeField] + GameObject m_CreateEmptyPrefab; + + HierarchyUI m_HierarchyUI; + protected FilterUI m_FilterUI; + + HierarchyData m_SelectedRow; + + bool m_Scrolling; + + public List hierarchyData + { + set + { + m_HierarchyData = value; + + if (m_HierarchyUI) + m_HierarchyUI.listView.data = value; + } + } + + protected List m_HierarchyData; + + public virtual List filterList + { + set + { + m_FilterList = value; + m_FilterList.Sort(); + m_FilterList.Insert(0, k_Locked); + + if (m_FilterUI) + m_FilterUI.filterList = value; + } + } + + protected List m_FilterList; + + public virtual string searchQuery { get { return m_FilterUI.searchQuery; } } + + public override void Setup() + { + // Initial bounds must be set before the base.Setup() is called + minBounds = new Vector3(0.522f, MinBounds.y, 0.5f); + m_CustomStartingBounds = minBounds; + + base.Setup(); + + var contentPrefab = ObjectUtils.Instantiate(m_ContentPrefab, m_WorkspaceUI.sceneContainer, false); + m_HierarchyUI = contentPrefab.GetComponent(); + m_HierarchyUI.listView.lockedQueryString = k_Locked; + hierarchyData = m_HierarchyData; + + if (m_FilterPrefab) + { + m_FilterUI = ObjectUtils.Instantiate(m_FilterPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); + foreach (var mb in m_FilterUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + m_FilterUI.filterList = m_FilterList; + } + + if (m_FocusPrefab) + { + var focusUI = ObjectUtils.Instantiate(m_FocusPrefab, m_WorkspaceUI.frontPanel, false); + foreach (var mb in focusUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + var button = focusUI.GetComponentInChildren(true); + button.clicked += FocusSelection; + button.hovered += OnButtonHovered; + } + + if (m_CreateEmptyPrefab) + { + var createEmptyUI = ObjectUtils.Instantiate(m_CreateEmptyPrefab, m_WorkspaceUI.frontPanel, false); + foreach (var mb in createEmptyUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + var button = createEmptyUI.GetComponentInChildren(true); + button.clicked += CreateEmptyGameObject; + button.clicked += OnButtonClicked; + button.hovered += OnButtonHovered; + } + + var listView = m_HierarchyUI.listView; + listView.selectRow = SelectRow; + listView.matchesFilter = this.MatchesFilter; + listView.getSearchQuery = () => searchQuery; + this.ConnectInterfaces(listView); + + var scrollHandle = m_HierarchyUI.scrollHandle; + scrollHandle.dragStarted += OnScrollDragStarted; + scrollHandle.dragging += OnScrollDragging; + scrollHandle.dragEnded += OnScrollDragEnded; + scrollHandle.hoverStarted += OnScrollHoverStarted; + scrollHandle.hoverEnded += OnScrollHoverEnded; + + contentBounds = new Bounds(Vector3.zero, m_CustomStartingBounds.Value); + + var scrollHandleTransform = m_HierarchyUI.scrollHandle.transform; + scrollHandleTransform.SetParent(m_WorkspaceUI.topFaceContainer); + scrollHandleTransform.localScale = new Vector3(1.03f, 0.02f, 1.02f); // Extra space for scrolling + scrollHandleTransform.localPosition = new Vector3(0f, -0.015f, 0f); // Offset from content for collision purposes + + m_FilterUI.buttonClicked += OnButtonClicked; + m_FilterUI.buttonHovered += OnButtonHovered; + + // Propagate initial bounds + OnBoundsChanged(); + } + + protected override void OnDestroy() + { + m_FilterUI.buttonClicked -= OnButtonClicked; + m_FilterUI.buttonHovered -= OnButtonHovered; + + base.OnDestroy(); + } + + protected override void OnBoundsChanged() + { + var size = contentBounds.size; + var listView = m_HierarchyUI.listView; + size.y = float.MaxValue; // Add height for dropdowns + size.x -= DoubleFaceMargin; // Shrink the content width, so that there is space allowed to grab and scroll + size.z -= DoubleFaceMargin; // Reduce the height of the inspector contents as to fit within the bounds of the workspace + listView.size = size; + } + + static void SelectRow(int index) + { + var gameObject = EditorUtility.InstanceIDToObject(index) as GameObject; + if (gameObject && Selection.activeGameObject != gameObject) + Selection.activeGameObject = gameObject; + else + Selection.activeGameObject = null; + } + + void OnScrollDragStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = true; + + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = false; + + m_HierarchyUI.listView.OnBeginScrolling(); + } + + void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_HierarchyUI.listView.scrollOffset -= Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); + } + + void OnScrollDragEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = false; + + m_WorkspaceUI.topHighlight.visible = false; + + m_HierarchyUI.listView.OnScrollEnded(); + } + + void OnScrollHoverStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + if (!m_Scrolling) + { + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = true; + } + } + + void OnScrollHoverEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + if (!m_Scrolling) + { + m_WorkspaceUI.topHighlight.visible = false; + m_WorkspaceUI.amplifyTopHighlight = false; + } + } + + public void OnSelectionChanged() + { + m_HierarchyUI.listView.SelectRow(Selection.activeInstanceID); + } + + void FocusSelection(Transform rayOrigin) + { + if (Selection.gameObjects.Length == 0) + return; + + var mainCamera = CameraUtils.GetMainCamera().transform; + var bounds = ObjectUtils.GetBounds(Selection.transforms); + + var size = bounds.size; + size.y = 0; + var maxSize = size.MaxComponent(); + + const float kExtraDistance = 0.25f; // Add some extra distance so selection isn't in your face + maxSize += kExtraDistance; + + var viewDirection = mainCamera.transform.forward; + viewDirection.y = 0; + viewDirection.Normalize(); + + var cameraDiff = mainCamera.position - CameraUtils.GetCameraRig().position; + cameraDiff.y = 0; + + this.MoveCameraRig(bounds.center - cameraDiff - viewDirection * maxSize); + + OnButtonClicked(rayOrigin); + } + + static void CreateEmptyGameObject(Transform rayOrigin) + { + var camera = CameraUtils.GetMainCamera().transform; + var go = new GameObject(); + go.transform.position = camera.position + camera.forward; + Selection.activeGameObject = go; + } + } +} +#endif diff --git a/Workspaces/HierarchyWorkspace/Scripts/HierarchyListItem.cs b/Workspaces/HierarchyWorkspace/Scripts/HierarchyListItem.cs index 64ed69d8d..4b02ad769 100644 --- a/Workspaces/HierarchyWorkspace/Scripts/HierarchyListItem.cs +++ b/Workspaces/HierarchyWorkspace/Scripts/HierarchyListItem.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using System.Collections.Generic; using UnityEditor.Experimental.EditorVR.Handles; @@ -275,7 +275,7 @@ void OnClick(BaseHandle handle, PointerEventData pointerEventData) toggleExpanded(data.index); } - protected override void OnGrabDragStart(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) + protected override void OnDragStarted(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) { // handle will be the backing cube, not the whole row object var row = handle.transform.parent; @@ -329,7 +329,7 @@ void OnGrabRecursive(List visibleChildren, Transform rayOrigi } } - protected override void OnGrabDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) + protected override void OnDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) { if (m_DragObject) { diff --git a/Workspaces/InspectorWorkspace/InspectorWorkspace.cs b/Workspaces/InspectorWorkspace/InspectorWorkspace.cs index 80f37092b..994c4bebe 100644 --- a/Workspaces/InspectorWorkspace/InspectorWorkspace.cs +++ b/Workspaces/InspectorWorkspace/InspectorWorkspace.cs @@ -1,371 +1,371 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor.Experimental.EditorVR.Data; -using UnityEditor.Experimental.EditorVR.Handles; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Workspaces -{ - [MainMenuItem("Inspector", "Workspaces", "View and edit GameObject properties")] - sealed class InspectorWorkspace : Workspace, ISelectionChanged - { - public new static readonly Vector3 DefaultBounds = new Vector3(0.3f, 0.1f, 0.5f); - - [SerializeField] - GameObject m_ContentPrefab; - - [SerializeField] - GameObject m_LockPrefab; - - InspectorUI m_InspectorUI; - GameObject m_SelectedObject; - LockUI m_LockUI; - - bool m_Scrolling; - - bool m_IsLocked; - - public override void Setup() - { - // Initial bounds must be set before the base.Setup() is called - minBounds = new Vector3(0.502f, MinBounds.y, 0.3f); - m_CustomStartingBounds = new Vector3(0.502f, MinBounds.y, 0.6f); - - base.Setup(); - var contentPrefab = ObjectUtils.Instantiate(m_ContentPrefab, m_WorkspaceUI.sceneContainer, false); - m_InspectorUI = contentPrefab.GetComponent(); - - m_LockUI = ObjectUtils.Instantiate(m_LockPrefab, m_WorkspaceUI.frontPanel, false).GetComponentInChildren(); - this.ConnectInterfaces(m_LockUI); - m_LockUI.clicked += OnLockButtonClicked; - m_LockUI.hovered += OnButtonHovered; - EditorApplication.delayCall += m_LockUI.Setup; // Need to write stencilRef after WorkspaceButton does it - - var listView = m_InspectorUI.listView; - this.ConnectInterfaces(listView); - listView.data = new List(); - listView.arraySizeChanged += OnArraySizeChanged; - - var scrollHandle = m_InspectorUI.scrollHandle; - scrollHandle.dragStarted += OnScrollDragStarted; - scrollHandle.dragging += OnScrollDragging; - scrollHandle.dragEnded += OnScrollDragEnded; - scrollHandle.hoverStarted += OnScrollHoverStarted; - scrollHandle.hoverEnded += OnScrollHoverEnded; - - contentBounds = new Bounds(Vector3.zero, m_CustomStartingBounds.Value); - - var scrollHandleTransform = m_InspectorUI.scrollHandle.transform; - scrollHandleTransform.SetParent(m_WorkspaceUI.topFaceContainer); - scrollHandleTransform.localScale = new Vector3(1.03f, 0.02f, 1.02f); // Extra space for scrolling - scrollHandleTransform.localPosition = new Vector3(0f, -0.01f, 0f); // Offset from content for collision purposes - - if (Selection.activeGameObject) - OnSelectionChanged(); - - Undo.postprocessModifications += OnPostprocessModifications; - Undo.undoRedoPerformed += OnUndoRedo; - - // Propagate initial bounds - OnBoundsChanged(); - } - - void OnUndoRedo() - { - UpdateCurrentObject(true); - } - - void OnScrollDragStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_Scrolling = true; - - m_WorkspaceUI.topHighlight.visible = true; - m_WorkspaceUI.amplifyTopHighlight = false; - - m_InspectorUI.listView.OnBeginScrolling(); - } - - void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_InspectorUI.listView.scrollOffset += Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); - } - - void OnScrollDragEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - m_Scrolling = false; - - m_WorkspaceUI.topHighlight.visible = false; - - m_InspectorUI.listView.OnScrollEnded(); - } - - void OnScrollHoverStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - if (!m_Scrolling) - { - m_WorkspaceUI.topHighlight.visible = true; - m_WorkspaceUI.amplifyTopHighlight = true; - } - } - - void OnScrollHoverEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) - { - if (!m_Scrolling) - { - m_WorkspaceUI.topHighlight.visible = false; - m_WorkspaceUI.amplifyTopHighlight = false; - } - } - - public void OnSelectionChanged() - { - if (m_IsLocked) - return; - - if (Selection.activeGameObject == m_SelectedObject) - return; - - if (Selection.activeGameObject == null) - { - m_InspectorUI.listView.data = new List(); - m_SelectedObject = null; - return; - } - - m_SelectedObject = Selection.activeGameObject; - UpdateInspectorData(m_SelectedObject, true); - } - - void UpdateInspectorData(GameObject selection, bool fullReload) - { - var listView = m_InspectorUI.listView; - if (fullReload) - { - var inspectorData = new List(); - var objectChildren = new List(); - - foreach (var component in selection.GetComponents()) - { - var obj = new SerializedObject(component); - - var componentChildren = new List(); - - var property = obj.GetIterator(); - while (property.NextVisible(true)) - { - if (property.depth == 0) - componentChildren.Add(SerializedPropertyToPropertyData(property, obj)); - } - - var componentData = new InspectorData("InspectorComponentItem", obj, componentChildren); - objectChildren.Add(componentData); - } - - var objectData = new InspectorData("InspectorHeaderItem", new SerializedObject(selection), objectChildren); - inspectorData.Add(objectData); - - listView.data = inspectorData; - } - else - { - listView.OnObjectModified(); - } - } - - UndoPropertyModification[] OnPostprocessModifications(UndoPropertyModification[] modifications) - { - if (!m_SelectedObject || !IncludesCurrentObject(modifications)) - return modifications; - - UpdateCurrentObject(false); - - return modifications; - } - - bool IncludesCurrentObject(UndoPropertyModification[] modifications) - { - foreach (var modification in modifications) - { - if (modification.previousValue.target == m_SelectedObject) - return true; - - if (modification.currentValue.target == m_SelectedObject) - return true; - - foreach (var component in m_SelectedObject.GetComponents()) - { - if (modification.previousValue.target == component) - return true; - - if (modification.currentValue.target == component) - return true; - } - } - - return false; - } - - void UpdateCurrentObject(bool fullReload) - { - if (m_SelectedObject) - UpdateInspectorData(m_SelectedObject, fullReload); - } - - PropertyData SerializedPropertyToPropertyData(SerializedProperty property, SerializedObject obj) - { - string template; - switch (property.propertyType) - { - case SerializedPropertyType.Vector2: - case SerializedPropertyType.Vector3: - case SerializedPropertyType.Vector4: - case SerializedPropertyType.Quaternion: - template = "InspectorVectorItem"; - break; - case SerializedPropertyType.Integer: - goto case SerializedPropertyType.Float; - case SerializedPropertyType.Float: - template = "InspectorNumberItem"; - break; - case SerializedPropertyType.Character: - case SerializedPropertyType.String: - template = "InspectorStringItem"; - break; - case SerializedPropertyType.Bounds: - template = "InspectorBoundsItem"; - break; - case SerializedPropertyType.Boolean: - template = "InspectorBoolItem"; - break; - case SerializedPropertyType.ObjectReference: - template = "InspectorObjectFieldItem"; - break; - case SerializedPropertyType.Color: - template = "InspectorColorItem"; - break; - case SerializedPropertyType.Rect: - template = "InspectorRectItem"; - break; - case SerializedPropertyType.LayerMask: - case SerializedPropertyType.Enum: - template = "InspectorDropDownItem"; - break; - case SerializedPropertyType.Generic: - return GenericProperty(property, obj); - default: - template = "InspectorUnimplementedItem"; - break; - } - - return new PropertyData(template, obj, null, property.Copy()); - } - - PropertyData GenericProperty(SerializedProperty property, SerializedObject obj) - { - var children = GetSubProperties(property, obj); - - var propertyData = property.isArray - ? new PropertyData("InspectorArrayHeaderItem", obj, children, property.Copy()) - : new PropertyData("InspectorGenericItem", obj, children, property.Copy()); - - propertyData.childrenChanging += m_InspectorUI.listView.OnBeforeChildrenChanged; - - return propertyData; - } - - List GetSubProperties(SerializedProperty property, SerializedObject obj) - { - var children = new List(); - var iteratorProperty = property.Copy(); - while (iteratorProperty.NextVisible(true)) - { - if (iteratorProperty.depth == 0) - break; - - switch (iteratorProperty.propertyType) - { - case SerializedPropertyType.ArraySize: - children.Add(new PropertyData("InspectorNumberItem", obj, null, iteratorProperty.Copy())); - break; - default: - children.Add(SerializedPropertyToPropertyData(iteratorProperty, obj)); - break; - } - } - - return children; - } - - void OnArraySizeChanged(List data, PropertyData element) - { - foreach (var d in data) - { - if (FindElementAndUpdateParent(d, element)) - break; - } - } - - bool FindElementAndUpdateParent(InspectorData parent, PropertyData element) - { - if (parent.children != null) - { - foreach (var child in parent.children) - { - if (child == element) - { - var propertyData = (PropertyData)parent; - propertyData.children = GetSubProperties(propertyData.property.Copy(), propertyData.serializedObject); - return true; - } - - if (FindElementAndUpdateParent(child, element)) - return true; - } - } - - return false; - } - - protected override void OnBoundsChanged() - { - var size = contentBounds.size; - var listView = m_InspectorUI.listView; - var bounds = contentBounds; - size.y = float.MaxValue; // Add height for dropdowns - size.x -= FaceMargin * 2; // Shrink the content width, so that there is space allowed to grab and scroll - size.z -= FaceMargin; // Reduce the height of the inspector contents as to fit within the bounds of the workspace - bounds.size = size; - listView.size = bounds.size; - - var listPanel = m_InspectorUI.listPanel; - listPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); - listPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z); - } - - void SetIsLocked() - { - m_IsLocked = !m_IsLocked; - m_LockUI.UpdateIcon(m_IsLocked); - - if (!m_IsLocked) - OnSelectionChanged(); - - OnButtonClicked(null); - } - - protected override void OnDestroy() - { - Undo.postprocessModifications -= OnPostprocessModifications; - Undo.undoRedoPerformed -= OnUndoRedo; - base.OnDestroy(); - } - - void OnLockButtonClicked(Transform rayOrigin) - { - SetIsLocked(); - OnButtonClicked(rayOrigin); - } - } -} -#endif +#if UNITY_EDITOR +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Data; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + [MainMenuItem("Inspector", "Workspaces", "View and edit GameObject properties")] + sealed class InspectorWorkspace : Workspace, ISelectionChanged + { + public new static readonly Vector3 DefaultBounds = new Vector3(0.3f, 0.1f, 0.5f); + + [SerializeField] + GameObject m_ContentPrefab; + + [SerializeField] + GameObject m_LockPrefab; + + InspectorUI m_InspectorUI; + GameObject m_SelectedObject; + LockUI m_LockUI; + + bool m_Scrolling; + + bool m_IsLocked; + + public override void Setup() + { + // Initial bounds must be set before the base.Setup() is called + minBounds = new Vector3(0.502f, MinBounds.y, 0.3f); + m_CustomStartingBounds = new Vector3(0.502f, MinBounds.y, 0.6f); + + base.Setup(); + var contentPrefab = ObjectUtils.Instantiate(m_ContentPrefab, m_WorkspaceUI.sceneContainer, false); + m_InspectorUI = contentPrefab.GetComponent(); + + m_LockUI = ObjectUtils.Instantiate(m_LockPrefab, m_WorkspaceUI.frontPanel, false).GetComponentInChildren(); + this.ConnectInterfaces(m_LockUI); + m_LockUI.clicked += OnLockButtonClicked; + m_LockUI.hovered += OnButtonHovered; + EditorApplication.delayCall += m_LockUI.Setup; // Need to write stencilRef after WorkspaceButton does it + + var listView = m_InspectorUI.listView; + this.ConnectInterfaces(listView); + listView.data = new List(); + listView.arraySizeChanged += OnArraySizeChanged; + + var scrollHandle = m_InspectorUI.scrollHandle; + scrollHandle.dragStarted += OnScrollDragStarted; + scrollHandle.dragging += OnScrollDragging; + scrollHandle.dragEnded += OnScrollDragEnded; + scrollHandle.hoverStarted += OnScrollHoverStarted; + scrollHandle.hoverEnded += OnScrollHoverEnded; + + contentBounds = new Bounds(Vector3.zero, m_CustomStartingBounds.Value); + + var scrollHandleTransform = m_InspectorUI.scrollHandle.transform; + scrollHandleTransform.SetParent(m_WorkspaceUI.topFaceContainer); + scrollHandleTransform.localScale = new Vector3(1.03f, 0.02f, 1.02f); // Extra space for scrolling + scrollHandleTransform.localPosition = new Vector3(0f, -0.01f, 0f); // Offset from content for collision purposes + + if (Selection.activeGameObject) + OnSelectionChanged(); + + Undo.postprocessModifications += OnPostprocessModifications; + Undo.undoRedoPerformed += OnUndoRedo; + + // Propagate initial bounds + OnBoundsChanged(); + } + + void OnUndoRedo() + { + UpdateCurrentObject(true); + } + + void OnScrollDragStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = true; + + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = false; + + m_InspectorUI.listView.OnBeginScrolling(); + } + + void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_InspectorUI.listView.scrollOffset += Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); + } + + void OnScrollDragEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = false; + + m_WorkspaceUI.topHighlight.visible = false; + + m_InspectorUI.listView.OnScrollEnded(); + } + + void OnScrollHoverStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + if (!m_Scrolling) + { + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = true; + } + } + + void OnScrollHoverEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + if (!m_Scrolling) + { + m_WorkspaceUI.topHighlight.visible = false; + m_WorkspaceUI.amplifyTopHighlight = false; + } + } + + public void OnSelectionChanged() + { + if (m_IsLocked) + return; + + if (Selection.activeGameObject == m_SelectedObject) + return; + + if (Selection.activeGameObject == null) + { + m_InspectorUI.listView.data = new List(); + m_SelectedObject = null; + return; + } + + m_SelectedObject = Selection.activeGameObject; + UpdateInspectorData(m_SelectedObject, true); + } + + void UpdateInspectorData(GameObject selection, bool fullReload) + { + var listView = m_InspectorUI.listView; + if (fullReload) + { + var inspectorData = new List(); + var objectChildren = new List(); + + foreach (var component in selection.GetComponents()) + { + var obj = new SerializedObject(component); + + var componentChildren = new List(); + + var property = obj.GetIterator(); + while (property.NextVisible(true)) + { + if (property.depth == 0) + componentChildren.Add(SerializedPropertyToPropertyData(property, obj)); + } + + var componentData = new InspectorData("InspectorComponentItem", obj, componentChildren); + objectChildren.Add(componentData); + } + + var objectData = new InspectorData("InspectorHeaderItem", new SerializedObject(selection), objectChildren); + inspectorData.Add(objectData); + + listView.data = inspectorData; + } + else + { + listView.OnObjectModified(); + } + } + + UndoPropertyModification[] OnPostprocessModifications(UndoPropertyModification[] modifications) + { + if (!m_SelectedObject || !IncludesCurrentObject(modifications)) + return modifications; + + UpdateCurrentObject(false); + + return modifications; + } + + bool IncludesCurrentObject(UndoPropertyModification[] modifications) + { + foreach (var modification in modifications) + { + if (modification.previousValue.target == m_SelectedObject) + return true; + + if (modification.currentValue.target == m_SelectedObject) + return true; + + foreach (var component in m_SelectedObject.GetComponents()) + { + if (modification.previousValue.target == component) + return true; + + if (modification.currentValue.target == component) + return true; + } + } + + return false; + } + + void UpdateCurrentObject(bool fullReload) + { + if (m_SelectedObject) + UpdateInspectorData(m_SelectedObject, fullReload); + } + + PropertyData SerializedPropertyToPropertyData(SerializedProperty property, SerializedObject obj) + { + string template; + switch (property.propertyType) + { + case SerializedPropertyType.Vector2: + case SerializedPropertyType.Vector3: + case SerializedPropertyType.Vector4: + case SerializedPropertyType.Quaternion: + template = "InspectorVectorItem"; + break; + case SerializedPropertyType.Integer: + goto case SerializedPropertyType.Float; + case SerializedPropertyType.Float: + template = "InspectorNumberItem"; + break; + case SerializedPropertyType.Character: + case SerializedPropertyType.String: + template = "InspectorStringItem"; + break; + case SerializedPropertyType.Bounds: + template = "InspectorBoundsItem"; + break; + case SerializedPropertyType.Boolean: + template = "InspectorBoolItem"; + break; + case SerializedPropertyType.ObjectReference: + template = "InspectorObjectFieldItem"; + break; + case SerializedPropertyType.Color: + template = "InspectorColorItem"; + break; + case SerializedPropertyType.Rect: + template = "InspectorRectItem"; + break; + case SerializedPropertyType.LayerMask: + case SerializedPropertyType.Enum: + template = "InspectorDropDownItem"; + break; + case SerializedPropertyType.Generic: + return GenericProperty(property, obj); + default: + template = "InspectorUnimplementedItem"; + break; + } + + return new PropertyData(template, obj, null, property.Copy()); + } + + PropertyData GenericProperty(SerializedProperty property, SerializedObject obj) + { + var children = GetSubProperties(property, obj); + + var propertyData = property.isArray + ? new PropertyData("InspectorArrayHeaderItem", obj, children, property.Copy()) + : new PropertyData("InspectorGenericItem", obj, children, property.Copy()); + + propertyData.childrenChanging += m_InspectorUI.listView.OnBeforeChildrenChanged; + + return propertyData; + } + + List GetSubProperties(SerializedProperty property, SerializedObject obj) + { + var children = new List(); + var iteratorProperty = property.Copy(); + while (iteratorProperty.NextVisible(true)) + { + if (iteratorProperty.depth == 0) + break; + + switch (iteratorProperty.propertyType) + { + case SerializedPropertyType.ArraySize: + children.Add(new PropertyData("InspectorNumberItem", obj, null, iteratorProperty.Copy())); + break; + default: + children.Add(SerializedPropertyToPropertyData(iteratorProperty, obj)); + break; + } + } + + return children; + } + + void OnArraySizeChanged(List data, PropertyData element) + { + foreach (var d in data) + { + if (FindElementAndUpdateParent(d, element)) + break; + } + } + + bool FindElementAndUpdateParent(InspectorData parent, PropertyData element) + { + if (parent.children != null) + { + foreach (var child in parent.children) + { + if (child == element) + { + var propertyData = (PropertyData)parent; + propertyData.children = GetSubProperties(propertyData.property.Copy(), propertyData.serializedObject); + return true; + } + + if (FindElementAndUpdateParent(child, element)) + return true; + } + } + + return false; + } + + protected override void OnBoundsChanged() + { + var size = contentBounds.size; + var listView = m_InspectorUI.listView; + var bounds = contentBounds; + size.y = float.MaxValue; // Add height for dropdowns + size.x -= DoubleFaceMargin; // Shrink the content width, so that there is space allowed to grab and scroll + size.z -= FaceMargin; // Reduce the height of the inspector contents as to fit within the bounds of the workspace + bounds.size = size; + listView.size = bounds.size; + + var listPanel = m_InspectorUI.listPanel; + listPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); + listPanel.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.z); + } + + void SetIsLocked() + { + m_IsLocked = !m_IsLocked; + m_LockUI.UpdateIcon(m_IsLocked); + + if (!m_IsLocked) + OnSelectionChanged(); + + OnButtonClicked(null); + } + + protected override void OnDestroy() + { + Undo.postprocessModifications -= OnPostprocessModifications; + Undo.undoRedoPerformed -= OnUndoRedo; + base.OnDestroy(); + } + + void OnLockButtonClicked(Transform rayOrigin) + { + SetIsLocked(); + OnButtonClicked(rayOrigin); + } + } +} +#endif diff --git a/Workspaces/InspectorWorkspace/Scripts/ListItems/InspectorListItem.cs b/Workspaces/InspectorWorkspace/Scripts/ListItems/InspectorListItem.cs index c40854c42..e8dc3bbb6 100644 --- a/Workspaces/InspectorWorkspace/Scripts/ListItems/InspectorListItem.cs +++ b/Workspaces/InspectorWorkspace/Scripts/ListItems/InspectorListItem.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using UnityEditor.Experimental.EditorVR.Data; using UnityEditor.Experimental.EditorVR.Handles; @@ -201,7 +201,7 @@ protected override void OnDragStarted(BaseHandle handle, HandleEventData eventDa m_HorizontalDrag = false; } - protected override void OnGrabDragStart(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) + protected override void OnDragStarted(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) { var dragVector = eventData.rayOrigin.position - dragStart; var distance = dragVector.magnitude; @@ -217,7 +217,7 @@ protected override void OnGrabDragStart(BaseHandle handle, HandleEventData event } } - protected override void OnGrabDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) + protected override void OnDragging(BaseHandle handle, HandleEventData eventData, Vector3 dragStart) { if (m_HorizontalDrag) OnHorizontalDragging(eventData.rayOrigin); diff --git a/Workspaces/LockedObjectsWorkspace/LockedObjectsWorkspace.cs b/Workspaces/LockedObjectsWorkspace/LockedObjectsWorkspace.cs index 4dccded0d..129f4b035 100644 --- a/Workspaces/LockedObjectsWorkspace/LockedObjectsWorkspace.cs +++ b/Workspaces/LockedObjectsWorkspace/LockedObjectsWorkspace.cs @@ -1,5 +1,4 @@ #if UNITY_EDITOR -using System; using System.Collections.Generic; using UnityEditor.Experimental.EditorVR.Utilities; using UnityEngine; @@ -43,9 +42,6 @@ public override List filterList } } - public Action setLocked { get; set; } - public Func isLocked { get; set; } - public override void Setup() { base.Setup(); @@ -69,12 +65,15 @@ void UnlockAll() void UnlockAll(List hierarchyData) { - if (hierarchyData == null) + if (hierarchyData == null || hierarchyData.Count == 0) return; + if (!hierarchyData[0].gameObject) + hierarchyData = hierarchyData[0].children; + foreach (var hd in hierarchyData) { - setLocked(hd.gameObject, false); + this.SetLocked(hd.gameObject, false); UnlockAll(hd.children); } diff --git a/Workspaces/MiniWorldWorkspace/MiniWorldWorkspace.cs b/Workspaces/MiniWorldWorkspace/MiniWorldWorkspace.cs index c7706d294..2129fc881 100644 --- a/Workspaces/MiniWorldWorkspace/MiniWorldWorkspace.cs +++ b/Workspaces/MiniWorldWorkspace/MiniWorldWorkspace.cs @@ -522,17 +522,14 @@ void ShowFeedback(List requests, Node node, string control { foreach (var id in ids) { - var request = new ProxyFeedbackRequest - { - node = node, - control = id, - priority = 1, - tooltipText = tooltipText, - suppressExisting = suppressExisting - }; - - this.AddFeedbackRequest(request); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.node = node; + request.control = id; + request.priority = 1; + request.tooltipText = tooltipText; + request.suppressExisting = suppressExisting; requests.Add(request); + this.AddFeedbackRequest(request); } } } diff --git a/Models/Vive/Models/button.mtl.meta b/Workspaces/PolyWorkspace.meta similarity index 52% rename from Models/Vive/Models/button.mtl.meta rename to Workspaces/PolyWorkspace.meta index 30da8fc25..088e07f54 100644 --- a/Models/Vive/Models/button.mtl.meta +++ b/Workspaces/PolyWorkspace.meta @@ -1,8 +1,10 @@ fileFormatVersion: 2 -guid: 539e42079f414614786f29d31d92a2b6 -timeCreated: 1507075387 +guid: 8a77465c5aa291a4e95c57b094a8a99c +folderAsset: yes +timeCreated: 1471887792 licenseType: Pro DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Models/Vive/Models/l_grip.mtl.meta b/Workspaces/PolyWorkspace/Materials.meta similarity index 58% rename from Models/Vive/Models/l_grip.mtl.meta rename to Workspaces/PolyWorkspace/Materials.meta index fd9e15ebb..66c0c7e52 100644 --- a/Models/Vive/Models/l_grip.mtl.meta +++ b/Workspaces/PolyWorkspace/Materials.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 -guid: c02966373ee087e4b87648a95a463b28 -timeCreated: 1507075387 +guid: 555b4a24a85d526439f2a5cc9a30afe8 +folderAsset: yes +timeCreated: 1505260860 licenseType: Pro DefaultImporter: userData: diff --git a/Workspaces/PolyWorkspace/Materials/Thumbnail.mat b/Workspaces/PolyWorkspace/Materials/Thumbnail.mat new file mode 100644 index 000000000..7e5903a45 --- /dev/null +++ b/Workspaces/PolyWorkspace/Materials/Thumbnail.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Thumbnail + m_Shader: {fileID: 4800000, guid: c6719621509287341948674c92277f06, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.441 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Workspaces/PolyWorkspace/Materials/Thumbnail.mat.meta b/Workspaces/PolyWorkspace/Materials/Thumbnail.mat.meta new file mode 100644 index 000000000..72fa87327 --- /dev/null +++ b/Workspaces/PolyWorkspace/Materials/Thumbnail.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d7eb5f17472593743b1dfc33914d425a +timeCreated: 1505260867 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Models.meta b/Workspaces/PolyWorkspace/Models.meta new file mode 100644 index 000000000..45ecd16c9 --- /dev/null +++ b/Workspaces/PolyWorkspace/Models.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d277239811391bb47b2b31f75a2b753d +folderAsset: yes +timeCreated: 1510106650 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Models/PreviewCube.fbx b/Workspaces/PolyWorkspace/Models/PreviewCube.fbx new file mode 100644 index 000000000..ad3ab621b --- /dev/null +++ b/Workspaces/PolyWorkspace/Models/PreviewCube.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16c351d27662f96f59c3e117ad76640326dc650fb95a87be5891be6e77aa9f93 +size 14972 diff --git a/Workspaces/PolyWorkspace/Models/PreviewCube.fbx.meta b/Workspaces/PolyWorkspace/Models/PreviewCube.fbx.meta new file mode 100644 index 000000000..5d9e1dc7b --- /dev/null +++ b/Workspaces/PolyWorkspace/Models/PreviewCube.fbx.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: 65a5ef1e9b0c30546bcafdadb3b521eb +timeCreated: 1510106651 +licenseType: Pro +ModelImporter: + serializedVersion: 22 + fileIDToRecycleName: + 100000: //RootNode + 100002: Camera + 100004: Cube + 100006: Lamp + 400000: //RootNode + 400002: Camera + 400004: Cube + 400006: Lamp + 2000000: Camera + 2100000: Material + 2100002: Material.001 + 2300000: //RootNode + 2300002: Cube + 3300000: //RootNode + 3300002: Cube + 4300000: Cube + 10800000: Lamp + externalObjects: {} + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + keepQuads: 0 + weldVertices: 1 + preserveHierarchy: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + serializedVersion: 2 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + rootMotionBoneName: + rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 0 + humanoidOversampling: 1 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Poly.prefab b/Workspaces/PolyWorkspace/Poly.prefab new file mode 100644 index 000000000..d75fce802 --- /dev/null +++ b/Workspaces/PolyWorkspace/Poly.prefab @@ -0,0 +1,292 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1000010661511152} + m_IsPrefabParent: 1 +--- !u!1 &1000010661511152 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000012395172298} + - component: {fileID: 114000011829900818} + m_Layer: 5 + m_Name: Poly + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000012138296068 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000012337325098} + - component: {fileID: 65000013486880540} + - component: {fileID: 114000013168122432} + - component: {fileID: 114000011150243682} + m_Layer: 5 + m_Name: ScrollHandle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000013566133352 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000010478384770} + - component: {fileID: 114000011974647448} + m_Layer: 5 + m_Name: Grid + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1684674945869184 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4235827334236770} + - component: {fileID: 33377829788683320} + - component: {fileID: 23035117804624906} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1872046847078704 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4724973473163676} + m_Layer: 0 + m_Name: Spinner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4000010478384770 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000013566133352} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4000012395172298} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4000012337325098 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012138296068} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -0.0005, z: 0} + m_LocalScale: {x: 0.333333, y: 0.001, z: 0.5} + m_Children: [] + m_Father: {fileID: 4000012395172298} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4000012395172298 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010661511152} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.050000012, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4724973473163676} + - {fileID: 4000010478384770} + - {fileID: 4000012337325098} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4235827334236770 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1684674945869184} + m_LocalRotation: {x: -0.4170287, y: 0.33836657, z: -0.179835, w: 0.824169} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.7698965, y: 0.76989645, z: 0.7698965} + m_Children: [] + m_Father: {fileID: 4724973473163676} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: -34.451, y: 59.123, z: -44.565002} +--- !u!4 &4724973473163676 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1872046847078704} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.064502716, y: 0.064502716, z: 0.064502716} + m_Children: + - {fileID: 4235827334236770} + m_Father: {fileID: 4000012395172298} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &23035117804624906 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1684674945869184} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: 3ac4991e69337ae41badfeef7c8ba134, type: 2} + - {fileID: 2100000, guid: d3bb23d585e936140a5f274d7450f24e, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &33377829788683320 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1684674945869184} + m_Mesh: {fileID: 4300000, guid: 4f59d2c28d92b4a0486ef9a7530a7236, type: 3} +--- !u!65 &65000013486880540 +BoxCollider: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012138296068} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &114000011150243682 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012138296068} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a6578b7c795e17243af7f851d5c98d6f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ListView: {fileID: 114000011974647448} +--- !u!114 &114000011829900818 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010661511152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 33e1473776ce1dc4f838a0fb9687bf5a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_GridView: {fileID: 114000011974647448} + m_ScrollHandle: {fileID: 114000013168122432} +--- !u!114 &114000011974647448 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000013566133352} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 66259449855f4014f8f987cbbc7fe988, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ScrollOffset: -0.00013233244 + m_Padding: 0.6 + m_ScrollDamping: 1.2 + m_MaxMomentum: 2 + m_Templates: + - {fileID: 1120077170014744, guid: 618b5d52a53fb1141b25899666a4721d, type: 2} + m_ScrollPulse: {fileID: 11400000, guid: 77319cd620700db49a9223c7305480f9, type: 2} + m_SettleSpeed: 0.3 + m_ScrollSpeed: 0.3 + m_ItemClickPulse: {fileID: 11400000, guid: 72c68844f1d53f549976daae6a207100, type: 2} + m_ItemHoverStartPulse: {fileID: 11400000, guid: d71c4adadeb37984aa5f37d8c0096997, + type: 2} + m_ItemHoverEndPulse: {fileID: 0} + m_ItemDragStartPulse: {fileID: 11400000, guid: 0df1c3251269d8a41a11a33faf676222, + type: 2} + m_ItemDraggingPulse: {fileID: 11400000, guid: 5ccd598d3356a834e87a36e7111cb173, + type: 2} + m_ItemDragEndPulse: {fileID: 11400000, guid: 64a535853bdb5b24f8d196dedeea8cba, type: 2} + m_ScaleFactor: 0.056 + m_Spinner: {fileID: 4724973473163676} + m_SpinnerSpeed: 25 + m_SpinnerOffset: {x: 0.065, y: -0.0125, z: -0.023} + m_IconTypes: [] + m_Icons: [] +--- !u!114 &114000013168122432 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012138296068} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 410244f902f0bbc47a023d4a93ffeea9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SelectionFlags: 3 + m_OrientDragPlaneToRay: 0 + m_Constraints: 0 diff --git a/Models/Vive/Models/led.mtl.meta b/Workspaces/PolyWorkspace/Poly.prefab.meta similarity index 52% rename from Models/Vive/Models/led.mtl.meta rename to Workspaces/PolyWorkspace/Poly.prefab.meta index 45374f3ff..9a394ac19 100644 --- a/Models/Vive/Models/led.mtl.meta +++ b/Workspaces/PolyWorkspace/Poly.prefab.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: e0da3db3a4fb87c4685dcc2ea06495e4 -timeCreated: 1507075387 +guid: b419cb0d10c5da54b9bd9a557c3978ae +timeCreated: 1471990162 licenseType: Pro -DefaultImporter: +NativeFormatImporter: userData: assetBundleName: assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/PolyWorkspace.cs b/Workspaces/PolyWorkspace/PolyWorkspace.cs new file mode 100644 index 000000000..2474708c5 --- /dev/null +++ b/Workspaces/PolyWorkspace/PolyWorkspace.cs @@ -0,0 +1,508 @@ +#if UNITY_EDITOR +using System; +using System.Collections; +using System.Threading; +using UnityEditor.Experimental.EditorVR; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEngine; + +#if INCLUDE_POLY_TOOLKIT +using System.Collections.Generic; +using PolyToolkit; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEditor.Experimental.EditorVR.UI; +using UnityEditor.Experimental.EditorVR.Utilities; +#else +using UnityEditor.Experimental.EditorVR.Core; +using UnityEngine.InputNew; +#endif + +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ +#if INCLUDE_POLY_TOOLKIT + [MainMenuItem("Poly", "Workspaces", "Import models from Google Poly")] + sealed class PolyWorkspace : Workspace, ISerializeWorkspace + { + const float k_XBounds = 1.094f; + const float k_YBounds = 0.2f; + + const float k_MinScale = 0.05f; + const float k_MaxScale = 0.2f; + + const float k_HighlightDelay = 0.05f; + + const float k_FilterUIWidth = 0.162f; + + const string k_Featured = "Featured"; + const string k_Newest = "Newest"; + + const string k_Blocks = "Blocks"; + const string k_TiltBrush = "Tilt Brush"; + + const string k_Medium = "Medium"; + const string k_Simple = "Simple"; + + [Serializable] + class Preferences + { + [SerializeField] + float m_ScaleFactor; + + public float scaleFactor + { + get { return m_ScaleFactor; } + set { m_ScaleFactor = value; } + } + } + + [SerializeField] + GameObject m_ContentPrefab; + + [SerializeField] + GameObject m_FilterUIPrefab; + + [SerializeField] + GameObject m_SliderPrefab; + + bool m_Scrolling; + + PolyUI m_PolyUI; + FilterUI m_SortingUI; + FilterUI m_FormatFilterUI; + FilterUI m_ComplexityFilterUI; + FilterUI m_CategoryFilterUI; + ZoomSliderUI m_ZoomSliderUI; + + Coroutine m_HighlightDelayCoroutine; + + public List assetData + { + set + { + if (m_PolyUI) + m_PolyUI.gridView.data = value; + } + } + + public override void Setup() + { + // Initial bounds must be set before the base.Setup() is called + minBounds = new Vector3(k_XBounds, k_YBounds, 0.5f); + m_CustomStartingBounds = minBounds; + + base.Setup(); + + var contentPrefab = ObjectUtils.Instantiate(m_ContentPrefab, m_WorkspaceUI.sceneContainer, false); + m_PolyUI = contentPrefab.GetComponent(); + + var gridView = m_PolyUI.gridView; + this.ConnectInterfaces(gridView); + assetData = new List(); + + var sliderObject = ObjectUtils.Instantiate(m_SliderPrefab, m_WorkspaceUI.frontPanel, false); + m_ZoomSliderUI = sliderObject.GetComponent(); + m_ZoomSliderUI.zoomSlider.minValue = Mathf.Log10(k_MinScale); + m_ZoomSliderUI.zoomSlider.maxValue = Mathf.Log10(k_MaxScale); + m_ZoomSliderUI.sliding += Scale; + UpdateZoomSliderValue(); + foreach (var mb in m_ZoomSliderUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + + SetupCategoryFilterUI(); + SetupComplextyFilterUI(); + SetupFormatFilterUI(); + SetupSortingUI(); + + var zoomTooltip = sliderObject.GetComponentInChildren(); + if (zoomTooltip) + zoomTooltip.tooltipText = "Drag the Handle to Zoom the Asset Grid"; + + var scrollHandle = m_PolyUI.scrollHandle; + var scrollHandleTransform = scrollHandle.transform; + scrollHandleTransform.SetParent(m_WorkspaceUI.topFaceContainer); + scrollHandleTransform.localScale = new Vector3(1.03f, 0.02f, 1.02f); // Extra space for scrolling + scrollHandleTransform.localPosition = new Vector3(0f, -0.015f, 0f); // Offset from content for collision purposes + + scrollHandle.dragStarted += OnScrollDragStarted; + scrollHandle.dragging += OnScrollDragging; + scrollHandle.dragEnded += OnScrollDragEnded; + m_PolyUI.scrollHandle.hoverStarted += OnScrollHoverStarted; + m_PolyUI.scrollHandle.hoverEnded += OnScrollHoverEnded; + + // Propagate initial bounds + OnBoundsChanged(); + } + + void SetupCategoryFilterUI() + { + m_CategoryFilterUI = ObjectUtils.Instantiate(m_FilterUIPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); + m_CategoryFilterUI.transform.localPosition += Vector3.right * k_FilterUIWidth * 3; + foreach (var mb in m_CategoryFilterUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + + m_CategoryFilterUI.filterChanged += () => + { + var gridView = m_PolyUI.gridView; + var searchQuery = m_CategoryFilterUI.searchQuery; + if (string.IsNullOrEmpty(searchQuery)) + gridView.category = PolyCategory.UNSPECIFIED; + else + gridView.category = (PolyCategory)Enum.Parse(typeof(PolyCategory), searchQuery.ToUpper()); + + gridView.RequestAssetList(); + UpdateComplexityFilterUI(); + }; + + m_CategoryFilterUI.buttonClicked += handle => + { + m_SortingUI.SetListVisibility(false); + m_FormatFilterUI.SetListVisibility(false); + m_ComplexityFilterUI.SetListVisibility(false); + }; + + var categoryList = new List(); + var textInfo = Thread.CurrentThread.CurrentCulture.TextInfo; + + foreach (var category in Enum.GetNames(typeof(PolyCategory))) + { + if (category == "UNSPECIFIED") + continue; + + categoryList.Add(textInfo.ToTitleCase(category.ToLower())); + } + + m_CategoryFilterUI.filterList = categoryList; + + m_CategoryFilterUI.GetComponentInChildren().tooltipText = "Filter by Category"; + + UpdateCategoryFilterUI(); + } + + void UpdateCategoryFilterUI() + { + var searchQuery = m_CategoryFilterUI.searchQuery; + if (string.IsNullOrEmpty(searchQuery)) + { + m_CategoryFilterUI.summaryText.text = "All"; + m_CategoryFilterUI.descriptionText.text = "Showing all categories"; + } + else + { + m_CategoryFilterUI.summaryText.text = searchQuery; + m_CategoryFilterUI.descriptionText.text = "Showing " + searchQuery; + } + } + + void SetupComplextyFilterUI() + { + m_ComplexityFilterUI = ObjectUtils.Instantiate(m_FilterUIPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); + m_ComplexityFilterUI.transform.localPosition += Vector3.right * k_FilterUIWidth * 2; + foreach (var mb in m_ComplexityFilterUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + + m_ComplexityFilterUI.filterChanged += () => + { + var gridView = m_PolyUI.gridView; + switch (m_ComplexityFilterUI.searchQuery) + { + case k_Medium: + gridView.complexity = PolyMaxComplexityFilter.MEDIUM; + break; + case k_Simple: + gridView.complexity = PolyMaxComplexityFilter.SIMPLE; + break; + default: + gridView.complexity = PolyMaxComplexityFilter.UNSPECIFIED; + break; + } + + gridView.RequestAssetList(); + UpdateComplexityFilterUI(); + }; + + m_ComplexityFilterUI.buttonClicked += handle => + { + m_SortingUI.SetListVisibility(false); + m_FormatFilterUI.SetListVisibility(false); + m_CategoryFilterUI.SetListVisibility(false); + }; + + m_ComplexityFilterUI.filterList = new List + { + k_Medium, + k_Simple + }; + + m_ComplexityFilterUI.GetComponentInChildren().tooltipText = "Filter by Complexity"; + + UpdateComplexityFilterUI(); + } + + void UpdateComplexityFilterUI() + { + switch (m_ComplexityFilterUI.searchQuery) + { + case k_Medium: + m_ComplexityFilterUI.summaryText.text = k_Featured; + m_ComplexityFilterUI.descriptionText.text = "Showing simple and medium models"; + break; + case k_Simple: + m_ComplexityFilterUI.summaryText.text = k_Simple; + m_ComplexityFilterUI.descriptionText.text = "Showing simple models"; + break; + default: + m_ComplexityFilterUI.summaryText.text = "All"; + m_ComplexityFilterUI.descriptionText.text = "Showing all complexities"; + break; + } + } + + void SetupFormatFilterUI() + { + m_FormatFilterUI = ObjectUtils.Instantiate(m_FilterUIPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); + m_FormatFilterUI.transform.localPosition += Vector3.right * k_FilterUIWidth; + foreach (var mb in m_FormatFilterUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + + m_FormatFilterUI.filterChanged += () => + { + var gridView = m_PolyUI.gridView; + switch (m_FormatFilterUI.searchQuery) + { + case k_Blocks: + gridView.format = PolyFormatFilter.BLOCKS; + break; + case k_TiltBrush: + gridView.format = PolyFormatFilter.TILT; + break; + default: + gridView.format = null; + break; + } + + gridView.RequestAssetList(); + UpdateFormatFilterUI(); + }; + + m_FormatFilterUI.buttonClicked += handle => + { + m_SortingUI.SetListVisibility(false); + m_ComplexityFilterUI.SetListVisibility(false); + m_CategoryFilterUI.SetListVisibility(false); + }; + + m_FormatFilterUI.filterList = new List + { + k_Blocks, + k_TiltBrush + }; + + m_FormatFilterUI.GetComponentInChildren().tooltipText = "Filter by Format"; + + UpdateFormatFilterUI(); + } + + void UpdateFormatFilterUI() + { + switch (m_FormatFilterUI.searchQuery) + { + case k_Blocks: + m_FormatFilterUI.summaryText.text = k_Blocks; + m_FormatFilterUI.descriptionText.text = "Showing Blocks models"; + break; + case k_TiltBrush: + m_FormatFilterUI.summaryText.text = k_TiltBrush; + m_FormatFilterUI.descriptionText.text = "Showing Tiltbrush models"; + break; + default: + m_FormatFilterUI.summaryText.text = "All"; + m_FormatFilterUI.descriptionText.text = "Showing all formats"; + break; + } + } + + void SetupSortingUI() + { + m_SortingUI = ObjectUtils.Instantiate(m_FilterUIPrefab, m_WorkspaceUI.frontPanel, false).GetComponent(); + foreach (var mb in m_SortingUI.GetComponentsInChildren()) + { + this.ConnectInterfaces(mb); + } + + m_SortingUI.filterChanged += () => + { + var gridView = m_PolyUI.gridView; + switch (m_SortingUI.searchQuery) + { + case k_Featured: + gridView.sorting = PolyOrderBy.BEST; + break; + case k_Newest: + gridView.sorting = PolyOrderBy.NEWEST; + break; + } + + gridView.RequestAssetList(); + UpdateSortingUI(); + }; + + m_SortingUI.buttonClicked += handle => + { + m_FormatFilterUI.SetListVisibility(false); + m_ComplexityFilterUI.SetListVisibility(false); + m_CategoryFilterUI.SetListVisibility(false); + }; + + m_SortingUI.addDefaultOption = false; + m_SortingUI.filterList = new List + { + k_Featured, + k_Newest + }; + + m_SortingUI.GetComponentInChildren().tooltipText = "Change sorting"; + + UpdateSortingUI(); + } + + void UpdateSortingUI() + { + switch (m_SortingUI.searchQuery) + { + case k_Featured: + m_SortingUI.summaryText.text = k_Featured; + m_SortingUI.descriptionText.text = "Sorted by popularity"; + break; + case k_Newest: + m_SortingUI.summaryText.text = k_Newest; + m_SortingUI.descriptionText.text = "Sorted by date"; + break; + } + } + + public object OnSerializeWorkspace() + { + var preferences = new Preferences(); + preferences.scaleFactor = m_PolyUI.gridView.scaleFactor; + return preferences; + } + + public void OnDeserializeWorkspace(object obj) + { + var preferences = (Preferences)obj; + m_PolyUI.gridView.scaleFactor = preferences.scaleFactor; + UpdateZoomSliderValue(); + } + + protected override void OnBoundsChanged() + { + var size = contentBounds.size; + var gridView = m_PolyUI.gridView; + size.x -= DoubleFaceMargin; // Shrink the content width, so that there is space allowed to grab and scroll + size.z -= DoubleFaceMargin; // Reduce the height of the inspector contents as to fit within the bounds of the workspace + gridView.size = size; + } + + void OnScrollDragStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = true; + + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = false; + + m_PolyUI.gridView.OnBeginScrolling(); + } + + void OnScrollDragging(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_PolyUI.gridView.scrollOffset -= Vector3.Dot(eventData.deltaPosition, handle.transform.forward) / this.GetViewerScale(); + } + + void OnScrollDragEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + m_Scrolling = false; + + m_WorkspaceUI.topHighlight.visible = false; + + m_PolyUI.gridView.OnScrollEnded(); + } + + void OnScrollHoverStarted(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + if (!m_Scrolling && m_HighlightDelayCoroutine == null) + { + m_HighlightDelayCoroutine = StartCoroutine(DelayHighlight()); + } + } + + IEnumerator DelayHighlight() + { + yield return new WaitForSeconds(k_HighlightDelay); + m_WorkspaceUI.topHighlight.visible = true; + m_WorkspaceUI.amplifyTopHighlight = true; + } + + void OnScrollHoverEnded(BaseHandle handle, HandleEventData eventData = default(HandleEventData)) + { + this.StopCoroutine(ref m_HighlightDelayCoroutine); + if (!m_Scrolling && m_WorkspaceUI.gameObject.activeInHierarchy) // Check active to prevent errors in OnDestroy + { + m_WorkspaceUI.topHighlight.visible = false; + m_WorkspaceUI.amplifyTopHighlight = false; + } + } + + void Scale(float value) + { + m_PolyUI.gridView.scaleFactor = Mathf.Pow(10, value); + } + + void UpdateZoomSliderValue() + { + m_ZoomSliderUI.zoomSlider.value = Mathf.Log10(m_PolyUI.gridView.scaleFactor); + } + } +#else + // Non-Workspace stub to protect serialization + sealed class PolyWorkspace : MonoBehaviour + { + [SerializeField] + Vector3 m_MinBounds; + + [SerializeField] + GameObject m_BasePrefab; + + [SerializeField] + ActionMap m_ActionMap; + + [SerializeField] + HapticPulse m_ButtonClickPulse; + + [SerializeField] + HapticPulse m_ButtonHoverPulse; + + [SerializeField] + HapticPulse m_ResizePulse; + + [SerializeField] + HapticPulse m_MovePulse; + + [SerializeField] + GameObject m_ContentPrefab; + + [SerializeField] + GameObject m_SliderPrefab; + } +#endif +} +#endif diff --git a/Workspaces/PolyWorkspace/PolyWorkspace.cs.meta b/Workspaces/PolyWorkspace/PolyWorkspace.cs.meta new file mode 100644 index 000000000..4ba0c46f3 --- /dev/null +++ b/Workspaces/PolyWorkspace/PolyWorkspace.cs.meta @@ -0,0 +1,28 @@ +fileFormatVersion: 2 +guid: 961e8cd46fb66f24386c3a139fd31265 +timeCreated: 1511078187 +licenseType: Pro +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_BasePrefab: {fileID: 1000011022840156, guid: 3a2153f70c365c540a3703c4cf22bc45, + type: 2} + - m_ActionMap: {fileID: 11400000, guid: 0a408a921faf5724492272bab472326f, type: 2} + - m_ButtonClickPulse: {fileID: 11400000, guid: 43f6d76e312f45145bc1ef9af446edfe, + type: 2} + - m_ButtonHoverPulse: {fileID: 11400000, guid: bf8c18d5dc5c90f4aa0782421bbaaf0e, + type: 2} + - m_ResizePulse: {fileID: 11400000, guid: daa1fd8c3e222aa4db108e0a2b0f7a7d, type: 2} + - m_MovePulse: {fileID: 11400000, guid: 83427d10dc20237408e0246b4b672682, type: 2} + - m_ContentPrefab: {fileID: 1000010661511152, guid: b419cb0d10c5da54b9bd9a557c3978ae, + type: 2} + - m_FilterUIPrefab: {fileID: 1000011003453154, guid: 02743e4708990fd43adb43911cb8fb26, + type: 2} + - m_SliderPrefab: {fileID: 1000011177834630, guid: 41f89a1e8d8d49f4f861f7cb581c1227, + type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Models/Vive/Models/body.mtl.meta b/Workspaces/PolyWorkspace/Prefabs.meta similarity index 58% rename from Models/Vive/Models/body.mtl.meta rename to Workspaces/PolyWorkspace/Prefabs.meta index 96e6bffb1..2f937066d 100644 --- a/Models/Vive/Models/body.mtl.meta +++ b/Workspaces/PolyWorkspace/Prefabs.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 -guid: 7a2d4a15a7c7a1148ac269365748a334 -timeCreated: 1507075387 +guid: f643ed1417c5d714391529d36bd55763 +folderAsset: yes +timeCreated: 1504908721 licenseType: Pro DefaultImporter: userData: diff --git a/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab b/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab new file mode 100644 index 000000000..baf5118e9 --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab @@ -0,0 +1,424 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1000011664971740} + m_IsPrefabParent: 1 +--- !u!1 &1000010032005098 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000013482272966} + - component: {fileID: 222000013436926836} + - component: {fileID: 114000013254149160} + - component: {fileID: 114099970811118152} + m_Layer: 5 + m_Name: TextBg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000010208401484 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000010255316478} + - component: {fileID: 222000012941897208} + - component: {fileID: 114730833999572488} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011664971740 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000013187928610} + - component: {fileID: 114000013101132712} + - component: {fileID: 114000013399222220} + - component: {fileID: 222000011971560006} + - component: {fileID: 114000012094917522} + - component: {fileID: 114336130626859894} + m_Layer: 5 + m_Name: FilterButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &114000012094917522 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114000013101132712 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 61c8087a6302b684e85cb58549f41066, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Button: {fileID: 114000013399222220} + m_EyePanel: {fileID: 0} + m_Eye: {fileID: 0} + m_TextPanel: {fileID: 114000013254149160} + m_Text: {fileID: 114730833999572488} +--- !u!114 &114000013254149160 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010032005098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} + m_Color: {r: 0.101960786, g: 0.101960786, b: 0.101960786, a: 0.94509804} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114000013399222220 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c75e541e7d7e17f40b6aae5dd949e157, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 0 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 114000012094917522} + m_OnClick: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SelectionFlags: 3 + onEnter: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + onExit: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + onDown: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + onUp: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &114099970811118152 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010032005098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 1 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!114 &114336130626859894 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: -1 + m_FlexibleWidth: 1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!114 &114730833999572488 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010208401484} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: All/None with some overflow + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.014 + m_fontSizeBase: 0.014 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 513 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_firstOverflowCharacterIndex: -1 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114730833999572488} + characterCount: 16 + spriteCount: 0 + spaceCount: 2 + wordCount: 4 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &222000011971560006 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} +--- !u!222 &222000012941897208 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010208401484} +--- !u!222 &222000013436926836 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010032005098} +--- !u!224 &224000010255316478 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010208401484} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224000013482272966} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.00192, y: -0.00011} + m_SizeDelta: {x: 0.105, y: 0.02} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224000013187928610 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011664971740} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000013482272966} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: -0.5, y: -0.45} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224000013482272966 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010032005098} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000010255316478} + m_Father: {fileID: 224000013187928610} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: -0.015000005} + m_SizeDelta: {x: 0.12, y: 0.03} + m_Pivot: {x: 0, y: 0.5} diff --git a/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab.meta b/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab.meta new file mode 100644 index 000000000..8bf472760 --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/FilterButton.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 407b37a21eeed774f9037627e0b983c4 +timeCreated: 1472762484 +licenseType: Pro +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab b/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab new file mode 100644 index 000000000..576071716 --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab @@ -0,0 +1,1265 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1000011003453154} + m_IsPrefabParent: 1 +--- !u!1 &1000010336788726 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000012846441888} + - component: {fileID: 222000013708054270} + - component: {fileID: 114000011492943456} + - component: {fileID: 114000010404580652} + m_Layer: 5 + m_Name: Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000010508801244 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4267353158915280} + m_Layer: 5 + m_Name: TooltipSource + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011003453154 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000011986940760} + - component: {fileID: 114000010697686692} + m_Layer: 5 + m_Name: FilterUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011014807798 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000011291863102} + - component: {fileID: 33000011345001038} + - component: {fileID: 23000011039186558} + m_Layer: 0 + m_Name: BackgroundMesh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011598381904 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000010705424688} + - component: {fileID: 114000012214752062} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011609924910 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000013333582342} + - component: {fileID: 114000013631895690} + - component: {fileID: 114000012445660226} + - component: {fileID: 225000014235020344} + m_Layer: 5 + m_Name: ButtonList + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!1 &1000011663923998 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000013690042288} + - component: {fileID: 222000010729594934} + - component: {fileID: 114000012308107684} + - component: {fileID: 114000011143325692} + m_Layer: 5 + m_Name: CloseButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011788878884 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000013947219512} + - component: {fileID: 222000010645976992} + - component: {fileID: 114518685845511386} + m_Layer: 5 + m_Name: Description + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000011849677544 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000010866448056} + - component: {fileID: 225000010025708586} + - component: {fileID: 114441283146293506} + m_Layer: 5 + m_Name: ButtonsContainer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000012133731784 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000011653624854} + - component: {fileID: 114000010158068876} + - component: {fileID: 225000013559454362} + - component: {fileID: 114000011811000892} + m_Layer: 5 + m_Name: SummaryButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000012583667622 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224000010366256770} + - component: {fileID: 222000011540912930} + - component: {fileID: 114408092455480224} + m_Layer: 5 + m_Name: Summary + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1000012599563970 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4000010181320156} + - component: {fileID: 33000013494617214} + - component: {fileID: 23000010134553482} + m_Layer: 0 + m_Name: ButtonMesh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1193717129972310 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224063822735215512} + - component: {fileID: 222422492707105604} + - component: {fileID: 114310412869207340} + - component: {fileID: 114746809633966926} + m_Layer: 5 + m_Name: Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1343572776259684 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224530730319996344} + m_Layer: 5 + m_Name: ButtonListContainer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1574889629579100 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4810109964590046} + m_Layer: 5 + m_Name: TooltipTarget + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1824866865475994 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224765274623983058} + m_Layer: 5 + m_Name: IconContainer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4000010181320156 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012599563970} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -0.000000057041493, z: -0.00000008218965} + m_LocalScale: {x: 7.5641837, y: 2.503347, z: 1} + m_Children: + - {fileID: 4810109964590046} + - {fileID: 4267353158915280} + m_Father: {fileID: 4000011653624854} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4000010705424688 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011598381904} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0.13224973, y: 0.44703272, z: 0.17524552} + m_LocalScale: {x: 0.42500004, y: 0.3500007, z: 0.70000035} + m_Children: + - {fileID: 4000011291863102} + m_Father: {fileID: 224000013333582342} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4000011291863102 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011014807798} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.055} + m_LocalScale: {x: 51, y: 51, z: 4} + m_Children: [] + m_Father: {fileID: 4000010705424688} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4000011653624854 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012133731784} + m_LocalRotation: {x: -0, y: -0, z: -7.251184e-18, w: 1} + m_LocalPosition: {x: 0, y: 0.00000003331204, z: -0.000000077919545} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224765274623983058} + - {fileID: 4000010181320156} + m_Father: {fileID: 224000010866448056} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4267353158915280 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010508801244} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -0.01, z: 0} + m_LocalScale: {x: 1.0000013, y: 1.0000013, z: 1} + m_Children: [] + m_Father: {fileID: 4000010181320156} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4810109964590046 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1574889629579100} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: -0.03, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4000010181320156} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &23000010134553482 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012599563970} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_Materials: + - {fileID: 2100000, guid: 9a5391a306f086742a2f0d1088c296ed, type: 2} + - {fileID: 2100000, guid: e1423c0176008a841a94b94a6034bbf8, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!23 &23000011039186558 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011014807798} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_Materials: + - {fileID: 2100000, guid: 5288f1f01d802a6448aa792c60a0d7d0, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &33000011345001038 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011014807798} + m_Mesh: {fileID: 4300000, guid: 97e633ff61f95564f8eca8139321b9a1, type: 3} +--- !u!33 &33000013494617214 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012599563970} + m_Mesh: {fileID: 4300000, guid: 778451e1d0bcdba4aa329586e9d8146e, type: 3} +--- !u!114 &114000010158068876 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012133731784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4ea8f288a8eeaef46b1f6bfb72debc2a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_AutoHighlight: 1 + m_CustomHighlightColor: {r: 0.101960786, g: 0.101960786, b: 0.101960786, a: 1} + m_AlternateIconSprite: {fileID: 0} + m_ButtonMeshRenderer: {fileID: 23000010134553482} + m_CanvasGroup: {fileID: 225000013559454362} + m_Icon: {fileID: 0} + m_IconContainer: {fileID: 224765274623983058} + m_Button: {fileID: 114310412869207340} + m_SwapIconsOnClick: 0 + m_HighlightItems: + - {fileID: 0} + - {fileID: 0} + m_GrayscaleGradient: 0 + m_AnimatedReveal: 1 + m_DelayBeforeReveal: 0.125 +--- !u!114 &114000010404580652 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010336788726} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 114000011492943456} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 114000010697686692} + m_MethodName: SetListVisibility + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 1 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &114000010697686692 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011003453154} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6ce73cffb6071a94e84ff5b160100080, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SummaryText: {fileID: 114408092455480224} + m_DescriptionText: {fileID: 114518685845511386} + m_ButtonList: {fileID: 224000013333582342} + m_ButtonPrefab: {fileID: 1000011664971740, guid: 407b37a21eeed774f9037627e0b983c4, + type: 2} + m_ActiveColor: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 1} + m_DisableColor: {r: 0.50371873, g: 0.5137931, b: 0.5137931, a: 1} + m_CanvasGroup: {fileID: 225000010025708586} + m_ButtonListGrid: {fileID: 114000013631895690} + m_ButtonListCanvasGroup: {fileID: 225000014235020344} + m_Background: {fileID: 23000011039186558} + m_VisibilityButton: {fileID: 0} + m_SummaryButton: {fileID: 114000010158068876} +--- !u!114 &114000011143325692 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011663923998} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1679637790, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 1 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!114 &114000011492943456 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010336788726} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 21300000, guid: 8f21106ed0539b64ca132508f61ed30b, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114000011811000892 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012133731784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 121a9b94e41e9e444af3e8069a887154, type: 3} + m_Name: + m_EditorClassIdentifier: + m_TooltipText: Filter by Type + m_TooltipTarget: {fileID: 4810109964590046} + m_TooltipSource: {fileID: 4267353158915280} + m_TooltipAlignment: 1 +--- !u!114 &114000012214752062 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011598381904} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 08eb1a78fb9eff94e939fef2d709ac04, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SourceRectTransform: {fileID: 224000013333582342} + m_XPositionPadding: 0 + m_YPositionPadding: 0 + m_ZPositionPadding: 0.04 + m_XScalePadding: 0.01 + m_YScalePadding: 0 + m_ParentUnderSource: 1 +--- !u!114 &114000012308107684 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011663923998} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: a8930be3d3835af44ab7343980dc74ad, type: 2} + m_Color: {r: 0.19607843, g: 0.2, b: 0.2, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114000012445660226 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011609924910} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741964061, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 1 + m_VerticalFit: 2 +--- !u!114 &114000013631895690 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011609924910} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -2095666955, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 1 + m_StartCorner: 0 + m_StartAxis: 1 + m_CellSize: {x: 0.12, y: 0.03} + m_Spacing: {x: 0, y: 0.0015} + m_Constraint: 1 + m_ConstraintCount: 1 +--- !u!114 &114310412869207340 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1193717129972310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 0 + m_Colors: + m_NormalColor: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 1} + m_HighlightedColor: {r: 0.101960786, g: 0.101960786, b: 0.101960786, a: 1} + m_PressedColor: {r: 0.19607843, g: 0.2, b: 0.2, a: 1} + m_DisabledColor: {r: 0.9607843, g: 0.972549, b: 0.9764706, a: 0.2509804} + m_ColorMultiplier: 1 + m_FadeDuration: 0.25 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 114746809633966926} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 114000010697686692} + m_MethodName: SetListVisibility + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 1 + m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!114 &114408092455480224 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012583667622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: View all + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.02 + m_fontSizeBase: 0.02 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 513 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: 0 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0.000055372133, z: -0.000009955811, w: 0.000015010124} + m_textInfo: + textComponent: {fileID: 114408092455480224} + characterCount: 8 + spriteCount: 0 + spaceCount: 1 + wordCount: 2 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &114441283146293506 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011849677544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: 0 + m_MinHeight: 0 + m_PreferredWidth: 100 + m_PreferredHeight: 100 + m_FlexibleWidth: 1 + m_FlexibleHeight: 1 + m_LayoutPriority: 1 +--- !u!114 &114518685845511386 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011788878884} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: All types of objects are visible + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 76ff077e92eb4fe41aa26173a3d98fb6, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 54d3f6429fd638b4d9ca906c1354d050, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.01 + m_fontSizeBase: 0.01 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 257 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: -1 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114518685845511386} + characterCount: 32 + spriteCount: 0 + spaceCount: 5 + wordCount: 6 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &114746809633966926 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1193717129972310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!222 &222000010645976992 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011788878884} +--- !u!222 &222000010729594934 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011663923998} +--- !u!222 &222000011540912930 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012583667622} +--- !u!222 &222000013708054270 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010336788726} +--- !u!222 &222422492707105604 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1193717129972310} +--- !u!224 &224000010366256770 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012583667622} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224765274623983058} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.0701, y: 0.0046} + m_SizeDelta: {x: 0.14102, y: 0.02027} + m_Pivot: {x: 0, y: 0.5} +--- !u!224 &224000010866448056 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011849677544} + m_LocalRotation: {x: -0, y: -0, z: -7.251184e-18, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.0010000002} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4000011653624854} + m_Father: {fileID: 224000011986940760} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0.1512, y: 0.05} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224000011986940760 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011003453154} + m_LocalRotation: {x: 0.00000008940696, y: 0.000000007531685, z: 8.5815555e-10, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000010866448056} + - {fileID: 224530730319996344} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0.1482, y: 0} + m_SizeDelta: {x: 0.1512, y: 0.05} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224000012846441888 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000010336788726} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.0009999275} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224000013690042288} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 4.5229305e-23, y: 0} + m_SizeDelta: {x: 0.05, y: 0.05} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224000013333582342 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011609924910} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -1.138} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000013690042288} + - {fileID: 4000010705424688} + m_Father: {fileID: 224530730319996344} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0.000001706183, y: 0} + m_SizeDelta: {x: -99.880005, y: 0} + m_Pivot: {x: 0.5, y: 0} +--- !u!224 &224000013690042288 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011663923998} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000012846441888} + m_Father: {fileID: 224000013333582342} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0.15890121, y: 0} + m_SizeDelta: {x: 0.05, y: 0.05} + m_Pivot: {x: 0.5, y: 1} +--- !u!224 &224000013947219512 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011788878884} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224765274623983058} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.00041122, y: -0.01057} + m_SizeDelta: {x: 0.14102, y: 0.01393} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224063822735215512 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1193717129972310} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224765274623983058} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0.1512, y: 0.049968} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224530730319996344 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1343572776259684} + m_LocalRotation: {x: -0, y: -0, z: -7.251184e-18, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0.15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000013333582342} + m_Father: {fileID: 224000011986940760} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.0000000083819, y: 0.0000000023283} + m_SizeDelta: {x: 0.1512, y: 0.05} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224765274623983058 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1824866865475994} + m_LocalRotation: {x: -0, y: -0, z: 7.251184e-18, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224000010366256770} + - {fileID: 224000013947219512} + - {fileID: 224063822735215512} + m_Father: {fileID: 4000011653624854} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.00003, y: 0.000032} + m_SizeDelta: {x: 0.1512, y: 0.049968} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!225 &225000010025708586 +CanvasGroup: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011849677544} + m_Enabled: 1 + m_Alpha: 1 + m_Interactable: 1 + m_BlocksRaycasts: 1 + m_IgnoreParentGroups: 0 +--- !u!225 &225000013559454362 +CanvasGroup: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000012133731784} + m_Enabled: 1 + m_Alpha: 1 + m_Interactable: 1 + m_BlocksRaycasts: 1 + m_IgnoreParentGroups: 0 +--- !u!225 &225000014235020344 +CanvasGroup: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1000011609924910} + m_Enabled: 1 + m_Alpha: 1 + m_Interactable: 1 + m_BlocksRaycasts: 1 + m_IgnoreParentGroups: 0 diff --git a/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab.meta b/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab.meta new file mode 100644 index 000000000..be24b8c17 --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/FilterUI.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 02743e4708990fd43adb43911cb8fb26 +timeCreated: 1472243742 +licenseType: Pro +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab b/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab new file mode 100644 index 000000000..76a33a685 --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab @@ -0,0 +1,380 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1120077170014744} + m_IsPrefabParent: 1 +--- !u!1 &1120077170014744 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4829068277204254} + - component: {fileID: 114010240193939082} + - component: {fileID: 65849786678441232} + - component: {fileID: 114952149326489544} + m_Layer: 0 + m_Name: PolyGridItem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1234179680900500 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224628885176571246} + - component: {fileID: 222505867373165040} + - component: {fileID: 114648639881106846} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1644338248129450 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224029013077951842} + - component: {fileID: 222622958392439364} + - component: {fileID: 114417040511043732} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1797739298096832 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4629492376652418} + - component: {fileID: 33857985333396578} + - component: {fileID: 23147992908279880} + m_Layer: 0 + m_Name: PreviewCube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4629492376652418 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1797739298096832} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 0.5, z: 1} + m_Children: [] + m_Father: {fileID: 4829068277204254} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4829068277204254 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1120077170014744} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4629492376652418} + - {fileID: 224029013077951842} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &23147992908279880 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1797739298096832} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: d7eb5f17472593743b1dfc33914d425a, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &33857985333396578 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1797739298096832} + m_Mesh: {fileID: 4300000, guid: 65a5ef1e9b0c30546bcafdadb3b521eb, type: 3} +--- !u!65 &65849786678441232 +BoxCollider: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1120077170014744} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0.5, z: 0} +--- !u!114 &114010240193939082 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1120077170014744} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4e40f52fad02674faece487e85b34e6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Text: {fileID: 114648639881106846} + m_Handle: {fileID: 114952149326489544} + m_TextPanel: {fileID: 114417040511043732} + m_Icon: {fileID: 1797739298096832} + m_ImportingTargetColor: {r: 0.011764706, g: 0.6627451, b: 0.95686275, a: 1} + m_PreviewObjectTransform: {fileID: 0} +--- !u!114 &114417040511043732 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1644338248129450} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: dec2d25be9058334c91a0402762efa61, type: 2} + m_Color: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114648639881106846 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1234179680900500} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1453722849, guid: 89f0137620f6af44b9ba852b4190e64e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_text: Test text with overflow + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: ea721564999c75441b5b3aa01ae88f76, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 5be343b145ab9dd42821b06c75f9a60c, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 0.12 + m_fontSizeBase: 0.12 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 514 + m_isAlignmentEnumConverted: 1 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_firstOverflowCharacterIndex: -1 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 114648639881106846} + characterCount: 18 + spriteCount: 0 + spaceCount: 3 + wordCount: 4 + linkCount: 0 + lineCount: 1 + pageCount: 1 + materialCount: 1 + m_havePropertiesChanged: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_isInputParsingRequired: 1 + m_inputSource: 0 + m_hasFontAssetChanged: 0 + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &114952149326489544 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1120077170014744} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4fb8f7696afa96048aa938286d04f96c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SelectionFlags: 3 +--- !u!222 &222505867373165040 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1234179680900500} +--- !u!222 &222622958392439364 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1644338248129450} +--- !u!224 &224029013077951842 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1644338248129450} + m_LocalRotation: {x: 0.38268343, y: -0, z: -0, w: 0.92387956} + m_LocalPosition: {x: 0, y: 0, z: 0.579} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224628885176571246} + m_Father: {fileID: 4829068277204254} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -0.49350005, y: 0.871} + m_SizeDelta: {x: 0.98700005, y: 0.177} + m_Pivot: {x: 0, y: 0.5} +--- !u!224 &224628885176571246 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1234179680900500} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.00000059005106} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 224029013077951842} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.00059413165} + m_SizeDelta: {x: 0, y: 0.2} + m_Pivot: {x: 0.5, y: 0.49987867} diff --git a/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab.meta b/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab.meta new file mode 100644 index 000000000..be97df9ea --- /dev/null +++ b/Workspaces/PolyWorkspace/Prefabs/PolyGridItem.prefab.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 618b5d52a53fb1141b25899666a4721d +timeCreated: 1504908729 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts.meta b/Workspaces/PolyWorkspace/Scripts.meta new file mode 100644 index 000000000..47c26fdbc --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 28dea0687c24dd942b5d2f083ae3126a +folderAsset: yes +timeCreated: 1471988368 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs b/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs new file mode 100644 index 000000000..544071c02 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs @@ -0,0 +1,150 @@ +#if UNITY_EDITOR +using System; +using UnityEditor.Experimental.EditorVR; +using UnityEngine; +using ListView; + +#if INCLUDE_POLY_TOOLKIT +using PolyToolkit; +#endif + +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + public class PolyGridAsset : ListViewItemData, IWeb + { + const int k_MaxPreviewComplexity = 2500; + +#if INCLUDE_POLY_TOOLKIT + static PolyImportOptions s_Options; +#else +#pragma warning disable 649 +#endif + + readonly PolyAsset m_Asset; + readonly Transform m_Container; // Parent object under which to store imported prefabs--should be cleared on reset + readonly long m_Complexity; // Cached to avoid loop lookup + + GameObject m_Prefab; + Texture2D m_Thumbnail; + bool m_Initialized; // Whether the download/import process has started + bool m_Importing; + + public PolyAsset asset { get { return m_Asset; } } + public GameObject prefab { get { return m_Prefab; } } + public Texture2D thumbnail { get { return m_Thumbnail; } } + public bool initialized { get { return m_Initialized; } } + public long complexity { get { return m_Complexity; } } + public override string index { get { return m_Asset.name; } } + + public event Action modelImportCompleted; + public event Action thumbnailImportCompleted; + +#if INCLUDE_POLY_TOOLKIT + static PolyGridAsset() + { + s_Options = PolyImportOptions.Default(); + s_Options.rescalingMode = PolyImportOptions.RescalingMode.FIT; + s_Options.desiredSize = 1.0f; + s_Options.recenter = true; + } +#endif + + public PolyGridAsset(PolyAsset asset, Transform container) + { +#if INCLUDE_POLY_TOOLKIT + m_Asset = asset; + m_Container = container; + m_Complexity = 0L; + foreach (var format in asset.formats) + { + m_Complexity = Math.Max(m_Complexity, format.formatComplexity.triangleCount); + } +#endif + + template = "PolyGridItem"; + } + + public void Initialize() + { +#if INCLUDE_POLY_TOOLKIT + m_Initialized = true; + + GetThumbnail(); + + if (m_Complexity < k_MaxPreviewComplexity) + ImportModel(); +#endif + } + + public void ImportModel() + { +#if INCLUDE_POLY_TOOLKIT + if (m_Prefab == null && !m_Importing) + PolyApi.Import(asset, s_Options, ImportAssetCallback); + + m_Importing = true; +#endif + } + +#if INCLUDE_POLY_TOOLKIT + // Callback invoked when an asset has just been imported. + void ImportAssetCallback(PolyAsset asset, PolyStatusOr result) + { + m_Importing = false; + if (!result.Ok) + { + Debug.LogError("Failed to import asset. :( Reason: " + result.Status); + return; + } + + var importedAsset = result.Value.gameObject; + importedAsset.transform.parent = m_Container; + importedAsset.SetActive(false); + m_Prefab = importedAsset; + m_Prefab.name = asset.displayName; + + if (modelImportCompleted != null) + modelImportCompleted(this, m_Prefab); + } + + void GetThumbnail() + { + var thumbnail = m_Asset.thumbnail; + if (thumbnail == null) + return; + + this.DownloadTexture(thumbnail.url, handler => + { + m_Thumbnail = handler.texture; + if (m_Thumbnail == null) + return; + + m_Thumbnail.wrapMode = TextureWrapMode.Clamp; + + if (thumbnailImportCompleted != null) + thumbnailImportCompleted(this, m_Thumbnail); + }); + } +#endif + } + +#if !INCLUDE_POLY_TOOLKIT + // Stub classes to avoid too many #ifs + public class PolyAsset + { + public string name; + public string displayName; + public PolyThumbnail thumbnail; + } + + public class PolyThumbnail + { + public string url; + } +#else + #pragma warning restore 618 +#endif +} +#endif diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs.meta b/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs.meta new file mode 100644 index 000000000..f4f323f5e --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridAsset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 75cf61a1d1c5fe449b8a5157c90ebfd8 +timeCreated: 1504905447 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs b/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs new file mode 100644 index 000000000..9f93d2628 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs @@ -0,0 +1,538 @@ +#if UNITY_EDITOR +using System; +using System.Collections; +using UnityEditor.Experimental.EditorVR.Core; +using UnityEditor.Experimental.EditorVR.Extensions; +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEditor.Experimental.EditorVR.Helpers; +using UnityEditor.Experimental.EditorVR.Proxies; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; +using UnityEngine.InputNew; +using UnityEngine.UI; + +#if INCLUDE_TEXT_MESH_PRO +using TMPro; +#endif + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + class PolyGridItem : DraggableListItem, IPlaceSceneObject, IUsesSpatialHash, + IUsesViewerBody, IRayVisibilitySettings, IRequestFeedback, IUsesGrouping, IControlHaptics + { + const float k_PreviewDuration = 0.1f; + const float k_MinPreviewScale = 0.01f; + const float k_IconPreviewScale = 0.1f; + const float k_MaxPreviewScale = 0.2f; + const float k_TransitionDuration = 0.1f; + const float k_ScaleBump = 0.1f; + const float k_ThumbnailScaleBump = -0.1f; + const float k_ThumbnailOffsetBump = k_ThumbnailScaleBump * -0.5f; + const float k_ImportingScaleBump = 0.375f; + + const float k_InitializeDelay = 0.5f; // Delay initialization for fast scrolling + + const int k_AutoHidePreviewComplexity = 10000; + +#if INCLUDE_TEXT_MESH_PRO + [SerializeField] + TextMeshProUGUI m_Text; +#else + [SerializeField] + Text m_Text; +#endif + + [SerializeField] + BaseHandle m_Handle; + + [SerializeField] + Image m_TextPanel; + + [SerializeField] + GameObject m_Icon; + + [SerializeField] + Color m_ImportingTargetColor; + + [HideInInspector] + [SerializeField] // Serialized so that this remains set after cloning + Transform m_PreviewObjectTransform; + + bool m_Setup; + bool m_AutoHidePreview; + Vector3 m_PreviewPrefabScale; + Vector3 m_PreviewTargetScale; + Vector3 m_PreviewPivotOffset; + Bounds m_PreviewBounds; + Transform m_PreviewObjectClone; + Material m_IconMaterial; + Vector3 m_IconScale; + + bool m_Hovered; + bool m_WasHovered; + float m_HoverTime; + float m_HoverLerpStart; + float m_HoverLerp; + + bool m_Importing; + bool m_WasImporting; + float m_ImportingTime; + float m_ImportingStartScale; + float m_ImportingScale; + + Color m_ImportingDefaultColor; + Color m_ImportingStartColor; + Color m_ImportingColor; + + Coroutine m_VisibilityCoroutine; + + float m_SetupTime = float.MaxValue; + + public float scaleFactor { private get; set; } + + // Local method use only -- created here to reduce garbage collection + Action m_CompleteHoverTransition; + Action m_SetThumbnailScale; + Action m_SetImportingScale; + + Action m_SetImportingColor; + + void Awake() + { + m_CompleteHoverTransition = CompleteHoverTransition; + m_SetThumbnailScale = SetThumbnailScale; + m_SetImportingScale = SetImportingScale; + + m_SetImportingColor = SetImportingColor; + } + + public override void Setup(PolyGridAsset listData) + { + base.Setup(listData); + + // First time setup + if (!m_Setup) + { + m_IconScale = m_Icon.transform.localScale; + + m_ImportingDefaultColor = m_TextPanel.color; + + m_Handle.dragStarted += OnDragStarted; + m_Handle.dragging += OnDragging; + m_Handle.dragEnded += OnDragEnded; + + m_Handle.hoverStarted += OnHoverStarted; + m_Handle.hoverEnded += OnHoverEnded; + + m_IconMaterial = MaterialUtils.GetMaterialClone(m_Icon.GetComponent()); + + m_Setup = true; + } + + m_Hovered = false; + m_WasHovered = false; + m_HoverLerpStart = 1f; + m_HoverLerp = 1f; + + m_Importing = false; + m_WasImporting = false; + m_ImportingStartScale = m_IconScale.y; + m_ImportingScale = m_ImportingStartScale; + + m_ImportingStartColor = m_ImportingDefaultColor; + m_ImportingColor = m_ImportingStartColor; + + m_VisibilityCoroutine = null; + m_Icon.transform.localScale = m_IconScale; + m_IconMaterial.mainTexture = null; + + if (m_PreviewObjectTransform) + ObjectUtils.Destroy(m_PreviewObjectTransform.gameObject); + + m_SetupTime = Time.time; + UpdateRepresentation(); + } + + void OnModelImportCompleted(PolyGridAsset gridAsset, GameObject prefab) + { + m_Importing = false; + UpdateRepresentation(); + } + + void OnThumbnailImportCompleted(PolyGridAsset gridAsset, Texture2D thumbnail) + { + UpdateRepresentation(); + } + + void UpdateRepresentation() + { + if (!m_Icon) // Prevent MissingReferenceException if shutdown occurs while fetching thumbnails + return; + + m_Text.text = data.asset.displayName; + + if (!m_PreviewObjectTransform && data.prefab) + { + m_Icon.SetActive(false); + InstantiatePreview(); + } + + m_Icon.SetActive(!m_PreviewObjectTransform || m_AutoHidePreview); + + if (m_IconMaterial.mainTexture == null && data.thumbnail) + m_IconMaterial.mainTexture = data.thumbnail; + } + + public void UpdateTransforms(float scale) + { + if (Time.time - m_SetupTime > k_InitializeDelay) + { + m_SetupTime = float.MaxValue; + + // If this AssetData hasn't started fetching its asset yet, do so now + if (!data.initialized) + data.Initialize(); + + data.modelImportCompleted += OnModelImportCompleted; + data.thumbnailImportCompleted += OnThumbnailImportCompleted; + } + + // Don't scale the item while changing visibility because this would conflict with AnimateVisibility + if (m_VisibilityCoroutine != null) + return; + + var time = Time.time; + + TransitionUtils.AnimateProperty(time, m_Hovered, ref m_WasHovered, ref m_HoverTime, ref m_HoverLerp, + ref m_HoverLerpStart, 0f, 1f, k_PreviewDuration, Mathf.Approximately, TransitionUtils.GetPercentage, + Mathf.Lerp, m_SetThumbnailScale, true, m_CompleteHoverTransition); + + TransitionUtils.AnimateProperty(time, m_Importing, ref m_WasImporting, ref m_ImportingTime, + ref m_ImportingScale, ref m_ImportingStartScale, m_IconScale.y, k_ImportingScaleBump, k_PreviewDuration, + Mathf.Approximately, TransitionUtils.GetPercentage, Mathf.Lerp, m_SetImportingScale, false); + + TransitionUtils.AnimateProperty(time, m_Importing, ref m_WasImporting, ref m_ImportingTime, + ref m_ImportingColor, ref m_ImportingStartColor, m_ImportingDefaultColor, m_ImportingTargetColor, + k_PreviewDuration, TransitionUtils.Approximately, TransitionUtils.GetPercentage, Color.Lerp, + m_SetImportingColor); + + scaleFactor = scale; + + transform.localScale = Vector3.one * scale; + + m_TextPanel.transform.localRotation = CameraUtils.LocalRotateTowardCamera(transform.parent); + } + + void SetThumbnailScale(float lerp) + { + if (m_PreviewObjectTransform) + { + if (m_AutoHidePreview) + { + m_PreviewObjectTransform.localScale = lerp * Vector3.one; + m_Icon.transform.localScale = (1 - lerp) * m_IconScale; + } + else + { + m_PreviewObjectTransform.localScale = Vector3.one + lerp * Vector3.one * k_ScaleBump; + } + + return; + } + + m_IconMaterial.mainTextureOffset = lerp * Vector3.one * k_ThumbnailOffsetBump; + m_IconMaterial.mainTextureScale = Vector3.one + lerp * Vector3.one * k_ThumbnailScaleBump; + } + + void CompleteHoverTransition(float lerp) + { + if (m_PreviewObjectTransform && m_AutoHidePreview) + { + m_PreviewObjectTransform.gameObject.SetActive(lerp != 0); + m_Icon.SetActive(lerp == 0); + } + } + + void SetImportingScale(float scale) + { + var transform = m_Icon.transform; + var localScale = transform.localScale; + localScale.y = scale; + transform.localScale = localScale; + } + + void SetImportingColor(Color color) + { + m_TextPanel.color = color; + } + + void InstantiatePreview() + { + if (!data.prefab) + return; + + var previewObject = Instantiate(data.prefab); + previewObject.SetActive(true); + m_PreviewObjectTransform = previewObject.transform; + + m_PreviewObjectTransform.position = Vector3.zero; + m_PreviewObjectTransform.rotation = Quaternion.identity; + + m_PreviewPrefabScale = m_PreviewObjectTransform.localScale; + + // Normalize total scale to 1 + m_PreviewBounds = ObjectUtils.GetBounds(m_PreviewObjectTransform); + + // Don't show a preview if there are no renderers + if (m_PreviewBounds.size == Vector3.zero) + { + ObjectUtils.Destroy(previewObject); + return; + } + + m_PreviewPivotOffset = m_PreviewObjectTransform.position - m_PreviewBounds.center; + m_PreviewObjectTransform.SetParent(transform, false); + + var maxComponent = m_PreviewBounds.size.MaxComponent(); + var scaleFactor = 1 / maxComponent; + m_PreviewTargetScale = m_PreviewPrefabScale * scaleFactor; + m_PreviewObjectTransform.localPosition = m_PreviewPivotOffset * scaleFactor + Vector3.up * 0.5f; + + var complexity = data.complexity; + // Auto hide previews over a smaller vert count + if (complexity > k_AutoHidePreviewComplexity) + { + m_AutoHidePreview = true; + m_PreviewObjectTransform.localScale = Vector3.zero; + } + else + { + m_PreviewObjectTransform.localScale = Vector3.one; + m_Icon.SetActive(false); + } + } + + protected override void OnDragStarted(BaseHandle handle, HandleEventData eventData) + { + if (data.prefab) + { + base.OnDragStarted(handle, eventData); + + var rayOrigin = eventData.rayOrigin; + this.AddRayVisibilitySettings(rayOrigin, this, false, true); + + var clone = Instantiate(gameObject, transform.position, transform.rotation, transform.parent); + var cloneItem = clone.GetComponent(); + + if (cloneItem.m_PreviewObjectTransform) + { + m_PreviewObjectClone = cloneItem.m_PreviewObjectTransform; + cloneItem.m_Icon.gameObject.SetActive(false); + + m_PreviewObjectClone.gameObject.SetActive(true); + m_PreviewObjectClone.localScale = m_PreviewTargetScale; + + // Destroy label + ObjectUtils.Destroy(cloneItem.m_TextPanel.gameObject); + } + + m_DragObject = clone.transform; + + // Disable any SmoothMotion that may be applied to a cloned Asset Grid Item now referencing input device p/r/s + var smoothMotion = clone.GetComponent(); + if (smoothMotion != null) + smoothMotion.enabled = false; + + StartCoroutine(ShowGrabbedObject()); + } + } + + protected override void OnDragEnded(BaseHandle handle, HandleEventData eventData) + { + if (data.prefab) + { + var gridItem = m_DragObject.GetComponent(); + + var rayOrigin = eventData.rayOrigin; + this.RemoveRayVisibilitySettings(rayOrigin, this); + + if (!this.IsOverShoulder(eventData.rayOrigin)) + { + var previewObject = gridItem.m_PreviewObjectTransform; + if (previewObject) + { + this.MakeGroup(previewObject.gameObject); + this.PlaceSceneObject(previewObject, m_PreviewPrefabScale); + } + } + + StartCoroutine(HideGrabbedObject(m_DragObject.gameObject)); + } + else + { + data.ImportModel(); + m_Text.text = "Importing..."; + m_Importing = true; + } + + base.OnDragEnded(handle, eventData); + } + + void OnHoverStarted(BaseHandle handle, HandleEventData eventData) + { + base.OnHoverStart(handle, eventData); + + m_Hovered = true; + + ShowGrabFeedback(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); + } + + void OnHoverEnded(BaseHandle handle, HandleEventData eventData) + { + base.OnHoverEnd(handle, eventData); + + m_Hovered = false; + + HideGrabFeedback(); + } + + public void SetVisibility(bool visible, Action callback = null) + { + this.RestartCoroutine(ref m_VisibilityCoroutine, AnimateVisibility(visible, callback)); + } + + IEnumerator AnimateVisibility(bool visible, Action callback) + { + var currentTime = 0f; + + // Item should always be at a scale of zero before becoming visible + if (visible) + { + transform.localScale = Vector3.zero; + } + else + { + data.modelImportCompleted -= OnModelImportCompleted; + data.thumbnailImportCompleted -= OnThumbnailImportCompleted; + } + + var currentScale = transform.localScale; + var targetScale = visible ? m_IconScale * scaleFactor : Vector3.zero; + + while (currentTime < k_TransitionDuration) + { + currentTime += Time.deltaTime; + transform.localScale = Vector3.Lerp(currentScale, targetScale, currentTime / k_TransitionDuration); + yield return null; + } + + transform.localScale = targetScale; + + if (callback != null) + callback(this); + + m_VisibilityCoroutine = null; + } + + // Animate the LocalScale of the asset towards a common/unified scale + // used when the asset is magnetized/attached to the proxy, after grabbing it from the asset grid + IEnumerator ShowGrabbedObject() + { + var currentLocalScale = m_DragObject.localScale; + var currentPreviewOffset = Vector3.zero; + var currentPreviewRotationOffset = Quaternion.identity; + + if (m_PreviewObjectClone) + currentPreviewOffset = m_PreviewObjectClone.localPosition; + + var currentTime = 0f; + var currentVelocity = 0f; + const float kDuration = 1f; + + var targetScale = Vector3.one * k_IconPreviewScale; + var pivotOffset = Vector3.zero; + var rotationOffset = Quaternion.AngleAxis(30, Vector3.right); + if (m_PreviewObjectClone) + { + var viewerScale = this.GetViewerScale(); + var maxComponent = m_PreviewBounds.size.MaxComponent() / viewerScale; + targetScale = Vector3.one * maxComponent; + + // Object will preview at the same size when grabbed + var previewExtents = m_PreviewBounds.extents / viewerScale; + pivotOffset = m_PreviewPivotOffset / viewerScale; + + // If bounds are greater than offset, set to bounds + if (previewExtents.y > pivotOffset.y) + pivotOffset.y = previewExtents.y; + + if (previewExtents.z > pivotOffset.z) + pivotOffset.z = previewExtents.z; + + if (maxComponent < k_MinPreviewScale) + { + // Object will be preview at the minimum scale + targetScale = Vector3.one * k_MinPreviewScale; + pivotOffset = pivotOffset * scaleFactor + (Vector3.up + Vector3.forward) * 0.5f * k_MinPreviewScale; + } + + if (maxComponent > k_MaxPreviewScale) + { + // Object will be preview at the maximum scale + targetScale = Vector3.one * k_MaxPreviewScale; + pivotOffset = pivotOffset * scaleFactor + (Vector3.up + Vector3.forward) * 0.5f * k_MaxPreviewScale; + } + } + + while (currentTime < kDuration - 0.05f) + { + if (m_DragObject == null) + yield break; // Exit coroutine if m_GrabbedObject is destroyed before the loop is finished + + currentTime = MathUtilsExt.SmoothDamp(currentTime, kDuration, ref currentVelocity, 0.5f, Mathf.Infinity, Time.deltaTime); + m_DragObject.localScale = Vector3.Lerp(currentLocalScale, targetScale, currentTime); + + if (m_PreviewObjectClone) + { + m_PreviewObjectClone.localPosition = Vector3.Lerp(currentPreviewOffset, pivotOffset, currentTime); + m_PreviewObjectClone.localRotation = Quaternion.Lerp(currentPreviewRotationOffset, rotationOffset, currentTime); // Compensate for preview origin rotation + } + + yield return null; + } + + m_DragObject.localScale = targetScale; + } + + static IEnumerator HideGrabbedObject(GameObject itemToHide) + { + var itemTransform = itemToHide.transform; + var currentScale = itemTransform.localScale; + var targetScale = Vector3.zero; + var transitionAmount = Time.deltaTime; + var transitionAddMultiplier = 6; + while (transitionAmount < 1) + { + itemTransform.localScale = Vector3.Lerp(currentScale, targetScale, transitionAmount); + transitionAmount += Time.deltaTime * transitionAddMultiplier; + yield return null; + } + ObjectUtils.Destroy(itemToHide); + } + + void ShowGrabFeedback(Node node) + { + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = VRInputDevice.VRControl.Trigger1; + request.node = node; + request.tooltipText = "Grab"; + this.AddFeedbackRequest(request); + } + + void HideGrabFeedback() + { + this.ClearFeedbackRequests(); + } + } +} +#endif diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs.meta b/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs.meta new file mode 100644 index 000000000..da4051b0f --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridItem.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4e40f52fad02674faece487e85b34e6 +timeCreated: 1504905301 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs b/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs new file mode 100644 index 000000000..0dbea0cb6 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs @@ -0,0 +1,274 @@ +#if UNITY_EDITOR +using ListView; +using UnityEngine; + +#if INCLUDE_POLY_TOOLKIT +using PolyToolkit; +#endif + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + class PolyGridViewController : ListViewController, IPoly + { + const int k_RequestSize = 100; + + const float k_PositionFollow = 0.4f; + + [SerializeField] + float m_ScaleFactor = 0.05f; + + [SerializeField] + Transform m_Spinner; + + [SerializeField] + float m_SpinnerSpeed = 25f; + + [SerializeField] + Vector3 m_SpinnerOffset = new Vector3(0.08f, -0.0125f, -0.023f); + + [SerializeField] + string[] m_IconTypes; + + [SerializeField] + GameObject[] m_Icons; + + Transform m_GrabbedObject; + + int m_NumPerRow; + + float m_LastHiddenItemOffset; + int m_LastDataCount; + string m_NextPageToken; + +#if INCLUDE_POLY_TOOLKIT + PolyOrderBy m_Sorting; + PolyMaxComplexityFilter m_Complexity; + PolyFormatFilter? m_Format; + PolyCategory m_Category; + + public PolyOrderBy sorting { private get; set; } + public PolyMaxComplexityFilter complexity { private get; set; } + public PolyFormatFilter? format { private get; set; } + public PolyCategory category { private get; set; } +#endif + + public float scaleFactor + { + get { return m_ScaleFactor; } + set + { + m_LastHiddenItemOffset = Mathf.Infinity; // Allow any change in scale to change visibility states + m_ScaleFactor = value; + } + } + + protected override float listHeight + { + get + { + if (m_NumPerRow == 0) + return 0; + + return Mathf.CeilToInt(m_Data.Count / m_NumPerRow) * itemSize.z; + } + } + + protected override void Setup() + { + base.Setup(); + + m_ScrollOffset = itemSize.z * 0.5f; + + RequestAssetList(); + } + + public void RequestAssetList() + { +#if INCLUDE_POLY_TOOLKIT + var nextPageToken = m_NextPageToken; + m_NextPageToken = null; + + if (m_Sorting != sorting || m_Complexity != complexity || m_Format != format || m_Category != category) + { + nextPageToken = null; + foreach (var asset in data) + { + RecycleGridItem(asset); + } + + data.Clear(); + m_LastHiddenItemOffset = Mathf.Infinity; + } + + m_Sorting = sorting; + m_Complexity = complexity; + m_Format = format; + m_Category = category; + this.GetAssetList(sorting, complexity, format, category, k_RequestSize, data, SetNextPageToken, nextPageToken); +#endif + } + + void SetNextPageToken(string nextPageToken) + { + m_NextPageToken = nextPageToken; + } + + protected override void ComputeConditions() + { + base.ComputeConditions(); + + var itemSize = m_ItemSize.Value; + m_NumPerRow = (int)(m_Size.x / itemSize.x); + if (m_NumPerRow < 1) // Early out if item size exceeds bounds size + return; + + if (m_LastDataCount != m_Data.Count) + { + m_LastDataCount = m_Data.Count; + m_LastHiddenItemOffset = Mathf.Infinity; + } + + m_StartPosition = m_Extents.z * Vector3.forward + (m_Extents.x - itemSize.x * 0.5f) * Vector3.left; + + var spinnerGameObject = m_Spinner.gameObject; + if (m_NextPageToken == null) // If no NextPageToken we are waiting on a list request + { + if (!spinnerGameObject.activeSelf) + spinnerGameObject.SetActive(true); + + m_Spinner.localPosition = -m_StartPosition + m_SpinnerOffset; + m_Spinner.Rotate(Vector3.up, m_SpinnerSpeed * Time.deltaTime, Space.Self); + } + else if (spinnerGameObject.activeSelf) + { + spinnerGameObject.SetActive(false); + } + + // Snap back if list scrolled too far + m_ScrollReturn = float.MaxValue; + if (listHeight > 0 && -m_ScrollOffset >= listHeight) + { + m_ScrollReturn = -listHeight + m_ScaleFactor; + + if (m_Data.Count % m_NumPerRow == 0) + m_ScrollReturn += itemSize.z; + } + } + + protected override Vector3 GetObjectSize(GameObject g) + { + return g.GetComponent().size * m_ScaleFactor + Vector3.one * m_Padding * m_ScaleFactor; + } + + protected override void UpdateItems() + { + var count = 0; + var order = 0; + foreach (var data in m_Data) + { + if (m_NumPerRow == 0) // If the list is too narrow, display nothing + { + RecycleGridItem(data); + continue; + } + + var offset = count / m_NumPerRow * itemSize.z; + if (offset + scrollOffset < 0 || offset + scrollOffset > m_Size.z) + { + RecycleGridItem(data); + } + else + { + var ignored = true; + UpdateVisibleItem(data, order++, count, ref ignored); + +#if INCLUDE_POLY_TOOLKIT + if (m_NextPageToken != null && count == m_Data.Count - k_RequestSize / 2) + RequestAssetList(); +#endif + } + + count++; + } + } + + void RecycleGridItem(PolyGridAsset data) + { + var index = data.index; + PolyGridItem item; + if (!m_ListItems.TryGetValue(index, out item)) + return; + + m_LastHiddenItemOffset = scrollOffset; + + m_ListItems.Remove(index); + + item.SetVisibility(false, OnRecycleCompleted); + } + + void OnRecycleCompleted(PolyGridItem gridItem) + { + gridItem.gameObject.SetActive(false); + m_TemplateDictionary[gridItem.data.template].pool.Add(gridItem); + } + + protected override void UpdateVisibleItem(PolyGridAsset data, int order, float offset, ref bool doneSettling) + { + PolyGridItem item; + if (!m_ListItems.TryGetValue(data.index, out item)) + item = GetItem(data); + + if (item) + UpdateGridItem(item, order, (int)offset); + } + + public override void OnScrollEnded() + { + m_Scrolling = false; + if (m_ScrollOffset > m_ScaleFactor) + { + m_ScrollOffset = m_ScaleFactor; + m_ScrollDelta = 0; + } + + if (m_ScrollReturn < float.MaxValue) + { + m_ScrollOffset = m_ScrollReturn; + m_ScrollReturn = float.MaxValue; + m_ScrollDelta = 0; + } + } + + void UpdateGridItem(PolyGridItem item, int order, int count) + { + item.UpdateTransforms(m_ScaleFactor); + + var itemSize = m_ItemSize.Value; + var t = item.transform; + var zOffset = itemSize.z * (count / m_NumPerRow) + m_ScrollOffset; + var xOffset = itemSize.x * (count % m_NumPerRow); + + t.localPosition = Vector3.Lerp(t.localPosition, m_StartPosition + zOffset * Vector3.back + xOffset * Vector3.right, k_PositionFollow); + t.localRotation = Quaternion.identity; + + t.SetSiblingIndex(order); + } + + protected override PolyGridItem GetItem(PolyGridAsset data) + { + const float jitterMargin = 0.125f; + if (Mathf.Abs(scrollOffset - m_LastHiddenItemOffset) < itemSize.z * jitterMargin) // Avoid jitter while scrolling rows in and out of view + return null; + + var item = base.GetItem(data); + + item.transform.localPosition = m_StartPosition; + + item.scaleFactor = m_ScaleFactor; + item.SetVisibility(true); + + return item; + } + } +} +#endif diff --git a/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs.meta b/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs.meta new file mode 100644 index 000000000..96ab5fc88 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyGridViewController.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 66259449855f4014f8f987cbbc7fe988 +timeCreated: 1504906534 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts/PolyModule.cs b/Workspaces/PolyWorkspace/Scripts/PolyModule.cs new file mode 100644 index 000000000..d2621fc9b --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyModule.cs @@ -0,0 +1,102 @@ +#if UNITY_EDITOR +using System; +using System.Text; +using UnityEditor.Experimental.EditorVR; +using UnityEditor.Experimental.EditorVR.Workspaces; +using UnityEngine; + +#if INCLUDE_POLY_TOOLKIT +using PolyToolkit; +using System.Collections.Generic; +using UnityEditor.Experimental.EditorVR.Utilities; +#endif + +[assembly: OptionalDependency("PolyToolkit.PolyApi", "INCLUDE_POLY_TOOLKIT")] + +#if INCLUDE_POLY_TOOLKIT +namespace UnityEditor.Experimental.EditorVR.Modules +{ + public class PolyModule : MonoBehaviour, IWeb + { + class RequestHandler + { + List m_Assets; + Transform m_Container; + Action m_ListCallback; + + public RequestHandler(PolyOrderBy orderBy, PolyMaxComplexityFilter complexity, PolyFormatFilter? format, + PolyCategory category, int requestSize, List assets, Transform container, + Action listCallback, string nextPageToken = null) + { + m_Assets = assets; + m_Container = container; + m_ListCallback = listCallback; + + var request = new PolyListAssetsRequest + { + orderBy = orderBy, + maxComplexity = complexity, + formatFilter = format, + category = category + }; + + request.pageToken = nextPageToken; + request.pageSize = requestSize; + PolyApi.ListAssets(request, ListAssetsCallback); + } + + // Callback invoked when the featured assets results are returned. + void ListAssetsCallback(PolyStatusOr result) + { + if (!result.Ok) + { + Debug.LogError("Failed to get featured assets. :( Reason: " + result.Status); + return; + } + + if (m_ListCallback != null) + m_ListCallback(result.Value.nextPageToken); + + foreach (var asset in result.Value.assets) + { + PolyGridAsset polyGridAsset; + var name = asset.name; + if (!k_AssetCache.TryGetValue(name, out polyGridAsset)) + { + polyGridAsset = new PolyGridAsset(asset, m_Container); + k_AssetCache[name] = polyGridAsset; + } + + m_Assets.Add(polyGridAsset); + } + } + } + + const string k_APIKey = "QUl6YVN5QUZvMEp6ZVZZRFNDSURFa3hlWmdMNjg0OUM0MThoWlYw"; + + static readonly Dictionary k_AssetCache = new Dictionary(); + + Transform m_Container; + + void Awake() + { + PolyApi.Init(new PolyAuthConfig(Encoding.UTF8.GetString(Convert.FromBase64String(k_APIKey)), "", "")); + m_Container = ObjectUtils.CreateEmptyGameObject("Poly Prefabs", transform).transform; + } + + void OnDestroy() + { + k_AssetCache.Clear(); + PolyApi.Shutdown(); + } + + public void GetAssetList(PolyOrderBy orderBy, PolyMaxComplexityFilter complexity, PolyFormatFilter? format, + PolyCategory category, int requestSize, List assets, Action listCallback, + string nextPageToken = null) + { + new RequestHandler(orderBy, complexity, format,category, requestSize, assets, m_Container, listCallback, nextPageToken); + } + } +} +#endif +#endif diff --git a/Workspaces/PolyWorkspace/Scripts/PolyModule.cs.meta b/Workspaces/PolyWorkspace/Scripts/PolyModule.cs.meta new file mode 100644 index 000000000..a34697563 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5a3845d1493cb7648ae7a70ad2474039 +timeCreated: 1504902852 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/PolyWorkspace/Scripts/PolyUI.cs b/Workspaces/PolyWorkspace/Scripts/PolyUI.cs new file mode 100644 index 000000000..6cf21077e --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyUI.cs @@ -0,0 +1,19 @@ +#if UNITY_EDITOR +using UnityEditor.Experimental.EditorVR.Handles; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + sealed class PolyUI : MonoBehaviour + { + [SerializeField] + PolyGridViewController m_GridView; + + [SerializeField] + LinearHandle m_ScrollHandle; + + public PolyGridViewController gridView { get { return m_GridView; } } + public LinearHandle scrollHandle { get { return m_ScrollHandle; } } + } +} +#endif diff --git a/Workspaces/PolyWorkspace/Scripts/PolyUI.cs.meta b/Workspaces/PolyWorkspace/Scripts/PolyUI.cs.meta new file mode 100644 index 000000000..c3a4fb0f1 --- /dev/null +++ b/Workspaces/PolyWorkspace/Scripts/PolyUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 33e1473776ce1dc4f838a0fb9687bf5a +timeCreated: 1471991641 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Workspaces/ProjectWorkspace/Project.prefab b/Workspaces/ProjectWorkspace/Project.prefab index 2ef4c819c..3ce540e2a 100644 --- a/Workspaces/ProjectWorkspace/Project.prefab +++ b/Workspaces/ProjectWorkspace/Project.prefab @@ -390,6 +390,12 @@ MonoBehaviour: m_ScrollPulse: {fileID: 11400000, guid: 77319cd620700db49a9223c7305480f9, type: 2} m_SettleSpeed: 0.3 m_ScrollSpeed: 0.3 + m_ItemClickPulse: {fileID: 0} + m_ItemHoverStartPulse: {fileID: 0} + m_ItemHoverEndPulse: {fileID: 0} + m_ItemDragStartPulse: {fileID: 0} + m_ItemDraggingPulse: {fileID: 0} + m_ItemDragEndPulse: {fileID: 0} m_TextMaterial: {fileID: 2100000, guid: 2569ce4f009c407448c0df4aa8d7db55, type: 2} m_ExpandArrowMaterial: {fileID: 2100000, guid: 41165fc29d3ea90418665f906b7fa247, type: 2} @@ -444,6 +450,15 @@ MonoBehaviour: m_ScrollPulse: {fileID: 11400000, guid: 77319cd620700db49a9223c7305480f9, type: 2} m_SettleSpeed: 0.3 m_ScrollSpeed: 0.3 + m_ItemClickPulse: {fileID: 11400000, guid: 72c68844f1d53f549976daae6a207100, type: 2} + m_ItemHoverStartPulse: {fileID: 11400000, guid: d71c4adadeb37984aa5f37d8c0096997, + type: 2} + m_ItemHoverEndPulse: {fileID: 0} + m_ItemDragStartPulse: {fileID: 11400000, guid: 0df1c3251269d8a41a11a33faf676222, + type: 2} + m_ItemDraggingPulse: {fileID: 11400000, guid: 5ccd598d3356a834e87a36e7111cb173, + type: 2} + m_ItemDragEndPulse: {fileID: 11400000, guid: 64a535853bdb5b24f8d196dedeea8cba, type: 2} m_ScaleFactor: 0.056 m_IconTypes: - Scene diff --git a/Workspaces/ProjectWorkspace/Scripts/AssetGridItem.cs b/Workspaces/ProjectWorkspace/Scripts/AssetGridItem.cs index 8d6f48842..75ddfe76f 100644 --- a/Workspaces/ProjectWorkspace/Scripts/AssetGridItem.cs +++ b/Workspaces/ProjectWorkspace/Scripts/AssetGridItem.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if UNITY_EDITOR using System; using System.Collections; using UnityEditor.Experimental.EditorVR.Core; @@ -377,6 +377,7 @@ protected override void OnDragEnded(BaseHandle handle, HandleEventData eventData } StartCoroutine(HideGrabbedObject(m_DragObject.gameObject, gridItem.m_Cube)); + base.OnDragEnded(handle, eventData); } void OnHoverStarted(BaseHandle handle, HandleEventData eventData) @@ -394,6 +395,7 @@ void OnHoverStarted(BaseHandle handle, HandleEventData eventData) } } + base.OnHoverStart(handle, eventData); ShowGrabFeedback(this.RequestNodeFromRayOrigin(eventData.rayOrigin)); } @@ -581,12 +583,11 @@ static IEnumerator HideGrabbedObject(GameObject itemToHide, Renderer cubeRendere void ShowGrabFeedback(Node node) { - this.AddFeedbackRequest(new ProxyFeedbackRequest - { - control = VRInputDevice.VRControl.Trigger1, - node = node, - tooltipText = "Grab" - }); + var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest)); + request.control = VRInputDevice.VRControl.Trigger1; + request.node = node; + request.tooltipText = "Grab"; + this.AddFeedbackRequest(request); } void HideGrabFeedback() diff --git a/Workspaces/ProjectWorkspace/Scripts/AssetGridViewController.cs b/Workspaces/ProjectWorkspace/Scripts/AssetGridViewController.cs index 12b9a29d7..10239893f 100644 --- a/Workspaces/ProjectWorkspace/Scripts/AssetGridViewController.cs +++ b/Workspaces/ProjectWorkspace/Scripts/AssetGridViewController.cs @@ -1,277 +1,277 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using ListView; -using UnityEditor.Experimental.EditorVR.Data; -using UnityEditor.Experimental.EditorVR.Utilities; -using UnityEngine; - -namespace UnityEditor.Experimental.EditorVR.Workspaces -{ - sealed class AssetGridViewController : ListViewController - { - const float k_PositionFollow = 0.4f; - - Transform m_GrabbedObject; - - int m_NumPerRow; - - public float scaleFactor - { - get { return m_ScaleFactor; } - set - { - m_LastHiddenItemOffset = Mathf.Infinity; // Allow any change in scale to change visibility states - m_ScaleFactor = value; - } - } - - [SerializeField] - float m_ScaleFactor = 0.05f; - - [SerializeField] - string[] m_IconTypes; - - [SerializeField] - GameObject[] m_Icons; - - float m_LastHiddenItemOffset; - - readonly Dictionary m_IconDictionary = new Dictionary(); - - Action m_OnRecyleComplete; - - public Func matchesFilter { private get; set; } - - protected override float listHeight - { - get - { - if (m_NumPerRow == 0) - return 0; - - var numRows = Mathf.CeilToInt(m_Data.Count / m_NumPerRow); - return Mathf.Clamp(numRows, 1, Int32.MaxValue) * itemSize.z; - } - } - - public override List data - { - set - { - base.data = value; - - m_LastHiddenItemOffset = Mathf.Infinity; - } - } - - public override Vector3 size - { - set - { - base.size = value; - m_LastHiddenItemOffset = Mathf.Infinity; - } - } - - void Awake() - { - m_OnRecyleComplete = OnRecycleComplete; - } - - protected override void Setup() - { - base.Setup(); - - m_ScrollOffset = itemSize.z * 0.5f; - - for (int i = 0; i < m_IconTypes.Length; i++) - { - if (!string.IsNullOrEmpty(m_IconTypes[i]) && m_Icons[i] != null) - m_IconDictionary[m_IconTypes[i]] = m_Icons[i]; - } - } - - protected override void ComputeConditions() - { - base.ComputeConditions(); - - var itemSize = m_ItemSize.Value; - m_NumPerRow = (int)(m_Size.x / itemSize.x); - if (m_NumPerRow < 1) // Early out if item size exceeds bounds size - return; - - m_StartPosition = m_Extents.z * Vector3.forward + (m_Extents.x - itemSize.x * 0.5f) * Vector3.left; - - // Snap back if list scrolled too far - m_ScrollReturn = float.MaxValue; - if (listHeight > 0 && -m_ScrollOffset >= listHeight) - { - m_ScrollReturn = -listHeight + m_ScaleFactor; - - if (m_Data.Count % m_NumPerRow == 0) - m_ScrollReturn += itemSize.z; - } - // if we only have one row, snap back as soon as that row would be hidden - else if (listHeight == itemSize.z && -m_ScrollOffset > 0) - { - m_ScrollReturn = itemSize.z / 2; - } - } - - protected override Vector3 GetObjectSize(GameObject g) - { - return g.GetComponent().size * m_ScaleFactor + Vector3.one * m_Padding * m_ScaleFactor; - } - - protected override void UpdateItems() - { - var count = 0; - var order = 0; - foreach (var data in m_Data) - { - if (m_NumPerRow == 0) // If the list is too narrow, display nothing - { - RecycleGridItem(data); - continue; - } - - if (!matchesFilter(data.type)) // If this item doesn't match the filter, move on to the next item; do not count - { - RecycleGridItem(data); - continue; - } - - var offset = count / m_NumPerRow * itemSize.z; - if (offset + scrollOffset < 0 || offset + scrollOffset > m_Size.z) - RecycleGridItem(data); - else - { - var ignored = true; - UpdateVisibleItem(data, order++, count, ref ignored); - } - - count++; - } - } - - void RecycleGridItem(AssetData data) - { - var index = data.index; - AssetGridItem item; - if (!m_ListItems.TryGetValue(index, out item)) - return; - - m_LastHiddenItemOffset = scrollOffset; - - m_ListItems.Remove(index); - - item.SetVisibility(false, m_OnRecyleComplete); - } - - void OnRecycleComplete(AssetGridItem gridItem) - { - gridItem.gameObject.SetActive(false); - m_TemplateDictionary[gridItem.data.template].pool.Add(gridItem); - } - - protected override void UpdateVisibleItem(AssetData data, int order, float offset, ref bool doneSettling) - { - AssetGridItem item; - if (!m_ListItems.TryGetValue(data.index, out item)) - item = GetItem(data); - - if (item) - UpdateGridItem(item, order, (int)offset); - } - - public override void OnScrollEnded() - { - m_Scrolling = false; - if (m_ScrollOffset > m_ScaleFactor) - { - m_ScrollOffset = m_ScaleFactor; - m_ScrollDelta = 0; - } - if (m_ScrollReturn < float.MaxValue) - { - m_ScrollOffset = m_ScrollReturn; - m_ScrollReturn = float.MaxValue; - m_ScrollDelta = 0; - } - } - - void UpdateGridItem(AssetGridItem item, int order, int count) - { - item.UpdateTransforms(m_ScaleFactor); - - var itemSize = m_ItemSize.Value; - var t = item.transform; - var zOffset = itemSize.z * (count / m_NumPerRow) + m_ScrollOffset; - var xOffset = itemSize.x * (count % m_NumPerRow); - - t.localPosition = Vector3.Lerp(t.localPosition, m_StartPosition + zOffset * Vector3.back + xOffset * Vector3.right, k_PositionFollow); - t.localRotation = Quaternion.identity; - - t.SetSiblingIndex(order); - } - - protected override AssetGridItem GetItem(AssetData data) - { - const float kJitterMargin = 0.125f; - if (Mathf.Abs(scrollOffset - m_LastHiddenItemOffset) < itemSize.z * kJitterMargin) // Avoid jitter while scrolling rows in and out of view - return null; - - // If this AssetData hasn't fetched its asset yet, do so now - if (data.asset == null) - { - data.asset = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(data.index)); - data.preview = data.asset as GameObject; - } - - var item = base.GetItem(data); - - item.transform.localPosition = m_StartPosition; - - item.scaleFactor = m_ScaleFactor; - item.SetVisibility(true); - - switch (data.type) - { - case "Material": - var material = data.asset as Material; - if (material) - item.material = material; - else - LoadFallbackTexture(item, data); - break; - case "Texture2D": - goto case "Texture"; - case "Texture": - var texture = data.asset as Texture; - if (texture) - item.texture = texture; - else - LoadFallbackTexture(item, data); - break; - default: - GameObject icon; - if (m_IconDictionary.TryGetValue(data.type, out icon)) - item.icon = icon; - else - LoadFallbackTexture(item, data); - break; - } - return item; - } - - static void LoadFallbackTexture(AssetGridItem item, AssetData data) - { - item.fallbackTexture = null; - item.StartCoroutine(ObjectUtils.GetAssetPreview( - AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(data.index)), - texture => item.fallbackTexture = texture)); - } - } -} -#endif +#if UNITY_EDITOR +using System; +using System.Collections.Generic; +using ListView; +using UnityEditor.Experimental.EditorVR.Data; +using UnityEditor.Experimental.EditorVR.Utilities; +using UnityEngine; + +namespace UnityEditor.Experimental.EditorVR.Workspaces +{ + sealed class AssetGridViewController : ListViewController + { + const float k_PositionFollow = 0.4f; + + Transform m_GrabbedObject; + + int m_NumPerRow; + + public float scaleFactor + { + get { return m_ScaleFactor; } + set + { + m_LastHiddenItemOffset = Mathf.Infinity; // Allow any change in scale to change visibility states + m_ScaleFactor = value; + } + } + + [SerializeField] + float m_ScaleFactor = 0.05f; + + [SerializeField] + string[] m_IconTypes; + + [SerializeField] + GameObject[] m_Icons; + + float m_LastHiddenItemOffset; + + readonly Dictionary m_IconDictionary = new Dictionary(); + + Action m_OnRecyleComplete; + + public Func matchesFilter { private get; set; } + + protected override float listHeight + { + get + { + if (m_NumPerRow == 0) + return 0; + + var numRows = Mathf.CeilToInt(m_Data.Count / m_NumPerRow); + return Mathf.Clamp(numRows, 1, Int32.MaxValue) * itemSize.z; + } + } + + public override List data + { + set + { + base.data = value; + + m_LastHiddenItemOffset = Mathf.Infinity; + } + } + + public override Vector3 size + { + set + { + base.size = value; + m_LastHiddenItemOffset = Mathf.Infinity; + } + } + + void Awake() + { + m_OnRecyleComplete = OnRecycleComplete; + } + + protected override void Setup() + { + base.Setup(); + + m_ScrollOffset = itemSize.z * 0.5f; + + for (int i = 0; i < m_IconTypes.Length; i++) + { + if (!string.IsNullOrEmpty(m_IconTypes[i]) && m_Icons[i] != null) + m_IconDictionary[m_IconTypes[i]] = m_Icons[i]; + } + } + + protected override void ComputeConditions() + { + base.ComputeConditions(); + + var itemSize = m_ItemSize.Value; + m_NumPerRow = (int)(m_Size.x / itemSize.x); + if (m_NumPerRow < 1) // Early out if item size exceeds bounds size + return; + + m_StartPosition = m_Extents.z * Vector3.forward + (m_Extents.x - itemSize.x * 0.5f) * Vector3.left; + + // Snap back if list scrolled too far + m_ScrollReturn = float.MaxValue; + if (listHeight > 0 && -m_ScrollOffset >= listHeight) + { + m_ScrollReturn = -listHeight + m_ScaleFactor; + + if (m_Data.Count % m_NumPerRow == 0) + m_ScrollReturn += itemSize.z; + } + // if we only have one row, snap back as soon as that row would be hidden + else if (listHeight == itemSize.z && -m_ScrollOffset > 0) + { + m_ScrollReturn = itemSize.z / 2; + } + } + + protected override Vector3 GetObjectSize(GameObject g) + { + return g.GetComponent().size * m_ScaleFactor + Vector3.one * m_Padding * m_ScaleFactor; + } + + protected override void UpdateItems() + { + var count = 0; + var order = 0; + foreach (var data in m_Data) + { + if (m_NumPerRow == 0) // If the list is too narrow, display nothing + { + RecycleGridItem(data); + continue; + } + + if (!matchesFilter(data.type)) // If this item doesn't match the filter, move on to the next item; do not count + { + RecycleGridItem(data); + continue; + } + + var offset = count / m_NumPerRow * itemSize.z; + if (offset + scrollOffset < 0 || offset + scrollOffset > m_Size.z) + RecycleGridItem(data); + else + { + var ignored = true; + UpdateVisibleItem(data, order++, count, ref ignored); + } + + count++; + } + } + + void RecycleGridItem(AssetData data) + { + var index = data.index; + AssetGridItem item; + if (!m_ListItems.TryGetValue(index, out item)) + return; + + m_LastHiddenItemOffset = scrollOffset; + + m_ListItems.Remove(index); + + item.SetVisibility(false, m_OnRecyleComplete); + } + + void OnRecycleComplete(AssetGridItem gridItem) + { + gridItem.gameObject.SetActive(false); + m_TemplateDictionary[gridItem.data.template].pool.Add(gridItem); + } + + protected override void UpdateVisibleItem(AssetData data, int order, float offset, ref bool doneSettling) + { + AssetGridItem item; + if (!m_ListItems.TryGetValue(data.index, out item)) + item = GetItem(data); + + if (item) + UpdateGridItem(item, order, (int)offset); + } + + public override void OnScrollEnded() + { + m_Scrolling = false; + if (m_ScrollOffset > m_ScaleFactor) + { + m_ScrollOffset = m_ScaleFactor; + m_ScrollDelta = 0; + } + if (m_ScrollReturn < float.MaxValue) + { + m_ScrollOffset = m_ScrollReturn; + m_ScrollReturn = float.MaxValue; + m_ScrollDelta = 0; + } + } + + void UpdateGridItem(AssetGridItem item, int order, int count) + { + item.UpdateTransforms(m_ScaleFactor); + + var itemSize = m_ItemSize.Value; + var t = item.transform; + var zOffset = itemSize.z * (count / m_NumPerRow) + m_ScrollOffset; + var xOffset = itemSize.x * (count % m_NumPerRow); + + t.localPosition = Vector3.Lerp(t.localPosition, m_StartPosition + zOffset * Vector3.back + xOffset * Vector3.right, k_PositionFollow); + t.localRotation = Quaternion.identity; + + t.SetSiblingIndex(order); + } + + protected override AssetGridItem GetItem(AssetData data) + { + const float jitterMargin = 0.125f; + if (Mathf.Abs(scrollOffset - m_LastHiddenItemOffset) < itemSize.z * jitterMargin) // Avoid jitter while scrolling rows in and out of view + return null; + + // If this AssetData hasn't fetched its asset yet, do so now + if (data.asset == null) + { + data.asset = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(data.index)); + data.preview = data.asset as GameObject; + } + + var item = base.GetItem(data); + + item.transform.localPosition = m_StartPosition; + + item.scaleFactor = m_ScaleFactor; + item.SetVisibility(true); + + switch (data.type) + { + case "Material": + var material = data.asset as Material; + if (material) + item.material = material; + else + LoadFallbackTexture(item, data); + break; + case "Texture2D": + goto case "Texture"; + case "Texture": + var texture = data.asset as Texture; + if (texture) + item.texture = texture; + else + LoadFallbackTexture(item, data); + break; + default: + GameObject icon; + if (m_IconDictionary.TryGetValue(data.type, out icon)) + item.icon = icon; + else + LoadFallbackTexture(item, data); + break; + } + return item; + } + + static void LoadFallbackTexture(AssetGridItem item, AssetData data) + { + item.fallbackTexture = null; + item.StartCoroutine(ObjectUtils.GetAssetPreview( + AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(data.index)), + texture => item.fallbackTexture = texture)); + } + } +} +#endif diff --git a/Workspaces/ProjectWorkspace/Shaders/StandardDecal.shader b/Workspaces/ProjectWorkspace/Shaders/StandardDecal.shader index ac65fb621..205517310 100644 --- a/Workspaces/ProjectWorkspace/Shaders/StandardDecal.shader +++ b/Workspaces/ProjectWorkspace/Shaders/StandardDecal.shader @@ -1,9 +1,9 @@ -Shader "EditorVR/Standard Decal" +Shader "EditorVR/Standard Decal" { Properties { _Color ("Color", Color) = (1,1,1,1) - _MainTex ("Albedo (RGB)", 2D) = "white" {} + _MainTex ("Albedo (RGB)", 2D) = "black" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } @@ -32,11 +32,16 @@ void surf (Input IN, inout SurfaceOutputStandard o) { - fixed4 c = tex2D(_MainTex, IN.uv_MainTex); - c *= _Color * c.a; - o.Emission = c.rgb; + if (IN.uv_MainTex.x > 1 || IN.uv_MainTex.x < 0 + || IN.uv_MainTex.y > 1 || IN.uv_MainTex.y < 0) + o.Emission = 0; + else { + fixed4 c = tex2D(_MainTex, IN.uv_MainTex); + c *= _Color * c.a; + o.Emission = c.rgb; + } } ENDCG } FallBack "Diffuse" -} \ No newline at end of file +} diff --git a/libs/input-prototype b/libs/input-prototype index 38e4e350b..a60de5a09 160000 --- a/libs/input-prototype +++ b/libs/input-prototype @@ -1 +1 @@ -Subproject commit 38e4e350bfd91ae3f28471d31e0a3bc8a560e6b9 +Subproject commit a60de5a09aaa927f767c4263e212a6ab5748fe18