/// <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); }
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); } } }
/// <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); } } }