diff --git a/README.md b/README.md index 74bd116..6e78aa5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Frame Recorder +# Unity Recorder ### Brief -The *Frame Recorder* is a project that facilitates recording of Unity artifacts from Unity. The framework does not define what can be recorded, but defines a standard way of how to implement and setup a recorder and takes care of aspects common to all recorders (time managenent, Timeline integration, record windows, etc). +The *Recorder* is a project that facilitates recording of Unity artifacts from Unity. The framework does not define what can be recorded, but defines a standard way of how to implement and setup a recorder and takes care of aspects common to all recorders (time managenent, Timeline integration, record windows, etc). Extensibility is a prim concideration and since not all use cases can be thought of in advance, whenever relevant, the framework's base classes strive to offer an easy way to override the default beahviour of the system. @@ -10,6 +10,9 @@ A key consideration is providing a uniform UX. By defining a standard pattern an Code reusability and easy of use for developers is also a prime consideration. As much as possible, modularization in a Lego mentality is promoted so that work done for one specific recorder, say MP4 recording, can be reused by an other type of recorder, say PNG or WAV recorders. +### +Found a bug? Let us know and [post an issue](https://github.com/Unity-Technologies/GenericFrameRecorder/issues). + ### Current limitations * Recorders are Player standalone friendly, but not the editors. * Framerate is set at the Recorder level which makes for potential conflict when multiple recorders are active simultaneously. @@ -32,8 +35,8 @@ Note that this can be done from edit mode and from game mode... ### From a timeline track 1. Create a timeline asset and add it to the scene. -2. Add a "Frame Recorder track" to the timeline. -3. Add a "Frame Recorder clip" to the track. +2. Add a "Recorder track" to the timeline. +3. Add a "Recorder clip" to the track. 4. Select the newly added slip ![](docs/images/TimelineTrack.png) diff --git a/issue_template.md b/issue_template.md new file mode 100644 index 0000000..955e9d6 --- /dev/null +++ b/issue_template.md @@ -0,0 +1,7 @@ +##### What happened? + +##### Is it reproduceable? + +##### Released package version / tag? + +##### Unity version, operating system, target platform (standalone windows, mac, iOS, PS4...)? \ No newline at end of file diff --git a/issue_template.md.meta b/issue_template.md.meta new file mode 100644 index 0000000..29fceeb --- /dev/null +++ b/issue_template.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08b73bf0f58e24b4a9fa26c8d0f528c5 +timeCreated: 1504627508 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/license b/license new file mode 100644 index 0000000..e81e76c --- /dev/null +++ b/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2017, Unity Technologies + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/license.meta b/license.meta new file mode 100644 index 0000000..6d894f1 --- /dev/null +++ b/license.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d1ee2a4fdbf74a53b086f78d6d07db7 +timeCreated: 1504627508 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Editor/AboutBox.cs b/source/FrameRecorder/Core/Editor/AboutBox.cs new file mode 100644 index 0000000..77bfe25 --- /dev/null +++ b/source/FrameRecorder/Core/Editor/AboutBox.cs @@ -0,0 +1,68 @@ +using System; +using UnityEngine; + +namespace UnityEditor.FrameRecorder +{ + public class AboutBox : EditorWindow + { + [MenuItem("Tools/Recorder/About...", false, Int32.MinValue)] + public static void ShowAboutBox() + { + EditorWindow.GetWindowWithRect(new Rect(100, 100, 550, 310), true, "About Recorder"); + } + + GUIContent s_Header; + + void OnEnable() + { + s_Header = EditorGUIUtility.IconContent("AboutWindow.MainHeader"); + } + + public void OnGUI() + { + GUILayout.Space(10); + GUILayout.BeginHorizontal(); + GUILayout.Space(5); + GUILayout.BeginVertical(); + GUILayout.Label(s_Header, GUIStyle.none); + + GUILayout.BeginHorizontal(); + GUILayout.Space(52f); + GUILayout.Label("Recorder " + RecorderVersion.Stage, EditorStyles.boldLabel); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Space(52f); + GUILayout.Label(string.Format("Version {0}", RecorderVersion.Version)); + GUILayout.EndHorizontal(); + GUILayout.Space(4); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + + var text = "The Unity Recorder package is a collection of Recorders that allow in-game capturing of data and saving it. For example; generate an mp4 file from a game session.\r\n\r\nIn support to the recorders, it provides a graphical interface that is used to manually trigger recording sessions, which take care of: entering play mode, recording requested data and exiting play mode when done. It also supports triggering recording sessions from user scripts and timeline tracks.\r\n\r\nThe Recorder is aimed at extensibility and is implemented as a plugin system, where anyone can create new recorders and have them seamlessly integrate into the Unity Recorder ecosystem, while maximizing code reuse."; + + float textWidth = position.width - 10; + float textHeight = EditorStyles.wordWrappedLabel.CalcHeight(new GUIContent(text), textWidth); + Rect creditsNamesRect = new Rect(5, 120, textWidth, textHeight); + GUI.Label(creditsNamesRect, text, EditorStyles.wordWrappedLabel); + GUILayout.Space(25); + GUILayout.Space(textHeight); + GUILayout.BeginHorizontal(); + if (GUILayout.Button("View user manual")) + { + var file = FRPackagerPaths.GetFrameRecorderPath() + "/Recorder_install.pdf"; + Debug.Log(file); + Application.OpenURL(file); + this.Close(); + } + GUILayout.Space(25); + if (GUILayout.Button("Want to write a recorder?")) + { + Application.OpenURL("https://github.com/Unity-Technologies/GenericFrameRecorder/blob/master/README.md"); + this.Close(); + } + GUILayout.EndHorizontal(); + + } + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Core/Editor/AboutBox.cs.meta b/source/FrameRecorder/Core/Editor/AboutBox.cs.meta new file mode 100644 index 0000000..98209ca --- /dev/null +++ b/source/FrameRecorder/Core/Editor/AboutBox.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7a5ee59e307671242998d2b49bb809e3 +timeCreated: 1504289434 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Editor/InputEditor.cs b/source/FrameRecorder/Core/Editor/InputEditor.cs index c83d7b8..9a87e2f 100644 --- a/source/FrameRecorder/Core/Editor/InputEditor.cs +++ b/source/FrameRecorder/Core/Editor/InputEditor.cs @@ -6,11 +6,12 @@ namespace UnityEditor.FrameRecorder { public delegate EFieldDisplayState IsFieldAvailableDelegate(SerializedProperty property); - public IsFieldAvailableDelegate IsFieldAvailableForHost { get; set; } + public IsFieldAvailableDelegate isFieldAvailableForHost { get; set; } protected virtual void AddProperty(SerializedProperty prop, Action action ) { - var state = IsFieldAvailableForHost(prop); + var state = isFieldAvailableForHost == null ? EFieldDisplayState.Disabled : isFieldAvailableForHost(prop); + if (state == EFieldDisplayState.Enabled) state = IsFieldAvailable(prop); if (state != EFieldDisplayState.Hidden) diff --git a/source/FrameRecorder/Core/Editor/RecorderEditor.cs b/source/FrameRecorder/Core/Editor/RecorderEditor.cs index f008d8c..eecd798 100644 --- a/source/FrameRecorder/Core/Editor/RecorderEditor.cs +++ b/source/FrameRecorder/Core/Editor/RecorderEditor.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using UnityEngine.FrameRecorder; +using UnityEngine.SceneManagement; namespace UnityEditor.FrameRecorder { @@ -32,7 +34,7 @@ namespace UnityEditor.FrameRecorder editor = Editor.CreateEditor(m_SettingsObj); if (editor is InputEditor) - (editor as InputEditor).IsFieldAvailableForHost = m_Validator; + (editor as InputEditor).isFieldAvailableForHost = m_Validator; } } @@ -44,9 +46,8 @@ namespace UnityEditor.FrameRecorder } protected List m_InputEditors; - protected SerializedProperty m_Inputs; + //protected SerializedProperty m_Inputs; - SerializedProperty m_Verbose; SerializedProperty m_FrameRateMode; SerializedProperty m_FrameRate; SerializedProperty m_DurationMode; @@ -71,8 +72,6 @@ namespace UnityEditor.FrameRecorder m_FrameRateLabels = EnumHelper.MaskOutEnumNames(0xFFFF, (x) => FrameRateHelper.ToLable( (EFrameRate)x) ); var pf = new PropertyFinder(serializedObject); - m_Inputs = pf.Find(x => x.m_SourceSettings); - m_Verbose = pf.Find(x => x.m_Verbose); m_FrameRateMode = pf.Find(x => x.m_FrameRateMode); m_FrameRate = pf.Find(x => x.m_FrameRate); m_DurationMode = pf.Find(x => x.m_DurationMode); @@ -86,20 +85,34 @@ namespace UnityEditor.FrameRecorder m_DestinationPath = pf.Find(w => w.m_DestinationPath); m_BaseFileName = pf.Find(w => w.m_BaseFileName); - foreach (var input in (target as RecorderSettings).m_SourceSettings) - { - m_InputEditors.Add( new InputEditorState(GetFieldDisplayState, input) { visible = true} ); - } + BuildInputEditors(); } } + void BuildInputEditors() + { + var rs = target as RecorderSettings; + if (!rs.inputsSettings.hasBrokenBindings && rs.inputsSettings.Count == m_InputEditors.Count) + return; + + if (rs.inputsSettings.hasBrokenBindings) + rs.BindSceneInputSettings(); + + foreach (var editor in m_InputEditors) + UnityHelpers.Destroy(editor.editor); + m_InputEditors.Clear(); + + foreach (var input in rs.inputsSettings) + m_InputEditors.Add( new InputEditorState(GetFieldDisplayState, input) { visible = true} ); + } + protected virtual void OnDisable() {} protected virtual void Awake() {} public bool isValid { - get { return (target as RecorderSettings).isValid; } + get { return (target as RecorderSettings).isValid && (target as RecorderSettings).isPlatformSupported; } } public bool showBounds { get; set; } @@ -114,44 +127,51 @@ namespace UnityEditor.FrameRecorder if (target == null) return; + + + + BuildInputEditors(); + EditorGUI.BeginChangeCheck(); serializedObject.Update(); OnInputGroupGui(); OnOutputGroupGui(); OnEncodingGroupGui(); - OnTimeGroupGui(); + OnFrameRateGroupGui(); OnBoundsGroupGui(); OnExtraGroupsGui(); - EditorGUILayout.PropertyField( m_Verbose, new GUIContent( "Verbose logging" ) ); + RecorderSettings.m_Verbose = EditorGUILayout.Toggle( "Verbose logging", RecorderSettings.m_Verbose ); serializedObject.ApplyModifiedProperties(); EditorGUI.EndChangeCheck(); + + + if (!(target as RecorderSettings).isValid) + { + EditorGUILayout.HelpBox("Incomplete/Invalid settings", MessageType.Warning); + } + + if (!(target as RecorderSettings).isPlatformSupported) + { + EditorGUILayout.HelpBox("Current platform is not supported", MessageType.Warning); + } } - protected void AddSourceSettings(RecorderInputSetting sourceSettings) + protected void AddInputSettings(RecorderInputSetting inputSettings) { - m_Inputs.InsertArrayElementAtIndex(m_Inputs.arraySize); - var arryItem = m_Inputs.GetArrayElementAtIndex(m_Inputs.arraySize-1); - arryItem.objectReferenceValue = sourceSettings; - - m_InputEditors.Add( new InputEditorState(GetFieldDisplayState, sourceSettings) { visible = true} ); - - serializedObject.ApplyModifiedProperties(); + var inputs = (target as RecorderSettings).inputsSettings; + inputs.Add(inputSettings); + m_InputEditors.Add( new InputEditorState(GetFieldDisplayState, inputSettings) { visible = true} ); } public void ChangeInputSettings(int atIndex, RecorderInputSetting newSettings) { if (newSettings != null) { - AssetDatabase.AddObjectToAsset(newSettings, serializedObject.targetObject); - AssetDatabase.Refresh(); - - var arryItem = m_Inputs.GetArrayElementAtIndex(atIndex); - UnityHelpers.Destroy(arryItem.objectReferenceValue, true); - arryItem.objectReferenceValue = newSettings; - + var inputs = (target as RecorderSettings).inputsSettings; + inputs.ReplaceAt(atIndex, newSettings); m_InputEditors[atIndex].settingsObj = newSettings; } else if(m_InputEditors.Count == 0) @@ -162,8 +182,10 @@ namespace UnityEditor.FrameRecorder protected virtual void OnInputGui() { - bool multiInputs = m_Inputs.arraySize > 1; - for( int i = 0; i < m_Inputs.arraySize; i++) + var inputs = (target as RecorderSettings).inputsSettings; + + bool multiInputs = inputs.Count > 1; + for( int i = 0; i < inputs.Count; i++) { if (multiInputs) { @@ -196,10 +218,10 @@ namespace UnityEditor.FrameRecorder // place holder } - protected virtual void OnTimeGui() + protected virtual void OnFrameRateGui() { - AddProperty( m_FrameRateMode, () => EditorGUILayout.PropertyField(m_FrameRateMode, new GUIContent("Frame rate mode"))); + AddProperty( m_FrameRateMode, () => EditorGUILayout.PropertyField(m_FrameRateMode, new GUIContent("Constraint Type"))); AddProperty( m_FrameRateExact, () => { @@ -235,9 +257,9 @@ namespace UnityEditor.FrameRecorder }); } - protected virtual void OnBounds() + protected virtual void OnBoundsGui() { - EditorGUILayout.PropertyField(m_DurationMode, new GUIContent("Recording Duration")); + EditorGUILayout.PropertyField(m_DurationMode, new GUIContent("Mode")); ++EditorGUI.indentLevel; switch ((DurationMode)m_DurationMode.intValue) @@ -304,13 +326,13 @@ namespace UnityEditor.FrameRecorder } } - protected virtual void OnTimeGroupGui() + protected virtual void OnFrameRateGroupGui() { - m_FoldoutTime = EditorGUILayout.Foldout(m_FoldoutTime, "Time"); + m_FoldoutTime = EditorGUILayout.Foldout(m_FoldoutTime, "Frame rate"); if (m_FoldoutTime) { ++EditorGUI.indentLevel; - OnTimeGui(); + OnFrameRateGui(); --EditorGUI.indentLevel; } } @@ -323,7 +345,7 @@ namespace UnityEditor.FrameRecorder if (m_FoldoutBounds) { ++EditorGUI.indentLevel; - OnBounds(); + OnBoundsGui(); --EditorGUI.indentLevel; } } diff --git a/source/FrameRecorder/Core/Editor/RecorderSelector.cs b/source/FrameRecorder/Core/Editor/RecorderSelector.cs index 7652e19..4b2ff16 100644 --- a/source/FrameRecorder/Core/Editor/RecorderSelector.cs +++ b/source/FrameRecorder/Core/Editor/RecorderSelector.cs @@ -38,7 +38,8 @@ namespace UnityEditor.FrameRecorder if (string.Compare(recInfo.category, startingCategory, StringComparison.InvariantCultureIgnoreCase) != 0) { // forced another category, flush existing settings obj. - SelectRecorder(null); + SetCategory(startingCategory); + SelectRecorder( GetRecorderFromIndex(0) ); } } @@ -50,8 +51,8 @@ namespace UnityEditor.FrameRecorder return; } } - - SetCategory(string.Empty); + else + SetCategory(startingCategory); } int GetCategoryIndex() diff --git a/source/FrameRecorder/Core/Editor/RecorderWindow.cs b/source/FrameRecorder/Core/Editor/RecorderWindow.cs index e6e484b..ee2821d 100644 --- a/source/FrameRecorder/Core/Editor/RecorderWindow.cs +++ b/source/FrameRecorder/Core/Editor/RecorderWindow.cs @@ -26,7 +26,10 @@ namespace UnityEditor.FrameRecorder var window = GetWindow(typeof(RecorderWindow), false, "Recorder") as RecorderWindow; if (RecordersInventory.recordersByCategory.ContainsKey(category)) + { window.m_StartingCategory = category; + window.m_recorderSelector = null; + } } public void OnEnable() @@ -44,7 +47,6 @@ namespace UnityEditor.FrameRecorder } } - Vector2 m_ScrollPos; public void OnGUI() @@ -77,7 +79,8 @@ namespace UnityEditor.FrameRecorder else { m_WindowSettingsAsset = ScriptableObject.CreateInstance(); - AssetDatabase.CreateAsset(m_WindowSettingsAsset, "Assets/FrameRecordingSettings.asset"); + //System.IO.Directory.CreateDirectory(FRPackagerPaths.GetFrameRecorderRootPath()); + AssetDatabase.CreateAsset(m_WindowSettingsAsset, FRPackagerPaths.GetFrameRecorderRootPath() + "/RecorderWindowSettings.asset"); AssetDatabase.Refresh(); } } @@ -109,19 +112,22 @@ namespace UnityEditor.FrameRecorder { EditorGUILayout.EndScrollView(); } + } + catch (ExitGUIException) + { + } catch (Exception ex) { if (m_State == EState.Recording) + { try { Debug.LogError("Aborting recording due to an exception!\n" + ex.ToString()); StopRecording(); } - catch (Exception) - { - - } + catch (Exception) {} + } Debug.LogException(ex); } } @@ -142,7 +148,7 @@ namespace UnityEditor.FrameRecorder { case EState.Idle: { - using (new EditorGUI.DisabledScope(!m_Editor.isValid)) + using (new EditorGUI.DisabledScope(!m_Editor.isValid )) { if (GUILayout.Button("Start Recording")) StartRecording(); @@ -158,7 +164,7 @@ namespace UnityEditor.FrameRecorder case EState.Recording: { - var recorderGO = FrameRecorderGOControler.FindRecorder((RecorderSettings)m_Editor.target); + var recorderGO = SceneHook.FindRecorder((RecorderSettings)m_Editor.target); if (recorderGO == null) { GUILayout.Button("Start Recording"); // just to keep the ui system happy. @@ -235,7 +241,7 @@ namespace UnityEditor.FrameRecorder void StartRecording(bool autoExitPlayMode) { var settings = (RecorderSettings)m_Editor.target; - var go = FrameRecorderGOControler.HookupRecorder(!settings.m_Verbose); + var go = SceneHook.HookupRecorder(); var session = new RecordingSession() { m_Recorder = RecordersInventory.GenerateNewRecorder(m_recorderSelector.selectedRecorder, settings), @@ -262,7 +268,7 @@ namespace UnityEditor.FrameRecorder var settings = (RecorderSettings)m_Editor.target; if (settings != null) { - var recorderGO = FrameRecorderGOControler.FindRecorder(settings); + var recorderGO = SceneHook.FindRecorder(settings); if (recorderGO != null) { UnityHelpers.Destroy(recorderGO); @@ -289,7 +295,7 @@ namespace UnityEditor.FrameRecorder } if( m_WindowSettingsAsset.m_Settings == null ) - m_WindowSettingsAsset.m_Settings = RecordersInventory.GenerateNewSettingsAsset(m_WindowSettingsAsset, m_recorderSelector.selectedRecorder ); + m_WindowSettingsAsset.m_Settings = RecordersInventory.GenerateRecorderInitialSettings(m_WindowSettingsAsset, m_recorderSelector.selectedRecorder ); m_Editor = Editor.CreateEditor( m_WindowSettingsAsset.m_Settings ) as RecorderEditor; AssetDatabase.Refresh(); diff --git a/source/FrameRecorder/Core/Editor/SerializableObjHelper.cs b/source/FrameRecorder/Core/Editor/SerializableObjHelper.cs index f93bbb4..655f2fd 100644 --- a/source/FrameRecorder/Core/Editor/SerializableObjHelper.cs +++ b/source/FrameRecorder/Core/Editor/SerializableObjHelper.cs @@ -57,6 +57,31 @@ namespace UnityEditor.FrameRecorder } } + public class StructPropertyFinder where TType : struct + { + SerializedObject m_Obj; + public StructPropertyFinder(SerializedObject obj) + { + m_Obj = obj; + } + + public delegate TResult FuncX(TType x); + public SerializedProperty Find( Expression> exp) + { + var body = exp.Body as MemberExpression; + if (body == null) + { + var ubody = (UnaryExpression)exp.Body; + body = ubody.Operand as MemberExpression; + } + + var name = body.Member.Name; + + return m_Obj.FindProperty(name); + } + + } + public class PropertyFinder where TType : class { SerializedObject m_Obj; diff --git a/source/FrameRecorder/Core/Editor/Timeline/RecorderClipEditor.cs b/source/FrameRecorder/Core/Editor/Timeline/RecorderClipEditor.cs index 5395c71..fb826ef 100644 --- a/source/FrameRecorder/Core/Editor/Timeline/RecorderClipEditor.cs +++ b/source/FrameRecorder/Core/Editor/Timeline/RecorderClipEditor.cs @@ -4,7 +4,7 @@ using UnityEngine.Timeline; namespace UnityEditor.FrameRecorder.Timeline { - [CustomEditor(typeof(FrameRecorderClip), true)] + [CustomEditor(typeof(RecorderClip), true)] public class RecorderClipEditor : Editor { RecorderEditor m_Editor; @@ -32,7 +32,7 @@ namespace UnityEditor.FrameRecorder.Timeline if (m_recorderSelector == null) { m_recorderSelector = new RecorderSelector( OnRecorderSelected, false ); - m_recorderSelector.Init((target as FrameRecorderClip).m_Settings); + m_recorderSelector.Init((target as RecorderClip).m_Settings); } m_recorderSelector.OnGui(); @@ -61,7 +61,7 @@ namespace UnityEditor.FrameRecorder.Timeline public void OnRecorderSelected() { - var clip = this.target as FrameRecorderClip; + var clip = this.target as RecorderClip; if (m_Editor != null) { @@ -79,7 +79,7 @@ namespace UnityEditor.FrameRecorder.Timeline } if(clip.m_Settings == null) - clip.m_Settings = RecordersInventory.GenerateNewSettingsAsset(clip, m_recorderSelector.selectedRecorder ); + clip.m_Settings = RecordersInventory.GenerateRecorderInitialSettings(clip, m_recorderSelector.selectedRecorder ); m_Editor = Editor.CreateEditor(clip.m_Settings) as RecorderEditor; AssetDatabase.Refresh(); } diff --git a/source/FrameRecorder/Core/Engine/FrameRateHelper.cs b/source/FrameRecorder/Core/Engine/FrameRateHelper.cs index 10fe17e..055b287 100644 --- a/source/FrameRecorder/Core/Engine/FrameRateHelper.cs +++ b/source/FrameRecorder/Core/Engine/FrameRateHelper.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace UnityEngine.FrameRecorder { diff --git a/source/FrameRecorder/Core/Engine/FrameRecorderAttribute.cs b/source/FrameRecorder/Core/Engine/FrameRecorderAttribute.cs index 8cd2fb6..c50c9b9 100644 --- a/source/FrameRecorder/Core/Engine/FrameRecorderAttribute.cs +++ b/source/FrameRecorder/Core/Engine/FrameRecorderAttribute.cs @@ -22,4 +22,17 @@ namespace UnityEngine.FrameRecorder } } + /// + /// What is this: Indicate that a Input settings instance is scene specific and should not be shared accross scenes (not in a project wide asset) + /// Motivation : Some input settings target specific scenes, for example target a game object in the scene. Having the settings be stored in the + /// scene simplifies referencing. + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class StoreInSceneAttribute : Attribute + { + public StoreInSceneAttribute() + { + } + } + } diff --git a/source/FrameRecorder/Core/Engine/FrameRecorderGOControler.cs b/source/FrameRecorder/Core/Engine/FrameRecorderGOControler.cs deleted file mode 100644 index fb9e0c7..0000000 --- a/source/FrameRecorder/Core/Engine/FrameRecorderGOControler.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; - -namespace UnityEngine.FrameRecorder -{ - - /// - /// What is this: - /// Motivation : - /// Notes: - /// - public class FrameRecorderGOControler - { - const string k_HostGoName = "UnityEngine-Recorder-FrameRecorder"; - - static GameObject GetGameObject(bool createIfAbsent, bool hide) - { - var go = GameObject.Find(k_HostGoName); - if (go == null && createIfAbsent) - { - go = new GameObject(k_HostGoName); - if (hide) - go.hideFlags = HideFlags.HideInHierarchy; - } - - return go; - } - - static GameObject GetRecordingSessionsRoot(bool createIfAbsent, bool hideGameObjects) - { - var root = GetGameObject(createIfAbsent, hideGameObjects); - if (root == null) - return null; - - var settingsTr = root.transform.Find("RecordingSessions"); - GameObject settingsGO; - if (settingsTr == null) - { - settingsGO = new GameObject("RecordingSessions"); - settingsGO.transform.parent = root.transform; - } - else - settingsGO = settingsTr.gameObject; - - return settingsGO; - } - - public static GameObject HookupRecorder(bool hideGameObjects) - { - var ctrl = GetRecordingSessionsRoot(true, hideGameObjects); - - var recorderGO = new GameObject(); - - recorderGO.transform.parent = ctrl.transform; - - return recorderGO; - } - - public static GameObject FindRecorder(RecorderSettings settings) - { - var ctrl = GetRecordingSessionsRoot(false, false); - if (ctrl == null) - return null; - - for (int i = 0; i < ctrl.transform.childCount; i++) - { - var child = ctrl.transform.GetChild(i); - var settingsHost = child.GetComponent(); - if (settingsHost != null && settingsHost.session != null && settingsHost.session.settings == settings) - return settingsHost.gameObject; - } - - return null; - } - } -} diff --git a/source/FrameRecorder/Core/Engine/ImageRecorderSettings.cs b/source/FrameRecorder/Core/Engine/ImageRecorderSettings.cs index 4a01249..2ad8ae2 100644 --- a/source/FrameRecorder/Core/Engine/ImageRecorderSettings.cs +++ b/source/FrameRecorder/Core/Engine/ImageRecorderSettings.cs @@ -13,7 +13,7 @@ namespace UnityEngine.FrameRecorder public enum EImageDimension { - x8640p_16K = 8640, + //x8640p_16K = 8640, x4320p_8K = 4320, x2880p_5K = 2880, x2160p_4K = 2160, diff --git a/source/FrameRecorder/Core/Engine/InputBinder.cs b/source/FrameRecorder/Core/Engine/InputBinder.cs new file mode 100644 index 0000000..f52f037 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputBinder.cs @@ -0,0 +1,19 @@ +using System; + +namespace UnityEngine.FrameRecorder +{ + public class InputBinder : RecorderInputSetting + { + public string m_TypeName; + public override Type inputType + { + get { return Type.GetType(m_TypeName); } + } + + public override bool isValid + { + get { return false; } + } + + } +} diff --git a/source/FrameRecorder/Core/Engine/InputBinder.cs.meta b/source/FrameRecorder/Core/Engine/InputBinder.cs.meta new file mode 100644 index 0000000..814b8fb --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputBinder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cbfd129ef371e0b468332962917d1a8b +timeCreated: 1504708921 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Engine/InputSettings.cs b/source/FrameRecorder/Core/Engine/InputSettings.cs index 62477cd..a8bdb71 100644 --- a/source/FrameRecorder/Core/Engine/InputSettings.cs +++ b/source/FrameRecorder/Core/Engine/InputSettings.cs @@ -1,4 +1,5 @@ using System; +using UnityEditor; namespace UnityEngine.FrameRecorder { @@ -12,6 +13,18 @@ namespace UnityEngine.FrameRecorder public abstract Type inputType { get; } public abstract bool isValid { get; } public string m_DisplayName; + public string m_Id; + + protected virtual void OnEnable() + { + if (string.IsNullOrEmpty(m_Id)) + m_Id = Guid.NewGuid().ToString(); + } + + public bool storeInScene + { + get { return Attribute.GetCustomAttribute(GetType(), typeof(StoreInSceneAttribute)) != null; } + } } /// diff --git a/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs b/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs new file mode 100644 index 0000000..be8f10e --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEngine.FrameRecorder +{ + public class InputSettingsComponent : MonoBehaviour + { + public List m_Settings; + } +} + \ No newline at end of file diff --git a/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs.meta b/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs.meta new file mode 100644 index 0000000..37c3f32 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputSettingsComponent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 393ba449d1ca2d84ead6595000d41c14 +timeCreated: 1504640541 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Engine/InputSettingsList.cs b/source/FrameRecorder/Core/Engine/InputSettingsList.cs new file mode 100644 index 0000000..a3ea964 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputSettingsList.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +namespace UnityEngine.FrameRecorder +{ + [Serializable] + public class InputSettingsList : IEnumerable + { + [SerializeField] + List m_InputsSettingsAssets; + List m_InputsSettings; + public string m_ParentAssetId; + + public void OnEnable( string parentAssetId ) + { + m_ParentAssetId = parentAssetId; + Reset(); + } + + public void Reset() + { + if(m_InputsSettingsAssets == null) + m_InputsSettingsAssets = new List(); + + Rebuild(); + } + + public void Rebuild() + { + m_InputsSettings = new List(); + + foreach (var inputAsset in m_InputsSettingsAssets) + { + var ib = inputAsset as InputBinder; + if (ib != null) + { + var sceneInputs = SceneHook.GetInputsComponent(m_ParentAssetId); + foreach (var input in sceneInputs.m_Settings) + { + if (input.m_Id == inputAsset.m_Id) + { + m_InputsSettings.Add(input); + break; + } + } + } + else + m_InputsSettings.Add(inputAsset); + } + } + + public bool isValid + { + get + { + foreach( var x in m_InputsSettings ) + if (!x.isValid) + return false; + return true; + } + } + + public bool hasBrokenBindings + { + get + { + foreach( var x in m_InputsSettings.ToList() ) + if (x == null || x is InputBinder) + return true; + return false; + } + } + + public RecorderInputSetting this [int index] + { + get + { + return m_InputsSettings[index]; + } + + set + { + ReplaceAt(index, value); + } + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)m_InputsSettings).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void AddRange(List list) + { + foreach (var value in list) + Add(value); + } + + public void Add(RecorderInputSetting input) + { + m_InputsSettings.Add(null); + m_InputsSettingsAssets.Add(null); + ReplaceAt(m_InputsSettings.Count - 1, input); + } + + public int Count + { + get + { + return m_InputsSettings.Count; + } + } + + public void Rebind(RecorderInputSetting input) + { + if (input is InputBinder) + { + Debug.LogError("Cannot bind a InputBinder object!"); + return; + } + + for (int i = 0; i < m_InputsSettings.Count; i++) + { + var x = m_InputsSettings[i]; + var ib = x as InputBinder; + if ( ib != null && ib.m_Id == input.m_Id) + { + m_InputsSettings[i] = input; + return; + } + } + } + + public void Remove(RecorderInputSetting input) + { + for (int i = 0; i < m_InputsSettings.Count; i++) + { + if (m_InputsSettings[i] == input) + { + ReleaseAt(i); + m_InputsSettings.RemoveAt(i); + m_InputsSettingsAssets.RemoveAt(i); + } + } + } + + public void ReplaceAt(int index, RecorderInputSetting input) + { + if (m_InputsSettingsAssets == null || m_InputsSettings.Count <= index) + throw new ArgumentException("Index out of range"); + + // Release input + ReleaseAt(index); + + m_InputsSettings[index] = input; + if (input.storeInScene) + { + var binder = ScriptableObject.CreateInstance(); + binder.name = "Scene-Stored"; + binder.m_DisplayName = input.m_DisplayName; + binder.m_TypeName = input.GetType().AssemblyQualifiedName; + binder.m_Id = input.m_Id; + m_InputsSettingsAssets[index] = binder; + SceneHook.RegisterInputSettingObj(m_ParentAssetId, input); + +#if UNITY_EDITOR + var assetPath = AssetDatabase.GUIDToAssetPath(m_ParentAssetId); + AssetDatabase.AddObjectToAsset(binder, assetPath); + AssetDatabase.SaveAssets(); +#endif + + } + else + { + m_InputsSettingsAssets[index] = input; +#if UNITY_EDITOR + AssetDatabase.AddObjectToAsset(input, AssetDatabase.GUIDToAssetPath(m_ParentAssetId)); + AssetDatabase.SaveAssets(); +#endif + } + AssetDatabase.Refresh(); + } + + void ReleaseAt(int index) + { + if (m_InputsSettingsAssets[index] is InputBinder ) + SceneHook.UnregisterInputSettingObj(m_ParentAssetId, m_InputsSettings[index]); + + UnityHelpers.Destroy(m_InputsSettingsAssets[index],true); + + m_InputsSettings[index] = null; + m_InputsSettingsAssets[index] = null; + } + +#if UNITY_EDITOR + public void RepareMissingBindings() + { + for (int i = 0; i < m_InputsSettingsAssets.Count; i++) + { + var ib = m_InputsSettingsAssets[i] as InputBinder; + if (ib != null && m_InputsSettings[i] == null) + { + var newInput = ScriptableObject.CreateInstance(ib.inputType) as RecorderInputSetting; + newInput.m_DisplayName = ib.m_DisplayName; + newInput.m_Id = ib.m_Id; + m_InputsSettings[i] = newInput; + SceneHook.RegisterInputSettingObj(m_ParentAssetId, newInput); + } + } + } +#endif + + public void OnDestroy() + { + for (int i = 0; i < m_InputsSettingsAssets.Count; i++) + { + if (m_InputsSettingsAssets[i] is InputBinder) + SceneHook.UnregisterInputSettingObj(m_ParentAssetId, m_InputsSettings[i]); + + UnityHelpers.Destroy(m_InputsSettingsAssets[i], true); + } + } + + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Core/Engine/InputSettingsList.cs.meta b/source/FrameRecorder/Core/Engine/InputSettingsList.cs.meta new file mode 100644 index 0000000..2aac8e2 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/InputSettingsList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 68168008d5a13ae469b8010cdd9c280a +timeCreated: 1504637954 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Engine/Recorder.cs b/source/FrameRecorder/Core/Engine/Recorder.cs index 6234fe6..0282d71 100644 --- a/source/FrameRecorder/Core/Engine/Recorder.cs +++ b/source/FrameRecorder/Core/Engine/Recorder.cs @@ -46,8 +46,8 @@ namespace UnityEngine.FrameRecorder if (sm_CaptureFrameRateCount == 0) { Time.captureFramerate = 0; - if (settings.m_Verbose) - Debug.Log("Frame recorder resetting 'CaptureFrameRate' to zero"); + if (RecorderSettings.m_Verbose) + Debug.Log("Recorder resetting 'CaptureFrameRate' to zero"); } } } @@ -56,15 +56,15 @@ namespace UnityEngine.FrameRecorder public virtual void SessionCreated(RecordingSession session) { - if (settings.m_Verbose) + if (RecorderSettings.m_Verbose) Debug.Log(string.Format("Recorder {0} session created", GetType().Name)); var fixedRate = settings.m_FrameRateMode == FrameRateMode.Constant ? (int)settings.m_FrameRate : 0; if (fixedRate > 0) { if (Time.captureFramerate != 0 && fixedRate != Time.captureFramerate ) - Debug.LogError(string.Format("Frame Recorder {0} is set to record at a fixed rate and another component has already set a conflicting value for [Time.captureFramerate], new value being applied : {1}!", GetType().Name, fixedRate)); - else if( Time.captureFramerate == 0 && settings.m_Verbose ) + Debug.LogError(string.Format("Recorder {0} is set to record at a fixed rate and another component has already set a conflicting value for [Time.captureFramerate], new value being applied : {1}!", GetType().Name, fixedRate)); + else if( Time.captureFramerate == 0 && RecorderSettings.m_Verbose ) Debug.Log("Frame recorder set fixed frame rate to " + fixedRate); Time.captureFramerate = (int)fixedRate; @@ -74,7 +74,7 @@ namespace UnityEngine.FrameRecorder } m_Inputs = new List(); - foreach (var inputSettings in settings.m_SourceSettings) + foreach (var inputSettings in settings.inputsSettings) { var input = Activator.CreateInstance(inputSettings.inputType) as RecorderInput; input.settings = inputSettings; @@ -88,7 +88,7 @@ namespace UnityEngine.FrameRecorder if (recording) throw new Exception("Already recording!"); - if (settings.m_Verbose) + if (RecorderSettings.m_Verbose) Debug.Log(string.Format("Recorder {0} starting to record", GetType().Name)); return recording = true; @@ -107,8 +107,8 @@ namespace UnityEngine.FrameRecorder if (sm_CaptureFrameRateCount == 0) { Time.captureFramerate = 0; - if (settings.m_Verbose) - Debug.Log("Frame recorder resetting 'CaptureFrameRate' to zero"); + if (RecorderSettings.m_Verbose) + Debug.Log("Recorder resetting 'CaptureFrameRate' to zero"); } } diff --git a/source/FrameRecorder/Core/Engine/RecorderSettings.cs b/source/FrameRecorder/Core/Engine/RecorderSettings.cs index 0d244fb..bd47762 100644 --- a/source/FrameRecorder/Core/Engine/RecorderSettings.cs +++ b/source/FrameRecorder/Core/Engine/RecorderSettings.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace UnityEngine.FrameRecorder { @@ -35,8 +34,11 @@ namespace UnityEngine.FrameRecorder /// Motivation : /// Notes: /// + [ExecuteInEditMode] public abstract class RecorderSettings : ScriptableObject { + [SerializeField] + string m_AssetID; public int m_CaptureEveryNthFrame = 1; public FrameRateMode m_FrameRateMode = FrameRateMode.Constant; [Range(1,120)] @@ -47,16 +49,36 @@ namespace UnityEngine.FrameRecorder public float m_StartTime = 0.0f; public float m_EndTime = 1.0f; public DurationMode m_DurationMode; - public bool m_Verbose = false; public bool m_SynchFrameRate = true; public FileNameGenerator m_BaseFileName; - public OutputPath m_DestinationPath; + public OutputPath m_DestinationPath; + + public static bool m_Verbose; + + [SerializeField] + private InputSettingsList m_InputsSettings = new InputSettingsList(); + + public InputSettingsList inputsSettings + { + get + { + return m_InputsSettings; + } + } - public RecorderInputSetting[] m_SourceSettings = new RecorderInputSetting[0]; - [SerializeField] string m_RecorderTypeName; + public string assetID + { + get { return m_AssetID; } + set + { + m_AssetID = value; + m_InputsSettings.m_ParentAssetId = value; + } + } + public RecorderSettings() { m_DestinationPath.root = OutputPath.ERoot.Current; @@ -83,41 +105,59 @@ namespace UnityEngine.FrameRecorder { get { - if (m_FrameRate == 0) + if (m_FrameRate == 0 || m_CaptureEveryNthFrame <= 0) return false; - if (m_SourceSettings != null) + if (m_InputsSettings != null) { - var valid = m_SourceSettings.All(x => x.isValid); - return valid; + return m_InputsSettings.isValid; } return true; } } + public virtual bool isPlatformSupported {get { return true; }} + public virtual void OnEnable() { + m_InputsSettings.OnEnable(m_AssetID); + BindSceneInputSettings(); + } + + public void BindSceneInputSettings() + { + if (!m_InputsSettings.hasBrokenBindings) + return; + + m_InputsSettings.Rebuild(); +#if UNITY_EDITOR + if (m_InputsSettings.hasBrokenBindings) + { + // only supported case is scene stored input settings are missing (for example: new scene loaded that does not contain the scene stored inputs.) + m_InputsSettings.RepareMissingBindings(); + } +#endif + + if (m_InputsSettings.hasBrokenBindings) + Debug.LogError("Recorder: missing input settings"); } public virtual void OnDestroy() { - if (m_SourceSettings != null) - { - foreach( var settings in m_SourceSettings) - UnityHelpers.Destroy(settings, true); - } + if (m_InputsSettings != null) + m_InputsSettings.OnDestroy(); } - public abstract List GetDefaultSourcesSettings(); + public abstract List GetDefaultInputSettings(); public T NewInputSettingsObj( string title ) where T: class { return NewInputSettingsObj(typeof(T), title) as T; } - public virtual RecorderInputSetting NewInputSettingsObj(Type type,string title ) + public virtual RecorderInputSetting NewInputSettingsObj(Type type, string title ) { var obj = (RecorderInputSetting)ScriptableObject.CreateInstance(type) ; obj.m_DisplayName = title; diff --git a/source/FrameRecorder/Core/Engine/RecorderVersion.cs b/source/FrameRecorder/Core/Engine/RecorderVersion.cs new file mode 100644 index 0000000..a3f1930 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/RecorderVersion.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.FrameRecorder +{ + public class RecorderVersion : ScriptableObject + { + public const string Version = "0.1.170901-04"; + public const string Stage = "(Beta)"; + } +} diff --git a/source/FrameRecorder/Core/Engine/RecorderVersion.cs.meta b/source/FrameRecorder/Core/Engine/RecorderVersion.cs.meta new file mode 100644 index 0000000..34881d9 --- /dev/null +++ b/source/FrameRecorder/Core/Engine/RecorderVersion.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9e740d9b4062aba498ea343c42b49a37 +timeCreated: 1504287906 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Core/Engine/RecordersInventory.cs b/source/FrameRecorder/Core/Engine/RecordersInventory.cs index de4bd75..e00323e 100644 --- a/source/FrameRecorder/Core/Engine/RecordersInventory.cs +++ b/source/FrameRecorder/Core/Engine/RecordersInventory.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; #if UNITY_EDITOR using UnityEditor; +using System.Linq; #endif namespace UnityEngine.FrameRecorder @@ -175,8 +175,9 @@ namespace UnityEngine.FrameRecorder else throw new ArgumentException("No factory was registered for " + recorderType.Name); } + #if UNITY_EDITOR - public static RecorderSettings GenerateNewSettingsAsset(UnityEngine.Object parentAsset, Type recorderType) + public static RecorderSettings GenerateRecorderInitialSettings(UnityEngine.Object parent, Type recorderType) { Init(); var recorderinfo = GetRecorderInfo(recorderType); @@ -184,14 +185,14 @@ namespace UnityEngine.FrameRecorder { RecorderSettings settings = null; settings = ScriptableObject.CreateInstance(recorderinfo.settings) as RecorderSettings; - settings.name = "Frame Recorder Settings"; + settings.name = "Recorder Settings"; settings.recorderType = recorderType; - settings.m_SourceSettings = settings.GetDefaultSourcesSettings().ToArray(); - AssetDatabase.AddObjectToAsset(settings, parentAsset); - foreach (var obj in settings.m_SourceSettings) - AssetDatabase.AddObjectToAsset(obj, parentAsset); + AssetDatabase.AddObjectToAsset(settings, parent); + AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); + settings.assetID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(settings)); + settings.inputsSettings.AddRange( settings.GetDefaultInputSettings() ); return settings; } @@ -199,5 +200,6 @@ namespace UnityEngine.FrameRecorder throw new ArgumentException("No factory was registered for " + recorderType.Name); } #endif + } } diff --git a/source/FrameRecorder/Core/Engine/RecordingSession.cs b/source/FrameRecorder/Core/Engine/RecordingSession.cs index 83b2592..ccb5a04 100644 --- a/source/FrameRecorder/Core/Engine/RecordingSession.cs +++ b/source/FrameRecorder/Core/Engine/RecordingSession.cs @@ -38,8 +38,18 @@ namespace UnityEngine.FrameRecorder get { return (float)(m_CurrentFrameStartTS - settings.m_StartTime); } } + void AllowInBackgroundMode() + { + if (!Application.runInBackground) + { + Application.runInBackground = true; + Debug.Log("Recording sessions is enabling Application.runInBackground!"); + } + } + public bool SessionCreated() { + AllowInBackgroundMode(); m_RecordingStartTS = (Time.time / Time.timeScale); m_SessionStartTS = DateTime.Now; m_Recorder.SessionCreated(this); @@ -49,6 +59,14 @@ namespace UnityEngine.FrameRecorder public bool BeginRecording() { + if (!settings.isPlatformSupported) + { + Debug.LogError( string.Format("Recorder {0} does not support current platform", m_Recorder.GetType().Name)); + return false; + } + + AllowInBackgroundMode(); + m_RecordingStartTS = (Time.time / Time.timeScale); m_Recorder.SignalInputsOfStage(ERecordingSessionStage.BeginRecording, this); @@ -91,13 +109,13 @@ namespace UnityEngine.FrameRecorder if (sleep > 2) { - if(settings.m_Verbose) + if(RecorderSettings.m_Verbose) Debug.Log( string.Format("Recording session info => dT: {0:F1}s, Target dT: {1:F1}s, Retarding: {2}ms, fps: {3:F1}", elapsed, target, sleep, frameCount / elapsed )); - System.Threading.Thread.Sleep(sleep); + System.Threading.Thread.Sleep( Math.Min(sleep,1000)); } else if (sleep < -frameLen) m_InitialFrame--; - else if(settings.m_Verbose) + else if(RecorderSettings.m_Verbose) Debug.Log( string.Format("Recording session info => fps: {0:F1}", frameCount / elapsed )); // reset every 30 frames @@ -118,6 +136,8 @@ namespace UnityEngine.FrameRecorder public void PrepareNewFrame() { + AllowInBackgroundMode(); + m_CurrentFrameStartTS = (Time.time / Time.timeScale) - m_RecordingStartTS; m_Recorder.SignalInputsOfStage(ERecordingSessionStage.NewFrameStarting, this); m_Recorder.PrepareNewFrame(this); diff --git a/source/FrameRecorder/Core/Engine/SceneHook.cs b/source/FrameRecorder/Core/Engine/SceneHook.cs new file mode 100644 index 0000000..da327cb --- /dev/null +++ b/source/FrameRecorder/Core/Engine/SceneHook.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using UnityEditor; + +namespace UnityEngine.FrameRecorder +{ + + /// + /// What is this: + /// Motivation : + /// Notes: + /// + public class SceneHook + { + const string k_HostGoName = "UnityEngine-Recorder"; + + static GameObject GetGameObject(bool createIfAbsent) + { + var go = GameObject.Find(k_HostGoName); + if (go == null && createIfAbsent) + { + go = new GameObject(k_HostGoName); + if (!RecorderSettings.m_Verbose) + go.hideFlags = HideFlags.HideInHierarchy; + } + + return go; + } + + static GameObject GetRecordingSessionsRoot(bool createIfAbsent) + { + var root = GetGameObject(createIfAbsent); + if (root == null) + return null; + + var settingsTr = root.transform.Find("RecordingSessions"); + GameObject settingsGO; + if (settingsTr == null) + { + settingsGO = new GameObject("RecordingSessions"); + settingsGO.transform.parent = root.transform; + } + else + settingsGO = settingsTr.gameObject; + + return settingsGO; + } + + public static GameObject GetSettingsRoot(bool createIfAbsent) + { + var root = GetGameObject(createIfAbsent); + if (root == null) + return null; + + var settingsTr = root.transform.Find("Settings"); + GameObject settingsGO; + if (settingsTr == null) + { + settingsGO = new GameObject("Settings"); + settingsGO.transform.parent = root.transform; + } + else + settingsGO = settingsTr.gameObject; + + return settingsGO; + } + + public static GameObject HookupRecorder() + { + var ctrl = GetRecordingSessionsRoot(true); + + var recorderGO = new GameObject(); + + recorderGO.transform.parent = ctrl.transform; + + return recorderGO; + } + + public static GameObject FindRecorder(RecorderSettings settings) + { + var ctrl = GetRecordingSessionsRoot(false); + if (ctrl == null) + return null; + + for (int i = 0; i < ctrl.transform.childCount; i++) + { + var child = ctrl.transform.GetChild(i); + var settingsHost = child.GetComponent(); + if (settingsHost != null && settingsHost.session != null && settingsHost.session.settings == settings) + return settingsHost.gameObject; + } + + return null; + } + + public static void RegisterInputSettingObj(string assetId, RecorderInputSetting input) + { + var settingsRoot = GetInputsComponent(assetId); + settingsRoot.m_Settings.Add(input); + } + + public static void UnregisterInputSettingObj(string assetId, RecorderInputSetting input) + { + var settingsRoot = GetInputsComponent(assetId); + settingsRoot.m_Settings.Remove(input); + UnityHelpers.Destroy(input); + } + + public static InputSettingsComponent GetInputsComponent(string assetId) + { + var ctrl = GetSettingsRoot(true); + var parentRoot = ctrl.transform.Find(assetId); + if (parentRoot == null) + { + parentRoot = (new GameObject()).transform; + parentRoot.name = assetId; + parentRoot.parent = ctrl.transform; + } + var settings = parentRoot.GetComponent(); + + if (settings == null) + { + settings = parentRoot.gameObject.AddComponent(); + settings.m_Settings = new List(); + } + + return settings; + } + } +} diff --git a/source/FrameRecorder/Core/Engine/FrameRecorderGOControler.cs.meta b/source/FrameRecorder/Core/Engine/SceneHook.cs.meta similarity index 100% rename from source/FrameRecorder/Core/Engine/FrameRecorderGOControler.cs.meta rename to source/FrameRecorder/Core/Engine/SceneHook.cs.meta diff --git a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderClip.cs b/source/FrameRecorder/Core/Engine/Timeline/RecorderClip.cs similarity index 89% rename from source/FrameRecorder/Core/Engine/Timeline/FrameRecorderClip.cs rename to source/FrameRecorder/Core/Engine/Timeline/RecorderClip.cs index 66458c2..ac33b8d 100644 --- a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderClip.cs +++ b/source/FrameRecorder/Core/Engine/Timeline/RecorderClip.cs @@ -10,7 +10,7 @@ namespace UnityEngine.FrameRecorder.Timeline /// /// Note: Instances of this call Own their associated Settings asset's lifetime. /// - public class FrameRecorderClip : PlayableAsset, ITimelineClipAsset + public class RecorderClip : PlayableAsset, ITimelineClipAsset { [SerializeField] public RecorderSettings m_Settings; @@ -34,7 +34,7 @@ namespace UnityEngine.FrameRecorder.Timeline behaviour.session = new RecordingSession() { m_Recorder = RecordersInventory.GenerateNewRecorder(recorderType, m_Settings), - m_RecorderGO = FrameRecorderGOControler.HookupRecorder(!m_Settings.m_Verbose), + m_RecorderGO = SceneHook.HookupRecorder(), }; } return playable; diff --git a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderClip.cs.meta b/source/FrameRecorder/Core/Engine/Timeline/RecorderClip.cs.meta similarity index 100% rename from source/FrameRecorder/Core/Engine/Timeline/FrameRecorderClip.cs.meta rename to source/FrameRecorder/Core/Engine/Timeline/RecorderClip.cs.meta diff --git a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderTrack.cs b/source/FrameRecorder/Core/Engine/Timeline/RecorderTrack.cs similarity index 83% rename from source/FrameRecorder/Core/Engine/Timeline/FrameRecorderTrack.cs rename to source/FrameRecorder/Core/Engine/Timeline/RecorderTrack.cs index 6718c4d..eb4b5ce 100644 --- a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderTrack.cs +++ b/source/FrameRecorder/Core/Engine/Timeline/RecorderTrack.cs @@ -10,11 +10,13 @@ namespace UnityEngine.FrameRecorder.Timeline /// Note: Instances of this call Own their associated Settings asset's lifetime. /// [System.Serializable] - [TrackClipType(typeof(FrameRecorderClip))] + [TrackClipType(typeof(RecorderClip))] [TrackMediaType(TimelineAsset.MediaType.Script)] [TrackColor(0f, 0.53f, 0.08f)] - public class FrameRecorderTrack : TrackAsset + public class RecorderTrack : TrackAsset { + + } } diff --git a/source/FrameRecorder/Core/Engine/Timeline/FrameRecorderTrack.cs.meta b/source/FrameRecorder/Core/Engine/Timeline/RecorderTrack.cs.meta similarity index 100% rename from source/FrameRecorder/Core/Engine/Timeline/FrameRecorderTrack.cs.meta rename to source/FrameRecorder/Core/Engine/Timeline/RecorderTrack.cs.meta diff --git a/source/FrameRecorder/Inputs/Adam/Engine/AdamBeautyInput.cs b/source/FrameRecorder/Inputs/Adam/Engine/AdamBeautyInput.cs index bef3203..0dd07c8 100644 --- a/source/FrameRecorder/Inputs/Adam/Engine/AdamBeautyInput.cs +++ b/source/FrameRecorder/Inputs/Adam/Engine/AdamBeautyInput.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; namespace UnityEngine.FrameRecorder.Input { @@ -169,7 +168,7 @@ namespace UnityEngine.FrameRecorder.Input continue; } - if (!cam.enabled || !cam.gameObject.active || cam.targetDisplay != 0) + if (!cam.enabled || !cam.gameObject.activeInHierarchy || cam.targetDisplay != 0) continue; hookedCam = new HookedCamera() { camera = cam, textureBackup = cam.targetTexture }; @@ -181,7 +180,7 @@ namespace UnityEngine.FrameRecorder.Input if (sort) { - m_hookedCameras = m_hookedCameras.OrderBy(x => x.camera.depth).ToList(); + m_hookedCameras.Sort((x, y) => x.camera.depth < y.camera.depth ? -1 : x.camera.depth > y.camera.depth ? 1 : 0 ); } break; } diff --git a/source/FrameRecorder/Inputs/Animation.meta b/source/FrameRecorder/Inputs/Animation.meta new file mode 100644 index 0000000..05f470a --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bce584456d820498b8cc7bd0ff6fdd25 +folderAsset: yes +timeCreated: 1504040760 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Editor.meta b/source/FrameRecorder/Inputs/Animation/Editor.meta new file mode 100644 index 0000000..efd910c --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f400e83e75546484ba9cba936ede7675 +folderAsset: yes +timeCreated: 1504040760 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs b/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs new file mode 100644 index 0000000..c1184c0 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.FrameRecorder; +using UnityEngine.FrameRecorder.Input; + +namespace UnityEditor.FrameRecorder.Input +{ + + [CustomEditor(typeof(AnimationInputSettings))] + public class AnimationInputSettingsEditor : Editor + { + public override void OnInspectorGUI() + { + var animImputSetting = target as AnimationInputSettings;; + EditorGUILayout.BeginHorizontal(); + + EditorGUI.BeginChangeCheck(); + + animImputSetting.gameObject = EditorGUILayout.ObjectField(animImputSetting.gameObject, typeof(GameObject), true) as GameObject; + if (EditorGUI.EndChangeCheck()) + { + + } + if (animImputSetting.gameObject != null) + { + var compos = animImputSetting.gameObject.GetComponents() + .Where(x=>x!=null).Select(x => x.GetType()) + .Distinct().ToList(); + var i = animImputSetting.bindingType == null ? 0 : Math.Max(compos.IndexOf(animImputSetting.bindingType), 0); + i = EditorGUILayout.Popup(i, compos.Select(x=>x.Name).ToArray()); + animImputSetting.bindingTypeName = compos[i].AssemblyQualifiedName; + } + + animImputSetting.enabled = EditorGUILayout.Toggle(animImputSetting.enabled); + EditorGUILayout.EndHorizontal(); + } + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs.meta b/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs.meta new file mode 100644 index 0000000..1c59f66 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Editor/AnimationInputSettingsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: afc6867a22e414a188b45973bcc23273 +timeCreated: 1504040760 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Engine.meta b/source/FrameRecorder/Inputs/Animation/Engine.meta new file mode 100644 index 0000000..0605d1c --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8b264dd2aed5c4771a8980de70e71c1c +folderAsset: yes +timeCreated: 1504040760 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs new file mode 100644 index 0000000..af3b608 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEditor.Experimental.Animations; +using UnityEngine; +using UnityEngine.FrameRecorder; +using UnityEngine.FrameRecorder.Input; +using UnityEngine.Rendering; + +namespace UnityEngine.FrameRecorder.Input +{ + public class AnimationInput : RecorderInput + { + public GameObjectRecorder m_gameObjectRecorder; + private float m_time; + public override void BeginRecording(RecordingSession session) + { + var aniSettings = (settings as AnimationInputSettings); + var srcGO= aniSettings.gameObject; + m_gameObjectRecorder = new GameObjectRecorder {root = srcGO}; + m_gameObjectRecorder.BindComponent(srcGO, aniSettings.bindingType, true); + m_time = 0; + } + + public void NewFrame(RecordingSession session) + { + if (session.recording && (settings as AnimationInputSettings).enabled ) + { + m_gameObjectRecorder.TakeSnapshot(session.RecorderTime - m_time); + m_time = session.RecorderTime; + } + } + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs.meta b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs.meta new file mode 100644 index 0000000..4562142 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInput.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 262e9424f303141518c858a648377c23 +timeCreated: 1504030414 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs new file mode 100644 index 0000000..3496b5e --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs @@ -0,0 +1,26 @@ +/* +using System; +using System.Collections.Generic; +using System.Linq; + +namespace UnityEngine.FrameRecorder.Input +{ + + [Serializable] + public class AnimationInputComponent:MonoBehaviour + { + [HideInInspector] + [SerializeField] + public int componentSelectionPopup; + + public Type GetBinding() + { + return gameObject.GetComponents().Select(x => x.GetType()).Distinct().ToList()[componentSelectionPopup]; + } + private void OnEnable() + { + } + + + } +}*/ \ No newline at end of file diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs.meta b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs.meta new file mode 100644 index 0000000..503fba8 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputComponent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c06b5c17c9a435d8af2b251871069c5 +timeCreated: 1504112224 \ No newline at end of file diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs new file mode 100644 index 0000000..686064c --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs @@ -0,0 +1,32 @@ +using System; + +namespace UnityEngine.FrameRecorder.Input +{ + [Serializable] + [StoreInScene] + public class AnimationInputSettings : InputSettings + { + + [SerializeField] + public GameObject gameObject; + [SerializeField] + public bool enabled; + + [SerializeField] + public string bindingTypeName; + + + public Type bindingType + { + get { return string.IsNullOrEmpty( bindingTypeName) ? null : Type.GetType(bindingTypeName); } + } + + public override bool isValid + { + get + { + return !enabled || gameObject != null && bindingType !=null; + } + } + } +} diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs.meta b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs.meta new file mode 100644 index 0000000..95a1a48 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationInputSettings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c011637fb4c894c56a9178092966b5ac +timeCreated: 1504030414 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs b/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs new file mode 100644 index 0000000..9c87186 --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs @@ -0,0 +1,71 @@ +/*using UnityEditor; +using UnityEngine.Playables; +using UnityEngine.Timeline; + +namespace UnityEngine.FrameRecorder.Input +{ + [ExecuteInEditMode] + public class AnimationOutputComponent:MonoBehaviour + { + [HideInInspector] + public AnimationRecorderSettings recorderSettings; + void OnEnable() + { + EditorApplication.playmodeStateChanged += PlayStateChange; + } + + private void OnDisable() + { + EditorApplication.playmodeStateChanged -= PlayStateChange; + } + + + void PlayStateChange() + { + if (!EditorApplication.isPlaying && !EditorApplication.isPlayingOrWillChangePlaymode) + { + Debug.Log(EditorApplication.isPlaying); + EnsureOutputStructure(); + CreateTimelineData(); + } + } + + private void EnsureOutputStructure() + { + var director = gameObject.GetComponent(); + if (director == null) + { + gameObject.AddComponent(); + director = gameObject.GetComponent(); + } + + var timeline = director.playableAsset; + if (timeline == null) + { + timeline = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(timeline, AnimationRecorder.rootAssetPath+"AnimationRecorder.playable"); + director.playableAsset = timeline; + } + } + + private void CreateTimelineData() + { + if (recorderSettings.dirty) + { + var director = gameObject.GetComponent(); + var timeline = director.playableAsset as TimelineAsset; + TrackAsset groupTrack = timeline.CreateTrack(null, "Take"); + for (int i = 0;i(groupTrack, go.name); + var animClip = AssetDatabase.LoadAssetAtPath(recorderSettings.animClips[i]); + animTrack.CreateClip(animClip).displayName = go.name; + director.SetGenericBinding(animTrack,go); + } + + recorderSettings.dirty = false; + } + } + } +}*/ \ No newline at end of file diff --git a/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs.meta b/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs.meta new file mode 100644 index 0000000..6245aef --- /dev/null +++ b/source/FrameRecorder/Inputs/Animation/Engine/AnimationOutputComponent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8f6d6e22ba88c4ba8b42a1271c6b11c3 +timeCreated: 1504202270 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/source/FrameRecorder/Inputs/CBRenderTexture/Engine/CBRenderTextureInput.cs b/source/FrameRecorder/Inputs/CBRenderTexture/Engine/CBRenderTextureInput.cs index 67208a1..8936d02 100644 --- a/source/FrameRecorder/Inputs/CBRenderTexture/Engine/CBRenderTextureInput.cs +++ b/source/FrameRecorder/Inputs/CBRenderTexture/Engine/CBRenderTextureInput.cs @@ -93,7 +93,7 @@ namespace UnityEngine.FrameRecorder.Input outputHeight = (outputHeight + 1) & ~1; } - var size = GameViewSize.FindSize(outputWidth, outputHeight); + var size = GameViewSize.SetCustomSize(outputWidth, outputHeight); if (size == null) size = GameViewSize.AddSize(outputWidth, outputHeight); @@ -179,7 +179,7 @@ namespace UnityEngine.FrameRecorder.Input m_mat_copy.EnableKeyword("TRANSPARENCY_ON"); var tid = Shader.PropertyToID("_TmpFrameBuffer"); - m_cbCopyFB = new CommandBuffer { name = "Frame Recorder: copy frame buffer" }; + m_cbCopyFB = new CommandBuffer { name = "Recorder: copy frame buffer" }; m_cbCopyFB.GetTemporaryRT(tid, -1, -1, 0, FilterMode.Bilinear); m_cbCopyFB.Blit(BuiltinRenderTextureType.CurrentActive, tid); m_cbCopyFB.SetRenderTarget(outputRT); diff --git a/source/FrameRecorder/Inputs/CBRenderTexture/Engine/GameViewSize.cs b/source/FrameRecorder/Inputs/CBRenderTexture/Engine/GameViewSize.cs index c78e7a7..1362e1b 100644 --- a/source/FrameRecorder/Inputs/CBRenderTexture/Engine/GameViewSize.cs +++ b/source/FrameRecorder/Inputs/CBRenderTexture/Engine/GameViewSize.cs @@ -1,6 +1,7 @@ #if UNITY_EDITOR using System; +using System.Collections.Generic; using System.Reflection; using UnityEditor; @@ -9,10 +10,8 @@ namespace UnityEngine.FrameRecorder.Input public class GameViewSize { - static object m_InitialSizeObj; - public static EditorWindow GetMainGameView() { System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor"); @@ -63,28 +62,58 @@ namespace UnityEngine.FrameRecorder.Input height = (int)gameViewSize.GetType().GetProperty("height", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).GetValue(gameViewSize, new object[0] { }); } - public static object FindSize(int width, int height) + public static object SetCustomSize(int width, int height) + { + // Find recorder size object + var sizeObj = FindRecorderSizeObj(); + if (sizeObj != null) + { + sizeObj.GetType().GetField("m_Width",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(sizeObj,width); + sizeObj.GetType().GetField("m_Height", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(sizeObj,height); + } + else + { + sizeObj = AddSize(width, height); + } + + return sizeObj; + } + + + private static object FindRecorderSizeObj() { var group = Group(); - int total = TotalCount(); - for (int i = 0; i < total; i++) + var customs = group.GetType().GetField("m_Custom", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(group); + + var itr = (System.Collections.IEnumerator)customs.GetType().GetMethod("GetEnumerator").Invoke(customs, new object[] {}); + while (itr.MoveNext()) { - var sizeObj = GetGameViewSize(group, i); - int x, y; - SizeOf(sizeObj, out x, out y); - if (x == width && y == height) - return sizeObj; + var txt = (string)itr.Current.GetType().GetField("m_BaseText", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(itr.Current); + if (txt == "(Recording resolution)") + return itr.Current; } return null; } + public static int IndexOf(object sizeObj) { var group = Group(); - var obj = group.GetType().GetMethod("IndexOf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - return (int)obj.Invoke(group, new object[] {sizeObj}) ; + var method = group.GetType().GetMethod("IndexOf", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + int index = (int)method.Invoke(group, new object[] {sizeObj}) ; + + var builtinList = group.GetType().GetField("m_Builtin", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(group); + + method = builtinList.GetType().GetMethod("Contains"); + if ((bool)method.Invoke(builtinList, new object[] { sizeObj })) + return index; + + method = group.GetType().GetMethod("GetBuiltinCount"); + index += (int)method.Invoke(group, new object[] { }); + + return index; } static object NewSizeObj(int width, int height) @@ -95,7 +124,7 @@ namespace UnityEngine.FrameRecorder.Input T.GetProperty("sizeType", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).SetValue(sizeObj, 1, new object[0] { }); T.GetProperty("width", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).SetValue(sizeObj, width, new object[0] { }); T.GetProperty("height", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).SetValue(sizeObj, height, new object[0] { }); - T.GetProperty("baseText", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).SetValue(sizeObj, string.Format("FR:{0}x{1}", width, height), new object[0] { }); + T.GetProperty("baseText", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).SetValue(sizeObj, "(Recording resolution)", new object[0] { }); return sizeObj; } @@ -113,7 +142,7 @@ namespace UnityEngine.FrameRecorder.Input public static void SelectSize(object size) { - var index = IndexOf(size) + 7; + var index = IndexOf(size); var gameView = GetMainGameView(); var obj = gameView.GetType().GetMethod("SizeSelectionCallback", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); diff --git a/source/FrameRecorder/Packager/Editor/FRPackagerPaths.cs b/source/FrameRecorder/Packager/Editor/FRPackagerPaths.cs index eef05f5..7e6591a 100644 --- a/source/FrameRecorder/Packager/Editor/FRPackagerPaths.cs +++ b/source/FrameRecorder/Packager/Editor/FRPackagerPaths.cs @@ -1,5 +1,6 @@ using System.IO; using UnityEngine; +using UnityEngine.FrameRecorder; namespace UnityEditor.FrameRecorder { @@ -7,12 +8,28 @@ namespace UnityEditor.FrameRecorder { public static string GetFrameRecorderRootPath() { - var dummy = ScriptableObject.CreateInstance(); - string path = Application.dataPath + AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(dummy)).Substring("Assets".Length); - + var path = GetFrameRecorderPath(); path = path.Substring(path.IndexOf("Assets")); - path = path.Replace("/Framework/FrameRecorder/Packager/Editor/FRPackagerPaths.cs", ""); return path; } + + public static string GetFrameRecorderVersionFilePath() + { + var dummy = ScriptableObject.CreateInstance(); + var path = Application.dataPath + AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(dummy)).Substring("Assets".Length); + UnityHelpers.Destroy(dummy); + return path; + } + + public static string GetFrameRecorderPath() + { + var dummy = ScriptableObject.CreateInstance(); + var path = Application.dataPath + AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(dummy)).Substring("Assets".Length); + UnityHelpers.Destroy(dummy); + + path= path.Replace("/Packager/Editor/FRPackagerPaths.cs", ""); + return path.Substring(0, path.LastIndexOf("/")); + } + } } \ No newline at end of file diff --git a/source/FrameRecorder/Packager/Private/Editor/FRPackager.cs b/source/FrameRecorder/Packager/Private/Editor/FRPackager.cs index 4718d29..65bac78 100644 --- a/source/FrameRecorder/Packager/Private/Editor/FRPackager.cs +++ b/source/FrameRecorder/Packager/Private/Editor/FRPackager.cs @@ -17,15 +17,15 @@ namespace UnityEditor.FrameRecorder static void GeneratePackage() { var rootPath = FRPackagerPaths.GetFrameRecorderRootPath(); + UpdateVersion(); string[] files = new string[] { Path.Combine(rootPath, "Framework.meta"), - Path.Combine(rootPath, "Framework/FrameRecorder.meta"), - Path.Combine(rootPath, "Framework/FrameRecorder/Core"), - Path.Combine(rootPath, "Framework/FrameRecorder/Inputs"), - Path.Combine(rootPath, "Framework/FrameRecorder/Recorders"), - Path.Combine(rootPath, "Framework/FrameRecorder/Packager/Editor"), + Path.Combine(rootPath, "Framework/Core"), + Path.Combine(rootPath, "Framework/Inputs"), + Path.Combine(rootPath, "Framework/Recorders"), + Path.Combine(rootPath, "Framework/Packager/Editor"), }; var destFile = k_PackageName + ".unitypackage"; AssetDatabase.ExportPackage(files, destFile, ExportPackageOptions.Recurse); @@ -37,25 +37,68 @@ namespace UnityEditor.FrameRecorder { var rootPath = FRPackagerPaths.GetFrameRecorderRootPath(); var type = System.Type.GetType("UnityEditor.FrameRecorder.MovieRecorderPackager"); - var method = type.GetMethod("GeneratePackage"); - method.Invoke(null, null); - AssetDatabase.Refresh(); + if (type != null) + { + var method = type.GetMethod("GeneratePackage"); + method.Invoke(null, null); + AssetDatabase.Refresh(); + } + UpdateVersion(); var files = new [] { Path.Combine(rootPath, "Framework.meta" ), - Path.Combine(rootPath, "Framework/FrameRecorder.meta" ), - Path.Combine(rootPath, "Framework/FrameRecorder/Core" ), - Path.Combine(rootPath, "Framework/FrameRecorder/Inputs" ), - Path.Combine(rootPath, "Framework/FrameRecorder/Recorders" ), - Path.Combine(rootPath, "Framework/FrameRecorder/Packager/Editor" ), + Path.Combine(rootPath, "Framework/Core" ), + Path.Combine(rootPath, "Framework/Inputs" ), + Path.Combine(rootPath, "Framework/Recorders" ), + Path.Combine(rootPath, "Framework/Packager/Editor" ), Path.Combine(rootPath, "Extensions/UTJ" ), - Path.Combine(rootPath, "Extensions/FrameCapturerRecorder" ), + Path.Combine(rootPath, "Extensions/FCIntegration" ), Path.Combine(rootPath, "Extensions/MovieRecorder/Packaging" ), }; var destFile = k_PackageName + "(full).unitypackage"; AssetDatabase.ExportPackage(files, destFile, ExportPackageOptions.Recurse); Debug.Log("Generated package: " + destFile); } + + [MenuItem("Assets/Recorder/Generate Assetstore package")] + static void GenerateAssetStorePackage() + { + var rootPath = FRPackagerPaths.GetFrameRecorderRootPath(); + + UpdateVersion(); + + var files = new [] + { + Path.Combine(rootPath, "Recorder_install.pdf" ), + Path.Combine(rootPath, "Framework.meta" ), + Path.Combine(rootPath, "Framework/Core" ), + Path.Combine(rootPath, "Framework/Inputs" ), + Path.Combine(rootPath, "Framework/Recorders" ), + Path.Combine(rootPath, "Framework/Packager/Editor" ), + Path.Combine(rootPath, "Extensions/UTJ" ), + Path.Combine(rootPath, "Extensions/FCIntegration" ), + }; + var destFile = k_PackageName + ".unitypackage"; + AssetDatabase.ExportPackage(files, destFile, ExportPackageOptions.Recurse); + Debug.Log("Generated package: " + destFile); + } + + static void UpdateVersion() + { + var path = FRPackagerPaths.GetFrameRecorderVersionFilePath(); + var script = File.ReadAllText(path); + + var tag = "public const string Version = "; + var startOffset = script.IndexOf(tag); + var endOffset = script.IndexOf("\"", startOffset + tag.Length + 1); + + var pattern = script.Substring(startOffset, endOffset - startOffset); + startOffset = pattern.LastIndexOf("."); + var newValue = pattern.Substring(0, startOffset + 1) + DateTime.Now.ToString("yyMMdd-hh"); + script = script.Replace(pattern, newValue); + File.WriteAllText(path, script); + } + } } diff --git a/source/FrameRecorder/Recorders/AnimationRecorder.meta b/source/FrameRecorder/Recorders/AnimationRecorder.meta new file mode 100644 index 0000000..f4fe457 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 118aaf48522942c3953f714a6739285e +timeCreated: 1503926431 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Editor.meta b/source/FrameRecorder/Recorders/AnimationRecorder/Editor.meta new file mode 100644 index 0000000..ad232f6 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49dc301ad9764dae95349a3b7603aa34 +timeCreated: 1503942643 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs b/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs new file mode 100644 index 0000000..283b3b0 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.FrameRecorder; +using UnityEngine.FrameRecorder.Input; +using UnityEngine.SceneManagement; +using Component = System.ComponentModel.Component; + +namespace UnityEditor.FrameRecorder +{ + [Serializable] + [CustomEditor(typeof(AnimationRecorderSettings))] + public class AnimationRecorderEditor: RecorderEditor + { + [MenuItem("Tools/Recorder/Animation")] + static void ShowRecorderWindow() + { + RecorderWindow.ShowAndPreselectCategory("Animation"); + } + + + protected override void OnEncodingGroupGui() + {} + + + protected override void OnInputGui() + { + var inputs = (target as RecorderSettings).inputsSettings; + + for (int i = 0; i < inputs.Count; i++) + { + OnInputGui(i); + } + + var aRecorderSettings = target as AnimationRecorderSettings; + + + EditorGUI.BeginChangeCheck(); + GameObject newgo = EditorGUILayout.ObjectField(null, typeof(GameObject), true) as GameObject; + if (EditorGUI.EndChangeCheck() && newgo !=null) + { + var newSettings = aRecorderSettings.NewInputSettingsObj(newgo.name); + newSettings.gameObject = newgo; + newSettings.enabled = true; + aRecorderSettings.inputsSettings.Add(newSettings); + } + } + + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs.meta b/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs.meta new file mode 100644 index 0000000..69cb778 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Editor/AnimationRecorderEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b5f9edca0e76485d8490267712eb006c +timeCreated: 1503942663 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Engine.meta b/source/FrameRecorder/Recorders/AnimationRecorder/Engine.meta new file mode 100644 index 0000000..f4d0264 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Engine.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eee171e060724e798c109b1bd0c3433b +timeCreated: 1503926447 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs new file mode 100644 index 0000000..c6620d0 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Experimental.Animations; +using UnityEditor; +using UnityEngine.FrameRecorder.Input; +using UnityEngine.Playables; +using UnityEngine.SceneManagement; +using UnityEngine.Timeline; + +namespace UnityEngine.FrameRecorder +{ + [FrameRecorder(typeof(AnimationRecorderSettings), "Animation", "Unity/Animation Recording")] + public class AnimationRecorder : GenericRecorder + { + public static string rootAssetPath = "Assets/AnimRecorder/"; + + + public override void RecordFrame(RecordingSession session) + { + foreach (RecorderInput t in m_Inputs) + { + var aInput = t as AnimationInput; + aInput.NewFrame(session); + } + } + + + public override void EndRecording(RecordingSession ctx) + { + var path = settings.m_BaseFileName.BuildFileName(ctx, 0, 0, 0, "anim"); + System.IO.Directory.CreateDirectory(rootAssetPath); + for (int i = 0; i < m_Inputs.Count; ++i) + { + var set = (settings.inputsSettings[i] as AnimationInputSettings); + if (set.enabled) + { + var aInput = m_Inputs[i] as AnimationInput; + AnimationClip clip = new AnimationClip(); + var clipname = rootAssetPath + set.gameObject.name+"-"+System.IO.Path.GetRandomFileName() + ".anim"; + AssetDatabase.CreateAsset(clip, clipname); + aInput.m_gameObjectRecorder.SaveToClip(clip); + aInput.m_gameObjectRecorder.ResetRecording(); + } + } + + base.EndRecording(ctx); + } + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs.meta b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs.meta new file mode 100644 index 0000000..e32c377 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0808b4ae0e5a40bc818e43f28ebe29e2 +timeCreated: 1503926464 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs new file mode 100644 index 0000000..88d3904 --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.FrameRecorder +{ + [ExecuteInEditMode] + [Serializable] + public class AnimationRecorderSettings : RecorderSettings + { + public override List GetDefaultInputSettings() + { + return new List(); + } + + public override bool isPlatformSupported + { + get + { + return Application.platform == RuntimePlatform.LinuxEditor || + Application.platform == RuntimePlatform.OSXEditor || + Application.platform == RuntimePlatform.WindowsEditor; + } + } + } +} \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs.meta b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs.meta new file mode 100644 index 0000000..ae8a6ed --- /dev/null +++ b/source/FrameRecorder/Recorders/AnimationRecorder/Engine/AnimationRecorderSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a9f55b158f7c43688c1c21ce05ac46ba +timeCreated: 1503926485 \ No newline at end of file diff --git a/source/FrameRecorder/Recorders/ImageRecorder/Editor/ImageRecorderEditor.cs b/source/FrameRecorder/Recorders/ImageRecorder/Editor/ImageRecorderEditor.cs index 9317c73..c74ccfe 100644 --- a/source/FrameRecorder/Recorders/ImageRecorder/Editor/ImageRecorderEditor.cs +++ b/source/FrameRecorder/Recorders/ImageRecorder/Editor/ImageRecorderEditor.cs @@ -11,7 +11,7 @@ namespace UnityEditor.FrameRecorder SerializedProperty m_OutputFormat; RTInputSelector m_RTInputSelector; - [MenuItem("Window/Recorder/Video")] + [MenuItem("Tools/Recorder/Video")] static void ShowRecorderWindow() { RecorderWindow.ShowAndPreselectCategory("Video"); @@ -27,7 +27,6 @@ namespace UnityEditor.FrameRecorder m_RTInputSelector = new RTInputSelector( target as RecorderSettings, "Pixels"); var pf = new PropertyFinder(serializedObject); - m_Inputs = pf.Find(w => w.m_SourceSettings); m_OutputFormat = pf.Find(w => w.m_OutputFormat); } @@ -38,7 +37,8 @@ namespace UnityEditor.FrameRecorder protected override void OnInputGui( int inputIndex) { - var input = m_Inputs.GetArrayElementAtIndex(inputIndex).objectReferenceValue as RecorderInputSetting; + var inputs = (target as RecorderSettings).inputsSettings; + var input = inputs[inputIndex]; if (m_RTInputSelector.OnInputGui(ref input)) ChangeInputSettings(inputIndex, input); diff --git a/source/FrameRecorder/Recorders/ImageRecorder/Engine/ImageRecorderSettings.cs b/source/FrameRecorder/Recorders/ImageRecorder/Engine/ImageRecorderSettings.cs index b22dfa5..d486afe 100644 --- a/source/FrameRecorder/Recorders/ImageRecorder/Engine/ImageRecorderSettings.cs +++ b/source/FrameRecorder/Recorders/ImageRecorder/Engine/ImageRecorderSettings.cs @@ -22,7 +22,7 @@ namespace UnityEngine.FrameRecorder m_BaseFileName.pattern = "image_<0000>."; } - public override List GetDefaultSourcesSettings() + public override List GetDefaultInputSettings() { return new List() { diff --git a/source/FrameRecorder/license b/source/FrameRecorder/license new file mode 100644 index 0000000..e81e76c --- /dev/null +++ b/source/FrameRecorder/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2017, Unity Technologies + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/source/FrameRecorder/license.meta b/source/FrameRecorder/license.meta new file mode 100644 index 0000000..028365c --- /dev/null +++ b/source/FrameRecorder/license.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4a883be6cc3a6547b0849c2f51911d9 +timeCreated: 1504201738 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: