/// <summary>
        /// Render list of data provider configuration profiles in inspector. Use provided add and remove content labels for the insert/remove buttons
        /// Returns true if any property has changed in this render pass, false otherwise
        /// </summary>
        protected bool RenderDataProviderList(GUIContent addContentLabel, GUIContent removeContentLabel, string errorMsg, Type dataProviderProfileType = null)
        {
            bool changed = false;

            using (new EditorGUILayout.VerticalScope())
            {
                if (providerConfigurations == null || providerConfigurations.arraySize == 0)
                {
                    EditorGUILayout.HelpBox(errorMsg, MessageType.Info);
                }

                if (InspectorUIUtility.RenderIndentedButton(addContentLabel, EditorStyles.miniButton))
                {
                    AddDataProvider();
                    return(true);
                }

                for (int i = 0; i < providerConfigurations.arraySize; i++)
                {
                    changed |= RenderDataProviderEntry(i, removeContentLabel, dataProviderProfileType);
                }

                return(changed);
            }
        }
        public override void OnInspectorGUI()
        {
            if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, isInitialized, BackProfileType.Input))
            {
                return;
            }

            CheckMixedRealityInputActions();

            using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
            {
                serializedObject.Update();

                selectedBaseActionId = RenderBaseInputAction(selectedBaseActionId, out currentBaseAction);

                using (new EditorGUI.DisabledGroupScope(currentBaseAction == MixedRealityInputAction.None))
                {
                    RenderCriteriaField(currentBaseAction);

                    if (selectedBaseActionId == selectedRuleActionId)
                    {
                        selectedRuleActionId = 0;
                    }

                    selectedRuleActionId = RenderRuleInputAction(selectedRuleActionId, out currentRuleAction);

                    EditorGUILayout.Space();
                }

                bool addButtonEnable = !RuleExists() &&
                                       currentBaseAction != MixedRealityInputAction.None &&
                                       currentRuleAction != MixedRealityInputAction.None &&
                                       currentBaseAction.AxisConstraint != AxisType.None &&
                                       currentBaseAction.AxisConstraint != AxisType.Raw;

                using (new EditorGUI.DisabledGroupScope(!addButtonEnable))
                {
                    if (InspectorUIUtility.RenderIndentedButton(RuleAddButtonContent, EditorStyles.miniButton))
                    {
                        AddRule();
                        ResetCriteria();
                    }
                }

                EditorGUILayout.Space();

                var isWideMode = EditorGUIUtility.wideMode;
                EditorGUIUtility.wideMode = true;

                RenderList(inputActionRulesDigital, digitalFoldouts);
                RenderList(inputActionRulesSingleAxis, singleAxisFoldouts);
                RenderList(inputActionRulesDualAxis, dualAxisFoldouts);
                RenderList(inputActionRulesVectorAxis, vectorFoldouts);
                RenderList(inputActionRulesQuaternionAxis, quaternionFoldouts);
                RenderList(inputActionRulesPoseAxis, poseFoldouts);

                EditorGUIUtility.wideMode = isWideMode;
                serializedObject.ApplyModifiedProperties();
            }
        }
        /// <summary>
        /// Helper function to render header correctly for all profiles
        /// </summary>
        /// <param name="title">Title of profile</param>
        /// <param name="description">profile tooltip describing purpose</param>
        /// <param name="selectionObject">The profile object. Used to re-select the object after MRTK instance is created.</param>
        /// <param name="isProfileInitialized">profile properties are full initialized for rendering</param>
        /// <param name="backText">Text for back button if not rendering as sub-profile</param>
        /// <param name="backProfile">Target profile to return to if not rendering as sub-profile</param>
        protected void RenderProfileHeader(string title, string description, Object selectionObject, bool isProfileInitialized = true, BackProfileType returnProfileTarget = BackProfileType.Configuration)
        {
            RenderMRTKLogo();

            var profile = target as BaseMixedRealityProfile;

            if (!RenderAsSubProfile)
            {
                CheckEditorPlayMode();

                if (!profile.IsCustomProfile)
                {
                    EditorGUILayout.HelpBox("Default MRTK profiles cannot be edited. Create a clone of this profile to modify settings.", MessageType.Warning);
                    if (GUILayout.Button(new GUIContent("Clone")))
                    {
                        MixedRealityProfileCloneWindow.OpenWindow(null, (BaseMixedRealityProfile)target, null);
                    }
                }

                if (IsProfileInActiveInstance())
                {
                    DrawBacktrackProfileButton(returnProfileTarget);
                }

                if (!isProfileInitialized)
                {
                    if (!MixedRealityToolkit.IsInitialized)
                    {
                        EditorGUILayout.HelpBox("There is not a MRTK instance in your scene. Some properties may not be editable", MessageType.Error);
                        if (InspectorUIUtility.RenderIndentedButton(new GUIContent("Add Mixed Reality Toolkit instance to scene"), EditorStyles.miniButton))
                        {
                            MixedRealityInspectorUtility.AddMixedRealityToolkitToScene(MixedRealityInspectorUtility.GetDefaultConfigProfile());
                            // After the toolkit has been created, set the selection back to this item so the user doesn't get lost
                            Selection.activeObject = selectionObject;
                        }
                    }
                    else if (!MixedRealityToolkit.Instance.HasActiveProfile)
                    {
                        EditorGUILayout.HelpBox("There is no active profile assigned in the current MRTK instance. Some properties may not be editable.", MessageType.Error);
                    }
                }
            }
            else
            {
                if (!isProfileInitialized && profile.IsCustomProfile)
                {
                    EditorGUILayout.HelpBox("Some properties may not be editable in this profile. Please refer to the error messages below to resolve editing.", MessageType.Warning);
                }
            }

            using (new EditorGUILayout.HorizontalScope())
            {
                EditorGUILayout.LabelField(new GUIContent(title, description), EditorStyles.boldLabel, GUILayout.ExpandWidth(true));
                RenderDocumentation(selectionObject);
            }

            EditorGUILayout.LabelField(string.Empty, GUI.skin.horizontalSlider);
        }
Example #4
0
        public override void OnInspectorGUI()
        {
            if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
            {
                return;
            }

            using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
            {
                serializedObject.Update();

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Gaze Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.Space();
                    EditorGUILayout.PropertyField(gazeCursorPrefab);
                    EditorGUILayout.PropertyField(gazeProviderType);
                    EditorGUILayout.PropertyField(useHeadGazeOverride);
                    EditorGUILayout.PropertyField(isEyeTrackingEnabled);
                    EditorGUILayout.Space();

                    if (InspectorUIUtility.RenderIndentedButton("Customize Gaze Provider Settings"))
                    {
                        Selection.activeObject = CameraCache.Main.gameObject;
                    }
                }

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Pointer Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(pointingExtent);
                    EditorGUILayout.PropertyField(pointingRaycastLayerMasks, true);
                    EditorGUILayout.PropertyField(pointerMediator);
                    EditorGUILayout.PropertyField(primaryPointerSelector);

                    EditorGUILayout.Space();
                    showPointerOptionProperties = EditorGUILayout.Foldout(showPointerOptionProperties, "Pointer Options", true);
                    if (showPointerOptionProperties)
                    {
                        using (new EditorGUI.IndentLevelScope())
                        {
                            RenderPointerList(pointerOptions);
                        }
                    }
                }

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Debug Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(debugDrawPointingRays);
                    EditorGUILayout.PropertyField(debugDrawPointingRayColors, true);
                }

                serializedObject.ApplyModifiedProperties();
            }
        }
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            InspectorUIUtility.DrawTitle("Profiles");

            if (profilesProperty.arraySize == 0)
            {
                AddProfile();
            }

            for (int i = 0; i < profilesProperty.arraySize; i++)
            {
                using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                {
                    SerializedProperty profile = profilesProperty.GetArrayElementAtIndex(i);

                    using (new EditorGUILayout.HorizontalScope())
                    {
                        SerializedProperty targetGameObject = profile.FindPropertyRelative("Target");
                        EditorGUILayout.PropertyField(targetGameObject, new GUIContent("Target", "Target gameObject for this theme properties to manipulate"));

                        if (InspectorUIUtility.SmallButton(RemoveProfileContent))
                        {
                            profilesProperty.DeleteArrayElementAtIndex(i);
                            serializedObject.ApplyModifiedProperties();
                            continue;
                        }
                    }

                    SerializedProperty theme = profile.FindPropertyRelative("Theme");
                    EditorGUILayout.PropertyField(theme, new GUIContent("Theme", "Theme properties for interaction feedback"));

                    // Render Theme Settings
                    if (theme.objectReferenceValue != null)
                    {
                        InspectorUIUtility.ListSettings settings = listSettings[i];
                        settings.Show = InspectorUIUtility.DrawSectionFoldout("Theme Settings (Click to edit)", listSettings[i].Show);
                        if (settings.Show)
                        {
                            UnityEditor.Editor themeEditor = UnityEditor.Editor.CreateEditor(theme.objectReferenceValue);
                            themeEditor.OnInspectorGUI();
                        }

                        listSettings[i] = settings;
                    }
                }
            }// profile for loop

            if (InspectorUIUtility.RenderIndentedButton(AddProfileContent, EditorStyles.miniButton))
            {
                AddProfile();
            }

            serializedObject.ApplyModifiedProperties();
        }
        private static void RenderList(SerializedProperty list)
        {
            GUILayout.BeginVertical();

            if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
            {
                list.arraySize += 1;
                var inputAction            = list.GetArrayElementAtIndex(list.arraySize - 1);
                var inputActionId          = inputAction.FindPropertyRelative("id");
                var inputActionDescription = inputAction.FindPropertyRelative("description");
                var inputActionConstraint  = inputAction.FindPropertyRelative("axisConstraint");
                inputActionConstraint.intValue     = 0;
                inputActionDescription.stringValue = $"New Action {inputActionId.intValue = list.arraySize}";
            }

            GUILayout.BeginVertical();

            GUILayout.BeginHorizontal();
            var labelWidth = EditorGUIUtility.labelWidth;

            EditorGUIUtility.labelWidth = 36f;
            EditorGUILayout.LabelField(ActionContent, GUILayout.ExpandWidth(true));
            EditorGUILayout.LabelField(AxisConstraintContent, GUILayout.Width(96f));
            EditorGUILayout.LabelField(string.Empty, GUILayout.Width(24f));
            EditorGUIUtility.labelWidth = labelWidth;
            GUILayout.EndHorizontal();

            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(100f));

            for (int i = 0; i < list.arraySize; i++)
            {
                EditorGUILayout.BeginHorizontal();
                var previousLabelWidth = EditorGUIUtility.labelWidth;
                EditorGUIUtility.labelWidth = 64f;
                SerializedProperty inputAction            = list.GetArrayElementAtIndex(i);
                SerializedProperty inputActionDescription = inputAction.FindPropertyRelative("description");
                var inputActionConstraint = inputAction.FindPropertyRelative("axisConstraint");
                EditorGUILayout.PropertyField(inputActionDescription, GUIContent.none);
                EditorGUILayout.PropertyField(inputActionConstraint, GUIContent.none, GUILayout.Width(96f));
                EditorGUIUtility.labelWidth = previousLabelWidth;

                if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                {
                    list.DeleteArrayElementAtIndex(i);
                }

                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.EndScrollView();
            GUILayout.EndVertical();
            GUILayout.EndVertical();
            EditorGUILayout.Space();
        }
Example #7
0
        private void RenderProjectOptimizations()
        {
            GUILayout.BeginVertical("Box");
            EditorGUILayout.LabelField(this.ToolbarTitles[(int)ToolbarSection.Project], BoldLargeTitle);
            using (new EditorGUI.IndentLevelScope())
            {
                BuildSection("Single Pass Instanced Rendering", "https://docs.unity3d.com/Manual/SinglePassStereoRendering.html", () =>
                {
                    EditorGUILayout.LabelField("Single Pass Instanced Rendering is an option in the Unity render pipeline to more efficiently render your scene and optimize CPU & GPU work. This path requires shaders though to be written to support instancing which is automatic in all Unity & MRTK shaders. Click the \"Learn More\" button to learn how to update your custom shaders to support instancing.", EditorStyles.wordWrappedLabel);

                    EditorGUILayout.BeginHorizontal();
                    singlePassInstanced = EditorGUILayout.ToggleLeft("Set Single Pass Instanced Rendering", singlePassInstanced);
                    if (GUILayout.Button(new GUIContent("Learn More", "Learn more about Single Pass Instanced Rendering"), EditorStyles.miniButton, GUILayout.Width(120f)))
                    {
                        Application.OpenURL("https://docs.unity3d.com/Manual/SinglePassInstancing.html");
                    }
                    EditorGUILayout.EndHorizontal();
                });

                // TODO: Put in Quality settings section

                BuildSection("Depth Buffer Sharing", null, () =>
                {
                    EditorGUILayout.LabelField("This option shares the application's depth buffer with the running platform which allows the platform to more accurately stabilize holograms and content.", EditorStyles.wordWrappedLabel);
                    EditorGUILayout.LabelField("Note: Depth buffer sharing & format is a platform dependent feature.", EditorStyles.wordWrappedLabel);
                    enableDepthBufferSharing = EditorGUILayout.ToggleLeft("Enable Depth Buffer Sharing", enableDepthBufferSharing);

                    /*
                     * TODO: Finish rationalizing this section per platform
                     * EditorGUILayout.LabelField("The depth format determines the level of precision for the depth texture (i.e 16-bit vs 24-bit etc). Using a lower precision format (i.e 16-bit) will generally result in performance gains however this also results in lower precision to resolve one object being farther than another. Thus, particularly for AR devices, it is recommended to lower the camera's far plane value so there is a reduced range of possible values.", EditorStyles.wordWrappedLabel);
                     * enableDepthBufferSharing = EditorGUILayout.BeginToggleGroup("Enable Depth Buffer Sharing", enableDepthBufferSharing);
                     *
                     * if (this.PerfTarget == PerformanceTarget.AR_Headsets)
                     * {
                     *  enable16BitDepthBuffer = EditorGUILayout.ToggleLeft("Set Depth Buffer to 16-bit", enable16BitDepthBuffer);
                     *  enable16BitDepthBuffer = EditorGUILayout.ToggleLeft("Set MRTK Camera Far Plane to 50m", enable16BitDepthBuffer);
                     * }
                     * else if (this.PerfTarget == PerformanceTarget.VR_Standalone)
                     * {
                     *  enable16BitDepthBuffer = EditorGUILayout.ToggleLeft("Set Depth Buffer to 16-bit", enable16BitDepthBuffer);
                     *  enable16BitDepthBuffer = EditorGUILayout.ToggleLeft("Set MRTK Camera Far Plane to 50m", enable16BitDepthBuffer);
                     * }
                     * EditorGUILayout.EndToggleGroup();
                     */
                });

                if (InspectorUIUtility.RenderIndentedButton("Optimize Project"))
                {
                    OptimizeProject();
                }
            }

            GUILayout.EndVertical();
        }
        private void RenderPointerList(SerializedProperty list)
        {
            if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
            {
                pointerOptions.arraySize += 1;

                var newPointerOption = list.GetArrayElementAtIndex(list.arraySize - 1);
                var controllerType   = newPointerOption.FindPropertyRelative("controllerType");
                var handedness       = newPointerOption.FindPropertyRelative("handedness");
                var prefab           = newPointerOption.FindPropertyRelative("pointerPrefab");

                // Reset new entry
                controllerType.intValue     = 0;
                handedness.intValue         = 0;
                prefab.objectReferenceValue = null;
            }

            if (list == null || list.arraySize == 0)
            {
                EditorGUILayout.HelpBox("Create a new Pointer Option entry.", MessageType.Warning);
                return;
            }

            for (int i = 0; i < list.arraySize; i++)
            {
                using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                {
                    var pointerOption  = list.GetArrayElementAtIndex(i);
                    var controllerType = pointerOption.FindPropertyRelative("controllerType");
                    var handedness     = pointerOption.FindPropertyRelative("handedness");
                    var prefab         = pointerOption.FindPropertyRelative("pointerPrefab");

                    using (new EditorGUILayout.HorizontalScope())
                    {
                        EditorGUILayout.PropertyField(prefab);
                        if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                        {
                            list.DeleteArrayElementAtIndex(i);
                            break;
                        }
                    }

                    EditorGUILayout.PropertyField(controllerType, ControllerTypeContent);
                    EditorGUILayout.PropertyField(handedness);
                }
                EditorGUILayout.Space();
            }
        }
        public override void OnInspectorGUI()
        {
            if (!MixedRealityToolkit.IsInitialized)
            {
                return;
            }

            RenderProfileHeader(ProfileTitle, ProfileDescription, target);

            MixedRealityInspectorUtility.CheckMixedRealityConfigured(true);

            serializedObject.Update();

            MixedRealitySceneSystemProfile profile = (MixedRealitySceneSystemProfile)target;

            RenderFoldout(ref showEditorProperties, "Editor Settings", () =>
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    EditorGUILayout.PropertyField(editorManageBuildSettings);
                    EditorGUILayout.PropertyField(editorManageLoadedScenes);
                    EditorGUILayout.PropertyField(editorEnforceSceneOrder);
                    EditorGUILayout.PropertyField(editorEnforceLightingSceneTypes);

                    if (editorEnforceLightingSceneTypes.boolValue)
                    {
                        EditorGUILayout.Space();
                        EditorGUILayout.HelpBox("Below are the component types that will be allowed in lighting scenes. Types not found in this list will be moved to another scene.", MessageType.Info);
                        EditorGUIUtility.labelWidth = LightingSceneTypesLabelWidth;
                        EditorGUILayout.PropertyField(permittedLightingSceneComponentTypes, true);
                        EditorGUIUtility.labelWidth = 0;
                    }
                }
            }, ShowSceneSystem_Editor_PreferenceKey);

            RenderFoldout(ref showManagerProperties, "Manager Scene Settings", () =>
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    EditorGUILayout.HelpBox(managerSceneContent, MessageType.Info);

                    // Disable the tag field since we're drawing manager scenes
                    SceneInfoDrawer.DrawTagProperty = false;
                    EditorGUILayout.PropertyField(useManagerScene);

                    if (useManagerScene.boolValue && profile.ManagerScene.IsEmpty && !Application.isPlaying)
                    {
                        EditorGUILayout.HelpBox("You haven't created a manager scene yet. Click the button below to create one.", MessageType.Warning);
                        var buttonRect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(new GUILayoutOption[] { }));
                        if (GUI.Button(buttonRect, "Create Manager Scene", EditorStyles.miniButton))
                        {
                            // Create a new manager scene and add it to build settings
                            SceneInfo newManagerScene = EditorSceneUtils.CreateAndSaveScene("ManagerScene");
                            SerializedObjectUtils.SetStructValue <SceneInfo>(managerScene, newManagerScene);
                            EditorSceneUtils.AddSceneToBuildSettings(newManagerScene, EditorBuildSettings.scenes, EditorSceneUtils.BuildIndexTarget.First);
                        }
                        EditorGUILayout.Space();
                    }

                    if (useManagerScene.boolValue)
                    {
                        EditorGUILayout.PropertyField(managerScene, includeChildren: true);
                    }
                }
            }, ShowSceneSystem_Manager_PreferenceKey);

            RenderFoldout(ref showLightingProperties, "Lighting Scene Settings", () =>
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    EditorGUILayout.HelpBox(lightingSceneContent, MessageType.Info);

                    EditorGUILayout.PropertyField(useLightingScene);

                    if (useLightingScene.boolValue && profile.NumLightingScenes < 1 && !Application.isPlaying)
                    {
                        EditorGUILayout.HelpBox("You haven't created a lighting scene yet. Click the button below to create one.", MessageType.Warning);
                        var buttonRect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(new GUILayoutOption[] { }));
                        if (GUI.Button(buttonRect, "Create Lighting Scene", EditorStyles.miniButton))
                        {
                            // Create a new lighting scene and add it to build settings
                            SceneInfo newLightingScene = EditorSceneUtils.CreateAndSaveScene("LightingScene");
                            // Create an element in the array
                            lightingScenes.arraySize = 1;
                            serializedObject.ApplyModifiedProperties();
                            SerializedObjectUtils.SetStructValue <SceneInfo>(lightingScenes.GetArrayElementAtIndex(0), newLightingScene);
                            EditorSceneUtils.AddSceneToBuildSettings(newLightingScene, EditorBuildSettings.scenes, EditorSceneUtils.BuildIndexTarget.Last);
                        }
                        EditorGUILayout.Space();
                    }

                    if (useLightingScene.boolValue)
                    {
                        // Disable the tag field since we're drawing lighting scenes
                        SceneInfoDrawer.DrawTagProperty = false;

                        if (profile.NumLightingScenes > 0)
                        {
                            string[] lightingSceneNames        = profile.LightingScenes.Select(l => l.Name).ToArray <string>();
                            defaultLightingSceneIndex.intValue = EditorGUILayout.Popup("Default Lighting Scene", defaultLightingSceneIndex.intValue, lightingSceneNames);
                        }

                        EditorGUILayout.PropertyField(lightingScenes, includeChildren: true);
                        //DrawSceneInfoDragAndDrop(lightingScenes);

                        EditorGUILayout.Space();

                        if (profile.NumLightingScenes > 0)
                        {
                            if (profile.EditorLightingCacheOutOfDate)
                            {
                                EditorGUILayout.HelpBox("Your cached lighting settings may be out of date. This could result in unexpected appearances at runtime.", MessageType.Warning);
                            }
                            if (InspectorUIUtility.RenderIndentedButton(new GUIContent("Update Cached Lighting Settings"), EditorStyles.miniButton))
                            {
                                profile.EditorLightingCacheUpdateRequested = true;
                            }
                        }
                        EditorGUILayout.Space();
                    }
                }
            }, ShowSceneSystem_Lighting_PreferenceKey);

            RenderFoldout(ref showContentProperties, "Content Scene Settings", () =>
            {
                using (new EditorGUI.IndentLevelScope())
                {
                    EditorGUILayout.HelpBox(contentSceneContent, MessageType.Info);

                    // Enable the tag field since we're drawing content scenes
                    SceneInfoDrawer.DrawTagProperty = true;
                    EditorGUILayout.PropertyField(contentScenes, includeChildren: true);
                    //DrawSceneInfoDragAndDrop(contentScenes);
                }
            }, ShowSceneSystem_Content_PreferenceKey);

            serializedObject.ApplyModifiedProperties();

            // Keep this inspector perpetually refreshed
            EditorUtility.SetDirty(target);
        }
Example #10
0
        private void RenderList(SerializedProperty list)
        {
            bool changed = false;

            using (new EditorGUILayout.VerticalScope())
            {
                if (list == null || list.arraySize == 0)
                {
                    EditorGUILayout.HelpBox("The Mixed Reality Camera System will use default settings.\nAdd a settings provider to customize the camera.", MessageType.Info);
                }

                if (InspectorUIUtility.RenderIndentedButton(addSettingsProviderTitle, EditorStyles.miniButton))
                {
                    list.InsertArrayElementAtIndex(list.arraySize);
                    SerializedProperty provider = list.GetArrayElementAtIndex(list.arraySize - 1);

                    SerializedProperty providerName = provider.FindPropertyRelative("componentName");
                    providerName.stringValue = $"New camera settings {list.arraySize - 1}";

                    SerializedProperty runtimePlatform = provider.FindPropertyRelative("runtimePlatform");
                    runtimePlatform.intValue = -1;

                    SerializedProperty configurationProfile = provider.FindPropertyRelative("settingsProfile");
                    configurationProfile.objectReferenceValue = null;

                    serializedObject.ApplyModifiedProperties();

                    SystemType providerType = ((MixedRealityCameraProfile)serializedObject.targetObject).SettingsConfigurations[list.arraySize - 1].ComponentType;
                    providerType.Type = null;

                    providerFoldouts = new bool[list.arraySize];
                    return;
                }

                for (int i = 0; i < list.arraySize; i++)
                {
                    SerializedProperty provider        = list.GetArrayElementAtIndex(i);
                    SerializedProperty providerName    = provider.FindPropertyRelative("componentName");
                    SerializedProperty providerType    = provider.FindPropertyRelative("componentType");
                    SerializedProperty providerProfile = provider.FindPropertyRelative("settingsProfile");
                    SerializedProperty runtimePlatform = provider.FindPropertyRelative("runtimePlatform");

                    using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                    {
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            providerFoldouts[i] = EditorGUILayout.Foldout(providerFoldouts[i], providerName.stringValue, true);

                            if (GUILayout.Button(removeSettingsProviderTitle, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                            {
                                list.DeleteArrayElementAtIndex(i);
                                serializedObject.ApplyModifiedProperties();
                                changed = true;
                                break;
                            }
                        }

                        if (providerFoldouts[i])
                        {
                            EditorGUI.BeginChangeCheck();
                            EditorGUILayout.PropertyField(providerType, componentType);
                            if (EditorGUI.EndChangeCheck())
                            {
                                serializedObject.ApplyModifiedProperties();
                                System.Type type = ((MixedRealityCameraProfile)serializedObject.targetObject).SettingsConfigurations[i].ComponentType.Type;
                                ApplyProviderConfiguration(type, providerName, providerProfile, runtimePlatform);
                                changed = true;
                                break;
                            }

                            EditorGUI.BeginChangeCheck();
                            EditorGUILayout.PropertyField(runtimePlatform, supportedPlatformsTitle);
                            changed |= EditorGUI.EndChangeCheck();

                            var serviceType = (target as MixedRealityCameraProfile).SettingsConfigurations[i].ComponentType;

                            changed |= RenderProfile(providerProfile, typeof(BaseCameraSettingsProfile), true, false, serviceType);

                            serializedObject.ApplyModifiedProperties();
                        }
                    }
                }

                if (changed && MixedRealityToolkit.IsInitialized)
                {
                    EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(MixedRealityToolkit.Instance.ActiveProfile);
                }
            }
        }
Example #11
0
        private void RenderSettingOptimizations()
        {
            GUILayout.BeginVertical("Box");
            EditorGUILayout.LabelField(this.ToolbarTitles[(int)ToolbarSection.Settings], MixedRealityStylesUtility.BoldLargeTitleStyle);
            using (new EditorGUI.IndentLevelScope())
            {
                bool isSinglePassInstancedEnabled = PlayerSettings.stereoRenderingPath == StereoRenderingPath.Instancing;
                BuildSection("Single Pass Instanced Rendering", SinglePassInstanced_URL, GetTitleIcon(isSinglePassInstancedEnabled), () =>
                {
                    EditorGUILayout.LabelField("Single Pass Instanced Rendering is an option in the Unity graphics pipeline to more efficiently render your scene and optimize CPU & GPU work.");

                    EditorGUILayout.HelpBox("This rendering configuration requires shaders to be written to support GPU instancing which is automatic in all Unity & MRTK shaders.Click the \"Documentation\" button for instruction to update your custom shaders to support instancing.", MessageType.Info);

                    using (new GUIEnabledWrapper(!isSinglePassInstancedEnabled))
                    {
                        if (InspectorUIUtility.RenderIndentedButton("Enable Single Pass Instanced rendering"))
                        {
                            PlayerSettings.stereoRenderingPath = StereoRenderingPath.Instancing;
                        }
                    }
                });

                // TODO: Put in Quality settings section

                bool isDepthBufferSharingEnabled = MixedRealityOptimizeUtils.IsDepthBufferSharingEnabled();
                BuildSection("Depth Buffer Sharing", DepthBufferSharing_URL, GetTitleIcon(isDepthBufferSharingEnabled), () =>
                {
                    EditorGUILayout.LabelField("This option shares the application's depth buffer with the running platform which allows the platform to more accurately stabilize holograms and content.", EditorStyles.wordWrappedLabel);

                    EditorGUILayout.HelpBox("Depth buffer sharing requires that a valid depth buffer is submitted to the platform. Click the \"Documentation\" button for instructions to ensure that transparent & text gameobjects write to depth.", MessageType.Info);

                    using (new GUIEnabledWrapper(!isDepthBufferSharingEnabled))
                    {
                        if (InspectorUIUtility.RenderIndentedButton("Enable Depth Buffer Sharing"))
                        {
                            MixedRealityOptimizeUtils.SetDepthBufferSharing(true);
                        }
                    }
                });

                bool is16BitDepthFormat = MixedRealityOptimizeUtils.IsWMRDepthBufferFormat16bit();
                BuildSection("Depth Buffer Format", DepthBufferFormat_URL, GetTitleIcon(is16BitDepthFormat), () =>
                {
                    EditorGUILayout.LabelField("If sharing the depth buffer with the underlying mixed reality platform, it is generally recommended to utilize a 16-bit depth format buffer to save on performance.", EditorStyles.wordWrappedLabel);

                    EditorGUILayout.HelpBox("Although 16-bit depth format is better performing, it can result in z-fighting if the far clip plane is too far. Click the \"Documentation\" button to learn more", MessageType.Info);

                    using (new GUIEnabledWrapper(!is16BitDepthFormat))
                    {
                        if (InspectorUIUtility.RenderIndentedButton("Enable 16-bit depth format"))
                        {
                            MixedRealityOptimizeUtils.SetDepthBufferFormat(true);
                        }
                    }
                });

                bool isGIEnabled = MixedRealityOptimizeUtils.IsRealtimeGlobalIlluminationEnabled();
                BuildSection("Real-time Global Illumination", GlobalIllumination_URL, GetTitleIcon(!isGIEnabled), () =>
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Real-time Global Illumination can produce great visual results but at great expense. It is recommended to disable this feature in lighting settings.", EditorStyles.wordWrappedLabel);
                    if (GUILayout.Button(new GUIContent("View Lighting Settings", "Open Lighting Settings"), EditorStyles.miniButton, GUILayout.Width(160f)))
                    {
                        EditorApplication.ExecuteMenuItem("Window/Rendering/Lighting Settings");
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.HelpBox("Note: Real-time Global Illumination is a per-scene setting.", MessageType.Info);

                    using (new GUIEnabledWrapper(isGIEnabled))
                    {
                        if (InspectorUIUtility.RenderIndentedButton("Disable Real-time Global Illumination"))
                        {
                            MixedRealityOptimizeUtils.SetRealtimeGlobalIlluminationEnabled(false);
                        }
                    }
                });
            }

            GUILayout.EndVertical();
        }
        private void RenderControllerList(SerializedProperty controllerList)
        {
            if (thisProfile.ControllerVisualizationSettings.Length != controllerList.arraySize)
            {
                return;
            }

            EditorGUILayout.Space();

            if (InspectorUIUtility.RenderIndentedButton(ControllerAddButtonContent, EditorStyles.miniButton))
            {
                controllerList.InsertArrayElementAtIndex(controllerList.arraySize);
                var index             = controllerList.arraySize - 1;
                var controllerSetting = controllerList.GetArrayElementAtIndex(index);

                var mixedRealityControllerMappingDescription = controllerSetting.FindPropertyRelative("description");
                mixedRealityControllerMappingDescription.stringValue = typeof(GenericJoystickController).Name;

                var mixedRealityControllerHandedness = controllerSetting.FindPropertyRelative("handedness");
                mixedRealityControllerHandedness.intValue = 1;

                serializedObject.ApplyModifiedProperties();

                thisProfile.ControllerVisualizationSettings[index].ControllerType.Type = typeof(GenericJoystickController);
                return;
            }

            for (int i = 0; i < controllerList.arraySize; i++)
            {
                EditorGUILayout.Space();
                EditorGUILayout.BeginHorizontal();

                var  controllerSetting = controllerList.GetArrayElementAtIndex(i);
                var  mixedRealityControllerMappingDescription = controllerSetting.FindPropertyRelative("description");
                bool hasValidType = thisProfile.ControllerVisualizationSettings[i].ControllerType != null &&
                                    thisProfile.ControllerVisualizationSettings[i].ControllerType.Type != null;

                mixedRealityControllerMappingDescription.stringValue = hasValidType
                    ? thisProfile.ControllerVisualizationSettings[i].ControllerType.Type.Name.ToProperCase()
                    : "Undefined Controller";

                serializedObject.ApplyModifiedProperties();
                var mixedRealityControllerHandedness = controllerSetting.FindPropertyRelative("handedness");
                EditorGUILayout.LabelField($"{mixedRealityControllerMappingDescription.stringValue} {((Handedness)mixedRealityControllerHandedness.intValue).ToString().ToProperCase()} Hand", EditorStyles.boldLabel);

                if (GUILayout.Button(ControllerMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                {
                    controllerList.DeleteArrayElementAtIndex(i);
                    EditorGUILayout.EndHorizontal();
                    GUILayout.EndVertical();
                    return;
                }

                EditorGUILayout.EndHorizontal();

                EditorGUILayout.PropertyField(controllerSetting.FindPropertyRelative("controllerType"));
                EditorGUILayout.PropertyField(controllerSetting.FindPropertyRelative("controllerVisualizationType"));

                if (!hasValidType)
                {
                    EditorGUILayout.HelpBox("A controller type must be defined!", MessageType.Error);
                }

                var handednessValue = mixedRealityControllerHandedness.intValue - 1;

                // Reset in case it was set to something other than left or right.
                if (handednessValue < 0 || handednessValue > 1)
                {
                    handednessValue = 0;
                }

                EditorGUI.BeginChangeCheck();
                handednessValue = EditorGUILayout.IntPopup(new GUIContent(mixedRealityControllerHandedness.displayName, mixedRealityControllerHandedness.tooltip), handednessValue, HandednessSelections, null);

                if (EditorGUI.EndChangeCheck())
                {
                    mixedRealityControllerHandedness.intValue = handednessValue + 1;
                }

                var overrideModel       = controllerSetting.FindPropertyRelative("overrideModel");
                var overrideModelPrefab = overrideModel.objectReferenceValue as GameObject;

                var controllerUseDefaultModelOverride = controllerSetting.FindPropertyRelative("useDefaultModel");

                using (new GUILayout.HorizontalScope())
                {
                    EditorGUILayout.PropertyField(controllerUseDefaultModelOverride);

                    var defaultModelMaterial = controllerSetting.FindPropertyRelative("defaultModelMaterial");
                    EditorGUILayout.PropertyField(defaultModelMaterial);
                }

                if (controllerUseDefaultModelOverride.boolValue && overrideModelPrefab != null)
                {
                    EditorGUILayout.HelpBox("When default model is used, the override model will only be used if the default model cannot be loaded from the driver.", MessageType.Warning);
                }

                EditorGUI.BeginChangeCheck();
                overrideModelPrefab = EditorGUILayout.ObjectField(new GUIContent(overrideModel.displayName, "If no override model is set, the global model is used."), overrideModelPrefab, typeof(GameObject), false) as GameObject;

                if (EditorGUI.EndChangeCheck() && CheckVisualizer(overrideModelPrefab))
                {
                    overrideModel.objectReferenceValue = overrideModelPrefab;
                }
            }
        }
        private void RenderControllerList(SerializedProperty controllerList)
        {
            if (thisProfile.MixedRealityControllerMappings.Length != controllerList.arraySize)
            {
                return;
            }

            if (InspectorUIUtility.RenderIndentedButton(ControllerAddButtonContent, EditorStyles.miniButton))
            {
                AddController(controllerList, typeof(GenericJoystickController));
                return;
            }

            controllerRenderList.Clear();

            // Generating the set of controllers that belong to each Controller Mapping Signature
            Dictionary <ControllerMappingSignature, List <string> > controllersAffectedByMappingSignatures = new Dictionary <ControllerMappingSignature, List <string> >();

            for (int i = 0; i < thisProfile.MixedRealityControllerMappings.Length; i++)
            {
                MixedRealityControllerMapping controllerMapping = thisProfile.MixedRealityControllerMappings[i];
                Type controllerType = controllerMapping.ControllerType;
                if (controllerType == null)
                {
                    continue;
                }

                Handedness handedness = controllerMapping.Handedness;
                SupportedControllerType supportedControllerType = controllerMapping.SupportedControllerType;

                ControllerMappingSignature currentSignature = new ControllerMappingSignature(supportedControllerType, handedness);
                if (!controllersAffectedByMappingSignatures.ContainsKey(currentSignature))
                {
                    controllersAffectedByMappingSignatures.Add(currentSignature, new List <string>());
                }
                controllersAffectedByMappingSignatures[currentSignature].Add(controllerType.ToString());
            }

            showControllerDefinitions = EditorGUILayout.Foldout(showControllerDefinitions, "Controller Definitions", true);
            if (showControllerDefinitions)
            {
                using (var outerVerticalScope = new GUILayout.VerticalScope())
                {
                    GUILayout.HorizontalScope horizontalScope = null;

                    for (int i = 0; i < thisProfile.MixedRealityControllerMappings.Length; i++)
                    {
                        MixedRealityControllerMapping controllerMapping = thisProfile.MixedRealityControllerMappings[i];
                        Type controllerType = controllerMapping.ControllerType;
                        if (controllerType == null)
                        {
                            continue;
                        }

                        Handedness handedness = controllerMapping.Handedness;
                        bool       useCustomInteractionMappings         = controllerMapping.HasCustomInteractionMappings;
                        SupportedControllerType supportedControllerType = controllerMapping.SupportedControllerType;

                        var controllerMappingProperty = controllerList.GetArrayElementAtIndex(i);
                        var handednessProperty        = controllerMappingProperty.FindPropertyRelative("handedness");

                        #region Profile Migration

                        // Between MRTK v2 RC2 and GA, the HoloLens clicker and HoloLens voice select input were migrated from
                        // SupportedControllerType.WindowsMixedReality && Handedness.None to SupportedControllerType.GGVHand && Handedness.None
                        if (supportedControllerType == SupportedControllerType.WindowsMixedReality && handedness == Handedness.None)
                        {
                            for (int j = 0; j < thisProfile.MixedRealityControllerMappings.Length; j++)
                            {
                                if (thisProfile.MixedRealityControllerMappings[j].SupportedControllerType == SupportedControllerType.GGVHand &&
                                    thisProfile.MixedRealityControllerMappings[j].Handedness == Handedness.None)
                                {
                                    if (horizontalScope != null)
                                    {
                                        horizontalScope.Dispose(); horizontalScope = null;
                                    }

                                    serializedObject.ApplyModifiedProperties();

                                    for (int k = 0; k < controllerMapping.Interactions.Length; k++)
                                    {
                                        MixedRealityInteractionMapping currentMapping = controllerMapping.Interactions[k];

                                        if (currentMapping.InputType == DeviceInputType.Select)
                                        {
                                            thisProfile.MixedRealityControllerMappings[j].Interactions[0].MixedRealityInputAction = currentMapping.MixedRealityInputAction;
                                        }
                                        else if (currentMapping.InputType == DeviceInputType.SpatialGrip)
                                        {
                                            thisProfile.MixedRealityControllerMappings[j].Interactions[1].MixedRealityInputAction = currentMapping.MixedRealityInputAction;
                                        }
                                    }

                                    serializedObject.Update();
                                    controllerList.DeleteArrayElementAtIndex(i);
                                    EditorUtility.DisplayDialog("Mappings updated", "The \"HoloLens Voice and Clicker\" mappings have been migrated to a new serialization. Please save this asset.", "Okay, thanks!");
                                    return;
                                }
                            }
                        }

                        #endregion Profile Migration

                        if (!useCustomInteractionMappings)
                        {
                            bool skip = false;

                            // Merge controllers with the same supported controller type.
                            for (int j = 0; j < controllerRenderList.Count; j++)
                            {
                                if (controllerRenderList[j].SupportedControllerType == supportedControllerType &&
                                    controllerRenderList[j].Handedness == handedness)
                                {
                                    try
                                    {
                                        thisProfile.MixedRealityControllerMappings[i].SynchronizeInputActions(controllerRenderList[j].Interactions);
                                    }
                                    catch (ArgumentException e)
                                    {
                                        Debug.LogError($"Controller mappings between {thisProfile.MixedRealityControllerMappings[i].Description} and {controllerMapping.Description} do not match. Error message: {e.Message}");
                                    }
                                    serializedObject.ApplyModifiedProperties();
                                    skip = true;
                                }
                            }

                            if (skip)
                            {
                                continue;
                            }
                        }

                        controllerRenderList.Add(new ControllerRenderProfile(supportedControllerType, handedness, thisProfile.MixedRealityControllerMappings[i].Interactions));

                        string controllerTitle      = thisProfile.MixedRealityControllerMappings[i].Description;
                        var    interactionsProperty = controllerMappingProperty.FindPropertyRelative("interactions");

                        if (useCustomInteractionMappings)
                        {
                            if (horizontalScope != null)
                            {
                                horizontalScope.Dispose(); horizontalScope = null;
                            }

                            GUILayout.Space(24f);

                            using (var verticalScope = new GUILayout.VerticalScope())
                            {
                                using (horizontalScope = new GUILayout.HorizontalScope())
                                {
                                    EditorGUILayout.LabelField(controllerTitle, EditorStyles.boldLabel);

                                    if (GUILayout.Button(ControllerMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                                    {
                                        controllerList.DeleteArrayElementAtIndex(i);
                                        return;
                                    }
                                }

                                EditorGUI.BeginChangeCheck();

                                // Generic Type dropdown
                                Type[] genericTypes           = MixedRealityControllerMappingProfile.CustomControllerMappingTypes;
                                var    genericTypeListContent = new GUIContent[genericTypes.Length];
                                var    genericTypeListIds     = new int[genericTypes.Length];
                                int    currentGenericType     = -1;
                                for (int genericTypeIdx = 0; genericTypeIdx < genericTypes.Length; genericTypeIdx++)
                                {
                                    var attribute = MixedRealityControllerAttribute.Find(genericTypes[genericTypeIdx]);
                                    if (attribute != null)
                                    {
                                        genericTypeListContent[genericTypeIdx] = new GUIContent(attribute.SupportedControllerType.ToString().Replace("Generic", "").ToProperCase() + " Controller");
                                    }
                                    else
                                    {
                                        genericTypeListContent[genericTypeIdx] = new GUIContent("Unknown Controller");
                                    }

                                    genericTypeListIds[genericTypeIdx] = genericTypeIdx;

                                    if (controllerType == genericTypes[genericTypeIdx])
                                    {
                                        currentGenericType = genericTypeIdx;
                                    }
                                }
                                Debug.Assert(currentGenericType != -1);

                                currentGenericType = EditorGUILayout.IntPopup(GenericTypeContent, currentGenericType, genericTypeListContent, genericTypeListIds);
                                controllerType     = genericTypes[currentGenericType];

                                {
                                    // Handedness dropdown
                                    var attribute = MixedRealityControllerAttribute.Find(controllerType);
                                    if (attribute != null && attribute.SupportedHandedness.Length >= 1)
                                    {
                                        // Make sure handedness is valid for the selected controller type.
                                        if (Array.IndexOf(attribute.SupportedHandedness, (Handedness)handednessProperty.intValue) < 0)
                                        {
                                            handednessProperty.intValue = (int)attribute.SupportedHandedness[0];
                                        }

                                        if (attribute.SupportedHandedness.Length >= 2)
                                        {
                                            var handednessListContent = new GUIContent[attribute.SupportedHandedness.Length];
                                            var handednessListIds     = new int[attribute.SupportedHandedness.Length];
                                            for (int handednessIdx = 0; handednessIdx < attribute.SupportedHandedness.Length; handednessIdx++)
                                            {
                                                handednessListContent[handednessIdx] = new GUIContent(attribute.SupportedHandedness[handednessIdx].ToString());
                                                handednessListIds[handednessIdx]     = (int)attribute.SupportedHandedness[handednessIdx];
                                            }

                                            handednessProperty.intValue = EditorGUILayout.IntPopup(HandednessTypeContent, handednessProperty.intValue, handednessListContent, handednessListIds);
                                        }
                                    }
                                    else
                                    {
                                        handednessProperty.intValue = (int)Handedness.None;
                                    }
                                }

                                if (EditorGUI.EndChangeCheck())
                                {
                                    interactionsProperty.ClearArray();
                                    serializedObject.ApplyModifiedProperties();
                                    thisProfile.MixedRealityControllerMappings[i].ControllerType.Type = genericTypes[currentGenericType];
                                    thisProfile.MixedRealityControllerMappings[i].SetDefaultInteractionMapping(true);
                                    serializedObject.ApplyModifiedProperties();
                                    return;
                                }

                                if (InspectorUIUtility.RenderIndentedButton("Edit Input Action Map"))
                                {
                                    ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness);
                                }

                                if (InspectorUIUtility.RenderIndentedButton("Reset Input Actions"))
                                {
                                    interactionsProperty.ClearArray();
                                    serializedObject.ApplyModifiedProperties();
                                    thisProfile.MixedRealityControllerMappings[i].SetDefaultInteractionMapping(true);
                                    serializedObject.ApplyModifiedProperties();
                                }
                            }
                        }
                        else
                        {
                            if (handedness != Handedness.Right)
                            {
                                if (horizontalScope != null)
                                {
                                    horizontalScope.Dispose(); horizontalScope = null;
                                }
                                horizontalScope = new GUILayout.HorizontalScope();
                            }

                            var buttonContent = new GUIContent(controllerTitle, ControllerMappingLibrary.GetControllerTextureScaled(controllerType, handedness));

                            if (GUILayout.Button(buttonContent, MixedRealityStylesUtility.ControllerButtonStyle, GUILayout.Height(128f), GUILayout.MinWidth(32f), GUILayout.ExpandWidth(true)))
                            {
                                ControllerMappingSignature buttonSignature = new ControllerMappingSignature(supportedControllerType, handedness);
                                ControllerPopupWindow.Show(controllerMapping, interactionsProperty, handedness, controllersAffectedByMappingSignatures[buttonSignature]);
                            }
                        }
                    }

                    if (horizontalScope != null)
                    {
                        horizontalScope.Dispose(); horizontalScope = null;
                    }
                }
            }
        }
        private void RenderList(SerializedProperty list)
        {
            // Disable gestures list if we could not initialize successfully
            using (new GUIEnabledWrapper(isInitialized, false))
            {
                EditorGUILayout.Space();
                GUILayout.BeginVertical();

                if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
                {
                    list.arraySize += 1;
                    var speechCommand = list.GetArrayElementAtIndex(list.arraySize - 1);
                    var keyword       = speechCommand.FindPropertyRelative("description");
                    keyword.stringValue = string.Empty;
                    var gestureType = speechCommand.FindPropertyRelative("gestureType");
                    gestureType.intValue = (int)GestureInputType.None;
                    var action   = speechCommand.FindPropertyRelative("action");
                    var actionId = action.FindPropertyRelative("id");
                    actionId.intValue = 0;
                    var actionDescription = action.FindPropertyRelative("description");
                    actionDescription.stringValue = string.Empty;
                    var actionConstraint = action.FindPropertyRelative("axisConstraint");
                    actionConstraint.intValue = 0;
                }

                if (list == null || list.arraySize == 0)
                {
                    EditorGUILayout.HelpBox("Define a new Gesture.", MessageType.Warning);
                    GUILayout.EndVertical();
                    UpdateGestureLabels();
                    return;
                }

                GUILayout.BeginVertical();

                GUILayout.BeginHorizontal();
                var labelWidth = EditorGUIUtility.labelWidth;
                EditorGUIUtility.labelWidth = 24f;
                EditorGUILayout.LabelField(DescriptionContent, GUILayout.ExpandWidth(true));
                EditorGUILayout.LabelField(GestureTypeContent, GUILayout.Width(80f));
                EditorGUILayout.LabelField(ActionContent, GUILayout.Width(64f));
                EditorGUILayout.LabelField(string.Empty, GUILayout.Width(24f));
                EditorGUIUtility.labelWidth = labelWidth;
                GUILayout.EndHorizontal();

                var inputActions = GetInputActions();

                for (int i = 0; i < list.arraySize; i++)
                {
                    EditorGUILayout.BeginHorizontal();
                    SerializedProperty gesture = list.GetArrayElementAtIndex(i);
                    var keyword           = gesture.FindPropertyRelative("description");
                    var gestureType       = gesture.FindPropertyRelative("gestureType");
                    var action            = gesture.FindPropertyRelative("action");
                    var actionId          = action.FindPropertyRelative("id");
                    var actionDescription = action.FindPropertyRelative("description");
                    var actionConstraint  = action.FindPropertyRelative("axisConstraint");

                    EditorGUILayout.PropertyField(keyword, GUIContent.none, GUILayout.ExpandWidth(true));

                    Debug.Assert(allGestureLabels.Length == allGestureIds.Length);

                    var gestureLabels = new GUIContent[allGestureLabels.Length + 1];
                    var gestureIds    = new int[allGestureIds.Length + 1];

                    gestureLabels[0] = new GUIContent(((GestureInputType)gestureType.intValue).ToString());
                    gestureIds[0]    = gestureType.intValue;

                    for (int j = 0; j < allGestureLabels.Length; j++)
                    {
                        gestureLabels[j + 1] = allGestureLabels[j];
                        gestureIds[j + 1]    = allGestureIds[j];
                    }

                    EditorGUI.BeginChangeCheck();
                    gestureType.intValue = EditorGUILayout.IntPopup(GUIContent.none, gestureType.intValue, gestureLabels, gestureIds, GUILayout.Width(80f));

                    if (EditorGUI.EndChangeCheck())
                    {
                        serializedObject.ApplyModifiedProperties();
                        UpdateGestureLabels();
                    }

                    EditorGUI.BeginChangeCheck();

                    actionId.intValue = EditorGUILayout.IntPopup(GUIContent.none, actionId.intValue, actionLabels, actionIds, GUILayout.Width(64f));

                    if (EditorGUI.EndChangeCheck())
                    {
                        MixedRealityInputAction inputAction = MixedRealityInputAction.None;
                        int idx = actionId.intValue - 1;
                        if (idx >= 0 && idx < inputActions.Length)
                        {
                            inputAction = inputActions[idx];
                        }

                        actionDescription.stringValue   = inputAction.Description;
                        actionConstraint.enumValueIndex = (int)inputAction.AxisConstraint;
                        serializedObject.ApplyModifiedProperties();
                    }

                    if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                    {
                        list.DeleteArrayElementAtIndex(i);
                        serializedObject.ApplyModifiedProperties();
                        UpdateGestureLabels();
                    }

                    EditorGUILayout.EndHorizontal();
                }

                GUILayout.EndVertical();
                GUILayout.EndVertical();
            }
        }
        public override void OnInspectorGUI()
        {
            if (!RenderProfileHeader(ProfileTitle, ProfileDescription, target, true, BackProfileType.Input))
            {
                return;
            }

            using (new EditorGUI.DisabledGroupScope(IsProfileLock((BaseMixedRealityProfile)target)))
            {
                serializedObject.Update();

                EditorGUILayout.Space();
                EditorGUILayout.PropertyField(pointingExtent);
                EditorGUILayout.PropertyField(defaultRaycastLayerMasks, RaycastLayerMaskContent, true);
                EditorGUILayout.PropertyField(pointerMediator);
                EditorGUILayout.PropertyField(primaryPointerSelector);

                GUIStyle boldFoldout = new GUIStyle(EditorStyles.foldout)
                {
                    fontStyle = FontStyle.Bold
                };

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Gaze Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.Space();
                    EditorGUILayout.PropertyField(gazeCursorPrefab, GazeCursorPrefabContent);
                    EditorGUILayout.PropertyField(gazeProviderType);
                    EditorGUILayout.PropertyField(useHeadGazeOverride);

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.PropertyField(useEyeTrackingDataWhenAvailable, UseEyeTrackingDataContent);
                    // Render a help link for getting started with eyetracking documentation
                    string helpURL = "https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/input/eye-tracking/eye-tracking-basic-setup";
                    InspectorUIUtility.RenderDocumentationButton(helpURL);
                    EditorGUILayout.EndHorizontal();

#if UNITY_2019_3_OR_NEWER
                    if (useEyeTrackingDataWhenAvailable.boolValue && MixedRealityOptimizeUtils.IsBuildTargetUWP() && !PlayerSettings.WSA.GetCapability(PlayerSettings.WSACapability.GazeInput))
                    {
                        EditorGUILayout.HelpBox(EnableGazeCapabilityContent, MessageType.Warning);
                        if (InspectorUIUtility.RenderIndentedButton("Set GazeInput capability"))
                        {
                            PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.GazeInput, true);
                        }
                    }
#endif // UNITY_2019_3_OR_NEWER

                    EditorGUILayout.Space();

                    showGazeProviderProperties = EditorGUILayout.Foldout(showGazeProviderProperties, "Gaze Provider Settings", true, boldFoldout);
                    if (showGazeProviderProperties && CameraCache.Main != null)
                    {
                        var gazeProvider = CameraCache.Main.GetComponent <IMixedRealityGazeProvider>();
                        CreateCachedEditor((Object)gazeProvider, null, ref gazeProviderEditor);

                        // Provide a convenient way to toggle the gaze provider as enabled/disabled via editor
                        gazeProvider.Enabled = EditorGUILayout.Toggle("Enable Gaze Provider", gazeProvider.Enabled);

                        if (gazeProviderEditor != null)
                        {
                            using (new EditorGUI.IndentLevelScope())
                            {
                                // Draw out the rest of the Gaze Provider's settings
                                gazeProviderEditor.OnInspectorGUI();
                            }
                        }
                    }
                }

                EditorGUILayout.Space();
                showPointerOptionProperties = EditorGUILayout.Foldout(showPointerOptionProperties, "Pointer Options", true, boldFoldout);

                if (showPointerOptionProperties)
                {
                    using (new EditorGUI.IndentLevelScope())
                    {
                        RenderPointerList(pointerOptions);
                    }
                }

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Debug Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(debugDrawPointingRays);
                    EditorGUILayout.PropertyField(debugDrawPointingRayColors, true);
                }

                serializedObject.ApplyModifiedProperties();
            }
        }
        private void RenderPointerList(SerializedProperty list)
        {
            if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
            {
                pointerOptions.arraySize += 1;

                var newPointerOption = list.GetArrayElementAtIndex(list.arraySize - 1);
                var controllerType   = newPointerOption.FindPropertyRelative("controllerType");
                var handedness       = newPointerOption.FindPropertyRelative("handedness");
                var prefab           = newPointerOption.FindPropertyRelative("pointerPrefab");
                var raycastLayerMask = newPointerOption.FindPropertyRelative("prioritizedLayerMasks");

                // Reset new entry
                controllerType.intValue     = 0;
                handedness.intValue         = 0;
                prefab.objectReferenceValue = null;
                raycastLayerMask.arraySize  = 0;
            }

            if (list == null || list.arraySize == 0)
            {
                EditorGUILayout.HelpBox("Create a new Pointer Option entry.", MessageType.Warning);
                return;
            }

            bool anyPrefabChanged = false;

            for (int i = 0; i < list.arraySize; i++)
            {
                using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                {
                    Color prevColor = GUI.color;

                    var pointerOption         = list.GetArrayElementAtIndex(i);
                    var controllerType        = pointerOption.FindPropertyRelative("controllerType");
                    var handedness            = pointerOption.FindPropertyRelative("handedness");
                    var prefab                = pointerOption.FindPropertyRelative("pointerPrefab");
                    var prioritizedLayerMasks = pointerOption.FindPropertyRelative("prioritizedLayerMasks");

                    GameObject           pointerPrefab = prefab.objectReferenceValue as GameObject;
                    IMixedRealityPointer pointer       = pointerPrefab != null?pointerPrefab.GetComponent <IMixedRealityPointer>() : null;

                    // Display an error if the prefab doesn't have a IMixedRealityPointer Component
                    if (pointer.IsNull())
                    {
                        InspectorUIUtility.DrawError($"The prefab associated with this pointer option needs an {typeof(IMixedRealityPointer).Name} component");
                        GUI.color = MixedRealityInspectorUtility.ErrorColor;
                    }

                    using (new EditorGUILayout.HorizontalScope())
                    {
                        EditorGUILayout.PropertyField(prefab);
                        if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                        {
                            list.DeleteArrayElementAtIndex(i);
                            break;
                        }
                    }

                    EditorGUILayout.PropertyField(controllerType, ControllerTypeContent);
                    EditorGUILayout.PropertyField(handedness);

                    // Ultimately sync the pointer prefab's value with the pointer option's
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(prioritizedLayerMasks, PointerRaycastLayerMaskContent, true);
                    if (EditorGUI.EndChangeCheck() && pointer.IsNotNull())
                    {
                        Undo.RecordObject(pointerPrefab, "Sync Pointer Prefab");

                        int prioritizedLayerMasksCount = prioritizedLayerMasks.arraySize;
                        if (pointer.PrioritizedLayerMasksOverride?.Length != prioritizedLayerMasksCount)
                        {
                            pointer.PrioritizedLayerMasksOverride = new LayerMask[prioritizedLayerMasksCount];
                        }

                        for (int j = 0; j < prioritizedLayerMasksCount; j++)
                        {
                            pointer.PrioritizedLayerMasksOverride[j] = prioritizedLayerMasks.GetArrayElementAtIndex(j).intValue;
                        }

                        PrefabUtility.RecordPrefabInstancePropertyModifications(pointerPrefab);
                        EditorUtility.SetDirty(pointerPrefab);
                        anyPrefabChanged = true;
                    }

                    GUI.color = prevColor;
                }
                EditorGUILayout.Space();
            }

            if (anyPrefabChanged)
            {
                AssetDatabase.SaveAssets();
            }
        }
Example #17
0
        private void RenderSceneOptimizations()
        {
            GUILayout.BeginVertical("Box");
            EditorGUILayout.LabelField(this.ToolbarTitles[(int)ToolbarSection.Scene], BoldLargeTitle);
            using (new EditorGUI.IndentLevelScope())
            {
                EditorGUILayout.LabelField("This section provides controls and performance information for the currently opened scene. Any optimizations performed are only for the active scene at any moment. Also be aware that changes made while in editor Play mode will not be saved.", EditorStyles.wordWrappedLabel);

                BuildSection("Lighting Settings", "https://docs.unity3d.com/Manual/GlobalIllumination.html", () =>
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Global Illumination can produce great visual results but sometimes at great expense.", EditorStyles.wordWrappedLabel);
                    if (GUILayout.Button(new GUIContent("View Lighting Settings", "Open Lighting Settings"), EditorStyles.miniButton, GUILayout.Width(160f)))
                    {
                        EditorApplication.ExecuteMenuItem("Window/Rendering/Lighting Settings");
                    }
                    EditorGUILayout.EndHorizontal();

                    disableRealtimeGlobalIllumination = EditorGUILayout.ToggleLeft("Disable Realtime Global Illumination", disableRealtimeGlobalIllumination);

                    if (this.PerfTarget == PerformanceTarget.AR_Headsets)
                    {
                        disableBakedGlobalIllumination = EditorGUILayout.ToggleLeft("Disable Baked Global Illumination", disableBakedGlobalIllumination);
                    }

                    if (InspectorUIUtility.RenderIndentedButton("Optimize Lighting"))
                    {
                        OptimizeScene();
                    }
                });

                BuildSection("Live Scene Analysis", null, () =>
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField(lastAnalyzedTime == null ? "Click analysis button for MRTK to scan your currently opened scene" : "Scanned " + GetRelativeTime(lastAnalyzedTime));

                    if (GUILayout.Button("Analyze Scene", GUILayout.Width(160f)))
                    {
                        AnalyzeScene();
                        lastAnalyzedTime = DateTime.UtcNow;
                    }
                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.Space();

                    if (lastAnalyzedTime != null)
                    {
                        // Lighting analysis
                        bool showNumOfSceneLights = this.sceneLights != null && this.sceneLights.Length > SceneLightCountMax[(int)PerfTarget];
                        bool showDisableShadows   = this.PerfTarget == PerformanceTarget.AR_Headsets;
                        if (showNumOfSceneLights || showDisableShadows)
                        {
                            EditorGUILayout.LabelField("Lighting Analysis", EditorStyles.boldLabel);
                            if (showNumOfSceneLights)
                            {
                                EditorGUILayout.LabelField(this.sceneLights.Length + " lights in the scene. Consider reducing the number of lights.");
                            }

                            if (showDisableShadows)
                            {
                                foreach (var l in this.sceneLights)
                                {
                                    if (l.shadows != LightShadows.None)
                                    {
                                        EditorGUILayout.ObjectField("Disable shadows", l, typeof(Light), true);
                                    }
                                }
                            }
                            EditorGUILayout.Space();
                        }

                        // Mesh Analysis
                        EditorGUILayout.LabelField("Polygon Count Analysis", EditorStyles.boldLabel);

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField(TotalPolyCountStr);
                        EditorGUILayout.LabelField(TotalActivePolyCountStr);
                        EditorGUILayout.LabelField(TotalInactivePolyCountStr);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.LabelField("Top " + TopListSize + " GameObjects in scene with highest polygon count");
                        for (int i = 0; i < LargestMeshes.Length; i++)
                        {
                            if (LargestMeshes[i] != null)
                            {
                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("Num of Polygons: " + this.LargestMeshSizes[i].ToString("N0"));
                                EditorGUILayout.ObjectField(this.LargestMeshes[i], typeof(GameObject), true);
                                if (GUILayout.Button(new GUIContent("View", "Selects & view this asset in inspector"), EditorStyles.miniButton, GUILayout.Width(42f)))
                                {
                                    Selection.activeObject = this.LargestMeshes[i];
                                }
                                EditorGUILayout.EndHorizontal();
                            }
                        }
                    }
                });
            }

            GUILayout.EndVertical();
        }
Example #18
0
        private void RenderPointerList(SerializedProperty list)
        {
            var profile = target as MixedRealityPointerProfile;

            if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
            {
                pointerOptions.arraySize += 1;

                var newPointerOption = list.GetArrayElementAtIndex(list.arraySize - 1);
                var controllerType   = newPointerOption.FindPropertyRelative("controllerType");
                var handedness       = newPointerOption.FindPropertyRelative("handedness");
                var prefab           = newPointerOption.FindPropertyRelative("pointerPrefab");
                var raycastLayerMask = newPointerOption.FindPropertyRelative("prioritizedLayerMasks");

                // Reset new entry
                controllerType.intValue     = 0;
                handedness.intValue         = 0;
                prefab.objectReferenceValue = null;
                raycastLayerMask.arraySize  = 0;
            }

            if (list == null || list.arraySize == 0)
            {
                EditorGUILayout.HelpBox("Create a new Pointer Option entry.", MessageType.Warning);
                return;
            }

            for (int i = 0; i < list.arraySize; i++)
            {
                IMixedRealityPointer pointer = null;
                Object pointerPrefab         = null;

                using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                {
                    Color prevColor = GUI.color;

                    var pointerOption         = list.GetArrayElementAtIndex(i);
                    var controllerType        = pointerOption.FindPropertyRelative("controllerType");
                    var handedness            = pointerOption.FindPropertyRelative("handedness");
                    var prefab                = pointerOption.FindPropertyRelative("pointerPrefab");
                    var prioritizedLayerMasks = pointerOption.FindPropertyRelative("prioritizedLayerMasks");

                    pointerPrefab = prefab.objectReferenceValue;
                    pointer       = pointerPrefab.IsNull() ? null : ((GameObject)pointerPrefab).GetComponent <IMixedRealityPointer>();

                    // Display an error if the prefab doesn't have a IMixedRealityPointer Component
                    if (pointer == null)
                    {
                        InspectorUIUtility.DrawError($"The prefab associated with this pointer option needs an {typeof(IMixedRealityPointer).Name} component");

                        GUI.color = MixedRealityInspectorUtility.ErrorColor;
                    }
                    // if the prefab does have the component, provide a field to display and edit it's PrioritzedLayerMaskOverrides if it specifies a way to get it
                    else
                    {
                        // sync the pointer option with the prefab
                        if (pointer.PrioritizedLayerMasksOverride != null)
                        {
                            if (prioritizedLayerMasks.arraySize != pointer.PrioritizedLayerMasksOverride.Length)
                            {
                                prioritizedLayerMasks.arraySize = pointer.PrioritizedLayerMasksOverride.Length;
                            }
                            foreach (LayerMask mask in pointer.PrioritizedLayerMasksOverride)
                            {
                                SerializedProperty item = prioritizedLayerMasks.GetArrayElementAtIndex(prioritizedLayerMasks.arraySize - 1);
                                item.intValue = mask;
                            }
                        }

                        // if after syncing the the pointer option list is still empty, initialize with the global default
                        // sync the pointer option with the prefab
                        if (prioritizedLayerMasks.arraySize == 0)
                        {
                            for (int j = 0; j < pointingRaycastLayerMasks.arraySize; j++)
                            {
                                var mask = pointingRaycastLayerMasks.GetArrayElementAtIndex(j).intValue;

                                prioritizedLayerMasks.InsertArrayElementAtIndex(prioritizedLayerMasks.arraySize);
                                SerializedProperty item = prioritizedLayerMasks.GetArrayElementAtIndex(prioritizedLayerMasks.arraySize - 1);
                                item.intValue = mask;
                            }
                        }
                    }

                    using (new EditorGUILayout.HorizontalScope())
                    {
                        EditorGUILayout.PropertyField(prefab);
                        if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                        {
                            list.DeleteArrayElementAtIndex(i);
                            break;
                        }
                    }

                    EditorGUILayout.PropertyField(controllerType, ControllerTypeContent);
                    EditorGUILayout.PropertyField(handedness);

                    // Ultimately sync the pointer prefab's value with the pointer option's
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(prioritizedLayerMasks, new GUIContent("Pointer Raycast LayerMasks"), true);
                    if (EditorGUI.EndChangeCheck() && pointer.PrioritizedLayerMasksOverride != null)
                    {
                        Undo.RecordObject(pointerPrefab, "Sync Pointer Prefab");
                        pointer.PrioritizedLayerMasksOverride = new LayerMask[prioritizedLayerMasks.arraySize];
                        for (int j = 0; j < prioritizedLayerMasks.arraySize; j++)
                        {
                            pointer.PrioritizedLayerMasksOverride[j] = prioritizedLayerMasks.GetArrayElementAtIndex(j).intValue;
                        }

                        PrefabUtility.RecordPrefabInstancePropertyModifications(pointerPrefab);
                    }

                    GUI.color = prevColor;
                }
                EditorGUILayout.Space();
            }
        }
        public override void OnInspectorGUI()
        {
            var configurationProfile = (MixedRealityToolkitConfigurationProfile)target;

            serializedObject.Update();

            RenderMRTKLogo();

            CheckEditorPlayMode();

            if (!MixedRealityToolkit.IsInitialized)
            {
                EditorGUILayout.HelpBox("No Mixed Reality Toolkit found in scene.", MessageType.Warning);
                if (InspectorUIUtility.RenderIndentedButton("Add Mixed Reality Toolkit instance to scene"))
                {
                    MixedRealityInspectorUtility.AddMixedRealityToolkitToScene(configurationProfile);
                }
            }

            if (!configurationProfile.IsCustomProfile)
            {
                EditorGUILayout.HelpBox("The Mixed Reality Toolkit's core SDK profiles can be used to get up and running quickly.\n\n" +
                                        "You can use the default profiles provided, copy and customize the default profiles, or create your own.", MessageType.Warning);
                EditorGUILayout.BeginHorizontal();

                if (GUILayout.Button("Copy & Customize"))
                {
                    SerializedProperty targetProperty  = null;
                    UnityEngine.Object selectionTarget = null;
                    // If we have an active MRTK instance, find its config profile serialized property
                    if (MixedRealityToolkit.IsInitialized)
                    {
                        selectionTarget = MixedRealityToolkit.Instance;
                        SerializedObject mixedRealityToolkitObject = new SerializedObject(MixedRealityToolkit.Instance);
                        targetProperty = mixedRealityToolkitObject.FindProperty("activeProfile");
                    }
                    MixedRealityProfileCloneWindow.OpenWindow(null, target as BaseMixedRealityProfile, targetProperty, selectionTarget);
                }

                if (MixedRealityToolkit.IsInitialized)
                {
                    if (GUILayout.Button("Create new profiles"))
                    {
                        ScriptableObject profile = CreateInstance(nameof(MixedRealityToolkitConfigurationProfile));
                        var newProfile           = profile.CreateAsset("Assets/MixedRealityToolkit.Generated/CustomProfiles") as MixedRealityToolkitConfigurationProfile;
                        UnityEditor.Undo.RecordObject(MixedRealityToolkit.Instance, "Create new profiles");
                        MixedRealityToolkit.Instance.ActiveProfile = newProfile;
                        Selection.activeObject = newProfile;
                    }
                }

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.LabelField(string.Empty, GUI.skin.horizontalSlider);
            }

            bool isGUIEnabled = !IsProfileLock((BaseMixedRealityProfile)target) && GUI.enabled;

            GUI.enabled = isGUIEnabled;

            EditorGUI.BeginChangeCheck();
            bool changed = false;

            // Experience configuration
            ExperienceScale experienceScale = (ExperienceScale)targetExperienceScale.intValue;

            EditorGUILayout.PropertyField(targetExperienceScale, TargetScaleContent);

            string scaleDescription = GetExperienceDescription(experienceScale);

            if (!string.IsNullOrEmpty(scaleDescription))
            {
                EditorGUILayout.HelpBox(scaleDescription, MessageType.Info);
                EditorGUILayout.Space();
            }

            changed |= EditorGUI.EndChangeCheck();

            EditorGUILayout.BeginHorizontal();

            EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(100));
            GUI.enabled = true; // Force enable so we can view profile defaults

            int prefsSelectedTab = EditorPrefs.GetInt(SelectedTabPreferenceKey);

            SelectedProfileTab = GUILayout.SelectionGrid(prefsSelectedTab, ProfileTabTitles, 1, EditorStyles.boldLabel, GUILayout.MaxWidth(125));
            if (SelectedProfileTab != prefsSelectedTab)
            {
                EditorPrefs.SetInt(SelectedTabPreferenceKey, SelectedProfileTab);
            }

            GUI.enabled = isGUIEnabled;
            EditorGUILayout.EndVertical();

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            using (new EditorGUI.IndentLevelScope())
            {
                changed |= RenderProfileFuncs[SelectedProfileTab]();
            }
            EditorGUILayout.EndVertical();
            EditorGUILayout.EndHorizontal();

            serializedObject.ApplyModifiedProperties();
            GUI.enabled = true;

            if (changed && MixedRealityToolkit.IsInitialized)
            {
                EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(configurationProfile);
            }
        }
        private void RenderList(SerializedProperty list)
        {
            // Disable speech commands if we could not initialize successfully
            using (new EditorGUI.DisabledGroupScope(!isInitialized))
            {
                EditorGUILayout.Space();
                using (new EditorGUILayout.VerticalScope())
                {
                    if (InspectorUIUtility.RenderIndentedButton(AddButtonContent, EditorStyles.miniButton))
                    {
                        list.arraySize += 1;
                        var speechCommand   = list.GetArrayElementAtIndex(list.arraySize - 1);
                        var localizationKey = speechCommand.FindPropertyRelative("localizationKey");
                        localizationKey.stringValue = string.Empty;
                        var keyword = speechCommand.FindPropertyRelative("keyword");
                        keyword.stringValue = string.Empty;
                        var keyCode = speechCommand.FindPropertyRelative("keyCode");
                        keyCode.intValue = (int)KeyCode.None;
                        var action   = speechCommand.FindPropertyRelative("action");
                        var actionId = action.FindPropertyRelative("id");
                        actionId.intValue = 0;
                    }

                    EditorGUILayout.Space();

                    if (list == null || list.arraySize == 0)
                    {
                        EditorGUILayout.HelpBox("Create a new Speech Command.", MessageType.Warning);
                        return;
                    }

                    for (int i = 0; i < list.arraySize; i++)
                    {
                        using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                        {
                            SerializedProperty speechCommand = list.GetArrayElementAtIndex(i);

                            using (new EditorGUILayout.HorizontalScope())
                            {
                                var keyword = speechCommand.FindPropertyRelative("keyword");
                                EditorGUILayout.PropertyField(keyword, KeywordContent);
                                if (GUILayout.Button(MinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                                {
                                    list.DeleteArrayElementAtIndex(i);
                                    break;
                                }
                            }

                            var localizationKey = speechCommand.FindPropertyRelative("localizationKey");
                            EditorGUILayout.PropertyField(localizationKey, LocalizationContent);

                            var keyCode = speechCommand.FindPropertyRelative("keyCode");
                            EditorGUILayout.PropertyField(keyCode, KeyCodeContent);

                            var action            = speechCommand.FindPropertyRelative("action");
                            var actionId          = action.FindPropertyRelative("id");
                            var actionDescription = action.FindPropertyRelative("description");
                            var actionConstraint  = action.FindPropertyRelative("axisConstraint");

                            EditorGUI.BeginChangeCheck();
                            actionId.intValue = EditorGUILayout.IntPopup(ActionContent, actionId.intValue, actionLabels, actionIds);

                            if (EditorGUI.EndChangeCheck())
                            {
                                MixedRealityInputAction inputAction = actionId.intValue == 0 ? MixedRealityInputAction.None : MixedRealityToolkit.Instance.ActiveProfile.InputSystemProfile.InputActionsProfile.InputActions[actionId.intValue - 1];
                                actionDescription.stringValue   = inputAction.Description;
                                actionConstraint.enumValueIndex = (int)inputAction.AxisConstraint;
                            }
                        }
                        EditorGUILayout.Space();
                    }
                }
            }
        }
Example #21
0
        private void RenderList(SerializedProperty list)
        {
            bool changed = false;

            using (new EditorGUILayout.VerticalScope())
            {
                if (InspectorUIUtility.RenderIndentedButton(AddObserverContent, EditorStyles.miniButton))
                {
                    list.InsertArrayElementAtIndex(list.arraySize);
                    SerializedProperty observer = list.GetArrayElementAtIndex(list.arraySize - 1);

                    SerializedProperty observerName = observer.FindPropertyRelative("componentName");
                    observerName.stringValue = $"New spatial observer {list.arraySize - 1}";

                    SerializedProperty runtimePlatform = observer.FindPropertyRelative("runtimePlatform");
                    runtimePlatform.intValue = -1;

                    SerializedProperty configurationProfile = observer.FindPropertyRelative("observerProfile");
                    configurationProfile.objectReferenceValue = null;

                    serializedObject.ApplyModifiedProperties();

                    SystemType observerType = ((MixedRealitySpatialAwarenessSystemProfile)serializedObject.targetObject).ObserverConfigurations[list.arraySize - 1].ComponentType;
                    observerType.Type = null;

                    observerFoldouts = new bool[list.arraySize];
                    return;
                }

                if (list == null || list.arraySize == 0)
                {
                    EditorGUILayout.HelpBox("The Mixed Reality Spatial Awareness System requires one or more observers.", MessageType.Warning);
                    return;
                }

                for (int i = 0; i < list.arraySize; i++)
                {
                    SerializedProperty observer        = list.GetArrayElementAtIndex(i);
                    SerializedProperty observerName    = observer.FindPropertyRelative("componentName");
                    SerializedProperty observerType    = observer.FindPropertyRelative("componentType");
                    SerializedProperty observerProfile = observer.FindPropertyRelative("observerProfile");
                    SerializedProperty runtimePlatform = observer.FindPropertyRelative("runtimePlatform");

                    using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
                    {
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            observerFoldouts[i] = EditorGUILayout.Foldout(observerFoldouts[i], observerName.stringValue, true);

                            if (GUILayout.Button(RemoveObserverContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                            {
                                list.DeleteArrayElementAtIndex(i);
                                serializedObject.ApplyModifiedProperties();
                                changed = true;
                                break;
                            }
                        }

                        if (observerFoldouts[i])
                        {
                            EditorGUI.BeginChangeCheck();
                            EditorGUILayout.PropertyField(observerType, ComponentTypeContent);
                            if (EditorGUI.EndChangeCheck())
                            {
                                serializedObject.ApplyModifiedProperties();
                                System.Type type = ((MixedRealitySpatialAwarenessSystemProfile)serializedObject.targetObject).ObserverConfigurations[i].ComponentType.Type;
                                ApplyObserverConfiguration(type, observerName, observerProfile, runtimePlatform);
                                break;
                            }

                            EditorGUI.BeginChangeCheck();
                            EditorGUILayout.PropertyField(runtimePlatform, RuntimePlatformContent);
                            changed |= EditorGUI.EndChangeCheck();

                            System.Type serviceType = null;
                            if (observerProfile.objectReferenceValue != null)
                            {
                                serviceType = (target as MixedRealitySpatialAwarenessSystemProfile).ObserverConfigurations[i].ComponentType;
                            }

                            changed |= RenderProfile(observerProfile, null, true, false, serviceType);

                            serializedObject.ApplyModifiedProperties();
                        }
                    }
                }

                if (changed && MixedRealityToolkit.IsInitialized)
                {
                    EditorApplication.delayCall += () => MixedRealityToolkit.Instance.ResetConfiguration(MixedRealityToolkit.Instance.ActiveProfile);
                }
            }
        }
Example #22
0
        private void RenderShaderOptimizations()
        {
            GUILayout.BeginVertical("Box");
            EditorGUILayout.LabelField(this.ToolbarTitles[(int)ToolbarSection.Shader], MixedRealityStylesUtility.BoldLargeTitleStyle);
            using (new EditorGUI.IndentLevelScope())
            {
                EditorGUILayout.LabelField("The Unity standard shader is generally not performant or optimized for Mixed Reality development. The MRTK Standard shader can be a more performant option. "
                                           + "This tool allows developers to discover and automatically convert materials in their project to the replacement shader option below. It is recommended to utilize the MRTK Standard Shader."
                                           , EditorStyles.wordWrappedLabel);
                EditorGUILayout.Space();

                replacementShader = (Shader)EditorGUILayout.ObjectField("Replacement Shader", replacementShader, typeof(Shader), false);
                if (replacementShader == null)
                {
                    EditorGUILayout.HelpBox("Please set a replacement shader to utilize this tool", MessageType.Error);
                    if (InspectorUIUtility.RenderIndentedButton(new GUIContent("Use MRTK Standard Shader", "Set Replacement Shader to MRKT Standard Shader"), EditorStyles.miniButton, GUILayout.Width(200f)))
                    {
                        FindShaders();
                    }
                }
                else
                {
                    onlyUnityShader = EditorGUILayout.ToggleLeft("Only Discover Materials with Unity Standard Shader", onlyUnityShader);
                    EditorGUILayout.Space();

                    EditorGUILayout.BeginHorizontal();
                    if (GUILayout.Button("Discover Materials in Assets"))
                    {
                        DiscoverMaterials();
                    }

                    bool wasGUIEnabled = GUI.enabled;
                    GUI.enabled = wasGUIEnabled && discoveredMaterials.Count > 0;
                    if (GUILayout.Button("Convert All Discovered Materials"))
                    {
                        ConvertMaterials();
                    }
                    GUI.enabled = wasGUIEnabled;
                    EditorGUILayout.EndHorizontal();

                    if (discoveredMaterials.Count > 0)
                    {
                        showDiscoveredMaterials = EditorGUILayout.Foldout(showDiscoveredMaterials, "Discovered Materials", true);
                        if (showDiscoveredMaterials)
                        {
                            using (new EditorGUI.IndentLevelScope())
                            {
                                EditorGUILayout.LabelField("Discovered " + discoveredMaterials.Count + " materials to convert");

                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("Current Shader", EditorStyles.boldLabel);
                                EditorGUILayout.LabelField("Material Asset", EditorStyles.boldLabel);
                                EditorGUILayout.EndHorizontal();

                                for (int i = 0; i < discoveredMaterials.Count; i++)
                                {
                                    if (discoveredMaterials[i] != null)
                                    {
                                        EditorGUILayout.BeginHorizontal();
                                        EditorGUILayout.LabelField(discoveredMaterials[i].shader.name);
                                        discoveredMaterials[i] = (Material)EditorGUILayout.ObjectField(discoveredMaterials[i], typeof(Material), false);
                                        if (GUILayout.Button(new GUIContent("View", "Selects & views this asset in inspector"), EditorStyles.miniButton, GUILayout.Width(42f)))
                                        {
                                            Selection.activeObject = this.discoveredMaterials[i];
                                        }
                                        if (GUILayout.Button(new GUIContent("Convert", "Converts this material's shader to the replacement shader"), EditorStyles.miniButton, GUILayout.Width(64f)))
                                        {
                                            Undo.RecordObject(this.discoveredMaterials[i], "Convert to MRTK Standard shader");
                                            ConvertMaterial(this.discoveredMaterials[i]);
                                        }
                                        EditorGUILayout.EndHorizontal();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            GUILayout.EndVertical();
            EditorGUILayout.Space();
        }
Example #23
0
        private void RenderControllerList(SerializedProperty controllerList)
        {
            if (thisProfile.ControllerVisualizationSettings.Length != controllerList.arraySize)
            {
                return;
            }

            EditorGUILayout.Space();

            if (InspectorUIUtility.RenderIndentedButton(ControllerAddButtonContent, EditorStyles.miniButton))
            {
                controllerList.InsertArrayElementAtIndex(controllerList.arraySize);
                var index             = controllerList.arraySize - 1;
                var controllerSetting = controllerList.GetArrayElementAtIndex(index);

                var mixedRealityControllerMappingDescription = controllerSetting.FindPropertyRelative("description");
                mixedRealityControllerMappingDescription.stringValue = typeof(GenericJoystickController).Name;

                var mixedRealityControllerHandedness = controllerSetting.FindPropertyRelative("handedness");
                mixedRealityControllerHandedness.intValue = 1;

                serializedObject.ApplyModifiedProperties();

                thisProfile.ControllerVisualizationSettings[index].ControllerType.Type = typeof(GenericJoystickController);
                return;
            }

#if UNITY_2019
            xrPipelineUtility.RenderXRPipelineTabs();
#endif // UNITY_2019

            for (int i = 0; i < controllerList.arraySize; i++)
            {
                var        controllerSetting = controllerList.GetArrayElementAtIndex(i);
                var        mixedRealityControllerMappingDescription = controllerSetting.FindPropertyRelative("description");
                SystemType controllerType = thisProfile.ControllerVisualizationSettings[i].ControllerType;
                bool       hasValidType   = controllerType != null &&
                                            controllerType.Type != null;

                if (hasValidType)
                {
                    MixedRealityControllerAttribute controllerAttribute = MixedRealityControllerAttribute.Find(controllerType.Type);
                    if (controllerAttribute != null && !controllerAttribute.SupportedUnityXRPipelines.HasFlag(xrPipelineUtility.SelectedPipeline))
                    {
                        continue;
                    }
                }
                else if (!MixedRealityProjectPreferences.ShowNullDataProviders)
                {
                    continue;
                }

                EditorGUILayout.Space();

                mixedRealityControllerMappingDescription.stringValue = hasValidType
                    ? controllerType.Type.Name.ToProperCase()
                    : "Undefined Controller";

                serializedObject.ApplyModifiedProperties();
                SerializedProperty mixedRealityControllerHandedness = controllerSetting.FindPropertyRelative("handedness");

                using (new EditorGUILayout.HorizontalScope())
                {
                    EditorGUILayout.LabelField($"{mixedRealityControllerMappingDescription.stringValue} {((Handedness)mixedRealityControllerHandedness.intValue).ToString().ToProperCase()} Hand{(mixedRealityControllerHandedness.intValue == (int)(Handedness.Both) ? "s" : "")}", EditorStyles.boldLabel);

                    if (GUILayout.Button(ControllerMinusButtonContent, EditorStyles.miniButtonRight, GUILayout.Width(24f)))
                    {
                        controllerList.DeleteArrayElementAtIndex(i);
                        return;
                    }
                }

                EditorGUILayout.PropertyField(controllerSetting.FindPropertyRelative("controllerType"));
                EditorGUILayout.PropertyField(controllerSetting.FindPropertyRelative("controllerVisualizationType"));

                if (!hasValidType)
                {
                    EditorGUILayout.HelpBox("A controller type must be defined!", MessageType.Error);
                }
                else
                {
                    // Only check for Oculus if we already know the type is valid (otherwise, null ref)
                    bool isOculusType = controllerType.Type.FullName.Contains("OculusXRSDKTouchController");
                    if (isOculusType)
                    {
                        EditorGUILayout.HelpBox("Oculus Touch controller model visualization is not managed by MRTK, refer to the Oculus XRSDK Device Manager to configure controller visualization settings", MessageType.Error);
                    }
                }

                var handednessValue = mixedRealityControllerHandedness.intValue - 1;

                // Reset in case it was set to something other than left, right, or both.
                if (handednessValue < 0 || handednessValue > 2)
                {
                    handednessValue = 0;
                }

                EditorGUI.BeginChangeCheck();
                handednessValue = EditorGUILayout.IntPopup(new GUIContent(mixedRealityControllerHandedness.displayName, mixedRealityControllerHandedness.tooltip), handednessValue, HandednessSelections, null);
                if (EditorGUI.EndChangeCheck())
                {
                    mixedRealityControllerHandedness.intValue = handednessValue + 1;
                }

                var overrideModel       = controllerSetting.FindPropertyRelative("overrideModel");
                var overrideModelPrefab = overrideModel.objectReferenceValue as GameObject;

                var controllerUsePlatformModelOverride = controllerSetting.FindPropertyRelative("usePlatformModels");
                EditorGUILayout.PropertyField(controllerUsePlatformModelOverride);
                if (controllerUsePlatformModelOverride.boolValue)
                {
                    var platformModelMaterial = controllerSetting.FindPropertyRelative("platformModelMaterial");
                    EditorGUILayout.PropertyField(platformModelMaterial);
                }

                if (controllerUsePlatformModelOverride.boolValue && overrideModelPrefab != null)
                {
                    EditorGUILayout.HelpBox("When platform model is used, the override model will only be used if the default model cannot be loaded from the driver.", MessageType.Warning);
                }

                EditorGUI.BeginChangeCheck();
                overrideModelPrefab = EditorGUILayout.ObjectField(new GUIContent(overrideModel.displayName, "If no override model is set, the global model is used."), overrideModelPrefab, typeof(GameObject), false) as GameObject;
                if (overrideModelPrefab == null && !controllerUsePlatformModelOverride.boolValue)
                {
                    EditorGUILayout.HelpBox("No override model was assigned and this controller will not attempt to use the platform's model, the global model will be used instead", MessageType.Warning);
                }

                if (EditorGUI.EndChangeCheck() && CheckVisualizer(overrideModelPrefab))
                {
                    overrideModel.objectReferenceValue = overrideModelPrefab;
                }
            }
        }
        /// <summary>
        /// Render list of data provider configuration profiles in inspector. Use provided add and remove content labels for the insert/remove buttons
        /// Returns true if any property has changed in this render pass, false otherwise
        /// </summary>
        protected bool RenderDataProviderList(GUIContent addContentLabel, GUIContent removeContentLabel, string errorMsg, Type dataProviderProfileType = null)
        {
            bool changed = false;

            using (new EditorGUILayout.VerticalScope())
            {
                if (providerConfigurations == null || providerConfigurations.arraySize == 0)
                {
                    EditorGUILayout.HelpBox(errorMsg, MessageType.Info);
                }

                if (InspectorUIUtility.RenderIndentedButton(addContentLabel, EditorStyles.miniButton))
                {
                    AddDataProvider();
                    return(true);
                }

#if UNITY_2019
                xrPipelineUtility.RenderXRPipelineTabs();
#endif // UNITY_2019

                delayedDisplayProviders.Clear();

                for (int i = 0; i < providerConfigurations.arraySize; i++)
                {
                    SystemType serviceType = GetDataProviderConfiguration(i).ComponentType;

                    if (serviceType.Type != null && MixedRealityExtensionServiceAttribute.Find(serviceType.Type) is MixedRealityDataProviderAttribute providerAttribute)
                    {
                        // Using == here to compare flags because we want to know if this is the only supported pipeline
                        // Providers that support multiple pipelines are rendered below the tabbed section
                        if (providerAttribute.SupportedUnityXRPipelines == xrPipelineUtility.SelectedPipeline)
                        {
                            changed |= RenderDataProviderEntry(i, removeContentLabel, serviceType, dataProviderProfileType);
                            delayedDisplayProviders.Add(null);
                        }
                        else if (providerAttribute.SupportedUnityXRPipelines == (SupportedUnityXRPipelines)(-1))
                        {
                            delayedDisplayProviders.Add(serviceType);
                        }
                        else
                        {
                            // Add null to ensure the delayedDisplayProviders list has an identical size to providerConfigurations.arraySize
                            // This is so we can iterate through without keeping track of i separately
                            delayedDisplayProviders.Add(null);
                        }
                    }
                    else
                    {
                        delayedDisplayProviders.Add(serviceType);
                    }
                }

#if UNITY_2019
                EditorGUILayout.LabelField(GeneralProvidersLabel, EditorStyles.boldLabel);
#endif // UNITY_2019

                for (int i = 0; i < delayedDisplayProviders.Count; i++)
                {
                    SystemType service = delayedDisplayProviders[i];
                    if (service != null)
                    {
                        changed |= RenderDataProviderEntry(i, removeContentLabel, service, dataProviderProfileType);
                    }
                }

                return(changed);
            }
        }