// NOTE: The code here is highly similar to RemoveChildCore in ModelVisual3D, // but slightly different because the parent is 2D here. void IVisual3DContainer.RemoveChild(Visual3D child) { int index = child.ParentIndex; // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } Debug.Assert(child != null); Debug.Assert(child.InternalVisualParent == this); VisualDiagnostics.OnVisualChildChanged(this, child, false); child.SetParent(/* newParent = */ (Visual)null); // CS0121: Call is ambigious without casting null to Visual. // remove the inheritance context if (_inheritanceContextForChildren != null) { _inheritanceContextForChildren.RemoveSelfAsInheritanceContext(child, null); } // // Remove the child on all channels this visual is marshalled to. // for (int i = 0, limit = _proxy3D.Count; i < limit; i++) { DUCE.Channel channel = _proxy3D.GetChannel(i); if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) { child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); DUCE.IResource childResource = (DUCE.IResource)child; childResource.RemoveChildFromParent(this, channel); childResource.ReleaseOnChannel(channel); } } SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty); // // Force a full precompute and render pass for this visual. // Visual.PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); // child.FireOnVisualParentChanged(this); OnVisualChildrenChanged(/* visualAdded = */ null, child); }
/// <summary> /// DisconnectChild /// /// Derived classes must call this method to notify the Visual3D layer that a /// child was removed from the children collection. The Visual3D layer will then call /// GetVisual3DChild to find out which child has been removed. /// /// </summary> protected void RemoveVisual3DChild(Visual3D child) { // It is invalid to modify the children collection that we // might be iterating during a property invalidation tree walk. if (IsVisualChildrenIterationInProgress) { throw new InvalidOperationException(SR.Get(SRID.CannotModifyVisualChildrenDuringTreeWalk)); } Debug.Assert(child != null); Debug.Assert(child.InternalVisualParent == this); child.SetParent(/* newParent = */ (Visual3D) null); // CS0121: Call is ambigious without casting null to Visual3D. // remove the inheritance context RemoveSelfAsInheritanceContext(child, null); // // Remove the child on all the channels // this visual is being marshalled to. // for (int i = 0, limit = _proxy.Count; i < limit; i++) { DUCE.Channel channel = _proxy.GetChannel(i); if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) { child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); DUCE.IResource childResource = (DUCE.IResource)child; childResource.RemoveChildFromParent(this, channel); childResource.ReleaseOnChannel(channel); } } // // Force a full precompute and render pass for this visual. // Visual3D.PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); // // Fire notifications child.FireOnVisualParentChanged(this); OnVisualChildrenChanged(/* visualAdded = */ null , child); }
/// <summary> /// Propagates the flags up to the root. /// </summary> /// <remarks> /// The walk stops on a node with all of the required flags set. /// </remarks> internal static void PropagateFlags( Visual3D e, VisualFlags flags, VisualProxyFlags proxyFlags) { while ((e != null) && (!e.CheckFlagsAnd(flags) || !e.CheckFlagsOnAllChannels(proxyFlags))) { // These asserts are mostly for documentation when diffing the 2D/3D // implementations. Debug.Assert(!e.CheckFlagsOr(VisualFlags.ShouldPostRender), "Visual3Ds should never be the root of a tree."); Debug.Assert(!e.CheckFlagsOr(VisualFlags.NodeIsCyclicBrushRoot), "Visual3Ds should never be the root of an ICyclicBrush."); e.SetFlags(true, flags); e.SetFlagsOnAllChannels(true, proxyFlags); // If our 3D parent is null call back into VisualTreeUtils to potentially // continue the walk in 2D. if (e._3DParent == null) { Viewport3DVisual viewport = e.InternalVisualParent as Viewport3DVisual; Debug.Assert((viewport == null) == (e.InternalVisualParent == null), "Viewport3DVisual is the only supported 2D parent of a 3D visual."); if(viewport != null) { // We must notify the 2D visual that its contents have changed. // This will cause the 2D visual to set it's content dirty flag // and continue the propagation of IsDirtyForRender/Precompute. viewport.Visual3DTreeChanged(); // continue propagating flags up the 2D world Visual.PropagateFlags(viewport, flags, proxyFlags); } // Stop propagating. We are at the root of the 3D subtree. return; } e = e._3DParent; } }
internal override void RenderContent(RenderContext ctx, bool isOnChannel) { DUCE.Channel channel = ctx.Channel; // // At this point, the visual has to be marshalled. Force // marshalling of the camera and viewport in case we have // just created a new visual resource. // Debug.Assert(IsOnChannel(channel)); VisualProxyFlags flags = _proxy.GetFlags(channel); // // Make sure the camera resource is being marshalled properly. // if ((flags & VisualProxyFlags.Viewport3DVisual_IsCameraDirty) != 0) { Camera camera = Camera; if (camera != null) { DUCE.Viewport3DVisualNode.SetCamera( ((DUCE.IResource) this).GetHandle(channel), ((DUCE.IResource)camera).AddRefOnChannel(channel), channel); } else if (isOnChannel) /* camera == null */ { DUCE.Viewport3DVisualNode.SetCamera( ((DUCE.IResource) this).GetHandle(channel), DUCE.ResourceHandle.Null, channel); } SetFlags(channel, false, VisualProxyFlags.Viewport3DVisual_IsCameraDirty); } // // Set the viewport if it's dirty. // if ((flags & VisualProxyFlags.Viewport3DVisual_IsViewportDirty) != 0) { DUCE.Viewport3DVisualNode.SetViewport( ((DUCE.IResource) this).GetHandle(channel), Viewport, channel); SetFlags(channel, false, VisualProxyFlags.Viewport3DVisual_IsViewportDirty); } //we only want to recurse in the children if the visual does not have a bitmap effect //or we are in the BitmapVisualManager render pass // Visit children of this node ----------------------------------------------------------------------- Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentNodeConnected), "Only HostVisuals are expected to have a content node."); if (_children != null) { for (uint i = 0; i < _children.InternalCount; i++) { Visual3D child = _children.InternalGetItem((int)i); if (child != null) { if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsSubtreeDirtyForRender) || // or the visual is dirty !(child.IsOnChannel(channel))) // or the child has not been marshalled yet. { child.RenderRecursive(ctx); } if (child.IsOnChannel(channel)) { if (!child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) { DUCE.Visual3DNode.InsertChildAt( _proxy3D.GetHandle(channel), ((DUCE.IResource)child).GetHandle(channel), /* iPosition = */ i, channel); child.SetFlags(channel, true, VisualProxyFlags.IsConnectedToParent); } } } } } }