void OnMarker(MarkerMsg marker)
            {
                Dictionary <int, Drawing3d> ns;
                Drawing3d drawing;

                switch (marker.action)
                {
                case MarkerMsg.DELETEALL:
                    foreach (Dictionary <int, Drawing3d> namespaceToDestroy in m_DrawingNamespaces.Values)
                    {
                        foreach (Drawing3d drawingToDestroy in namespaceToDestroy.Values)
                        {
                            drawingToDestroy.Destroy();
                        }
                    }
                    m_DrawingNamespaces.Clear();
                    break;

                case MarkerMsg.ADD:
                    if (!m_DrawingNamespaces.TryGetValue(marker.ns, out ns))
                    {
                        ns = new Dictionary <int, Drawing3d>();
                        m_DrawingNamespaces.Add(marker.ns, ns);
                    }
                    if (!ns.TryGetValue(marker.id, out drawing))
                    {
                        drawing = Drawing3d.Create();
                        ns.Add(marker.id, drawing);
                    }
                    if (marker.lifetime.sec == 0 && marker.lifetime.nanosec == 0)
                    {
                        drawing.ClearDuration();
                    }
                    else
                    {
                        drawing.SetDuration(marker.lifetime.sec + marker.lifetime.nanosec / 1E9f);
                    }
                    drawing.Clear();
                    Draw <FLU>(marker, drawing);
                    break;

                case MarkerMsg.DELETE:
                    if (!m_DrawingNamespaces.TryGetValue(marker.ns, out ns))
                    {
                        ns = new Dictionary <int, Drawing3d>();
                        m_DrawingNamespaces.Add(marker.ns, ns);
                    }
                    if (ns.TryGetValue(marker.id, out drawing))
                    {
                        drawing.Destroy();
                        ns.Remove(marker.id);
                    }
                    break;
                }
            }
        public void OnChanged(TFStream stream)
        {
            Drawing3d drawing;

            if (!drawings.TryGetValue(stream.Name, out drawing))
            {
                drawing = Drawing3d.Create();
                drawings[stream.Name] = drawing;
                if (stream.Parent != null)
                {
                    OnChanged(stream.Parent);
                    Drawing3d parentStream;
                    if (drawings.TryGetValue(stream.Parent.Name, out parentStream))
                    {
                        drawing.transform.parent = parentStream.transform;
                    }
                }
            }

            TFFrame frame = stream.GetLocalTF();

            drawing.transform.localPosition = frame.translation;
            drawing.transform.localRotation = frame.rotation;
            drawing.Clear();
            EnsureSettings(stream);
            if (m_ShowAxes[stream])
            {
                VisualizationUtils.DrawAxisVectors <FLU>(drawing, Vector3.zero.To <FLU>(), Quaternion.identity.To <FLU>(), axesScale, false);
            }

            if (m_ShowLinks[stream])
            {
                drawing.DrawLine(Quaternion.Inverse(frame.rotation) * -frame.translation, Vector3.zero, color, lineThickness);
            }

            if (m_ShowNames[stream])
            {
                drawing.DrawLabel(stream.Name, Vector3.zero, color);
            }
        }