Example #1
0
    internal static bool CreateSceneCachePlayerAndPrefab(string sceneCacheFilePath, 
        string prefabPath, string assetsFolder, 
        out SceneCachePlayer player, out GameObject prefab) 
    {
        player = null;
        prefab = null;
        
        GameObject go = new GameObject();        
        go.name = Path.GetFileNameWithoutExtension(sceneCacheFilePath);

        player = AddSceneCachePlayer(go, sceneCacheFilePath, assetsFolder);
        if (null == player) {
            Object.DestroyImmediate(go);            
            return false;
        }

        //Optimize serialization by ensuring to serialize the key values at the end 
        player.EnableKeyValuesSerialization(false);
        prefab = player.gameObject.SaveAsPrefab(prefabPath);
        if (null == prefab) {
            Object.DestroyImmediate(go);            
            return false;
        }
        
        player.EnableKeyValuesSerialization(true);       
        PrefabUtility.ApplyPrefabInstance(player.gameObject, InteractionMode.AutomatedAction);
        
        Undo.RegisterCreatedObjectUndo(go, "SceneCachePlayer");
        return true;
    }
Example #2
0
//----------------------------------------------------------------------------------------------------------------------    
    /// <inheritdoc/>
    public override ClipDrawOptions GetClipOptions(TimelineClip clip) {
        ClipDrawOptions         clipOptions = base.GetClipOptions(clip);
        SceneCachePlayableAsset asset       = clip.asset as SceneCachePlayableAsset;
        if (null == asset) {
            Debug.LogError("Asset is not a SceneCachePlayableAsset: " + clip.asset);
            return clipOptions;
        }
        
        SceneCacheClipData clipData = asset.GetBoundClipData();
        if (null == clipData) 
            return clipOptions;

        SceneCachePlayer scPlayer = asset.GetSceneCachePlayer();
        if (null == scPlayer) {
            clipOptions.errorText = NO_SCENE_CACHE_ASSIGNED_ERROR;
            return clipOptions;
        }

        LimitedAnimationController overrideLimitedAnimationController =asset.GetOverrideLimitedAnimationController();
        
        if (!scPlayer.IsLimitedAnimationOverrideable() && overrideLimitedAnimationController.IsEnabled()) {
            clipOptions.errorText = UNABLE_TO_OVERRIDE_LIMITED_ANIMATION_ERROR;
            return clipOptions;
        }

        clipOptions.tooltip = scPlayer.GetSceneCacheFilePath();

        return clipOptions;
    } 
        public static GameObject CreateSceneCachePlayerPrefab(string path)
        {
            GameObject go = CreateSceneCachePlayer(path);

            if (go == null)
            {
                return(null);
            }

            // export materials & animation and generate prefab
            SceneCachePlayer player = go.GetComponent <SceneCachePlayer>();

            player.UpdatePlayer();
            player.ExportMaterials(false, true);
            player.ResetTimeAnimation();
            player.handleAssets = false;
            SceneData scene = player.GetLastScene();

            if (!scene.submeshesHaveUniqueMaterial)
            {
                MeshSyncPlayerConfig config = player.GetConfig();
                config.SyncMaterialList = false;
            }

            string prefabPath = string.Format("Assets/SceneCache/{0}.prefab", go.name);

            PrefabUtility.SaveAsPrefabAssetAndConnect(go, prefabPath, InteractionMode.AutomatedAction);
            return(go);
        }
        public void ChangeSceneCacheOnDirectPrefab()
        {
            //Initial setup
            const string DEST_PREFAB_PATH = "Assets/TestSceneCache.prefab";
            const string ASSETS_FOLDER    = "Assets/TestSceneCacheAssets";

            bool prefabCreated = SceneCachePlayerEditorUtility.CreateSceneCachePlayerAndPrefab(
                Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH), DEST_PREFAB_PATH, ASSETS_FOLDER,
                out SceneCachePlayer player, out GameObject prefab
                );

            Assert.IsTrue(prefabCreated);

            //Check the prefab
            Assert.IsFalse(prefab.IsPrefabInstance());
            Assert.IsTrue(prefab.IsPrefab());
            SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>();

            Assert.IsNotNull(prefabPlayer);
            Camera cam0   = prefabPlayer.GetComponentInChildren <Camera>();
            Light  light0 = prefabPlayer.GetComponentInChildren <Light>();

            //Change
            TestDataComponents comps = ChangeSceneCacheFileAndVerify(prefabPlayer,
                                                                     Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH)
                                                                     );

            Assert.AreEqual(cam0, comps.cam);
            Assert.AreEqual(light0, comps.light);

            //Cleanup
            Object.DestroyImmediate(player.gameObject);
            DeleteSceneCachePlayerPrefab(prefab);
        }
//----------------------------------------------------------------------------------------------------------------------

        void DeleteSceneCachePlayerPrefab(GameObject prefab)
        {
            Assert.IsTrue(prefab.IsPrefab());

            SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>();

            Assert.IsNotNull(prefabPlayer);

            string assetsFolder = prefabPlayer.GetAssetsFolder();

            //Check assets folder
            Assert.IsTrue(Directory.Exists(assetsFolder));
            string[] prefabAssetGUIDs = AssetDatabase.FindAssets("", new[] { assetsFolder });
            Assert.Greater(prefabAssetGUIDs.Length, 0);


            //Cleanup
            foreach (string guid in prefabAssetGUIDs)
            {
                AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(guid));
            }
            FileUtil.DeleteFileOrDirectory(assetsFolder);

            string prefabPath = AssetDatabase.GetAssetPath(prefab);

            Assert.IsFalse(string.IsNullOrEmpty(prefabPath));
            AssetDatabase.DeleteAsset(prefabPath);

            AssetDatabase.Refresh();
        }
//----------------------------------------------------------------------------------------------------------------------
    
    private void DrawLimitedAnimationGUI(SceneCachePlayableAsset scPlayableAsset) {
        SceneCachePlayer scPlayer = scPlayableAsset.GetSceneCachePlayer();
        
        bool disableScope = null == scPlayer;
        
        if (null != scPlayer) {
            disableScope |= (!scPlayer.IsLimitedAnimationOverrideable());
        }

        if (disableScope) {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.HelpBox(
                "Disabled because Limited Animation settings on the SceneCache GameObject is enabled, or the playback mode is set to interpolate", 
                MessageType.Warning
            );
            if (GUILayout.Button("Fix", GUILayout.Width(64), GUILayout.Height(36))) {
                scPlayer.AllowLimitedAnimationOverride();
                Repaint();
            }
            EditorGUILayout.EndHorizontal();
            
        }

        using (new EditorGUI.DisabledScope(disableScope)) {
            SceneCachePlayerEditorUtility.DrawLimitedAnimationGUI(scPlayableAsset.GetOverrideLimitedAnimationController(),
                m_scPlayableAsset, scPlayer);
        }
        
    }
        public void ChangeSceneCacheOnDirectPrefab()
        {
            //Initial setup
            const string DEST_PREFAB_PATH = "Assets/TestSceneCache.prefab";
            const string ASSETS_FOLDER    = "Assets/TestSceneCacheAssets";

            bool prefabCreated = SceneCachePlayerEditorUtility.CreateSceneCachePlayerAndPrefab(
                Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH), DEST_PREFAB_PATH, ASSETS_FOLDER,
                out SceneCachePlayer player, out GameObject prefab
                );

            Assert.IsTrue(prefabCreated);

            //Check the prefab
            Assert.IsFalse(prefab.IsPrefabInstance());
            Assert.IsTrue(prefab.IsPrefab());
            SceneCachePlayer prefabPlayer = prefab.GetComponent <SceneCachePlayer>();

            Assert.IsNotNull(prefabPlayer);


            //Change
            string newSceneCacheFilePath = Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH);

            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(prefabPlayer, newSceneCacheFilePath);
            string convertedPath = newSceneCacheFilePath.Replace('\\', '/');

            Assert.AreEqual(convertedPath, player.GetSceneCacheFilePath());


            //Cleanup
            Object.DestroyImmediate(player.gameObject);
            DeleteSceneCachePlayerPrefab(prefab);
        }
        private static SceneCachePlayer CreateTestSceneCachePlayer()
        {
            GameObject       sceneCacheGo     = new GameObject();
            SceneCachePlayer sceneCachePlayer = sceneCacheGo.AddComponent <SceneCachePlayer>();

            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(sceneCachePlayer, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH));
            return(sceneCachePlayer);
        }
Example #9
0
        public IEnumerator CreatePlayableAsset()
        {
            EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);

            //Add director
            GameObject       directorGo = new GameObject("Director");
            PlayableDirector director   = directorGo.AddComponent <PlayableDirector>();

            //Setup scene cache
            GameObject       sceneCacheGo     = new GameObject();
            SceneCachePlayer sceneCachePlayer = sceneCacheGo.AddComponent <SceneCachePlayer>();

            Assert.IsFalse(sceneCachePlayer.IsSceneCacheOpened());
            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(sceneCachePlayer, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH));


            //Create timeline asset
            TimelineAsset asset = ScriptableObject.CreateInstance <TimelineAsset>();

            director.playableAsset = asset;

            //Create PlayableAsset/Track/ etc
            SceneCachePlayableAsset playableAsset   = ScriptableObject.CreateInstance <SceneCachePlayableAsset>();
            SceneCacheTrack         sceneCacheTrack = asset.CreateTrack <SceneCacheTrack>(null, "TestSceneCacheTrack");
            TimelineClip            clip            = sceneCacheTrack.CreateDefaultClip();

            clip.asset = playableAsset;
            director.SetReferenceValue(playableAsset.GetSceneCachePlayerRef().exposedName, sceneCachePlayer);


            //Select gameObject and open Timeline Window. This will trigger the TimelineWindow's update etc.
            EditorApplication.ExecuteMenuItem("Window/Sequencing/Timeline");
            Selection.activeTransform = directorGo.transform;
            yield return(null);

            director.time = 0;
            yield return(null);

            Assert.AreEqual(0, sceneCachePlayer.GetRequestedNormalizedTime());
            double timePerFrame = 1.0f / sceneCacheTrack.timelineAsset.editorSettings.fps;

            double directorTime = clip.start + clip.duration - timePerFrame;

            SetDirectorTime(director, directorTime);
            yield return(null);

            //Check clipData and curve
            SceneCacheClipData clipData = playableAsset.GetBoundClipData();

            Assert.IsNotNull(clipData);
            AnimationCurve curve = clipData.GetAnimationCurve();

            Assert.IsNotNull(curve);
            float normalizedTime = curve.Evaluate((float)directorTime);


            Assert.AreEqual(normalizedTime, sceneCachePlayer.GetRequestedNormalizedTime());
        }
Example #10
0
//----------------------------------------------------------------------------------------------------------------------    

    internal static TimelineClip AddSceneCacheTrackAndClip(PlayableDirector director, string trackName, 
        SceneCachePlayer sceneCachePlayer) 
    {
        TimelineAsset timelineAsset = director.playableAsset as TimelineAsset;
        Assert.IsNotNull(timelineAsset);
    
        SceneCacheTrack         sceneCacheTrack = timelineAsset.CreateTrack<SceneCacheTrack>(null, trackName);
        TimelineClip            clip            = sceneCacheTrack.CreateDefaultClip();
        SceneCachePlayableAsset playableAsset = clip.asset as SceneCachePlayableAsset;
        Assert.IsNotNull(playableAsset);
        director.SetReferenceValue(playableAsset.GetSceneCachePlayerRef().exposedName, sceneCachePlayer );
        return clip;
    }
//----------------------------------------------------------------------------------------------------------------------

        private static void InitTest(bool enableSceneCacheGo, out PlayableDirector director,
                                     out SceneCachePlayer sceneCachePlayer, out TimelineClip clip)
        {
            EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);

            director         = CreateTestDirector();
            sceneCachePlayer = CreateTestSceneCachePlayer();
            sceneCachePlayer.gameObject.SetActive(enableSceneCacheGo);
            clip = SceneCachePlayerEditorUtility.AddSceneCacheTrackAndClip(director, "TestSceneCacheTrack", sceneCachePlayer);

            TimelineEditorUtility.SelectDirectorInTimelineWindow(director); //trigger the TimelineWindow's update etc.
            TimelineEditorUtility.RefreshTimelineEditor();
        }
Example #12
0
//----------------------------------------------------------------------------------------------------------------------

        bool DrawCacheFile(SceneCachePlayer t)
        {
            t.ShowCacheFileInInspector(EditorGUILayout.Foldout(t.IsCacheFileShownInInspector(), "File", true, GetDefaultFoldoutStyle()));
            if (!t.IsCacheFileShownInInspector())
            {
                return(false);
            }

            bool changed = false;

            //Show Selector GUI. Check if we should reopen
            string fullPath           = t.GetSceneCacheFilePath();
            string prevNormalizedPath = AssetEditorUtility.NormalizePath(fullPath);

            string newNormalizedPath = EditorGUIDrawerUtility.DrawFileSelectorGUI("Cache File Path", "MeshSync",
                                                                                  prevNormalizedPath, "sc", OnSceneCacheFileReload);

            newNormalizedPath = AssetEditorUtility.NormalizePath(newNormalizedPath);

            if (newNormalizedPath != prevNormalizedPath)
            {
                ChangeSceneCacheFileInInspector(t, newNormalizedPath);
            }

            if (!string.IsNullOrEmpty(fullPath) && !fullPath.StartsWith(Application.streamingAssetsPath))
            {
                GUILayout.BeginHorizontal();
                const float BUTTON_WIDTH = 50.0f;
                if (GUILayout.Button("Copy", GUILayout.Width(BUTTON_WIDTH)))
                {
                    string dstPath = Misc.CopyFileToStreamingAssets(fullPath);
                    ChangeSceneCacheFileInInspector(t, dstPath);
                }
                GUILayout.Label("Scene Cache file to StreamingAssets");
                EditorGUILayout.LabelField("(RECOMMENDED)", EditorStyles.boldLabel);
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
                GUILayout.Space(15);
            }
            EditorGUILayout.Space();

            //[TODO-sin: 2022-3-14] This may cause crash when sliding the values back and forth. Find out why
            // preload
            {
                // changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Preload",
                //     guiFunc: () => (EditorGUILayout.IntSlider("Preload Length", t.GetPreloadLength(), 0, t.frameCount)),
                //     updateFunc: (int preloadLength) => { t.SetPreloadLength(preloadLength); });
            }

            return(changed);
        }
//----------------------------------------------------------------------------------------------------------------------    
    
    internal static void ChangeSceneCacheFile(SceneCachePlayer cachePlayer, string sceneCacheFilePath) {
        string     prefabPath = null;
        GameObject go         = cachePlayer.gameObject;
        //Check if it's possible to reuse the old assetsFolder
        string assetsFolder = cachePlayer.GetAssetsFolder();
        if (string.IsNullOrEmpty(assetsFolder)) {
            MeshSyncRuntimeSettings runtimeSettings = MeshSyncRuntimeSettings.GetOrCreateSettings();        
            string                  scOutputPath    = runtimeSettings.GetSceneCacheOutputPath();            
            assetsFolder = Path.Combine(scOutputPath, Path.GetFileNameWithoutExtension(sceneCacheFilePath));
        }
        
        bool isPrefabInstance = cachePlayer.gameObject.IsPrefabInstance();        
        //We are directly modifying a prefab
        if (!isPrefabInstance && go.IsPrefab()) {
            prefabPath = AssetDatabase.GetAssetPath(go);
            CreateSceneCachePlayerAndPrefab(sceneCacheFilePath, prefabPath, assetsFolder, out SceneCachePlayer player,
                out GameObject newPrefab);
            Object.DestroyImmediate(player.gameObject);
            return;

        } 
        
        if (isPrefabInstance) {
            GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(cachePlayer.gameObject);
            prefabPath = AssetDatabase.GetAssetPath(prefab);
        } 
        
        cachePlayer.CloseCache();
        
        //[TODO-sin: 2020-9-28] Find out if it is possible to do undo properly
        Undo.RegisterFullObjectHierarchyUndo(cachePlayer.gameObject, "SceneCachePlayer");
        
        cachePlayer.Init(assetsFolder);
        cachePlayer.OpenCacheInEditor(sceneCacheFilePath);

        //Save as prefab again
        if (string.IsNullOrEmpty(prefabPath)) {
            return;
        }
        
        //Prevent overwriting ".sc" file itself
        bool isPrefabExt = (Path.GetExtension(prefabPath).ToLower() == ".prefab");
        if (isPrefabExt) {
            cachePlayer.gameObject.SaveAsPrefab(prefabPath);            
        }        
    }
        public void ChangeSceneCacheOnGameObject()
        {
            //Initial setup
            GameObject       go     = new GameObject();
            SceneCachePlayer player = go.AddComponent <SceneCachePlayer>();

            Assert.IsFalse(player.IsSceneCacheOpened());

            //Change
            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, Path.GetFullPath(MeshSyncTestEditorConstants.CUBE_TEST_DATA_PATH));
            Assert.IsTrue(player.IsSceneCacheOpened());
            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, Path.GetFullPath(MeshSyncTestEditorConstants.SPHERE_TEST_DATA_PATH));
            Assert.IsTrue(player.IsSceneCacheOpened());

            //Cleanup
            Object.DestroyImmediate(go);
        }
Example #15
0
//----------------------------------------------------------------------------------------------------------------------    
    private static SceneCachePlayer  AddSceneCachePlayer(GameObject go, 
                                                            string sceneCacheFilePath, 
                                                            string assetsFolder) 
    {
        if (!ValidateSceneCacheOutputPath()) {
            return null;
        }
        
              
        SceneCachePlayer player = go.GetOrAddComponent<SceneCachePlayer>();
        player.Init(assetsFolder);

        if (!player.OpenCacheInEditor(sceneCacheFilePath)) {
            return null;
        }       
        
        return player;
    }
Example #16
0
//----------------------------------------------------------------------------------------------------------------------

        public override void OnImportAsset(AssetImportContext ctx)
        {
            //Ignore assets outside Assets folder (for example: Packages, etc)
            if (!ctx.assetPath.StartsWith("Assets/"))
            {
                return;
            }

            GameObject       go     = new GameObject();
            SceneCachePlayer player = go.AddComponent <SceneCachePlayer>();

            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, ctx.assetPath);

            string objectName = Path.GetFileNameWithoutExtension(ctx.assetPath);

            go.name = objectName;

            ctx.AddObjectToAsset(objectName, go);
            ctx.SetMainObject(go);
        }
//----------------------------------------------------------------------------------------------------------------------

        static TestDataComponents ChangeSceneCacheFileAndVerify(SceneCachePlayer player, string scPath)
        {
            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(player, scPath);
            string savedScFilePath = player.GetSceneCacheFilePath();

            Assert.AreEqual(AssetEditorUtility.NormalizePath(scPath), savedScFilePath);
            Assert.IsTrue(AssetEditorUtility.IsPathNormalized(savedScFilePath), $"{savedScFilePath} is not normalized");
            Assert.IsTrue(player.transform.childCount > 0);

            TestDataComponents ret = new TestDataComponents(
                player.GetComponentInChildren <Camera>(),
                player.GetComponentInChildren <Light>(),
                player.GetComponentInChildren <MeshRenderer>()
                );

            Assert.IsNotNull(ret.cam);
            Assert.IsNotNull(ret.light);
            Assert.IsNotNull(ret.meshRenderer);
            return(ret);
        }
        public static GameObject CreateSceneCachePlayer(string path)
        {
            // create temporary GO to make prefab
            GameObject go = new GameObject();

            go.name = System.IO.Path.GetFileNameWithoutExtension(path);

            SceneCachePlayer player = go.AddComponent <SceneCachePlayer>();

            player.rootObject            = go.GetComponent <Transform>();
            player.assetDir              = new DataPath(DataPath.Root.DataPath, string.Format("SceneCache/{0}", go.name));
            player.markMeshesDynamic     = true;
            player.dontSaveAssetsInScene = true;

            if (!player.OpenCache(path))
            {
                Debug.LogError("Failed to open " + path + ". Possible reasons: file format version does not match, or the file is not scene cache.");
                DestroyImmediate(go);
                return(null);
            }
            return(go);
        }
Example #19
0
//----------------------------------------------------------------------------------------------------------------------
        private static bool DrawPlaybackMode(SceneCachePlayer t)
        {
            t.ShowPlaybackInInspector(EditorGUILayout.Foldout(t.IsPlaybackInInspectorShown(), "Playback", true, GetDefaultFoldoutStyle()));
            if (!t.IsPlaybackInInspectorShown())
            {
                return(false);
            }

            bool changed = false;

            changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Playback Mode",
                                                              guiFunc: () =>
                                                              (SceneCachePlaybackMode)EditorGUILayout.EnumPopup("Playback Mode", t.GetPlaybackMode()),
                                                              updateFunc: (SceneCachePlaybackMode mode) => {
                t.SetPlaybackMode(mode);
                SceneCachePlayerEditorUtility.RefreshSceneCache(t);
            }
                                                              );

            ++EditorGUI.indentLevel;
            changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time",
                                                              guiFunc: () => (EditorGUILayout.FloatField("Time", t.GetTime())),
                                                              updateFunc: (float time) => { t.SetTime(Mathf.Max(0, time)); });

            using (new EditorGUI.DisabledScope(t.GetPlaybackMode() == SceneCachePlaybackMode.Interpolate)) {
                changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Frame",
                                                                  guiFunc: () => (EditorGUILayout.IntField("Frame", t.GetFrame())),
                                                                  updateFunc: (int frame) => { t.SetTimeByFrame(Mathf.Max(0, frame)); });
            }
            --EditorGUI.indentLevel;

            using (new EditorGUI.DisabledScope(t.GetPlaybackMode() == SceneCachePlaybackMode.Interpolate)) {
                changed |= SceneCachePlayerEditorUtility.DrawLimitedAnimationGUI(t.GetLimitedAnimationController(), t, t);
            }

            EditorGUILayout.Space();

            return(changed);
        }
Example #20
0
//----------------------------------------------------------------------------------------------------------------------    
    
    internal static bool DrawLimitedAnimationGUI(LimitedAnimationController ctrl, 
        Object target, SceneCachePlayer sc) 
    {
        bool         changed   = false;
        const string UNDO_TEXT = "SceneCache: Limited Animation";
        
        //Limited Animation
        changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT,
            guiFunc: () => (EditorGUILayout.Toggle("Limited Animation", ctrl.IsEnabled())),
            updateFunc: (bool limitedAnimation) => {
                ctrl.SetEnabled(limitedAnimation);
                SceneCachePlayerEditorUtility.RefreshSceneCache(sc);
            });

        ++EditorGUI.indentLevel;
        using (new EditorGUI.DisabledScope(!ctrl.IsEnabled())) {
            changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT,
                guiFunc: () => (
                    EditorGUILayout.IntField("Num Frames to Hold", ctrl.GetNumFramesToHold())
                ),
                updateFunc: (int frames) => {
                    ctrl.SetNumFramesToHold(frames);
                    SceneCachePlayerEditorUtility.RefreshSceneCache(sc);
                });
            changed |= EditorGUIDrawerUtility.DrawUndoableGUI(target, UNDO_TEXT,
                guiFunc: () => (
                    EditorGUILayout.IntField("Frame Offset", ctrl.GetFrameOffset())
                ),
                updateFunc: (int offset) => {
                    ctrl.SetFrameOffset(offset);
                    SceneCachePlayerEditorUtility.RefreshSceneCache(sc);
                });
        }

        --EditorGUI.indentLevel;

        EditorGUILayout.Space();
        return changed;
    }
Example #21
0
        private static void DrawCacheInfo(SceneCachePlayer t)
        {
            ISceneCacheInfo scInfo = t.ExtractSceneCacheInfo(forceOpen: false);

            if (null == scInfo)
            {
                return;
            }

            t.ShowInfoInInspector(EditorGUILayout.Foldout(t.IsInfoInInspectorShown(), "Info", true, GetDefaultFoldoutStyle()));
            if (!t.IsInfoInInspectorShown())
            {
                return;
            }

            ++EditorGUI.indentLevel;

            const int leftWidth  = 160;
            int       numFrames  = scInfo.GetNumFrames();
            float     sampleRate = scInfo.GetSampleRate();
            TimeRange timeRange  = scInfo.GetTimeRange();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label($"Num Frames: {numFrames}", GUILayout.MaxWidth(leftWidth));
            GUILayout.Label($"Start Time: {timeRange.start,15:N4}");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label($"Frame Rate: {sampleRate}", GUILayout.MaxWidth(leftWidth));
            GUILayout.Label($"End Time  : {timeRange.end,15:N4}");
            EditorGUILayout.EndHorizontal();

            --EditorGUI.indentLevel;

            EditorGUILayout.Space();
            EditorGUILayout.Space();
        }
//----------------------------------------------------------------------------------------------------------------------
    public override void OnInspectorGUI() {
        if (m_scPlayableAsset.IsNullRef())
            return;
        
        SerializedObject so = serializedObject;
        EditorGUILayout.PropertyField(so.FindProperty("m_sceneCachePlayerRef"), SCENE_CACHE_PLAYER);

        SceneCacheClipData clipData = m_scPlayableAsset.GetBoundClipData();
        if (null == clipData)
            return;

        SceneCachePlayer scPlayer = m_scPlayableAsset.GetSceneCachePlayer();
        if (null == scPlayer)
            return;

        DrawLimitedAnimationGUI(m_scPlayableAsset);
        
        {
            // Curve Operations
            GUILayout.BeginVertical("Box");
            EditorGUILayout.LabelField("Curves", EditorStyles.boldLabel);

            const float BUTTON_X     = 30;
            const float BUTTON_WIDTH = 160f;
            if (DrawGUIButton(BUTTON_X, BUTTON_WIDTH,"To Linear")) {
                m_scPlayableAsset.SetCurveToLinearInEditor();
            }
            
            if (DrawGUIButton(BUTTON_X, BUTTON_WIDTH,"Apply Original")) {
                m_scPlayableAsset.ApplyOriginalSceneCacheCurveInEditor();
            }
            
            GUILayout.EndVertical();                    
        }
        
        so.ApplyModifiedProperties();       
    }
    internal static bool CreateSceneCachePlayerAndPrefab(string sceneCacheFilePath, 
        string prefabPath, string assetsFolder, 
        out SceneCachePlayer player, out GameObject prefab) 
    {
        player = null;
        prefab = null;
        
        GameObject go = new GameObject();        
        go.name = Path.GetFileNameWithoutExtension(sceneCacheFilePath);

        player = AddSceneCachePlayer(go, sceneCacheFilePath, assetsFolder);
        if (null == player) {
            Object.DestroyImmediate(go);            
            return false;
        }
        prefab = player.gameObject.SaveAsPrefab(prefabPath);
        if (null == prefab) {
            Object.DestroyImmediate(go);            
            return false;
        }
        
        Undo.RegisterCreatedObjectUndo(go, "SceneCachePlayer");
        return true;
    }
        public override void OnInspectorGUI()
        {
            var so             = serializedObject;
            SceneCachePlayer t = target as SceneCachePlayer;

            EditorGUILayout.Space();
            DrawCacheSettings(t, so);
            DrawPlayerSettings(t, so);
            MeshSyncPlayerConfig config = t.GetConfig();

            if (config.Profiling)
            {
                EditorGUILayout.TextArea(t.dbgProfileReport, GUILayout.Height(120));
                EditorGUILayout.Space();
            }

            DrawMaterialList(t);
            DrawTextureList(t);
            DrawAnimationTweak(t);
            DrawExportAssets(t);
            DrawPluginVersion();

            so.ApplyModifiedProperties();
        }
Example #25
0
//----------------------------------------------------------------------------------------------------------------------    
    
    internal static void ChangeSceneCacheFile(SceneCachePlayer cachePlayer, string sceneCacheFilePath) {
        string     prefabPath = null;
        GameObject go         = cachePlayer.gameObject;
        //Check if it's possible to reuse the old assetsFolder
        string assetsFolder = cachePlayer.GetAssetsFolder();
        if (string.IsNullOrEmpty(assetsFolder)) {
            MeshSyncProjectSettings projectSettings = MeshSyncProjectSettings.GetOrCreateSettings();        
            string                  scOutputPath    = projectSettings.GetSceneCacheOutputPath();            
            assetsFolder = Path.Combine(scOutputPath, Path.GetFileNameWithoutExtension(sceneCacheFilePath));
        }
        
        bool isPrefabInstance = cachePlayer.gameObject.IsPrefabInstance();        
        //We are directly modifying a prefab
        if (!isPrefabInstance && go.IsPrefab()) {
            prefabPath = AssetDatabase.GetAssetPath(go);
            CreateSceneCachePlayerAndPrefab(sceneCacheFilePath, prefabPath, assetsFolder, out SceneCachePlayer player,
                out GameObject newPrefab);
            Object.DestroyImmediate(player.gameObject);
            return;

        } 
        
        if (isPrefabInstance) {
            GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(cachePlayer.gameObject);
            
            //GetCorrespondingObjectFromSource() may return the ".sc" GameObject instead of the prefab
            //due to the SceneCacheImporter
            string assetPath = AssetDatabase.GetAssetPath(prefab);
            if (Path.GetExtension(assetPath).ToLower() == ".prefab") {
                prefabPath = assetPath;
            } else {
                isPrefabInstance = false;
            }            
        } 
        
        cachePlayer.CloseCache();
        
        //[TODO-sin: 2020-9-28] Find out if it is possible to do undo properly
        Undo.RegisterFullObjectHierarchyUndo(cachePlayer.gameObject, "SceneCachePlayer");
        
        Dictionary<string,EntityRecord> prevRecords = new Dictionary<string, EntityRecord>(cachePlayer.GetClientObjects());        
        
        GameObject tempGO = null;
        Dictionary<Transform, Transform> nonPrefabTrans = new Dictionary<Transform, Transform>(); //nonPrefab -> origParent
        if (isPrefabInstance) {
            //Move non-prefab transforms
            tempGO = new GameObject("Temp");
            FindNonPrefabChildren(cachePlayer.transform, ref nonPrefabTrans);
            nonPrefabTrans.Keys.SetParent(tempGO.transform);
            
            PrefabUtility.UnpackPrefabInstance(cachePlayer.gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);                       
        }


        //remove irrelevant  components of the GameObject if the entity type is different
        void ChangeEntityTypeCB(GameObject updatedGo, TransformData data) {
            string dataPath = data.path;
            if (!prevRecords.ContainsKey(dataPath)) 
                return;

            EntityRecord prevRecord = prevRecords[dataPath];
            if (data.entityType == prevRecord.dataType) 
                return;

            DestroyIrrelevantComponents(updatedGo, data.entityType);
        }


        cachePlayer.onUpdateEntity += ChangeEntityTypeCB;        
        cachePlayer.Init(assetsFolder);
        cachePlayer.OpenCacheInEditor(sceneCacheFilePath);        
        cachePlayer.onUpdateEntity -= ChangeEntityTypeCB;
        
        IDictionary<string,EntityRecord> curRecords = cachePlayer.GetClientObjects();
        DeleteInvalidRecordedGameObjects(prevRecords, curRecords);

        if (!isPrefabInstance) {
            return;
        }
        
        
        cachePlayer.gameObject.SaveAsPrefab(prefabPath); //Save as prefab if it was originally a prefab instance
        
        //Move nonPrefab transforms back
        foreach (KeyValuePair<Transform, Transform> kv in nonPrefabTrans) {
            Transform origParent = kv.Value;
            Transform t          = kv.Key;
            if (null == origParent) {
                ObjectUtility.Destroy(t.gameObject);
            } else {
                t.SetParent(origParent);
            } 
        }
        ObjectUtility.Destroy(tempGO);
        
        
    }
//----------------------------------------------------------------------------------------------------------------------

        bool DrawCacheSettings(SceneCachePlayer t)
        {
            bool     changed   = false;
            GUIStyle styleFold = EditorStyles.foldout;

            styleFold.fontStyle = FontStyle.Bold;

            t.foldCacheSettings = EditorGUILayout.Foldout(t.foldCacheSettings, "Player", true, styleFold);
            if (t.foldCacheSettings)
            {
                //Show Selector GUI. Check if we should reopen
                string fullPath           = t.GetSceneCacheFilePath();
                string prevNormalizedPath = AssetEditorUtility.NormalizePath(fullPath);

                string newNormalizedPath = EditorGUIDrawerUtility.DrawFileSelectorGUI("Cache File Path", "MeshSync",
                                                                                      prevNormalizedPath, "sc", OnSceneCacheFileReload);
                newNormalizedPath = AssetEditorUtility.NormalizePath(newNormalizedPath);

                if (newNormalizedPath != prevNormalizedPath)
                {
                    ChangeSceneCacheFileInInspector(t, newNormalizedPath);
                }

                if (!string.IsNullOrEmpty(fullPath) && !fullPath.StartsWith(Application.streamingAssetsPath))
                {
                    GUILayout.BeginHorizontal();
                    const float BUTTON_WIDTH = 50.0f;
                    if (GUILayout.Button("Copy", GUILayout.Width(BUTTON_WIDTH)))
                    {
                        string dstPath = Misc.CopyFileToStreamingAssets(fullPath);
                        ChangeSceneCacheFileInInspector(t, dstPath);
                    }
                    GUILayout.Label("Scene Cache file to StreamingAssets");
                    EditorGUILayout.LabelField("(RECOMMENDED)", EditorStyles.boldLabel);
                    GUILayout.FlexibleSpace();
                    GUILayout.EndHorizontal();
                    GUILayout.Space(15);
                }
                EditorGUILayout.Space();

                //Time Unit
                changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time Unit",
                                                                  guiFunc: () => (SceneCachePlayer.TimeUnit)EditorGUILayout.Popup("Time Unit",
                                                                                                                                  (int)t.GetTimeUnit(), TIME_UNIT_ENUMS),
                                                                  updateFunc: (SceneCachePlayer.TimeUnit timeUnit) => {
                    t.SetTimeUnit(timeUnit);
                    t.ResetTimeAnimation();
                }
                                                                  );


                SceneCachePlayer.TimeUnit selectedTimeUnit = t.GetTimeUnit();

                if (selectedTimeUnit == SceneCachePlayer.TimeUnit.Seconds)
                {
                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Time",
                                                                      guiFunc: () => (EditorGUILayout.FloatField("Time", t.GetTime())),
                                                                      updateFunc: (float time) => { t.SetTime(time); });

                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Interpolation",
                                                                      guiFunc: () => (EditorGUILayout.Toggle("Interpolation", t.GetInterpolation())),
                                                                      updateFunc: (bool toggle) => { t.SetInterpolation(toggle); });
                }
                else if (selectedTimeUnit == SceneCachePlayer.TimeUnit.Frames)
                {
                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Base Frame",
                                                                      guiFunc: () => ((SceneCachePlayer.BaseFrame)EditorGUILayout.Popup("Base Frame", (int)t.GetBaseFrame(), BASE_FRAME_ENUMS)),
                                                                      updateFunc: (SceneCachePlayer.BaseFrame baseFrame) => {
                        t.SetBaseFrame(baseFrame);
                        t.ResetTimeAnimation();
                    });

                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Frame",
                                                                      guiFunc: () => (EditorGUILayout.IntField("Frame", t.GetFrame())),
                                                                      updateFunc: (int frame) => { t.SetFrame(frame); });
                }

                // preload
                {
                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "SceneCache: Preload",
                                                                      guiFunc: () => (EditorGUILayout.IntSlider("Preload Length", t.GetPreloadLength(), 0, t.frameCount)),
                                                                      updateFunc: (int preloadLength) => { t.SetPreloadLength(preloadLength); });
                }

                EditorGUILayout.Space();
            }

            return(changed);
        }
//----------------------------------------------------------------------------------------------------------------------
        private static void ChangeSceneCacheFileInInspector(SceneCachePlayer cachePlayer, string sceneCacheFilePath)
        {
            SceneCachePlayerEditorUtility.ChangeSceneCacheFile(cachePlayer, sceneCacheFilePath);
        }
//----------------------------------------------------------------------------------------------------------------------

        private static bool DrawSceneCacheImportSettings(SceneCachePlayer t)
        {
            bool changed = false;
            MeshSyncPlayerConfig playerConfig = t.GetConfigV();

            t.foldImportSettings = EditorGUILayout.Foldout(t.foldImportSettings, "Import Settings", true, GetBoldFoldoutStyle());
            if (t.foldImportSettings)
            {
                IHasModelImporterSettings importer         = AssetImporter.GetAtPath(t.GetSceneCacheFilePath()) as IHasModelImporterSettings;
                ModelImporterSettings     importerSettings = playerConfig.GetModelImporterSettings();

                if (null == importer)
                {
                    MeshSyncInspectorUtility.DrawModelImporterSettingsGUI(t, importerSettings);
                }
                else
                {
                    bool isOverride = t.IsModelImporterSettingsOverridden();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUIDrawerUtility.DrawUndoableGUI(t, "Override",
                                                           guiFunc: () => GUILayout.Toggle(isOverride, "", GUILayout.MaxWidth(15.0f)),
                                                           updateFunc: (bool overrideValue) => { t.OverrideModelImporterSettings(overrideValue); });

                    using (new EditorGUI.DisabledScope(!isOverride)) {
                        EditorGUIDrawerUtility.DrawUndoableGUI(t, "Create Materials",
                                                               guiFunc: () => (bool)EditorGUILayout.Toggle("Create Materials", importerSettings.CreateMaterials),
                                                               updateFunc: (bool createMat) => { importerSettings.CreateMaterials = createMat; });
                    }

                    EditorGUILayout.EndHorizontal();

                    using (new EditorGUI.DisabledScope(!isOverride)) {
                        ++EditorGUI.indentLevel;
                        MeshSyncInspectorUtility.DrawModelImporterMaterialSearchMode(t, importerSettings);
                        --EditorGUI.indentLevel;
                    }
                }



                changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Animation Interpolation",
                                                                  guiFunc: () => EditorGUILayout.Popup(new GUIContent("Animation Interpolation"),
                                                                                                       playerConfig.AnimationInterpolation, MeshSyncEditorConstants.ANIMATION_INTERPOLATION_ENUMS),
                                                                  updateFunc: (int val) => { playerConfig.AnimationInterpolation = val; }
                                                                  );


                changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Keyframe Reduction",
                                                                  guiFunc: () => EditorGUILayout.Toggle("Keyframe Reduction", playerConfig.KeyframeReduction),
                                                                  updateFunc: (bool toggle) => { playerConfig.KeyframeReduction = toggle; }
                                                                  );

                if (playerConfig.KeyframeReduction)
                {
                    EditorGUI.indentLevel++;

                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Threshold",
                                                                      guiFunc: () => EditorGUILayout.FloatField("Threshold", playerConfig.ReductionThreshold),
                                                                      updateFunc: (float val) => { playerConfig.ReductionThreshold = val; }
                                                                      );

                    changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Erase Flat Curves",
                                                                      guiFunc: () => EditorGUILayout.Toggle("Erase Flat Curves", playerConfig.ReductionEraseFlatCurves),
                                                                      updateFunc: (bool toggle) => { playerConfig.ReductionEraseFlatCurves = toggle; }
                                                                      );
                    EditorGUI.indentLevel--;
                }

                changed |= EditorGUIDrawerUtility.DrawUndoableGUI(t, "MeshSync: Z-Up Correction",
                                                                  guiFunc: () => EditorGUILayout.Popup(new GUIContent("Z-Up Correction"), playerConfig.ZUpCorrection,
                                                                                                       MeshSyncEditorConstants.Z_UP_CORRECTION_ENUMS),
                                                                  updateFunc: (int val) => { playerConfig.ZUpCorrection = val; }
                                                                  );

                EditorGUILayout.Space();
            }

            return(changed);
        }
        void DrawCacheSettings(SceneCachePlayer t, SerializedObject so)
        {
            var styleFold = EditorStyles.foldout;

            styleFold.fontStyle = FontStyle.Bold;

            t.foldCacheSettings = EditorGUILayout.Foldout(t.foldCacheSettings, "Player", true, styleFold);
            if (t.foldCacheSettings)
            {
                // cache file path
                EditorGUILayout.PropertyField(so.FindProperty("m_cacheFilePath"));
                var dataPath = t.cacheFilePath;
                if (dataPath.root != DataPath.Root.StreamingAssets)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button("Copy to StreamingAssets", GUILayout.Width(160.0f)))
                    {
                        var srcPath = dataPath.fullPath;
                        var dstPath = Misc.CopyFileToStreamingAssets(dataPath.fullPath);
                        Undo.RecordObject(t, "SceneCachePlayer");
                        t.OpenCache(dstPath);
                        Repaint();
                    }
                    if (GUILayout.Button("Move to StreamingAssets", GUILayout.Width(160.0f)))
                    {
                        t.CloseCache();
                        var srcPath = dataPath.fullPath;
                        var dstPath = Misc.MoveFileToStreamingAssets(dataPath.fullPath);
                        Undo.RecordObject(t, "SceneCachePlayer");
                        t.OpenCache(dstPath);
                        Repaint();
                    }
                    GUILayout.EndHorizontal();
                }
                EditorGUILayout.Space();


                // time / frame
                System.Action resetTimeAnimation = () =>
                {
                    so.ApplyModifiedProperties();
                    t.ResetTimeAnimation();
                };

                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(so.FindProperty("m_timeUnit"));
                if (EditorGUI.EndChangeCheck())
                {
                    resetTimeAnimation();
                }

                if (t.timeUnit == SceneCachePlayer.TimeUnit.Seconds)
                {
                    EditorGUILayout.PropertyField(so.FindProperty("m_time"));
                    EditorGUILayout.PropertyField(so.FindProperty("m_interpolation"));
                }
                else if (t.timeUnit == SceneCachePlayer.TimeUnit.Frames)
                {
                    EditorGUI.BeginChangeCheck();
                    EditorGUILayout.PropertyField(so.FindProperty("m_baseFrame"));
                    if (EditorGUI.EndChangeCheck())
                    {
                        resetTimeAnimation();
                    }

                    EditorGUILayout.PropertyField(so.FindProperty("m_frame"));
                }

                // preload
                {
                    var preloadLength = so.FindProperty("m_preloadLength");
                    preloadLength.intValue = EditorGUILayout.IntSlider("Preload Length", preloadLength.intValue, 0, t.frameCount);
                }

                EditorGUILayout.Space();
            }
        }
        private IEnumerator IterateAllSceneCacheFrames(PlayableDirector director, TimelineClip clip, SceneCachePlayer scPlayer,
                                                       Action <int> afterUpdateFunc)
        {
            ISceneCacheInfo scInfo = scPlayer.ExtractSceneCacheInfo(forceOpen: true);

            Assert.IsNotNull(scInfo);

            double timePerFrame = 1.0f / scInfo.GetSampleRate();

            //Use (numFrames-1) because when it becomes invisible when Timeline reaches the last frame
            for (int i = 0; i < scInfo.GetNumFrames() - 1; ++i)
            {
                double elapsedTime = i * timePerFrame;
                if (elapsedTime >= clip.duration)
                {
                    yield break;
                }

                double directorTime = clip.start + i * timePerFrame;
                SetDirectorTime(director, directorTime); //this will trigger change in the time of the SceneCachePlayable
                yield return(null);

                afterUpdateFunc(i);
            }
        }