using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditorInternal;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Recorder
{
///
/// Use this class to manage the recording settings (frame rate, frame range, list of Recorder Settings) for the .
///
public class RecorderControllerSettings : ScriptableObject
{
[SerializeField] RecordMode m_RecordMode = RecordMode.Manual;
[SerializeField] FrameRatePlayback m_FrameRatePlayback = FrameRatePlayback.Constant;
[SerializeField] FrameRateType m_FrameRateType = FrameRateType.FR_30;
[SerializeField] float m_CustomFrameRateValue = 30.0f;
[SerializeField] int m_StartFrame;
[SerializeField] int m_EndFrame;
[SerializeField] float m_StartTime;
[SerializeField] float m_EndTime;
[SerializeField] bool m_CapFrameRate = true;
[SerializeField] bool m_ExitPlayMode = true;
static readonly Dictionary s_FPSToValue = new Dictionary()
{
{ FrameRateType.FR_23, 24 * 1000 / 1001f },
{ FrameRateType.FR_24, 24 },
{ FrameRateType.FR_25, 25 },
{ FrameRateType.FR_29, 30 * 1000 / 1001f },
{ FrameRateType.FR_30, 30 },
{ FrameRateType.FR_50, 50 },
{ FrameRateType.FR_59, 60 * 1000 / 1001f },
{ FrameRateType.FR_60, 60 }
};
void OnValidate()
{
m_CustomFrameRateValue = Mathf.Max(2 * float.Epsilon, m_CustomFrameRateValue); // Eps complains about the invalid frame rate.
}
internal RecordMode RecordMode => m_RecordMode;
///
/// Instructs the recorder to exit Play Mode once the recording has finished.
///
public bool ExitPlayMode
{
get { return m_ExitPlayMode; }
set { m_ExitPlayMode = value; }
}
///
/// Indicates the type of frame rate (constant or variable) for the current list of Recorders.
///
public FrameRatePlayback FrameRatePlayback
{
get { return m_FrameRatePlayback; }
set { m_FrameRatePlayback = value; }
}
///
/// Allows setting and retrieving the frame rate for the current list of Recorders.
///
public float FrameRate
{
get
{
return m_FrameRateType == FrameRateType.FR_CUSTOM ? m_CustomFrameRateValue : s_FPSToValue[m_FrameRateType];
}
set
{
m_FrameRateType = FrameRateType.FR_CUSTOM;
m_CustomFrameRateValue = value;
}
}
///
/// Sets the Recorders to Manual mode.
///
public void SetRecordModeToManual()
{
m_RecordMode = RecordMode.Manual;
}
///
/// Sets the Recorders to Single Frame recording mode.
///
/// The frame to be recorded.
public void SetRecordModeToSingleFrame(int frameNumber)
{
m_RecordMode = RecordMode.SingleFrame;
m_StartFrame = m_EndFrame = frameNumber;
}
///
/// Sets the Recorders to Frame Interval mode and defines the Start and End frame of the interval to record.
///
/// Start frame.
/// End frame.
public void SetRecordModeToFrameInterval(int startFrame, int endFrame)
{
m_RecordMode = RecordMode.FrameInterval;
m_StartFrame = startFrame;
m_EndFrame = endFrame;
}
///
/// Sets the Recorders to Time Interval mode and defines the Start and End times of the interval to record.
///
/// The start time, in seconds.
/// The end time, in seconds.
public void SetRecordModeToTimeInterval(float startTime, float endTime)
{
m_RecordMode = RecordMode.TimeInterval;
m_StartTime = startTime;
m_EndTime = endTime;
}
///
/// Indicates if the Recorders frame rate should cap the Unity rendering frame rate. When enabled, Unity is prevented from rendering faster than the set FrameRate.
///
public bool CapFrameRate
{
get { return m_CapFrameRate; }
set { m_CapFrameRate = value; }
}
[SerializeField] List m_RecorderSettings = new List();
string m_Path;
///
/// Loads or creates Recorder Settings to the specified file path.
///
/// The path to load or create Recorder Settings.
/// The loaded or created Recorder Settings.
public static RecorderControllerSettings LoadOrCreate(string path)
{
RecorderControllerSettings prefs;
try
{
var objs = InternalEditorUtility.LoadSerializedFileAndForget(path);
prefs = objs.FirstOrDefault(p => p is RecorderControllerSettings) as RecorderControllerSettings;
}
catch (Exception e)
{
Debug.LogError("Unhandled exception while loading Recorder preferences: " + e);
prefs = null;
}
if (prefs == null)
{
prefs = CreateInstance();
prefs.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy;
prefs.name = "Global Settings";
prefs.Save();
}
prefs.m_Path = path;
return prefs;
}
///
/// Get the global controller settings.
///
/// The global RecorderControllerSettings
public static RecorderControllerSettings GetGlobalSettings()
{
var globalPath = Path.Combine(Application.dataPath, "..", "Library", "Recorder", "recorder.pref");
return LoadOrCreate(globalPath);
}
internal void ReleaseRecorderSettings()
{
foreach (var recorder in m_RecorderSettings)
{
DestroyImmediate(recorder);
}
ClearRecorderSettings();
}
internal void ClearRecorderSettings()
{
m_RecorderSettings.Clear();
}
///
/// Stores the collection of Recorder Settings instances.
///
public IEnumerable RecorderSettings
{
get
{
foreach (var setting in m_RecorderSettings)
{
if (setting != null) // It's important to keep null entries because they could be recorderSettings that rely on external code (that did not compile for now)
yield return setting;
}
}
}
///
/// Adds a new instance of Recorder Settings to the current collection.
///
/// The Recorder Settings instance to add.
public void AddRecorderSettings(RecorderSettings recorder)
{
EditorUtility.SetDirty(this);
Undo.RegisterCompleteObjectUndo(this, "Add Recorder");
if (!m_RecorderSettings.Contains(recorder))
{
AddRecorderInternal(recorder);
Save();
}
}
///
/// Removes an instance of Recorder Settings from the current collection.
///
/// The Recorder settings instance to be removed.
public void RemoveRecorder(RecorderSettings recorder)
{
if (m_RecorderSettings.Contains(recorder))
{
EditorUtility.SetDirty(this);
Undo.RegisterCompleteObjectUndo(this, "Remove Recorder");
m_RecorderSettings.Remove(recorder);
Undo.DestroyObjectImmediate(recorder);
Save();
}
}
///
/// Saves the current list of Recorder Settings instances to disk.
///
public void Save()
{
if (string.IsNullOrEmpty(m_Path))
return;
try
{
var directory = Path.GetDirectoryName(m_Path);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
Directory.CreateDirectory(directory);
var recordersCopy = RecorderSettings.ToArray();
var objs = new UnityObject[recordersCopy.Length + 1];
objs[0] = this;
for (int i = 0; i < recordersCopy.Length; ++i)
objs[i + 1] = recordersCopy[i];
InternalEditorUtility.SaveToSerializedFileAndForget(objs, m_Path, true);
}
catch (Exception e)
{
Debug.LogError("Unhandled exception while saving Recorder settings: " + e);
}
}
internal void ApplyGlobalSetting(RecorderSettings recorder)
{
recorder.RecordMode = m_RecordMode;
recorder.FrameRatePlayback = m_FrameRatePlayback;
recorder.FrameRate = FrameRate;
recorder.StartFrame = m_StartFrame;
recorder.EndFrame = m_EndFrame;
recorder.StartTime = m_StartTime;
recorder.EndTime = m_EndTime;
recorder.CapFrameRate = m_CapFrameRate;
recorder.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy;
}
internal void ApplyGlobalSettingToAllRecorders()
{
foreach (var recorder in RecorderSettings)
ApplyGlobalSetting(recorder);
}
void AddRecorderInternal(RecorderSettings recorder)
{
ApplyGlobalSetting(recorder);
m_RecorderSettings.Add(recorder);
}
///
/// Gets the number of currently active recorders that capture accumulation.
///
/// The number of recorders that are currently capturing accumulation.
int GetNumberOfActiveSubFrameRecorders()
{
return RecorderSettings.Count(r => r.Enabled && UnityHelpers.CaptureAccumulation(r));
}
///
/// Whether the current context should prevent recording due to invalid accumulation settings or not.
///
///
internal bool InvalidContextBecauseOfAccumulation()
{
return GetNumberOfActiveSubFrameRecorders() >= 1 && RecorderSettings.Count(r => r.Enabled) > 1;
}
}
}