public override void OnInspectorGUI()
        {
            serializedObject.Update();

            var script               = serializedObject.FindProperty("m_Script");
            var groupName            = serializedObject.FindProperty("GroupName");
            var syncWithPlayerUpdate = serializedObject.FindProperty("SyncWithPlayerUpdate");
            var updateRate           = serializedObject.FindProperty("UpdateRate");
            var positionThreshold    = serializedObject.FindProperty("PositionThreshold");
            var rotationThreshold    = serializedObject.FindProperty("RotationThreshold");
            var snapshotOnEnable     = serializedObject.FindProperty("SnapshotOnEnable");
            var updateTicksOnEnable  = serializedObject.FindProperty("UpdateTicksOnEnable");
            var releaseOnDisable     = serializedObject.FindProperty("ReleaseIdOnDisable");
            var releaseOnDestroy     = serializedObject.FindProperty("ReleaseIdOnDestroy");
            var useCustomID          = serializedObject.FindProperty("UseCustomId");
            var customId             = serializedObject.FindProperty("CustomId");
            var commonMeshName       = serializedObject.FindProperty("CommonMesh");
            var meshname             = serializedObject.FindProperty("MeshName");
            var useCustomMesh        = serializedObject.FindProperty("UseCustomMesh");
            var trackGaze            = serializedObject.FindProperty("TrackGaze");
            var requiresManualEnable = serializedObject.FindProperty("RequiresManualEnable");

            foreach (var t in serializedObject.targetObjects)
            {
                var dynamic = t as DynamicObject;
                if (dynamic.iId != dynamic.GetInstanceID() || string.IsNullOrEmpty(dynamic.CustomId)) //only check if something has changed on a dynamic
                {
                    if (dynamic.UseCustomId)
                    {
                        dynamic.iId = dynamic.GetInstanceID(); //this will often mark the scene dirty without any apparent or meaningful changes
                        CheckCustomId(ref dynamic.CustomId);
                        //TODO cache while scene active, but don't bother marking scene dirty if only iId is dirty
                    }
                }
            }


#if UNITY_5_6_OR_NEWER
            //video
            //var flipVideo = serializedObject.FindProperty("FlipVideo");
            //var externalVideoSource = serializedObject.FindProperty("ExternalVideoSource");
            var videoPlayer = serializedObject.FindProperty("VideoPlayer");
#endif

            //display script on component
            EditorGUI.BeginDisabledGroup(true);
            EditorGUILayout.PropertyField(script, true, new GUILayoutOption[0]);
            EditorGUI.EndDisabledGroup();

            GUILayout.BeginHorizontal();

            UnityEditor.EditorGUILayout.PropertyField(useCustomMesh);

            bool anycustomnames = false;
            foreach (var t in targets)
            {
                var dyn = t as DynamicObject;
                if (dyn.UseCustomMesh)
                {
                    anycustomnames = true;
                    if (string.IsNullOrEmpty(dyn.MeshName))
                    {
                        dyn.MeshName = dyn.gameObject.name.ToLower().Replace(" ", "_");
                        UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
                    }
                    if (targets.Length == 1)
                    {
                        dyn.MeshName = UnityEditor.EditorGUILayout.TextField("", dyn.MeshName);
                    }
                }
            }
            if (!anycustomnames)
            {
                UnityEditor.EditorGUILayout.PropertyField(commonMeshName, new GUIContent(""));
            }

            GUILayout.EndHorizontal();

            EditorGUILayout.PropertyField(trackGaze, new GUIContent("Track Gaze on Dynamic Object"));
            DisplayGazeTrackHelpbox(trackGaze.boolValue);

            GUILayout.Space(10);

            foldout = EditorGUILayout.Foldout(foldout, "Advanced");
            if (foldout)
            {
                if (useCustomMesh.boolValue)
                {
                    //Mesh
                    GUILayout.Label("Mesh", EditorStyles.boldLabel);


                    //EditorGUI.BeginDisabledGroup(useCustomMesh.boolValue);
                    //UnityEditor.EditorGUILayout.PropertyField(commonMeshName);
                    //EditorGUI.EndDisabledGroup();

                    if (string.IsNullOrEmpty(meshname.stringValue))
                    {
                        //meshname.stringValue = serializedObject.targetObject.name.ToLower().Replace(" ", "_");
                        UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
                    }

                    GUILayout.BeginHorizontal();
                    //UnityEditor.EditorGUILayout.PropertyField(useCustomMesh);

                    //EditorGUI.BeginDisabledGroup(!useCustomMesh.boolValue);
                    UnityEditor.EditorGUILayout.PropertyField(meshname, new GUIContent(""));
                    if (GUILayout.Button("Export", "ButtonLeft", GUILayout.MaxWidth(100)))
                    {
                        CognitiveVR_SceneExportWindow.ExportSelectedObjectsPrefab();
                        foreach (var t in serializedObject.targetObjects)
                        {
                            var dyn = t as DynamicObject;
                            if (!dyn.UseCustomId)
                            {
                                EditorCore.SaveDynamicThumbnailAutomatic(dyn.gameObject);
                            }
                        }
                    }

                    EditorGUI.BeginDisabledGroup(!EditorCore.HasDynamicExportFiles(meshname.stringValue));
                    if (GUILayout.Button("Upload", "ButtonRight", GUILayout.MaxWidth(100)))
                    {
                        CognitiveVR_SceneExportWindow.UploadSelectedDynamicObjects(true);
                    }
                    EditorGUI.EndDisabledGroup();

                    GUILayout.EndHorizontal();

                    GUILayout.BeginHorizontal();
                    GUILayout.FlexibleSpace();
                    EditorGUI.BeginDisabledGroup(!EditorCore.HasDynamicExportFiles(meshname.stringValue));
                    if (GUILayout.Button("Thumbnail from SceneView", GUILayout.MaxWidth(180)))
                    {
                        foreach (var v in serializedObject.targetObjects)
                        {
                            EditorCore.SaveDynamicThumbnailSceneView((v as DynamicObject).gameObject);
                        }
                    }
                    EditorGUI.EndDisabledGroup();
                    GUILayout.EndHorizontal();
                }

                //Setup
                GUILayout.Label("Setup", EditorStyles.boldLabel);

                UnityEditor.EditorGUILayout.PropertyField(snapshotOnEnable, new GUIContent("Snapshot On Enable", "Save the transform when this object is first enabled"));

                //EditorGUI.BeginDisabledGroup(!snapshotOnEnable.boolValue);
                UnityEditor.EditorGUILayout.PropertyField(updateTicksOnEnable, new GUIContent("Update Ticks on Enable", "Begin coroutine that saves the transform of this object when it moves"));
                //EditorGUI.EndDisabledGroup();

                EditorGUILayout.PropertyField(trackGaze, new GUIContent("Track Gaze on Dynamic Object"));

                DisplayGazeTrackHelpbox(trackGaze.boolValue);

                EditorGUILayout.PropertyField(requiresManualEnable, new GUIContent("Requires Manual Enable", "If true, ManualEnable must be called before OnEnable will function. Used to set initial variables on an object"));


                //Object ID
                GUILayout.Label("Ids", EditorStyles.boldLabel);

                GUILayout.BeginHorizontal();

                EditorGUILayout.PropertyField(useCustomID, new GUIContent("Use Custom Id", "This is used to identify specific objects to aggregate the position across multiple play sessions"));

                EditorGUI.BeginDisabledGroup(!useCustomID.boolValue);
                EditorGUILayout.PropertyField(customId, new GUIContent(""));
                EditorGUI.EndDisabledGroup();

                GUILayout.EndHorizontal();

                EditorGUILayout.PropertyField(groupName, new GUIContent("Group Name", "This is used to identify types of objects and combine aggregated data"));

                EditorGUILayout.PropertyField(releaseOnDisable, new GUIContent("Release Id OnDisable", "Allow other objects to use this Id when this object is no longer active"));
                EditorGUILayout.PropertyField(releaseOnDestroy, new GUIContent("Release Id OnDestroy", "Allow other objects to use this Id when this object is no longer active"));

                //Snapshot Threshold
                GUILayout.Label("Snapshot Threshold", EditorStyles.boldLabel);


                EditorGUILayout.PropertyField(syncWithPlayerUpdate, new GUIContent("Sync with Player Update", "This is the Snapshot interval in the Tracker Options Window"));

                EditorGUI.BeginDisabledGroup(syncWithPlayerUpdate.boolValue);
                if (syncWithPlayerUpdate.boolValue)
                {
                    EditorGUILayout.FloatField(new GUIContent("Update Rate", "Synced with Player Update.\nThe interval between checking for modified position and rotation"), EditorCore.GetPreferences().SnapshotInterval);
                }
                else
                {
                    EditorGUILayout.PropertyField(updateRate, new GUIContent("Update Rate", "The interval between checking for modified position and rotation"));
                }
                updateRate.floatValue = Mathf.Max(0.1f, updateRate.floatValue);
                EditorGUI.EndDisabledGroup();


                EditorGUILayout.PropertyField(positionThreshold, new GUIContent("Position Threshold", "Meters the object must move to write a new snapshot. Checked each 'Tick'"));
                positionThreshold.floatValue = Mathf.Max(0, positionThreshold.floatValue);

                EditorGUILayout.PropertyField(rotationThreshold, new GUIContent("Rotation Threshold", "Degrees the object must rotate to write a new snapshot. Checked each 'Tick'"));
                rotationThreshold.floatValue = Mathf.Max(0, rotationThreshold.floatValue);

#if !UNITY_5_6_OR_NEWER
                GUILayout.Label("Video Settings", EditorStyles.boldLabel);
                EditorGUILayout.HelpBox("Video Player requires Unity 5.6 or newer!", MessageType.Warning);
#else
                GUILayout.Label("Video Settings", EditorStyles.boldLabel);

                EditorGUILayout.PropertyField(videoPlayer, new GUIContent("Video Player"));

                //EditorGUILayout.PropertyField(externalVideoSource, new GUIContent("External Video Source", "The URL source of the video"));
                //EditorGUILayout.PropertyField(flipVideo, new GUIContent("Flip Video Horizontally"));
#endif
            } //advanced foldout


            if (GUI.changed)
            {
                foreach (var t in targets)
                {
                    var dyn = t as DynamicObject;
                    if (dyn.UseCustomMesh)
                    {
                        dyn.MeshName = dyn.MeshName.Replace(" ", "_");
                    }
                }

                //remove spaces from meshname
                //meshname.stringValue = meshname.stringValue.Replace(" ", "_");

                UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
            }

            serializedObject.ApplyModifiedProperties();
            serializedObject.Update();
        }
        /// <summary>
        /// export selected gameobjects, temporarily spawn them in the scene if they are prefabs
        /// </summary>
        /// <returns>true if exported at least 1 mesh</returns>
        public static bool ExportSelectedObjectsPrefab()
        {
            List <Transform> entireSelection = new List <Transform>();

            entireSelection.AddRange(Selection.GetTransforms(SelectionMode.Editable));

            if (entireSelection.Count == 0)
            {
                Debug.Log("No Dynamic Objects selected"); return(false);
            }

            Debug.Log("Starting export of " + entireSelection.Count + " Dynamic Objects");

            List <Transform> sceneObjects = new List <Transform>();

            sceneObjects.AddRange(Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab));

            List <Transform> prefabsToSpawn = new List <Transform>();

            //add prefab objects to a list
            foreach (var v in entireSelection)
            {
                if (!sceneObjects.Contains(v))
                {
                    prefabsToSpawn.Add(v);
                }
            }

            //spawn prefabs
            var temporarySpawnedPrefabs = new List <GameObject>();

            foreach (var v in prefabsToSpawn)
            {
                var newPrefab = GameObject.Instantiate(v.gameObject);
                temporarySpawnedPrefabs.Add(newPrefab);
                sceneObjects.Add(newPrefab.transform);
            }

            //export all the objects
            int           successfullyExportedCount = 0;
            List <string> exportedMeshNames         = new List <string>();
            List <string> totalExportedMeshNames    = new List <string>();

            foreach (var v in sceneObjects)
            {
                var dynamic = v.GetComponent <DynamicObject>();
                if (dynamic == null)
                {
                    continue;
                }

                if (!dynamic.UseCustomMesh)
                {
                    //skip exporting a mesh with no name
                    continue;
                }
                if (string.IsNullOrEmpty(dynamic.MeshName))
                {
                    if (!totalExportedMeshNames.Contains(""))
                    {
                        totalExportedMeshNames.Add("");
                    }
                    Debug.LogWarning("GameObject " + dynamic.gameObject + " has empty mesh name");
                    continue;
                }

                if (exportedMeshNames.Contains(dynamic.MeshName))
                {
                    successfullyExportedCount++; continue;
                }                                                                                            //skip exporting same mesh

                if (v.GetComponent <Canvas>() != null)
                {
                    //TODO merge this deeper in the export process. do this recurively ignoring child dynamics
                    //take a snapshot
                    var width  = v.GetComponent <RectTransform>().sizeDelta.x *v.localScale.x;
                    var height = v.GetComponent <RectTransform>().sizeDelta.y *v.localScale.y;

                    var screenshot = CognitiveVR_SceneExplorerExporter.Snapshot(v);

                    var mesh = CognitiveVR_SceneExplorerExporter.ExportQuad(dynamic.MeshName, width, height, v, UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name, screenshot);
                    CognitiveVR_SceneExplorerExporter.ExportDynamicObject(mesh, dynamic.MeshName, screenshot, dynamic.MeshName);
                    EditorCore.SaveDynamicThumbnailAutomatic(dynamic.gameObject);
                    successfullyExportedCount++;
                }
                else if (CognitiveVR_SceneExplorerExporter.ExportDynamicObject(v))
                {
                    EditorCore.SaveDynamicThumbnailAutomatic(dynamic.gameObject);
                    successfullyExportedCount++;
                }

                foreach (var common in System.Enum.GetNames(typeof(DynamicObject.CommonDynamicMesh)))
                {
                    if (common.ToLower() == dynamic.MeshName.ToLower())
                    {
                        //don't export common meshes!
                        continue;
                    }
                }
                if (!totalExportedMeshNames.Contains(dynamic.MeshName))
                {
                    totalExportedMeshNames.Add(dynamic.MeshName);
                }
                if (!exportedMeshNames.Contains(dynamic.MeshName))
                {
                    exportedMeshNames.Add(dynamic.MeshName);
                }
            }

            //destroy the temporary prefabs
            foreach (var v in temporarySpawnedPrefabs)
            {
                GameObject.DestroyImmediate(v);
            }

            if (entireSelection.Count == 0)
            {
                EditorUtility.DisplayDialog("Dynamic Object Export", "No Dynamic Objects selected", "Ok");
                return(false);
            }

            if (successfullyExportedCount == 0)
            {
                EditorUtility.DisplayDialog("Dynamic Object Export", "No Dynamic Objects successfully exported.\n\nDo you have Mesh Renderers, Skinned Mesh Renderers or Canvas components attached or as children?", "Ok");
                return(false);
            }

            if (successfullyExportedCount == 1 && entireSelection.Count == 1)
            {
                EditorUtility.DisplayDialog("Dynamic Object Export", "Successfully exported 1 Dynamic Object mesh", "Ok");
            }
            else
            {
                EditorUtility.DisplayDialog("Dynamic Object Export", "From selected Dynamic Objects , found " + totalExportedMeshNames.Count + " unique mesh names and successfully exported " + successfullyExportedCount, "Ok");
            }
            return(true);
        }
Beispiel #3
0
        private void OnGUI()
        {
            if (needsRefreshDevKey == true)
            {
                EditorCore.CheckForExpiredDeveloperKey(GetDevKeyResponse);
                needsRefreshDevKey = false;
            }
            GUI.skin = EditorCore.WizardGUISkin;

            GUI.DrawTexture(new Rect(0, 0, 500, 550), EditorGUIUtility.whiteTexture);

            var currentscene = CognitiveVR_Preferences.FindCurrentScene();

            if (string.IsNullOrEmpty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name))
            {
                GUI.Label(steptitlerect, "DYNAMIC OBJECTS   Scene Not Saved", "steptitle");
            }
            else if (currentscene == null || string.IsNullOrEmpty(currentscene.SceneId))
            {
                GUI.Label(steptitlerect, "DYNAMIC OBJECTS   Scene Not Uploaded", "steptitle");
            }
            else
            {
                GUI.Label(steptitlerect, "DYNAMIC OBJECTS   " + currentscene.SceneName + " Version: " + currentscene.VersionNumber, "steptitle");
            }

            GUI.Label(new Rect(30, 45, 440, 440), "These are the active <color=#8A9EB7FF>Dynamic Object components</color> currently found in your scene.", "boldlabel");

            //headers
            Rect mesh = new Rect(30, 95, 120, 30);

            GUI.Label(mesh, "Mesh Name", "dynamicheader");
            Rect gameobject = new Rect(190, 95, 120, 30);

            GUI.Label(gameobject, "GameObject", "dynamicheader");
            //Rect ids = new Rect(320, 95, 120, 30);
            //GUI.Label(ids, "Ids", "dynamicheader");
            Rect uploaded = new Rect(380, 95, 120, 30);

            GUI.Label(uploaded, "Exported Mesh", "dynamicheader");
            //IMPROVEMENT get list of uploaded mesh names from dashboard


            //content
            DynamicObject[] tempdynamics = GetDynamicObjects;

            if (tempdynamics.Length == 0)
            {
                GUI.Label(new Rect(30, 120, 420, 270), "No objects found.\n\nHave you attached any Dynamic Object components to objects?\n\nAre they active in your hierarchy?", "button_disabledtext");
            }

            DynamicObjectIdPool[] poolAssets = EditorCore.GetDynamicObjectPoolAssets;


            Rect innerScrollSize = new Rect(30, 0, 420, (tempdynamics.Length + poolAssets.Length) * 30);

            dynamicScrollPosition = GUI.BeginScrollView(new Rect(30, 120, 440, 285), dynamicScrollPosition, innerScrollSize, false, true);

            Rect dynamicrect;
            int  GuiOffset = 0;

            for (; GuiOffset < tempdynamics.Length; GuiOffset++)
            {
                if (tempdynamics[GuiOffset] == null)
                {
                    RefreshSceneDynamics(); GUI.EndScrollView(); return;
                }
                dynamicrect = new Rect(30, GuiOffset * 30, 460, 30);
                DrawDynamicObject(tempdynamics[GuiOffset], dynamicrect, GuiOffset % 2 == 0);
            }
            for (int i = 0; i < poolAssets.Length; i++)
            {
                //if (poolAssets[i] == null) { RefreshSceneDynamics(); GUI.EndScrollView(); return; }
                dynamicrect = new Rect(30, (i + GuiOffset) * 30, 460, 30);
                DrawDynamicObjectPool(poolAssets[i], dynamicrect, (i + GuiOffset) % 2 == 0);
            }
            GUI.EndScrollView();
            GUI.Box(new Rect(30, 120, 425, 285), "", "box_sharp_alpha");

            //buttons

            string scenename     = "Not Saved";
            int    versionnumber = 0;

            //string buttontextstyle = "button_bluetext";
            if (currentscene == null || string.IsNullOrEmpty(currentscene.SceneId))
            {
                //buttontextstyle = "button_disabledtext";
            }
            else
            {
                scenename     = currentscene.SceneName;
                versionnumber = currentscene.VersionNumber;
            }

            int selectionCount = 0;

            foreach (var v in Selection.gameObjects)
            {
                if (v.GetComponentInChildren <DynamicObject>())
                {
                    selectionCount++;
                }
            }

            //IMPROVEMENT enable mesh upload from selected dynamic object id pool that has exported mesh files
            //if (Selection.activeObject.GetType() == typeof(DynamicObjectIdPool))
            //{
            //    var pool = Selection.activeObject as DynamicObjectIdPool;
            //    if (EditorCore.HasDynamicExportFiles(pool.MeshName))
            //    {
            //        selectionCount++;
            //    }
            //}

            //texture resolution

            if (CognitiveVR_Preferences.Instance.TextureResize > 4)
            {
                CognitiveVR_Preferences.Instance.TextureResize = 4;
            }

            //resolution settings here
            EditorGUI.BeginDisabledGroup(DisableButtons);
            if (GUI.Button(new Rect(30, 415, 140, 35), new GUIContent("1/4 Resolution", DisableButtons?"":"Quarter resolution of dynamic object textures"), CognitiveVR_Preferences.Instance.TextureResize == 4 ? "button_blueoutline" : "button_disabledtext"))
            {
                CognitiveVR_Preferences.Instance.TextureResize = 4;
            }
            if (CognitiveVR_Preferences.Instance.TextureResize != 4)
            {
                GUI.Box(new Rect(30, 415, 140, 35), "", "box_sharp_alpha");
            }

            if (GUI.Button(new Rect(180, 415, 140, 35), new GUIContent("1/2 Resolution", DisableButtons ? "" : "Half resolution of dynamic object textures"), CognitiveVR_Preferences.Instance.TextureResize == 2 ? "button_blueoutline" : "button_disabledtext"))
            {
                CognitiveVR_Preferences.Instance.TextureResize = 2;
            }
            if (CognitiveVR_Preferences.Instance.TextureResize != 2)
            {
                GUI.Box(new Rect(180, 415, 140, 35), "", "box_sharp_alpha");
            }

            if (GUI.Button(new Rect(330, 415, 140, 35), new GUIContent("1/1 Resolution", DisableButtons ? "" : "Full resolution of dynamic object textures"), CognitiveVR_Preferences.Instance.TextureResize == 1 ? "button_blueoutline" : "button_disabledtext"))
            {
                CognitiveVR_Preferences.Instance.TextureResize = 1;
            }
            if (CognitiveVR_Preferences.Instance.TextureResize != 1)
            {
                GUI.Box(new Rect(330, 415, 140, 35), "", "box_sharp_alpha");
            }
            EditorGUI.EndDisabledGroup();


            EditorGUI.BeginDisabledGroup(currentscene == null || string.IsNullOrEmpty(currentscene.SceneId) || selectionCount == 0);
            if (GUI.Button(new Rect(30, 460, 200, 30), new GUIContent("Upload " + selectionCount + " Selected Meshes", DisableButtons ? "" : "Export and Upload to " + scenename + " version " + versionnumber)))
            {
                EditorCore.RefreshSceneVersion(() =>
                {
                    foreach (var go in Selection.gameObjects)
                    {
                        var dyn = go.GetComponent <DynamicObject>();
                        if (dyn == null)
                        {
                            continue;
                        }
                        //check if export files exist
                        if (!EditorCore.HasDynamicExportFiles(dyn.MeshName))
                        {
                            ExportUtility.ExportDynamicObject(dyn);
                        }
                        //check if thumbnail exists
                        if (!EditorCore.HasDynamicObjectThumbnail(dyn.MeshName))
                        {
                            EditorCore.SaveDynamicThumbnailAutomatic(dyn.gameObject);
                        }
                    }

                    EditorCore.RefreshSceneVersion(delegate()
                    {
                        var manifest = new AggregationManifest();
                        AddOrReplaceDynamic(manifest, GetDynamicObjectsInScene());
                        ManageDynamicObjects.UploadManifest(manifest, () => ExportUtility.UploadSelectedDynamicObjectMeshes(true));
                    });
                });
            }
            EditorGUI.EndDisabledGroup();

            EditorGUI.BeginDisabledGroup(currentscene == null || string.IsNullOrEmpty(currentscene.SceneId));
            if (GUI.Button(new Rect(270, 460, 200, 30), new GUIContent("Upload All Meshes", DisableButtons ? "" : "Export and Upload to " + scenename + " version " + versionnumber)))
            {
                EditorCore.RefreshSceneVersion(() =>
                {
                    var dynamics          = GameObject.FindObjectsOfType <DynamicObject>();
                    List <GameObject> gos = new List <GameObject>();
                    foreach (var v in dynamics)
                    {
                        gos.Add(v.gameObject);
                    }

                    Selection.objects = gos.ToArray();

                    foreach (var go in Selection.gameObjects)
                    {
                        var dyn = go.GetComponent <DynamicObject>();
                        if (dyn == null)
                        {
                            continue;
                        }
                        //check if export files exist
                        if (!EditorCore.HasDynamicExportFiles(dyn.MeshName))
                        {
                            ExportUtility.ExportDynamicObject(dyn);
                        }
                        //check if thumbnail exists
                        if (!EditorCore.HasDynamicObjectThumbnail(dyn.MeshName))
                        {
                            EditorCore.SaveDynamicThumbnailAutomatic(dyn.gameObject);
                        }
                    }

                    EditorCore.RefreshSceneVersion(delegate()
                    {
                        var manifest = new AggregationManifest();
                        AddOrReplaceDynamic(manifest, GetDynamicObjectsInScene());
                        ManageDynamicObjects.UploadManifest(manifest, () => ExportUtility.UploadSelectedDynamicObjectMeshes(true));
                    });
                });
            }
            EditorGUI.EndDisabledGroup();

            DrawFooter();
            Repaint(); //manually repaint gui each frame to make sure it's responsive
        }
        /// <summary>
        /// export all dynamic objects in scene. skip prefabs
        /// </summary>
        /// <returns>true if any dynamics are exported</returns>
        public static bool ExportAllDynamicsInScene()
        {
            //List<Transform> entireSelection = new List<Transform>();
            //entireSelection.AddRange(Selection.GetTransforms(SelectionMode.Editable));

            var dynamics = FindObjectsOfType <DynamicObject>();

            Debug.Log("Starting export of " + dynamics.Length + " Dynamic Objects");


            //export all the objects
            int           successfullyExportedCount = 0;
            List <string> exportedMeshNames         = new List <string>();
            List <string> totalExportedMeshNames    = new List <string>();

            foreach (var dynamic in dynamics)
            {
                if (!dynamic.UseCustomMesh)
                {
                    //skip exporting a mesh with no name
                    continue;
                }
                if (string.IsNullOrEmpty(dynamic.MeshName))
                {
                    if (!totalExportedMeshNames.Contains(""))
                    {
                        totalExportedMeshNames.Add("");
                    }
                    Debug.LogWarning("GameObject " + dynamic.gameObject + " has empty mesh name");
                    continue;
                }

                if (exportedMeshNames.Contains(dynamic.MeshName))
                {
                    successfullyExportedCount++; continue;
                }                                                                                            //skip exporting same mesh

                if (dynamic.GetComponent <Canvas>() != null)
                {
                    //TODO merge this deeper in the export process. do this recurively ignoring child dynamics
                    //take a snapshot
                    var width  = dynamic.GetComponent <RectTransform>().sizeDelta.x *dynamic.transform.localScale.x;
                    var height = dynamic.GetComponent <RectTransform>().sizeDelta.y *dynamic.transform.localScale.y;

                    var screenshot = CognitiveVR_SceneExplorerExporter.Snapshot(dynamic.transform);

                    var mesh = CognitiveVR_SceneExplorerExporter.ExportQuad(dynamic.MeshName, width, height, dynamic.transform, UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name, screenshot);
                    CognitiveVR_SceneExplorerExporter.ExportDynamicObject(mesh, dynamic.MeshName, screenshot, dynamic.MeshName);
                    EditorCore.SaveDynamicThumbnailAutomatic(dynamic.gameObject);
                    successfullyExportedCount++;
                }
                else if (CognitiveVR_SceneExplorerExporter.ExportDynamicObject(dynamic.transform))
                {
                    EditorCore.SaveDynamicThumbnailAutomatic(dynamic.gameObject);
                    successfullyExportedCount++;
                }

                foreach (var common in System.Enum.GetNames(typeof(DynamicObject.CommonDynamicMesh)))
                {
                    if (common.ToLower() == dynamic.MeshName.ToLower())
                    {
                        //don't export common meshes!
                        continue;
                    }
                }
                if (!totalExportedMeshNames.Contains(dynamic.MeshName))
                {
                    totalExportedMeshNames.Add(dynamic.MeshName);
                }

                if (!exportedMeshNames.Contains(dynamic.MeshName))
                {
                    exportedMeshNames.Add(dynamic.MeshName);
                }
            }

            if (successfullyExportedCount == 0)
            {
                EditorUtility.DisplayDialog("Dynamic Object Export", "No Dynamic Objects successfully exported.\n\nDo you have Mesh Renderers, Skinned Mesh Renderers or Canvas components attached or as children?", "Ok");
                return(false);
            }

            EditorUtility.DisplayDialog("Dynamic Object Export", "From all Dynamic Objects in scene, found " + totalExportedMeshNames.Count + " unique mesh names and successfully exported " + successfullyExportedCount, "Ok");
            return(true);
        }