//---------------------------------------------------------------------------------------------------------------------- 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(); } }
//---------------------------------------------------------------------------------------------------------------------- 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); }
//---------------------------------------------------------------------------------------------------------------------- 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); }