/// <summary>
        /// Tries to add the given graphic to this group.  This can safely be called
        /// during runtime or edit time.  This method can fail under the following
        /// conditions:
        ///    - The graphic is already attached to this group.
        ///    - The graphic is already attached to a different group.
        ///    - It is runtime and add/remove is not supported by this group.
        ///
        /// At runtime the actual attachment is delayed until LateUpdate for efficiency
        /// reasons.  Expect that even if this method returns true that the graphic will
        /// not actually be attached until the end of LateUpdate.
        /// </summary>
        public bool TryAddGraphic(LeapGraphic graphic)
        {
            Assert.IsNotNull(graphic);

            if (graphic.willbeAttached || (graphic.isAttachedToGroup && !graphic.willbeDetached))
            {
                return(false);
            }

            if (!addRemoveSupportedOrEditTime())
            {
                return(false);
            }

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                Undo.RecordObject(graphic, "Added graphic to group");
            }
            else
#endif
            {
                if (_toAttach.Contains(graphic))
                {
                    return(false);
                }
                if (_toDetach.Contains(graphic))
                {
                    graphic.CancelWillBeDetached();
                    graphic.isRepresentationDirty = true;
                    _toDetach.Remove(graphic);
                    return(true);
                }
            }

            if (_graphics.Contains(graphic))
            {
                if (graphic.attachedGroup == null)
                {
                    //detatch and re-add, it forgot it was attached!
                    //This can easily happen at edit time due to prefab shenanigans
                    graphic.OnDetachedFromGroup();
                    _graphics.Remove(graphic);
                }
                else
                {
                    Debug.LogWarning("Could not add graphic because it was already a part of this group.");
                    return(false);
                }
            }

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                int newIndex = _graphics.Count;
                _graphics.Add(graphic);

                LeapSpaceAnchor anchor = _renderer.space == null ? null : LeapSpaceAnchor.GetAnchor(graphic.transform);

                RebuildFeatureData();
                RebuildFeatureSupportInfo();

                graphic.OnAttachedToGroup(this, anchor);

                if (_renderer.space != null)
                {
                    _renderer.space.RebuildHierarchy();
                    _renderer.space.RecalculateTransformers();
                }

                _renderer.editor.ScheduleRebuild();
            }
            else
#endif
            {
                if (_toAttach.Contains(graphic))
                {
                    return(false);
                }

                graphic.NotifyWillBeAttached(this);
                _toAttach.Add(graphic);
            }

            return(true);
        }
Exemple #2
0
        private void handleRuntimeAddRemove()
        {
            if (_toAttach.Count == 0 && _toDetach.Count == 0)
            {
                return;
            }

            using (new ProfilerSample("Handle Runtime Add/Remove")) {
                List <int> dirtyIndexes = Pool <List <int> > .Spawn();

                try {
                    var  attachEnum = _toAttach.GetEnumerator();
                    var  detachEnum = _toDetach.GetEnumerator();
                    bool canAttach  = attachEnum.MoveNext();
                    bool canDetach  = detachEnum.MoveNext();

                    //First, we can handle pairs of adds/removes easily by simply placing
                    //the new graphic in the same place the old graphic was.
                    while (canAttach && canDetach)
                    {
                        int toDetatchIndex = _graphics.IndexOf(detachEnum.Current);
                        _graphics[toDetatchIndex] = attachEnum.Current;

                        var anchor = _renderer.space == null ? null : LeapSpaceAnchor.GetAnchor(attachEnum.Current.transform);

                        detachEnum.Current.OnDetachedFromGroup();
                        attachEnum.Current.OnAttachedToGroup(this, anchor);

                        dirtyIndexes.Add(toDetatchIndex);

                        canAttach = attachEnum.MoveNext();
                        canDetach = detachEnum.MoveNext();
                    }

                    int newGraphicStart = _graphics.Count;

                    //Then we append all the new graphics if there are any left.  This
                    //only happens if more graphics were added than were remove this
                    //frame.
                    while (canAttach)
                    {
                        _graphics.Add(attachEnum.Current);
                        canAttach = attachEnum.MoveNext();
                    }

                    //We remove any graphics that did not have a matching add.  This
                    //only happens if more graphics were removed than were added this
                    //frame.
                    while (canDetach)
                    {
                        int toDetachIndex = _graphics.IndexOf(detachEnum.Current);
                        dirtyIndexes.Add(toDetachIndex);

                        _graphics[_graphics.Count - 1].isRepresentationDirty = true;
                        _graphics.RemoveAtUnordered(toDetachIndex);

                        detachEnum.Current.OnDetachedFromGroup();

                        canDetach = detachEnum.MoveNext();
                    }

                    //TODO: this is gonna need to be optimized
                    //Make sure to call this before OnAttachedToGroup or else the graphic
                    //will not have the correct feature data when it gets attached!
                    RebuildFeatureData();
                    RebuildFeatureSupportInfo();

                    //newGraphicStart is either less than _graphics.Count because we added
                    //new graphics, or it is greater than _graphics.Count because we removed
                    //some graphics.
                    for (int i = newGraphicStart; i < _graphics.Count; i++)
                    {
                        var anchor = _renderer.space == null ? null : LeapSpaceAnchor.GetAnchor(attachEnum.Current.transform);
                        _graphics[i].OnAttachedToGroup(this, anchor);
                    }

                    attachEnum.Dispose();
                    detachEnum.Dispose();
                    _toAttach.Clear();
                    _toDetach.Clear();

                    //Make sure the dirty indexes only point to valid graphics areas.
                    //Could potentially be optimized, but hasnt been a bottleneck.
                    for (int i = dirtyIndexes.Count; i-- != 0;)
                    {
                        if (dirtyIndexes[i] >= _graphics.Count)
                        {
                            dirtyIndexes.RemoveAt(i);
                        }
                    }

                    if (renderer.space != null)
                    {
                        renderer.space.RebuildHierarchy();
                        renderer.space.RecalculateTransformers();
                    }

                    foreach (var feature in _features)
                    {
                        feature.isDirty = true;
                    }

                    (_renderingMethod.Value as ISupportsAddRemove).OnAddRemoveGraphics(dirtyIndexes);
                } finally {
                    dirtyIndexes.Clear();
                    Pool <List <int> > .Recycle(dirtyIndexes);
                }
            }
        }
Exemple #3
0
 /// <summary>
 /// Called by graphic groups when a renderer's attached space changes.
 /// </summary>
 public void OnUpdateAnchor(LeapSpaceAnchor anchor)
 {
     _anchor = anchor;
 }
            private void validateGraphics()
            {
                Assert.IsFalse(InternalUtility.IsPrefab(_renderer), "Should never validate graphics for prefabs");

                _renderer.GetComponentsInChildren(includeInactive: true, result: _tempGraphicList);

                HashSet <LeapGraphic> graphicsInGroup = Pool <HashSet <LeapGraphic> > .Spawn();

                try {
                    foreach (var group in _renderer._groups)
                    {
                        for (int i = group.graphics.Count; i-- != 0;)
                        {
                            if (group.graphics[i] == null)
                            {
                                group.graphics.RemoveAt(i);
                            }
                            else
                            {
                                graphicsInGroup.Add(group.graphics[i]);
                            }
                        }

                        foreach (var graphic in _tempGraphicList)
                        {
                            if (graphic.isAttachedToGroup)
                            {
                                //If the graphic claims it is attached to this group, but it really isn't, remove
                                //it and re-add it.
                                bool graphicThinksItsInGroup = graphic.attachedGroup == group;
                                bool isActuallyInGroup       = graphicsInGroup.Contains(graphic);

                                //Also re add it if it is attached to a completely different renderer!
                                if (graphicThinksItsInGroup != isActuallyInGroup ||
                                    graphic.attachedGroup.renderer != _renderer)
                                {
                                    if (!group.TryRemoveGraphic(graphic))
                                    {
                                        //If we fail, detach using force!!
                                        graphic.OnDetachedFromGroup();
                                    }

                                    group.TryAddGraphic(graphic);
                                }
                            }
                        }

                        graphicsInGroup.Clear();
                    }
                } finally {
                    graphicsInGroup.Clear();
                    Pool <HashSet <LeapGraphic> > .Recycle(graphicsInGroup);
                }

                foreach (var graphic in _tempGraphicList)
                {
                    if (graphic.isAttachedToGroup)
                    {
                        //procede to validate

                        //If the graphic is anchored to the wrong anchor, detach and reattach
                        var anchor = _renderer._space == null ? null : LeapSpaceAnchor.GetAnchor(graphic.transform);
                        if (graphic.anchor != anchor)
                        {
                            var group = graphic.attachedGroup;

                            if (group.TryRemoveGraphic(graphic))
                            {
                                group.TryAddGraphic(graphic);
                            }
                        }

                        if (!graphic.enabled || !graphic.transform.IsActiveRelativeToParent(_renderer.transform))
                        {
                            graphic.attachedGroup.TryRemoveGraphic(graphic);
                        }
                    }

                    if (!graphic.isAttachedToGroup && graphic.enabled && graphic.gameObject.activeInHierarchy)
                    {
                        _renderer.TryAddGraphic(graphic);
                    }
                }
            }