Skip to content

Merging 2017.1 into master #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Assets/Clients/GraphVisualizerClient.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Experimental.Director;
using UnityEngine.Playables;

// Bridge between runtime and editor code: the graph created in runtime code can call GraphVisualizerClient.Show(...)
// and the EditorWindow will register itself with the client to display any available graph.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using GraphVisualizer;
using UnityEngine.Experimental.Director;
using UnityEngine.Playables;

public class DefaultGraphRenderer : IGraphRenderer
{
Expand Down
175 changes: 130 additions & 45 deletions Assets/Editor/GraphVisualizer/PlayableGraphVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,60 @@
using System.Collections.Generic;
using System.Text;
using GraphVisualizer;
using UnityEngine.Experimental.Director;
using UnityEngine.Playables;

public class PlayableGraphNode : Node
public class SharedPlayableNode : Node
{
public PlayableGraphNode(PlayableHandle content, float weight = 1, bool active = false)
public SharedPlayableNode(object content, float weight = 1, bool active = false)
: base(content, weight, active)
{
}

protected static string InfoString(string key, double value)
{
return String.Format(
((Math.Abs(value) < 100000.0) ? "<b>{0}:</b> {1:#.###}" : "<b>{0}:</b> {1:E4}"), key, value);
}

protected static string InfoString(string key, int value)
{
return String.Format("<b>{0}:</b> {1:D}", key, value);
}

protected static string InfoString(string key, object value)
{
return "<b>" + key + ":</b> " + (value ?? "(none)");
}

protected static string RemoveFromEnd(string str, string suffix)
{
if (str.EndsWith(suffix))
{
return str.Substring(0, str.Length - suffix.Length);
}
return str;
}
}

public class PlayableNode : SharedPlayableNode
{
public PlayableNode(Playable content, float weight = 1, bool active = false)
: base(content, weight, active)
{
}

public override Type GetContentType()
{
Playable p = null;
Playable p = Playable.Null;
try
{
p = ((PlayableHandle)content).GetObject<Playable>();
p = ((Playable)content);
}
catch
{
// Ignore.
}
return p == null ? null : p.GetType();
return !p.IsValid() ? null : p.GetPlayableType();
}

public override string GetContentTypeShortName()
Expand All @@ -39,48 +72,66 @@ public override string ToString()

sb.AppendLine(InfoString("Handle", GetContentTypeShortName()));

var h = (PlayableHandle)content;
var h = (Playable)content;

sb.AppendLine(InfoString("IsValid", h.IsValid()));

if (h.IsValid())
{
sb.AppendLine(InfoString("IsDone", h.isDone));
sb.AppendLine(InfoString("InputCount", h.inputCount));
sb.AppendLine(InfoString("OutputCount", h.outputCount));
sb.AppendLine(InfoString("PlayState", h.playState));
sb.AppendLine(InfoString("Speed", h.speed));
sb.AppendLine(InfoString("Duration", h.duration));
sb.AppendLine(InfoString("Time", h.time));
sb.AppendLine(InfoString("IsDone", h.IsDone()));
sb.AppendLine(InfoString("InputCount", h.GetInputCount()));
sb.AppendLine(InfoString("OutputCount", h.GetOutputCount()));
sb.AppendLine(InfoString("PlayState", h.GetPlayState()));
sb.AppendLine(InfoString("Speed", h.GetSpeed()));
sb.AppendLine(InfoString("Duration", h.GetDuration()));
sb.AppendLine(InfoString("Time", h.GetTime()));
// sb.AppendLine(InfoString("Animation", h.animatedProperties));
}

return sb.ToString();
}
}

private static string InfoString(string key, double value)
public class PlayableOutputNode : SharedPlayableNode
{
public PlayableOutputNode(PlayableOutput content)
: base(content, content.GetWeight(), true)
{
return String.Format(
((Math.Abs(value) < 100000.0) ? "<b>{0}:</b> {1:#.###}" : "<b>{0}:</b> {1:E4}") , key, value);
}

private static string InfoString(string key, int value)
public override Type GetContentType()
{
return String.Format("<b>{0}:</b> {1:D}", key, value);
PlayableOutput p = PlayableOutput.Null;
try
{
p = ((PlayableOutput)content);
}
catch
{
// Ignore.
}
return !p.IsOutputValid() ? null : p.GetPlayableOutputType();
}

private static string InfoString(string key, object value)
public override string GetContentTypeShortName()
{
return "<b>" + key + ":</b> " + (value ?? "(none)");
// Remove the extra Playable at the end of the Playable types.
string shortName = base.GetContentTypeShortName();
string cleanName = RemoveFromEnd(shortName, "PlayableOutput") + "Output";
return string.IsNullOrEmpty(cleanName) ? shortName : cleanName;
}

private static string RemoveFromEnd(string str, string suffix)
public override string ToString()
{
if (str.EndsWith(suffix))
{
return str.Substring(0, str.Length - suffix.Length);
}
return str;
var sb = new StringBuilder();

sb.AppendLine(InfoString("Handle", GetContentTypeShortName()));

var h = (PlayableOutput)content;

sb.AppendLine(InfoString("IsValid", h.IsOutputValid()));

return sb.ToString();
}
}

Expand All @@ -95,47 +146,81 @@ public PlayableGraphVisualizer(PlayableGraph playableGraph)

protected override void Populate()
{
if (!m_PlayableGraph.IsValid()) return;
int roots = m_PlayableGraph.rootPlayableCount;
for (int i = 0; i < roots; i++)
if (!m_PlayableGraph.IsValid())
return;

int outputs = m_PlayableGraph.GetOutputCount();
for (int i = 0; i < outputs; i++)
{
AddNodeHierarchy(CreateNodeFromPlayableHandle(m_PlayableGraph.GetRootPlayable(i), 1.0f));
var output = m_PlayableGraph.GetOutput(i);
if(output.IsOutputValid())
{
AddNodeHierarchy(CreateNodeFromPlayableOutput(output));
}
}
}

protected override IEnumerable<Node> GetChildren(Node node)
{
// Children are the PlayableHandle Inputs.
return GetInputsNode((PlayableHandle)node.content);
// Children are the Playable Inputs.
if(node is PlayableNode)
return GetInputsFromPlayableNode((Playable)node.content);
else if(node is PlayableOutputNode)
return GetInputsFromPlayableOutputNode((PlayableOutput)node.content);

return new List<Node>();
}

private List<Node> GetInputsNode(PlayableHandle h)
private List<Node> GetInputsFromPlayableNode(Playable h)
{
var inputs = new List<Node>();
for (int port = 0; port < h.inputCount; ++port)
if (h.IsValid())
{
PlayableHandle playableHandle = h.GetInput(port);
if (playableHandle.IsValid())
for (int port = 0; port < h.GetInputCount(); ++port)
{
Playable playable = h.GetInput(port);
if (playable.IsValid())
{
float weight = h.GetInputWeight(port);
Node node = CreateNodeFromPlayable(playable, weight);
inputs.Add(node);
}
}
}
return inputs;
}

private List<Node> GetInputsFromPlayableOutputNode(PlayableOutput h)
{
var inputs = new List<Node>();
if (h.IsOutputValid())
{
Playable playable = h.GetSourcePlayable();
if (playable.IsValid())
{
float weight = h.GetInputWeight(port);
Node node = CreateNodeFromPlayableHandle(playableHandle, weight);
Node node = CreateNodeFromPlayable(playable, 1);
inputs.Add(node);
}
}
return inputs;
}

private PlayableGraphNode CreateNodeFromPlayableHandle(PlayableHandle h, float weight)
private PlayableNode CreateNodeFromPlayable(Playable h, float weight)
{
return new PlayableNode(h, weight, h.GetPlayState() == PlayState.Playing);
}

private PlayableOutputNode CreateNodeFromPlayableOutput(PlayableOutput h)
{
return new PlayableGraphNode(h, weight, h.playState == PlayState.Playing);
return new PlayableOutputNode(h);
}

private static bool HasValidOuputs(PlayableHandle h)
private static bool HasValidOuputs(Playable h)
{
for (int port = 0; port < h.outputCount; ++port)
for (int port = 0; port < h.GetOutputCount(); ++port)
{
PlayableHandle playableHandle = h.GetOutput(port);
if (playableHandle.IsValid())
Playable playable = h.GetOutput(port);
if (playable.IsValid())
{
return true;
}
Expand Down
26 changes: 16 additions & 10 deletions Assets/Editor/GraphVisualizer/PlayableGraphVisualizerWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using GraphVisualizer;
using UnityEngine.Experimental.Director;
using UnityEngine.Playables;
using UnityEditor.Animations;

public class PlayableGraphVisualizerWindow : EditorWindow, IHasCustomMenu
Expand Down Expand Up @@ -67,12 +67,21 @@ private PlayableGraphInfo GetSelectedGraphInToolBar(IList<PlayableGraphInfo> gra
return selectedDirector;
}

private void ShowMessage(string msg)
private static void ShowMessage(string msg)
{
GUIStyle centeredStyle = GUI.skin.GetStyle("Label");
centeredStyle.alignment = TextAnchor.UpperCenter;
int width = 15 * msg.Length;
GUI.Label(new Rect(0.5f * (Screen.width - width), 0.5f * (Screen.height - 50), width, 50), msg, centeredStyle);
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();

GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();

GUILayout.Label(msg);

GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();

GUILayout.FlexibleSpace();
GUILayout.EndVertical();
}

void Update()
Expand Down Expand Up @@ -100,7 +109,6 @@ void OnGUI()
// that are in the current scene.
if (m_AutoScanScene)
{
#if PLAYABLE_DIRECTOR
// This code could be generalized, maybe if we added a IHasPlayableGraph Interface.
IList<PlayableDirector> directors = FindObjectsOfType<PlayableDirector>();
if (directors != null)
Expand All @@ -115,8 +123,7 @@ void OnGUI()
}
}
}
#endif
#if ANIMATOR_5_6

IList<Animator> animators = FindObjectsOfType<Animator>();
if (animators != null)
{
Expand All @@ -130,7 +137,6 @@ void OnGUI()
}
}
}
#endif
}

if (GraphVisualizerClient.GetGraphs() != null)
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
The PlayableGraph Visualizer window can be used to display any *PlayableGraph*.
The tool can be used in both Play and Edit mode and will always reflect the current state of the graph.
Playable Handles in the graph are represented by colored nodes, varying according to their type. Wire color intensity indicates the local weight of the blending.
## Setup ##
- Download the release that matches your current Unity version, or the latest if there your Unity version is more recent than the latest release.
- Copy the content of this repos Asset folder into a the Asset folder of an Unity Project. You will need to do this for every project.
## Window ##
- You can open the Timeline Visualizer in **Window > PlayableGraph Visualizer**.
## Usage ##
- Copy the content of this repos into a Unity Project.
- Open any scene that contains at least one *PlayableGraph*.
- Register your *PlayableGraph* with the method GraphVisualizerClient.Show(PlayableGraph, string).
- Open the Timeline Visualizer in **Window > PlayableGraph Visualizer**.
- Select the *PlayableGraph* to display in the top-left combo box.
- Click on a Node to display more information about the associated Playable Handle.
## Notes ##
Expand Down