Files
UmaViewer/Assets/Scripts/Audio/CRIMW/CriWare/Editor/CriProfilerEditor.cs
T
2022-09-10 16:59:44 +08:00

1293 lines
51 KiB
C#

/****************************************************************************
*
* Copyright (c) 2018 CRI Middleware Co., Ltd.
*
****************************************************************************/
using System;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace CriWare {
[Serializable]
public sealed class CriProfilerEditor : EditorWindow
{
private static CriProfiler profiler = CriProfiler.GetSingleton();
#region Unity Event Callbacks
[MenuItem ("Window/CRIWARE/CRI Profiler")]
static void InitWindow() {
CriProfilerEditor window = (CriProfilerEditor)EditorWindow.GetWindow(typeof(CriProfilerEditor));
#if UNITY_5_2 || UNITY_5_3 || UNITY_5_4_OR_NEWER
window.titleContent = new GUIContent("CRI Profiler");
#else
window.title = "CRI Profiler";
#endif
window.Show();
}
private struct PlaymodeState {
public readonly bool isPlaying;
public readonly bool isPaused;
public readonly bool isPlayingOrWillChangePlaymode;
public PlaymodeState(bool isPlaying, bool isPaused, bool isPlayingOrWillChangePlaymode) {
this.isPlaying = isPlaying;
this.isPaused = isPaused;
this.isPlayingOrWillChangePlaymode = isPlayingOrWillChangePlaymode;
}
}
private PlaymodeState prevPlaymodeState = new PlaymodeState(false, false, false);
private void OnStateChanged() {
if (EditorApplication.isPlayingOrWillChangePlaymode == false) {
profiler.StopProfiling();
} else if (startWithUnityPlayer == true && EditorApplication.isPlaying == true && prevPlaymodeState.isPlaying == false) {
this.remoteProfiling = false;
profiler.ipAddressString = DEFAULT_IP_ADDR;
profiler.StartProfiling(saveLogFile, logFileDir);
}
if (this.pauseWithUnityPlayer == true) {
this.isWindowPaused = EditorApplication.isPaused;
}
prevPlaymodeState = new PlaymodeState(EditorApplication.isPlaying, EditorApplication.isPaused, EditorApplication.isPlayingOrWillChangePlaymode);
}
#if UNITY_2017_2_OR_NEWER
private void OnPlayModeStateChanged(PlayModeStateChange state) {
OnStateChanged();
}
private void OnPauseStateChanged(PauseState state) {
OnStateChanged();
}
#endif
private void OnEnable() {
#if UNITY_2017_2_OR_NEWER
UnityEditor.EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
UnityEditor.EditorApplication.pauseStateChanged += OnPauseStateChanged;
#else
UnityEditor.EditorApplication.playmodeStateChanged += OnStateChanged;
#endif
}
private void OnDisable() {
if (profiler != null) {
profiler.StopProfiling();
}
DestroyResources();
#if UNITY_2017_2_OR_NEWER
UnityEditor.EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
UnityEditor.EditorApplication.pauseStateChanged -= OnPauseStateChanged;
#else
UnityEditor.EditorApplication.playmodeStateChanged -= OnStateChanged;
#endif
}
#endregion Unity Event Callbacks
#region Data Slice Definition
private struct DataSlicePerformance {
public readonly Single cpuLoad;
public readonly Single[] cpuLoadHistory;
public readonly UInt32 maxVoices;
public readonly UInt32 usedVoices;
public readonly UInt32[] voiceUsageHistory;
public readonly UInt32 maxStandardVoices;
public readonly int usedStandardVoices;
public readonly UInt32 maxHcaMxVoices;
public readonly int usedHcaMxVoices;
public readonly UInt32 usedStreams;
public readonly Single totalBps;
public DataSlicePerformance(CriProfiler profiler) {
this.cpuLoad = profiler.cpu_load;
this.cpuLoadHistory = profiler.CpuLoadHistory;
this.maxVoices =
profiler.maxVoice_stdStreaming +
profiler.maxVoice_hcamxStreaming +
profiler.maxVoice_stdOnMemory +
profiler.maxVoice_hcamxOnMemory;
this.usedVoices = profiler.num_used_voices;
this.voiceUsageHistory = profiler.VoiceUsageHistory;
this.maxStandardVoices = profiler.maxVoice_stdOnMemory + profiler.maxVoice_stdStreaming;
this.usedStandardVoices = profiler.GetVoicePoolUsage(CriProfiler.VoicePoolFormat.Standard);
this.maxHcaMxVoices = profiler.maxVoice_hcamxOnMemory + profiler.maxVoice_hcamxStreaming;
this.usedHcaMxVoices = profiler.GetVoicePoolUsage(CriProfiler.VoicePoolFormat.HcaMx);
this.usedStreams = profiler.num_used_streams;
this.totalBps = profiler.total_bps;
}
}
private struct DataSlicePlayback {
public readonly CriProfiler.PlaybackInfo[] playbackList;
public readonly StringBuilder playbackListString;
public readonly string cuenameLastPlayed;
public DataSlicePlayback(CriProfiler profiler) {
this.playbackList = profiler.PlaybackList;
this.playbackListString = new StringBuilder();
for (int i = 0; i < playbackList.Length; ++i) {
playbackListString.Append(playbackList[i].cueName + " ");
}
this.cuenameLastPlayed = string.IsNullOrEmpty(profiler.cuename_lastPlayed) ? "---" : profiler.cuename_lastPlayed + " (" + profiler.cuesheetName_lastPlayed + ")";
}
}
private struct DataSliceLoudness {
public readonly Single momentary;
public readonly Single shortTerm;
public readonly Single integrated;
public DataSliceLoudness(CriProfiler profiler) {
this.momentary = profiler.loudness_momentary;
this.shortTerm = profiler.loudness_shortTerm;
this.integrated = profiler.loudness_integrated;
}
}
private struct DataSliceLevels {
public readonly CriProfiler.LevelInfo[] levels;
public readonly int outputCh;
public DataSliceLevels(CriProfiler profiler) {
this.levels = profiler.LevelsAllCh;
this.outputCh = profiler.numChMasterOut;
}
}
private struct DataSliceLocalRuntime {
public readonly uint memUsageAtom;
public readonly uint memUsageFs;
public DataSliceLocalRuntime(bool isPlaying) {
if (isPlaying == true) {
memUsageAtom = CriAtomPlugin.IsLibraryInitialized() ? CriWare.Common.GetAtomMemoryUsage() : 0;
memUsageFs = CriFsPlugin.IsLibraryInitialized() ? CriWare.Common.GetFsMemoryUsage() : 0;
} else {
memUsageAtom = 0;
memUsageFs = 0;
}
}
}
#endregion Data Slice Definition
#region Internal Fields
/* configurations */
private const Single DB_MIN = -96.0f;
private const Single DB_MAX = 20.0f;
private const Single DEFAULT_DB_FLOOR = -48.0f;
private const Single DEFAULT_DB_CEILING = 0;
private const Single DEFAULT_DB_TARGET = -24.0f;
private const Single DB_RANGE_PLUSMINUS_MAX = 20.0f;
private const Single DB_RANGE_PLUSMINUS_MIN = 0;
private const Single DEFAULT_DB_RANGE_PLUSMINUS = 2.0f;
private const Single DEFAULT_DB_WARNING = -6.0f;
private const Single DEFAULT_LEVEL_FLOOR = -48.0f;
private const Single DEFAULT_LEVEL_CEILING = 0;
private const Single DEFAULT_LEVEL_WARNING = -6.0f;
private const int DEFAULT_LEVEL_CAL_INTVL = 6;
private const int DEFAULT_LEVEL_CAL_INTVL_MIN = 1;
private const int DEFAULT_LEVEL_CAL_INTVL_MAX = 24;
private const MultiChannelMeterType DEFAULT_LEVEL_TYPE = MultiChannelMeterType.Peak;
private const string DEFAULT_IP_ADDR = "127.0.0.1";
[SerializeField] private bool startWithUnityPlayer = true;
[SerializeField] private bool pauseWithUnityPlayer = true;
[SerializeField] private bool saveLogFile = false;
[SerializeField] private string logFileDir = "";
[SerializeField] private bool remoteProfiling = false;
[SerializeField] private bool isWindowPaused = false;
[SerializeField] private Single currentDbFloor = DEFAULT_DB_FLOOR;
[SerializeField] private Single currentDbCeiling = DEFAULT_DB_CEILING;
[SerializeField] private Single currentDbTarget = DEFAULT_DB_TARGET;
[SerializeField] private Single currentDbRangePlusMinus = DEFAULT_DB_RANGE_PLUSMINUS;
[SerializeField] private Single currentDbWarning = DEFAULT_DB_WARNING;
[SerializeField] private Single currentLevelFloor = DEFAULT_LEVEL_FLOOR;
[SerializeField] private Single currentLevelCeiling = DEFAULT_LEVEL_CEILING;
[SerializeField] private Single currentLevelWarning = DEFAULT_LEVEL_WARNING;
[SerializeField] private int currentLevelCalInterval = DEFAULT_LEVEL_CAL_INTVL;
[SerializeField] private MultiChannelMeterType currentLevelType = DEFAULT_LEVEL_TYPE;
/* GUI constants */
private const float LABEL_WIDTH = 148.0f;
private const float CHART_INDENT_WIDTH = 15.0f;
private const float GUI_INDENT_WIDTH = 15.0f;
private const int TEXT_SIZE_CALIBRATOR = 10;
private const int TEXT_SIZE_LABEL = 11;
private const int TEXT_SIZE_CUE_LIST = 12;
private const int TEXT_SIZE_GIANT = 20;
private const int LOG_ITEM_HEIGHT = 20;
static private Vector2 textOffsetChartTitle = new Vector2(3.0f, 2.0f);
static private Vector2 textOffsetCalibrator = new Vector2(-4.0f, -6.0f);
static private Color colorWarningHigh = new Color(224 / 255.0f, 44 / 255.0f, 44 / 255.0f);
static private Color colorWarningHighTolerant = new Color(244 / 255.0f, 170 / 255.0f, 44 / 255.0f);
static private Color colorMidRange = new Color(107 / 255.0f, 224 / 255.0f, 44 / 255.0f);
static private Color colorWarningLow = new Color(44 / 255.0f, 107 / 255.0f, 224 / 255.0f);
static private Color colorGrid = new Color(0.2f, 0.2f, 0.2f);
private const int CNT_CUSTOM_STYLES = 20;
static private GUIStyle[] customStyles = new GUIStyle[CNT_CUSTOM_STYLES];
static private Texture2D[] customStyleTex = new Texture2D[CNT_CUSTOM_STYLES];
private GUIStyle barBorderStyle { get { return InitializeStyleWithBgColor(0, Color.gray); } }
private GUIStyle barBackgroundStyle { get { return InitializeStyleWithBgColor(1, Color.black); } }
private GUIStyle barStyle { get { return InitializeStyleWithBgColor(2, Color.gray); } }
private GUIStyle barWarningHighStyle { get { return InitializeStyleWithBgColor(3, colorWarningHigh); } }
private GUIStyle barWarningHighTolerantStyle { get { return InitializeStyleWithBgColor(4, colorWarningHighTolerant); } }
private GUIStyle barMidRangeStyle { get { return InitializeStyleWithBgColor(5, colorMidRange); } }
private GUIStyle barWarningLowStyle { get { return InitializeStyleWithBgColor(6, colorWarningLow); } }
private GUIStyle barTextStyle { get { return InitializeTextStyle(7, TEXT_SIZE_LABEL, Color.white, TextAnchor.UpperLeft); } }
private GUIStyle barTextShadowStyle { get { return InitializeTextStyle(8, TEXT_SIZE_LABEL, Color.black, TextAnchor.UpperLeft); } }
private GUIStyle meterTextWarningHighStyle { get { return InitializeTextStyle(9, TEXT_SIZE_GIANT, colorWarningHigh, TextAnchor.MiddleCenter); } }
private GUIStyle meterTextWarningHighTolerantStyle { get { return InitializeTextStyle(10, TEXT_SIZE_GIANT, colorWarningHighTolerant, TextAnchor.MiddleCenter); } }
private GUIStyle meterTextMidRangeStyle { get { return InitializeTextStyle(11, TEXT_SIZE_GIANT, colorMidRange, TextAnchor.MiddleCenter); } }
private GUIStyle meterTextWarningLowStyle { get { return InitializeTextStyle(12, TEXT_SIZE_GIANT, colorWarningLow, TextAnchor.MiddleCenter); } }
private GUIStyle multiChMeterTextStyle { get { return InitializeTextStyle(13, TEXT_SIZE_LABEL, Color.white, TextAnchor.MiddleCenter); } }
private GUIStyle cueListStyle { get { return InitializeTextStyle(14, TEXT_SIZE_CUE_LIST, Color.white, TextAnchor.UpperLeft, s => {
s.fontStyle = FontStyle.Bold;
s.wordWrap = true;
}); } }
private GUIStyle chartLabelStyle { get { return InitializeTextStyle(15, TEXT_SIZE_CALIBRATOR, Color.gray, TextAnchor.UpperRight); } }
private GUIStyle timelineHeaderStyle { get { return InitializeStyleWithBgColor(16, new Color(0.15f, 0.15f, 0.15f)); } }
private GUIStyle timelineStyle { get { return InitializeStyleWithBgColor(17, new Color(0.1f, 0.1f, 0.1f)); } }
private GUIStyle timelineButtonStyle { get { return InitializeStyleWithGradColor(18, new Color(0.8f, 0.8f, 0.8f), new Color(0.7f, 0.7f, 0.7f), s => {
s.fixedHeight = 18;
s.alignment = TextAnchor.MiddleCenter;
s.clipping = TextClipping.Clip;
s.margin = new RectOffset(1, 1, 1, 1);
s.padding = new RectOffset(1, 1, 1, 1);
}); } }
private GUIStyle timelineCueSheetStyle { get { return InitializeStyleWithGradColor(19, new Color(0.4f, 0.4f, 0.4f), new Color(0.3f, 0.3f, 0.3f), s => {
s.alignment = TextAnchor.MiddleCenter;
s.clipping = TextClipping.Clip;
s.fontStyle = FontStyle.Bold;
s.normal.textColor = Color.white;
s.margin = new RectOffset(1, 1, 1, 1);
s.padding = new RectOffset(1, 1, 1, 1);
}); } }
private delegate void AdditionalStyleDelegate(GUIStyle style);
static private Color[] chartGradientColors = new Color[] {
Color.green,
Color.green * 0.8f + Color.yellow * 0.2f,
Color.green * 0.6f + Color.yellow * 0.4f,
Color.green * 0.4f + Color.yellow * 0.6f,
Color.green * 0.2f + Color.yellow * 0.8f,
Color.yellow,
Color.yellow * 0.8f + Color.red * 0.2f,
Color.yellow * 0.6f + Color.red * 0.4f,
Color.yellow * 0.4f + Color.red * 0.6f,
Color.yellow * 0.2f + Color.red * 0.8f,
Color.red
};
/* GUI variables */
[SerializeField] private bool foldTogglerConfig = false;
[SerializeField] private bool foldTogglerExperimental = false;
[SerializeField] private bool foldTogglerPerformance = true;
[SerializeField] private bool foldTogglerPlayingList = true;
[SerializeField] private bool foldTogglerLoudness = true;
[SerializeField] private bool foldTogglerLoudnessAppearance = false;
[SerializeField] private bool foldTogglerLevels = true;
[SerializeField] private bool foldTogglerLevelAppearance = false;
[SerializeField] private bool foldTogglerTimeline = true;
[SerializeField] private bool foldTogglerLogList = true;
[SerializeField] private bool timelineAutoScroll = true;
private Vector2 monitorPanelScrollPos;
private Vector2 timelinePanelScrollPos;
private Vector2 logListPanelScrollPos;
private Vector2 logListScrollPos;
private Vector2 textareaScrollViewPostion;
private int logItemCount = 0;
private bool isLogItemCountChanged = false;
private int logViewCount = 0;
private int logFirstViewIndex = 0;
private bool refreshLogListOnce = false;
private List<byte[]> logViewSubList = null;
private Color currentGuiColor;
private Rect timelineWinRect;
private Shader m_shader;
private Material m_mat;
private Material mat {
get {
if (m_shader == null) {
#if UNITY_5_2 || UNITY_5_3 || UNITY_5_4_OR_NEWER
m_shader = Shader.Find("Hidden/Internal-Colored");
#else
m_shader = Shader.Find("Sprites/Default");
#endif
}
if (m_mat == null && m_shader != null) {
m_mat = new Material(m_shader);
} else if (m_mat.shader != m_shader) {
DestroyImmediate(m_mat);
m_mat = new Material(m_shader);
}
return m_mat;
}
}
private StringBuilder gStrBuilder = new StringBuilder(50);
private StringBuilder gStrBuilderSub = new StringBuilder(50);
/* Data slices */
private DataSlicePerformance perfData = new DataSlicePerformance(profiler);
private DataSlicePlayback playbackData = new DataSlicePlayback(profiler);
private DataSliceLoudness loudnessData = new DataSliceLoudness(profiler);
private DataSliceLevels levelsData = new DataSliceLevels(profiler);
private DataSliceLocalRuntime runtimeData = new DataSliceLocalRuntime(false);
private Dictionary<string, CriProfiler.CueSheetGroup> timeline = null;
private ulong firstTimeStamp = 0;
private ulong currentTimeStamp = 0;
private CriProfiler.Playback? currentTimelinePlayback = null;
private GUIStyle InitializeStyleWithBgColor(int id, Color color, AdditionalStyleDelegate func = null) {
if (customStyleTex[id] == null) {
customStyleTex[id] = new Texture2D(1, 1, TextureFormat.RGB24, false);
customStyleTex[id].SetPixel(1, 1, color);
customStyleTex[id].Apply();
}
if (customStyles[id] == null) {
customStyles[id] = new GUIStyle();
if (func != null) {
func(customStyles[id]);
}
}
customStyles[id].normal.background = customStyleTex[id];
return customStyles[id];
}
private GUIStyle InitializeStyleWithGradColor(int id, Color color1, Color color2, AdditionalStyleDelegate func = null) {
if (customStyleTex[id] == null) {
customStyleTex[id] = new Texture2D(1, 4, TextureFormat.RGB24, false);
customStyleTex[id].SetPixel(1, 1, color2);
customStyleTex[id].SetPixel(1, 2, color1);
customStyleTex[id].SetPixel(1, 3, color1);
customStyleTex[id].SetPixel(1, 4, color2);
customStyleTex[id].Apply();
}
if (customStyles[id] == null) {
customStyles[id] = new GUIStyle();
if (func != null) {
func(customStyles[id]);
}
}
customStyles[id].normal.background = customStyleTex[id];
return customStyles[id];
}
private GUIStyle InitializeTextStyle(int id, int size, Color color, TextAnchor anchor, AdditionalStyleDelegate func = null) {
if (customStyles[id] == null) {
customStyles[id] = new GUIStyle();
customStyles[id].normal.textColor = color;
customStyles[id].fontSize = size;
customStyles[id].alignment = anchor;
if (func != null) {
func(customStyles[id]);
}
}
return customStyles[id];
}
private void DestroyResources() {
if (m_mat != null) {
DestroyImmediate(m_mat);
}
}
#endregion Internal Fields
#region Const strings on GUI
private const string S_DIVIDER = " / ";
private const string S_NAN = "-";
private readonly GUIContent S_LOGFILEDIR = new GUIContent("Log file directory", "leave empty to use default location");
private readonly GUIContent GC_LEVELRANGE = new GUIContent("Disp. Range (dB)");
private readonly string[] S_MultiChMeterButton = { "Peak", "RMS" };
private readonly string[] S_ChannelNames = { "L", "R", "C", "LFE", "Ls", "Rs", "Ex1", "Ex2" };
#endregion Const strings on GUI
#region OnGUI
private void OnGUI() {
GUILayoutOption buttonHeightSetting = GUILayout.Height(25);
this.currentGuiColor = GUI.color;
using (var globalHorizontal = new GUILayout.HorizontalScope()) {
using (var leftPaneVertical = new GUILayout.VerticalScope(GUILayout.Width(430))) {
GUILayout.Space(5.0f);
using (var startControlHorizontal = new GUILayout.HorizontalScope()) {
GUI.enabled = EditorApplication.isPlaying || remoteProfiling;
if (profiler.IsProfiling == false) {
if (GUILayout.Button("Start", buttonHeightSetting)) {
profiler.StartProfiling(saveLogFile, logFileDir);
this.isWindowPaused = false;
}
} else {
if (GUILayout.Button("Stop", buttonHeightSetting)) {
profiler.StopProfiling();
}
}
GUI.enabled = profiler.IsProfiling;
if (this.isWindowPaused == false) {
if (GUILayout.Button("Pause", buttonHeightSetting)) {
this.isWindowPaused = true;
}
} else {
if (GUILayout.Button("Resume", buttonHeightSetting)) {
this.isWindowPaused = false;
}
}
GUI.enabled = true;
}
using (var monitorScrollView = new GUILayout.ScrollViewScope(monitorPanelScrollPos)) {
monitorPanelScrollPos = monitorScrollView.scrollPosition;
DrawConfigurationInfo();
GUILayout.Label("Monitoring", EditorStyles.whiteBoldLabel);
DrawrPerformanceInfo();
DrawrPlaybackInfo();
DrawLoudnessInfo();
DrawLevelsInfo();
GUILayout.Space(20.0f);
}
}
using (var rightPaneVertical = new GUILayout.VerticalScope()) {
DrawTimeline();
DrawLogList();
}
}
this.Repaint();
}
private void DrawConfigurationInfo() {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
foldTogglerConfig = CriFoldout(foldTogglerConfig, "Configuration");
if (foldTogglerConfig) {
EditorGUI.indentLevel++;
startWithUnityPlayer = EditorGUILayout.Toggle("Start with Player", startWithUnityPlayer);
pauseWithUnityPlayer = EditorGUILayout.Toggle("Pause with Player", pauseWithUnityPlayer);
saveLogFile = EditorGUILayout.Toggle("Save log file", saveLogFile);
GUI.enabled = saveLogFile;
EditorGUI.indentLevel++;
logFileDir = EditorGUILayout.TextField(S_LOGFILEDIR, profiler.LogFileSavePath);
EditorGUI.indentLevel--;
GUI.enabled = true;
foldTogglerExperimental = CriFoldout(foldTogglerExperimental, "Experimental");
if (foldTogglerExperimental) {
EditorGUI.indentLevel++;
GUI.enabled = (profiler.IsProfiling == false);
remoteProfiling = EditorGUILayout.Toggle("Remote Profiling", remoteProfiling);
if (remoteProfiling == false) {
profiler.ipAddressString = DEFAULT_IP_ADDR;
}
GUI.enabled = remoteProfiling && (profiler.IsProfiling == false);
profiler.ipAddressString = EditorGUILayout.TextField("IP Address", profiler.ipAddressString);
GUI.enabled = true;
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawrPerformanceInfo() {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
foldTogglerPerformance = CriFoldout(foldTogglerPerformance, "Performance");
if (foldTogglerPerformance) {
if (isWindowPaused == false) {
perfData = new DataSlicePerformance(profiler);
if (this.remoteProfiling == false) {
runtimeData = new DataSliceLocalRuntime(EditorApplication.isPlaying);
}
}
EditorGUI.indentLevel++;
Rect chartRect = EditorGUILayout.GetControlRect(GUILayout.Height(80));
chartRect.xMin += CHART_INDENT_WIDTH;
LineGraph(chartRect, ClearedStr.Append("CPU Usage: ").AppendFormat("{0:F2}", perfData.cpuLoad).Append("%").ToString(), perfData.cpuLoadHistory, 100.0f, 5, 5.0f, true);
chartRect = EditorGUILayout.GetControlRect(GUILayout.Height(80));
chartRect.xMin += CHART_INDENT_WIDTH;
LineGraph(chartRect, ClearedStr.Append("Number of Voices: ").Append(perfData.usedVoices).Append(S_DIVIDER).Append(perfData.maxVoices).ToString(), Array.ConvertAll(perfData.voiceUsageHistory, x => (float)x), perfData.maxVoices, 5, 4.0f, false);
GUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("Standard Pool Usage", GUILayout.Width(LABEL_WIDTH));
SimpleBarGraph(EditorGUILayout.GetControlRect(), perfData.usedStandardVoices, 0, perfData.maxStandardVoices,
ClearedStr.Append(perfData.usedStandardVoices >= 0 ? perfData.usedStandardVoices.ToString() : S_NAN)
.Append(S_DIVIDER)
.Append(perfData.maxStandardVoices > 0 ? perfData.maxStandardVoices.ToString() : S_NAN)
.ToString());
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("HCA-MX Pool Usage", GUILayout.Width(LABEL_WIDTH));
SimpleBarGraph(EditorGUILayout.GetControlRect(), perfData.usedHcaMxVoices, 0, perfData.maxHcaMxVoices,
ClearedStr.Append(perfData.usedHcaMxVoices >= 0 ? perfData.usedHcaMxVoices.ToString() : S_NAN)
.Append(S_DIVIDER)
.Append(perfData.maxHcaMxVoices > 0 ? perfData.maxHcaMxVoices.ToString() : S_NAN)
.ToString());
}
GUILayout.EndHorizontal();
if (this.remoteProfiling == false) {
EditorGUILayout.LabelField("Atom Memory Usage", DataSize2String(runtimeData.memUsageAtom));
EditorGUILayout.LabelField("FS Memory Usage", DataSize2String(runtimeData.memUsageFs));
}
EditorGUILayout.LabelField("Streaming Usage", ClearedStr.Append(perfData.usedStreams).Append(" voice(s) (").AppendFormat("{0:F2}", perfData.totalBps / 1000000).Append(" Mbps)").ToString());
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawrPlaybackInfo() {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
foldTogglerPlayingList = CriFoldout(foldTogglerPlayingList, "Playing");
if (foldTogglerPlayingList) {
if (isWindowPaused == false) {
playbackData = new DataSlicePlayback(profiler);
}
GUILayout.BeginHorizontal();
{
GUILayout.Space(GUI_INDENT_WIDTH);
textareaScrollViewPostion = GUILayout.BeginScrollView(new Vector2(textareaScrollViewPostion.x, Mathf.Infinity), EditorStyles.helpBox, GUILayout.Height(60));
GUILayout.Label(playbackData.playbackListString.ToString(), cueListStyle, GUILayout.ExpandHeight(true));
GUILayout.EndScrollView();
}
GUILayout.EndHorizontal();
EditorGUI.indentLevel++;
EditorGUILayout.LabelField("Last Played", ClearedStr.Append("[ ").Append(playbackData.cuenameLastPlayed).Append(" ]").ToString());
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawLoudnessInfo() {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
foldTogglerLoudness = CriFoldout(foldTogglerLoudness, "Loudness");
if (foldTogglerLoudness) {
if (isWindowPaused == false) {
loudnessData = new DataSliceLoudness(profiler);
}
Rect chartRect;
GUILayoutOption[] numberRectGUISettings = { GUILayout.Height(60), GUILayout.MinWidth(60) };
GUILayoutOption barHeightSetting = GUILayout.Height(15);
const float paddingOffset = 2.0f;
GUILayout.BeginHorizontal();
{
chartRect = EditorGUILayout.GetControlRect(numberRectGUISettings);
chartRect.x += CHART_INDENT_WIDTH;
NumericMeter(chartRect, "Momentary LKFS", loudnessData.momentary);
chartRect = EditorGUILayout.GetControlRect(numberRectGUISettings);
chartRect.x += CHART_INDENT_WIDTH - paddingOffset;
NumericMeter(chartRect, "Short Term LKFS", loudnessData.shortTerm);
chartRect = EditorGUILayout.GetControlRect(numberRectGUISettings);
chartRect.xMin += CHART_INDENT_WIDTH - paddingOffset * 2;
NumericMeter(chartRect, "Integrated LKFS", loudnessData.integrated);
}
GUILayout.EndHorizontal();
chartRect = EditorGUILayout.GetControlRect(barHeightSetting);
chartRect.xMin += CHART_INDENT_WIDTH;
LoudnessBarGraph(chartRect, loudnessData.momentary, currentDbFloor, currentDbCeiling, currentDbTarget, currentDbRangePlusMinus, currentDbWarning, "Momentary");
chartRect = EditorGUILayout.GetControlRect(barHeightSetting);
chartRect.xMin += CHART_INDENT_WIDTH;
LoudnessBarGraph(chartRect, loudnessData.shortTerm, currentDbFloor, currentDbCeiling, currentDbTarget, currentDbRangePlusMinus, currentDbWarning, "Short Term");
chartRect = EditorGUILayout.GetControlRect(barHeightSetting);
chartRect.xMin += CHART_INDENT_WIDTH;
LoudnessBarGraph(chartRect, loudnessData.integrated, currentDbFloor, currentDbCeiling, currentDbTarget, currentDbRangePlusMinus, currentDbWarning, "Integrated");
EditorGUI.indentLevel++;
foldTogglerLoudnessAppearance = CriFoldout(foldTogglerLoudnessAppearance, "Appearance");
if (foldTogglerLoudnessAppearance) {
EditorGUI.indentLevel++;
EditorGUILayout.MinMaxSlider(GC_LEVELRANGE, ref currentDbFloor, ref currentDbCeiling, DB_MIN, DB_MAX);
EditorGUILayout.LabelField(" ", ClearedStr.Append("Min: ").AppendFormat("{0:F2}", currentDbFloor).Append(S_DIVIDER).Append("Max: ").AppendFormat("{0:F2}", currentDbCeiling).ToString());
currentDbTarget = EditorGUILayout.Slider("Target (dB)", currentDbTarget, DB_MIN, DB_MAX);
currentDbRangePlusMinus = EditorGUILayout.Slider("Tgt. Range (+/-dB)", currentDbRangePlusMinus, DB_RANGE_PLUSMINUS_MIN, DB_RANGE_PLUSMINUS_MAX);
currentDbWarning = EditorGUILayout.Slider("Warning (dB)", currentDbWarning, DB_MIN, DB_MAX);
GUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("", GUILayout.Width(LABEL_WIDTH));
if (GUILayout.Button("Reset", GUILayout.ExpandWidth(false))) {
currentDbFloor = DEFAULT_DB_FLOOR;
currentDbCeiling = DEFAULT_DB_CEILING;
currentDbTarget = DEFAULT_DB_TARGET;
currentDbRangePlusMinus = DEFAULT_DB_RANGE_PLUSMINUS;
currentDbWarning = DEFAULT_DB_WARNING;
}
}
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawLevelsInfo() {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
foldTogglerLevels = CriFoldout(foldTogglerLevels, "Peak / RMS");
if (foldTogglerLevels) {
if (isWindowPaused == false) {
levelsData = new DataSliceLevels(profiler);
}
GUILayout.BeginHorizontal();
{
GUILayout.Space(GUI_INDENT_WIDTH);
currentLevelType = (MultiChannelMeterType)GUILayout.Toolbar((int)currentLevelType, S_MultiChMeterButton);
}
GUILayout.EndHorizontal();
Rect chartRect = EditorGUILayout.GetControlRect(GUILayout.Height(200));
chartRect.xMin += CHART_INDENT_WIDTH;
MultiChannelMeter(chartRect, levelsData.levels, levelsData.outputCh, currentLevelType, currentLevelFloor, currentLevelCeiling, currentLevelWarning, S_MultiChMeterButton[(int)currentLevelType]);
EditorGUI.indentLevel++;
foldTogglerLevelAppearance = CriFoldout(foldTogglerLevelAppearance, "Appearance");
if (foldTogglerLevelAppearance) {
EditorGUI.indentLevel++;
EditorGUILayout.MinMaxSlider(GC_LEVELRANGE, ref currentLevelFloor, ref currentLevelCeiling, DB_MIN, DB_MAX);
EditorGUILayout.LabelField(" ", ClearedStr.Append("Min: ").AppendFormat("{0:F2}", currentLevelFloor).Append(S_DIVIDER).Append("Max: ").AppendFormat("{0:F2}", currentLevelCeiling).ToString());
currentLevelWarning = EditorGUILayout.Slider("Warning (dB)", currentLevelWarning, DB_MIN, DB_MAX);
currentLevelCalInterval = EditorGUILayout.IntSlider("Grid Interval (dB)", currentLevelCalInterval, DEFAULT_LEVEL_CAL_INTVL_MIN, DEFAULT_LEVEL_CAL_INTVL_MAX);
GUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("", GUILayout.Width(LABEL_WIDTH));
if (GUILayout.Button("Reset", GUILayout.ExpandWidth(false))) {
currentLevelFloor = DEFAULT_LEVEL_FLOOR;
currentLevelCeiling = DEFAULT_LEVEL_CEILING;
currentLevelWarning = DEFAULT_LEVEL_WARNING;
currentLevelCalInterval = DEFAULT_LEVEL_CAL_INTVL;
}
}
GUILayout.EndHorizontal();
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
private void DrawTimeline() {
const float timeScaleFromMicroSec = 0.00005f;
if (Event.current.type == EventType.Layout) {
if (this.isWindowPaused == false && profiler.IsProfiling) {
this.timeline = profiler.TimelineDataSlice;
this.firstTimeStamp = profiler.timestampStart;
this.currentTimeStamp = profiler.timestamp;
}
}
using (var scope = new GUILayout.HorizontalScope("ToolBar")) {
this.foldTogglerTimeline = GUILayout.Toggle(this.foldTogglerTimeline, "Timeline", EditorStyles.toolbarButton, GUILayout.Width(100));
GUILayout.Label(currentTimelinePlayback.HasValue ? currentTimelinePlayback.Value.cuename + " (" + currentTimelinePlayback.Value.cuesheet + ") started at " + MicroSec2String(currentTimelinePlayback.Value.timestamp) : " ");
this.timelineAutoScroll = GUILayout.Toggle(this.timelineAutoScroll, "Auto Scroll", EditorStyles.toolbarButton, GUILayout.Width(100));
}
if (this.foldTogglerTimeline == false) { return; }
GUI.color = Color.white;
EditorGUILayout.BeginHorizontal();
var heightStyle = this.foldTogglerLogList ? GUILayout.MinHeight(300) : GUILayout.ExpandHeight(true);
/* CueSheet Group */
using (var scrollView = new GUILayout.ScrollViewScope(new Vector2(0, timelinePanelScrollPos.y), false, false, GUIStyle.none, GUIStyle.none, timelineHeaderStyle, heightStyle, GUILayout.Width(100))) {
GUILayout.Space(0);
if (timeline != null && timeline.Count > 0) foreach (var elem in timeline) {
GUI.color = elem.Value.cuesheetColor;
GUILayout.Label(elem.Value.name, timelineCueSheetStyle, GUILayout.Height((timelineButtonStyle.fixedHeight + 1) * elem.Value.TotalLaneCount - 1));
GUI.color = Color.white;
}
GUILayout.Space(18);
}
/* Timeline */
using (var scrollView = new GUILayout.ScrollViewScope(timelinePanelScrollPos, timelineStyle, heightStyle)) {
float timelinePixelLength = (this.currentTimeStamp - this.firstTimeStamp) * timeScaleFromMicroSec;
timelinePanelScrollPos = (this.timelineAutoScroll && this.isWindowPaused == false && profiler.IsProfiling) ? new Vector2(Mathf.Max(0, timelinePixelLength + 12 - this.timelineWinRect.width), scrollView.scrollPosition.y) : scrollView.scrollPosition;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical(GUILayout.Width(timelinePixelLength));
if (timeline == null || timeline.Count <= 0) {
GUILayout.Space(timelinePixelLength);
} else {
foreach (var cuesheetGroup in timeline) {
EditorGUILayout.BeginVertical();
foreach (var cuelane in cuesheetGroup.Value.cueLaneDict) {
EditorGUILayout.BeginVertical();
for (int j = 0; j < cuelane.Value.playbackLaneList.Count; ++j) {
EditorGUILayout.BeginHorizontal();
var pbList = cuelane.Value.playbackLaneList[j].playbackList;
bool firstPlaybackDrawn = false;
if (timelinePanelScrollPos.x > 0) {
GUILayout.Space(timelinePanelScrollPos.x);
}
for (int k = 0; k < pbList.Count; ++k) {
float posRelative = ((long)pbList[k].timestamp - (long)this.firstTimeStamp) * timeScaleFromMicroSec - timelinePanelScrollPos.x;
if (posRelative > this.timelineWinRect.width) { break; } /* skip invisible */
if (pbList[k].isStart) {
float currentLength = 0;
float priorSpaceWidth = 0;
if (k < pbList.Count - 1) {
if (((long)pbList[k + 1].timestamp - (long)this.firstTimeStamp) * timeScaleFromMicroSec - timelinePanelScrollPos.x < 0) { /* skip invisible */
k++;
continue;
}
currentLength = ((long)pbList[k + 1].timestamp - (long)pbList[k].timestamp) * timeScaleFromMicroSec;
} else {
currentLength = ((long)this.currentTimeStamp - (long)pbList[k].timestamp) * timeScaleFromMicroSec;
}
currentLength = Mathf.Min(currentLength + Mathf.Min(0, posRelative), this.timelineWinRect.width - Mathf.Max(0, posRelative));
if (firstPlaybackDrawn == false) {
priorSpaceWidth = Mathf.Max(0, posRelative);
} else {
priorSpaceWidth = ((long)pbList[k].timestamp - (long)pbList[k - 1].timestamp) * timeScaleFromMicroSec;
}
GUILayout.Space(priorSpaceWidth);
GUI.color = cuelane.Value.cueColor;
DrawPlaybackEventButton(pbList[k], currentLength);
GUI.color = Color.white;
firstPlaybackDrawn = true;
} else if (firstPlaybackDrawn == false && posRelative > 0) {
GUI.color = cuelane.Value.cueColor;
DrawPlaybackEventButton(pbList[k], posRelative);
GUI.color = Color.white;
firstPlaybackDrawn = true;
}
}
if (firstPlaybackDrawn == false) {
GUILayout.Label("", timelineButtonStyle, GUILayout.Width(0)); /* empty lane */
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndVertical();
}
}
EditorGUILayout.EndVertical();
GUILayout.Box("", barBorderStyle, GUILayout.Width(1), GUILayout.ExpandHeight(true));
GUILayout.Box("", barBorderStyle, GUILayout.Width(2), GUILayout.Height(30));
GUILayout.Space(9);
EditorGUILayout.EndHorizontal();
}
if (Event.current.type == EventType.Repaint) {
this.timelineWinRect = GUILayoutUtility.GetLastRect();
}
EditorGUILayout.EndHorizontal();
GUI.color = this.currentGuiColor;
}
private void DrawPlaybackEventButton(CriProfiler.Playback playback, float width) {
if (GUILayout.Button(playback.cuename, timelineButtonStyle, GUILayout.Width(width - 1), GUILayout.MinWidth(-100))) {
this.currentTimelinePlayback = playback;
this.timelineAutoScroll = false;
}
}
private void DrawLogList() {
if (Event.current.type == EventType.Layout && ((this.isWindowPaused == false && profiler.IsProfiling) || refreshLogListOnce)) {
refreshLogListOnce = false;
int logListlen = profiler.GetLogList().Count;
if (this.logItemCount != logListlen) {
this.logItemCount = logListlen;
this.isLogItemCountChanged = true;
}
this.logViewCount = (int)position.height / LOG_ITEM_HEIGHT;
this.logFirstViewIndex = Mathf.Clamp((int)logListScrollPos.y / LOG_ITEM_HEIGHT, 0, Mathf.Max(0, logItemCount - logViewCount));
this.logViewSubList = profiler.GetLogList(logFirstViewIndex, logViewCount);
}
using (var scope = new GUILayout.HorizontalScope("ToolBar", GUILayout.ExpandWidth(true))) {
this.foldTogglerLogList = GUILayout.Toggle(this.foldTogglerLogList, "Event Log", EditorStyles.toolbarButton, GUILayout.Width(100));
GUILayout.Label(logItemCount.ToString() + " lines", EditorStyles.miniLabel);
if (GUILayout.Button("Open Log File", EditorStyles.toolbarButton, GUILayout.Width(120))) {
var path = EditorUtility.OpenFilePanel("Open Log File", profiler.LogFileSavePath, CriProfiler.LOG_FILE_EXTENSION);
if (string.IsNullOrEmpty(path) == false) {
profiler.ClearLog();
profiler.LoadLogFromFile(path);
refreshLogListOnce = true;
}
}
if (GUILayout.Button("Clear Log", EditorStyles.toolbarButton, GUILayout.Width(100))) {
profiler.ClearLog();
refreshLogListOnce = true;
}
}
if (this.foldTogglerLogList == false) { return; }
using (var scrollView = new GUILayout.ScrollViewScope(logListPanelScrollPos, "CN Box")) {
logListPanelScrollPos = scrollView.scrollPosition;
if (this.isLogItemCountChanged) {
this.isLogItemCountChanged = false;
this.logListScrollPos = new Vector2(0, logItemCount * LOG_ITEM_HEIGHT);
}
logListScrollPos = GUILayout.BeginScrollView(logListScrollPos);
{
/* only render visible UI elements */
if (logViewSubList != null) {
GUILayout.Space(logFirstViewIndex * LOG_ITEM_HEIGHT);
for (int i = 0; i < logViewSubList.Count; i++) {
GUILayout.Label(profiler.FilteredLog2String(logViewSubList[i]), EditorStyles.textArea, GUILayout.Height(LOG_ITEM_HEIGHT));
}
GUILayout.Space(Mathf.Max(0, logItemCount - logFirstViewIndex - logViewCount) * LOG_ITEM_HEIGHT);
}
}
GUILayout.EndScrollView();
}
}
#endregion OnGUI
#region Drawing Functions
private void SimpleBarGraph(UnityEngine.Rect rect, Single val, Single min, Single max, String text) {
Single ratio = Value2Ratio(val, min, max);
UnityEngine.GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
rect.xMax--;
rect.yMax--;
UnityEngine.GUI.Box(rect, "", barBackgroundStyle);
if (Event.current.type == EventType.Repaint) {
if (ratio > 0.0f) {
Rect barRect = rect;
if (ratio > 0.999999f) {
UnityEngine.GUI.Box(barRect, "", barWarningHighStyle);
} else {
barRect.width *= ratio;
UnityEngine.GUI.Box(barRect, "", barStyle);
}
}
}
rect.xMin += 2;
UnityEngine.GUI.Label(new Rect(rect.x + 1, rect.y + 1, rect.width, rect.height), text, barTextShadowStyle);
UnityEngine.GUI.Label(rect, text, barTextStyle);
}
private void LoudnessBarGraph(
UnityEngine.Rect rect,
Single val,
Single min,
Single max,
Single valTarget,
Single valRangePlusMinus,
Single valWarningHigh,
String text)
{
Single ratio = Value2Ratio(val, min, max);
Single ratioTarget = Value2Ratio(valTarget, min, max);
Single ratioRange = Value2Ratio(min + valRangePlusMinus, min, max);
Single ratioWarning = Value2Ratio(valWarningHigh, min, max);
UnityEngine.GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
rect.xMax--;
rect.yMax--;
UnityEngine.GUI.Box(rect, "", barBackgroundStyle);
if (Event.current.type == EventType.Repaint) {
if (ratio > 0.0f) {
Rect barRect = rect;
if (ratio > ratioWarning) {
barRect.width = rect.width * ratio;
UnityEngine.GUI.Box(barRect, "", barWarningHighStyle);
}
if (ratio > ratioTarget + ratioRange) {
barRect.width = rect.width * Mathf.Min(ratio, ratioWarning);
UnityEngine.GUI.Box(barRect, "", barWarningHighTolerantStyle);
}
if (ratio > ratioTarget - ratioRange) {
barRect.width = rect.width * Mathf.Min(ratio, ratioTarget + ratioRange);
UnityEngine.GUI.Box(barRect, "", barMidRangeStyle);
}
if (ratio > 0) {
barRect.width = rect.width * Mathf.Max(0, Mathf.Min(ratio, ratioTarget - ratioRange));
UnityEngine.GUI.Box(barRect, "", barWarningLowStyle);
}
}
}
rect.xMin += 2;
UnityEngine.GUI.Label(new Rect(rect.x + 1, rect.y + 1, rect.width, rect.height), text, barTextShadowStyle);
UnityEngine.GUI.Label(rect, text, barTextStyle);
}
/* Positive values only */
private void LineGraph(Rect rect, string title, float[] data, float maxVal, int sections, float minInterVal, bool adaptiveScale) {
const float titleHeight = 20;
const float labelWidth = 30;
const float labelHeight = 10.0f;
float cellHeight = 0;
int count = 0;
Rect labelRect;
float currentMaxVal = maxVal;
if(adaptiveScale == true) {
currentMaxVal = Mathf.Min(Mathf.Max(data) * 2.0f, maxVal);
}
float interVal = (int)(currentMaxVal / sections);
if (interVal < minInterVal) {
interVal = minInterVal;
}
GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
rect.xMax--;
rect.yMax--;
GUI.Box(rect, "", barBackgroundStyle);
labelRect = new Rect(rect.x + textOffsetChartTitle.x, rect.y + textOffsetChartTitle.y, rect.width, titleHeight);
GUI.Label(labelRect, title, barTextStyle);
rect.xMin += labelWidth;
rect.yMin += titleHeight;
GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
GUI.Box(rect, "", barBackgroundStyle);
if (mat != null && Event.current.type == EventType.Repaint) {
GUI.BeginClip(rect);
GL.PushMatrix();
{
mat.SetPass(0);
/* grid */
GL.Begin(GL.LINES);
cellHeight = rect.height * interVal / currentMaxVal;
count = (int)(currentMaxVal / interVal);
if(currentMaxVal % interVal == 0) {
count -= 1;
}
GL.Color(colorGrid);
float lineYPos = 0;
for (int i = 1; i <= count; i++) {
lineYPos = rect.height - i * cellHeight;
GL.Vertex3(0, lineYPos, 0);
GL.Vertex3(rect.width, lineYPos, 0);
}
GL.End();
/* data */
#if UNITY_5_6_OR_NEWER
GL.Begin(GL.LINE_STRIP);
for (int i = 0; i < data.Length; i++) {
GL.Color(ColorSelector(data[i], maxVal));
GL.Vertex3((rect.width / (data.Length - 1)) * i, rect.height * (1 - data[i] / currentMaxVal), 0);
}
GL.End();
#else
GL.Begin(GL.LINES);
for (int i = 1; i < data.Length; i++)
{
GL.Color(ColorSelector(data[i - 1], maxVal));
GL.Vertex3((rect.width / (data.Length - 1)) * (i - 1), rect.height * (1 - data[i - 1] / currentMaxVal), 0);
GL.Color(ColorSelector(data[i], maxVal));
GL.Vertex3((rect.width / (data.Length - 1)) * i, rect.height * (1 - data[i] / currentMaxVal), 0);
}
GL.End();
#endif
}
GL.PopMatrix();
GUI.EndClip();
/* labels*/
rect.xMin -= labelWidth;
labelRect = new Rect(rect.x + textOffsetCalibrator.x, rect.y + textOffsetCalibrator.y, labelWidth, labelHeight);
GUI.Label(labelRect, currentMaxVal.ToString("F0"), chartLabelStyle);
for (int i = 1; i <= count; i++) {
labelRect.y = rect.y + rect.height - i * cellHeight + textOffsetCalibrator.y;
if (labelRect.y > rect.y) {
GUI.Label(labelRect, (interVal * i).ToString("F0"), chartLabelStyle);
}
}
} /* if Event == Repaint */
}
private void NumericMeter(UnityEngine.Rect rect, String meterLabel, Single meterVal) {
const Single titleHeight = 20;
Rect labelRect;
Rect numRect;
UnityEngine.GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
rect.xMax--;
rect.yMax--;
UnityEngine.GUI.Box(rect, "", barBackgroundStyle);
labelRect = new Rect(rect.x + textOffsetChartTitle.x, rect.y + textOffsetChartTitle.y, rect.width, titleHeight);
GUI.Label(labelRect, meterLabel, barTextStyle);
numRect = new Rect(rect.center.x, rect.center.y, 10, 10);
if (meterVal > currentDbWarning) {
GUI.Label(numRect, Dbfs2String(meterVal, "F1"), meterTextWarningHighStyle);
} else if (meterVal > currentDbTarget + currentDbRangePlusMinus) {
GUI.Label(numRect, Dbfs2String(meterVal, "F1"), meterTextWarningHighTolerantStyle);
} else if (meterVal > currentDbTarget - currentDbRangePlusMinus) {
GUI.Label(numRect, Dbfs2String(meterVal, "F1"), meterTextMidRangeStyle);
} else {
GUI.Label(numRect, Dbfs2String(meterVal, "F1"), meterTextWarningLowStyle);
}
}
private enum MultiChannelMeterType {
Peak,
RMS
}
private void MultiChannelMeter(
UnityEngine.Rect rect,
CriProfiler.LevelInfo[] info,
int numCh,
MultiChannelMeterType type,
float min,
float max,
float warningThresh,
string title)
{
float warningRatio = (warningThresh - min) / (max - min);
const float barInterval = 20.0f;
const float calWidth = 30.0f;
const float calHeight = 10.0f;
const float titleHeight = 20.0f;
const float headHeight = 20.0f;
const float footHeight = 20.0f;
const float baseValue = 0.0f;
Color barColor = Color.green;
Color barWarningColor = Color.red;
Color holderColor = Color.green;
Color holderWarningColor = Color.red;
Rect chartRect;
GUI.Box(rect, "", barBorderStyle);
rect.xMin++;
rect.yMin++;
rect.xMax--;
rect.yMax--;
GUI.Box(rect, "", barBackgroundStyle);
chartRect = rect;
chartRect.xMin += calWidth;
chartRect.xMax++;
chartRect.yMin += titleHeight + headHeight;
chartRect.yMax -= footHeight;
GUI.Box(chartRect, "", barBorderStyle);
chartRect.xMin++;
chartRect.yMin++;
chartRect.xMax--;
chartRect.yMax--;
GUI.Box(chartRect, "", barBackgroundStyle);
/* title */
GUI.Label(new Rect(rect.x + textOffsetChartTitle.x, rect.y + textOffsetChartTitle.y, rect.width, rect.height), title, barTextStyle);
rect.yMin += titleHeight;
/* horizontal labels */
float barWidth = (chartRect.width - barInterval * (numCh + 1)) / numCh;
float labelXStart = calWidth + 1 + barInterval;
if (info != null && info.Length >= numCh) {
for (int i = 0; i < numCh; ++i) {
switch (type) {
case MultiChannelMeterType.Peak:
GUI.Label(new Rect(rect.x + labelXStart, rect.y, barWidth, headHeight), Dbfs2String(Level2Db(info[i].levelPeak), "F1"), multiChMeterTextStyle);
break;
case MultiChannelMeterType.RMS:
GUI.Label(new Rect(rect.x + labelXStart, rect.y, barWidth, headHeight), Dbfs2String(Level2Db(info[i].levelRms), "F1"), multiChMeterTextStyle);
break;
default:
break;
}
GUI.Label(new Rect(rect.x + labelXStart, rect.y + rect.height - footHeight, barWidth, footHeight), i < S_ChannelNames.Length ? S_ChannelNames[i] : "CH" + (i + 1), multiChMeterTextStyle);
labelXStart += barInterval + barWidth;
}
}
/* vertical labels */
rect.yMin += headHeight + 1;
rect.yMax -= footHeight + 1;
float cellHeight = rect.height * currentLevelCalInterval / (currentLevelCeiling - currentLevelFloor);
float firstCellInterval = ((currentLevelCeiling - baseValue) % currentLevelCalInterval + currentLevelCalInterval) % currentLevelCalInterval;
if (firstCellInterval == 0) {
firstCellInterval = currentLevelCalInterval;
}
float firstCellHeight = rect.height * firstCellInterval / (currentLevelCeiling - currentLevelFloor);
float remainingInterval = currentLevelCeiling - firstCellInterval - currentLevelFloor;
int cellCount = (int)(remainingInterval / currentLevelCalInterval);
if (remainingInterval % currentLevelCalInterval == 0) {
cellCount -= 1;
}
GUI.Label(new Rect(rect.x + textOffsetCalibrator.x, rect.y + textOffsetCalibrator.y, calWidth, calHeight), currentLevelCeiling.ToString("F0"), chartLabelStyle);
GUI.Label(new Rect(rect.x + textOffsetCalibrator.x, rect.y + rect.height + textOffsetCalibrator.y, calWidth, calHeight), currentLevelFloor.ToString("F0"), chartLabelStyle);
for (int i=0; i < cellCount + 1; ++i) {
GUI.Label(new Rect(rect.x + textOffsetCalibrator.x, rect.y + firstCellHeight + cellHeight * i + textOffsetCalibrator.y, calWidth, calHeight), (currentLevelCeiling - firstCellInterval - currentLevelCalInterval * i).ToString("F0"), chartLabelStyle);
}
/* GL drawing */
if (mat != null && Event.current.type == EventType.Repaint) {
GUI.BeginClip(chartRect);
GL.PushMatrix();
{
mat.SetPass(0);
/* grid */
float lineYPos = 0;
GL.Begin(GL.LINES);
GL.Color(colorGrid);
for (int i = 0; i < cellCount + 1; ++i) {
lineYPos = firstCellHeight + i * cellHeight;
GL.Vertex3(0, lineYPos, 0);
GL.Vertex3(chartRect.width, lineYPos, 0);
}
GL.End();
/* bars */
if (info != null && info.Length >= numCh && barInterval * (numCh + 1) < chartRect.width) {
float barHeight;
float barWarningHeight;
float barXStart;
for (int i = 0; i < numCh; ++i) {
float heightRatio = 0;
switch (type) {
case MultiChannelMeterType.Peak:
heightRatio = ((Level2Db(info[i].levelPeak) - currentLevelFloor) / (currentLevelCeiling - currentLevelFloor));
break;
case MultiChannelMeterType.RMS:
heightRatio = ((Level2Db(info[i].levelRms) - currentLevelFloor) / (currentLevelCeiling - currentLevelFloor));
break;
default:
break;
}
if (heightRatio > 1.0f) {
heightRatio = 1.0f;
}
if (heightRatio < 0) {
heightRatio = 0;
}
barHeight = chartRect.height * heightRatio;
barWarningHeight = chartRect.height * warningRatio;
barXStart = (barInterval + barWidth) * i + barInterval;
GL.Begin(GL.QUADS);
if (heightRatio > warningRatio) {
GL.Color(barWarningColor);
GL.Vertex3(barXStart, chartRect.height, 0);
GL.Vertex3(barXStart + barWidth, chartRect.height, 0);
GL.Vertex3(barXStart + barWidth, chartRect.height - barHeight, 0);
GL.Vertex3(barXStart, chartRect.height - barHeight, 0);
}
GL.Color(barColor);
GL.Vertex3(barXStart, chartRect.height, 0);
GL.Vertex3(barXStart + barWidth, chartRect.height, 0);
GL.Vertex3(barXStart + barWidth, chartRect.height - Mathf.Max(0, Mathf.Min(barHeight, barWarningHeight)), 0);
GL.Vertex3(barXStart, chartRect.height - Mathf.Max(0, Mathf.Min(barHeight, barWarningHeight)), 0);
GL.End();
/* holders */
if (type == MultiChannelMeterType.Peak) {
heightRatio = ((Level2Db(info[i].levelPeakHold) - currentLevelFloor) / (currentLevelCeiling - currentLevelFloor));
if (heightRatio > 1.0f) {
heightRatio = 1.0f;
}
if (heightRatio < 0) {
heightRatio = 0;
}
barHeight = chartRect.height * heightRatio;
GL.Begin(GL.LINES);
if (heightRatio > warningRatio) {
GL.Color(holderWarningColor);
} else {
GL.Color(holderColor);
}
GL.Vertex3(barXStart, chartRect.height - barHeight, 0);
GL.Vertex3(barXStart + barWidth, chartRect.height - barHeight, 0);
GL.End();
}
}
}
}
GL.PopMatrix();
GUI.EndClip();
}
}
#endregion Drawing Functions
#region Utilities
static private bool CriFoldout(bool foldout, string content) {
#if UNITY_5_5_OR_NEWER
return EditorGUILayout.Foldout(foldout, content, true);
#else
return EditorGUILayout.Foldout(foldout, content);
#endif
}
static private Single Level2Db(Single level) {
return Mathf.Log10(level) * 20.0f;
}
static private Single Value2Ratio(Single val, Single min, Single max) {
if (max - min == 0.0f) {
return 0.0f;
}
if (val > max) {
return 1.0f;
}
if (val < min) {
return 0.0f;
}
return (val - min) / (max - min);
}
static private string Dbfs2String(Single dbVal, string format) {
if (dbVal < Single.MinValue) {
return "---";
} else {
return dbVal.ToString(format);
}
}
static private string MicroSec2String(ulong microSec) {
ulong hour = microSec / 3600000000;
ulong min = (microSec % 3600000000) / 60000000;
ulong sec = (microSec % 60000000) / 1000000;
ulong msec = (microSec % 1000000) / 1000;
return string.Format("{0}:{1}:{2}.{3}", hour, min, sec, msec);
}
/* Only to use on the first layer of OnGUI */
private StringBuilder ClearedStr {
get {
this.gStrBuilder.Length = 0;
return this.gStrBuilder;
}
}
private string DataSize2String(float sizeByte) {
gStrBuilderSub.Length = 0;
if (sizeByte > 524288.0f) {
return gStrBuilderSub.AppendFormat("{0:F2}", sizeByte / 1048576.0f).Append(" MB").ToString();
} else if (sizeByte > 512.0f) {
return gStrBuilderSub.AppendFormat("{0:F2}", sizeByte / 1024.0f).Append(" KB").ToString();
} else {
return gStrBuilderSub.AppendFormat("{0:F0}", sizeByte).Append(" Byte").ToString();
}
}
private Color ColorSelector(float sample, float maxVal) {
int index = (int)((chartGradientColors.Length - 1) * (maxVal == 0 ? 0 : sample / maxVal));
Mathf.Clamp(index, 0, chartGradientColors.Length - 1);
return (chartGradientColors.Length > 0) ? chartGradientColors[index] : Color.white;
}
#endregion Utilities
}
} //namespace CriWare