//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) { StreamingImageSequencePlayableAsset asset = clip.asset as StreamingImageSequencePlayableAsset; if (null == asset) { Debug.LogError("Asset is not a StreamingImageSequencePlayableAsset: " + clip.asset); return; } StreamingImageSequenceTrack sisTrack = track as StreamingImageSequenceTrack; Assert.IsNotNull(sisTrack); //This callback occurs before the clip is assigned to the track, but we need the track for creating curves. clip.parentTrack = track; //If we have a default asset, and clonedFrom is NULL, which means this is created by user interaction, //such as Folder D&D UnityEditor.DefaultAsset timelineDefaultAsset = asset.GetTimelineDefaultAsset(); if (null != timelineDefaultAsset && null == clonedFrom) { InitializeAssetFromDefaultAsset(asset, timelineDefaultAsset); } //If the clip already has curves (because of cloning, etc), then we don't set anything if (null == clip.curves) { if (asset.HasImages()) { clip.duration = asset.GetImageFileNames().Count * 0.125; // 8fps (standard limited animation) clip.displayName = Path.GetFileName(asset.GetFolder()); } clip.CreateCurves("Curves: " + clip.displayName); } TimelineClipSISData sisData = null; asset.InitTimelineClipCurve(clip); if (null == clonedFrom) { sisData = new TimelineClipSISData(clip); asset.BindTimelineClipSISData(sisData); return; } //Duplicate/Split process StreamingImageSequencePlayableAsset clonedFromAsset = clonedFrom.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(clonedFromAsset); TimelineClipSISData otherSISData = clonedFromAsset.GetBoundTimelineClipSISData(); sisData = new TimelineClipSISData(clip, otherSISData); asset.BindTimelineClipSISData(sisData); clip.displayName = clonedFrom.displayName + " (Cloned)"; }
//---------------------------------------------------------------------------------------------------------------------- private void ShowCaptureSelectedFramesGUI(TimelineClip timelineClip, TimelineClipSISData timelineClipSISData) { bool prevMarkersRequest = timelineClipSISData.AreFrameMarkersRequested(); TrackAsset track = timelineClip.parentTrack; GUILayout.BeginHorizontal(); bool markerVisibility = EditorGUILayout.Toggle("Show Frame Markers", prevMarkersRequest); if (markerVisibility != prevMarkersRequest) { timelineClipSISData.RequestFrameMarkers(markerVisibility); } GUILayout.FlexibleSpace(); EditorGUI.BeginDisabledGroup(!markerVisibility); if (GUILayout.Button("Capture All", GUILayout.Width(80))) { Undo.RegisterCompleteObjectUndo(track, "RenderCachePlayableAsset: Capturing all frames"); timelineClipSISData.SetAllPlayableFramesProperty(PlayableFramePropertyID.USED, true); } if (GUILayout.Button("Reset", GUILayout.Width(50))) { Undo.RegisterCompleteObjectUndo(track, "RenderCachePlayableAsset: Capturing no frame"); timelineClipSISData.SetAllPlayableFramesProperty(PlayableFramePropertyID.USED, false); } EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); }
public IEnumerator ShowFrameMarkers() { PlayableDirector director = EditorUtilityTest.NewSceneWithDirector(); TimelineClip clip = EditorUtilityTest.CreateTestTimelineClip(director); StreamingImageSequencePlayableAsset sisAsset = clip.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(sisAsset); yield return(null); //Show TimelineClipSISData timelineClipSISData = sisAsset.GetBoundTimelineClipSISData(); TrackAsset trackAsset = clip.parentTrack; timelineClipSISData.RequestFrameMarkers(true, true); TimelineEditor.Refresh(RefreshReason.ContentsModified); yield return(null); Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); yield return(null); //Undo showing FrameMarkers EditorUtilityTest.UndoAndRefreshTimelineEditor(); yield return(null); Assert.False(timelineClipSISData.AreFrameMarkersRequested()); Assert.AreEqual(0, trackAsset.GetMarkerCount()); EditorUtilityTest.DestroyTestTimelineAssets(clip); yield return(null); }
internal static void ShowFrameMarkersGUI(BaseTimelineClipSISDataPlayableAsset timelineClipSISDataPlayableAsset) { TimelineClipSISData timelineClipSISData = timelineClipSISDataPlayableAsset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { return; } using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { bool prevMarkerVisibility = timelineClipSISData.AreFrameMarkersRequested(); EditorGUILayout.BeginHorizontal(); bool markerVisibility = EditorGUILayout.Toggle("Show Frame Markers", prevMarkerVisibility); if (markerVisibility != prevMarkerVisibility) { timelineClipSISData.RequestFrameMarkers(markerVisibility); } if (GUILayout.Button("Reset", GUILayout.Width(50f))) { timelineClipSISDataPlayableAsset.ResetPlayableFrames(); } EditorGUILayout.EndHorizontal(); } }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void DrawBackground(TimelineClip clip, ClipBackgroundRegion region) { base.DrawBackground(clip, region); Rect rect = region.position; if (rect.width <= SISEditorConstants.MIN_PREVIEW_REGION_WIDTH) { return; } T curAsset = clip.asset as T; if (null == curAsset) { return; } DrawBackgroundTexture(rect, curAsset.GetTimelineBGColor()); int numImages = curAsset.GetNumImages(); if (numImages <= 0) { return; } if (Event.current.type == EventType.Repaint) { PreviewClipInfo clipInfo = new PreviewClipInfo() { Duration = clip.duration, TimeScale = clip.timeScale, ClipIn = clip.clipIn, FramePerSecond = clip.parentTrack.timelineAsset.editorSettings.fps, ImageDimensionRatio = curAsset.GetOrUpdateDimensionRatio(), VisibleLocalStartTime = region.startTime, VisibleLocalEndTime = region.endTime, VisibleRect = rect, }; PreviewUtility.EnumeratePreviewImages(ref clipInfo, (PreviewDrawInfo drawInfo) => { DrawPreviewImageV(ref drawInfo, clip, curAsset); }); //For hiding frame marker automatically TimelineClipSISData timelineClipSISData = curAsset.GetBoundTimelineClipSISData(); if (null != timelineClipSISData) { timelineClipSISData.UpdateTimelineWidthPerFrame(rect.width, region.endTime - region.startTime, clipInfo.FramePerSecond, clipInfo.TimeScale); } } }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom) { RenderCachePlayableAsset asset = clip.asset as RenderCachePlayableAsset; Assert.IsNotNull(asset); clip.parentTrack = track; TimelineClipSISData sisData = new TimelineClipSISData(clip); asset.BindTimelineClipSISData(sisData); }
public IEnumerator ResizePlayableAsset() { PlayableDirector director = EditorUtilityTest.NewSceneWithDirector(); TimelineClip clip = EditorUtilityTest.CreateTestTimelineClip(director); StreamingImageSequencePlayableAsset sisAsset = clip.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(sisAsset); TimelineClipSISData timelineClipSISData = sisAsset.GetBoundTimelineClipSISData(); yield return(null); timelineClipSISData.RequestFrameMarkers(true, true); Undo.IncrementCurrentGroup(); //the base of undo is here. FrameMarkerVisibility is still true after undo TimelineEditor.Refresh(RefreshReason.ContentsModified); yield return(null); //Original length TrackAsset trackAsset = clip.parentTrack; Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); double origClipDuration = clip.duration; //Resize longer EditorUtilityTest.ResizeSISTimelineClip(clip, origClipDuration + 3.0f); yield return(null); Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); //Undo EditorUtilityTest.UndoAndRefreshTimelineEditor(); yield return(null); Assert.AreEqual(origClipDuration, clip.duration); Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); //Resize shorter EditorUtilityTest.ResizeSISTimelineClip(clip, Mathf.Max(0.1f, ((float)(origClipDuration) - 3.0f))); yield return(null); Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); //Undo EditorUtilityTest.UndoAndRefreshTimelineEditor(); yield return(null); Assert.AreEqual(origClipDuration, clip.duration); Assert.AreEqual(TimelineUtility.CalculateNumFrames(clip), trackAsset.GetMarkerCount()); EditorUtilityTest.DestroyTestTimelineAssets(clip); yield return(null); }
//---------------------------------------------------------------------------------------------------------------------- /// <inheritdoc/> public override void DrawBackground(TimelineClip clip, ClipBackgroundRegion region) { base.DrawBackground(clip, region); Rect rect = region.position; if (rect.width <= SISEditorConstants.MIN_PREVIEW_REGION_WIDTH) { return; } StreamingImageSequencePlayableAsset curAsset = clip.asset as StreamingImageSequencePlayableAsset; if (null == curAsset || !curAsset.HasImages()) { return; } if (Event.current.type == EventType.Repaint) { PreviewClipInfo clipInfo = new PreviewClipInfo() { Duration = clip.duration, TimeScale = clip.timeScale, ClipIn = clip.clipIn, FramePerSecond = clip.parentTrack.timelineAsset.editorSettings.fps, ImageDimensionRatio = curAsset.GetOrUpdateDimensionRatio(), VisibleLocalStartTime = region.startTime, VisibleLocalEndTime = region.endTime, VisibleRect = rect, }; PreviewUtility.EnumeratePreviewImages(ref clipInfo, (PreviewDrawInfo drawInfo) => { DrawPreviewImage(ref drawInfo, clip, curAsset); }); //For hiding frame marker automatically int numFrames = Mathf.RoundToInt((float)((region.endTime - region.startTime) * clipInfo.FramePerSecond)); double widthPerFrame = rect.width / numFrames; TimelineClipSISData timelineClipSISData = curAsset.GetBoundTimelineClipSISData(); if (null != timelineClipSISData) { timelineClipSISData.SetTimelineWidthPerFrame(widthPerFrame); } } }
//---------------------------------------------------------------------------------------------------------------------- private static void SetMarkerValueByContext(FrameMarker frameMarker, bool value) { SISPlayableFrame playableFrame = frameMarker.GetOwner(); TimelineClipSISData timelineClipSISData = playableFrame.GetOwner(); PlayableFramePropertyID inspectedPropertyID = timelineClipSISData.GetInspectedProperty(); switch (inspectedPropertyID) { case PlayableFramePropertyID.USED: { playableFrame.SetUsed(value); break; } case PlayableFramePropertyID.LOCKED: { playableFrame.SetLocked(value); break; } } }
//---------------------------------------------------------------------------------------------------------------------- public override void DrawOverlay(IMarker m, MarkerUIStates uiState, MarkerOverlayRegion region) { FrameMarker marker = m as FrameMarker; if (null == marker) return; SISPlayableFrame playableFrame = marker.GetOwner(); //Check invalid PlayableFrame. Perhaps because of unsupported Duplicate operation ? if (null == playableFrame) return; TimelineClipSISData timelineClipSISData = playableFrame.GetOwner(); PlayableFramePropertyID inspectedPropertyID = timelineClipSISData.GetInspectedProperty(); switch (inspectedPropertyID) { case PlayableFramePropertyID.USED: { if (playableFrame.IsLocked()) { //At the moment, all locked frames are regarded as inactive if (playableFrame.IsUsed()) { Graphics.DrawTexture(region.markerRegion, EditorTextures.GetInactiveCheckedTexture()); } Rect lockRegion = region.markerRegion; lockRegion.x -= 5; lockRegion.y -= 8; Graphics.DrawTexture(lockRegion, EditorTextures.GetLockTexture()); } else { if (playableFrame.IsUsed()) { Graphics.DrawTexture(region.markerRegion, EditorTextures.GetCheckedTexture()); } } break; } case PlayableFramePropertyID.LOCKED: { if (playableFrame.IsLocked()) { Graphics.DrawTexture(region.markerRegion, EditorTextures.GetLockTexture()); } break; } } }
internal static void ToggleMarkerValueByContext(FrameMarker frameMarker) { SISPlayableFrame playableFrame = frameMarker.GetOwner(); TimelineClipSISData timelineClipSISData = playableFrame.GetOwner(); PlayableFramePropertyID inspectedPropertyID = timelineClipSISData.GetInspectedProperty(); switch (inspectedPropertyID) { case PlayableFramePropertyID.USED: { playableFrame.SetUsed(!playableFrame.IsUsed()); break; } case PlayableFramePropertyID.LOCKED: { playableFrame.SetLocked(!playableFrame.IsLocked()); break; } } }
public IEnumerator ResetFrameMarkers() { PlayableDirector director = EditorUtilityTest.NewSceneWithDirector(); TimelineClip clip = EditorUtilityTest.CreateTestTimelineClip(director); StreamingImageSequencePlayableAsset sisAsset = clip.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(sisAsset); TimelineClipSISData timelineClipSISData = sisAsset.GetBoundTimelineClipSISData(); timelineClipSISData.RequestFrameMarkers(true); yield return(null); //Change image to false StreamingImageSequenceTrack track = clip.parentTrack as StreamingImageSequenceTrack; Assert.IsNotNull(track); foreach (var m in track.GetMarkers()) { FrameMarker marker = m as FrameMarker; Assert.IsNotNull(marker); marker.SetFrameUsed(false); UnityEngine.Assertions.Assert.IsFalse(marker.IsFrameUsed()); } yield return(null); sisAsset.ResetPlayableFrames(); yield return(null); //Check if all markers have been reset to used foreach (var m in track.GetMarkers()) { FrameMarker marker = m as FrameMarker; Assert.IsNotNull(marker); UnityEngine.Assertions.Assert.IsTrue(marker.IsFrameUsed()); } yield return(null); EditorUtilityTest.DestroyTestTimelineAssets(clip); yield return(null); }
//---------------------------------------------------------------------------------------------------------------------- internal static TimelineClip CreateTestTimelineClip(PlayableDirector director) { string tempTimelineAssetPath = AssetDatabase.GenerateUniqueAssetPath("Assets/TempTimelineForTestRunner.playable"); //Create timeline asset TimelineAsset timelineAsset = ScriptableObject.CreateInstance <TimelineAsset>(); director.playableAsset = timelineAsset; AssetDatabase.CreateAsset(timelineAsset, tempTimelineAssetPath); //Create empty asset StreamingImageSequenceTrack sisTrack = timelineAsset.CreateTrack <StreamingImageSequenceTrack>(null, "Footage"); TimelineClip clip = sisTrack.CreateDefaultClip(); StreamingImageSequencePlayableAsset sisAsset = clip.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(sisAsset); clip.CreateCurves("Curves: " + clip.displayName); TimelineClipSISData sisData = new TimelineClipSISData(clip); sisAsset.InitTimelineClipCurve(clip); sisAsset.BindTimelineClipSISData(sisData); //Select gameObject and open Timeline Window. This will trigger the TimelineWindow's update etc. EditorApplication.ExecuteMenuItem("Window/Sequencing/Timeline"); // Selection.activeTransform = director.gameObject.transform; // TimelineEditor.selectedClip = sisAsset.GetBoundTimelineClip(); Selection.activeObject = director; string fullPath = Path.GetFullPath(SRC_IMAGE_PATH); ImageSequenceImporter.ImportImages(fullPath, sisAsset, false); return(clip); }
//---------------------------------------------------------------------------------------------------------------------- private void ShowLockFramesGUI(TimelineClip timelineClip, TimelineClipSISData timelineClipSISData) { TrackAsset track = timelineClip.parentTrack; using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Lock Frames"); bool lockMode = GUILayout.Toggle(m_lockMode, EditorTextures.GetLockTexture(), "Button", GUILayout.Height(20f), GUILayout.Width(30f)); if (lockMode != m_lockMode) //lock state changed { if (lockMode) { LockSISData(timelineClipSISData); } else { UnlockSISData(); } } GUILayout.FlexibleSpace(); EditorGUI.BeginDisabledGroup(!m_lockMode); if (GUILayout.Button("Lock All", GUILayout.Width(80))) { Undo.RegisterCompleteObjectUndo(track, "RenderCachePlayableAsset: Locking all frames"); timelineClipSISData.SetAllPlayableFramesProperty(PlayableFramePropertyID.LOCKED, true); } if (GUILayout.Button("Reset", GUILayout.Width(50))) { Undo.RegisterCompleteObjectUndo(track, "RenderCachePlayableAsset: Locking no frame"); timelineClipSISData.SetAllPlayableFramesProperty(PlayableFramePropertyID.LOCKED, false); } EditorGUI.EndDisabledGroup(); } }
//---------------------------------------------------------------------------------------------------------------------- public override void OnInspectorGUI() { //View resolution Vector2 res = ViewEditorUtility.GetMainGameViewSize(); EditorGUILayout.LabelField("Resolution (Modify GameView size to change)"); ++EditorGUI.indentLevel; EditorGUILayout.LabelField("Width", res.x.ToString(CultureInfo.InvariantCulture)); EditorGUILayout.LabelField("Height", res.y.ToString(CultureInfo.InvariantCulture)); --EditorGUI.indentLevel; EditorGUILayout.Space(15f); //Check if the asset is actually inspected if (null != TimelineEditor.selectedClip && TimelineEditor.selectedClip.asset != m_asset) { return; } ValidateAssetFolder(); string prevFolder = m_asset.GetFolder(); string newFolder = InspectorUtility.ShowFolderSelectorGUI("Cache Output Folder", "Select Folder", prevFolder, AssetEditorUtility.NormalizeAssetPath ); if (newFolder != prevFolder) { m_asset.SetFolder(AssetEditorUtility.NormalizeAssetPath(newFolder)); GUIUtility.ExitGUI(); } TimelineClipSISData timelineClipSISData = m_asset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { return; } GUILayout.Space(15); //Capture Selected Frames using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { ShowCaptureSelectedFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); ShowLockFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); } ShortcutBinding updateRenderCacheShortcut = ShortcutManager.instance.GetShortcutBinding(SISEditorConstants.SHORTCUT_UPDATE_RENDER_CACHE); GUILayout.Space(15); if (GUILayout.Button($"Update Render Cache ({updateRenderCacheShortcut})")) { PlayableDirector director = TimelineEditor.inspectedDirector; if (null == director) { EditorUtility.DisplayDialog("Streaming Image Sequence", "PlayableAsset is not loaded in scene. Please load the correct scene before doing this operation.", "Ok"); return; } //Loop time EditorCoroutineUtility.StartCoroutine(UpdateRenderCacheCoroutine(director, m_asset), this); } }
//---------------------------------------------------------------------------------------------------------------------- static void LockSISData(TimelineClipSISData timelineClipSISData) { m_inspectedSISDataForLocking = timelineClipSISData; m_inspectedSISDataForLocking.SetInspectedProperty(PlayableFramePropertyID.LOCKED); m_lockMode = true; }
//---------------------------------------------------------------------------------------------------------------------- public override void OnInspectorGUI() { //View resolution Vector2 res = ViewEditorUtility.GetMainGameViewSize(); EditorGUILayout.LabelField("Resolution (Modify GameView size to change)"); ++EditorGUI.indentLevel; EditorGUILayout.LabelField("Width", res.x.ToString(CultureInfo.InvariantCulture)); EditorGUILayout.LabelField("Height", res.y.ToString(CultureInfo.InvariantCulture)); --EditorGUI.indentLevel; EditorGUILayout.Space(15f); //Check if the asset is actually inspected if (null != TimelineEditor.selectedClip && TimelineEditor.selectedClip.asset != m_asset) { return; } ValidateAssetFolder(); string prevFolder = m_asset.GetFolder(); string newFolder = EditorGUIDrawerUtility.DrawFolderSelectorGUI("Cache Output Folder", "Select Folder", prevFolder, null, AssetUtility.NormalizeAssetPath ); if (newFolder != prevFolder) { m_asset.SetFolder(AssetUtility.NormalizeAssetPath(newFolder)); GUIUtility.ExitGUI(); } TimelineClipSISData timelineClipSISData = m_asset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { return; } GUILayout.Space(15); //Capture Selected Frames using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { DrawCaptureSelectedFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); DrawLockFramesGUI(TimelineEditor.selectedClip, timelineClipSISData); } GUILayout.Space(15); using (new EditorGUILayout.VerticalScope(GUI.skin.box)) { EditorGUILayout.LabelField("Background Colors"); ++EditorGUI.indentLevel; RenderCachePlayableAssetEditorConfig editorConfig = m_asset.GetEditorConfig(); Color updateBGColor = editorConfig.GetUpdateBGColor(); Color timelineBgColor = m_asset.GetTimelineBGColor(); editorConfig.SetUpdateBGColor(EditorGUILayout.ColorField("In Game Window (Update)", updateBGColor)); m_asset.SetTimelineBGColor(EditorGUILayout.ColorField("In Timeline Window", timelineBgColor)); --EditorGUI.indentLevel; GUILayout.Space(5); } GUILayout.Space(15); DrawUpdateRenderCacheGUI(); }
//---------------------------------------------------------------------------------------------------------------------- internal static IEnumerator UpdateRenderCacheCoroutine(PlayableDirector director, RenderCachePlayableAsset renderCachePlayableAsset) { Assert.IsNotNull(director); Assert.IsNotNull(renderCachePlayableAsset); TimelineClipSISData timelineClipSISData = renderCachePlayableAsset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { EditorUtility.DisplayDialog("Streaming Image Sequence", "RenderCachePlayableAsset is not ready", "Ok"); yield break; } TrackAsset track = renderCachePlayableAsset.GetBoundTimelineClipSISData().GetOwner().parentTrack; BaseRenderCapturer renderCapturer = director.GetGenericBinding(track) as BaseRenderCapturer; if (null == renderCapturer) { EditorUtility.DisplayDialog("Streaming Image Sequence", "Please bind an appropriate RenderCapturer component to the track.", "Ok"); yield break; } //begin capture bool canCapture = renderCapturer.BeginCapture(); if (!canCapture) { EditorUtility.DisplayDialog("Streaming Image Sequence", renderCapturer.GetLastErrorMessage(), "Ok"); yield break; } //Check output folder string outputFolder = renderCachePlayableAsset.GetFolder(); if (string.IsNullOrEmpty(outputFolder) || !Directory.Exists(outputFolder)) { EditorUtility.DisplayDialog("Streaming Image Sequence", "Invalid output folder", "Ok"); yield break; } Texture capturerTex = renderCapturer.GetInternalTexture(); //Show progress in game view GameObject progressGo = new GameObject("Blitter"); LegacyTextureBlitter blitter = progressGo.AddComponent <LegacyTextureBlitter>(); blitter.SetTexture(capturerTex); blitter.SetCameraDepth(int.MaxValue); TimelineClip timelineClip = timelineClipSISData.GetOwner(); double nextDirectorTime = timelineClip.start; double timePerFrame = 1.0f / track.timelineAsset.editorSettings.fps; int fileCounter = 0; int numFiles = (int)Math.Ceiling(timelineClip.duration / timePerFrame) + 1; int numDigits = MathUtility.GetNumDigits(numFiles); string prefix = $"{timelineClip.displayName}_"; List <string> imageFileNames = new List <string>(numFiles); //Store old files that has the same pattern string[] existingFiles = Directory.GetFiles(outputFolder, $"*.png"); HashSet <string> filesToDelete = new HashSet <string>(existingFiles); bool cancelled = false; while (nextDirectorTime <= timelineClip.end && !cancelled) { string fileName = $"{prefix}{fileCounter.ToString($"D{numDigits}")}.png"; string outputFilePath = Path.Combine(outputFolder, fileName); SISPlayableFrame playableFrame = timelineClipSISData.GetPlayableFrame(fileCounter); bool captureFrame = (!timelineClipSISData.AreFrameMarkersRequested() || //if markers are not requested, capture !File.Exists(outputFilePath) || //if file doesn't exist, capture (null != playableFrame && playableFrame.IsUsed() && !playableFrame.IsLocked()) ); if (filesToDelete.Contains(outputFilePath)) { filesToDelete.Remove(outputFilePath); } imageFileNames.Add(fileName); if (captureFrame) { SetDirectorTime(director, nextDirectorTime); //Need at least two frames in order to wait for the TimelineWindow to be updated ? yield return(null); yield return(null); yield return(null); //Unload texture because it may be overwritten StreamingImageSequencePlugin.UnloadImageAndNotify(outputFilePath); renderCapturer.CaptureToFile(outputFilePath); } nextDirectorTime += timePerFrame; ++fileCounter; cancelled = EditorUtility.DisplayCancelableProgressBar( "StreamingImageSequence", "Caching render results", ((float)fileCounter / numFiles)); } if (!cancelled) { renderCachePlayableAsset.SetImageFileNames(imageFileNames); //Delete old files if (AssetDatabase.IsValidFolder(outputFolder)) { foreach (string oldFile in filesToDelete) { AssetDatabase.DeleteAsset(oldFile); } } else { foreach (string oldFile in filesToDelete) { File.Delete(oldFile); } } } //Notify FolderContentsChangedNotifier.GetInstance().Notify(outputFolder); //Cleanup EditorUtility.ClearProgressBar(); renderCapturer.EndCapture(); ObjectUtility.Destroy(progressGo); AssetDatabase.Refresh(); yield return(null); }
//--------------------------------------------------------------------------------------------------------------------- /// <summary> /// Import a timeline file exported from DCC tools into the scene in the Timeline object /// </summary> /// <param name="jsTimelinePath">The path of the file</param> /// <param name="destFolder">The dest folder of the imported files</param> public static void ImportTimeline(string jsTimelinePath, string destFolder = "") { // prepare asset name, paths, etc string assetName = Path.GetFileNameWithoutExtension(jsTimelinePath); string timelineFolder = Path.GetDirectoryName(jsTimelinePath); if (string.IsNullOrEmpty(timelineFolder)) { Debug.LogError("Can't get directory name for: " + jsTimelinePath); return; } timelineFolder = Path.Combine(timelineFolder, destFolder, assetName).Replace("\\", "/"); //Check if we are exporting from external asset if (!timelineFolder.StartsWith("Assets/")) { timelineFolder = Path.Combine("Assets", destFolder, assetName); } Directory.CreateDirectory(timelineFolder); string strJson = File.ReadAllText(jsTimelinePath); TimelineParam container = JsonUtility.FromJson <TimelineParam>(strJson); string assetFolder = container.assetFolder; if (string.IsNullOrEmpty(assetFolder)) { assetFolder = Path.GetDirectoryName(jsTimelinePath); } //delete existing objects in the scene that is pointing to the Director string timelinePath = Path.Combine(timelineFolder, assetName + "_Timeline.playable").Replace("\\", "/"); PlayableDirector director = RemovePlayableFromDirectorsInScene(timelinePath); if (null == director) { GameObject directorGo = new GameObject(assetName); director = directorGo.AddComponent <PlayableDirector>(); } //Create timeline asset TimelineAsset asset = ScriptableObject.CreateInstance <TimelineAsset>(); AssetEditorUtility.OverwriteAsset(asset, timelinePath); director.playableAsset = asset; string strHome = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); int numTracks = container.Tracks.Length; for (int index = numTracks - 1; index >= 0; index--) { var track = container.Tracks[index]; string strFootagePath = track.Footage; // remove '~' if necessary if (strFootagePath.StartsWith("~")) { strFootagePath = strHome + strFootagePath.Substring(1); } if (!Path.IsPathRooted(strFootagePath)) { strFootagePath = Path.Combine(assetFolder, strFootagePath); } string strFootageName = Path.GetFileNameWithoutExtension(strFootagePath); string strJsonFootage = File.ReadAllText(strFootagePath); AEFootageInfo footageInfo = JsonUtility.FromJson <AEFootageInfo>(strJsonFootage); int numImages = footageInfo.Pictures.Count; if (numImages > 0) { List <string> originalImagePaths = new List <string>(footageInfo.Pictures); for (int xx = 0; xx < numImages; ++xx) { string fileName = footageInfo.Pictures[xx]; // replace '~' with the path to home (for Linux environment if (fileName.StartsWith("~")) { fileName = strHome + fileName.Substring(1); } footageInfo.Pictures[xx] = Path.GetFileName(fileName); } string destFootageFolder = Application.streamingAssetsPath; destFootageFolder = Path.Combine(destFootageFolder, strFootageName).Replace("\\", "/"); Directory.CreateDirectory(destFootageFolder); //make sure the directory exists footageInfo.Folder = AssetUtility.NormalizeAssetPath(destFootageFolder); for (int i = 0; i < numImages; ++i) { string destFilePath = Path.Combine(destFootageFolder, footageInfo.Pictures[i]); if (File.Exists(destFilePath)) { File.Delete(destFilePath); } string srcFilePath = Path.GetFullPath(Path.Combine(assetFolder, originalImagePaths[i])).Replace("\\", "/"); FileUtil.CopyFileOrDirectory(srcFilePath, destFilePath); } } //Convert to WatchedFileInfo List <WatchedFileInfo> imageFiles = WatchedFileInfo.CreateList(footageInfo.Folder, footageInfo.Pictures); StreamingImageSequencePlayableAsset sisAsset = ScriptableObject.CreateInstance <StreamingImageSequencePlayableAsset>(); sisAsset.InitFolder(footageInfo.Folder, imageFiles, footageInfo.Resolution); string playableAssetPath = Path.Combine(timelineFolder, strFootageName + "_StreamingImageSequence.playable"); AssetEditorUtility.OverwriteAsset(sisAsset, playableAssetPath); StreamingImageSequenceTrack movieTrack = asset.CreateTrack <StreamingImageSequenceTrack>(null, strFootageName); TimelineClip clip = movieTrack.CreateDefaultClip(); clip.asset = sisAsset; clip.start = track.Start; clip.duration = track.Duration; clip.CreateCurves("Curves: " + clip.displayName); TimelineClipSISData sisData = new TimelineClipSISData(clip); sisAsset.InitTimelineClipCurve(clip); sisAsset.BindTimelineClipSISData(sisData); if (Object.FindObjectOfType(typeof(UnityEngine.EventSystems.EventSystem)) == null) { var es = new GameObject(); es.AddComponent <UnityEngine.EventSystems.EventSystem>(); es.AddComponent <UnityEngine.EventSystems.StandaloneInputModule>(); es.name = "EventSystem"; } GameObject canvasObj = null; Canvas canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas; if (canvas != null) { canvasObj = canvas.gameObject; } else { canvasObj = UIUtility.CreateCanvas().gameObject; } Transform directorT = director.gameObject.transform; directorT.SetParent(canvasObj.transform); directorT.localPosition = new Vector3(0.0f, 0.0f, 0.0f); GameObject imageGo = null; Transform imageT = directorT.Find(strFootageName); if (null == imageT) { imageGo = new GameObject(strFootageName); imageT = imageGo.transform; } else { imageGo = imageT.gameObject; } Image image = imageGo.GetOrAddComponent <Image>(); StreamingImageSequenceRenderer renderer = imageGo.GetOrAddComponent <StreamingImageSequenceRenderer>(); RectTransform rectTransform = imageGo.GetComponent <RectTransform>(); rectTransform.SetParent(directorT); rectTransform.localPosition = new Vector3(0.0f, 0.0f, 0.0f); rectTransform.sizeDelta = new Vector2(footageInfo.Resolution.Width, footageInfo.Resolution.Height); director.SetGenericBinding(movieTrack, renderer); EditorUtility.SetDirty(director); } //cause crash if this is called inside of OnImportAsset() UnityEditor.EditorApplication.delayCall += () => { AssetDatabase.Refresh(); if (null != director) { Selection.activeGameObject = director.gameObject; } }; }
public IEnumerator UncheckFrameMarkers() { PlayableDirector director = EditorUtilityTest.NewSceneWithDirector(); TimelineClip clip = EditorUtilityTest.CreateTestTimelineClip(director); StreamingImageSequencePlayableAsset sisAsset = clip.asset as StreamingImageSequencePlayableAsset; Assert.IsNotNull(sisAsset); TimelineClipSISData timelineClipSISData = sisAsset.GetBoundTimelineClipSISData(); timelineClipSISData.RequestFrameMarkers(true); yield return(null); double timePerFrame = TimelineUtility.CalculateTimePerFrame(clip); int numImages = sisAsset.GetImageFileNames().Count; clip.timeScale = 3.75f; //use scaling EditorUtilityTest.ResizeSISTimelineClip(clip, (timePerFrame * numImages)); yield return(null); int numFrames = TimelineUtility.CalculateNumFrames(clip); Assert.AreEqual(numImages, numFrames); //Reset: make sure that the curve is a simple straight line from 0 to 1 StreamingImageSequencePlayableAsset.ResetTimelineClipCurve(clip); yield return(null); sisAsset.ResetPlayableFrames(); yield return(null); StreamingImageSequenceTrack track = clip.parentTrack as StreamingImageSequenceTrack; Assert.IsNotNull(track); List <FrameMarker> frameMarkers = new List <FrameMarker>(); int i = 0; foreach (var m in track.GetMarkers()) { FrameMarker marker = m as FrameMarker; Assert.IsNotNull(marker); frameMarkers.Add(marker); int imageIndex = sisAsset.GlobalTimeToImageIndex(clip, marker.time); Assert.AreEqual(i, imageIndex); ++i; } //Uncheck and see if the unchecked images became ignored frameMarkers[4].SetFrameUsed(false); frameMarkers[5].SetFrameUsed(false); Assert.AreEqual(3, sisAsset.GlobalTimeToImageIndex(clip, frameMarkers[4].time)); Assert.AreEqual(3, sisAsset.GlobalTimeToImageIndex(clip, frameMarkers[5].time)); frameMarkers[7].SetFrameUsed(false); frameMarkers[8].SetFrameUsed(false); Assert.AreEqual(6, sisAsset.GlobalTimeToImageIndex(clip, frameMarkers[7].time)); Assert.AreEqual(6, sisAsset.GlobalTimeToImageIndex(clip, frameMarkers[8].time)); EditorUtilityTest.DestroyTestTimelineAssets(clip); yield return(null); }
//---------------------------------------------------------------------------------------------------------------------- internal static IEnumerator UpdateRenderCacheCoroutine(PlayableDirector director, RenderCachePlayableAsset renderCachePlayableAsset) { Assert.IsNotNull(director); Assert.IsNotNull(renderCachePlayableAsset); TimelineClipSISData timelineClipSISData = renderCachePlayableAsset.GetBoundTimelineClipSISData(); if (null == timelineClipSISData) { EditorUtility.DisplayDialog("Streaming Image Sequence", "RenderCachePlayableAsset is not ready", "Ok"); yield break; } TrackAsset track = renderCachePlayableAsset.GetBoundTimelineClipSISData().GetOwner().parentTrack; BaseRenderCapturer renderCapturer = director.GetGenericBinding(track) as BaseRenderCapturer; if (null == renderCapturer) { EditorUtility.DisplayDialog("Streaming Image Sequence", "Please bind an appropriate RenderCapturer component to the track.", "Ok"); yield break; } //Check output folder string outputFolder = renderCachePlayableAsset.GetFolder(); if (string.IsNullOrEmpty(outputFolder) || !Directory.Exists(outputFolder)) { EditorUtility.DisplayDialog("Streaming Image Sequence", "Invalid output folder", "Ok"); yield break; } //Check if we can capture bool canCapture = renderCapturer.CanCapture(); if (!canCapture) { EditorUtility.DisplayDialog("Streaming Image Sequence", renderCapturer.GetLastErrorMessage(), "Ok"); yield break; } //begin capture IEnumerator beginCapture = renderCapturer.BeginCapture(); while (beginCapture.MoveNext()) { yield return(beginCapture.Current); } //Show progress in game view Texture capturerTex = renderCapturer.GetInternalTexture(); RenderCachePlayableAssetEditorConfig editorConfig = renderCachePlayableAsset.GetEditorConfig(); GameObject blitterGO = CreateBlitter(capturerTex, editorConfig.GetUpdateBGColor()); TimelineClip timelineClip = timelineClipSISData.GetOwner(); double timePerFrame = 1.0f / track.timelineAsset.editorSettings.fps; //initial calculation of loop vars bool captureAllFrames = editorConfig.GetCaptureAllFrames(); int fileCounter = 0; int numFiles = (int)Math.Ceiling(timelineClip.duration / timePerFrame) + 1; int numDigits = MathUtility.GetNumDigits(numFiles); if (!captureAllFrames) { fileCounter = editorConfig.GetCaptureStartFrame(); numFiles = (editorConfig.GetCaptureEndFrame() - fileCounter) + 1; if (numFiles <= 0) { EditorUtility.DisplayDialog("Streaming Image Sequence", "Invalid Start/End Frame Settings", "Ok"); yield break; } } int captureStartFrame = fileCounter; string prefix = $"{timelineClip.displayName}_"; List <WatchedFileInfo> imageFiles = new List <WatchedFileInfo>(numFiles); //Store old files that has the same pattern string[] existingFiles = Directory.GetFiles(outputFolder, $"*.png"); HashSet <string> filesToDelete = new HashSet <string>(existingFiles); bool cancelled = false; while (!cancelled) { //Always recalculate from start to avoid floating point errors double directorTime = timelineClip.start + (fileCounter * timePerFrame); if (directorTime > timelineClip.end) { break; } if (!captureAllFrames && fileCounter > editorConfig.GetCaptureEndFrame()) { break; } string fileName = $"{prefix}{fileCounter.ToString($"D{numDigits}")}.png"; string outputFilePath = Path.Combine(outputFolder, fileName); SISPlayableFrame playableFrame = timelineClipSISData.GetPlayableFrame(fileCounter); bool captureFrame = (!timelineClipSISData.AreFrameMarkersRequested() || //if markers are not requested, capture !File.Exists(outputFilePath) || //if file doesn't exist, capture (null != playableFrame && playableFrame.IsUsed() && !playableFrame.IsLocked()) ); if (filesToDelete.Contains(outputFilePath)) { filesToDelete.Remove(outputFilePath); } if (captureFrame) { SetDirectorTime(director, directorTime); //Need at least two frames in order to wait for the TimelineWindow to be updated ? yield return(null); yield return(null); yield return(null); //Unload texture because it may be overwritten StreamingImageSequencePlugin.UnloadImageAndNotify(outputFilePath); renderCapturer.CaptureToFile(outputFilePath); } Assert.IsTrue(File.Exists(outputFilePath)); FileInfo fileInfo = new FileInfo(outputFilePath); imageFiles.Add(new WatchedFileInfo(fileName, fileInfo.Length)); ++fileCounter; cancelled = EditorUtility.DisplayCancelableProgressBar( "StreamingImageSequence", "Caching render results", ((float)(fileCounter - captureStartFrame) / numFiles)); } if (!cancelled) { renderCachePlayableAsset.SetImageFiles(imageFiles); //Delete old files if (AssetDatabase.IsValidFolder(outputFolder)) { foreach (string oldFile in filesToDelete) { AssetDatabase.DeleteAsset(oldFile); } } else { foreach (string oldFile in filesToDelete) { File.Delete(oldFile); } } } //Notify FolderContentsChangedNotifier.GetInstance().Notify(outputFolder); //Cleanup EditorUtility.ClearProgressBar(); renderCapturer.EndCapture(); ObjectUtility.Destroy(blitterGO); AssetDatabase.Refresh(); yield return(null); }